@h-rig/cli 0.0.6-alpha.12 → 0.0.6-alpha.14

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/src/index.js CHANGED
@@ -2667,17 +2667,17 @@ function resolveSelectedConnection(projectRoot, options = {}) {
2667
2667
  }
2668
2668
 
2669
2669
  // packages/cli/src/commands/_server-client.ts
2670
- import { spawnSync } from "child_process";
2671
2670
  import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
2672
2671
  import { resolve as resolve9 } from "path";
2673
2672
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
2674
- var cachedGitHubBearerToken;
2673
+ var scopedGitHubBearerTokens = new Map;
2675
2674
  function cleanToken(value) {
2676
2675
  const trimmed = value?.trim();
2677
2676
  return trimmed ? trimmed : null;
2678
2677
  }
2679
- function setGitHubBearerTokenForCurrentProcess(token) {
2680
- cachedGitHubBearerToken = cleanToken(token ?? undefined);
2678
+ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
2679
+ const scopedKey = resolve9(projectRoot ?? process.cwd());
2680
+ scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
2681
2681
  }
2682
2682
  function readPrivateRemoteSessionToken(projectRoot) {
2683
2683
  const path = resolve9(projectRoot, ".rig", "state", "github-auth.json");
@@ -2691,25 +2691,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
2691
2691
  }
2692
2692
  }
2693
2693
  function readGitHubBearerTokenForRemote(projectRoot) {
2694
- if (cachedGitHubBearerToken !== undefined)
2695
- return cachedGitHubBearerToken;
2694
+ const scopedKey = resolve9(projectRoot);
2695
+ if (scopedGitHubBearerTokens.has(scopedKey))
2696
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
2696
2697
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
2697
- if (privateSession) {
2698
- cachedGitHubBearerToken = privateSession;
2699
- return cachedGitHubBearerToken;
2700
- }
2701
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
2702
- if (envToken) {
2703
- cachedGitHubBearerToken = envToken;
2704
- return cachedGitHubBearerToken;
2705
- }
2706
- const result = spawnSync("gh", ["auth", "token"], {
2707
- encoding: "utf8",
2708
- timeout: 5000,
2709
- stdio: ["ignore", "pipe", "ignore"]
2710
- });
2711
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
2712
- return cachedGitHubBearerToken;
2698
+ if (privateSession)
2699
+ return privateSession;
2700
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
2713
2701
  }
