@h-rig/cli 0.0.6-alpha.90 → 0.0.6-alpha.91

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.
Files changed (118) hide show
  1. package/README.md +18 -19
  2. package/dist/bin/build-rig-binaries.js +22 -10
  3. package/dist/bin/rig.d.ts +71 -1
  4. package/dist/bin/rig.js +15078 -11169
  5. package/dist/config/rig-default-config.yml +5 -0
  6. package/dist/src/app/drone-ui.d.ts +11 -14
  7. package/dist/src/app/drone-ui.js +70 -86
  8. package/dist/src/commands/_async-ui.d.ts +1 -4
  9. package/dist/src/commands/_async-ui.js +9 -111
  10. package/dist/src/commands/_cli-format.d.ts +16 -9
  11. package/dist/src/commands/_cli-format.js +167 -295
  12. package/dist/src/commands/_connection-state.d.ts +11 -1
  13. package/dist/src/commands/_connection-state.js +50 -5
  14. package/dist/src/commands/_doctor-checks.d.ts +0 -6
  15. package/dist/src/commands/_doctor-checks.js +79 -382
  16. package/dist/src/commands/_help-catalog.d.ts +1 -1
  17. package/dist/src/commands/_help-catalog.js +217 -157
  18. package/dist/src/commands/_inprocess-services.d.ts +33 -0
  19. package/dist/src/commands/_inprocess-services.js +102 -0
  20. package/dist/src/commands/_json-output.js +4 -0
  21. package/dist/src/commands/_lazy-reconcile.d.ts +34 -0
  22. package/dist/src/commands/_lazy-reconcile.js +102 -0
  23. package/dist/src/commands/_paths.js +1 -1
  24. package/dist/src/commands/_pi-frontend.d.ts +18 -10
  25. package/dist/src/commands/_pi-frontend.js +37 -715
  26. package/dist/src/commands/_pi-install.js +18 -36
  27. package/dist/src/commands/_policy.d.ts +1 -1
  28. package/dist/src/commands/_policy.js +56 -15
  29. package/dist/src/commands/_run-bridge.d.ts +114 -0
  30. package/dist/src/commands/_run-bridge.js +387 -0
  31. package/dist/src/commands/_run-diagnostics.d.ts +9 -0
  32. package/dist/src/commands/_run-diagnostics.js +51 -0
  33. package/dist/src/commands/_run-driver-helpers.d.ts +8 -81
  34. package/dist/src/commands/_run-driver-helpers.js +79 -283
  35. package/dist/src/commands/_run-projection.d.ts +50 -0
  36. package/dist/src/commands/_run-projection.js +349 -0
  37. package/dist/src/commands/_run-subcommands.d.ts +3 -0
  38. package/dist/src/commands/_run-subcommands.js +31 -0
  39. package/dist/src/commands/_spinner.js +1 -1
  40. package/dist/src/commands/agent.d.ts +1 -1
  41. package/dist/src/commands/agent.js +8559 -239
  42. package/dist/src/commands/dist.d.ts +1 -1
  43. package/dist/src/commands/dist.js +27 -19
  44. package/dist/src/commands/doctor.d.ts +1 -1
  45. package/dist/src/commands/doctor.js +93 -475
  46. package/dist/src/commands/github.d.ts +1 -1
  47. package/dist/src/commands/github.js +113 -387
  48. package/dist/src/commands/inbox.d.ts +22 -24
  49. package/dist/src/commands/inbox.js +420 -691
  50. package/dist/src/commands/init.d.ts +6 -16
  51. package/dist/src/commands/init.js +334 -971
  52. package/dist/src/commands/inspect.d.ts +19 -2
  53. package/dist/src/commands/inspect.js +644 -610
  54. package/dist/src/commands/pi.d.ts +1 -1
  55. package/dist/src/commands/plugin.d.ts +1 -1
  56. package/dist/src/commands/plugin.js +486 -7
  57. package/dist/src/commands/profile-and-review.d.ts +1 -1
  58. package/dist/src/commands/profile-and-review.js +94 -56
  59. package/dist/src/commands/queue.js +1 -21
  60. package/dist/src/commands/remote.d.ts +1 -1
  61. package/dist/src/commands/remote.js +837 -14
  62. package/dist/src/commands/repo-git-harness.d.ts +1 -1
  63. package/dist/src/commands/repo-git-harness.js +57 -14
  64. package/dist/src/commands/run.d.ts +20 -2
  65. package/dist/src/commands/run.js +17579 -1759
  66. package/dist/src/commands/server.d.ts +2 -6
  67. package/dist/src/commands/server.js +141 -723
  68. package/dist/src/commands/setup.d.ts +1 -1
  69. package/dist/src/commands/setup.js +102 -484
  70. package/dist/src/commands/stats.d.ts +13 -10
  71. package/dist/src/commands/stats.js +689 -761
  72. package/dist/src/commands/task-run-driver.d.ts +50 -88
  73. package/dist/src/commands/task-run-driver.js +116 -2717
  74. package/dist/src/commands/task.d.ts +34 -13
  75. package/dist/src/commands/task.js +668 -2523
  76. package/dist/src/commands/test.d.ts +1 -1
  77. package/dist/src/commands/triage.d.ts +11 -0
  78. package/dist/src/commands/triage.js +227 -0
  79. package/dist/src/commands/workspace.d.ts +1 -1
  80. package/dist/src/commands.d.ts +0 -16
  81. package/dist/src/commands.js +16657 -12250
  82. package/dist/src/index.js +16528 -12497
  83. package/dist/src/launcher.js +4 -0
  84. package/dist/src/operator-cli.d.ts +2 -0
  85. package/dist/src/operator-cli.js +17837 -0
  86. package/dist/src/operator-entry.d.ts +1 -0
  87. package/dist/src/operator-entry.js +3 -0
  88. package/package.json +18 -12
  89. package/dist/src/app/board.d.ts +0 -23
  90. package/dist/src/app/board.js +0 -1786
  91. package/dist/src/app/theme.d.ts +0 -47
  92. package/dist/src/app/theme.js +0 -150
  93. package/dist/src/commands/_authority-runs.d.ts +0 -22
  94. package/dist/src/commands/_authority-runs.js +0 -110
  95. package/dist/src/commands/_operator-surface.d.ts +0 -34
  96. package/dist/src/commands/_operator-surface.js +0 -220
  97. package/dist/src/commands/_operator-view.d.ts +0 -30
  98. package/dist/src/commands/_operator-view.js +0 -1070
  99. package/dist/src/commands/_preflight.d.ts +0 -22
  100. package/dist/src/commands/_preflight.js +0 -540
  101. package/dist/src/commands/_run-replay.d.ts +0 -24
  102. package/dist/src/commands/_run-replay.js +0 -142
  103. package/dist/src/commands/_server-client.d.ts +0 -186
  104. package/dist/src/commands/_server-client.js +0 -681
  105. package/dist/src/commands/_snapshot-upload.d.ts +0 -39
  106. package/dist/src/commands/_snapshot-upload.js +0 -455
  107. package/dist/src/commands/_task-picker.d.ts +0 -9
  108. package/dist/src/commands/_task-picker.js +0 -201
  109. package/dist/src/commands/browser.d.ts +0 -65
  110. package/dist/src/commands/browser.js +0 -1173
  111. package/dist/src/commands/connect.d.ts +0 -7
  112. package/dist/src/commands/connect.js +0 -419
  113. package/dist/src/commands/inspector.d.ts +0 -3
  114. package/dist/src/commands/inspector.js +0 -263
  115. package/dist/src/commands/task-report-bug.d.ts +0 -19
  116. package/dist/src/commands/task-report-bug.js +0 -1281
  117. package/dist/src/report-bug.d.ts +0 -44
  118. package/dist/src/report-bug.js +0 -260
