@h-rig/cli 0.0.6-alpha.19 → 0.0.6-alpha.20

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.
@@ -2783,7 +2783,8 @@ async function submitTaskRunViaServer(context, input) {
2783
2783
  import { existsSync as existsSync5, readFileSync as readFileSync4, rmSync as rmSync3 } from "fs";
2784
2784
  import { homedir as homedir3 } from "os";
2785
2785
  import { resolve as resolve9 } from "path";
2786
- var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
2786
+ var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
2787
+ var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
2787
2788
  var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
2788
2789
  export { default } from '@rig/pi-rig';
2789
2790
  `;
@@ -2811,7 +2812,7 @@ function resolvePiHomeDir(inputHomeDir) {
2811
2812
  function piListContainsPiRig(output) {
2812
2813
  return output.split(/\r?\n/).some((line) => {
2813
2814
  const normalized = line.trim();
2814
- return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
2815
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
2815
2816
  });
2816
2817
  }
2817
2818
  async function safeRun(runner, command, options) {
@@ -2927,7 +2928,7 @@ async function ensureRemotePiRigInstalled(input) {
2927
2928
  const payload = await input.requestJson("/api/pi-rig/install", {
2928
2929
  method: "POST",
2929
2930
  headers: { "content-type": "application/json" },
2930
- body: JSON.stringify({ package: "@rig/pi-rig", scope: "global" })
2931
+ body: JSON.stringify({ package: PI_RIG_PACKAGE_NAME, scope: "global" })
2931
2932
  });
2932
2933
  const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2933
2934
  const piOk = record.piOk === true || record.ok === true;
@@ -6469,6 +6470,193 @@ async function attachRunOperatorView(context, input) {
6469
6470
  return { ...snapshot, steered, detached };
6470
6471
  }
6471
6472
 
6473
+ // packages/cli/src/commands/_cli-format.ts
6474
+ import pc3 from "picocolors";
6475
+ function stringField(record, key, fallback = "") {
6476
+ const value = record[key];
6477
+ return typeof value === "string" && value.trim() ? value.trim() : fallback;
6478
+ }
6479
+ function arrayField(record, key) {
6480
+ const value = record[key];
6481
+ return Array.isArray(value) ? value.flatMap((entry) => typeof entry === "string" && entry.trim() ? [entry.trim()] : []) : [];
6482
+ }
6483
+ function rawObject(record) {
6484
+ const raw = record.raw;
6485
+ return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
6486
+ }
6487
+ function truncate(value, width) {
6488
+ if (value.length <= width)
6489
+ return value;
6490
+ if (width <= 1)
6491
+ return "\u2026";
6492
+ return `${value.slice(0, width - 1)}\u2026`;
6493
+ }
6494
+ function pad(value, width) {
6495
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
6496
+ }
6497
+ function statusColor(status) {
6498
+ const normalized = status.toLowerCase();
6499
+ if (["completed", "merged", "closed", "done", "accepted"].includes(normalized))
6500
+ return pc3.green;
6501
+ if (["failed", "needs_attention", "needs-attention", "blocked"].includes(normalized))
6502
+ return pc3.red;
6503
+ if (["running", "reviewing", "validating", "in_progress", "in-progress"].includes(normalized))
6504
+ return pc3.cyan;
6505
+ if (["ready", "open", "queued", "created", "preparing"].includes(normalized))
6506
+ return pc3.yellow;
6507
+ return pc3.dim;
6508
+ }
6509
+ function formatTaskList(tasks, options = {}) {
6510
+ if (tasks.length === 0)
6511
+ return pc3.dim("No matching tasks.");
6512
+ if (options.raw)
6513
+ return tasks.map((task) => JSON.stringify(task)).join(`
6514
+ `);
6515
+ const rows = tasks.map((task) => {
6516
+ const raw = rawObject(task);
6517
+ const id = stringField(task, "id", "<unknown>");
6518
+ const status = stringField(task, "status", "unknown");
6519
+ const title = stringField(task, "title", "Untitled task");
6520
+ const source = stringField(task, "source", stringField(raw, "source", ""));
6521
+ const labels = arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels");
6522
+ return { id, status, title, source, labels };
6523
+ });
6524
+ const idWidth = Math.min(18, Math.max(4, ...rows.map((row) => row.id.length)));
6525
+ const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
6526
+ const header = `${pc3.bold(pad("TASK", idWidth))} ${pc3.bold(pad("STATUS", statusWidth))} ${pc3.bold("TITLE")}`;
6527
+ const body = rows.map((row) => {
6528
+ const labels = row.labels.length > 0 ? pc3.dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
6529
+ const source = row.source ? pc3.dim(` ${row.source}`) : "";
6530
+ return [
6531
+ pc3.bold(pad(truncate(row.id, idWidth), idWidth)),
6532
+ statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
6533
+ `${row.title}${labels}${source}`
6534
+ ].join(" ");
6535
+ });
6536
+ return [pc3.bold("Rig tasks"), header, ...body].join(`
6537
+ `);
6538
+ }
6539
+ function formatRunList(runs, options = {}) {
6540
+ if (runs.length === 0) {
6541
+ return pc3.dim(options.source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
6542
+ }
6543
+ const rows = runs.map((run) => {
6544
+ const runId = stringField(run, "runId", stringField(run, "id", "(unknown-run)"));
6545
+ const status = stringField(run, "status", "unknown");
6546
+ const taskId2 = stringField(run, "taskId", "");
6547
+ const title = stringField(run, "title", taskId2 || "(untitled)");
6548
+ const runtime = stringField(run, "runtimeAdapter", "");
6549
+ return { runId, status, title, runtime };
6550
+ });
6551
+ const idWidth = Math.min(36, Math.max(6, ...rows.map((row) => row.runId.length)));
6552
+ const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
6553
+ const header = `${pc3.bold(pad("RUN", idWidth))} ${pc3.bold(pad("STATUS", statusWidth))} ${pc3.bold("TITLE")}`;
6554
+ const body = rows.map((row) => [
6555
+ pc3.bold(pad(truncate(row.runId, idWidth), idWidth)),
6556
+ statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
6557
+ `${row.title}${row.runtime ? pc3.dim(` ${row.runtime}`) : ""}`
6558
+ ].join(" "));
6559
+ return [pc3.bold(options.source === "server" ? "Rig runs (server)" : "Rig runs"), header, ...body].join(`
6560
+ `);
6561
+ }
6562
+ function formatSubmittedRun(input) {
6563
+ const lines = [`${pc3.green("Run submitted")}: ${pc3.bold(input.runId)}`];
6564
+ if (input.task) {
6565
+ const id = stringField(input.task, "id", "<unknown>");
6566
+ const status = stringField(input.task, "status", "unknown");
6567
+ const title = stringField(input.task, "title", "Untitled task");
6568
+ lines.push(`${pc3.dim("task")} ${pc3.bold(id)} ${statusColor(status)(status)} ${title}`);
6569
+ }
6570
+ return lines.join(`
6571
+ `);
6572
+ }
6573
+
6574
+ // packages/cli/src/commands/_pi-session.ts
6575
+ import { spawn as spawn2 } from "child_process";
6576
+ function buildPiRigSessionEnv(input) {
6577
+ return {
6578
+ RIG_PROJECT_ROOT: input.projectRoot,
6579
+ PROJECT_RIG_ROOT: input.projectRoot,
6580
+ RIG_RUN_ID: input.runId,
6581
+ RIG_SERVER_RUN_ID: input.runId,
6582
+ RIG_RUNTIME_ADAPTER: "pi",
6583
+ RIG_SERVER_URL: input.serverUrl,
6584
+ RIG_SERVER_BASE_URL: input.serverUrl,
6585
+ RIG_STEERING_POLL_MS: process.env.RIG_STEERING_POLL_MS?.trim() || "1000",
6586
+ RIG_PI_OPERATOR_SESSION: "1",
6587
+ ...input.taskId ? { RIG_TASK_ID: input.taskId } : {},
6588
+ ...input.authToken ? { RIG_AUTH_TOKEN: input.authToken } : {}
6589
+ };
6590
+ }
6591
+ function shellBinary(name) {
6592
+ const explicit = process.env.RIG_PI_BINARY?.trim();
6593
+ if (explicit)
6594
+ return explicit;
6595
+ return Bun.which(name) || name;
6596
+ }
6597
+ function buildPiRigSessionCommand(input) {
6598
+ const configuredExtension = input.extensionSource ?? process.env.RIG_PI_RIG_EXTENSION_SOURCE?.trim();
6599
+ const extensionSource = configuredExtension && configuredExtension.length > 0 ? configuredExtension : resolvePiRigPackageSource(input.projectRoot);
6600
+ const initialCommand = `/rig attach ${input.runId}`;
6601
+ return [
6602
+ shellBinary("pi"),
6603
+ "--no-extensions",
6604
+ "--extension",
6605
+ extensionSource,
6606
+ initialCommand
6607
+ ];
6608
+ }
6609
+ async function launchPiRigSession(context, input) {
6610
+ if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
6611
+ return { launched: false, exitCode: null, command: [] };
6612
+ }
6613
+ if (process.env.RIG_DISABLE_PI_LAUNCH === "1") {
6614
+ return { launched: false, exitCode: null, command: [] };
6615
+ }
6616
+ const server = await ensureServerForCli(context.projectRoot);
6617
+ const command = buildPiRigSessionCommand({ ...input, projectRoot: context.projectRoot });
6618
+ const env = {
6619
+ ...process.env,
6620
+ ...buildPiRigSessionEnv({
6621
+ projectRoot: context.projectRoot,
6622
+ runId: input.runId,
6623
+ taskId: input.taskId,
6624
+ serverUrl: server.baseUrl,
6625
+ authToken: server.authToken
6626
+ })
6627
+ };
6628
+ process.stdout.write(`Launching Pi for Rig run ${input.runId}\u2026
6629
+ `);
6630
+ process.stdout.write(`Pi command: ${formatCommand(command)}
6631
+ `);
6632
+ const launchedAt = Date.now();
6633
+ const child = spawn2(command[0], command.slice(1), {
6634
+ cwd: context.projectRoot,
6635
+ env,
6636
+ stdio: "inherit"
6637
+ });
6638
+ const launchError = await new Promise((resolve19) => {
6639
+ child.once("error", (error) => {
6640
+ resolve19({ error: error.message });
6641
+ });
6642
+ child.once("close", (code) => resolve19({ code }));
6643
+ });
6644
+ if ("error" in launchError) {
6645
+ process.stderr.write(`Failed to launch Pi; falling back to Rig attach view: ${launchError.error}
6646
+ `);
6647
+ return { launched: false, exitCode: null, command, error: launchError.error };
6648
+ }
6649
+ const exitCode = launchError.code;
6650
+ const elapsedMs = Date.now() - launchedAt;
6651
+ if (typeof exitCode === "number" && exitCode !== 0 && elapsedMs < 5000) {
6652
+ const error = `Pi exited during startup with code ${exitCode}.`;
6653
+ process.stderr.write(`${error} Falling back to Rig attach view.
6654
+ `);
6655
+ return { launched: false, exitCode, command, error };
6656
+ }
6657
+ return { launched: true, exitCode, command };
6658
+ }
6659
+
6472
6660
  // packages/cli/src/commands/run.ts
6473
6661
  function normalizeRemoteRunDetails(payload) {
6474
6662
  const run = payload.run;
@@ -6570,13 +6758,7 @@ async function executeRun(context, args) {
6570
6758
  requireNoExtraArgs(rest, "bun run rig run list");
6571
6759
  const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
6572
6760
  if (context.outputMode === "text") {
6573
- if (runs.length === 0) {
6574
- console.log(source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
6575
- } else {
6576
- for (const run of runs) {
6577
- console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runDisplayTitle(run)}`);
6578
- }
6579
- }
6761
+ console.log(formatRunList(runs, { source }));
6580
6762
  }
