@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.
package/dist/bin/rig.js CHANGED
@@ -2990,7 +2990,8 @@ async function submitTaskRunViaServer(context, input) {
2990
2990
  import { existsSync as existsSync6, readFileSync as readFileSync4, rmSync as rmSync3 } from "fs";
2991
2991
  import { homedir as homedir3 } from "os";
2992
2992
  import { resolve as resolve10 } from "path";
2993
- var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
2993
+ var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
2994
+ var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
2994
2995
  var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
2995
2996
  export { default } from '@rig/pi-rig';
2996
2997
  `;
@@ -3018,7 +3019,7 @@ function resolvePiHomeDir(inputHomeDir) {
3018
3019
  function piListContainsPiRig(output) {
3019
3020
  return output.split(/\r?\n/).some((line) => {
3020
3021
  const normalized = line.trim();
3021
- return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
3022
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
3022
3023
  });
3023
3024
  }
3024
3025
  async function safeRun(runner, command, options) {
@@ -3134,7 +3135,7 @@ async function ensureRemotePiRigInstalled(input) {
3134
3135
  const payload = await input.requestJson("/api/pi-rig/install", {
3135
3136
  method: "POST",
3136
3137
  headers: { "content-type": "application/json" },
3137
- body: JSON.stringify({ package: "@rig/pi-rig", scope: "global" })
3138
+ body: JSON.stringify({ package: PI_RIG_PACKAGE_NAME, scope: "global" })
3138
3139
  });
3139
3140
  const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
3140
3141
  const piOk = record.piOk === true || record.ok === true;
@@ -6676,6 +6677,193 @@ async function attachRunOperatorView(context, input) {
6676
6677
  return { ...snapshot, steered, detached };
6677
6678
  }
6678
6679
 
6680
+ // packages/cli/src/commands/_cli-format.ts
6681
+ import pc3 from "picocolors";
6682
+ function stringField(record, key, fallback = "") {
6683
+ const value = record[key];
6684
+ return typeof value === "string" && value.trim() ? value.trim() : fallback;
6685
+ }
6686
+ function arrayField(record, key) {
6687
+ const value = record[key];
6688
+ return Array.isArray(value) ? value.flatMap((entry) => typeof entry === "string" && entry.trim() ? [entry.trim()] : []) : [];
6689
+ }
6690
+ function rawObject(record) {
6691
+ const raw = record.raw;
6692
+ return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
6693
+ }
6694
+ function truncate(value, width) {
6695
+ if (value.length <= width)
6696
+ return value;
6697
+ if (width <= 1)
6698
+ return "\u2026";
6699
+ return `${value.slice(0, width - 1)}\u2026`;
6700
+ }
6701
+ function pad(value, width) {
6702
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
6703
+ }
6704
+ function statusColor(status) {
6705
+ const normalized = status.toLowerCase();
6706
+ if (["completed", "merged", "closed", "done", "accepted"].includes(normalized))
6707
+ return pc3.green;
6708
+ if (["failed", "needs_attention", "needs-attention", "blocked"].includes(normalized))
6709
+ return pc3.red;
6710
+ if (["running", "reviewing", "validating", "in_progress", "in-progress"].includes(normalized))
6711
+ return pc3.cyan;
6712
+ if (["ready", "open", "queued", "created", "preparing"].includes(normalized))
6713
+ return pc3.yellow;
6714
+ return pc3.dim;
6715
+ }
6716
+ function formatTaskList(tasks, options = {}) {
6717
+ if (tasks.length === 0)
6718
+ return pc3.dim("No matching tasks.");
6719
+ if (options.raw)
6720
+ return tasks.map((task) => JSON.stringify(task)).join(`
6721
+ `);
6722
+ const rows = tasks.map((task) => {
6723
+ const raw = rawObject(task);
6724
+ const id = stringField(task, "id", "<unknown>");
6725
+ const status = stringField(task, "status", "unknown");
6726
+ const title = stringField(task, "title", "Untitled task");
6727
+ const source = stringField(task, "source", stringField(raw, "source", ""));
6728
+ const labels = arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels");
6729
+ return { id, status, title, source, labels };
6730
+ });
6731
+ const idWidth = Math.min(18, Math.max(4, ...rows.map((row) => row.id.length)));
6732
+ const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
6733
+ const header = `${pc3.bold(pad("TASK", idWidth))} ${pc3.bold(pad("STATUS", statusWidth))} ${pc3.bold("TITLE")}`;
6734
+ const body = rows.map((row) => {
6735
+ const labels = row.labels.length > 0 ? pc3.dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
6736
+ const source = row.source ? pc3.dim(` ${row.source}`) : "";
6737
+ return [
6738
+ pc3.bold(pad(truncate(row.id, idWidth), idWidth)),
6739
+ statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
6740
+ `${row.title}${labels}${source}`
6741
+ ].join(" ");
6742
+ });
6743
+ return [pc3.bold("Rig tasks"), header, ...body].join(`
6744
+ `);
6745
+ }
6746
+ function formatRunList(runs, options = {}) {
6747
+ if (runs.length === 0) {
6748
+ return pc3.dim(options.source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
6749
+ }
6750
+ const rows = runs.map((run) => {
6751
+ const runId = stringField(run, "runId", stringField(run, "id", "(unknown-run)"));
6752
+ const status = stringField(run, "status", "unknown");
6753
+ const taskId2 = stringField(run, "taskId", "");
6754
+ const title = stringField(run, "title", taskId2 || "(untitled)");
6755
+ const runtime = stringField(run, "runtimeAdapter", "");
6756
+ return { runId, status, title, runtime };
6757
+ });
6758
+ const idWidth = Math.min(36, Math.max(6, ...rows.map((row) => row.runId.length)));
6759
+ const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
6760
+ const header = `${pc3.bold(pad("RUN", idWidth))} ${pc3.bold(pad("STATUS", statusWidth))} ${pc3.bold("TITLE")}`;
6761
+ const body = rows.map((row) => [
6762
+ pc3.bold(pad(truncate(row.runId, idWidth), idWidth)),
6763
+ statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
6764
+ `${row.title}${row.runtime ? pc3.dim(` ${row.runtime}`) : ""}`
6765
+ ].join(" "));
6766
+ return [pc3.bold(options.source === "server" ? "Rig runs (server)" : "Rig runs"), header, ...body].join(`
6767
+ `);
6768
+ }
6769
+ function formatSubmittedRun(input) {
6770
+ const lines = [`${pc3.green("Run submitted")}: ${pc3.bold(input.runId)}`];
6771
+ if (input.task) {
6772
+ const id = stringField(input.task, "id", "<unknown>");
6773
+ const status = stringField(input.task, "status", "unknown");
6774
+ const title = stringField(input.task, "title", "Untitled task");
6775
+ lines.push(`${pc3.dim("task")} ${pc3.bold(id)} ${statusColor(status)(status)} ${title}`);
6776
+ }
6777
+ return lines.join(`
6778
+ `);
6779
+ }
6780
+
6781
+ // packages/cli/src/commands/_pi-session.ts
6782
+ import { spawn as spawn2 } from "child_process";
6783
+ function buildPiRigSessionEnv(input) {
6784
+ return {
6785
+ RIG_PROJECT_ROOT: input.projectRoot,
6786
+ PROJECT_RIG_ROOT: input.projectRoot,
6787
+ RIG_RUN_ID: input.runId,
6788
+ RIG_SERVER_RUN_ID: input.runId,
6789
+ RIG_RUNTIME_ADAPTER: "pi",
6790
+ RIG_SERVER_URL: input.serverUrl,
6791
+ RIG_SERVER_BASE_URL: input.serverUrl,
6792
+ RIG_STEERING_POLL_MS: process.env.RIG_STEERING_POLL_MS?.trim() || "1000",
6793
+ RIG_PI_OPERATOR_SESSION: "1",
6794
+ ...input.taskId ? { RIG_TASK_ID: input.taskId } : {},
6795
+ ...input.authToken ? { RIG_AUTH_TOKEN: input.authToken } : {}
6796
+ };
6797
+ }
6798
+ function shellBinary(name) {
6799
+ const explicit = process.env.RIG_PI_BINARY?.trim();
6800
+ if (explicit)
6801
+ return explicit;
6802
+ return Bun.which(name) || name;
6803
+ }
6804
+ function buildPiRigSessionCommand(input) {
6805
+ const configuredExtension = input.extensionSource ?? process.env.RIG_PI_RIG_EXTENSION_SOURCE?.trim();
6806
+ const extensionSource = configuredExtension && configuredExtension.length > 0 ? configuredExtension : resolvePiRigPackageSource(input.projectRoot);
6807
+ const initialCommand = `/rig attach ${input.runId}`;
6808
+ return [
6809
+ shellBinary("pi"),
6810
+ "--no-extensions",
6811
+ "--extension",
6812
+ extensionSource,
6813
+ initialCommand
6814
+ ];
6815
+ }
6816
+ async function launchPiRigSession(context, input) {
6817
+ if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
6818
+ return { launched: false, exitCode: null, command: [] };
6819
+ }
6820
+ if (process.env.RIG_DISABLE_PI_LAUNCH === "1") {
6821
+ return { launched: false, exitCode: null, command: [] };
6822
+ }
6823
+ const server = await ensureServerForCli(context.projectRoot);
6824
+ const command = buildPiRigSessionCommand({ ...input, projectRoot: context.projectRoot });
6825
+ const env = {
6826
+ ...process.env,
6827
+ ...buildPiRigSessionEnv({
6828
+ projectRoot: context.projectRoot,
6829
+ runId: input.runId,
6830
+ taskId: input.taskId,
6831
+ serverUrl: server.baseUrl,
6832
+ authToken: server.authToken
6833
+ })
6834
+ };
6835
+ process.stdout.write(`Launching Pi for Rig run ${input.runId}\u2026
6836
+ `);
6837
+ process.stdout.write(`Pi command: ${formatCommand(command)}
6838
+ `);
6839
+ const launchedAt = Date.now();
6840
+ const child = spawn2(command[0], command.slice(1), {
6841
+ cwd: context.projectRoot,
6842
+ env,
6843
+ stdio: "inherit"
6844
+ });
6845
+ const launchError = await new Promise((resolve20) => {
6846
+ child.once("error", (error) => {
6847
+ resolve20({ error: error.message });
6848
+ });
6849
+ child.once("close", (code) => resolve20({ code }));
6850
+ });
6851
+ if ("error" in launchError) {
6852
+ process.stderr.write(`Failed to launch Pi; falling back to Rig attach view: ${launchError.error}
6853
+ `);
6854
+ return { launched: false, exitCode: null, command, error: launchError.error };
6855
+ }
6856
+ const exitCode = launchError.code;
6857
+ const elapsedMs = Date.now() - launchedAt;
6858
+ if (typeof exitCode === "number" && exitCode !== 0 && elapsedMs < 5000) {
6859
+ const error = `Pi exited during startup with code ${exitCode}.`;
6860
+ process.stderr.write(`${error} Falling back to Rig attach view.
6861
+ `);
6862
+ return { launched: false, exitCode, command, error };
6863
+ }
6864
+ return { launched: true, exitCode, command };
6865
+ }
6866
+
6679
6867
  // packages/cli/src/commands/run.ts
6680
6868
  function normalizeRemoteRunDetails(payload) {
6681
6869
  const run = payload.run;
@@ -6777,13 +6965,7 @@ async function executeRun(context, args) {
6777
6965
  requireNoExtraArgs(rest, "bun run rig run list");
6778
6966
  const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
6779
6967
  if (context.outputMode === "text") {
6780
- if (runs.length === 0) {
6781
- console.log(source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
6782
- } else {
6783
- for (const run of runs) {
6784
- console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runDisplayTitle(run)}`);
6785
- }
6786
- }
6968
+ console.log(formatRunList(runs, { source }));
6787
6969
  }