@@ -1,129 +1,40 @@
1
1
  // @bun
2
- // packages/cli/src/app/drone-ui.ts
3
- import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
4
-
5
- // packages/cli/src/app/theme.ts
6
- var RIG_PALETTE = {
7
- ink: "#f2f3f6",
8
- ink2: "#aeb0ba",
9
- ink3: "#6c6e79",
10
- ink4: "#44464f",
11
- accent: "#ccff4d",
12
- accentDim: "#a9d63f",
13
- cyan: "#56d8ff",
14
- red: "#ff5d5d",
15
- yellow: "#ffd24d"
16
- };
17
- function hexToRgb(hex) {
18
- const value = hex.replace("#", "");
19
- return [
20
- Number.parseInt(value.slice(0, 2), 16),
21
- Number.parseInt(value.slice(2, 4), 16),
22
- Number.parseInt(value.slice(4, 6), 16)
23
- ];
24
- }
25
- function fg(hex) {
26
- const [r, g, b] = hexToRgb(hex);
27
- return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
28
- }
29
- var ink = fg(RIG_PALETTE.ink);
30
- var ink2 = fg(RIG_PALETTE.ink2);
31
- var ink3 = fg(RIG_PALETTE.ink3);
32
- var ink4 = fg(RIG_PALETTE.ink4);
33
- var accent = fg(RIG_PALETTE.accent);
34
- var accentDim = fg(RIG_PALETTE.accentDim);
35
- var cyan = fg(RIG_PALETTE.cyan);
36
- var red = fg(RIG_PALETTE.red);
37
- var yellow = fg(RIG_PALETTE.yellow);
38
- function bold(text) {
39
- return `\x1B[1m${text}\x1B[22m`;
40
- }
41
- var DRONE_ART = [
42
- " .-=-. .-=-. ",
43
- " ( !!! ) ( !!! ) ",
44
- " '-=-'._ _.'-=-' ",
45
- " '._ _.' ",
46
- " '=$$$$$$$=.' ",
47
- " =$$$$$$$$$$$= ",
48
- " $$$@@@@@@@@@@$$$ ",
49
- " $$$@@ @@$$$ ",
50
- " $$@ ? @$$$ ",
51
- " $$$@ '-' @$$$ ",
52
- " $$$@@ @@$$$ ",
53
- " $$$@@@@@@@@@@$$$ ",
54
- " =$$$$$$$$$$$= ",
55
- " '=$$$$$$$=.' ",
56
- " _.' '._ ",
57
- " .-=-.' '.-=-. ",
58
- " ( !!! ) ( !!! ) ",
59
- " '-=-' '-=-' "
60
- ];
61
- var EYE_FRAMES = ["@", "o", "."];
62
- var DRONE_WIDTH = DRONE_ART[0].length;
63
- var DRONE_HEIGHT = DRONE_ART.length;
64
- var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
65
- function microDroneFrame(tick) {
66
- const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
67
- const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
68
- return `(${blade})${eye}(${blade})`;
69
- }
70
- var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
71
-
72
- // packages/cli/src/app/drone-ui.ts
73
- function droneNote(message, title) {
74
- if (title)
75
- console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
76
- for (const line of message.split(`
77
- `)) {
78
- console.log(` ${ink4("\u2502")} ${line}`);
79
- }
80
- }
81
-
82
2
  // packages/cli/src/commands/_cli-format.ts