6581
6763
  return { ok: true, group: "run", command, details: { runs, source } };
6582
6764
  }
@@ -6698,14 +6880,26 @@ async function executeRun(context, args) {
6698
6880
  if (!runId) {
6699
6881
  throw new CliError2("run attach requires a run id.", 2);
6700
6882
  }
6883
+ let steered = false;
6884
+ const shouldTryPiAttach = context.outputMode === "text" && follow.value && !once.value && Boolean(process.stdin.isTTY && process.stdout.isTTY) && process.env.RIG_DISABLE_PI_LAUNCH !== "1";
6885
+ if (shouldTryPiAttach && messageOption.value?.trim()) {
6886
+ await steerRunViaServer(context, runId, messageOption.value.trim());
6887
+ steered = true;
6888
+ }
6889
+ if (shouldTryPiAttach) {
6890
+ const piSession = await launchPiRigSession(context, { runId });
6891
+ if (piSession.launched) {
6892
+ return { ok: true, group: "run", command, details: { runId, steered, mode: "pi", ...piSession } };
6893
+ }
6894
+ }
6701
6895
  const attached = await attachRunOperatorView(context, {
6702
6896
  runId,
6703
- message: messageOption.value ?? null,
6897
+ message: shouldTryPiAttach ? null : messageOption.value ?? null,
6704
6898
  once: once.value,
6705
6899
  follow: follow.value,
6706
6900
  pollMs: parsePositiveInt(pollMs.value, "--poll-ms", 2000)
6707
6901
  });
6708
- return { ok: true, group: "run", command, details: attached };
6902
+ return { ok: true, group: "run", command, details: { ...attached, steered: attached.steered || steered } };
6709
6903
  }