6788
6970
  return { ok: true, group: "run", command, details: { runs, source } };
6789
6971
  }
@@ -6905,14 +7087,26 @@ async function executeRun(context, args) {
6905
7087
  if (!runId) {
6906
7088
  throw new CliError2("run attach requires a run id.", 2);
6907
7089
  }
7090
+ let steered = false;
7091
+ const shouldTryPiAttach = context.outputMode === "text" && follow.value && !once.value && Boolean(process.stdin.isTTY && process.stdout.isTTY) && process.env.RIG_DISABLE_PI_LAUNCH !== "1";
7092
+ if (shouldTryPiAttach && messageOption.value?.trim()) {
7093
+ await steerRunViaServer(context, runId, messageOption.value.trim());
7094
+ steered = true;
7095
+ }
7096
+ if (shouldTryPiAttach) {
7097
+ const piSession = await launchPiRigSession(context, { runId });
7098
+ if (piSession.launched) {
7099
+ return { ok: true, group: "run", command, details: { runId, steered, mode: "pi", ...piSession } };
7100
+ }
7101
+ }
6908
7102
  const attached = await attachRunOperatorView(context, {
6909
7103
  runId,
6910
- message: messageOption.value ?? null,
7104
+ message: shouldTryPiAttach ? null : messageOption.value ?? null,
6911
7105
  once: once.value,
6912
7106
  follow: follow.value,
6913
7107
  pollMs: parsePositiveInt(pollMs.value, "--poll-ms", 2000)
6914
7108
  });
6915
- return { ok: true, group: "run", command, details: attached };
7109
+ return { ok: true, group: "run", command, details: { ...attached, steered: attached.steered || steered } };
6916
7110
  }