83
3
  import pc from "picocolors";
84
- var themeDim = (value) => ink3(value);
85
- var themeFaint = (value) => ink4(value);
86
- function stringField(record, key, fallback = "") {
87
- const value = record[key];
88
- return typeof value === "string" && value.trim() ? value.trim() : fallback;
89
- }
4
+ var dim = pc.dim;
5
+ var faintBar = pc.dim("\u2502");
6
+ var accent = pc.cyan;
90
7
  function numberField(record, key) {
91
8
  const value = record[key];
92
9
  return typeof value === "number" && Number.isFinite(value) ? value : null;
93
10
  }
94
11
  function arrayField(record, key) {
95
12
  const value = record[key];
96
- return Array.isArray(value) ? value.flatMap((entry) => typeof entry === "string" && entry.trim() ? [entry.trim()] : []) : [];
13
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
97
14
  }
98
15
  function rawObject(record) {
99
- const raw = record.raw;
100
- return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
16
+ const value = record.raw;
17
+ return value && typeof value === "object" && !Array.isArray(value) ? value : record;
101
18
  }
102
19
  function truncate(value, width) {
103
- if (value.length <= width)
104
- return value;
105
- if (width <= 1)
106
- return "\u2026";
107
- return `${value.slice(0, width - 1)}\u2026`;
20
+ return value.length <= width ? value : `${value.slice(0, Math.max(0, width - 1))}\u2026`;
108
21
  }
109
22
  function pad(value, width) {
110
23
  return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
111
24
  }
112
25
  function statusColor(status) {
113
- const normalized = status.toLowerCase();
114
- if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved", "running"].includes(normalized))
115
- return accent;
116
- if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
117
- return red;
118
- if (["reviewing", "validating", "in_progress", "in-progress", "remote", "preparing", "closing-out"].includes(normalized))
119
- return cyan;
120
- if (["ready", "open", "queued", "created", "local", "pending"].includes(normalized))
121
- return yellow;
122
- return themeDim;
26
+ const normalized = status.trim().toLowerCase();
27
+ if (["done", "completed", "ready", "healthy", "open", "approved"].includes(normalized))
28
+ return pc.green;
29
+ if (["failed", "error", "blocked", "rejected", "stopped"].includes(normalized))
30
+ return pc.red;
31
+ if (["running", "in_progress", "in-progress", "active", "booting"].includes(normalized))
32
+ return pc.cyan;
33
+ if (["pending", "queued", "created", "local"].includes(normalized))
34
+ return pc.yellow;
35
+ return pc.dim;
123
36
  }