6710
6904
  case "status": {
6711
6905
  requireNoExtraArgs(rest, "bun run rig run status");
@@ -6971,8 +7165,8 @@ async function executeServer(context, args, options) {
6971
7165
  // packages/cli/src/commands/task.ts
6972
7166
  import { readFileSync as readFileSync9 } from "fs";
6973
7167
  import { spawnSync as spawnSync3 } from "child_process";
6974
- import { createInterface as createInterface3 } from "readline/promises";
6975
7168
  import { resolve as resolve19 } from "path";
7169
+ import { cancel as cancel3, confirm as confirm2, isCancel as isCancel3 } from "@clack/prompts";
6976
7170
  import {
6977
7171
  taskArtifactDir,
6978
7172
  taskArtifacts,
@@ -6990,6 +7184,7 @@ import {
6990
7184
  } from "@rig/runtime/control-plane/native/task-ops";
6991
7185
 
6992
7186
  // packages/cli/src/commands/_task-picker.ts
7187
+ import { cancel as cancel2, isCancel as isCancel2, select as select2 } from "@clack/prompts";
6993
7188
  function taskId2(task) {
6994
7189
  return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
6995
7190
  }
@@ -7002,20 +7197,37 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
7002
7197
  if (!isTty) {
7003
7198
  throw new Error("task run requires an interactive terminal to pick a task; pass --task <id>, --next, or --detach with a task id.");
7004
7199
  }
7005
- const prompt = io.prompt ?? promptForTaskSelection;
7006
- const renderer = io.renderer ?? { writeLine: (line) => process.stdout.write(`${line}
7200
+ if (io.prompt || io.renderer) {
7201
+ const prompt = io.prompt ?? promptForTaskSelection;
7202
+ const renderer = io.renderer ?? { writeLine: (line) => process.stdout.write(`${line}
7007
7203
  `) };
7008
- renderer.writeLine("Select Rig task:");
7009
- for (const row of renderTaskPickerRows(tasks))
7010
- renderer.writeLine(` ${row}`);
7011
- const answer = (await prompt(`Task [1-${tasks.length}] or id: `)).trim();
7012
- if (!answer)
7204
+ renderer.writeLine("Select Rig task:");
7205
+ for (const row of renderTaskPickerRows(tasks))
7206
+ renderer.writeLine(` ${row}`);
7207
+ const answer2 = (await prompt(`Task [1-${tasks.length}] or id: `)).trim();
7208
+ if (!answer2)
7209
+ return null;
7210
+ if (/^\d+$/.test(answer2)) {
7211
+ const index2 = Number.parseInt(answer2, 10) - 1;
7212
+ return tasks[index2] ?? null;
7213
+ }
7214
+ return tasks.find((task) => taskId2(task) === answer2) ?? null;
7215
+ }
7216
+ const options = tasks.map((task, index2) => ({
7217
+ value: `${index2}`,
7218
+ label: `${taskId2(task)} \xB7 ${typeof task.title === "string" && task.title.trim() ? task.title.trim() : "Untitled task"}`,
7219
+ hint: typeof task.status === "string" && task.status.trim() ? task.status.trim() : undefined
7220
+ }));
7221
+ const answer = await select2({
7222
+ message: "Select Rig task",
7223
+ options
7224
+ });
7225
+ if (isCancel2(answer)) {
7226
+ cancel2("No task selected.");
7013
7227
  return null;
7014
- if (/^\d+$/.test(answer)) {
7015
- const index = Number.parseInt(answer, 10) - 1;
7016
- return tasks[index] ?? null;
7017
7228
  }
7018
- return tasks.find((task) => taskId2(task) === answer) ?? null;
7229
+ const index = Number.parseInt(String(answer), 10);
7230
+ return Number.isFinite(index) ? tasks[index] ?? null : null;
7019
7231
  }
7020
7232
 
7021
7233
  // packages/cli/src/commands/task.ts
@@ -7127,13 +7339,15 @@ async function resolveDirtyBaselineForTaskRun(context, explicit) {
7127
7339
  if (explicit)
7128
7340
  return { mode: explicit, state };
7129
7341
  if (context.outputMode === "text" && process.stdin.isTTY && process.stdout.isTTY) {
7130
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
7131
- try {
7132
- const answer = (await rl.question("Include current uncommitted changes in run baseline? [y/N] ")).trim().toLowerCase();
7133
- return { mode: answer === "y" || answer === "yes" ? "dirty-snapshot" : "head", state };
7134
- } finally {
7135
- rl.close();
7342
+ const answer = await confirm2({
7343
+ message: "Include current uncommitted changes in run baseline?",
7344
+ initialValue: false
7345
+ });
7346
+ if (isCancel3(answer)) {
7347
+ cancel3("Run cancelled.");
7348
+ throw new CliError2("Run cancelled by user.", 1);
7136
7349
  }
7350
+ return { mode: answer ? "dirty-snapshot" : "head", state };
7137
7351
  }
7138
7352
  return { mode: "head", state };
7139
7353
  }
@@ -7168,10 +7382,7 @@ function summarizeTask(task, options = {}) {
7168
7382
  };
7169
7383
  }
7170
7384
  function printTaskSummary(task) {
7171
- const id = readTaskId(task) ?? "<unknown>";
7172
- const title = readTaskString(task, "title") ?? "Untitled task";
7173
- const status = readTaskString(task, "status") ?? "unknown";
7174
- console.log(`- ${id} \xB7 ${status} \xB7 ${title}`);
7385
+ console.log(formatTaskList([task]));
7175
7386
  }
7176
7387
  async function validatorRegistryForTaskCommands(projectRoot) {
7177
7388
  return buildPluginHostContext(projectRoot).then((ctx) => ctx?.validatorRegistry ?? undefined).catch(() => {
@@ -7189,16 +7400,8 @@ async function executeTask(context, args, options) {
7189
7400
  requireNoExtraArgs(remaining, "bun run rig task list [--raw] [--assignee <login|@me>] [--assigned-to <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
7190
7401
  const tasks = await listWorkspaceTasksViaServer(context, filters);
7191
7402
  if (context.outputMode === "text") {
7192
- if (tasks.length === 0) {
7193
- console.log("No matching tasks.");
7194
- } else {
7195
- for (const task of tasks) {
7196
- if (rawResult.value)
7197
- console.log(JSON.stringify(summarizeTask(task, { raw: true })));
7198
- else
7199
- printTaskSummary(task);
7200
- }
7201
- }
7403
+ const renderedTasks = rawResult.value ? tasks.map((task) => summarizeTask(task, { raw: true })) : tasks.map((task) => summarizeTask(task));
7404
+ console.log(formatTaskList(renderedTasks, { raw: rawResult.value }));
7202
7405
  }
7203
7406
  return {
7204
7407
  ok: true,
@@ -7417,16 +7620,23 @@ async function executeTask(context, args, options) {
7417
7620
  });
7418
7621
  let attachDetails = null;
7419
7622
  if (!detachResult.value && context.outputMode === "text") {
7420
- console.log(`Run submitted: ${submitted.runId}`);
7421
- if (selectedTask) {
7422
- printTaskSummary(selectedTask);
7623
+ console.log(formatSubmittedRun({ runId: submitted.runId, task: selectedTask ? summarizeTask(selectedTask) : null }));
7624
+ if (runtimeAdapter === "pi") {
7625
+ const piSession = await launchPiRigSession(context, {
7626
+ runId: submitted.runId,
7627
+ taskId: selectedTaskId,
7628
+ title: titleResult.value ?? readTaskString(selectedTask ?? {}, "title"),
7629
+ runtimeAdapter
7630
+ });
7631
+ attachDetails = { mode: "pi", ...piSession };
7632
+ if (!piSession.launched) {
7633
+ attachDetails = await attachRunOperatorView(context, { runId: submitted.runId, follow: true });
7634
+ }
7635
+ } else {
7636
+ attachDetails = await attachRunOperatorView(context, { runId: submitted.runId, follow: true });
7423
7637
  }
7424
- attachDetails = await attachRunOperatorView(context, { runId: submitted.runId, follow: true });
7425
7638
  } else if (context.outputMode === "text") {
7426
- console.log(`Run submitted: ${submitted.runId}`);
7427
- if (selectedTask) {
7428
- printTaskSummary(selectedTask);
7429
- }
7639
+ console.log(formatSubmittedRun({ runId: submitted.runId, task: selectedTask ? summarizeTask(selectedTask) : null }));
7430
7640
  }
7431
7641
  return {
7432
7642
  ok: true,
@@ -7511,7 +7721,7 @@ async function executeTask(context, args, options) {
7511
7721
  // packages/cli/src/commands/task-run-driver.ts
7512
7722
  import { copyFileSync as copyFileSync3, existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7513
7723
  import { resolve as resolve20 } from "path";
7514
- import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
7724
+ import { spawn as spawn3, spawnSync as spawnSync4 } from "child_process";
7515
7725
  import { createInterface as createLineInterface } from "readline";
7516
7726
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
7517
7727
  import {
@@ -7739,7 +7949,7 @@ async function runCheckedCommand(command, args, cwd, label = "git") {
7739
7949
  }
7740
7950
  function createCommandRunner(binary) {
7741
7951
  return async (args, options) => {
7742
- const child = spawn2(binary, [...args], {
7952
+ const child = spawn3(binary, [...args], {
7743
7953
  cwd: options?.cwd,
7744
7954
  stdio: ["ignore", "pipe", "pipe"]
7745
7955
  });
@@ -8853,7 +9063,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8853
9063
  }
8854
9064
  for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
8855
9065
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
8856
- const child = spawn2(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
9066
+ const child = spawn3(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
8857
9067
  cwd: context.projectRoot,
8858
9068
  env: childEnv,
8859
9069
  stdio: ["pipe", "pipe", "pipe"]
@@ -9200,7 +9410,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
9200
9410
  });
9201
9411
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Steering Pi from PR feedback" });
9202
9412
  const feedbackCommand = buildHostAgentCommand(message2);
9203
- const child = spawn2(feedbackCommand[0], feedbackCommand.slice(1), {
9413
+ const child = spawn3(feedbackCommand[0], feedbackCommand.slice(1), {
9204
9414
  cwd: latestRuntimeWorkspace ?? context.projectRoot,
9205
9415
  env: childEnv,
9206
9416
  stdio: ["pipe", "pipe", "pipe"]