2714
2702
  async function ensureServerForCli(projectRoot) {
2715
2703
  try {
@@ -2907,6 +2895,37 @@ async function getRunLogsViaServer(context, runId, options = {}) {
2907
2895
  const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
2908
2896
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
2909
2897
  }
2898
+ async function getRunTimelineViaServer(context, runId, options = {}) {
2899
+ const url = new URL(`http://rig.local/api/runs/${encodeURIComponent(runId)}/timeline`);
2900
+ if (options.limit !== undefined)
2901
+ url.searchParams.set("limit", String(options.limit));
2902
+ if (options.cursor)
2903
+ url.searchParams.set("cursor", options.cursor);
2904
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
2905
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
2906
+ }
2907
+ async function ensureTaskLabelsViaServer(context) {
2908
+ const payload = await requestServerJson(context, "/api/workspace/task-labels", { method: "POST" });
2909
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2910
+ }
2911
+ async function listGitHubProjectsViaServer(context, owner) {
2912
+ const url = new URL("http://rig.local/api/github/projects");
2913
+ url.searchParams.set("owner", owner);
2914
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
2915
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { projects: [] };
2916
+ }
2917
+ async function getGitHubProjectStatusFieldViaServer(context, projectId) {
2918
+ const payload = await requestServerJson(context, `/api/github/projects/${encodeURIComponent(projectId)}/status-field`);
2919
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2920
+ }
2921
+ async function updateWorkspaceTaskViaServer(context, input) {
2922
+ const payload = await requestServerJson(context, "/api/tasks/update", {
2923
+ method: "POST",
2924
+ headers: { "content-type": "application/json" },
2925
+ body: JSON.stringify(input)
2926
+ });
2927
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
2928
+ }
2910
2929
  async function stopRunViaServer(context, runId) {
2911
2930
  const payload = await requestServerJson(context, "/api/runs/stop", {
2912
2931
  method: "POST",
@@ -3186,6 +3205,9 @@ function permissionAllowsPr(payload) {
3186
3205
  }
3187
3206
  return null;
3188
3207
  }
3208
+ function isNotFoundError(error) {
3209
+ return /\b(404|not found)\b/i.test(message(error));
3210
+ }
3189
3211
  function projectCheckoutReady(payload) {
3190
3212
  if (!payload || typeof payload !== "object" || Array.isArray(payload))
3191
3213
  return null;
@@ -3218,19 +3240,33 @@ async function runFastTaskRunPreflight(context, options = {}) {
3218
3240
  const checks = [];
3219
3241
  const request = options.requestJson ?? ((pathname, init) => requestServerJson(context, pathname, init));
3220
3242
  const taskId = options.taskId?.trim() || null;
3243
+ const requiresCurrentRunApi = Boolean(taskId);
3244
+ const selectedServer = options.requestJson ? null : await ensureServerForCli(context.projectRoot).catch(() => null);
3245
+ const allowLocalLegacyTaskRunCompatibility = selectedServer?.connectionKind === "local";
3246
+ let legacyServerCompatibility = false;
3221
3247
  try {
3222
3248
  await request("/api/server/status");
3223
3249
  checks.push(preflightCheck("server", "Rig server reachable", "pass"));
3224
3250
  } catch (error) {
3225
- checks.push(preflightCheck("server", "Rig server reachable", "fail", message(error), "Start or select a reachable Rig server."));
3251
+ if (isNotFoundError(error)) {
3252
+ try {
3253
+ await request("/health");
3254
+ legacyServerCompatibility = !requiresCurrentRunApi || allowLocalLegacyTaskRunCompatibility;
3255
+ checks.push(requiresCurrentRunApi && !allowLocalLegacyTaskRunCompatibility ? preflightCheck("server", "Rig server reachable", "fail", "legacy /health endpoint only; current task-run APIs are required", "Upgrade/select the Rig server before launching a task run.") : preflightCheck("server", "Rig server reachable", "pass", allowLocalLegacyTaskRunCompatibility ? "local legacy /health endpoint; submit endpoint will be authoritative" : "legacy /health endpoint"));
3256
+ } catch (healthError) {
3257
+ checks.push(preflightCheck("server", "Rig server reachable", "fail", message(healthError), "Start or select a reachable Rig server."));
3258
+ }
3259
+ } else {
3260
+ checks.push(preflightCheck("server", "Rig server reachable", "fail", message(error), "Start or select a reachable Rig server."));
3261
+ }
3226
3262
  }
3227
3263
  const repo = readRepoConnection(context.projectRoot);
3228
- checks.push(repo ? preflightCheck("project-link", "project linked to Rig connection", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to record the GitHub repo slug.") : preflightCheck("project-link", "project linked to Rig connection", "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig connect use <alias|local>`."));
3264
+ checks.push(repo ? preflightCheck("project-link", "project linked to Rig connection", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to record the GitHub repo slug.") : preflightCheck("project-link", "project linked to Rig connection", legacyServerCompatibility ? "warn" : "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig connect use <alias|local>`."));
3229
3265
  try {
3230
3266
  const auth = await request("/api/github/auth/status");
3231
- checks.push(isAuthenticated(auth) ? preflightCheck("github-auth", "GitHub auth valid", "pass") : preflightCheck("github-auth", "GitHub auth valid", "fail", "not authenticated", "Run `rig github auth import-gh` or `rig github auth token --token <token>`."));
3267
+ checks.push(isAuthenticated(auth) ? preflightCheck("github-auth", "GitHub auth valid", "pass") : preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", "not authenticated", "Run `rig github auth import-gh` or `rig github auth token --token <token>`."));
3232
3268
  } catch (error) {
3233
- checks.push(preflightCheck("github-auth", "GitHub auth valid", "fail", message(error), "Fix GitHub auth on the selected Rig server."));
3269
+ checks.push(preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix GitHub auth on the selected Rig server."));
3234
3270
  }
3235
3271
  try {
3236
3272
  const projection = await request("/api/workspace/task-projection");
@@ -3258,9 +3294,9 @@ async function runFastTaskRunPreflight(context, options = {}) {
3258
3294
  try {
3259
3295
  const tasks = await request(`/api/workspace/tasks?limit=200&refresh=1`);
3260
3296
  const found = Array.isArray(tasks) && tasks.some((task) => taskMatchesId(task, taskId));
3261
- checks.push(found ? preflightCheck("issue", "task/issue accessible", "pass", taskId) : preflightCheck("issue", "task/issue accessible", "fail", taskId, "Confirm the issue exists and matches the configured task filters."));
3297
+ checks.push(found ? preflightCheck("issue", "task/issue accessible", "pass", taskId) : preflightCheck("issue", "task/issue accessible", legacyServerCompatibility ? "warn" : "fail", taskId, "Confirm the issue exists and matches the configured task filters."));
3262
3298
  } catch (error) {
3263
- checks.push(preflightCheck("issue", "task/issue accessible", "fail", message(error), "Fix the task source before launching a run."));
3299
+ checks.push(preflightCheck("issue", "task/issue accessible", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix the task source before launching a run."));
3264
3300
  }
3265
3301
  try {
3266
3302
  const runs = await request("/api/runs?limit=200");
@@ -4172,9 +4208,10 @@ async function executeInbox(context, args) {
4172
4208
 
4173
4209
  // packages/cli/src/commands/init.ts
4174
4210
  import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
4175
- import { spawnSync as spawnSync2 } from "child_process";
4211
+ import { spawnSync } from "child_process";
4176
4212
  import { resolve as resolve17 } from "path";
4177
4213
  import { buildRigInitConfigSource } from "@rig/core";
4214
+ import { listGitHubProjects as listGitHubProjectsDirect, resolveProjectStatusField as resolveProjectStatusFieldDirect } from "@rig/server";
4178
4215
 
4179
4216
  // packages/cli/src/commands/_snapshot-upload.ts
4180
4217
  import { mkdir, readdir, readFile, writeFile } from "fs/promises";
@@ -4498,7 +4535,7 @@ function parseRepoSlugFromRemote(remoteUrl) {
4498
4535
  return gitHubMatch ? `${gitHubMatch[1]}/${gitHubMatch[2]}` : null;
4499
4536
  }
4500
4537
  function detectOriginRepoSlug(projectRoot) {
4501
- const result = spawnSync2("git", ["-C", projectRoot, "remote", "get-url", "origin"], { encoding: "utf8" });
4538
+ const result = spawnSync("git", ["-C", projectRoot, "remote", "get-url", "origin"], { encoding: "utf8" });
4502
4539
  if (result.status !== 0)
4503
4540
  return null;
4504
4541
  return parseRepoSlugFromRemote(result.stdout.trim());
@@ -4554,11 +4591,14 @@ function applyGitHubProjectConfig(source, options) {
4554
4591
  return source;
4555
4592
  const projectId = JSON.stringify(options.githubProject);
4556
4593
  const statusFieldId = JSON.stringify(options.githubProjectStatusField ?? "Status");
4594
+ const statuses = options.githubProjectStatuses && Object.keys(options.githubProjectStatuses).length > 0 ? `
4595
+ statuses: ${JSON.stringify(options.githubProjectStatuses, null, 8).replace(/\n/g, `
4596
+ `)},` : "";
4557
4597
  return source.replace(` projects: { enabled: false },`, [
4558
4598
  ` projects: {`,
4559
4599
  ` enabled: true,`,
4560
4600
  ` projectId: ${projectId},`,
4561
- ` statusFieldId: ${statusFieldId},`,
4601
+ ` statusFieldId: ${statusFieldId},${statuses}`,
4562
4602
  ` },`
4563
4603
  ].join(`
4564
4604
  `));
@@ -4579,11 +4619,11 @@ function checkoutForInit(projectRoot, serverKind, strategy) {
4579
4619
  }
4580
4620
  }
4581
4621
  function detectGhLogin() {
4582
- const result = spawnSync2("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] });
4622
+ const result = spawnSync("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] });
4583
4623
  return result.status === 0 && result.stdout.trim() ? result.stdout.trim() : null;
4584
4624
  }
4585
4625
  function readGhAuthToken() {
4586
- const result = spawnSync2("gh", ["auth", "token"], { encoding: "utf8" });
4626
+ const result = spawnSync("gh", ["auth", "token"], { encoding: "utf8" });
4587
4627
  if (result.status !== 0 || !result.stdout.trim()) {
4588
4628
  throw new CliError2(result.stderr.trim() || "Could not read GitHub token from `gh auth token`.", result.status || 1);
4589
4629
  }
@@ -4592,8 +4632,15 @@ function readGhAuthToken() {
4592
4632
  async function loadClackPrompts() {
4593
4633
  return await import("@clack/prompts");
4594
4634
  }
4635
+ function clackTextOptions(options) {
4636
+ return {
4637
+ message: options.message,
4638
+ ...options.placeholder ? { placeholder: options.placeholder } : {},
4639
+ ...(options.initialValue ?? options.defaultValue)?.trim() ? { initialValue: (options.initialValue ?? options.defaultValue).trim() } : {}
4640
+ };
4641
+ }
4595
4642
  async function promptRequiredText(prompts, options) {
4596
- const value = await prompts.text(options);
4643
+ const value = await prompts.text(clackTextOptions(options));
4597
4644
  if (prompts.isCancel(value))
4598
4645
  throw new CliError2("Init cancelled.", 1);
4599
4646
  const text2 = String(value ?? "").trim();
@@ -4602,7 +4649,7 @@ async function promptRequiredText(prompts, options) {
4602
4649
  return text2;
4603
4650
  }
4604
4651
  async function promptOptionalText(prompts, options) {
4605
- const value = await prompts.text(options);
4652
+ const value = await prompts.text(clackTextOptions(options));
4606
4653
  if (prompts.isCancel(value))
4607
4654
  throw new CliError2("Init cancelled.", 1);
4608
4655
  return String(value ?? "").trim();
@@ -4613,6 +4660,132 @@ async function promptSelect(prompts, options) {
4613
4660
  throw new CliError2("Init cancelled.", 1);
4614
4661
  return String(value);
4615
4662
  }
4663
+ function repoOwnerFromSlug(repoSlug) {
4664
+ return repoSlug.trim().match(/^([^/]+)\/[^/]+$/)?.[1] ?? null;
4665
+ }
4666
+ function recordArray(value, key) {
4667
+ if (!value || typeof value !== "object" || Array.isArray(value))
4668
+ return [];
4669
+ const raw = value[key];
4670
+ return Array.isArray(raw) ? raw.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
4671
+ }
4672
+ async function listGitHubProjectsForInit(context, owner, token) {
4673
+ if (token?.trim()) {
4674
+ try {
4675
+ return { ok: true, projects: await listGitHubProjectsDirect({ owner, token: token.trim() }) };
4676
+ } catch (directError) {
4677
+ const serverPayload = await listGitHubProjectsViaServer(context, owner).catch(() => null);
4678
+ if (recordArray(serverPayload, "projects").length > 0)
4679
+ return serverPayload;
4680
+ return { ok: false, error: directError instanceof Error ? directError.message : String(directError), projects: [] };
4681
+ }
4682
+ }
4683
+ return listGitHubProjectsViaServer(context, owner);
4684
+ }
4685
+ async function getGitHubProjectStatusFieldForInit(context, projectId, token) {
4686
+ if (token?.trim()) {
4687
+ try {
4688
+ return { ok: true, field: await resolveProjectStatusFieldDirect({ projectId, token: token.trim() }) };
4689
+ } catch (directError) {
4690
+ const serverPayload = await getGitHubProjectStatusFieldViaServer(context, projectId).catch(() => null);
4691
+ if (serverPayload && typeof serverPayload === "object" && !Array.isArray(serverPayload) && "field" in serverPayload) {
4692
+ return serverPayload;
4693
+ }
4694
+ return { ok: false, error: directError instanceof Error ? directError.message : String(directError) };
4695
+ }
4696
+ }
4697
+ return getGitHubProjectStatusFieldViaServer(context, projectId);
4698
+ }
4699
+ var PROJECT_STATUS_PROMPTS = {
4700
+ running: "Running/In progress",
4701
+ prOpen: "PR open/review",
4702
+ ciFixing: "CI/review fixing",
4703
+ merging: "Merging",
4704
+ done: "Done",
4705
+ needsAttention: "Needs attention"
4706
+ };
4707
+ var DEFAULT_PROJECT_STATUS_OPTIONS = {
4708
+ running: "In Progress",
4709
+ prOpen: "In Review",
4710
+ ciFixing: "In Review",
4711
+ merging: "Merging",
4712
+ done: "Done",
4713
+ needsAttention: "Needs Attention"
4714
+ };
4715
+ async function promptManualProjectStatusMapping(prompts) {
4716
+ const statuses = {};
4717
+ for (const [key, label] of Object.entries(PROJECT_STATUS_PROMPTS)) {
4718
+ const defaultLabel = DEFAULT_PROJECT_STATUS_OPTIONS[key] ?? label;
4719
+ const value = await promptOptionalText(prompts, {
4720
+ message: `Project status option id/name for ${label} (blank for ${defaultLabel})`,
4721
+ placeholder: defaultLabel
4722
+ });
4723
+ statuses[key] = value || defaultLabel;
4724
+ }
4725
+ return statuses;
4726
+ }
4727
+ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken) {
4728
+ const projectChoice = await promptSelect(prompts, {
4729
+ message: "GitHub Projects status sync",
4730
+ options: [
4731
+ { value: "off", label: "Off" },
4732
+ { value: "select", label: "Select accessible ProjectV2" },
4733
+ { value: "manual", label: "Enter ProjectV2 ids manually" }
4734
+ ]
4735
+ });
4736
+ if (projectChoice === "off")
4737
+ return { githubProject: "off" };
4738
+ if (projectChoice === "manual") {
4739
+ return {
4740
+ githubProject: await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }),
4741
+ githubProjectStatusField: await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }),
4742
+ githubProjectStatuses: await promptManualProjectStatusMapping(prompts)
4743
+ };
4744
+ }
4745
+ const owner = repoOwnerFromSlug(repoSlug);
4746
+ if (!owner)
4747
+ throw new CliError2(`Cannot derive GitHub owner from repo slug ${repoSlug}.`, 1);
4748
+ const projectsPayload = await listGitHubProjectsForInit(context, owner, githubToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
4749
+ const projects = recordArray(projectsPayload, "projects");
4750
+ if (projects.length === 0) {
4751
+ const error = typeof projectsPayload.error === "string" ? ` (${projectsPayload.error})` : "";
4752
+ prompts.outro?.(`No accessible GitHub Projects were returned${error}; falling back to manual ProjectV2 ids.`);
4753
+ return {
4754
+ githubProject: await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }),
4755
+ githubProjectStatusField: await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }),
4756
+ githubProjectStatuses: await promptManualProjectStatusMapping(prompts)
4757
+ };
4758
+ }
4759
+ const selectedProjectId = await promptSelect(prompts, {
4760
+ message: "GitHub ProjectV2 project",
4761
+ options: [
4762
+ ...projects.map((project) => ({
4763
+ value: String(project.id),
4764
+ label: `${String(project.title ?? "Untitled project")} (#${String(project.number ?? "?")})`,
4765
+ hint: typeof project.url === "string" ? project.url : undefined
4766
+ })),
4767
+ { value: "manual", label: "Enter ProjectV2 id manually" }
4768
+ ]
4769
+ });
4770
+ const projectId = selectedProjectId === "manual" ? await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }) : selectedProjectId;
4771
+ const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId, githubToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
4772
+ const fieldPayloadRecord = fieldPayload && typeof fieldPayload === "object" && !Array.isArray(fieldPayload) ? fieldPayload : {};
4773
+ const rawField = fieldPayloadRecord.field;
4774
+ const field = rawField && typeof rawField === "object" && !Array.isArray(rawField) ? rawField : null;
4775
+ const fieldId = typeof field?.id === "string" && field.id.trim() ? field.id : await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" });
4776
+ const options = Array.isArray(field?.options) ? field.options.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
4777
+ if (options.length === 0) {
4778
+ return { githubProject: projectId, githubProjectStatusField: fieldId, githubProjectStatuses: await promptManualProjectStatusMapping(prompts) };
4779
+ }
4780
+ const statuses = {};
4781
+ for (const [key, label] of Object.entries(PROJECT_STATUS_PROMPTS)) {
4782
+ statuses[key] = await promptSelect(prompts, {
4783
+ message: `Project status option for ${label}`,
4784
+ options: options.map((option) => ({ value: String(option.id ?? option.name), label: String(option.name ?? option.id) }))
4785
+ });
4786
+ }
4787
+ return { githubProject: projectId, githubProjectStatusField: fieldId, githubProjectStatuses: Object.keys(statuses).length > 0 ? statuses : undefined };
4788
+ }
4616
4789
  function sleep2(ms) {
4617
4790
  return new Promise((resolve18) => setTimeout(resolve18, ms));
4618
4791
  }
@@ -4741,7 +4914,7 @@ async function runControlPlaneInit(context, options) {
4741
4914
  if (token) {
4742
4915
  githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug });
4743
4916
  const apiSessionToken = apiSessionTokenFrom(githubAuth);
4744
- setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4917
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token, projectRoot);
4745
4918
  if (serverKind === "remote") {
4746
4919
  writeRemoteGitHubAuthState(projectRoot, {
4747
4920
  source: authMethod === "gh" ? "gh" : "init-token",
@@ -4766,7 +4939,7 @@ async function runControlPlaneInit(context, options) {
4766
4939
  if (completed) {
4767
4940
  const apiSessionToken = apiSessionTokenFrom(completed);
4768
4941
  if (apiSessionToken) {
4769
- setGitHubBearerTokenForCurrentProcess(apiSessionToken);
4942
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken, projectRoot);
4770
4943
  if (serverKind === "remote") {
4771
4944
  writeRemoteGitHubAuthState(projectRoot, { source: "device", selectedRepo: repo.slug, apiSessionToken, authPayload: completed });
4772
4945
  }
@@ -4790,7 +4963,7 @@ async function runControlPlaneInit(context, options) {
4790
4963
  if (serverKind === "remote" && checkoutPath && token) {
4791
4964
  githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug, projectRoot: checkoutPath });
4792
4965
  const apiSessionToken = apiSessionTokenFrom(githubAuth);
4793
- setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
4966
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token, projectRoot);
4794
4967
  writeRemoteGitHubAuthState(projectRoot, { source: authMethod === "gh" ? "gh" : "init-token", selectedRepo: repo.slug, apiSessionToken, authPayload: githubAuth });
4795
4968
  }
4796
4969
  const registered = await registerProjectViaServer(context, {
@@ -4799,6 +4972,12 @@ async function runControlPlaneInit(context, options) {
4799
4972
  });
4800
4973
  const serverRootSwitch = serverKind === "remote" && checkoutPath ? await switchServerProjectRootViaServer(context, checkoutPath) : null;
4801
4974
  const activeProjectRegistration = serverRootSwitch ? await registerProjectViaServer(context, { repoSlug: repo.slug, checkout }) : null;
4975
+ const labelSetup = await ensureTaskLabelsViaServer(context).catch((error) => ({
4976
+ ok: false,
4977
+ ready: false,
4978
+ labelsReady: false,
4979
+ error: error instanceof Error ? error.message : String(error)
4980
+ }));
4802
4981
  const pi = serverKind === "remote" ? await ensureRemotePiRigInstalled({ requestJson: (pathname, init) => requestServerJson(context, pathname, init) }).catch((error) => ({
4803
4982
  remote: true,
4804
4983
  pi: { ok: false, label: "pi", hint: error instanceof Error ? error.message : String(error) },
@@ -4829,6 +5008,7 @@ async function runControlPlaneInit(context, options) {
4829
5008
  githubAuth,
4830
5009
  deviceAuth,
4831
5010
  githubAuthWarning: remoteGhTokenWarning,
5011
+ labelSetup,
4832
5012
  pi,
4833
5013
  doctor
4834
5014
  };
@@ -4983,24 +5163,17 @@ async function runInteractiveControlPlaneInit(context, prompts) {
4983
5163
  throw new CliError2("Remote gh-token import cancelled.", 1);
4984
5164
  }
4985
5165
  }
4986
- const githubToken = authMethod === "token" ? await promptRequiredText(prompts, { message: "GitHub token", placeholder: "ghp_..." }) : undefined;
4987
- const projectChoice = await promptSelect(prompts, {
4988
- message: "GitHub Projects status sync",
4989
- options: [
4990
- { value: "off", label: "Off" },
4991
- { value: "configure", label: "Configure ProjectV2 status field" }
4992
- ]
4993
- });
4994
- const githubProject = projectChoice === "configure" ? await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }) : "off";
4995
- const githubProjectStatusField = projectChoice === "configure" ? await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }) : undefined;
5166
+ const githubToken = authMethod === "token" ? await promptRequiredText(prompts, { message: "GitHub token", placeholder: "ghp_..." }) : authMethod === "gh" ? readGhAuthToken() : undefined;
5167
+ const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken);
4996
5168
  const result = await runControlPlaneInit(context, {
4997
5169
  server: serverChoice,
4998
5170
  remoteUrl,
4999
5171
  repoSlug,
5000
5172
  githubToken,
5001
5173
  githubAuthMethod: authMethod,
5002
- githubProject,
5003
- githubProjectStatusField,
5174
+ githubProject: projectConfig.githubProject,
5175
+ githubProjectStatusField: projectConfig.githubProjectStatusField,
5176
+ githubProjectStatuses: projectConfig.githubProjectStatuses,
5004
5177
  remoteCheckout,
5005
5178
  repair,
5006
5179
  privateStateOnly
@@ -5099,7 +5272,7 @@ Usage: rig connect <list|add|use|status>`, 1);
5099
5272
  }
5100
5273
 
5101
5274
  // packages/cli/src/commands/github.ts
5102
- import { spawnSync as spawnSync3 } from "child_process";
5275
+ import { spawnSync as spawnSync2 } from "child_process";
5103
5276
  function printPayload(context, payload, fallback) {
5104
5277
  if (context.outputMode === "json")
5105
5278
  console.log(JSON.stringify(payload, null, 2));
@@ -5107,7 +5280,7 @@ function printPayload(context, payload, fallback) {
5107
5280
  console.log(fallback);
5108
5281
  }
5109
5282
  function readGhToken() {
5110
- const result = spawnSync3("gh", ["auth", "token"], { encoding: "utf8" });
5283
+ const result = spawnSync2("gh", ["auth", "token"], { encoding: "utf8" });
5111
5284
  if (result.status !== 0) {
5112
5285
  const detail = result.stderr?.trim() || result.stdout?.trim() || "gh auth token failed";
5113
5286
  throw new CliError2(`Could not import GitHub token from gh: ${detail}`, 1);
@@ -6139,14 +6312,10 @@ async function executeRemote(context, args) {
6139
6312
  }
6140
6313
 
6141
6314
  // packages/cli/src/commands/run.ts
6142
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
6143
- import { resolve as resolve20 } from "path";
6144
6315
  import { createInterface as createInterface2 } from "readline/promises";
6145
6316
  import {
6146
6317
  listAuthorityRuns as listAuthorityRuns3,
6147
- readAuthorityRun as readAuthorityRun4,
6148
- readJsonlFile as readJsonlFile4,
6149
- resolveAuthorityRunDir as resolveAuthorityRunDir5
6318
+ readAuthorityRun as readAuthorityRun4
6150
6319
  } from "@rig/runtime/control-plane/authority-files";
6151
6320
  import {
6152
6321
  cleanupRunState,
@@ -6162,9 +6331,9 @@ import {
6162
6331
  } from "@rig/runtime/control-plane/native/run-ops";
6163
6332
  import { loadRuntimeContextFromEnv as loadRuntimeContextFromEnv2 } from "@rig/runtime/control-plane/runtime/context";
6164
6333
 
6165
- // packages/cli/src/commands/_operator-view.ts
6334
+ // packages/cli/src/commands/_operator-surface.ts
6166
6335
  import { createInterface } from "readline";
6167
- var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
6336
+ import { createInterface as createPromptInterface } from "readline/promises";
6168
6337
  var CANONICAL_STAGES = [
6169
6338
  "Connect",
6170
6339
  "GitHub/task sync",
@@ -6179,18 +6348,141 @@ var CANONICAL_STAGES = [
6179
6348
  "Merge",
6180
6349
  "Complete"
6181
6350
  ];
6351
+ function logDetail(log3) {
6352
+ return typeof log3.detail === "string" ? log3.detail.trim() : "";
6353
+ }
6354
+ function entryId(entry, fallback) {
6355
+ return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
6356
+ }
6182
6357
  function renderOperatorSnapshot(snapshot) {
6183
6358
  const run = snapshot.run.run && typeof snapshot.run.run === "object" ? snapshot.run.run : snapshot.run;
6184
6359
  const runId = String(run.runId ?? run.id ?? "run");
6185
6360
  const status = String(run.status ?? "unknown");
6186
6361
  const logs = snapshot.logs ?? [];
6362
+ const latestByStage = new Map;
6363
+ for (const log3 of logs) {
6364
+ const title = String(log3.title ?? "").toLowerCase();
6365
+ const stageName = String(log3.stage ?? "").toLowerCase();
6366
+ const stage = CANONICAL_STAGES.find((candidate) => candidate.toLowerCase() === title || candidate.toLowerCase() === stageName);
6367
+ if (stage)
6368
+ latestByStage.set(stage, log3);
6369
+ }
6187
6370
  const stageLines = CANONICAL_STAGES.flatMap((stage) => {
6188
- const match = logs.find((log3) => String(log3.title ?? "").toLowerCase() === stage.toLowerCase() || String(log3.stage ?? "").toLowerCase() === stage.toLowerCase());
6189
- return match ? [`${stage}: ${String(match.status ?? status)}`] : [];
6371
+ const match = latestByStage.get(stage);
6372
+ return match ? [`${stage}: ${String(match.status ?? status)}${logDetail(match) ? ` \u2014 ${logDetail(match)}` : ""}`] : [];
6190
6373
  });
6191
6374
  return [`Rig run ${runId}: ${status}`, ...stageLines].join(`
6192
6375
  `);
6193
6376
  }
6377
+ function createPiRunStreamRenderer(output = process.stdout) {
6378
+ let lastSnapshot = "";
6379
+ const assistantTextById = new Map;
6380
+ const seenTimeline = new Set;
6381
+ const seenLogs = new Set;
6382
+ const writeLine = (line) => output.write(`${line}
6383
+ `);
6384
+ return {
6385
+ renderSnapshot(snapshot) {
6386
+ const rendered = renderOperatorSnapshot(snapshot);
6387
+ if (rendered && rendered !== lastSnapshot) {
6388
+ writeLine(rendered);
6389
+ lastSnapshot = rendered;
6390
+ }
6391
+ },
6392
+ renderTimeline(entries) {
6393
+ for (const [index, entry] of entries.entries()) {
6394
+ const id = entryId(entry, `timeline:${index}:${String(entry.cursor ?? "")}`);
6395
+ if (entry.type === "assistant_message" && typeof entry.text === "string") {
6396
+ const text2 = entry.text;
6397
+ const previousText = assistantTextById.get(id) ?? "";
6398
+ if (text2.startsWith(previousText)) {
6399
+ const delta = text2.slice(previousText.length);
6400
+ if (delta)
6401
+ output.write(delta);
6402
+ } else if (text2.trim() && text2 !== previousText) {
6403
+ writeLine(`
6404
+ [Pi assistant]`);
6405
+ output.write(text2);
6406
+ }
6407
+ assistantTextById.set(id, text2);
6408
+ continue;
6409
+ }
6410
+ if (seenTimeline.has(id))
6411
+ continue;
6412
+ seenTimeline.add(id);
6413
+ if (entry.type === "tool_execution_start" || entry.type === "tool_execution_update" || entry.type === "tool_execution_end" || entry.type === "mcp_tool_call") {
6414
+ writeLine(`[Pi tool] ${String(entry.toolName ?? entry.name ?? entry.title ?? entry.type)} ${String(entry.status ?? entry.state ?? "")}`.trim());
6415
+ continue;
6416
+ }
6417
+ if (entry.type === "timeline_warning") {
6418
+ writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
6419
+ }
6420
+ }
6421
+ },
6422
+ renderLogs(entries) {
6423
+ for (const [index, entry] of entries.entries()) {
6424
+ const id = entryId(entry, `log:${index}:${String(entry.createdAt ?? "")}:${String(entry.title ?? "")}`);
6425
+ if (seenLogs.has(id))
6426
+ continue;
6427
+ seenLogs.add(id);
6428
+ const title = String(entry.title ?? "");
6429
+ if (CANONICAL_STAGES.some((stage) => stage.toLowerCase() === title.toLowerCase()))
6430
+ continue;
6431
+ const detail = logDetail(entry);
6432
+ if (!detail)
6433
+ continue;
6434
+ writeLine(`[${title || "Rig log"}] ${detail}`);
6435
+ }
6436
+ }
6437
+ };
6438
+ }
6439
+ function createOperatorSurface(options = {}) {
6440
+ const input = options.input ?? process.stdin;
6441
+ const output = options.output ?? process.stdout;
6442
+ const errorOutput = options.errorOutput ?? process.stderr;
6443
+ const renderer = createPiRunStreamRenderer(output);
6444
+ const writeLine = (line) => output.write(`${line}
6445
+ `);
6446
+ return {
6447
+ mode: "pi-compatible-text",
6448
+ ...renderer,
6449
+ info: writeLine,
6450
+ error: (message2) => errorOutput.write(`${message2}
6451
+ `),
6452
+ attachCommandInput(handler) {
6453
+ if (options.interactive === false || !input.isTTY)
6454
+ return null;
6455
+ const rl = createInterface({ input, output: process.stdout, terminal: false });
6456
+ rl.on("line", (line) => {
6457
+ Promise.resolve(handler(line)).catch((error) => writeLine(`Operator command failed: ${error instanceof Error ? error.message : String(error)}`));
6458
+ });
6459
+ return { close: () => rl.close() };
6460
+ }
6461
+ };
6462
+ }
6463
+ function taskId(task) {
6464
+ return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
6465
+ }
6466
+ function taskTitle(task) {
6467
+ return typeof task.title === "string" && task.title.trim() ? task.title : "Untitled task";
6468
+ }
6469
+ function taskStatus(task) {
6470
+ return typeof task.status === "string" && task.status.trim() ? task.status : "unknown";
6471
+ }
6472
+ function renderTaskPickerRows(tasks) {
6473
+ return tasks.map((task, index) => `${index + 1}. ${taskId(task)} \xB7 ${taskStatus(task)} \xB7 ${taskTitle(task)}`);
6474
+ }
6475
+ async function promptForTaskSelection(question) {
6476
+ const rl = createPromptInterface({ input: process.stdin, output: process.stdout });
6477
+ try {
6478
+ return await rl.question(question);
6479
+ } finally {
6480
+ rl.close();
6481
+ }
6482
+ }
6483
+
6484
+ // packages/cli/src/commands/_operator-view.ts
6485
+ var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
6194
6486
  function runStatusFromPayload(payload) {
6195
6487
  const run = payload.run && typeof payload.run === "object" && !Array.isArray(payload.run) ? payload.run : payload;
6196
6488
  return String(run.status ?? "unknown").toLowerCase();
@@ -6212,11 +6504,22 @@ async function applyOperatorCommand(context, input, deps = {}) {
6212
6504
  await (deps.steer ?? steerRunViaServer)(context, input.runId, userMessage);
6213
6505
  return { action: "continue", message: "Steering message queued." };
6214
6506
  }
6215
- async function readOperatorSnapshot(context, runId) {
6507
+ async function readOperatorSnapshot(context, runId, options = {}) {
6216
6508
  const run = await getRunDetailsViaServer(context, runId);
6217
6509
  const logsPage = await getRunLogsViaServer(context, runId, { limit: 100 });
6218
- const entries = Array.isArray(logsPage.entries) ? logsPage.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
6219
- return { run, logs: entries, rendered: renderOperatorSnapshot({ run, logs: entries }) };
6510
+ const timelinePage = await getRunTimelineViaServer(context, runId, { limit: 200, ...options.timelineCursor ? { cursor: options.timelineCursor } : {} }).catch((error) => ({
6511
+ entries: [{
6512
+ id: `timeline-unavailable:${runId}`,
6513
+ type: "timeline_warning",
6514
+ detail: `Selected Rig server did not provide run timeline events: ${error instanceof Error ? error.message : String(error)}`,
6515
+ createdAt: new Date().toISOString()
6516
+ }],
6517
+ nextCursor: options.timelineCursor ?? null
6518
+ }));
6519
+ const logs = Array.isArray(logsPage.entries) ? logsPage.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))).toReversed() : [];
6520
+ const timeline = Array.isArray(timelinePage.entries) ? timelinePage.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
6521
+ const timelineCursor = typeof timelinePage.nextCursor === "string" ? timelinePage.nextCursor : options.timelineCursor ?? null;
6522
+ return { run, logs, timeline, timelineCursor, rendered: renderOperatorSnapshot({ run, logs, timeline }) };
6220
6523
  }
6221
6524
  async function attachRunOperatorView(context, input) {
6222
6525
  let steered = false;
@@ -6224,40 +6527,41 @@ async function attachRunOperatorView(context, input) {
6224
6527
  await steerRunViaServer(context, input.runId, input.message.trim());
6225
6528
  steered = true;
6226
6529
  }
6530
+ const surface = createOperatorSurface({ interactive: input.interactive !== false });
6227
6531
  let snapshot = await readOperatorSnapshot(context, input.runId);
6228
6532
  if (context.outputMode === "text") {
6229
- console.log(snapshot.rendered);
6533
+ surface.renderSnapshot(snapshot);
6534
+ surface.renderTimeline(snapshot.timeline);
6535
+ surface.renderLogs(snapshot.logs);
6230
6536
  if (steered)
6231
- console.log("Steering message queued.");
6537
+ surface.info("Steering message queued.");
6232
6538
  }
6233
6539
  let detached = false;
6234
- let rl = null;
6540
+ let commandInput = null;
6235
6541
  if (input.follow && !input.once && context.outputMode === "text") {
6236
6542
  if (input.interactive !== false && process.stdin.isTTY) {
6237
- console.log("Controls: /user <message>, /stop, /detach");
6238
- rl = createInterface({ input: process.stdin, output: process.stdout, terminal: false });
6239
- rl.on("line", (line) => {
6240
- applyOperatorCommand(context, { runId: input.runId, line }).then((result) => {
6241
- if (result.message)
6242
- console.log(result.message);
6243
- if (result.action === "detach" || result.action === "stopped") {
6244
- detached = true;
6245
- rl?.close();
6246
- }
6247
- }).catch((error) => console.log(`Operator command failed: ${error instanceof Error ? error.message : String(error)}`));
6543
+ surface.info("Controls: /user <message>, /stop, /detach");
6544
+ commandInput = surface.attachCommandInput(async (line) => {
6545
+ const result = await applyOperatorCommand(context, { runId: input.runId, line });
6546
+ if (result.message)
6547
+ surface.info(result.message);
6548
+ if (result.action === "detach" || result.action === "stopped") {
6549
+ detached = true;
6550
+ commandInput?.close();
6551
+ }
6248
6552
  });
6249
6553
  }
6250
- let lastRendered = snapshot.rendered;
6251
6554
  const pollMs = Math.max(250, Math.trunc(input.pollMs ?? 2000));
6555
+ let timelineCursor = snapshot.timelineCursor;
6252
6556
  while (!detached && !TERMINAL_RUN_STATUSES.has(runStatusFromPayload(snapshot.run))) {
6253
6557
  await Bun.sleep(pollMs);
6254
- snapshot = await readOperatorSnapshot(context, input.runId);
6255
- if (snapshot.rendered !== lastRendered) {
6256
- console.log(snapshot.rendered);
6257
- lastRendered = snapshot.rendered;
6258
- }
6558
+ snapshot = await readOperatorSnapshot(context, input.runId, { timelineCursor });
6559
+ timelineCursor = snapshot.timelineCursor;
6560
+ surface.renderSnapshot(snapshot);
6561
+ surface.renderTimeline(snapshot.timeline);
6562
+ surface.renderLogs(snapshot.logs);
6259
6563
  }
6260
- rl?.close();
6564
+ commandInput?.close();
6261
6565
  }
6262
6566
  return { ...snapshot, steered, detached };
6263
6567
  }
@@ -6431,34 +6735,24 @@ async function executeRun(context, args) {
6431
6735
  if (!run.value) {
6432
6736
  throw new CliError2("run timeline requires --run <id>.");
6433
6737
  }
6434
- const timelinePath = resolve20(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
6435
- const printEvents = () => {
6436
- const events2 = readJsonlFile4(timelinePath);
6437
- if (context.outputMode === "text") {
6438
- for (const event of events2) {
6439
- console.log(JSON.stringify(event));
6440
- }
6441
- }
6442
- return events2;
6443
- };
6444
- const events = printEvents();
6738
+ const renderer = createPiRunStreamRenderer();
6739
+ let cursor = null;
6740
+ const page = await getRunTimelineViaServer(context, run.value, { limit: 500 });
6741
+ const events = Array.isArray(page.entries) ? page.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
6742
+ cursor = typeof page.nextCursor === "string" ? page.nextCursor : null;
6743
+ if (context.outputMode === "text") {
6744
+ renderer.renderTimeline(events);
6745
+ }
6445
6746
  if (follow.value && context.outputMode === "text") {
6446
- let lastLength = existsSync12(timelinePath) ? readFileSync9(timelinePath, "utf8").length : 0;
6447
6747
  while (true) {
6448
6748
  await Bun.sleep(1000);
6449
- if (!existsSync12(timelinePath))
6450
- continue;
6451
- const next = readFileSync9(timelinePath, "utf8");
6452
- if (next.length <= lastLength)
6453
- continue;
6454
- const delta = next.slice(lastLength);
6455
- lastLength = next.length;
6456
- for (const line of delta.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean)) {
6457
- console.log(line);
6458
- }
6749
+ const nextPage = await getRunTimelineViaServer(context, run.value, { limit: 500, ...cursor ? { cursor } : {} });
6750
+ const nextEvents = Array.isArray(nextPage.entries) ? nextPage.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
6751
+ cursor = typeof nextPage.nextCursor === "string" ? nextPage.nextCursor : cursor;
6752
+ renderer.renderTimeline(nextEvents);
6459
6753
  }
6460
6754
  }
6461
- return { ok: true, group: "run", command, details: { runId: run.value, events } };
6755
+ return { ok: true, group: "run", command, details: { runId: run.value, events, cursor } };
6462
6756
  }
6463
6757
  case "attach": {
6464
6758
  let pending = rest;
@@ -6748,10 +7042,10 @@ async function executeServer(context, args, options) {
6748
7042
  }
6749
7043
 
6750
7044
  // packages/cli/src/commands/task.ts
6751
- import { readFileSync as readFileSync10 } from "fs";
6752
- import { spawnSync as spawnSync4 } from "child_process";
6753
- import { createInterface as createInterface4 } from "readline/promises";
6754
- import { resolve as resolve21 } from "path";
7045
+ import { readFileSync as readFileSync9 } from "fs";
7046
+ import { spawnSync as spawnSync3 } from "child_process";
7047
+ import { createInterface as createInterface3 } from "readline/promises";
7048
+ import { resolve as resolve20 } from "path";
6755
7049
  import {
6756
7050
  taskArtifactDir,
6757
7051
  taskArtifacts,
@@ -6769,19 +7063,9 @@ import {
6769
7063
  } from "@rig/runtime/control-plane/native/task-ops";
6770
7064
 
6771
7065
  // packages/cli/src/commands/_task-picker.ts
6772
- import { createInterface as createInterface3 } from "readline/promises";
6773
- function taskId(task) {
7066
+ function taskId2(task) {
6774
7067
  return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
6775
7068
  }
6776
- function taskTitle(task) {
6777
- return typeof task.title === "string" && task.title.trim() ? task.title : "Untitled task";
6778
- }
6779
- function taskStatus(task) {
6780
- return typeof task.status === "string" && task.status.trim() ? task.status : "unknown";
6781
- }
6782
- function renderTaskPickerRows(tasks) {
6783
- return tasks.map((task, index) => `${index + 1}. ${taskId(task)} \xB7 ${taskStatus(task)} \xB7 ${taskTitle(task)}`);
6784
- }
6785
7069
  async function selectTaskWithTextPicker(tasks, io = {}) {
6786
7070
  if (tasks.length === 0)
6787
7071
  return null;
@@ -6791,17 +7075,12 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
6791
7075
  if (!isTty) {
6792
7076
  throw new Error("task run requires an interactive terminal to pick a task; pass --task <id>, --next, or --detach with a task id.");
6793
7077
  }
6794
- const prompt = io.prompt ?? (async (question) => {
6795
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
6796
- try {
6797
- return await rl.question(question);
6798
- } finally {
6799
- rl.close();
6800
- }
6801
- });
6802
- console.log("Select Rig task:");
7078
+ const prompt = io.prompt ?? promptForTaskSelection;
7079
+ const renderer = io.renderer ?? { writeLine: (line) => process.stdout.write(`${line}
7080
+ `) };
7081
+ renderer.writeLine("Select Rig task:");
6803
7082
  for (const row of renderTaskPickerRows(tasks))
6804
- console.log(` ${row}`);
7083
+ renderer.writeLine(` ${row}`);
6805
7084
  const answer = (await prompt(`Task [1-${tasks.length}] or id: `)).trim();
6806
7085
  if (!answer)
6807
7086
  return null;
@@ -6809,7 +7088,7 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
6809
7088
  const index = Number.parseInt(answer, 10) - 1;
6810
7089
  return tasks[index] ?? null;
6811
7090
  }
6812
- return tasks.find((task) => taskId(task) === answer) ?? null;
7091
+ return tasks.find((task) => taskId2(task) === answer) ?? null;
6813
7092
  }
6814
7093
 
6815
7094
  // packages/cli/src/commands/task.ts
@@ -6887,7 +7166,7 @@ function normalizePrMode(value) {
6887
7166
  throw new CliError2("--pr must be auto, ask, or off.", 2);
6888
7167
  }
6889
7168
  function detectLocalDirtyState(projectRoot) {
6890
- const result = spawnSync4("git", ["-C", projectRoot, "status", "--porcelain"], { encoding: "utf8", timeout: 5000 });
7169
+ const result = spawnSync3("git", ["-C", projectRoot, "status", "--porcelain"], { encoding: "utf8", timeout: 5000 });
6891
7170
  if (result.status !== 0)
6892
7171
  return { dirty: false, modified: 0, untracked: 0, lines: [] };
6893
7172
  const lines = result.stdout.split(/\r?\n/).map((line) => line.trimEnd()).filter(Boolean);
@@ -6921,7 +7200,7 @@ async function resolveDirtyBaselineForTaskRun(context, explicit) {
6921
7200
  if (explicit)
6922
7201
  return { mode: explicit, state };
6923
7202
  if (context.outputMode === "text" && process.stdin.isTTY && process.stdout.isTTY) {
6924
- const rl = createInterface4({ input: process.stdin, output: process.stdout });
7203
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
6925
7204
  try {
6926
7205
  const answer = (await rl.question("Include current uncommitted changes in run baseline? [y/N] ")).trim().toLowerCase();
6927
7206
  return { mode: answer === "y" || answer === "yes" ? "dirty-snapshot" : "head", state };
@@ -7006,12 +7285,12 @@ async function executeTask(context, args, options) {
7006
7285
  const positional = taskOption.rest.length > 0 && taskOption.rest[0] && !taskOption.rest[0].startsWith("-") ? taskOption.rest[0] : undefined;
7007
7286
  const remaining = positional ? taskOption.rest.slice(1) : taskOption.rest;
7008
7287
  requireNoExtraArgs(remaining, "bun run rig task show <id>|--task <id>");
7009
- const taskId2 = normalizeTaskRunTaskId(taskOption.value ?? positional);
7010
- if (!taskId2)
7288
+ const taskId3 = normalizeTaskRunTaskId(taskOption.value ?? positional);
7289
+ if (!taskId3)
7011
7290
  throw new CliError2("task show requires a task id.", 2);
7012
- const task = await getWorkspaceTaskViaServer(context, taskId2);
7291
+ const task = await getWorkspaceTaskViaServer(context, taskId3);
7013
7292
  if (!task)
7014
- throw new CliError2(`Task not found: ${taskId2}`, 3);
7293
+ throw new CliError2(`Task not found: ${taskId3}`, 3);
7015
7294
  const summary = summarizeTask(task, { raw: true });
7016
7295
  if (context.outputMode === "text")
7017
7296
  console.log(JSON.stringify(summary, null, 2));
@@ -7082,7 +7361,7 @@ async function executeTask(context, args, options) {
7082
7361
  const fileFlag = takeOption(rest.slice(1), "--file");
7083
7362
  let content;
7084
7363
  if (fileFlag.value) {
7085
- content = readFileSync10(resolve21(context.projectRoot, fileFlag.value), "utf-8");
7364
+ content = readFileSync9(resolve20(context.projectRoot, fileFlag.value), "utf-8");
7086
7365
  } else {
7087
7366
  content = await readStdin();
7088
7367
  }
@@ -7303,9 +7582,9 @@ async function executeTask(context, args, options) {
7303
7582
  }
7304
7583
 
7305
7584
  // packages/cli/src/commands/task-run-driver.ts
7306
- import { copyFileSync as copyFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7307
- import { resolve as resolve22 } from "path";
7308
- import { spawn as spawn2, spawnSync as spawnSync5 } from "child_process";
7585
+ import { copyFileSync as copyFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7586
+ import { resolve as resolve21 } from "path";
7587
+ import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
7309
7588
  import { createInterface as createLineInterface } from "readline";
7310
7589
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
7311
7590
  import {
@@ -7330,8 +7609,7 @@ import {
7330
7609
  import { resolvePreferredShellBinary } from "@rig/runtime/control-plane/native/run-ops";
7331
7610
  import { readAuthorityRun as readAuthorityRun5, readJsonFile as readJsonFile3, resolveTaskArtifactDirs as resolveTaskArtifactDirs2 } from "@rig/runtime/control-plane/authority-files";
7332
7611
  import {
7333
- buildTaskRunLifecycleComment,
7334
- updateConfiguredTaskSourceTask
7612
+ buildTaskRunLifecycleComment
7335
7613
  } from "@rig/runtime/control-plane/tasks/source-lifecycle";
7336
7614
  import {
7337
7615
  closeIssueAfterMergedPr,
@@ -7369,7 +7647,7 @@ function buildPiRigBridgeEnv(input) {
7369
7647
  };
7370
7648
  }
7371
7649
  function runGitSync(cwd, args, input) {
7372
- const result = spawnSync5("git", [...args], {
7650
+ const result = spawnSync4("git", [...args], {
7373
7651
  cwd,
7374
7652
  input,
7375
7653
  encoding: "utf8",
@@ -7387,12 +7665,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
7387
7665
  return 0;
7388
7666
  let copied = 0;
7389
7667
  for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
7390
- const sourcePath = resolve22(sourceRoot, relativePath);
7391
- const targetPath = resolve22(targetRoot, relativePath);
7668
+ const sourcePath = resolve21(sourceRoot, relativePath);
7669
+ const targetPath = resolve21(targetRoot, relativePath);
7392
7670
  try {
7393
7671
  if (!statSync2(sourcePath).isFile())
7394
7672
  continue;
7395
- mkdirSync8(resolve22(targetPath, ".."), { recursive: true });
7673
+ mkdirSync8(resolve21(targetPath, ".."), { recursive: true });
7396
7674
  copyFileSync3(sourcePath, targetPath);
7397
7675
  copied += 1;
7398
7676
  } catch {}
@@ -7431,7 +7709,7 @@ function buildDirtyBaselineHandshakeEnv(input) {
7431
7709
  return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
7432
7710
  return {
7433
7711
  RIG_BASELINE_MODE: "dirty-snapshot",
7434
- RIG_DIRTY_BASELINE_READY_FILE: resolve22(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
7712
+ RIG_DIRTY_BASELINE_READY_FILE: resolve21(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
7435
7713
  };
7436
7714
  }
7437
7715
  function positiveInt(value, fallback) {
@@ -7542,9 +7820,9 @@ function createCommandRunner(binary) {
7542
7820
  const stderrChunks = [];
7543
7821
  child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
7544
7822
  child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
7545
- return await new Promise((resolve23) => {
7546
- child.once("error", (error) => resolve23({ exitCode: 1, stderr: error.message }));
7547
- child.once("close", (code) => resolve23({
7823
+ return await new Promise((resolve22) => {
7824
+ child.once("error", (error) => resolve22({ exitCode: 1, stderr: error.message }));
7825
+ child.once("close", (code) => resolve22({
7548
7826
  exitCode: code ?? 1,
7549
7827
  stdout: Buffer.concat(stdoutChunks).toString("utf8"),
7550
7828
  stderr: Buffer.concat(stderrChunks).toString("utf8")
@@ -7564,12 +7842,13 @@ async function resolvePostValidationBranch(input) {
7564
7842
  return input.configuredBranch;
7565
7843
  }
7566
7844
  async function runTaskRunPostValidationLifecycle(input) {
7567
- const taskId2 = input.taskId?.trim();
7568
- if (!taskId2) {
7845
+ const taskId3 = input.taskId?.trim();
7846
+ if (!taskId3) {
7569
7847
  return { status: "skipped" };
7570
7848
  }
7571
- const config = input.config ?? {};
7572
- const prMode = config.pr?.mode ?? "auto";
7849
+ const configInput = input.config ?? null;
7850
+ const config = configInput ?? {};
7851
+ const prMode = configInput ? configInput.pr?.mode ?? "auto" : "off";
7573
7852
  if (prMode === "off" || prMode === "ask") {
7574
7853
  input.appendStage?.("Open PR", prMode === "off" ? "PR automation disabled by pr.mode=off." : "PR creation awaiting operator approval by pr.mode=ask.", "skipped", "info");
7575
7854
  input.appendStage?.("Complete", "Validation completed; no PR was opened and the issue was left open.", "completed", "info");
@@ -7585,7 +7864,7 @@ async function runTaskRunPostValidationLifecycle(input) {
7585
7864
  gitCommand
7586
7865
  });
7587
7866
  const prAutomation = input.prAutomation ?? runPrAutomation;
7588
- const updateTaskSource = input.updateTaskSource ?? updateConfiguredTaskSourceTask;
7867
+ const updateTaskSource = input.updateTaskSource ?? updateTaskSourceWithProjectSync;
7589
7868
  const stage = input.appendStage ?? (() => {
7590
7869
  return;
7591
7870
  });
@@ -7603,7 +7882,7 @@ async function runTaskRunPostValidationLifecycle(input) {
7603
7882
  stage("Commit", `Committing changes in ${workspace}.`, "running", "tool");
7604
7883
  const commit = await commitRunChanges({
7605
7884
  cwd: workspace,
7606
- message: `rig: complete task ${taskId2}`,
7885
+ message: `rig: complete task ${taskId3}`,
7607
7886
  command: gitCommand
7608
7887
  });
7609
7888
  stage("Commit", commit.committed ? "Committed run workspace changes." : "No workspace changes to commit.", "completed", "tool");
@@ -7611,14 +7890,15 @@ async function runTaskRunPostValidationLifecycle(input) {
7611
7890
  stage("Open PR", `Opening PR from ${branch}.`, "running", "tool");
7612
7891
  const pr = await prAutomation({
7613
7892
  projectRoot: workspace,
7614
- taskId: taskId2,
7893
+ taskId: taskId3,
7615
7894
  runId: input.runId,
7616
7895
  branch,
7617
7896
  config,
7618
7897
  sourceTask: input.sourceTask,
7619
7898
  uploadedSnapshot: input.uploadedSnapshot,
7620
- artifactRoot: resolve22(input.projectRoot, "artifacts", taskId2),
7899
+ artifactRoot: resolve21(input.projectRoot, "artifacts", taskId3),
7621
7900
  command: ghCommand,
7901
+ gitCommand,
7622
7902
  steerPi,
7623
7903
  lifecycle: {
7624
7904
  onPrOpened: async ({ prUrl }) => {
@@ -7626,7 +7906,7 @@ async function runTaskRunPostValidationLifecycle(input) {
7626
7906
  try {
7627
7907
  if (shouldWriteDriverIssueUpdate(config, "under_review")) {
7628
7908
  await updateTaskSource(input.projectRoot, {
7629
- taskId: taskId2,
7909
+ taskId: taskId3,
7630
7910
  sourceTask: runSourceTaskIdentity(input.sourceTask),
7631
7911
  update: {
7632
7912
  status: "under_review",
@@ -7656,7 +7936,7 @@ async function runTaskRunPostValidationLifecycle(input) {
7656
7936
  `), "reviewing", "error");
7657
7937
  if (shouldWriteDriverIssueUpdate(config, "ci_fixing")) {
7658
7938
  await updateTaskSource(input.projectRoot, {
7659
- taskId: taskId2,
7939
+ taskId: taskId3,
7660
7940
  sourceTask: runSourceTaskIdentity(input.sourceTask),
7661
7941
  update: {
7662
7942
  status: "ci_fixing",
@@ -7667,8 +7947,6 @@ async function runTaskRunPostValidationLifecycle(input) {
7667
7947
  runtimeWorkspace: input.runtimeWorkspace ?? null
7668
7948
  })
7669
7949
  }
7670
- }).catch(() => {
7671
- return;
7672
7950
  });
7673
7951
  }
7674
7952
  },
@@ -7676,7 +7954,7 @@ async function runTaskRunPostValidationLifecycle(input) {
7676
7954
  stage("Merge", prUrl, "running", "tool");
7677
7955
  if (shouldWriteDriverIssueUpdate(config, "merging")) {
7678
7956
  await updateTaskSource(input.projectRoot, {
7679
- taskId: taskId2,
7957
+ taskId: taskId3,
7680
7958
  sourceTask: runSourceTaskIdentity(input.sourceTask),
7681
7959
  update: {
7682
7960
  status: "merging",
@@ -7687,8 +7965,6 @@ async function runTaskRunPostValidationLifecycle(input) {
7687
7965
  runtimeWorkspace: input.runtimeWorkspace ?? null
7688
7966
  })
7689
7967
  }
7690
- }).catch(() => {
7691
- return;
7692
7968
  });
7693
7969
  }
7694
7970
  },
@@ -7705,7 +7981,7 @@ async function runTaskRunPostValidationLifecycle(input) {
7705
7981
  stage("Needs attention", detail, "needs_attention", "error");
7706
7982
  if (shouldWriteDriverIssueUpdate(config, "needs_attention")) {
7707
7983
  await updateTaskSource(input.projectRoot, {
7708
- taskId: taskId2,
7984
+ taskId: taskId3,
7709
7985
  sourceTask: runSourceTaskIdentity(input.sourceTask),
7710
7986
  update: {
7711
7987
  status: "needs_attention",
@@ -7717,8 +7993,17 @@ async function runTaskRunPostValidationLifecycle(input) {
7717
7993
  errorText: detail
7718
7994
  })
7719
7995
  }
7720
- }).catch(() => {
7721
- return;
7996
+ }).catch((error) => {
7997
+ try {
7998
+ appendRunLog(input.projectRoot, input.runId, {
7999
+ id: `log:${input.runId}:task-source-needs-attention-update`,
8000
+ title: "Task source needs-attention update failed",
8001
+ detail: error instanceof Error ? error.message : String(error),
8002
+ tone: "error",
8003
+ status: "needs_attention",
8004
+ createdAt: new Date().toISOString()
8005
+ });
8006
+ } catch {}
7722
8007
  });
7723
8008
  }
7724
8009
  return { status: "needs_attention", pr };
@@ -7726,7 +8011,7 @@ async function runTaskRunPostValidationLifecycle(input) {
7726
8011
  if (shouldWriteDriverIssueUpdate(config, "closed")) {
7727
8012
  await closeIssueAfterMergedPr({
7728
8013
  projectRoot: input.projectRoot,
7729
- taskId: taskId2,
8014
+ taskId: taskId3,
7730
8015
  runId: input.runId,
7731
8016
  prUrl: pr.prUrl,
7732
8017
  sourceTask: input.sourceTask,
@@ -7736,12 +8021,12 @@ async function runTaskRunPostValidationLifecycle(input) {
7736
8021
  stage("Complete", `PR merged and issue closed: ${pr.prUrl}`, "completed", "info");
7737
8022
  return { status: "completed", pr };
7738
8023
  }
7739
- function summarizeValidationFailure(projectRoot, taskId2) {
7740
- if (!taskId2) {
8024
+ function summarizeValidationFailure(projectRoot, taskId3) {
8025
+ if (!taskId3) {
7741
8026
  return null;
7742
8027
  }
7743
- for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId2)) {
7744
- const summary = readJsonFile3(resolve22(artifactDir, "validation-summary.json"), null);
8028
+ for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId3)) {
8029
+ const summary = readJsonFile3(resolve21(artifactDir, "validation-summary.json"), null);
7745
8030
  if (!summary || summary.status !== "fail") {
7746
8031
  continue;
7747
8032
  }
@@ -7822,9 +8107,9 @@ function readTaskRunAcceptedArtifactState(input) {
7822
8107
  if (!input.taskId || !input.workspaceDir) {
7823
8108
  return { accepted: false, reason: null };
7824
8109
  }
7825
- const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
7826
- const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
7827
- const taskResultPath = resolve22(artifactDir, "task-result.json");
8110
+ const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
8111
+ const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
8112
+ const taskResultPath = resolve21(artifactDir, "task-result.json");
7828
8113
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7829
8114
  if (reviewStatus !== "APPROVED") {
7830
8115
  return { accepted: false, reason: null };
@@ -7861,12 +8146,12 @@ function resolveTaskRunRetryContext(input) {
7861
8146
  if (!input.taskId || !input.workspaceDir) {
7862
8147
  return { shouldRetry: false, failureDetail: null, nextPrompt: null };
7863
8148
  }
7864
- const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
7865
- const reviewStatePath = resolve22(artifactDir, "review-state.json");
7866
- const reviewFeedbackPath = resolve22(artifactDir, "review-feedback.md");
7867
- const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
7868
- const failedApproachesPath = resolve22(input.workspaceDir, ".rig", "state", "failed_approaches.md");
7869
- const validationSummaryPath = resolve22(artifactDir, "validation-summary.json");
8149
+ const artifactDir = resolve21(input.workspaceDir, "artifacts", input.taskId);
8150
+ const reviewStatePath = resolve21(artifactDir, "review-state.json");
8151
+ const reviewFeedbackPath = resolve21(artifactDir, "review-feedback.md");
8152
+ const reviewStatusPath = resolve21(artifactDir, "review-status.txt");
8153
+ const failedApproachesPath = resolve21(input.workspaceDir, ".rig", "state", "failed_approaches.md");
8154
+ const validationSummaryPath = resolve21(artifactDir, "validation-summary.json");
7870
8155
  const reviewState = readJsonFile3(reviewStatePath, null);
7871
8156
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
7872
8157
  const reviewRejected = isTaskRunReviewRejected(reviewState);
@@ -7920,12 +8205,60 @@ function summarizeTaskRunReviewFailure(reviewState) {
7920
8205
  }
7921
8206
  return "Completion verification rejected the task. Read review-feedback.md for required fixes.";
7922
8207
  }
8208
+ function appendAssistantTimelineFromRecord(input) {
8209
+ let nextAssistantText = input.assistantText;
8210
+ if (input.record.type === "message_update") {
8211
+ const assistantMessageEvent = input.record.assistantMessageEvent && typeof input.record.assistantMessageEvent === "object" ? input.record.assistantMessageEvent : null;
8212
+ if (assistantMessageEvent?.type === "text_delta" && typeof assistantMessageEvent.delta === "string") {
8213
+ nextAssistantText += assistantMessageEvent.delta;
8214
+ }
8215
+ } else if (input.record.type === "stream_event") {
8216
+ const event = input.record.event && typeof input.record.event === "object" ? input.record.event : null;
8217
+ const delta = event?.delta && typeof event.delta === "object" ? event.delta : null;
8218
+ if (delta?.type === "text_delta" && typeof delta.text === "string") {
8219
+ nextAssistantText += delta.text;
8220
+ }
8221
+ } else if (input.record.type === "assistant") {
8222
+ const message2 = input.record.message && typeof input.record.message === "object" ? input.record.message : input.record;
8223
+ const content = Array.isArray(message2.content) ? message2.content : [];
8224
+ const fullText = content.map((entry) => entry && typeof entry === "object" && entry.type === "text" ? String(entry.text ?? "") : "").join("");
8225
+ if (fullText.length > nextAssistantText.length)
8226
+ nextAssistantText = fullText;
8227
+ }
8228
+ if (nextAssistantText !== input.assistantText) {
8229
+ appendRunTimeline(input.projectRoot, input.runId, {
8230
+ id: input.messageId,
8231
+ type: "assistant_message",
8232
+ text: nextAssistantText,
8233
+ state: "streaming",
8234
+ createdAt: new Date().toISOString()
8235
+ });
8236
+ }
8237
+ return nextAssistantText;
8238
+ }
8239
+ function appendToolTimelineFromLog(input) {
8240
+ const title = typeof input.log.title === "string" ? input.log.title : "";
8241
+ if (title !== "Tool activity")
8242
+ return;
8243
+ const payload = input.log.payload && typeof input.log.payload === "object" && !Array.isArray(input.log.payload) ? input.log.payload : {};
8244
+ const toolName = typeof payload.toolName === "string" && payload.toolName.trim() ? payload.toolName.trim() : typeof payload.tool_name === "string" && payload.tool_name.trim() ? payload.tool_name.trim() : null;
8245
+ const logId = typeof input.log.id === "string" && input.log.id.trim() ? input.log.id.trim() : `${Date.now()}`;
8246
+ appendRunTimeline(input.projectRoot, input.runId, {
8247
+ id: `tool:${logId}`,
8248
+ type: "tool_execution_update",
8249
+ toolName,
8250
+ status: typeof input.log.status === "string" ? input.log.status : "running",
8251
+ detail: typeof input.log.detail === "string" ? input.log.detail : null,
8252
+ payload,
8253
+ createdAt: typeof input.log.createdAt === "string" ? input.log.createdAt : new Date().toISOString()
8254
+ });
8255
+ }
7923
8256
  function readTaskRunReviewStatus(reviewStatusPath) {
7924
- if (!existsSync13(reviewStatusPath)) {
8257
+ if (!existsSync12(reviewStatusPath)) {
7925
8258
  return null;
7926
8259
  }
7927
8260
  try {
7928
- const status = readFileSync11(reviewStatusPath, "utf8").trim().toUpperCase();
8261
+ const status = readFileSync10(reviewStatusPath, "utf8").trim().toUpperCase();
7929
8262
  return status === "APPROVED" || status === "REJECTED" ? status : null;
7930
8263
  } catch {
7931
8264
  return null;
@@ -7943,14 +8276,45 @@ function isTaskRunReviewRejected(reviewState) {
7943
8276
  function runSourceTaskIdentity(sourceTask) {
7944
8277
  return sourceTask;
7945
8278
  }
7946
- async function updateTaskSourceAfterDriverRun(projectRoot, runId, taskId2, sourceTask, status, summary, input, updateTaskSource = updateConfiguredTaskSourceTask) {
7947
- if (!taskId2)
8279
+ function sourceTaskIssueNodeId(sourceTask) {
8280
+ if (!sourceTask || typeof sourceTask !== "object" || Array.isArray(sourceTask))
8281
+ return null;
8282
+ const record = sourceTask;
8283
+ const direct = typeof record.issueNodeId === "string" ? record.issueNodeId : typeof record.nodeId === "string" ? record.nodeId : typeof record.node_id === "string" ? record.node_id : null;
8284
+ if (direct?.trim())
8285
+ return direct.trim();
8286
+ const raw = record.raw && typeof record.raw === "object" && !Array.isArray(record.raw) ? record.raw : null;
8287
+ return typeof raw?.id === "string" && raw.id.trim() ? raw.id.trim() : null;
8288
+ }
8289
+ var updateTaskSourceWithProjectSync = async (projectRoot, input) => {
8290
+ const serverResult = await updateWorkspaceTaskViaServer({ projectRoot }, {
8291
+ id: input.taskId,
8292
+ ...input.update.status ? { status: input.update.status } : {},
8293
+ ...input.update.comment ? { comment: input.update.comment } : {},
8294
+ ...input.update.title ? { title: input.update.title } : {},
8295
+ ...typeof input.update.body === "string" ? { body: input.update.body } : {},
8296
+ issueNodeId: sourceTaskIssueNodeId(input.sourceTask)
8297
+ });
8298
+ if (serverResult.ok === false) {
8299
+ throw new Error(typeof serverResult.error === "string" ? serverResult.error : "Rig server task update failed.");
8300
+ }
8301
+ return {
8302
+ updated: serverResult.ok !== false,
8303
+ taskId: input.taskId,
8304
+ status: input.update.status,
8305
+ source: "server",
8306
+ sourceKind: "server",
8307
+ projectSync: serverResult.projectSync
8308
+ };
8309
+ };
8310
+ async function updateTaskSourceAfterDriverRun(projectRoot, runId, taskId3, sourceTask, status, summary, input, updateTaskSource = updateTaskSourceWithProjectSync) {
8311
+ if (!taskId3)
7948
8312
  return;
7949
8313
  const config = await loadTaskRunAutomationConfig(projectRoot);
7950
8314
  if (!shouldWriteDriverIssueUpdate(config, status))
7951
8315
  return;
7952
8316
  const result = await updateTaskSource(projectRoot, {
7953
- taskId: taskId2,
8317
+ taskId: taskId3,
7954
8318
  sourceTask: runSourceTaskIdentity(sourceTask),
7955
8319
  update: {
7956
8320
  status,
@@ -7969,14 +8333,14 @@ async function updateTaskSourceAfterDriverRun(projectRoot, runId, taskId2, sourc
7969
8333
  throw new Error(`Configured task source${result.sourceKind ? ` (${result.sourceKind})` : ""} did not accept lifecycle update for ${result.taskId}.`);
7970
8334
  }
7971
8335
  }
7972
- function readRunSourceTaskContract(projectRoot, runId, taskId2) {
8336
+ function readRunSourceTaskContract(projectRoot, runId, taskId3) {
7973
8337
  const run = readAuthorityRun5(projectRoot, runId);
7974
8338
  const raw = run?.sourceTask;
7975
8339
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
7976
8340
  return null;
7977
8341
  }
7978
8342
  const record = raw;
7979
- const id = typeof record.id === "string" && record.id.trim() ? record.id.trim() : taskId2?.trim();
8343
+ const id = typeof record.id === "string" && record.id.trim() ? record.id.trim() : taskId3?.trim();
7980
8344
  if (!id) {
7981
8345
  return null;
7982
8346
  }
@@ -8112,15 +8476,15 @@ async function executeRigOwnedTaskRun(context, input) {
8112
8476
  const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
8113
8477
  const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
8114
8478
  const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
8115
- const planningArtifactPath = resolve22("artifacts", runtimeTaskId, "implementation-plan.md");
8479
+ const planningArtifactPath = resolve21("artifacts", runtimeTaskId, "implementation-plan.md");
8116
8480
  const persistedPlanning = {
8117
8481
  ...planningClassification,
8118
8482
  classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
8119
8483
  artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
8120
8484
  classifiedAt: new Date().toISOString()
8121
8485
  };
8122
- mkdirSync8(resolve22(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
8123
- writeFileSync6(resolve22(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
8486
+ mkdirSync8(resolve21(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
8487
+ writeFileSync6(resolve21(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
8124
8488
  `, "utf8");
8125
8489
  patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
8126
8490
  prompt = `${prompt}
@@ -8170,7 +8534,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8170
8534
  let verificationStarted = false;
8171
8535
  let reviewStarted = false;
8172
8536
  let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
8173
- let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve22(existingRunRecord.sessionPath, "..") : null;
8537
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve21(existingRunRecord.sessionPath, "..") : null;
8174
8538
  let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
8175
8539
  let latestProviderCommand = null;
8176
8540
  let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
@@ -8253,10 +8617,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8253
8617
  patchAuthorityRun(context.projectRoot, input.runId, {
8254
8618
  status: "running",
8255
8619
  worktreePath: latestRuntimeWorkspace,
8256
- artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve22(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
8620
+ artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve21(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
8257
8621
  logRoot: latestLogsDir,
8258
- sessionPath: latestSessionDir ? resolve22(latestSessionDir, "session.json") : null,
8259
- sessionLogPath: latestLogsDir ? resolve22(latestLogsDir, "agent-stdout.log") : null,
8622
+ sessionPath: latestSessionDir ? resolve21(latestSessionDir, "session.json") : null,
8623
+ sessionLogPath: latestLogsDir ? resolve21(latestLogsDir, "agent-stdout.log") : null,
8260
8624
  branch: runtimeId
8261
8625
  });
8262
8626
  if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
@@ -8264,7 +8628,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8264
8628
  const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
8265
8629
  const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
8266
8630
  if (readyFile) {
8267
- mkdirSync8(resolve22(readyFile, ".."), { recursive: true });
8631
+ mkdirSync8(resolve21(readyFile, ".."), { recursive: true });
8268
8632
  writeFileSync6(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
8269
8633
  `, "utf8");
8270
8634
  }
@@ -8413,7 +8777,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8413
8777
  if (providerLogs.length > 0) {
8414
8778
  for (const providerLog of providerLogs) {
8415
8779
  appendRunLog(context.projectRoot, input.runId, providerLog);
8780
+ appendToolTimelineFromLog({ projectRoot: context.projectRoot, runId: input.runId, log: providerLog });
8416
8781
  emitServerRunEvent({ type: "log", runId: input.runId, title: providerLog.title });
8782
+ if (providerLog.title === "Tool activity")
8783
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
8417
8784
  }
8418
8785
  }
8419
8786
  if (input.runtimeAdapter === "codex") {
@@ -8571,7 +8938,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8571
8938
  let acceptedArtifactObservedAt = null;
8572
8939
  let acceptedArtifactPollTimer = null;
8573
8940
  let acceptedArtifactKillTimer = null;
8574
- const attemptExit = await new Promise((resolve23) => {
8941
+ const attemptExit = await new Promise((resolve22) => {
8575
8942
  let settled = false;
8576
8943
  const settle = (result) => {
8577
8944
  if (settled)
@@ -8579,7 +8946,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8579
8946
  settled = true;
8580
8947
  if (acceptedArtifactPollTimer)
8581
8948
  clearInterval(acceptedArtifactPollTimer);
8582
- resolve23(result);
8949
+ resolve22(result);
8583
8950
  };
8584
8951
  const pollAcceptedArtifacts = () => {
8585
8952
  const artifactState = readTaskRunAcceptedArtifactState({
@@ -8652,7 +9019,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8652
9019
  });
8653
9020
  for (const pendingLog of pendingLogs) {
8654
9021
  appendRunLog(context.projectRoot, input.runId, pendingLog);
9022
+ appendToolTimelineFromLog({ projectRoot: context.projectRoot, runId: input.runId, log: pendingLog });
8655
9023
  emitServerRunEvent({ type: "log", runId: input.runId, title: pendingLog.title });
9024
+ if (pendingLog.title === "Tool activity")
9025
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
8656
9026
  }
8657
9027
  process.off("SIGTERM", forwardSigterm);
8658
9028
  if (attemptExit.error) {
@@ -8778,8 +9148,8 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8778
9148
  }
8779
9149
  if (planningClassification.planningRequired) {
8780
9150
  const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
8781
- const expectedPlanPath = resolve22(planWorkspace, planningArtifactPath);
8782
- if (!existsSync13(expectedPlanPath)) {
9151
+ const expectedPlanPath = resolve21(planWorkspace, planningArtifactPath);
9152
+ if (!existsSync12(expectedPlanPath)) {
8783
9153
  const failedAt = new Date().toISOString();
8784
9154
  const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
8785
9155
  patchAuthorityRun(context.projectRoot, input.runId, {
@@ -8799,6 +9169,65 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8799
9169
  throw new CliError2(failureDetail, 1);
8800
9170
  }
8801
9171
  }
9172
+ if (process.env.RIG_SERVER_OWNS_CLOSEOUT === "1") {
9173
+ appendPiStageLog({
9174
+ projectRoot: context.projectRoot,
9175
+ runId: input.runId,
9176
+ stage: "Validate",
9177
+ detail: "Rig validation accepted the task run; server will continue PR/review/merge closeout.",
9178
+ status: "completed"
9179
+ });
9180
+ if (verificationAction && !reviewStarted) {
9181
+ verificationAction.complete("Completion verification checks finished.");
9182
+ }
9183
+ if (!reviewAction) {
9184
+ promoteToReviewing("Server-owned closeout is queued.");
9185
+ }
9186
+ if (reviewAction) {
9187
+ reviewAction.complete("Provider work accepted; server-owned closeout requested.");
9188
+ }
9189
+ const requestedAt = new Date().toISOString();
9190
+ patchAuthorityRun(context.projectRoot, input.runId, {
9191
+ status: "reviewing",
9192
+ completedAt: null,
9193
+ errorText: null,
9194
+ serverCloseout: {
9195
+ status: "pending",
9196
+ phase: "queued",
9197
+ requestedAt,
9198
+ updatedAt: requestedAt,
9199
+ runtimeWorkspace: latestRuntimeWorkspace,
9200
+ branch: latestRuntimeBranch,
9201
+ taskId: input.taskId ?? runtimeTaskId
9202
+ }
9203
+ });
9204
+ appendRunLog(context.projectRoot, input.runId, {
9205
+ id: `log:${input.runId}:server-closeout-requested`,
9206
+ title: "Server-owned closeout requested",
9207
+ detail: "The CLI provider worker finished validation and handed commit/PR/review/merge closeout back to the Rig server.",
9208
+ tone: "info",
9209
+ status: "reviewing",
9210
+ createdAt: requestedAt,
9211
+ payload: { runtimeWorkspace: latestRuntimeWorkspace, branch: latestRuntimeBranch }
9212
+ });
9213
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Server-owned closeout requested" });
9214
+ emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: "Server-owned closeout requested." });
9215
+ await context.emitEvent("command.finished", {
9216
+ command: [
9217
+ "rig",
9218
+ "server",
9219
+ "task-run",
9220
+ ...input.taskId ? ["--task", input.taskId] : [],
9221
+ ...input.title ? ["--title", input.title] : []
9222
+ ],
9223
+ formattedCommand: input.taskId ? `rig server task-run --task ${input.taskId}` : `rig server task-run --title ${JSON.stringify(input.title ?? `Run ${input.runId}`)}`,
9224
+ exitCode: 0,
9225
+ durationMs: 0,
9226
+ startedAt,
9227
+ finishedAt: requestedAt
9228
+ });
9229
+ return;
9230
+ }
8802
9231
  const runPiPrFeedbackFix = async (message2) => {
8803
9232
  appendPiStageLog({
8804
9233
  projectRoot: context.projectRoot,
@@ -8826,11 +9255,45 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8826
9255
  child.stdin.write(message2);
8827
9256
  }
8828
9257
  child.stdin.end();
9258
+ const feedbackAssistantMessageId = `message:${input.runId}:pr-feedback:${Date.now()}:assistant`;
9259
+ let feedbackAssistantText = "";
9260
+ const feedbackPendingToolUses = new Map;
8829
9261
  const stdout = createLineInterface({ input: child.stdout });
8830
9262
  stdout.on("line", (line) => {
8831
9263
  const trimmed = line.trim();
8832
9264
  if (!trimmed)
8833
9265
  return;
9266
+ try {
9267
+ const record = JSON.parse(trimmed);
9268
+ const providerLogs = buildClaudeLogsFromRecord({
9269
+ runId: input.runId,
9270
+ record,
9271
+ createdAtFallback: new Date().toISOString(),
9272
+ status: "reviewing",
9273
+ pendingToolUses: feedbackPendingToolUses
9274
+ });
9275
+ for (const providerLog of providerLogs) {
9276
+ appendRunLog(context.projectRoot, input.runId, providerLog);
9277
+ appendToolTimelineFromLog({ projectRoot: context.projectRoot, runId: input.runId, log: providerLog });
9278
+ emitServerRunEvent({ type: "log", runId: input.runId, title: providerLog.title });
9279
+ if (providerLog.title === "Tool activity")
9280
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
9281
+ }
9282
+ const nextFeedbackAssistantText = appendAssistantTimelineFromRecord({
9283
+ projectRoot: context.projectRoot,
9284
+ runId: input.runId,
9285
+ messageId: feedbackAssistantMessageId,
9286
+ record,
9287
+ assistantText: feedbackAssistantText
9288
+ });
9289
+ const hadAssistantDelta = nextFeedbackAssistantText !== feedbackAssistantText;
9290
+ if (hadAssistantDelta) {
9291
+ feedbackAssistantText = nextFeedbackAssistantText;
9292
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
9293
+ }
9294
+ if (providerLogs.length > 0 || hadAssistantDelta)
9295
+ return;
9296
+ } catch {}
8834
9297
  appendRunLog(context.projectRoot, input.runId, {
8835
9298
  id: nextRunLogId(),
8836
9299
  title: "Pi PR feedback fix output",
@@ -8856,10 +9319,31 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
8856
9319
  });
8857
9320
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
8858
9321
  });
8859
- const exitCode = await new Promise((resolve23) => {
8860
- child.once("error", () => resolve23(1));
8861
- child.once("close", (code) => resolve23(code ?? 1));
9322
+ const exitCode = await new Promise((resolve22) => {
9323
+ child.once("error", () => resolve22(1));
9324
+ child.once("close", (code) => resolve22(code ?? 1));
8862
9325
  });
9326
+ for (const pendingLog of flushPendingClaudeToolUseLogs({
9327
+ runId: input.runId,
9328
+ status: exitCode === 0 ? "completed" : "failed",
9329
+ pendingToolUses: feedbackPendingToolUses
9330
+ })) {
9331
+ appendRunLog(context.projectRoot, input.runId, pendingLog);
9332
+ appendToolTimelineFromLog({ projectRoot: context.projectRoot, runId: input.runId, log: pendingLog });
9333
+ emitServerRunEvent({ type: "log", runId: input.runId, title: pendingLog.title });
9334
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
9335
+ }
9336
+ if (feedbackAssistantText.trim()) {
9337
+ appendRunTimeline(context.projectRoot, input.runId, {
9338
+ id: feedbackAssistantMessageId,
9339
+ type: "assistant_message",
9340
+ text: feedbackAssistantText,
9341
+ state: "completed",
9342
+ createdAt: new Date().toISOString(),
9343
+ completedAt: new Date().toISOString()
9344
+ });
9345
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
9346
+ }
8863
9347
  if (exitCode !== 0) {
8864
9348
  throw new Error(`Pi PR feedback fix failed with exit code ${exitCode}.`);
8865
9349
  }
@@ -8977,8 +9461,8 @@ async function executeTest(context, args) {
8977
9461
  }
8978
9462
 
8979
9463
  // packages/cli/src/commands/setup.ts
8980
- import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync7 } from "fs";
8981
- import { resolve as resolve23 } from "path";
9464
+ import { existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync7 } from "fs";
9465
+ import { resolve as resolve22 } from "path";
8982
9466
  import { createPluginHost } from "@rig/core";
8983
9467
  import {
8984
9468
  isSupportedBunVersion as isSupportedBunVersion2,
@@ -9041,8 +9525,8 @@ function runSetupInit(projectRoot) {
9041
9525
  mkdirSync9(stateDir, { recursive: true });
9042
9526
  mkdirSync9(logsDir, { recursive: true });
9043
9527
  mkdirSync9(artifactsDir, { recursive: true });
9044
- const failuresPath = resolve23(stateDir, "failed_approaches.md");
9045
- if (!existsSync14(failuresPath)) {
9528
+ const failuresPath = resolve22(stateDir, "failed_approaches.md");
9529
+ if (!existsSync13(failuresPath)) {
9046
9530
  writeFileSync7(failuresPath, `# Failed Approaches
9047
9531
 
9048
9532
  `, "utf-8");
@@ -9060,18 +9544,18 @@ async function runSetupCheck(projectRoot) {
9060
9544
  }
9061
9545
  async function runSetupPreflight(projectRoot) {
9062
9546
  await runSetupCheck(projectRoot);
9063
- const validationRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
9064
- if (existsSync14(validationRoot)) {
9547
+ const validationRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
9548
+ if (existsSync13(validationRoot)) {
9065
9549
  const validators = readdirSync2(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
9066
9550
  for (const validator of validators) {
9067
- const script = resolve23(validationRoot, validator.name, "validate.sh");
9068
- if (existsSync14(script)) {
9551
+ const script = resolve22(validationRoot, validator.name, "validate.sh");
9552
+ if (existsSync13(script)) {
9069
9553
  console.log(`OK: validator script ${script}`);
9070
9554
  }
9071
9555
  }
9072
9556
  }
9073
- const hooksRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
9074
- if (existsSync14(hooksRoot)) {
9557
+ const hooksRoot = resolve22(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
9558
+ if (existsSync13(hooksRoot)) {
9075
9559
  const hooks = readdirSync2(hooksRoot).filter((name) => name.endsWith(".sh"));
9076
9560
  for (const hook of hooks) {
9077
9561
  console.log(`OK: hook ${hook}`);
@@ -9465,8 +9949,8 @@ var __testOnly = {
9465
9949
  validateRequiredBugPromptValue
9466
9950
  };
9467
9951
  // packages/cli/src/launcher.ts
9468
- import { existsSync as existsSync15 } from "fs";
9469
- import { basename as basename2, resolve as resolve24 } from "path";
9952
+ import { existsSync as existsSync14 } from "fs";
9953
+ import { basename as basename2, resolve as resolve23 } from "path";
9470
9954
  import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
9471
9955
  import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
9472
9956
  function parsePolicyMode(value) {
@@ -9479,7 +9963,7 @@ function parsePolicyMode(value) {
9479
9963
  throw new Error(`Invalid --policy-mode value: ${value}. Use off|observe|enforce.`);
9480
9964
  }
9481
9965
  function hasRigProjectMarker(candidate) {
9482
- 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"));
9966
+ 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"));
9483
9967
  }
9484
9968
  function resolveProjectRoot({
9485
9969
  envProjectRoot,
@@ -9488,19 +9972,19 @@ function resolveProjectRoot({
9488
9972
  cwd = process.cwd()
9489
9973
  }) {
9490
9974
  if (envProjectRoot) {
9491
- return resolve24(cwd, envProjectRoot);
9975
+ return resolve23(cwd, envProjectRoot);
9492
9976
  }
9493
9977
  const fallbackImportDir = importDir ?? cwd;
9494
9978
  const execName = basename2(execPath).toLowerCase();
9495
- const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve24(execPath, "..", "..")] : [];
9496
- const candidates = [cwd, ...execCandidates, resolve24(fallbackImportDir, "..")];
9979
+ const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve23(execPath, "..", "..")] : [];
9980
+ const candidates = [cwd, ...execCandidates, resolve23(fallbackImportDir, "..")];
9497
9981
  for (const candidate of candidates) {
9498
9982
  const nearest = resolveNearestRigProjectRoot(candidate);
9499
9983
  if (hasRigProjectMarker(nearest)) {
9500
9984
  return nearest;
9501
9985
  }
9502
9986
  }
9503
- return resolve24(cwd);
9987
+ return resolve23(cwd);
9504
9988
  }
9505
9989
  function normalizeCliErrorCode(message2, isCliError) {
9506
9990
  if (message2.startsWith("Invalid --policy-mode value:")) {
@@ -9567,7 +10051,7 @@ async function runRigCli(module, options = {}) {
9567
10051
  runId: context.runId,
9568
10052
  outcome,
9569
10053
  eventsFile: context.eventBus.getEventsFile(),
9570
- policyFile: resolve24(projectRoot, "rig", "policy", "policy.json"),
10054
+ policyFile: resolve23(projectRoot, "rig", "policy", "policy.json"),
9571
10055
  policyMode: context.policyMode ?? policyMode ?? module.loadPolicy(projectRoot).mode
9572
10056
  }, null, 2));
9573
10057
  }