124
37
  function compactDate(value) {
125
- if (!value.trim())
126
- return "";
127
38
  const parsed = Date.parse(value);
128
39
  if (!Number.isFinite(parsed))
129
40
  return value;
@@ -131,19 +42,17 @@ function compactDate(value) {
131
42
  }
132
43
  function compactValue(value) {
133
44
  if (value === null || value === undefined)
134
- return "";
45
+ return "\u2014";
135
46
  if (typeof value === "string")
136
47
  return value;
137
48
  if (typeof value === "number" || typeof value === "boolean")
138
49
  return String(value);
139
- if (Array.isArray(value))
140
- return value.map(compactValue).filter(Boolean).join(", ");
141
50
  return JSON.stringify(value);
142
51
  }
143
52
  function firstString(record, keys, fallback = "") {
144
53
  for (const key of keys) {
145
- const value = stringField(record, key);
146
- if (value)
54
+ const value = record[key];
55
+ if (typeof value === "string" && value.trim())
147
56
  return value;
148
57
  }
149
58
  return fallback;
@@ -160,25 +69,18 @@ function runTitleOf(run) {
160
69
  function requestIdOf(entry) {
161
70
  return firstString(entry, ["requestId", "id", "approvalId", "inputId"], "(unknown-request)");
162
71
  }
163
- function shouldUseClackOutput() {
164
- return Boolean(process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
165
- }
166
- function printFormattedOutput(message, options = {}) {
167
- if (!shouldUseClackOutput()) {
168
- console.log(message);
169
- return;
170
- }
171
- droneNote(message, options.title);
72
+ function printFormattedOutput(message) {
73
+ console.log(message);
172
74
  }
173
75
  function formatStatusPill(status) {
174
76
  const label = status || "unknown";
175
77
  return statusColor(label)(`\u25CF ${label}`);
176
78
  }
177
79
  function formatSection(title, subtitle) {
178
- return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? themeDim(` \u2014 ${subtitle}`) : ""}`;
80
+ return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? dim(` \u2014 ${subtitle}`) : ""}`;
179
81
  }
180
82
  function formatSuccessCard(title, rows = []) {
181
- const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${themeFaint("\u2502")} ${themeDim(key.padEnd(12))} ${value}`);
83
+ const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${faintBar} ${dim(key.padEnd(12))} ${value}`);
182
84
  return [formatSection(title), ...body].join(`
183
85
  `);
184
86
  }
@@ -187,66 +89,59 @@ function formatNextSteps(steps) {
187
89
  return [];
188
90
  return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
189
91
  }
92
+ function formatLegacyAutomationSurface() {
93
+ return [];
94
+ }
190
95
  function formatTaskList(tasks, options = {}) {
191
- if (options.raw)
192
- return tasks.map((task) => JSON.stringify(task)).join(`
96
+ if (tasks.length === 0) {
97
+ return [formatSection("Tasks", "empty"), dim("No tasks available."), "", ...formatNextSteps(["Refresh: `rig task list`", "Pick next: `rig task next`"])].join(`
193
98
  `);
194
- if (tasks.length === 0)
195
- return [formatSection("Tasks", "none found"), ...formatNextSteps(["Try `rig server status` to confirm the selected server.", "Relax filters or run `rig task run --title ... --initial-prompt ...` for ad hoc work."])].join(`
196
- `);
197
- const rows = tasks.map((task) => {
198
- const raw = rawObject(task);
199
- const id = stringField(task, "id", "<unknown>");
200
- const status = stringField(task, "status", "unknown");
201
- const title = stringField(task, "title", "Untitled task");
202
- const source = stringField(task, "source", stringField(raw, "source", ""));
203
- const labels = arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels");
204
- return { id, status, title, source, labels };
205
- });
206
- const idWidth = Math.min(18, Math.max(4, ...rows.map((row) => row.id.length)));
207
- const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
208
- const header = `${pc.bold(pad("TASK", idWidth))} ${pc.bold(pad("STATUS", statusWidth))} ${pc.bold("TITLE")}`;
99
+ }
100
+ if (options.raw) {
101
+ return JSON.stringify(tasks, null, 2);
102
+ }
103
+ const rows = tasks.map((task) => summarizeTaskRow(task));
104
+ const idWidth = Math.max(2, ...rows.map((row) => row.id.length));
105
+ const statusWidth = Math.max(6, ...rows.map((row) => row.status.length));
209
106
  const body = rows.map((row) => {
210
- const labels = row.labels.length > 0 ? themeDim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
211
- const source = row.source ? themeDim(` ${row.source}`) : "";
107
+ const labels = row.labels.length > 0 ? dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
108
+ const source = row.source ? dim(` ${row.source}`) : "";
212
109
  return [
213
110
  pc.bold(pad(truncate(row.id, idWidth), idWidth)),
214
111
  statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
215
112
  `${row.title}${labels}${source}`
216
113
  ].join(" ");
217
114
  });
218
- return [formatSection("Tasks", `${rows.length} shown`), header, ...body, "", ...formatNextSteps(["Run one: `rig task run <id>` or `rig task run --next`", "Attach later: `rig run attach <run-id> --follow`"])].join(`
115
+ return [formatSection("Tasks", `${tasks.length}`), ...body].join(`
219
116
  `);
220
117
  }
118
+ function summarizeTaskRow(task) {
119
+ const raw = rawObject(task);
120
+ return {
121
+ id: firstString(task, ["id", "taskId"], "(unknown-task)"),
122
+ title: firstString(task, ["title", "summary", "name"], "(untitled)"),
123
+ status: firstString(task, ["status"], "unknown"),
124
+ labels: arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels"),
125
+ source: firstString(task, ["source"], "")
126
+ };
127
+ }
221
128
  function formatTaskCard(task, options = {}) {
222
129
  const raw = rawObject(task);
223
- const id = stringField(task, "id", stringField(raw, "id", "<unknown>"));
224
- const status = stringField(task, "status", stringField(raw, "status", "unknown"));
225
- const title = stringField(task, "title", stringField(raw, "title", "Untitled task"));
226
- const source = stringField(task, "source", stringField(raw, "source", ""));
227
- const url = stringField(task, "url", stringField(raw, "url", ""));
228
- const number = numberField(task, "number") ?? numberField(raw, "number");
229
- const labels = arrayField(task, "labels").length > 0 ? arrayField(task, "labels") : arrayField(raw, "labels");
230
- const assignees = arrayField(task, "assignees").length > 0 ? arrayField(task, "assignees") : arrayField(raw, "assignees");
231
- const readiness = compactValue(task.readiness ?? raw.readiness);
232
- const validators = compactValue(task.validators ?? raw.validators ?? task.validation ?? raw.validation);
233
- const rows = [
234
- ["task", pc.bold(id)],
235
- ["status", formatStatusPill(status)],
236
- ["title", title],
237
- ["source", source],
238
- ["number", number],
239
- ["labels", labels.length ? labels.map((label) => `#${label}`).join(" ") : ""],
240
- ["assignees", assignees.join(", ")],
241
- ["readiness", readiness],
242
- ["validators", validators],
243
- ["url", url]
244
- ];
245
- return [
246
- formatSuccessCard(options.title ?? (options.selected ? "Selected task" : "Task"), rows),
247
- "",
248
- ...formatNextSteps([`Start: \`rig task run ${id}\``, `Details: \`rig task show ${id} --raw\``])
249
- ].join(`
130
+ const lines = [formatSection(options.title ?? (options.selected ? "Selected task" : "Task"))];
131
+ for (const [label, value] of [
132
+ ["id", firstString(task, ["id", "taskId"], "(unknown-task)")],
133
+ ["title", firstString(task, ["title", "summary", "name"], "(untitled)")],
134
+ ["status", firstString(task, ["status"], "unknown")],
135
+ ["source", firstString(task, ["source"], "")],
136
+ ["url", firstString(raw, ["url"], "")]
137
+ ]) {
138
+ if (value)
139
+ lines.push(`${faintBar} ${dim(label.padEnd(12))} ${value}`);
140
+ }
141
+ const labels = arrayField(task, "labels");
142
+ if (labels.length > 0)
143
+ lines.push(`${faintBar} ${dim("labels".padEnd(12))} ${labels.map((label) => `#${label}`).join(" ")}`);
144
+ return lines.join(`
250
145
  `);
251
146
  }
252
147
  function formatTaskDetails(task) {
@@ -256,179 +151,155 @@ function formatRunList(runs, options = {}) {
256
151
  if (runs.length === 0) {
257
152
  return [
258
153
  formatSection("Runs", "none recorded"),
259
- options.source === "server" ? themeDim("No runs recorded on the selected Rig server.") : themeDim("No runs recorded in .rig/runs."),
154
+ options.source === "server" ? dim("No runs recorded on the selected server.") : dim("No runs recorded in local state."),
260
155
  "",
261
- ...formatNextSteps(["Start one: `rig task run --next`", "Check server: `rig server status`"])
156
+ ...formatLegacyAutomationSurface()
262
157
  ].join(`
263
158
  `);
264
159
  }
265
- const rows = runs.map((run) => {
266
- const runId = stringField(run, "runId", stringField(run, "id", "(unknown-run)"));
267
- const status = stringField(run, "status", "unknown");
268
- const taskId = stringField(run, "taskId", "");
269
- const title = stringField(run, "title", taskId || "(untitled)");
270
- const runtime = stringField(run, "runtimeAdapter", "");
271
- return { runId, status, title, runtime };
160
+ const body = runs.map((run) => {
161
+ const row = run;
162
+ const runId = runIdOf(row);
163
+ const status = firstString(row, ["status"], "unknown");
164
+ const runtime = firstString(row, ["runtime", "runtimeAdapter"], "");
165
+ return [
166
+ pc.bold(runId),
167
+ statusColor(status)(pad(truncate(status, 12), 12)),
168
+ `${runTitleOf(row)}${runtime ? dim(` ${runtime}`) : ""}`
169
+ ].join(" ");
272
170
  });
273
- const idWidth = Math.min(36, Math.max(6, ...rows.map((row) => row.runId.length)));
274
- const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
275
- const header = `${pc.bold(pad("RUN", idWidth))} ${pc.bold(pad("STATUS", statusWidth))} ${pc.bold("TITLE")}`;
276
- const body = rows.map((row) => [
277
- pc.bold(pad(truncate(row.runId, idWidth), idWidth)),
278
- statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
279
- `${row.title}${row.runtime ? themeDim(` ${row.runtime}`) : ""}`
280
- ].join(" "));
281
- return [formatSection("Runs", options.source === "server" ? "selected server" : "local state"), header, ...body, "", ...formatNextSteps(["Follow live: `rig run attach <run-id> --follow`", "Details: `rig run show <run-id>`"])].join(`
171
+ return [formatSection("Runs", options.source === "server" ? "selected server" : "local state"), ...body, "", ...formatLegacyAutomationSurface()].join(`
282
172
  `);
283
173
  }
284
174
  function formatSubmittedRun(input) {
285
- const rows = [["run", pc.bold(input.runId)]];
286
- if (input.task) {
287
- const id = stringField(input.task, "id", "<unknown>");
288
- const status = stringField(input.task, "status", "unknown");
289
- const title = stringField(input.task, "title", "Untitled task");
290
- rows.push(["task", `${pc.bold(id)} ${formatStatusPill(status)} ${title}`]);
291
- }
292
- const runtime = [input.runtimeAdapter || "pi", input.runtimeMode || "full-access", input.interactionMode || "default"].filter(Boolean).join(" \xB7 ");
293
- rows.push(["runtime", runtime]);
294
- return [
295
- formatSuccessCard("Run submitted", rows),
296
- "",
297
- ...formatNextSteps([
298
- `Attach: \`rig run attach ${input.runId} --follow\``,
299
- `Inspect: \`rig run show ${input.runId}\``,
300
- input.detached ? "Submitted detached; attach when you are ready." : "Interactive mode opens the enriched bundled Pi (native UI + Rig layers, worker brain)."
301
- ])
302
- ].join(`
303
- `);
175
+ return formatSuccessCard("Run submitted", [
176
+ ["run", input.runId],
177
+ ["task", input.taskId ?? undefined],
178
+ ["title", input.title ?? undefined],
179
+ ["queue", input.queuePosition ?? undefined]
180
+ ]);
304
181
  }
305
182
  function formatRunCard(run, options = {}) {
306
- const raw = rawObject(run);
307
- const merged = { ...raw, ...run };
308
- const runId = runIdOf(merged);
309
- const status = firstString(merged, ["status"], "unknown");
310
- const taskId = taskIdOf(merged);
311
- const title = runTitleOf(merged);
312
- const runtime = firstString(merged, ["runtimeAdapter", "runtime", "adapter"]);
313
- const mode = firstString(merged, ["runtimeMode", "mode"]);
314
- const interaction = firstString(merged, ["interactionMode"]);
315
- const created = compactDate(firstString(merged, ["createdAt"]));
316
- const started = compactDate(firstString(merged, ["startedAt"]));
317
- const updated = compactDate(firstString(merged, ["updatedAt"]));
318
- const completed = compactDate(firstString(merged, ["completedAt", "finishedAt"]));
319
- const worktree = firstString(merged, ["worktreePath", "cwd", "projectRoot"]);
320
- const piSession = merged.piSession && typeof merged.piSession === "object" && !Array.isArray(merged.piSession) ? firstString(merged.piSession, ["sessionId", "id"]) : "";
321
- const timeline = Array.isArray(merged.timeline) ? merged.timeline.length : null;
322
- const approvals = Array.isArray(merged.approvals) ? merged.approvals.length : null;
323
- const inputs = Array.isArray(merged.userInputs) ? merged.userInputs.length : null;
324
- const rows = [
325
- ["run", pc.bold(runId)],
326
- ["status", formatStatusPill(status)],
327
- ["task", taskId],
328
- ["title", title],
329
- ["runtime", [runtime, mode, interaction].filter(Boolean).join(" \xB7 ")],
330
- ["created", created],
331
- ["started", started],
332
- ["updated", updated],
333
- ["completed", completed],
334
- ["worktree", worktree],
335
- ["pi", piSession],
336
- ["timeline", timeline],
337
- ["approvals", approvals],
338
- ["inputs", inputs]
339
- ];
340
- return [
341
- formatSuccessCard(options.title ?? "Run details", rows),
342
- "",
343
- ...formatNextSteps([`Follow live: \`rig run attach ${runId} --follow\``, `Raw payload: \`rig run show ${runId} --raw\``])
344
- ].join(`
183
+ const record = run;
184
+ const lines = [formatSection(options.title ?? "Run")];
185
+ for (const [label, value] of [
186
+ ["run", runIdOf(record)],
187
+ ["task", taskIdOf(record)],
188
+ ["title", runTitleOf(record)],
189
+ ["status", firstString(record, ["status"], "unknown")],
190
+ ["runtime", firstString(record, ["runtime", "runtimeAdapter"], "")],
191
+ ["created", firstString(record, ["createdAt"], "")],
192
+ ["updated", firstString(record, ["updatedAt"], "")]
193
+ ]) {
194
+ if (value)
195
+ lines.push(`${faintBar} ${dim(label.padEnd(12))} ${label === "created" || label === "updated" ? compactDate(value) : value}`);
196
+ }
197
+ const errorSummary = firstString(record, ["errorSummary"]);
198
+ if (errorSummary)
199
+ lines.push(`${faintBar} Error: ${errorSummary}`);
200
+ return lines.join(`
345
201
  `);
346
202
  }
347
203
  function formatRunStatus(summary, options = {}) {
348
204
  const activeRuns = summary.activeRuns ?? [];
349
205
  const recentRuns = summary.recentRuns ?? [];
350
206
  const lines = [formatSection("Run status", options.source === "server" ? "selected server" : "local state")];
351
- lines.push("", pc.bold(`Active runs (${activeRuns.length})`));
352
- if (activeRuns.length === 0) {
353
- lines.push(themeDim("No active runs."));
354
- } else {
355
- for (const run of activeRuns) {
207
+ lines.push(`Active runs (${activeRuns.length})`);
208
+ if (activeRuns.length === 0)
209
+ lines.push(dim("No active runs."));
210
+ else
211
+ for (const run of activeRuns)
356
212
  lines.push(formatRunSummaryLine(run));
357
- }
358
- }
359
- lines.push("", pc.bold(`Recent runs (${recentRuns.length})`));
360
- if (recentRuns.length === 0) {
361
- lines.push(themeDim("No recent terminal runs."));
362
- } else {
363
- for (const run of recentRuns.slice(0, 10)) {
213
+ lines.push("", `Recent runs (${recentRuns.length})`);
214
+ if (recentRuns.length === 0)
215
+ lines.push(dim("No recent terminal runs."));
216
+ else
217
+ for (const run of recentRuns.slice(0, 10))
364
218
  lines.push(formatRunSummaryLine(run));
365
- }
366
- }
367
- lines.push("", ...formatNextSteps(["Start work: `rig task run --next`", "Attach: `rig run attach <run-id> --follow`", "Details: `rig run show <run-id>`"]));
219
+ lines.push("", ...formatLegacyAutomationSurface());
368
220
  return lines.join(`
369
221
  `);
370
222
  }
371
223
  function formatRunSummaryLine(run) {
372
224
  const record = run;
373
225
  const runId = runIdOf(record);
374
- const status = firstString(record, ["status"], "unknown");
375
226
  const taskId = taskIdOf(record);
376
227
  const title = runTitleOf(record);
377
- const runtime = firstString(record, ["runtimeAdapter", "runtime", "adapter"]);
228
+ const status = firstString(record, ["status"], "unknown");
229
+ const runtime = firstString(record, ["runtime", "runtimeAdapter"], "");
378
230
  const descriptor = [taskId, title].filter(Boolean).join(" \xB7 ");
379
- return `${themeFaint("\u2502")} ${pc.bold(runId)} ${formatStatusPill(status)} ${descriptor}${runtime ? themeDim(` ${runtime}`) : ""}`;
231
+ return `${faintBar} ${pc.bold(runId)} ${formatStatusPill(status)} ${descriptor}${runtime ? dim(` ${runtime}`) : ""}`;
380
232
  }
381
233
  function formatInboxList(kind, entries) {
382
- const title = kind === "approvals" ? "Approval inbox" : "Input inbox";
234
+ const title = kind === "approvals" ? "Pending approvals" : "Pending user input";
383
235
  if (entries.length === 0) {
384
236
  return [
385
237
  formatSection(title, "empty"),
386
- themeDim(kind === "approvals" ? "No pending approvals." : "No pending user-input requests."),
238
+ dim(kind === "approvals" ? "No pending approvals." : "No pending user-input requests."),
387
239
  "",
388
- ...formatNextSteps(["Check runs: `rig run status`", "Start work: `rig task run --next`"])
240
+ ...formatLegacyAutomationSurface()
389
241
  ].join(`
390
242
  `);
391
243
  }
392
- const lines = [formatSection(title, `${entries.length} pending`)];
393
- for (const entry of entries) {
394
- const record = entry.record && typeof entry.record === "object" && !Array.isArray(entry.record) ? entry.record : entry;
395
- const runId = firstString(entry, ["runId"], firstString(record, ["runId"]));
396
- const taskId = firstString(entry, ["taskId"], firstString(record, ["taskId", "task"]));
397
- const requestId = requestIdOf(record);
398
- const status = firstString(record, ["status", "state"], "pending");
244
+ const lines = [formatSection(title, `${entries.length}`)];
245
+ for (const record of entries) {
246
+ const runId = firstString(record, ["runId"], "(unknown-run)");
247
+ const taskId = firstString(record, ["taskId"], "");
248
+ const status = firstString(record, ["status"], "pending");
399
249
  const prompt = firstString(record, ["prompt", "message", "reason", "title", "summary"], kind === "approvals" ? "Approval requested" : "Input requested");
400
- lines.push(`${themeFaint("\u2502")} ${pc.bold(requestId)} ${formatStatusPill(status)} ${prompt}`);
401
- lines.push(`${themeFaint("\u2502")} ${themeDim("run ")} ${runId || "(unknown-run)"}${taskId ? themeDim(` task ${taskId}`) : ""}`);
250
+ lines.push(`${faintBar} ${pc.bold(requestIdOf(record))} ${formatStatusPill(status)} ${prompt}`);
251
+ lines.push(`${faintBar} ${dim("run".padEnd(12))} ${runId}${taskId ? dim(` task ${taskId}`) : ""}`);
402
252
  }
403
- lines.push("", ...formatNextSteps(kind === "approvals" ? ["Resolve: `rig inbox approve --run <run-id> --request <request-id> --decision approve|reject`", "Rejoin: `rig run attach <run-id> --follow`"] : ["Respond: `rig inbox respond --run <run-id> --request <request-id> --answer key=value`", "Rejoin: `rig run attach <run-id> --follow`"]));
253
+ lines.push("", ...formatLegacyAutomationSurface(), ...formatNextSteps(kind === "approvals" ? ["Resolve: `rig inbox approve --run <run-id> --request <request-id> --decision approve|reject`"] : ["Reply: `rig inbox answer --run <run-id> --request <request-id> --text ...`"]));
404
254
  return lines.join(`
405
255
  `);
406
256
  }
407
257
  function formatConnectionList(connections) {
408
- const rows = [["local", { kind: "local", mode: "auto" }], ...Object.entries(connections)];
409
- const aliasWidth = Math.min(24, Math.max(5, ...rows.map(([alias]) => alias.length)));
410
- const lines = rows.map(([alias, connection]) => [
411
- pc.bold(pad(truncate(alias, aliasWidth), aliasWidth)),
412
- formatStatusPill(connection.kind),
413
- connection.kind === "remote" ? connection.baseUrl ?? "" : connection.mode ?? "local"
414
- ].join(" "));
415
- return [formatSection("Rig servers", `${rows.length} available`), `${pc.bold(pad("ALIAS", aliasWidth))} ${pc.bold("KIND")} ${pc.bold("TARGET")}`, ...lines, "", ...formatNextSteps(["Select one: `rig server use <alias|local>`"])].join(`
258
+ const names = Object.keys(connections).sort();
259
+ if (names.length === 0) {
260
+ return [formatSection("Rig servers", "empty"), dim("No saved server connections.")].join(`
261
+ `);
262
+ }
263
+ return [formatSection("Rig servers", `${names.length}`), ...names.map((name) => {
264
+ const connection = connections[name];
265
+ const target = connection.kind === "remote" ? connection.baseUrl ?? "(missing url)" : connection.mode ?? "local";
266
+ return `${faintBar} ${pc.bold(name)} ${dim(connection.kind)} ${target}`;
267
+ })].join(`
416
268
  `);
417
269
  }
418
- function formatConnectionStatus(selected, connections) {
419
- const connection = selected === "local" ? { kind: "local", mode: "auto" } : connections[selected];
420
- const target = !connection ? "not configured" : connection.kind === "remote" ? connection.baseUrl : "local";
421
- return [
422
- formatSection("Rig server", "selected for this repo"),
423
- `${themeFaint("\u2502")} ${themeDim("selected ")} ${pc.bold(selected)}`,
424
- `${themeFaint("\u2502")} ${themeDim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
425
- `${themeFaint("\u2502")} ${themeDim("target ")} ${target ?? "not configured"}`,
426
- "",
427
- ...formatNextSteps(["Change: `rig server use <alias|local>`", "List saved servers: `rig server list`"])
428
- ].join(`
270
+ function formatConnectionStatus(selected, connections, repo, remoteProjectLink) {
271
+ const selectedConnection = connections[selected];
272
+ const lines = [formatSection("Rig server", "selected for this repo")];
273
+ lines.push(`${faintBar} ${dim("selected".padEnd(12))} ${pc.bold(selected)}`);
274
+ if (selectedConnection) {
275
+ lines.push(`${faintBar} ${dim("kind".padEnd(12))} ${selectedConnection.kind}`);
276
+ if (selectedConnection.baseUrl)
277
+ lines.push(`${faintBar} ${dim("base url".padEnd(12))} ${selectedConnection.baseUrl}`);
278
+ if (selectedConnection.mode)
279
+ lines.push(`${faintBar} ${dim("mode".padEnd(12))} ${selectedConnection.mode}`);
280
+ }
281
+ if (repo?.project)
282
+ lines.push(`${faintBar} ${dim("project".padEnd(12))} ${repo.project}`);
283
+ if (repo?.serverProjectRoot)
284
+ lines.push(`${faintBar} ${dim("server root".padEnd(12))} ${repo.serverProjectRoot}`);
285
+ if (remoteProjectLink?.status)
286
+ lines.push(`${faintBar} ${dim("link".padEnd(12))} ${remoteProjectLink.status}`);
287
+ if (remoteProjectLink?.message)
288
+ lines.push(`${faintBar} ${dim("message".padEnd(12))} ${remoteProjectLink.message}`);
289
+ if (remoteProjectLink?.hint)
290
+ lines.push(`${faintBar} ${dim("hint".padEnd(12))} ${remoteProjectLink.hint}`);
291
+ return lines.join(`
292
+ `);
293
+ }
294
+ function formatStatsTable(rows) {
295
+ return rows.map(([label, value]) => `${faintBar} ${dim(label.padEnd(20))} ${compactValue(value)}`).join(`
429
296
  `);
430
297
  }
298
+ function readOptionalCount(record, key) {
299
+ return numberField(record, key);
300
+ }
431
301
  export {
302
+ readOptionalCount,
432
303
  printFormattedOutput,
433
304
  formatTaskList,
434
305
  formatTaskDetails,
@@ -436,6 +307,7 @@ export {
436
307
  formatSuccessCard,
437
308
  formatSubmittedRun,
438
309
  formatStatusPill,
310
+ formatStatsTable,
439
311
  formatSection,
440
312
  formatRunStatus,
441
313
  formatRunList,
@@ -17,6 +17,10 @@ export type RepoConnectionState = {
17
17
  * Sent as the x-rig-project-root header on every remote request.
18
18
  */
19
19
  serverProjectRoot?: string;
20
+ /** The selected alias that produced serverProjectRoot. Prevents cross-alias reuse. */
21
+ serverProjectRootAlias?: string;
22
+ /** The remote base URL that produced serverProjectRoot. Prevents same-alias retarget leaks. */
23
+ serverProjectRootBaseUrl?: string;
20
24
  };
21
25
  export declare function resolveGlobalConnectionsPath(env?: NodeJS.ProcessEnv): string;
22
26
  export declare function resolveRepoConnectionPath(projectRoot: string): string;
@@ -39,6 +43,12 @@ export declare function resolveSelectedConnection(projectRoot: string, options?:
39
43
  serverProjectRoot?: string;
40
44
  } | null;
41
45
  /** Persist the server-host project root this repo scopes to (multi-root serving). */
42
- export declare function writeRepoServerProjectRoot(projectRoot: string, serverProjectRoot: string): void;
46
+ export declare function writeRepoServerProjectRoot(projectRoot: string, serverProjectRoot: string, metadata?: {
47
+ alias?: string;
48
+ baseUrl?: string;
49
+ project?: string;
50
+ }): void;
51
+ /** Remove a stale server-host root while preserving selected server/repo state. */
52
+ export declare function clearRepoServerProjectRoot(projectRoot: string): void;
43
53
  /** Whether this repo's selected connection targets a remote Rig server. */
44
54
  export declare function isRemoteConnectionSelected(projectRoot: string): boolean;