6917
7111
  case "status": {
6918
7112
  requireNoExtraArgs(rest, "bun run rig run status");
@@ -7178,8 +7372,8 @@ async function executeServer(context, args, options) {
7178
7372
  // packages/cli/src/commands/task.ts
7179
7373
  import { readFileSync as readFileSync9 } from "fs";
7180
7374
  import { spawnSync as spawnSync3 } from "child_process";
7181
- import { createInterface as createInterface3 } from "readline/promises";
7182
7375
  import { resolve as resolve20 } from "path";
7376
+ import { cancel as cancel3, confirm as confirm2, isCancel as isCancel3 } from "@clack/prompts";
7183
7377
  import {
7184
7378
  taskArtifactDir,
7185
7379
  taskArtifacts,
@@ -7197,6 +7391,7 @@ import {
7197
7391
  } from "@rig/runtime/control-plane/native/task-ops";
7198
7392
 
7199
7393
  // packages/cli/src/commands/_task-picker.ts
7394
+ import { cancel as cancel2, isCancel as isCancel2, select as select2 } from "@clack/prompts";
7200
7395
  function taskId2(task) {
7201
7396
  return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
7202
7397
  }
@@ -7209,20 +7404,37 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
7209
7404
  if (!isTty) {
7210
7405
  throw new Error("task run requires an interactive terminal to pick a task; pass --task <id>, --next, or --detach with a task id.");
7211
7406
  }
7212
- const prompt = io.prompt ?? promptForTaskSelection;
7213
- const renderer = io.renderer ?? { writeLine: (line) => process.stdout.write(`${line}
7407
+ if (io.prompt || io.renderer) {
7408
+ const prompt = io.prompt ?? promptForTaskSelection;
7409
+ const renderer = io.renderer ?? { writeLine: (line) => process.stdout.write(`${line}
7214
7410
  `) };
7215
- renderer.writeLine("Select Rig task:");
7216
- for (const row of renderTaskPickerRows(tasks))
7217
- renderer.writeLine(` ${row}`);
7218
- const answer = (await prompt(`Task [1-${tasks.length}] or id: `)).trim();
7219
- if (!answer)
7411
+ renderer.writeLine("Select Rig task:");
7412
+ for (const row of renderTaskPickerRows(tasks))
7413
+ renderer.writeLine(` ${row}`);
7414
+ const answer2 = (await prompt(`Task [1-${tasks.length}] or id: `)).trim();
7415
+ if (!answer2)
7416
+ return null;
7417
+ if (/^\d+$/.test(answer2)) {
7418
+ const index2 = Number.parseInt(answer2, 10) - 1;
7419
+ return tasks[index2] ?? null;
7420
+ }
7421
+ return tasks.find((task) => taskId2(task) === answer2) ?? null;
7422
+ }
7423
+ const options = tasks.map((task, index2) => ({
7424
+ value: `${index2}`,
7425
+ label: `${taskId2(task)} \xB7 ${typeof task.title === "string" && task.title.trim() ? task.title.trim() : "Untitled task"}`,
7426
+ hint: typeof task.status === "string" && task.status.trim() ? task.status.trim() : undefined
7427
+ }));
7428
+ const answer = await select2({
7429
+ message: "Select Rig task",
7430
+ options
7431
+ });
7432
+ if (isCancel2(answer)) {
7433
+ cancel2("No task selected.");
7220
7434
  return null;
7221
- if (/^\d+$/.test(answer)) {
7222
- const index = Number.parseInt(answer, 10) - 1;
7223
- return tasks[index] ?? null;
7224
7435
  }
7225
- return tasks.find((task) => taskId2(task) === answer) ?? null;
7436
+ const index = Number.parseInt(String(answer), 10);
7437
+ return Number.isFinite(index) ? tasks[index] ?? null : null;
7226
7438
  }
7227
7439
 
7228
7440
  // packages/cli/src/commands/task.ts
@@ -7334,13 +7546,15 @@ async function resolveDirtyBaselineForTaskRun(context, explicit) {
7334
7546
  if (explicit)
7335
7547
  return { mode: explicit, state };
7336
7548
  if (context.outputMode === "text" && process.stdin.isTTY && process.stdout.isTTY) {
7337
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
7338
- try {
7339
- const answer = (await rl.question("Include current uncommitted changes in run baseline? [y/N] ")).trim().toLowerCase();
7340
- return { mode: answer === "y" || answer === "yes" ? "dirty-snapshot" : "head", state };
7341
- } finally {
7342
- rl.close();
7549
+ const answer = await confirm2({
7550
+ message: "Include current uncommitted changes in run baseline?",
7551
+ initialValue: false
7552
+ });
7553
+ if (isCancel3(answer)) {
7554
+ cancel3("Run cancelled.");
7555
+ throw new CliError2("Run cancelled by user.", 1);
7343
7556
  }
7557
+ return { mode: answer ? "dirty-snapshot" : "head", state };
7344
7558
  }
7345
7559
  return { mode: "head", state };
7346
7560
  }
@@ -7375,10 +7589,7 @@ function summarizeTask(task, options = {}) {
7375
7589
  };
7376
7590
  }
7377
7591
  function printTaskSummary(task) {
7378
- const id = readTaskId(task) ?? "<unknown>";
7379
- const title = readTaskString(task, "title") ?? "Untitled task";
7380
- const status = readTaskString(task, "status") ?? "unknown";
7381
- console.log(`- ${id} \xB7 ${status} \xB7 ${title}`);
7592
+ console.log(formatTaskList([task]));
7382
7593
  }
7383
7594
  async function validatorRegistryForTaskCommands(projectRoot) {
7384
7595
  return buildPluginHostContext(projectRoot).then((ctx) => ctx?.validatorRegistry ?? undefined).catch(() => {
@@ -7396,16 +7607,8 @@ async function executeTask(context, args, options) {
7396
7607
  requireNoExtraArgs(remaining, "bun run rig task list [--raw] [--assignee <login|@me>] [--assigned-to <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
7397
7608
  const tasks = await listWorkspaceTasksViaServer(context, filters);
7398
7609
  if (context.outputMode === "text") {
7399
- if (tasks.length === 0) {
7400
- console.log("No matching tasks.");
7401
- } else {
7402
- for (const task of tasks) {
7403
- if (rawResult.value)
7404
- console.log(JSON.stringify(summarizeTask(task, { raw: true })));
7405
- else
7406
- printTaskSummary(task);
7407
- }
7408
- }
7610
+ const renderedTasks = rawResult.value ? tasks.map((task) => summarizeTask(task, { raw: true })) : tasks.map((task) => summarizeTask(task));
7611
+ console.log(formatTaskList(renderedTasks, { raw: rawResult.value }));
7409
7612
  }
7410
7613
  return {
7411
7614
  ok: true,
@@ -7624,16 +7827,23 @@ async function executeTask(context, args, options) {
7624
7827
  });
7625
7828
  let attachDetails = null;
7626
7829
  if (!detachResult.value && context.outputMode === "text") {
7627
- console.log(`Run submitted: ${submitted.runId}`);
7628
- if (selectedTask) {
7629
- printTaskSummary(selectedTask);
7830
+ console.log(formatSubmittedRun({ runId: submitted.runId, task: selectedTask ? summarizeTask(selectedTask) : null }));
7831
+ if (runtimeAdapter === "pi") {
7832
+ const piSession = await launchPiRigSession(context, {
7833
+ runId: submitted.runId,
7834
+ taskId: selectedTaskId,
7835
+ title: titleResult.value ?? readTaskString(selectedTask ?? {}, "title"),
7836
+ runtimeAdapter
7837
+ });
7838
+ attachDetails = { mode: "pi", ...piSession };
7839
+ if (!piSession.launched) {
7840
+ attachDetails = await attachRunOperatorView(context, { runId: submitted.runId, follow: true });
7841
+ }
7842
+ } else {
7843
+ attachDetails = await attachRunOperatorView(context, { runId: submitted.runId, follow: true });
7630
7844
  }
7631
- attachDetails = await attachRunOperatorView(context, { runId: submitted.runId, follow: true });
7632
7845
  } else if (context.outputMode === "text") {
7633
- console.log(`Run submitted: ${submitted.runId}`);
7634
- if (selectedTask) {
7635
- printTaskSummary(selectedTask);
7636
- }
7846
+ console.log(formatSubmittedRun({ runId: submitted.runId, task: selectedTask ? summarizeTask(selectedTask) : null }));
7637
7847
  }
7638
7848
  return {
7639
7849
  ok: true,
@@ -7718,7 +7928,7 @@ async function executeTask(context, args, options) {
7718
7928
  // packages/cli/src/commands/task-run-driver.ts
7719
7929
  import { copyFileSync as copyFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7720
7930
  import { resolve as resolve21 } from "path";
7721
- import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
7931
+ import { spawn as spawn3, spawnSync as spawnSync4 } from "child_process";
7722
7932
  import { createInterface as createLineInterface } from "readline";
7723
7933
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
7724
7934
  import {
@@ -7946,7 +8156,7 @@ async function runCheckedCommand(command, args, cwd, label = "git") {
7946
8156
  }
7947
8157
  function createCommandRunner(binary) {
7948
8158
  return async (args, options) => {
7949
- const child = spawn2(binary, [...args], {
8159
+ const child = spawn3(binary, [...args], {
7950
8160
  cwd: options?.cwd,
7951
8161
  stdio: ["ignore", "pipe", "pipe"]
7952
8162
  });
@@ -9060,7 +9270,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
9060
9270
  }
9061
9271
  for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
9062
9272
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
9063
- const child = spawn2(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
9273
+ const child = spawn3(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
9064
9274
  cwd: context.projectRoot,
9065
9275
  env: childEnv,
9066
9276
  stdio: ["pipe", "pipe", "pipe"]
@@ -9407,7 +9617,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
9407
9617
  });
9408
9618
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Steering Pi from PR feedback" });
9409
9619
  const feedbackCommand = buildHostAgentCommand(message2);
9410
- const child = spawn2(feedbackCommand[0], feedbackCommand.slice(1), {
9620
+ const child = spawn3(feedbackCommand[0], feedbackCommand.slice(1), {
9411
9621
  cwd: latestRuntimeWorkspace ?? context.projectRoot,
9412
9622
  env: childEnv,
9413
9623
  stdio: ["pipe", "pipe", "pipe"]
@@ -0,0 +1,106 @@
1
+ // @bun
2
+ // packages/cli/src/commands/_cli-format.ts
3
+ import pc from "picocolors";
4
+ function stringField(record, key, fallback = "") {
5
+ const value = record[key];
6
+ return typeof value === "string" && value.trim() ? value.trim() : fallback;
7
+ }
8
+ function arrayField(record, key) {
9
+ const value = record[key];
10
+ return Array.isArray(value) ? value.flatMap((entry) => typeof entry === "string" && entry.trim() ? [entry.trim()] : []) : [];
11
+ }
12
+ function rawObject(record) {
13
+ const raw = record.raw;
14
+ return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
15
+ }
16
+ function truncate(value, width) {
17
+ if (value.length <= width)
18
+ return value;
19
+ if (width <= 1)
20
+ return "\u2026";
21
+ return `${value.slice(0, width - 1)}\u2026`;
22
+ }
23
+ function pad(value, width) {
24
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
25
+ }
26
+ function statusColor(status) {
27
+ const normalized = status.toLowerCase();
28
+ if (["completed", "merged", "closed", "done", "accepted"].includes(normalized))
29
+ return pc.green;
30
+ if (["failed", "needs_attention", "needs-attention", "blocked"].includes(normalized))
31
+ return pc.red;
32
+ if (["running", "reviewing", "validating", "in_progress", "in-progress"].includes(normalized))
33
+ return pc.cyan;
34
+ if (["ready", "open", "queued", "created", "preparing"].includes(normalized))
35
+ return pc.yellow;
36
+ return pc.dim;
37
+ }
38
+ function formatTaskList(tasks, options = {}) {
39
+ if (tasks.length === 0)
40
+ return pc.dim("No matching tasks.");
41
+ if (options.raw)
42
+ return tasks.map((task) => JSON.stringify(task)).join(`
43
+ `);
44
+ const rows = tasks.map((task) => {
45
+ const raw = rawObject(task);
46
+ const id = stringField(task, "id", "<unknown>");
47
+ const status = stringField(task, "status", "unknown");
48
+ const title = stringField(task, "title", "Untitled task");
49
+ const source = stringField(task, "source", stringField(raw, "source", ""));
50
+ const labels = arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels");
51
+ return { id, status, title, source, labels };
52
+ });
53
+ const idWidth = Math.min(18, Math.max(4, ...rows.map((row) => row.id.length)));
54
+ const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
55
+ const header = `${pc.bold(pad("TASK", idWidth))} ${pc.bold(pad("STATUS", statusWidth))} ${pc.bold("TITLE")}`;
56
+ const body = rows.map((row) => {
57
+ const labels = row.labels.length > 0 ? pc.dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
58
+ const source = row.source ? pc.dim(` ${row.source}`) : "";
59
+ return [
60
+ pc.bold(pad(truncate(row.id, idWidth), idWidth)),
61
+ statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
62
+ `${row.title}${labels}${source}`
63
+ ].join(" ");
64
+ });
65
+ return [pc.bold("Rig tasks"), header, ...body].join(`
66
+ `);
67
+ }
68
+ function formatRunList(runs, options = {}) {
69
+ if (runs.length === 0) {
70
+ return pc.dim(options.source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
71
+ }
72
+ const rows = runs.map((run) => {
73
+ const runId = stringField(run, "runId", stringField(run, "id", "(unknown-run)"));
74
+ const status = stringField(run, "status", "unknown");
75
+ const taskId = stringField(run, "taskId", "");
76
+ const title = stringField(run, "title", taskId || "(untitled)");
77
+ const runtime = stringField(run, "runtimeAdapter", "");
78
+ return { runId, status, title, runtime };
79
+ });
80
+ const idWidth = Math.min(36, Math.max(6, ...rows.map((row) => row.runId.length)));
81
+ const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
82
+ const header = `${pc.bold(pad("RUN", idWidth))} ${pc.bold(pad("STATUS", statusWidth))} ${pc.bold("TITLE")}`;
83
+ const body = rows.map((row) => [
84
+ pc.bold(pad(truncate(row.runId, idWidth), idWidth)),
85
+ statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
86
+ `${row.title}${row.runtime ? pc.dim(` ${row.runtime}`) : ""}`
87
+ ].join(" "));
88
+ return [pc.bold(options.source === "server" ? "Rig runs (server)" : "Rig runs"), header, ...body].join(`
89
+ `);
90
+ }
91
+ function formatSubmittedRun(input) {
92
+ const lines = [`${pc.green("Run submitted")}: ${pc.bold(input.runId)}`];
93
+ if (input.task) {
94
+ const id = stringField(input.task, "id", "<unknown>");
95
+ const status = stringField(input.task, "status", "unknown");
96
+ const title = stringField(input.task, "title", "Untitled task");
97
+ lines.push(`${pc.dim("task")} ${pc.bold(id)} ${statusColor(status)(status)} ${title}`);
98
+ }
99
+ return lines.join(`
100
+ `);
101
+ }
102
+ export {
103
+ formatTaskList,
104
+ formatSubmittedRun,
105
+ formatRunList
106
+ };
@@ -209,7 +209,8 @@ async function loadRigConfigOrNull(projectRoot) {
209
209
  import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
210
210
  import { homedir as homedir2 } from "os";
211
211
  import { resolve as resolve3 } from "path";
212
- var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
212
+ var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
213
+ var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
213
214
  async function defaultCommandRunner(command, options = {}) {
214
215
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
215
216
  const [stdout, stderr, exitCode] = await Promise.all([
@@ -228,7 +229,7 @@ function resolvePiHomeDir(inputHomeDir) {
228
229
  function piListContainsPiRig(output) {
229
230
  return output.split(/\r?\n/).some((line) => {
230
231
  const normalized = line.trim();
231
- return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
232
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
232
233
  });
233
234
  }
234
235
  async function safeRun(runner, command, options) {
@@ -3,7 +3,8 @@
3
3
  import { existsSync, readFileSync, rmSync } from "fs";
4
4
  import { homedir } from "os";
5
5
  import { resolve } from "path";
6
- var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
6
+ var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
7
+ var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
7
8
  var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
8
9
  export { default } from '@rig/pi-rig';
9
10
  `;
@@ -31,7 +32,7 @@ function resolvePiHomeDir(inputHomeDir) {
31
32
  function piListContainsPiRig(output) {
32
33
  return output.split(/\r?\n/).some((line) => {
33
34
  const normalized = line.trim();
34
- return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
35
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
35
36
  });
36
37
  }
37
38
  async function safeRun(runner, command, options) {
@@ -147,7 +148,7 @@ async function ensureRemotePiRigInstalled(input) {
147
148
  const payload = await input.requestJson("/api/pi-rig/install", {
148
149
  method: "POST",
149
150
  headers: { "content-type": "application/json" },
150
- body: JSON.stringify({ package: "@rig/pi-rig", scope: "global" })
151
+ body: JSON.stringify({ package: PI_RIG_PACKAGE_NAME, scope: "global" })
151
152
  });
152
153
  const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
153
154
  const piOk = record.piOk === true || record.ok === true;