@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.
package/dist/bin/rig.js CHANGED
@@ -105,12 +105,13 @@ async function runCommand(context, parts) {
105
105
  const envMode = process.env.RIG_BASH_MODE;
106
106
  const effectiveMode = context.policyMode || (envMode === "off" || envMode === "observe" || envMode === "enforce" ? envMode : loadPolicy(context.projectRoot).mode);
107
107
  const controlledPath = `${resolve(context.projectRoot, ".rig", "bin")}:${context.projectRoot}/rig/tools:${process.env.PATH ?? ""}`;
108
- const controlledBash = await ensureAgentShellBinary(context.projectRoot);
108
+ const usesInfrastructureBinary = parts[0] === "rig-server";
109
+ const controlledBash = usesInfrastructureBinary ? null : await ensureAgentShellBinary(context.projectRoot);
109
110
  const commandEnv = [
110
111
  "env",
111
112
  `PATH=${controlledPath}`,
112
113
  `PROJECT_RIG_ROOT=${context.projectRoot}`,
113
- `BASH=${controlledBash}`,
114
+ ...controlledBash ? [`BASH=${controlledBash}`] : [],
114
115
  `RIG_BASH_MODE=${effectiveMode}`,
115
116
  `RIG_POLICY_FILE=${resolve(context.projectRoot, "rig/policy/policy.json")}`,
116
117
  ...context.eventBus.getEventsFile() ? [`RIG_EVENTS_FILE=${context.eventBus.getEventsFile()}`] : []
@@ -2671,6 +2672,8 @@ function resolveSelectedConnection(projectRoot, options = {}) {
2671
2672
 
2672
2673
  // packages/cli/src/commands/_server-client.ts
2673
2674
  import { spawnSync } from "child_process";
2675
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
2676
+ import { resolve as resolve9 } from "path";
2674
2677
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
2675
2678
  var cachedGitHubBearerToken;
2676
2679
  function cleanToken(value) {
@@ -2680,9 +2683,25 @@ function cleanToken(value) {
2680
2683
  function setGitHubBearerTokenForCurrentProcess(token) {
2681
2684
  cachedGitHubBearerToken = cleanToken(token ?? undefined);
2682
2685
  }
2683
- function readGitHubBearerTokenForRemote() {
2686
+ function readPrivateRemoteSessionToken(projectRoot) {
2687
+ const path = resolve9(projectRoot, ".rig", "state", "github-auth.json");
2688
+ if (!existsSync5(path))
2689
+ return null;
2690
+ try {
2691
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
2692
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
2693
+ } catch {
2694
+ return null;
2695
+ }
2696
+ }
2697
+ function readGitHubBearerTokenForRemote(projectRoot) {
2684
2698
  if (cachedGitHubBearerToken !== undefined)
2685
2699
  return cachedGitHubBearerToken;
2700
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
2701
+ if (privateSession) {
2702
+ cachedGitHubBearerToken = privateSession;
2703
+ return cachedGitHubBearerToken;
2704
+ }
2686
2705
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
2687
2706
  if (envToken) {
2688
2707
  cachedGitHubBearerToken = envToken;
@@ -2702,7 +2721,7 @@ async function ensureServerForCli(projectRoot) {
2702
2721
  if (selected?.connection.kind === "remote") {
2703
2722
  return {
2704
2723
  baseUrl: selected.connection.baseUrl,
2705
- authToken: readGitHubBearerTokenForRemote(),
2724
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
2706
2725
  connectionKind: "remote"
2707
2726
  };
2708
2727
  }
@@ -2809,7 +2828,7 @@ async function postGitHubTokenViaServer(context, token, options = {}) {
2809
2828
  const payload = await requestServerJson(context, "/api/github/auth/token", {
2810
2829
  method: "POST",
2811
2830
  headers: { "content-type": "application/json" },
2812
- body: JSON.stringify({ token, selectedRepo: options.selectedRepo })
2831
+ body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
2813
2832
  });
2814
2833
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2815
2834
  }
@@ -2830,7 +2849,7 @@ async function registerProjectViaServer(context, input) {
2830
2849
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2831
2850
  }
2832
2851
  function sleep(ms) {
2833
- return new Promise((resolve9) => setTimeout(resolve9, ms));
2852
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
2834
2853
  }
2835
2854
  async function switchServerProjectRootViaServer(context, projectRoot, options = {}) {
2836
2855
  const switched = await requestServerJson(context, "/api/server/project-root", {
@@ -2921,9 +2940,9 @@ async function submitTaskRunViaServer(context, input) {
2921
2940
  }
2922
2941
 
2923
2942
  // packages/cli/src/commands/_pi-install.ts
2924
- import { existsSync as existsSync5, readFileSync as readFileSync3, rmSync as rmSync3 } from "fs";
2943
+ import { existsSync as existsSync6, readFileSync as readFileSync4, rmSync as rmSync3 } from "fs";
2925
2944
  import { homedir as homedir3 } from "os";
2926
- import { resolve as resolve9 } from "path";
2945
+ import { resolve as resolve10 } from "path";
2927
2946
  var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
2928
2947
  var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
2929
2948
  export { default } from '@rig/pi-rig';
@@ -2938,11 +2957,11 @@ async function defaultCommandRunner(command, options = {}) {
2938
2957
  return { exitCode, stdout, stderr };
2939
2958
  }
2940
2959
  function resolvePiRigExtensionPath(homeDir) {
2941
- return resolve9(homeDir, ".pi", "agent", "extensions", "pi-rig");
2960
+ return resolve10(homeDir, ".pi", "agent", "extensions", "pi-rig");
2942
2961
  }
2943
- function resolvePiRigPackageSource(projectRoot, exists = existsSync5) {
2944
- const localPackage = resolve9(projectRoot, "packages", "pi-rig");
2945
- if (exists(resolve9(localPackage, "package.json")))
2962
+ function resolvePiRigPackageSource(projectRoot, exists = existsSync6) {
2963
+ const localPackage = resolve10(projectRoot, "packages", "pi-rig");
2964
+ if (exists(resolve10(localPackage, "package.json")))
2946
2965
  return localPackage;
2947
2966
  return `npm:${PI_RIG_PACKAGE_NAME}`;
2948
2967
  }
@@ -2993,13 +3012,13 @@ async function ensurePiBinaryAvailable(input) {
2993
3012
  ...next.exitCode === 0 ? {} : { error: (next.stderr || next.stdout).trim() || "pi --version failed after install" }
2994
3013
  };
2995
3014
  }
2996
- function removeManagedLegacyPiRigBridge(homeDir, exists = existsSync5) {
3015
+ function removeManagedLegacyPiRigBridge(homeDir, exists = existsSync6) {
2997
3016
  const extensionPath = resolvePiRigExtensionPath(homeDir);
2998
- const indexPath = resolve9(extensionPath, "index.ts");
3017
+ const indexPath = resolve10(extensionPath, "index.ts");
2999
3018
  if (!exists(indexPath))
3000
3019
  return;
3001
3020
  try {
3002
- const content = readFileSync3(indexPath, "utf8");
3021
+ const content = readFileSync4(indexPath, "utf8");
3003
3022
  if (content === LEGACY_PI_RIG_MARKER || content.includes("Managed by Rig. Source package: @rig/pi-rig")) {
3004
3023
  rmSync3(extensionPath, { recursive: true, force: true });
3005
3024
  }
@@ -3015,13 +3034,13 @@ async function checkPiRigInstall(input = {}) {
3015
3034
  piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
3016
3035
  };
3017
3036
  }
3018
- const exists = input.exists ?? existsSync5;
3037
+ const exists = input.exists ?? existsSync6;
3019
3038
  const runner = input.commandRunner ?? defaultCommandRunner;
3020
3039
  const piResult = await safeRun(runner, ["pi", "--version"]);
3021
3040
  const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
3022
3041
  const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
3023
3042
  ${piListResult.stderr}`);
3024
- const legacyBridge = exists(resolve9(extensionPath, "index.ts"));
3043
+ const legacyBridge = exists(resolve10(extensionPath, "index.ts"));
3025
3044
  const hasPiRig = listedPiRig;
3026
3045
  return {
3027
3046
  extensionPath,
@@ -3359,7 +3378,7 @@ async function executeQueue(context, args) {
3359
3378
  }
3360
3379
 
3361
3380
  // packages/cli/src/commands/agent.ts
3362
- import { resolve as resolve11 } from "path";
3381
+ import { resolve as resolve12 } from "path";
3363
3382
  import {
3364
3383
  agentId,
3365
3384
  cleanupAgentRuntime,
@@ -3369,8 +3388,8 @@ import {
3369
3388
  } from "@rig/runtime/control-plane/runtime/isolation";
3370
3389
 
3371
3390
  // packages/cli/src/commands/_authority-runs.ts
3372
- import { existsSync as existsSync6 } from "fs";
3373
- import { resolve as resolve10 } from "path";
3391
+ import { existsSync as existsSync7 } from "fs";
3392
+ import { resolve as resolve11 } from "path";
3374
3393
  import {
3375
3394
  readAuthorityRun,
3376
3395
  readJsonlFile as readJsonlFile2,
@@ -3392,8 +3411,8 @@ function normalizeRuntimeAdapter(value) {
3392
3411
  return "claude-code";
3393
3412
  }
3394
3413
  function readLatestBeadRecord(projectRoot, taskId) {
3395
- const issuesPath = resolve10(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
3396
- if (!existsSync6(issuesPath)) {
3414
+ const issuesPath = resolve11(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
3415
+ if (!existsSync7(issuesPath)) {
3397
3416
  return null;
3398
3417
  }
3399
3418
  let latest = null;
@@ -3428,6 +3447,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3428
3447
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
3429
3448
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
3430
3449
  const next = {
3450
+ ...existing ?? {},
3431
3451
  runId: input.runId,
3432
3452
  projectRoot,
3433
3453
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -3460,7 +3480,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3460
3480
  } else if ("errorText" in next) {
3461
3481
  delete next.errorText;
3462
3482
  }
3463
- writeJsonFile3(resolve10(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
3483
+ writeJsonFile3(resolve11(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
3464
3484
  return next;
3465
3485
  }
3466
3486
 
@@ -3581,10 +3601,10 @@ async function executeAgent(context, args) {
3581
3601
  status: "running",
3582
3602
  startedAt: createdAt,
3583
3603
  worktreePath: runtime.workspaceDir,
3584
- artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3604
+ artifactRoot: resolve12(runtime.workspaceDir, "artifacts", taskId),
3585
3605
  logRoot: runtime.logsDir,
3586
- sessionPath: resolve11(runtime.sessionDir, "session.json"),
3587
- sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3606
+ sessionPath: resolve12(runtime.sessionDir, "session.json"),
3607
+ sessionLogPath: resolve12(runtime.logsDir, "agent-stdout.log"),
3588
3608
  pid: process.pid
3589
3609
  });
3590
3610
  const result = await runInAgentRuntime({
@@ -3604,10 +3624,10 @@ async function executeAgent(context, args) {
3604
3624
  startedAt: createdAt,
3605
3625
  completedAt: failedAt,
3606
3626
  worktreePath: runtime.workspaceDir,
3607
- artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3627
+ artifactRoot: resolve12(runtime.workspaceDir, "artifacts", taskId),
3608
3628
  logRoot: runtime.logsDir,
3609
- sessionPath: resolve11(runtime.sessionDir, "session.json"),
3610
- sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3629
+ sessionPath: resolve12(runtime.sessionDir, "session.json"),
3630
+ sessionLogPath: resolve12(runtime.logsDir, "agent-stdout.log"),
3611
3631
  pid: process.pid,
3612
3632
  errorText: result.stderr ? result.stderr.trim() : `Agent runtime command failed (${result.exitCode})`
3613
3633
  });
@@ -3624,10 +3644,10 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
3624
3644
  startedAt: createdAt,
3625
3645
  completedAt,
3626
3646
  worktreePath: runtime.workspaceDir,
3627
- artifactRoot: resolve11(runtime.workspaceDir, "artifacts", taskId),
3647
+ artifactRoot: resolve12(runtime.workspaceDir, "artifacts", taskId),
3628
3648
  logRoot: runtime.logsDir,
3629
- sessionPath: resolve11(runtime.sessionDir, "session.json"),
3630
- sessionLogPath: resolve11(runtime.logsDir, "agent-stdout.log"),
3649
+ sessionPath: resolve12(runtime.sessionDir, "session.json"),
3650
+ sessionLogPath: resolve12(runtime.logsDir, "agent-stdout.log"),
3631
3651
  pid: process.pid
3632
3652
  });
3633
3653
  return {
@@ -3701,7 +3721,7 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
3701
3721
  import {
3702
3722
  chmodSync,
3703
3723
  copyFileSync as copyFileSync2,
3704
- existsSync as existsSync7,
3724
+ existsSync as existsSync8,
3705
3725
  mkdirSync as mkdirSync6,
3706
3726
  readdirSync,
3707
3727
  readlinkSync,
@@ -3711,7 +3731,7 @@ import {
3711
3731
  unlinkSync
3712
3732
  } from "fs";
3713
3733
  import { homedir as homedir4 } from "os";
3714
- import { resolve as resolve12 } from "path";
3734
+ import { resolve as resolve13 } from "path";
3715
3735
  import { buildBinary as buildBinary2 } from "@rig/runtime/control-plane/runtime/isolation";
3716
3736
  import {
3717
3737
  computeRuntimeImageFingerprint,
@@ -3730,13 +3750,13 @@ async function runQuietBinaryProbe(binaryPath, args, cwd) {
3730
3750
 
3731
3751
  // packages/cli/src/commands/dist.ts
3732
3752
  function collectRigValidatorBuildTargets(input) {
3733
- const validatorsRoot = resolve12(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
3734
- if (!existsSync7(validatorsRoot))
3753
+ const validatorsRoot = resolve13(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
3754
+ if (!existsSync8(validatorsRoot))
3735
3755
  return [];
3736
3756
  const targets = [];
3737
3757
  const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
3738
3758
  for (const category of categories) {
3739
- const categoryDir = resolve12(validatorsRoot, category.name);
3759
+ const categoryDir = resolve13(validatorsRoot, category.name);
3740
3760
  for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
3741
3761
  if (!entry.isFile() || !entry.name.endsWith(".ts"))
3742
3762
  continue;
@@ -3745,7 +3765,7 @@ function collectRigValidatorBuildTargets(input) {
3745
3765
  continue;
3746
3766
  targets.push({
3747
3767
  source: `packages/runtime/src/control-plane/validators/${category.name}/${entry.name}`,
3748
- dest: resolve12(input.imageDir, `bin/validators/${category.name}-${check}`),
3768
+ dest: resolve13(input.imageDir, `bin/validators/${category.name}-${check}`),
3749
3769
  cwd: input.hostProjectRoot
3750
3770
  });
3751
3771
  }
@@ -3754,16 +3774,16 @@ function collectRigValidatorBuildTargets(input) {
3754
3774
  }
3755
3775
  async function findLatestDistBinary(projectRoot) {
3756
3776
  const distRoot = resolveControlPlaneHostDistDir(projectRoot);
3757
- if (!existsSync7(distRoot)) {
3777
+ if (!existsSync8(distRoot)) {
3758
3778
  return null;
3759
3779
  }
3760
3780
  const entries = readdirSync(distRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("rig-")).map((entry) => ({
3761
3781
  name: entry.name,
3762
- mtimeMs: statSync(resolve12(distRoot, entry.name)).mtimeMs
3782
+ mtimeMs: statSync(resolve13(distRoot, entry.name)).mtimeMs
3763
3783
  })).sort((a, b) => b.mtimeMs - a.mtimeMs || b.name.localeCompare(a.name));
3764
3784
  for (const { name } of entries) {
3765
- const candidate = resolve12(distRoot, name, "bin", "rig");
3766
- if (existsSync7(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
3785
+ const candidate = resolve13(distRoot, name, "bin", "rig");
3786
+ if (existsSync8(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
3767
3787
  return candidate;
3768
3788
  }
3769
3789
  }
@@ -3775,7 +3795,7 @@ async function isRunnableRigBinary(binaryPath, projectRoot) {
3775
3795
  async function runDistDoctor(projectRoot) {
3776
3796
  const bunPath = Bun.which("bun");
3777
3797
  const rigPath = Bun.which("rig");
3778
- const userBinDir = resolve12(homedir4(), ".local/bin");
3798
+ const userBinDir = resolve13(homedir4(), ".local/bin");
3779
3799
  const userBinInPath = (process.env.PATH || "").split(":").filter(Boolean).includes(userBinDir);
3780
3800
  let rigRunnable = false;
3781
3801
  if (rigPath) {
@@ -3823,15 +3843,15 @@ async function executeDist(context, args) {
3823
3843
  let source = await findLatestDistBinary(context.projectRoot);
3824
3844
  let buildDir = null;
3825
3845
  if (!source) {
3826
- buildDir = resolve12(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
3846
+ buildDir = resolve13(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
3827
3847
  await context.runCommand(["bun", "run", "packages/cli/bin/build-rig-binaries.ts", "--output-dir", buildDir]);
3828
- source = resolve12(buildDir, "bin", "rig");
3848
+ source = resolve13(buildDir, "bin", "rig");
3829
3849
  }
3830
- if (!existsSync7(source)) {
3850
+ if (!existsSync8(source)) {
3831
3851
  throw new CliError2(`Unable to locate rig binary at ${source}.`, 2);
3832
3852
  }
3833
- const installedPath = resolve12(installDir, "rig");
3834
- if (existsSync7(installedPath)) {
3853
+ const installedPath = resolve13(installDir, "rig");
3854
+ if (existsSync8(installedPath)) {
3835
3855
  unlinkSync(installedPath);
3836
3856
  }
3837
3857
  copyFileSync2(source, installedPath);
@@ -3873,22 +3893,22 @@ async function executeDist(context, args) {
3873
3893
  requireNoExtraArgs(rest, "bun run rig dist rebuild-agent");
3874
3894
  const fp = await computeRuntimeImageFingerprint(context.projectRoot);
3875
3895
  const currentId = computeRuntimeImageId(fp);
3876
- const imagesDir = resolve12(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
3896
+ const imagesDir = resolve13(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
3877
3897
  mkdirSync6(imagesDir, { recursive: true });
3878
3898
  let pruned = 0;
3879
3899
  for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
3880
3900
  if (entry.isDirectory() && entry.name !== currentId) {
3881
- rmSync4(resolve12(imagesDir, entry.name), { recursive: true, force: true });
3901
+ rmSync4(resolve13(imagesDir, entry.name), { recursive: true, force: true });
3882
3902
  pruned++;
3883
3903
  }
3884
3904
  }
3885
3905
  if (pruned > 0 && context.outputMode === "text") {
3886
3906
  console.log(`Pruned ${pruned} stale image(s).`);
3887
3907
  }
3888
- const imageDir = resolve12(imagesDir, currentId);
3889
- mkdirSync6(resolve12(imageDir, "bin/hooks"), { recursive: true });
3890
- mkdirSync6(resolve12(imageDir, "bin/plugins"), { recursive: true });
3891
- mkdirSync6(resolve12(imageDir, "bin/validators"), { recursive: true });
3908
+ const imageDir = resolve13(imagesDir, currentId);
3909
+ mkdirSync6(resolve13(imageDir, "bin/hooks"), { recursive: true });
3910
+ mkdirSync6(resolve13(imageDir, "bin/plugins"), { recursive: true });
3911
+ mkdirSync6(resolve13(imageDir, "bin/validators"), { recursive: true });
3892
3912
  const hookNames = [
3893
3913
  "scope-guard",
3894
3914
  "import-guard",
@@ -3902,25 +3922,25 @@ async function executeDist(context, args) {
3902
3922
  ];
3903
3923
  const targets = [];
3904
3924
  const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || context.projectRoot;
3905
- targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve12(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
3906
- targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
3925
+ targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve13(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
3926
+ targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve13(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
3907
3927
  for (const hookName of hookNames) {
3908
3928
  const src = `packages/runtime/src/control-plane/hooks/${hookName}.ts`;
3909
- targets.push({ source: src, dest: resolve12(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
3910
- targets.push({ source: src, dest: resolve12(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
3929
+ targets.push({ source: src, dest: resolve13(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
3930
+ targets.push({ source: src, dest: resolve13(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
3911
3931
  }
3912
- const pluginsDir = resolve12(context.projectRoot, "rig/plugins");
3913
- const binPluginsDir = resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
3914
- const validatorsRoot = resolve12(hostProjectRoot, "packages/runtime/src/control-plane/validators");
3915
- const binValidatorsDir = resolve12(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
3932
+ const pluginsDir = resolve13(context.projectRoot, "rig/plugins");
3933
+ const binPluginsDir = resolve13(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
3934
+ const validatorsRoot = resolve13(hostProjectRoot, "packages/runtime/src/control-plane/validators");
3935
+ const binValidatorsDir = resolve13(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
3916
3936
  mkdirSync6(binPluginsDir, { recursive: true });
3917
3937
  mkdirSync6(binValidatorsDir, { recursive: true });
3918
- if (existsSync7(pluginsDir)) {
3938
+ if (existsSync8(pluginsDir)) {
3919
3939
  for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
3920
3940
  const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
3921
3941
  if (!m)
3922
3942
  continue;
3923
- targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve12(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
3943
+ targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve13(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
3924
3944
  }
3925
3945
  }
3926
3946
  targets.push(...collectRigValidatorBuildTargets({ contextProjectRoot: context.projectRoot, hostProjectRoot, imageDir }));
@@ -3931,17 +3951,17 @@ async function executeDist(context, args) {
3931
3951
  const isValidator = dest.includes("/bin/validators/");
3932
3952
  await buildBinary2(source, dest, cwd, isValidator ? { AGENT_BUN_PATH: Bun.which("bun") || "bun" } : { AGENT_PROJECT_ROOT: context.projectRoot });
3933
3953
  }
3934
- if (existsSync7(pluginsDir)) {
3954
+ if (existsSync8(pluginsDir)) {
3935
3955
  for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
3936
3956
  const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
3937
3957
  if (!m)
3938
3958
  continue;
3939
3959
  const pluginName = m[1];
3940
- const imageBin = resolve12(imageDir, `bin/plugins/${pluginName}`);
3960
+ const imageBin = resolve13(imageDir, `bin/plugins/${pluginName}`);
3941
3961
  if (!pluginName)
3942
3962
  continue;
3943
- const symlinkPath = resolve12(binPluginsDir, pluginName);
3944
- if (existsSync7(imageBin)) {
3963
+ const symlinkPath = resolve13(binPluginsDir, pluginName);
3964
+ if (existsSync8(imageBin)) {
3945
3965
  try {
3946
3966
  unlinkSync(symlinkPath);
3947
3967
  } catch {}
@@ -3949,10 +3969,10 @@ async function executeDist(context, args) {
3949
3969
  }
3950
3970
  }
3951
3971
  }
3952
- if (existsSync7(validatorsRoot)) {
3972
+ if (existsSync8(validatorsRoot)) {
3953
3973
  const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
3954
3974
  for (const category of categories) {
3955
- const categoryDir = resolve12(validatorsRoot, category.name);
3975
+ const categoryDir = resolve13(validatorsRoot, category.name);
3956
3976
  for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
3957
3977
  if (!entry.isFile() || !entry.name.endsWith(".ts"))
3958
3978
  continue;
@@ -3960,9 +3980,9 @@ async function executeDist(context, args) {
3960
3980
  if (!check || check === "index" || check === "shared")
3961
3981
  continue;
3962
3982
  const validatorName = `${category.name}-${check}`;
3963
- const imageBin = resolve12(imageDir, `bin/validators/${validatorName}`);
3964
- const symlinkPath = resolve12(binValidatorsDir, validatorName);
3965
- if (existsSync7(imageBin)) {
3983
+ const imageBin = resolve13(imageDir, `bin/validators/${validatorName}`);
3984
+ const symlinkPath = resolve13(binValidatorsDir, validatorName);
3985
+ if (existsSync8(imageBin)) {
3966
3986
  try {
3967
3987
  unlinkSync(symlinkPath);
3968
3988
  } catch {}
@@ -3971,18 +3991,18 @@ async function executeDist(context, args) {
3971
3991
  }
3972
3992
  }
3973
3993
  }
3974
- const agentsDir = resolve12(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
3975
- if (existsSync7(agentsDir)) {
3994
+ const agentsDir = resolve13(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
3995
+ if (existsSync8(agentsDir)) {
3976
3996
  let relinkCount = 0;
3977
3997
  for (const agentEntry of readdirSync(agentsDir, { withFileTypes: true })) {
3978
3998
  if (!agentEntry.isDirectory())
3979
3999
  continue;
3980
- const agentBinDir = resolve12(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
3981
- if (!existsSync7(agentBinDir))
4000
+ const agentBinDir = resolve13(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
4001
+ if (!existsSync8(agentBinDir))
3982
4002
  continue;
3983
4003
  const walkDir = (dir) => {
3984
4004
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
3985
- const fullPath = resolve12(dir, entry.name);
4005
+ const fullPath = resolve13(dir, entry.name);
3986
4006
  if (entry.isDirectory()) {
3987
4007
  walkDir(fullPath);
3988
4008
  } else if (entry.isSymbolicLink()) {
@@ -4016,7 +4036,7 @@ async function executeDist(context, args) {
4016
4036
 
4017
4037
  // packages/cli/src/commands/inbox.ts
4018
4038
  import { writeFileSync as writeFileSync4 } from "fs";
4019
- import { resolve as resolve13 } from "path";
4039
+ import { resolve as resolve14 } from "path";
4020
4040
  import {
4021
4041
  listAuthorityRuns,
4022
4042
  readJsonlFile as readJsonlFile3,
@@ -4033,7 +4053,7 @@ async function executeInbox(context, args) {
4033
4053
  pending = task.rest;
4034
4054
  requireNoExtraArgs(pending, "bun run rig inbox approvals [--run <id>] [--task <id>]");
4035
4055
  const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!run.value || entry.runId === run.value) && (!task.value || entry.taskId === task.value));
4036
- const approvals = runs.flatMap((entry) => readJsonlFile3(resolve13(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "approvals.jsonl")).map((record) => ({
4056
+ const approvals = runs.flatMap((entry) => readJsonlFile3(resolve14(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "approvals.jsonl")).map((record) => ({
4037
4057
  runId: entry.runId,
4038
4058
  record
4039
4059
  })));
@@ -4061,7 +4081,7 @@ async function executeInbox(context, args) {
4061
4081
  if (decision.value !== "approve" && decision.value !== "reject") {
4062
4082
  throw new CliError2("decision must be approve or reject.");
4063
4083
  }
4064
- const approvalsPath = resolve13(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
4084
+ const approvalsPath = resolve14(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
4065
4085
  const approvals = readJsonlFile3(approvalsPath);
4066
4086
  const resolvedAt = new Date().toISOString();
4067
4087
  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);
@@ -4078,7 +4098,7 @@ async function executeInbox(context, args) {
4078
4098
  pending = task.rest;
4079
4099
  requireNoExtraArgs(pending, "bun run rig inbox inputs [--run <id>] [--task <id>]");
4080
4100
  const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!run.value || entry.runId === run.value) && (!task.value || entry.taskId === task.value));
4081
- const requests = runs.flatMap((entry) => readJsonlFile3(resolve13(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "user-input.jsonl")).map((record) => ({
4101
+ const requests = runs.flatMap((entry) => readJsonlFile3(resolve14(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "user-input.jsonl")).map((record) => ({
4082
4102
  runId: entry.runId,
4083
4103
  record
4084
4104
  })));
@@ -4120,7 +4140,7 @@ async function executeInbox(context, args) {
4120
4140
  const [key, ...restValue] = entry.split("=");
4121
4141
  return [key, restValue.join("=")];
4122
4142
  }));
4123
- const requestsPath = resolve13(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
4143
+ const requestsPath = resolve14(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
4124
4144
  const requests = readJsonlFile3(requestsPath);
4125
4145
  const resolvedAt = new Date().toISOString();
4126
4146
  const next = requests.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", answers: parsedAnswers, respondedAt: resolvedAt, resolvedAt } : entry);
@@ -4135,14 +4155,14 @@ async function executeInbox(context, args) {
4135
4155
  }
4136
4156
 
4137
4157
  // packages/cli/src/commands/init.ts
4138
- import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
4158
+ import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4139
4159
  import { spawnSync as spawnSync2 } from "child_process";
4140
- import { resolve as resolve16 } from "path";
4160
+ import { resolve as resolve17 } from "path";
4141
4161
  import { buildRigInitConfigSource } from "@rig/core";
4142
4162
 
4143
4163
  // packages/cli/src/commands/_snapshot-upload.ts
4144
4164
  import { mkdir, readdir, readFile, writeFile } from "fs/promises";
4145
- import { dirname as dirname2, resolve as resolve14, relative, sep } from "path";
4165
+ import { dirname as dirname2, resolve as resolve15, relative, sep } from "path";
4146
4166
  var SNAPSHOT_ARCHIVE_VERSION = 1;
4147
4167
  var SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/vnd.rig.snapshot+json";
4148
4168
  var DEFAULT_EXCLUDED_DIRECTORIES = new Set([
@@ -4164,15 +4184,15 @@ function assertManifestPath(root, relativePath) {
4164
4184
  if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\x00")) {
4165
4185
  throw new Error(`Invalid snapshot path: ${relativePath}`);
4166
4186
  }
4167
- const resolved = resolve14(root, relativePath);
4187
+ const resolved = resolve15(root, relativePath);
4168
4188
  const relativeToRoot = relative(root, resolved);
4169
- if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve14(relativeToRoot) === resolved) {
4189
+ if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve15(relativeToRoot) === resolved) {
4170
4190
  throw new Error(`Snapshot path escapes project root: ${relativePath}`);
4171
4191
  }
4172
4192
  return resolved;
4173
4193
  }
4174
4194
  async function buildSnapshotUploadManifest(projectRoot, options = {}) {
4175
- const root = resolve14(projectRoot);
4195
+ const root = resolve15(projectRoot);
4176
4196
  const excludedDirectories = [...new Set([
4177
4197
  ...DEFAULT_EXCLUDED_DIRECTORIES,
4178
4198
  ...options.excludedDirectories ?? []
@@ -4184,7 +4204,7 @@ async function buildSnapshotUploadManifest(projectRoot, options = {}) {
4184
4204
  for (const entry of entries) {
4185
4205
  if (entry.isDirectory() && excludedSet.has(entry.name))
4186
4206
  continue;
4187
- const fullPath = resolve14(dir, entry.name);
4207
+ const fullPath = resolve15(dir, entry.name);
4188
4208
  if (entry.isDirectory()) {
4189
4209
  await visit(fullPath);
4190
4210
  continue;
@@ -4232,8 +4252,8 @@ async function uploadSnapshotArchiveViaServer(context, input) {
4232
4252
  }
4233
4253
 
4234
4254
  // packages/cli/src/commands/_doctor-checks.ts
4235
- import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
4236
- import { resolve as resolve15 } from "path";
4255
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
4256
+ import { resolve as resolve16 } from "path";
4237
4257
  import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
4238
4258
  function check(id, label, status, detail, remediation) {
4239
4259
  return {
@@ -4273,11 +4293,11 @@ function repoSlugFromConfig(config) {
4273
4293
  function loadFallbackConfig(projectRoot) {
4274
4294
  const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
4275
4295
  for (const name of candidates) {
4276
- const path = resolve15(projectRoot, name);
4277
- if (!existsSync8(path))
4296
+ const path = resolve16(projectRoot, name);
4297
+ if (!existsSync9(path))
4278
4298
  continue;
4279
4299
  try {
4280
- const source = readFileSync4(path, "utf8");
4300
+ const source = readFileSync5(path, "utf8");
4281
4301
  if (name.endsWith(".json"))
4282
4302
  return JSON.parse(source);
4283
4303
  const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
@@ -4356,7 +4376,7 @@ async function runRigDoctorChecks(options) {
4356
4376
  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`)."));
4357
4377
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
4358
4378
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
4359
- const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync8(resolve15(projectRoot, name)));
4379
+ const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync9(resolve16(projectRoot, name)));
4360
4380
  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."));
4361
4381
  const taskSourceKind = config?.taskSource?.kind;
4362
4382
  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."));
@@ -4451,10 +4471,10 @@ function countDoctorFailures(checks) {
4451
4471
  }
4452
4472
 
4453
4473
  // packages/cli/src/commands/init.ts
4454
- var RIG_CONFIG_PACKAGE_VERSION = "0.0.6-alpha.1";
4474
+ var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
4455
4475
  var RIG_CONFIG_DEV_DEPENDENCIES = {
4456
- "@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_VERSION}`,
4457
- "@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_VERSION}`
4476
+ "@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
4477
+ "@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
4458
4478
  };
4459
4479
  function parseRepoSlugFromRemote(remoteUrl) {
4460
4480
  const trimmed = remoteUrl.trim();
@@ -4474,20 +4494,20 @@ function parseRepoSlug(value) {
4474
4494
  return { owner: match[1], repo: match[2], slug: `${match[1]}/${match[2]}` };
4475
4495
  }
4476
4496
  function ensureRigPrivateDirs(projectRoot) {
4477
- const rigDir = resolve16(projectRoot, ".rig");
4478
- mkdirSync7(resolve16(rigDir, "state"), { recursive: true });
4479
- mkdirSync7(resolve16(rigDir, "logs"), { recursive: true });
4480
- mkdirSync7(resolve16(rigDir, "runs"), { recursive: true });
4481
- mkdirSync7(resolve16(rigDir, "tmp"), { recursive: true });
4482
- mkdirSync7(resolve16(projectRoot, "artifacts"), { recursive: true });
4483
- const taskConfigPath = resolve16(rigDir, "task-config.json");
4484
- if (!existsSync9(taskConfigPath))
4497
+ const rigDir = resolve17(projectRoot, ".rig");
4498
+ mkdirSync7(resolve17(rigDir, "state"), { recursive: true });
4499
+ mkdirSync7(resolve17(rigDir, "logs"), { recursive: true });
4500
+ mkdirSync7(resolve17(rigDir, "runs"), { recursive: true });
4501
+ mkdirSync7(resolve17(rigDir, "tmp"), { recursive: true });
4502
+ mkdirSync7(resolve17(projectRoot, "artifacts"), { recursive: true });
4503
+ const taskConfigPath = resolve17(rigDir, "task-config.json");
4504
+ if (!existsSync10(taskConfigPath))
4485
4505
  writeFileSync5(taskConfigPath, `{}
4486
4506
  `, "utf-8");
4487
4507
  }
4488
4508
  function ensureGitignoreEntries(projectRoot) {
4489
- const path = resolve16(projectRoot, ".gitignore");
4490
- const existing = existsSync9(path) ? readFileSync5(path, "utf8") : "";
4509
+ const path = resolve17(projectRoot, ".gitignore");
4510
+ const existing = existsSync10(path) ? readFileSync6(path, "utf8") : "";
4491
4511
  const entries = [".rig/state/", ".rig/logs/", ".rig/runs/", ".rig/tmp/"];
4492
4512
  const missing = entries.filter((entry) => !existing.split(/\r?\n/).includes(entry));
4493
4513
  if (missing.length === 0)
@@ -4500,14 +4520,14 @@ function ensureGitignoreEntries(projectRoot) {
4500
4520
  `, "utf8");
4501
4521
  }
4502
4522
  function ensureRigConfigPackageDependencies(projectRoot) {
4503
- const path = resolve16(projectRoot, "package.json");
4504
- const existing = existsSync9(path) ? JSON.parse(readFileSync5(path, "utf8")) : {};
4523
+ const path = resolve17(projectRoot, "package.json");
4524
+ const existing = existsSync10(path) ? JSON.parse(readFileSync6(path, "utf8")) : {};
4505
4525
  const devDependencies = existing.devDependencies && typeof existing.devDependencies === "object" && !Array.isArray(existing.devDependencies) ? { ...existing.devDependencies } : {};
4506
4526
  for (const [name, spec] of Object.entries(RIG_CONFIG_DEV_DEPENDENCIES)) {
4507
4527
  devDependencies[name] = spec;
4508
4528
  }
4509
4529
  const next = {
4510
- ...existsSync9(path) ? existing : { name: "rig-project", private: true },
4530
+ ...existsSync10(path) ? existing : { name: "rig-project", private: true },
4511
4531
  devDependencies
4512
4532
  };
4513
4533
  writeFileSync5(path, `${JSON.stringify(next, null, 2)}
@@ -4577,15 +4597,54 @@ async function promptSelect(prompts, options) {
4577
4597
  throw new CliError2("Init cancelled.", 1);
4578
4598
  return String(value);
4579
4599
  }
4580
- async function pollDeviceAuthOnce(context, pollId) {
4600
+ function sleep2(ms) {
4601
+ return new Promise((resolve18) => setTimeout(resolve18, ms));
4602
+ }
4603
+ function positiveIntFromEnv(name, fallback) {
4604
+ const value = Number.parseInt(process.env[name] ?? "", 10);
4605
+ return Number.isFinite(value) && value >= 0 ? value : fallback;
4606
+ }
4607
+ function apiSessionTokenFrom(payload) {
4608
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
4609
+ return null;
4610
+ const token = payload.apiSessionToken;
4611
+ return typeof token === "string" && token.trim() ? token.trim() : null;
4612
+ }
4613
+ function writeRemoteGitHubAuthState(projectRoot, input) {
4614
+ writeFileSync5(resolve17(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
4615
+ authenticated: true,
4616
+ source: input.source,
4617
+ storedOnServer: true,
4618
+ selectedRepo: input.selectedRepo,
4619
+ ...input.apiSessionToken ? { apiSessionToken: input.apiSessionToken } : {},
4620
+ updatedAt: new Date().toISOString()
4621
+ }, null, 2)}
4622
+ `, "utf8");
4623
+ }
4624
+ async function pollDeviceAuthUntilComplete(context, pollId, firstPayload) {
4581
4625
  if (typeof pollId !== "string" || !pollId.trim())
4582
4626
  return null;
4583
- const payload = await requestServerJson(context, "/api/github/auth/device/poll", {
4584
- method: "POST",
4585
- headers: { "content-type": "application/json" },
4586
- body: JSON.stringify({ pollId })
4587
- }).catch(() => null);
4588
- return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
4627
+ const intervalSeconds = typeof firstPayload.interval === "number" && Number.isFinite(firstPayload.interval) && firstPayload.interval > 0 ? firstPayload.interval : 5;
4628
+ const timeoutMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_TIMEOUT_MS", 300000);
4629
+ const intervalMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_INTERVAL_MS", Math.max(1000, intervalSeconds * 1000));
4630
+ const deadline = Date.now() + timeoutMs;
4631
+ let last = null;
4632
+ do {
4633
+ const payload = await requestServerJson(context, "/api/github/auth/device/poll", {
4634
+ method: "POST",
4635
+ headers: { "content-type": "application/json" },
4636
+ body: JSON.stringify({ pollId })
4637
+ }).catch(() => null);
4638
+ last = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
4639
+ const status = typeof last?.status === "string" ? last.status : null;
4640
+ if (status === "signed-in" || status === "expired" || status === "cancelled" || status === "failed") {
4641
+ return last;
4642
+ }
4643
+ if (timeoutMs <= 0)
4644
+ return last;
4645
+ await sleep2(intervalMs);
4646
+ } while (Date.now() < deadline);
4647
+ return last;
4589
4648
  }
4590
4649
  async function runControlPlaneInit(context, options) {
4591
4650
  const projectRoot = context.projectRoot;
@@ -4608,9 +4667,9 @@ async function runControlPlaneInit(context, options) {
4608
4667
  });
4609
4668
  ensureRigPrivateDirs(projectRoot);
4610
4669
  ensureGitignoreEntries(projectRoot);
4611
- const configTsPath = resolve16(projectRoot, "rig.config.ts");
4612
- const configJsonPath = resolve16(projectRoot, "rig.config.json");
4613
- const configExists = existsSync9(configTsPath) || existsSync9(configJsonPath);
4670
+ const configTsPath = resolve17(projectRoot, "rig.config.ts");
4671
+ const configJsonPath = resolve17(projectRoot, "rig.config.json");
4672
+ const configExists = existsSync10(configTsPath) || existsSync10(configJsonPath);
4614
4673
  if (!options.privateStateOnly) {
4615
4674
  if (configExists && !options.repair) {
4616
4675
  if (context.outputMode !== "json")
@@ -4626,7 +4685,7 @@ async function runControlPlaneInit(context, options) {
4626
4685
  }
4627
4686
  ensureRigConfigPackageDependencies(projectRoot);
4628
4687
  }
4629
- writeFileSync5(resolve16(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
4688
+ writeFileSync5(resolve17(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
4630
4689
  `, "utf8");
4631
4690
  const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
4632
4691
  let uploadedSnapshot = null;
@@ -4648,10 +4707,14 @@ async function runControlPlaneInit(context, options) {
4648
4707
  const token = authMethod === "gh" && !options.githubToken ? readGhAuthToken() : options.githubToken?.trim();
4649
4708
  if (token) {
4650
4709
  githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug });
4651
- setGitHubBearerTokenForCurrentProcess(token);
4710
+ const apiSessionToken = apiSessionTokenFrom(githubAuth);
4711
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4652
4712
  if (serverKind === "remote") {
4653
- writeFileSync5(resolve16(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)}
4654
- `, "utf8");
4713
+ writeRemoteGitHubAuthState(projectRoot, {
4714
+ source: authMethod === "gh" ? "gh" : "init-token",
4715
+ selectedRepo: repo.slug,
4716
+ apiSessionToken
4717
+ });
4655
4718
  }
4656
4719
  } else if (authMethod === "device") {
4657
4720
  const payload = await requestServerJson(context, "/api/github/auth/device/start", {
@@ -4660,9 +4723,22 @@ async function runControlPlaneInit(context, options) {
4660
4723
  body: JSON.stringify({ repoSlug: repo.slug })
4661
4724
  });
4662
4725
  deviceAuth = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
4663
- const completed = await pollDeviceAuthOnce(context, deviceAuth.pollId);
4664
- if (completed)
4726
+ if (context.outputMode !== "json") {
4727
+ const verificationUri = String(deviceAuth.verificationUri ?? deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server");
4728
+ const userCode = String(deviceAuth.userCode ?? deviceAuth.user_code ?? "the returned user code");
4729
+ console.log(`GitHub device flow: open ${verificationUri} and enter ${userCode}. Waiting for authorization...`);
4730
+ }
4731
+ const completed = await pollDeviceAuthUntilComplete(context, deviceAuth.pollId, deviceAuth);
4732
+ if (completed) {
4733
+ const apiSessionToken = apiSessionTokenFrom(completed);
4734
+ if (apiSessionToken) {
4735
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken);
4736
+ if (serverKind === "remote") {
4737
+ writeRemoteGitHubAuthState(projectRoot, { source: "device", selectedRepo: repo.slug, apiSessionToken });
4738
+ }
4739
+ }
4665
4740
  deviceAuth = { ...deviceAuth, poll: completed, completed: completed.status === "signed-in" };
4741
+ }
4666
4742
  }
4667
4743
  let remoteCheckoutPreparation = null;
4668
4744
  if (serverKind === "remote" && options.remoteCheckout?.kind !== "uploaded-snapshot") {
@@ -4682,6 +4758,12 @@ async function runControlPlaneInit(context, options) {
4682
4758
  });
4683
4759
  const checkoutPath = typeof checkout.path === "string" ? checkout.path : null;
4684
4760
  const serverRootSwitch = serverKind === "remote" && checkoutPath ? await switchServerProjectRootViaServer(context, checkoutPath) : null;
4761
+ if (serverRootSwitch && token) {
4762
+ githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug, projectRoot: checkoutPath ?? undefined });
4763
+ const apiSessionToken = apiSessionTokenFrom(githubAuth);
4764
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4765
+ writeRemoteGitHubAuthState(projectRoot, { source: authMethod === "gh" ? "gh" : "init-token", selectedRepo: repo.slug, apiSessionToken });
4766
+ }
4685
4767
  const activeProjectRegistration = serverRootSwitch ? await registerProjectViaServer(context, { repoSlug: repo.slug, checkout }) : null;
4686
4768
  const pi = serverKind === "remote" ? await ensureRemotePiRigInstalled({ requestJson: (pathname, init) => requestServerJson(context, pathname, init) }).catch((error) => ({
4687
4769
  remote: true,
@@ -4791,7 +4873,7 @@ function parseInitOptions(args) {
4791
4873
  async function runInteractiveControlPlaneInit(context, prompts) {
4792
4874
  prompts.intro?.("Initialize a Rig control-plane project");
4793
4875
  const projectRoot = context.projectRoot;
4794
- const existingConfig = existsSync9(resolve16(projectRoot, "rig.config.ts")) || existsSync9(resolve16(projectRoot, "rig.config.json"));
4876
+ const existingConfig = existsSync10(resolve17(projectRoot, "rig.config.ts")) || existsSync10(resolve17(projectRoot, "rig.config.json"));
4795
4877
  let repair = false;
4796
4878
  let privateStateOnly = false;
4797
4879
  if (existingConfig) {
@@ -4891,7 +4973,7 @@ async function runInteractiveControlPlaneInit(context, prompts) {
4891
4973
  });
4892
4974
  const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
4893
4975
  const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
4894
- 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")}.` : "";
4976
+ 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")}.` : "";
4895
4977
  prompts.outro?.(`Rig project initialized.${deviceMessage} Next: rig doctor && rig task list`);
4896
4978
  return result;
4897
4979
  }
@@ -5053,8 +5135,8 @@ async function executeDoctor(context, args) {
5053
5135
  }
5054
5136
 
5055
5137
  // packages/cli/src/commands/_run-driver-helpers.ts
5056
- import { readFileSync as readFileSync6 } from "fs";
5057
- import { resolve as resolve17 } from "path";
5138
+ import { readFileSync as readFileSync7 } from "fs";
5139
+ import { resolve as resolve18 } from "path";
5058
5140
  import {
5059
5141
  appendJsonlRecord as appendJsonlRecord2,
5060
5142
  readAuthorityRun as readAuthorityRun2,
@@ -5074,7 +5156,7 @@ function patchAuthorityRun(projectRoot, runId, patch) {
5074
5156
  ...patch,
5075
5157
  updatedAt: new Date().toISOString()
5076
5158
  };
5077
- writeJsonFile4(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
5159
+ writeJsonFile4(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
5078
5160
  return next;
5079
5161
  }
5080
5162
  function touchAuthorityRun(projectRoot, runId) {
@@ -5082,21 +5164,21 @@ function touchAuthorityRun(projectRoot, runId) {
5082
5164
  if (!current) {
5083
5165
  return;
5084
5166
  }
5085
- writeJsonFile4(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
5167
+ writeJsonFile4(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
5086
5168
  ...current,
5087
5169
  updatedAt: new Date().toISOString()
5088
5170
  });
5089
5171
  }
5090
5172
  function appendRunTimeline(projectRoot, runId, value) {
5091
- appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
5173
+ appendJsonlRecord2(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
5092
5174
  touchAuthorityRun(projectRoot, runId);
5093
5175
  }
5094
5176
  function appendRunLog(projectRoot, runId, value) {
5095
- appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
5177
+ appendJsonlRecord2(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
5096
5178
  touchAuthorityRun(projectRoot, runId);
5097
5179
  }
5098
5180
  function appendRunAction(projectRoot, runId, value) {
5099
- appendJsonlRecord2(resolve17(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
5181
+ appendJsonlRecord2(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
5100
5182
  id: value.id,
5101
5183
  type: "action",
5102
5184
  actionType: value.actionType,
@@ -5167,7 +5249,7 @@ function buildRunPrompt(input) {
5167
5249
  })();
5168
5250
  const scopeText = (() => {
5169
5251
  try {
5170
- const parsed = JSON.parse(readFileSync6(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
5252
+ const parsed = JSON.parse(readFileSync7(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
5171
5253
  const entry = parsed[input.taskId] ?? {};
5172
5254
  const scope = Array.isArray(entry.scope) ? entry.scope.filter((item) => typeof item === "string") : [];
5173
5255
  const validation = Array.isArray(entry.validation) ? entry.validation.filter((item) => typeof item === "string") : [];
@@ -5280,8 +5362,8 @@ function renderSourceScopeValidation(task, validation) {
5280
5362
  }
5281
5363
 
5282
5364
  // packages/cli/src/commands/inspect.ts
5283
- import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
5284
- import { resolve as resolve18 } from "path";
5365
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
5366
+ import { resolve as resolve19 } from "path";
5285
5367
  import {
5286
5368
  listAuthorityRuns as listAuthorityRuns2,
5287
5369
  readAuthorityRun as readAuthorityRun3,
@@ -5302,8 +5384,8 @@ async function executeInspect(context, args) {
5302
5384
  if (!latestRun) {
5303
5385
  throw new CliError2(`No runs found for ${requiredTask}.`);
5304
5386
  }
5305
- const logsPath = resolve18(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
5306
- if (!existsSync10(logsPath)) {
5387
+ const logsPath = resolve19(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
5388
+ if (!existsSync11(logsPath)) {
5307
5389
  throw new CliError2(`No logs found for run ${latestRun.runId}.`);
5308
5390
  }
5309
5391
  await context.runCommand(["cat", logsPath]);
@@ -5313,7 +5395,7 @@ async function executeInspect(context, args) {
5313
5395
  const { value: task, rest: remaining } = takeOption(rest, "--task");
5314
5396
  requireNoExtraArgs(remaining, "bun run rig inspect artifacts --task <beads-id>");
5315
5397
  const requiredTask = requireTask(task, "bun run rig inspect artifacts --task <beads-id>");
5316
- const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync10(path));
5398
+ const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync11(path));
5317
5399
  if (!artifactRoot) {
5318
5400
  throw new CliError2(`No artifacts found for ${requiredTask}.`);
5319
5401
  }
@@ -5370,10 +5452,10 @@ async function executeInspect(context, args) {
5370
5452
  case "failures": {
5371
5453
  requireNoExtraArgs(rest, "bun run rig inspect failures");
5372
5454
  const failed = resolveHarnessPaths2(context.projectRoot).failedApproachesPath;
5373
- if (!existsSync10(failed)) {
5455
+ if (!existsSync11(failed)) {
5374
5456
  console.log("No failures recorded.");
5375
5457
  } else {
5376
- process.stdout.write(readFileSync7(failed, "utf-8"));
5458
+ process.stdout.write(readFileSync8(failed, "utf-8"));
5377
5459
  }
5378
5460
  return { ok: true, group: "inspect", command };
5379
5461
  }
@@ -5390,11 +5472,11 @@ async function executeInspect(context, args) {
5390
5472
  return { ok: true, group: "inspect", command };
5391
5473
  case "audit": {
5392
5474
  requireNoExtraArgs(rest, "bun run rig inspect audit");
5393
- const auditPath = resolve18(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
5394
- if (!existsSync10(auditPath)) {
5475
+ const auditPath = resolve19(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
5476
+ if (!existsSync11(auditPath)) {
5395
5477
  console.log("No audit log found.");
5396
5478
  } else {
5397
- const lines = readFileSync7(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
5479
+ const lines = readFileSync8(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
5398
5480
  for (const line of lines) {
5399
5481
  console.log(line);
5400
5482
  }
@@ -6023,8 +6105,8 @@ async function executeRemote(context, args) {
6023
6105
  }
6024
6106
 
6025
6107
  // packages/cli/src/commands/run.ts
6026
- import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
6027
- import { resolve as resolve19 } from "path";
6108
+ import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
6109
+ import { resolve as resolve20 } from "path";
6028
6110
  import { createInterface as createInterface2 } from "readline/promises";
6029
6111
  import {
6030
6112
  listAuthorityRuns as listAuthorityRuns3,
@@ -6038,6 +6120,7 @@ import {
6038
6120
  listOpenEpics,
6039
6121
  resolveDefaultEpic,
6040
6122
  runResume,
6123
+ runRestart,
6041
6124
  runStatus,
6042
6125
  runStop,
6043
6126
  startRun,
@@ -6146,6 +6229,17 @@ async function attachRunOperatorView(context, input) {
6146
6229
  }
6147
6230
 
6148
6231
  // packages/cli/src/commands/run.ts
6232
+ function normalizeRemoteRunDetails(payload) {
6233
+ const run = payload.run;
6234
+ if (!run || typeof run !== "object" || Array.isArray(run))
6235
+ return null;
6236
+ return {
6237
+ ...run,
6238
+ ...Array.isArray(payload.timeline) ? { timeline: payload.timeline } : {},
6239
+ ...Array.isArray(payload.approvals) ? { approvals: payload.approvals } : {},
6240
+ ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6241
+ };
6242
+ }
6149
6243
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
6150
6244
  if (noEpicPrompt) {
6151
6245
  return false;
@@ -6284,7 +6378,7 @@ async function executeRun(context, args) {
6284
6378
  if (!run.value) {
6285
6379
  throw new CliError2("run show requires --run <id>.");
6286
6380
  }
6287
- const record = readAuthorityRun4(context.projectRoot, run.value);
6381
+ const record = readAuthorityRun4(context.projectRoot, run.value) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, run.value).catch(() => ({})));
6288
6382
  if (!record) {
6289
6383
  throw new CliError2(`Run not found: ${run.value}`, 2);
6290
6384
  }
@@ -6303,7 +6397,7 @@ async function executeRun(context, args) {
6303
6397
  if (!run.value) {
6304
6398
  throw new CliError2("run timeline requires --run <id>.");
6305
6399
  }
6306
- const timelinePath = resolve19(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
6400
+ const timelinePath = resolve20(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
6307
6401
  const printEvents = () => {
6308
6402
  const events2 = readJsonlFile4(timelinePath);
6309
6403
  if (context.outputMode === "text") {
@@ -6315,12 +6409,12 @@ async function executeRun(context, args) {
6315
6409
  };
6316
6410
  const events = printEvents();
6317
6411
  if (follow.value && context.outputMode === "text") {
6318
- let lastLength = existsSync11(timelinePath) ? readFileSync8(timelinePath, "utf8").length : 0;
6412
+ let lastLength = existsSync12(timelinePath) ? readFileSync9(timelinePath, "utf8").length : 0;
6319
6413
  while (true) {
6320
6414
  await Bun.sleep(1000);
6321
- if (!existsSync11(timelinePath))
6415
+ if (!existsSync12(timelinePath))
6322
6416
  continue;
6323
- const next = readFileSync8(timelinePath, "utf8");
6417
+ const next = readFileSync9(timelinePath, "utf8");
6324
6418
  if (next.length <= lastLength)
6325
6419
  continue;
6326
6420
  const delta = next.slice(lastLength);
@@ -6465,6 +6559,20 @@ async function executeRun(context, args) {
6465
6559
  }
6466
6560
  return { ok: true, group: "run", command, details: resumed };
6467
6561
  }
6562
+ case "restart": {
6563
+ requireNoExtraArgs(rest, "bun run rig run restart");
6564
+ if (context.dryRun) {
6565
+ if (context.outputMode === "text") {
6566
+ console.log("[dry-run] rig run restart");
6567
+ }
6568
+ return { ok: true, group: "run", command };
6569
+ }
6570
+ const restarted = await runRestart(context.projectRoot, runtimeContext);
6571
+ if (context.outputMode === "text") {
6572
+ console.log(`Restarted run: ${restarted.runId}`);
6573
+ }
6574
+ return { ok: true, group: "run", command, details: restarted };
6575
+ }
6468
6576
  case "stop": {
6469
6577
  const runOption = takeOption(rest, "--run");
6470
6578
  const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
@@ -6522,7 +6630,7 @@ async function executeServer(context, args, options) {
6522
6630
  const authTokenResult = takeOption(pending, "--auth-token");
6523
6631
  pending = authTokenResult.rest;
6524
6632
  requireNoExtraArgs(pending, "bun run rig server start [--host <host>] [--port <n>] [--poll-ms <n>] [--auth-token <token>]");
6525
- const commandParts = ["bun", "run", "packages/server/src/server.ts", "start"];
6633
+ const commandParts = ["rig-server", "start"];
6526
6634
  if (hostResult.value) {
6527
6635
  commandParts.push("--host", hostResult.value);
6528
6636
  }
@@ -6545,7 +6653,7 @@ async function executeServer(context, args, options) {
6545
6653
  const eventResult = takeOption(pending, "--event");
6546
6654
  pending = eventResult.rest;
6547
6655
  requireNoExtraArgs(pending, "bun run rig server notify-test [--event <type>]");
6548
- const commandParts = ["bun", "run", "packages/server/src/server.ts", "notify-test"];
6656
+ const commandParts = ["rig-server", "notify-test"];
6549
6657
  if (eventResult.value) {
6550
6658
  commandParts.push("--event", eventResult.value);
6551
6659
  }
@@ -6606,10 +6714,10 @@ async function executeServer(context, args, options) {
6606
6714
  }
6607
6715
 
6608
6716
  // packages/cli/src/commands/task.ts
6609
- import { readFileSync as readFileSync9 } from "fs";
6717
+ import { readFileSync as readFileSync10 } from "fs";
6610
6718
  import { spawnSync as spawnSync4 } from "child_process";
6611
6719
  import { createInterface as createInterface4 } from "readline/promises";
6612
- import { resolve as resolve20 } from "path";
6720
+ import { resolve as resolve21 } from "path";
6613
6721
  import {
6614
6722
  taskArtifactDir,
6615
6723
  taskArtifacts,
@@ -6940,7 +7048,7 @@ async function executeTask(context, args, options) {
6940
7048
  const fileFlag = takeOption(rest.slice(1), "--file");
6941
7049
  let content;
6942
7050
  if (fileFlag.value) {
6943
- content = readFileSync9(resolve20(context.projectRoot, fileFlag.value), "utf-8");
7051
+ content = readFileSync10(resolve21(context.projectRoot, fileFlag.value), "utf-8");
6944
7052
  } else {
6945
7053
  content = await readStdin();
6946
7054
  }
@@ -7161,8 +7269,8 @@ async function executeTask(context, args, options) {
7161
7269
  }
7162
7270
 
7163
7271
  // packages/cli/src/commands/task-run-driver.ts
7164
- import { copyFileSync as copyFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync10, statSync as statSync2 } from "fs";
7165
- import { resolve as resolve21 } from "path";
7272
+ import { copyFileSync as copyFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7273
+ import { resolve as resolve22 } from "path";
7166
7274
  import { spawn as spawn2, spawnSync as spawnSync5 } from "child_process";
7167
7275
  import { createInterface as createLineInterface } from "readline";
7168
7276
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
@@ -7196,7 +7304,24 @@ import {
7196
7304
  commitRunChanges,
7197
7305
  runPrAutomation
7198
7306
  } from "@rig/runtime/control-plane/native/pr-automation";
7307
+ function looksLikeGitHubToken(value) {
7308
+ const token = value?.trim();
7309
+ if (!token)
7310
+ return false;
7311
+ return /^(gh[opusr]_|github_pat_)/.test(token);
7312
+ }
7313
+ function githubBridgeEnv(token) {
7314
+ const clean = token?.trim();
7315
+ if (!clean)
7316
+ return {};
7317
+ return {
7318
+ RIG_GITHUB_TOKEN: clean,
7319
+ GITHUB_TOKEN: clean,
7320
+ GH_TOKEN: clean
7321
+ };
7322
+ }
7199
7323
  function buildPiRigBridgeEnv(input) {
7324
+ const githubToken = input.githubToken?.trim() || (looksLikeGitHubToken(input.authToken) ? input.authToken.trim() : "");
7200
7325
  return {
7201
7326
  RIG_PROJECT_ROOT: input.projectRoot,
7202
7327
  PROJECT_RIG_ROOT: input.projectRoot,
@@ -7206,7 +7331,7 @@ function buildPiRigBridgeEnv(input) {
7206
7331
  RIG_RUNTIME_ADAPTER: "pi",
7207
7332
  ...input.serverUrl ? { RIG_SERVER_URL: input.serverUrl } : {},
7208
7333
  ...input.authToken ? { RIG_AUTH_TOKEN: input.authToken } : {},
7209
- ...input.githubToken ? { RIG_GITHUB_TOKEN: input.githubToken } : {}
7334
+ ...githubBridgeEnv(githubToken)
7210
7335
  };
7211
7336
  }
7212
7337
  function runGitSync(cwd, args, input) {
@@ -7228,12 +7353,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
7228
7353
  return 0;
7229
7354
  let copied = 0;
7230
7355
  for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
7231
- const sourcePath = resolve21(sourceRoot, relativePath);
7232
- const targetPath = resolve21(targetRoot, relativePath);
7356
+ const sourcePath = resolve22(sourceRoot, relativePath);
7357
+ const targetPath = resolve22(targetRoot, relativePath);
7233
7358
  try {
7234
7359
  if (!statSync2(sourcePath).isFile())
7235
7360
  continue;
7236
- mkdirSync8(resolve21(targetPath, ".."), { recursive: true });
7361
+ mkdirSync8(resolve22(targetPath, ".."), { recursive: true });
7237
7362
  copyFileSync3(sourcePath, targetPath);
7238
7363
  copied += 1;
7239
7364
  } catch {}
@@ -7267,6 +7392,14 @@ function buildTaskRunReviewEnv(config) {
7267
7392
  ...review?.provider ? { AI_REVIEW_PROVIDER: review.provider } : {}
7268
7393
  };
7269
7394
  }
7395
+ function buildDirtyBaselineHandshakeEnv(input) {
7396
+ if (input.baselineMode !== "dirty-snapshot")
7397
+ return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
7398
+ return {
7399
+ RIG_BASELINE_MODE: "dirty-snapshot",
7400
+ RIG_DIRTY_BASELINE_READY_FILE: resolve22(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
7401
+ };
7402
+ }
7270
7403
  function positiveInt(value, fallback) {
7271
7404
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
7272
7405
  }
@@ -7375,9 +7508,9 @@ function createCommandRunner(binary) {
7375
7508
  const stderrChunks = [];
7376
7509
  child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
7377
7510
  child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
7378
- return await new Promise((resolve22) => {
7379
- child.once("error", (error) => resolve22({ exitCode: 1, stderr: error.message }));
7380
- child.once("close", (code) => resolve22({
7511
+ return await new Promise((resolve23) => {
7512
+ child.once("error", (error) => resolve23({ exitCode: 1, stderr: error.message }));
7513
+ child.once("close", (code) => resolve23({
7381
7514
  exitCode: code ?? 1,
7382
7515
  stdout: Buffer.concat(stdoutChunks).toString("utf8"),
7383
7516
  stderr: Buffer.concat(stderrChunks).toString("utf8")
@@ -7573,7 +7706,7 @@ function summarizeValidationFailure(projectRoot, taskId2) {
7573
7706
  return null;
7574
7707
  }
7575
7708
  for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId2)) {
7576
- const summary = readJsonFile3(resolve21(artifactDir, "validation-summary.json"), null);
7709
+ const summary = readJsonFile3(resolve22(artifactDir, "validation-summary.json"), null);
7577
7710
  if (!summary || summary.status !== "fail") {
7578
7711
  continue;
7579
7712
  }
@@ -7654,9 +7787,9 @@ function readTaskRunAcceptedArtifactState(input) {
7654
7787
  if (!input.taskId || !input.workspaceDir) {
7655
7788
  return { accepted: false, reason: null };
7656
7789
  }
7657
- const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
7658
- const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
7659
- const taskResultPath = resolve21(artifactDir, "task-result.json");
7790
+ const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
7791
+ const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
7792
+ const taskResultPath = resolve22(artifactDir, "task-result.json");
7660
7793
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7661
7794
  if (reviewStatus !== "APPROVED") {
7662
7795
  return { accepted: false, reason: null };
@@ -7693,12 +7826,12 @@ function resolveTaskRunRetryContext(input) {
7693
7826
  if (!input.taskId || !input.workspaceDir) {
7694
7827
  return { shouldRetry: false, failureDetail: null, nextPrompt: null };
7695
7828
  }
7696
- const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
7697
- const reviewStatePath = resolve21(artifactDir, "review-state.json");
7698
- const reviewFeedbackPath = resolve21(artifactDir, "review-feedback.md");
7699
- const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
7700
- const failedApproachesPath = resolve21(input.workspaceDir, ".rig", "state", "failed_approaches.md");
7701
- const validationSummaryPath = resolve21(artifactDir, "validation-summary.json");
7829
+ const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
7830
+ const reviewStatePath = resolve22(artifactDir, "review-state.json");
7831
+ const reviewFeedbackPath = resolve22(artifactDir, "review-feedback.md");
7832
+ const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
7833
+ const failedApproachesPath = resolve22(input.workspaceDir, ".rig", "state", "failed_approaches.md");
7834
+ const validationSummaryPath = resolve22(artifactDir, "validation-summary.json");
7702
7835
  const reviewState = readJsonFile3(reviewStatePath, null);
7703
7836
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7704
7837
  const reviewRejected = isTaskRunReviewRejected(reviewState);
@@ -7753,11 +7886,11 @@ function summarizeTaskRunReviewFailure(reviewState) {
7753
7886
  return "Completion verification rejected the task. Read review-feedback.md for required fixes.";
7754
7887
  }
7755
7888
  function readTaskRunReviewStatus(reviewStatusPath) {
7756
- if (!existsSync12(reviewStatusPath)) {
7889
+ if (!existsSync13(reviewStatusPath)) {
7757
7890
  return null;
7758
7891
  }
7759
7892
  try {
7760
- const status = readFileSync10(reviewStatusPath, "utf8").trim().toUpperCase();
7893
+ const status = readFileSync11(reviewStatusPath, "utf8").trim().toUpperCase();
7761
7894
  return status === "APPROVED" || status === "REJECTED" ? status : null;
7762
7895
  } catch {
7763
7896
  return null;
@@ -7840,8 +7973,11 @@ function stringArrayField(record, key) {
7840
7973
  }
7841
7974
  async function executeRigOwnedTaskRun(context, input) {
7842
7975
  const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
7976
+ const existingRunRecord = readAuthorityRun5(context.projectRoot, input.runId);
7977
+ const resumeMode = process.env.RIG_RUN_RESUME === "1";
7978
+ const resumePreviousStatus = String(existingRunRecord?.status ?? "").toLowerCase();
7843
7979
  const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
7844
- const prompt = buildRunPrompt({
7980
+ let prompt = buildRunPrompt({
7845
7981
  projectRoot: context.projectRoot,
7846
7982
  taskId: input.taskId,
7847
7983
  fallbackTitle: input.title,
@@ -7895,14 +8031,14 @@ async function executeRigOwnedTaskRun(context, input) {
7895
8031
  taskId: runtimeTaskId,
7896
8032
  createdAt: startedAt,
7897
8033
  runtimeAdapter: input.runtimeAdapter,
7898
- status: "created"
8034
+ status: resumeMode ? "preparing" : "created"
7899
8035
  });
7900
8036
  patchAuthorityRun(context.projectRoot, input.runId, {
7901
8037
  status: "preparing",
7902
8038
  startedAt,
7903
8039
  completedAt: null,
7904
8040
  errorText: null,
7905
- artifactRoot: null,
8041
+ artifactRoot: resumeMode ? existingRunRecord?.artifactRoot ?? null : null,
7906
8042
  runtimeAdapter: input.runtimeAdapter,
7907
8043
  runtimeMode: input.runtimeMode,
7908
8044
  interactionMode: input.interactionMode,
@@ -7918,9 +8054,9 @@ async function executeRigOwnedTaskRun(context, input) {
7918
8054
  detail: input.taskId ?? input.title ?? runtimeTaskId
7919
8055
  });
7920
8056
  appendRunLog(context.projectRoot, input.runId, {
7921
- id: `log:${input.runId}:start`,
7922
- title: "Rig task run started",
7923
- detail: input.taskId ?? input.title ?? runtimeTaskId,
8057
+ id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
8058
+ title: resumeMode ? "Rig task run resumed" : "Rig task run started",
8059
+ detail: resumeMode ? `Continuing the same run lifecycle for ${input.taskId ?? input.title ?? runtimeTaskId}.` : input.taskId ?? input.title ?? runtimeTaskId,
7924
8060
  tone: "info",
7925
8061
  status: "preparing",
7926
8062
  createdAt: startedAt
@@ -7941,7 +8077,22 @@ async function executeRigOwnedTaskRun(context, input) {
7941
8077
  const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
7942
8078
  const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
7943
8079
  const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
7944
- patchAuthorityRun(context.projectRoot, input.runId, { planning: planningClassification });
8080
+ const planningArtifactPath = resolve22("artifacts", runtimeTaskId, "implementation-plan.md");
8081
+ const persistedPlanning = {
8082
+ ...planningClassification,
8083
+ classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
8084
+ artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
8085
+ classifiedAt: new Date().toISOString()
8086
+ };
8087
+ mkdirSync8(resolve22(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
8088
+ writeFileSync6(resolve22(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
8089
+ `, "utf8");
8090
+ patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
8091
+ prompt = `${prompt}
8092
+
8093
+ Rig planning classification:
8094
+ ${JSON.stringify(persistedPlanning, null, 2)}
8095
+ ${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."}`;
7945
8096
  if (input.runtimeAdapter === "pi") {
7946
8097
  for (const stage of ["Connect", "GitHub/task sync", "Prepare workspace", "Launch Pi", "Plan", "Implement"]) {
7947
8098
  appendPiStageLog({
@@ -7983,11 +8134,11 @@ async function executeRigOwnedTaskRun(context, input) {
7983
8134
  let reviewAction;
7984
8135
  let verificationStarted = false;
7985
8136
  let reviewStarted = false;
7986
- let latestRuntimeWorkspace = null;
7987
- let latestSessionDir = null;
7988
- let latestLogsDir = null;
8137
+ let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
8138
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve22(existingRunRecord.sessionPath, "..") : null;
8139
+ let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
7989
8140
  let latestProviderCommand = null;
7990
- let latestRuntimeBranch = null;
8141
+ let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
7991
8142
  let snapshotSidecarPromise = null;
7992
8143
  let dirtyBaselineApplied = false;
7993
8144
  const childEnv = {
@@ -8005,9 +8156,14 @@ async function executeRigOwnedTaskRun(context, input) {
8005
8156
  RIG_RUNTIME_ADAPTER: input.runtimeAdapter,
8006
8157
  RIG_SERVER_RUN_ID: input.runId
8007
8158
  },
8008
- ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
8159
+ ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {},
8160
+ ...resumeMode ? {
8161
+ RIG_RUN_RESUME: "1",
8162
+ RIG_RUNTIME_ARTIFACT_CLEANUP: "preserve"
8163
+ } : {}
8009
8164
  };
8010
8165
  Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
8166
+ Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
8011
8167
  const automationLimits = resolveTaskRunAutomationLimits(automationConfig);
8012
8168
  const maxAttempts = automationLimits.maxValidationAttempts;
8013
8169
  const promoteToValidating = (detail) => {
@@ -8062,22 +8218,29 @@ async function executeRigOwnedTaskRun(context, input) {
8062
8218
  patchAuthorityRun(context.projectRoot, input.runId, {
8063
8219
  status: "running",
8064
8220
  worktreePath: latestRuntimeWorkspace,
8065
- artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve21(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
8221
+ artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve22(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
8066
8222
  logRoot: latestLogsDir,
8067
- sessionPath: latestSessionDir ? resolve21(latestSessionDir, "session.json") : null,
8068
- sessionLogPath: latestLogsDir ? resolve21(latestLogsDir, "agent-stdout.log") : null,
8223
+ sessionPath: latestSessionDir ? resolve22(latestSessionDir, "session.json") : null,
8224
+ sessionLogPath: latestLogsDir ? resolve22(latestLogsDir, "agent-stdout.log") : null,
8069
8225
  branch: runtimeId
8070
8226
  });
8071
8227
  if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
8072
8228
  dirtyBaselineApplied = true;
8073
8229
  const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
8230
+ const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
8231
+ if (readyFile) {
8232
+ mkdirSync8(resolve22(readyFile, ".."), { recursive: true });
8233
+ writeFileSync6(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
8234
+ `, "utf8");
8235
+ }
8074
8236
  appendRunLog(context.projectRoot, input.runId, {
8075
8237
  id: `log:${input.runId}:dirty-baseline`,
8076
8238
  title: "Dirty baseline snapshot",
8077
8239
  detail: dirty.detail,
8078
8240
  tone: dirty.applied ? "tool" : "info",
8079
8241
  status: dirty.applied ? "completed" : "skipped",
8080
- createdAt: new Date().toISOString()
8242
+ createdAt: new Date().toISOString(),
8243
+ payload: readyFile ? { readyFile } : undefined
8081
8244
  });
8082
8245
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Dirty baseline snapshot" });
8083
8246
  }
@@ -8303,7 +8466,36 @@ async function executeRigOwnedTaskRun(context, input) {
8303
8466
  let reviewFailureDetail = null;
8304
8467
  const stderrLines = [];
8305
8468
  const piAcceptedArtifactExitGraceMs = resolvePiAcceptedArtifactExitGraceMs(childEnv);
8306
- for (let attempt = 1;attempt <= maxAttempts; attempt += 1) {
8469
+ if (resumeMode && ["validating", "reviewing"].includes(resumePreviousStatus)) {
8470
+ appendRunLog(context.projectRoot, input.runId, {
8471
+ id: `log:${input.runId}:resume-closeout-phase`,
8472
+ title: "Resume continuing from closeout phase",
8473
+ detail: `Previous run status was ${resumePreviousStatus}; skipping agent relaunch and continuing validation/PR/merge closeout for the same run.`,
8474
+ tone: "info",
8475
+ status: resumePreviousStatus,
8476
+ createdAt: new Date().toISOString()
8477
+ });
8478
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume continuing from closeout phase" });
8479
+ exit = { code: 0, signal: null };
8480
+ } else if (resumeMode && latestRuntimeWorkspace) {
8481
+ const acceptedArtifactState = readTaskRunAcceptedArtifactState({
8482
+ taskId: input.taskId ?? runtimeTaskId,
8483
+ workspaceDir: latestRuntimeWorkspace
8484
+ });
8485
+ if (acceptedArtifactState.accepted) {
8486
+ appendRunLog(context.projectRoot, input.runId, {
8487
+ id: `log:${input.runId}:resume-accepted-artifacts`,
8488
+ title: "Resume found accepted artifacts; continuing closeout",
8489
+ detail: acceptedArtifactState.reason ?? "Accepted task artifacts are present from the previous run process.",
8490
+ tone: "info",
8491
+ status: "validating",
8492
+ createdAt: new Date().toISOString()
8493
+ });
8494
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume found accepted artifacts; continuing closeout" });
8495
+ exit = { code: 0, signal: null };
8496
+ }
8497
+ }
8498
+ for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
8307
8499
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
8308
8500
  const child = spawn2(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
8309
8501
  cwd: context.projectRoot,
@@ -8344,7 +8536,7 @@ async function executeRigOwnedTaskRun(context, input) {
8344
8536
  let acceptedArtifactObservedAt = null;
8345
8537
  let acceptedArtifactPollTimer = null;
8346
8538
  let acceptedArtifactKillTimer = null;
8347
- const attemptExit = await new Promise((resolve22) => {
8539
+ const attemptExit = await new Promise((resolve23) => {
8348
8540
  let settled = false;
8349
8541
  const settle = (result) => {
8350
8542
  if (settled)
@@ -8352,7 +8544,7 @@ async function executeRigOwnedTaskRun(context, input) {
8352
8544
  settled = true;
8353
8545
  if (acceptedArtifactPollTimer)
8354
8546
  clearInterval(acceptedArtifactPollTimer);
8355
- resolve22(result);
8547
+ resolve23(result);
8356
8548
  };
8357
8549
  const pollAcceptedArtifacts = () => {
8358
8550
  const artifactState = readTaskRunAcceptedArtifactState({
@@ -8549,6 +8741,29 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8549
8741
  });
8550
8742
  throw new CliError2(terminalFailureDetail, exit.code ?? 1);
8551
8743
  }
8744
+ if (planningClassification.planningRequired) {
8745
+ const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
8746
+ const expectedPlanPath = resolve22(planWorkspace, planningArtifactPath);
8747
+ if (!existsSync13(expectedPlanPath)) {
8748
+ const failedAt = new Date().toISOString();
8749
+ const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
8750
+ patchAuthorityRun(context.projectRoot, input.runId, {
8751
+ status: "needs_attention",
8752
+ completedAt: failedAt,
8753
+ errorText: failureDetail
8754
+ });
8755
+ appendRunLog(context.projectRoot, input.runId, {
8756
+ id: `log:${input.runId}:plan-artifact-missing`,
8757
+ title: "Required plan artifact missing",
8758
+ detail: failureDetail,
8759
+ tone: "error",
8760
+ status: "needs_attention",
8761
+ createdAt: failedAt
8762
+ });
8763
+ emitServerRunEvent({ type: "failed", runId: input.runId, error: failureDetail });
8764
+ throw new CliError2(failureDetail, 1);
8765
+ }
8766
+ }
8552
8767
  const runPiPrFeedbackFix = async (message2) => {
8553
8768
  appendPiStageLog({
8554
8769
  projectRoot: context.projectRoot,
@@ -8606,9 +8821,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8606
8821
  });
8607
8822
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
8608
8823
  });
8609
- const exitCode = await new Promise((resolve22) => {
8610
- child.once("error", () => resolve22(1));
8611
- child.once("close", (code) => resolve22(code ?? 1));
8824
+ const exitCode = await new Promise((resolve23) => {
8825
+ child.once("error", () => resolve23(1));
8826
+ child.once("close", (code) => resolve23(code ?? 1));
8612
8827
  });
8613
8828
  if (exitCode !== 0) {
8614
8829
  throw new Error(`Pi PR feedback fix failed with exit code ${exitCode}.`);
@@ -8727,8 +8942,8 @@ async function executeTest(context, args) {
8727
8942
  }
8728
8943
 
8729
8944
  // packages/cli/src/commands/setup.ts
8730
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync6 } from "fs";
8731
- import { resolve as resolve22 } from "path";
8945
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync7 } from "fs";
8946
+ import { resolve as resolve23 } from "path";
8732
8947
  import { createPluginHost } from "@rig/core";
8733
8948
  import {
8734
8949
  isSupportedBunVersion as isSupportedBunVersion2,
@@ -8791,9 +9006,9 @@ function runSetupInit(projectRoot) {
8791
9006
  mkdirSync9(stateDir, { recursive: true });
8792
9007
  mkdirSync9(logsDir, { recursive: true });
8793
9008
  mkdirSync9(artifactsDir, { recursive: true });
8794
- const failuresPath = resolve22(stateDir, "failed_approaches.md");
8795
- if (!existsSync13(failuresPath)) {
8796
- writeFileSync6(failuresPath, `# Failed Approaches
9009
+ const failuresPath = resolve23(stateDir, "failed_approaches.md");
9010
+ if (!existsSync14(failuresPath)) {
9011
+ writeFileSync7(failuresPath, `# Failed Approaches
8797
9012
 
8798
9013
  `, "utf-8");
8799
9014
  }
@@ -8810,18 +9025,18 @@ async function runSetupCheck(projectRoot) {
8810
9025
  }
8811
9026
  async function runSetupPreflight(projectRoot) {
8812
9027
  await runSetupCheck(projectRoot);
8813
- const validationRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
8814
- if (existsSync13(validationRoot)) {
9028
+ const validationRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
9029
+ if (existsSync14(validationRoot)) {
8815
9030
  const validators = readdirSync2(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
8816
9031
  for (const validator of validators) {
8817
- const script = resolve22(validationRoot, validator.name, "validate.sh");
8818
- if (existsSync13(script)) {
9032
+ const script = resolve23(validationRoot, validator.name, "validate.sh");
9033
+ if (existsSync14(script)) {
8819
9034
  console.log(`OK: validator script ${script}`);
8820
9035
  }
8821
9036
  }
8822
9037
  }
8823
- const hooksRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
8824
- if (existsSync13(hooksRoot)) {
9038
+ const hooksRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
9039
+ if (existsSync14(hooksRoot)) {
8825
9040
  const hooks = readdirSync2(hooksRoot).filter((name) => name.endsWith(".sh"));
8826
9041
  for (const hook of hooks) {
8827
9042
  console.log(`OK: hook ${hook}`);
@@ -9198,8 +9413,8 @@ async function executeGroup(context, group, args) {
9198
9413
  }
9199
9414
  }
9200
9415
  // packages/cli/src/launcher.ts
9201
- import { existsSync as existsSync14 } from "fs";
9202
- import { resolve as resolve23 } from "path";
9416
+ import { existsSync as existsSync15 } from "fs";
9417
+ import { basename as basename2, resolve as resolve24 } from "path";
9203
9418
  import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
9204
9419
  import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
9205
9420
  function parsePolicyMode(value) {
@@ -9212,7 +9427,7 @@ function parsePolicyMode(value) {
9212
9427
  throw new Error(`Invalid --policy-mode value: ${value}. Use off|observe|enforce.`);
9213
9428
  }
9214
9429
  function hasRigProjectMarker(candidate) {
9215
- return existsSync14(resolve23(candidate, RIG_DEFINITION_DIRNAME)) || existsSync14(resolve23(candidate, RIG_STATE_DIRNAME)) || existsSync14(resolve23(candidate, "rig.config.ts")) || existsSync14(resolve23(candidate, "rig.config.json"));
9430
+ return existsSync15(resolve24(candidate, RIG_DEFINITION_DIRNAME)) || existsSync15(resolve24(candidate, RIG_STATE_DIRNAME)) || existsSync15(resolve24(candidate, "rig.config.ts")) || existsSync15(resolve24(candidate, "rig.config.json"));
9216
9431
  }
9217
9432
  function resolveProjectRoot({
9218
9433
  envProjectRoot,
@@ -9221,17 +9436,19 @@ function resolveProjectRoot({
9221
9436
  cwd = process.cwd()
9222
9437
  }) {
9223
9438
  if (envProjectRoot) {
9224
- return resolve23(cwd, envProjectRoot);
9439
+ return resolve24(cwd, envProjectRoot);
9225
9440
  }
9226
9441
  const fallbackImportDir = importDir ?? cwd;
9227
- const candidates = [cwd, resolve23(execPath, "..", ".."), resolve23(fallbackImportDir, "..")];
9442
+ const execName = basename2(execPath).toLowerCase();
9443
+ const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve24(execPath, "..", "..")] : [];
9444
+ const candidates = [cwd, ...execCandidates, resolve24(fallbackImportDir, "..")];
9228
9445
  for (const candidate of candidates) {
9229
9446
  const nearest = resolveNearestRigProjectRoot(candidate);
9230
9447
  if (hasRigProjectMarker(nearest)) {
9231
9448
  return nearest;
9232
9449
  }
9233
9450
  }
9234
- return resolve23(cwd);
9451
+ return resolve24(cwd);
9235
9452
  }
9236
9453
  function normalizeCliErrorCode(message2, isCliError) {
9237
9454
  if (message2.startsWith("Invalid --policy-mode value:")) {
@@ -9298,7 +9515,7 @@ async function runRigCli(module, options = {}) {
9298
9515
  runId: context.runId,
9299
9516
  outcome,
9300
9517
  eventsFile: context.eventBus.getEventsFile(),
9301
- policyFile: resolve23(projectRoot, "rig", "policy", "policy.json"),
9518
+ policyFile: resolve24(projectRoot, "rig", "policy", "policy.json"),
9302
9519
  policyMode: context.policyMode ?? policyMode ?? module.loadPolicy(projectRoot).mode
9303
9520
  }, null, 2));
9304
9521
  }