@h-rig/cli 0.0.6-alpha.76 → 0.0.6-alpha.78
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 +10130 -9246
- package/dist/src/app/board.js +1783 -0
- package/dist/src/app/drone-ui.js +294 -0
- package/dist/src/{commands/_tui-theme.js → app/theme.js} +16 -1
- package/dist/src/commands/_async-ui.js +74 -3
- package/dist/src/commands/_cli-format.js +107 -29
- package/dist/src/commands/_doctor-checks.js +3 -1
- package/dist/src/commands/_help-catalog.js +8 -70
- package/dist/src/commands/_operator-view.js +184 -7
- package/dist/src/commands/_pi-frontend.js +184 -7
- package/dist/src/commands/_preflight.js +3 -1
- package/dist/src/commands/_server-client.js +3 -1
- package/dist/src/commands/_snapshot-upload.js +3 -1
- package/dist/src/commands/_task-picker.js +132 -7
- package/dist/src/commands/browser.js +306 -30
- package/dist/src/commands/connect.js +146 -20
- package/dist/src/commands/doctor.js +77 -4
- package/dist/src/commands/github.js +77 -4
- package/dist/src/commands/inbox.js +171 -88
- package/dist/src/commands/init.js +349 -9
- package/dist/src/commands/inspect.js +77 -4
- package/dist/src/commands/run.js +214 -28
- package/dist/src/commands/server.js +149 -21
- package/dist/src/commands/setup.js +77 -4
- package/dist/src/commands/stats.js +109 -107
- package/dist/src/commands/task-report-bug.js +231 -40
- package/dist/src/commands/task-run-driver.js +3 -1
- package/dist/src/commands/task.js +355 -184
- package/dist/src/commands.js +10126 -9242
- package/dist/src/index.js +10131 -9247
- package/package.json +8 -9
- package/dist/src/commands/_operator-board.js +0 -730
|
@@ -1,9 +1,221 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/commands/task.ts
|
|
3
|
-
import { readFileSync as
|
|
3
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
4
4
|
import { spawnSync } from "child_process";
|
|
5
5
|
import { resolve as resolve3 } from "path";
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
// packages/cli/src/app/drone-ui.ts
|
|
8
|
+
import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
|
|
9
|
+
|
|
10
|
+
// packages/cli/src/app/theme.ts
|
|
11
|
+
var RIG_PALETTE = {
|
|
12
|
+
ink: "#f2f3f6",
|
|
13
|
+
ink2: "#aeb0ba",
|
|
14
|
+
ink3: "#6c6e79",
|
|
15
|
+
ink4: "#44464f",
|
|
16
|
+
accent: "#ccff4d",
|
|
17
|
+
accentDim: "#a9d63f",
|
|
18
|
+
cyan: "#56d8ff",
|
|
19
|
+
red: "#ff5d5d",
|
|
20
|
+
yellow: "#ffd24d"
|
|
21
|
+
};
|
|
22
|
+
function hexToRgb(hex) {
|
|
23
|
+
const value = hex.replace("#", "");
|
|
24
|
+
return [
|
|
25
|
+
Number.parseInt(value.slice(0, 2), 16),
|
|
26
|
+
Number.parseInt(value.slice(2, 4), 16),
|
|
27
|
+
Number.parseInt(value.slice(4, 6), 16)
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
function fg(hex) {
|
|
31
|
+
const [r, g, b] = hexToRgb(hex);
|
|
32
|
+
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
33
|
+
}
|
|
34
|
+
var ink = fg(RIG_PALETTE.ink);
|
|
35
|
+
var ink2 = fg(RIG_PALETTE.ink2);
|
|
36
|
+
var ink3 = fg(RIG_PALETTE.ink3);
|
|
37
|
+
var ink4 = fg(RIG_PALETTE.ink4);
|
|
38
|
+
var accent = fg(RIG_PALETTE.accent);
|
|
39
|
+
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
40
|
+
var cyan = fg(RIG_PALETTE.cyan);
|
|
41
|
+
var red = fg(RIG_PALETTE.red);
|
|
42
|
+
var yellow = fg(RIG_PALETTE.yellow);
|
|
43
|
+
function bold(text) {
|
|
44
|
+
return `\x1B[1m${text}\x1B[22m`;
|
|
45
|
+
}
|
|
46
|
+
var DRONE_ART = [
|
|
47
|
+
" .-=-. .-=-. ",
|
|
48
|
+
" ( !!! ) ( !!! ) ",
|
|
49
|
+
" '-=-'._ _.'-=-' ",
|
|
50
|
+
" '._ _.' ",
|
|
51
|
+
" '=$$$$$$$=.' ",
|
|
52
|
+
" =$$$$$$$$$$$= ",
|
|
53
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
54
|
+
" $$$@@ @@$$$ ",
|
|
55
|
+
" $$@ ? @$$$ ",
|
|
56
|
+
" $$$@ '-' @$$$ ",
|
|
57
|
+
" $$$@@ @@$$$ ",
|
|
58
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
59
|
+
" =$$$$$$$$$$$= ",
|
|
60
|
+
" '=$$$$$$$=.' ",
|
|
61
|
+
" _.' '._ ",
|
|
62
|
+
" .-=-.' '.-=-. ",
|
|
63
|
+
" ( !!! ) ( !!! ) ",
|
|
64
|
+
" '-=-' '-=-' "
|
|
65
|
+
];
|
|
66
|
+
var EYE_FRAMES = ["@", "o", "."];
|
|
67
|
+
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
68
|
+
var DRONE_HEIGHT = DRONE_ART.length;
|
|
69
|
+
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
70
|
+
function microDroneFrame(tick) {
|
|
71
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
72
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
73
|
+
return `(${blade})${eye}(${blade})`;
|
|
74
|
+
}
|
|
75
|
+
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
76
|
+
function renderMicroDroneFrame(tick) {
|
|
77
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
78
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
79
|
+
return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// packages/cli/src/commands/_spinner.ts
|
|
83
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
84
|
+
function createTtySpinner(input) {
|
|
85
|
+
const output = input.output ?? process.stdout;
|
|
86
|
+
const isTty = output.isTTY === true;
|
|
87
|
+
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
88
|
+
let label = input.label;
|
|
89
|
+
let frame = 0;
|
|
90
|
+
let paused = false;
|
|
91
|
+
let stopped = false;
|
|
92
|
+
let lastPrintedLabel = "";
|
|
93
|
+
const render = () => {
|
|
94
|
+
if (stopped || paused)
|
|
95
|
+
return;
|
|
96
|
+
if (!isTty) {
|
|
97
|
+
if (label !== lastPrintedLabel) {
|
|
98
|
+
output.write(`${label}
|
|
99
|
+
`);
|
|
100
|
+
lastPrintedLabel = label;
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
frame = (frame + 1) % frames.length;
|
|
105
|
+
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
106
|
+
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
107
|
+
};
|
|
108
|
+
const clearLine = () => {
|
|
109
|
+
if (isTty)
|
|
110
|
+
output.write("\r\x1B[2K");
|
|
111
|
+
};
|
|
112
|
+
render();
|
|
113
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
114
|
+
return {
|
|
115
|
+
setLabel(next) {
|
|
116
|
+
label = next;
|
|
117
|
+
render();
|
|
118
|
+
},
|
|
119
|
+
pause() {
|
|
120
|
+
paused = true;
|
|
121
|
+
clearLine();
|
|
122
|
+
},
|
|
123
|
+
resume() {
|
|
124
|
+
if (stopped)
|
|
125
|
+
return;
|
|
126
|
+
paused = false;
|
|
127
|
+
render();
|
|
128
|
+
},
|
|
129
|
+
stop(finalLine) {
|
|
130
|
+
if (stopped)
|
|
131
|
+
return;
|
|
132
|
+
stopped = true;
|
|
133
|
+
if (timer)
|
|
134
|
+
clearInterval(timer);
|
|
135
|
+
clearLine();
|
|
136
|
+
if (finalLine)
|
|
137
|
+
output.write(`${finalLine}
|
|
138
|
+
`);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// packages/cli/src/app/drone-ui.ts
|
|
144
|
+
var isTty = () => Boolean(process.stdout.isTTY);
|
|
145
|
+
function droneNote(message, title) {
|
|
146
|
+
if (title)
|
|
147
|
+
console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
|
|
148
|
+
for (const line of message.split(`
|
|
149
|
+
`)) {
|
|
150
|
+
console.log(` ${ink4("\u2502")} ${line}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function droneCancel(text) {
|
|
154
|
+
console.log(` ${red("\u2716")} ${ink3(text)}`);
|
|
155
|
+
}
|
|
156
|
+
var SELECT_THEME = {
|
|
157
|
+
selectedPrefix: (text) => accent(text),
|
|
158
|
+
selectedText: (text) => bold(ink(text)),
|
|
159
|
+
description: (text) => ink3(text),
|
|
160
|
+
scrollInfo: (text) => ink4(text),
|
|
161
|
+
noMatch: (text) => ink3(text)
|
|
162
|
+
};
|
|
163
|
+
async function runMiniTui(build) {
|
|
164
|
+
const terminal = new ProcessTerminal;
|
|
165
|
+
const tui = new TUI(terminal);
|
|
166
|
+
let settled = false;
|
|
167
|
+
return await new Promise((resolve) => {
|
|
168
|
+
const finish = (result) => {
|
|
169
|
+
if (settled)
|
|
170
|
+
return;
|
|
171
|
+
settled = true;
|
|
172
|
+
tui.stop();
|
|
173
|
+
resolve(result);
|
|
174
|
+
};
|
|
175
|
+
build(tui, finish);
|
|
176
|
+
tui.start();
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
async function droneSelect(input) {
|
|
180
|
+
if (!isTty() || input.options.length === 0) {
|
|
181
|
+
return input.initialValue ?? input.options[0]?.value ?? null;
|
|
182
|
+
}
|
|
183
|
+
return runMiniTui((tui, finish) => {
|
|
184
|
+
tui.addChild(new Text(` ${accent("\u258D")}${bold(ink(input.message))}`));
|
|
185
|
+
const items = input.options.map((option) => ({
|
|
186
|
+
value: option.value,
|
|
187
|
+
label: option.label,
|
|
188
|
+
...option.hint ? { description: option.hint } : {}
|
|
189
|
+
}));
|
|
190
|
+
const list = new SelectList(items, Math.min(items.length, 12), SELECT_THEME);
|
|
191
|
+
const initialIndex = input.initialValue ? items.findIndex((item) => item.value === input.initialValue) : -1;
|
|
192
|
+
if (initialIndex > 0)
|
|
193
|
+
list.setSelectedIndex(initialIndex);
|
|
194
|
+
list.onSelect = (item) => finish(item.value);
|
|
195
|
+
list.onCancel = () => finish(null);
|
|
196
|
+
tui.addChild(list);
|
|
197
|
+
tui.addChild(new Text(ink4(" \u2191\u2193 navigate \xB7 enter select \xB7 esc cancel")));
|
|
198
|
+
tui.setFocus(list);
|
|
199
|
+
tui.addInputListener((data) => {
|
|
200
|
+
if (matchesKey(data, "ctrl+c") || matchesKey(data, "escape")) {
|
|
201
|
+
finish(null);
|
|
202
|
+
return { consume: true };
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async function droneConfirm(input) {
|
|
209
|
+
const answer = await droneSelect({
|
|
210
|
+
message: input.message,
|
|
211
|
+
options: [
|
|
212
|
+
{ value: "yes", label: "Yes" },
|
|
213
|
+
{ value: "no", label: "No" }
|
|
214
|
+
],
|
|
215
|
+
initialValue: input.initialValue === false ? "no" : "yes"
|
|
216
|
+
});
|
|
217
|
+
return answer === null ? null : answer === "yes";
|
|
218
|
+
}
|
|
7
219
|
|
|
8
220
|
// packages/cli/src/runner.ts
|
|
9
221
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
@@ -413,7 +625,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
413
625
|
})() : null;
|
|
414
626
|
if (!response.ok) {
|
|
415
627
|
const diagnostics = diagnosticMessage(payload);
|
|
416
|
-
const
|
|
628
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
629
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
630
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
417
631
|
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
418
632
|
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
419
633
|
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
@@ -786,9 +1000,6 @@ function withMutedConsole(mute, fn) {
|
|
|
786
1000
|
}
|
|
787
1001
|
}
|
|
788
1002
|
|
|
789
|
-
// packages/cli/src/commands/_task-picker.ts
|
|
790
|
-
import { cancel, isCancel, select } from "@clack/prompts";
|
|
791
|
-
|
|
792
1003
|
// packages/cli/src/commands/_operator-surface.ts
|
|
793
1004
|
import { createInterface } from "readline";
|
|
794
1005
|
import { createInterface as createPromptInterface } from "readline/promises";
|
|
@@ -1011,8 +1222,8 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
|
1011
1222
|
return null;
|
|
1012
1223
|
if (tasks.length === 1)
|
|
1013
1224
|
return tasks[0];
|
|
1014
|
-
const
|
|
1015
|
-
if (!
|
|
1225
|
+
const isTty2 = io.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
1226
|
+
if (!isTty2) {
|
|
1016
1227
|
throw new Error("task run requires an interactive terminal to pick a task; pass --task <id>, --next, or --detach with a task id.");
|
|
1017
1228
|
}
|
|
1018
1229
|
if (io.prompt || io.renderer) {
|
|
@@ -1036,12 +1247,12 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
|
1036
1247
|
label: `${taskId2(task)} \xB7 ${typeof task.title === "string" && task.title.trim() ? task.title.trim() : "Untitled task"}`,
|
|
1037
1248
|
hint: typeof task.status === "string" && task.status.trim() ? task.status.trim() : undefined
|
|
1038
1249
|
}));
|
|
1039
|
-
const answer = await
|
|
1250
|
+
const answer = await droneSelect({
|
|
1040
1251
|
message: "Select Rig task",
|
|
1041
1252
|
options
|
|
1042
1253
|
});
|
|
1043
|
-
if (
|
|
1044
|
-
|
|
1254
|
+
if (answer === null) {
|
|
1255
|
+
droneCancel("No task selected.");
|
|
1045
1256
|
return null;
|
|
1046
1257
|
}
|
|
1047
1258
|
const index = Number.parseInt(String(answer), 10);
|
|
@@ -1050,70 +1261,6 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
|
1050
1261
|
|
|
1051
1262
|
// packages/cli/src/commands/_async-ui.ts
|
|
1052
1263
|
import pc from "picocolors";
|
|
1053
|
-
|
|
1054
|
-
// packages/cli/src/commands/_spinner.ts
|
|
1055
|
-
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1056
|
-
function createTtySpinner(input) {
|
|
1057
|
-
const output = input.output ?? process.stdout;
|
|
1058
|
-
const isTty = output.isTTY === true;
|
|
1059
|
-
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
1060
|
-
let label = input.label;
|
|
1061
|
-
let frame = 0;
|
|
1062
|
-
let paused = false;
|
|
1063
|
-
let stopped = false;
|
|
1064
|
-
let lastPrintedLabel = "";
|
|
1065
|
-
const render = () => {
|
|
1066
|
-
if (stopped || paused)
|
|
1067
|
-
return;
|
|
1068
|
-
if (!isTty) {
|
|
1069
|
-
if (label !== lastPrintedLabel) {
|
|
1070
|
-
output.write(`${label}
|
|
1071
|
-
`);
|
|
1072
|
-
lastPrintedLabel = label;
|
|
1073
|
-
}
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
frame = (frame + 1) % frames.length;
|
|
1077
|
-
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
1078
|
-
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
1079
|
-
};
|
|
1080
|
-
const clearLine = () => {
|
|
1081
|
-
if (isTty)
|
|
1082
|
-
output.write("\r\x1B[2K");
|
|
1083
|
-
};
|
|
1084
|
-
render();
|
|
1085
|
-
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
1086
|
-
return {
|
|
1087
|
-
setLabel(next) {
|
|
1088
|
-
label = next;
|
|
1089
|
-
render();
|
|
1090
|
-
},
|
|
1091
|
-
pause() {
|
|
1092
|
-
paused = true;
|
|
1093
|
-
clearLine();
|
|
1094
|
-
},
|
|
1095
|
-
resume() {
|
|
1096
|
-
if (stopped)
|
|
1097
|
-
return;
|
|
1098
|
-
paused = false;
|
|
1099
|
-
render();
|
|
1100
|
-
},
|
|
1101
|
-
stop(finalLine) {
|
|
1102
|
-
if (stopped)
|
|
1103
|
-
return;
|
|
1104
|
-
stopped = true;
|
|
1105
|
-
if (timer)
|
|
1106
|
-
clearInterval(timer);
|
|
1107
|
-
clearLine();
|
|
1108
|
-
if (finalLine)
|
|
1109
|
-
output.write(`${finalLine}
|
|
1110
|
-
`);
|
|
1111
|
-
}
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
// packages/cli/src/commands/_async-ui.ts
|
|
1116
|
-
var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
|
|
1117
1264
|
var DONE_SYMBOL = pc.green("\u25C7");
|
|
1118
1265
|
var FAIL_SYMBOL = pc.red("\u25A0");
|
|
1119
1266
|
var activeUpdate = null;
|
|
@@ -1127,9 +1274,9 @@ async function withSpinner(label, work, options = {}) {
|
|
|
1127
1274
|
return work(outer);
|
|
1128
1275
|
}
|
|
1129
1276
|
const output = options.output ?? process.stderr;
|
|
1130
|
-
const
|
|
1277
|
+
const isTty2 = output.isTTY === true;
|
|
1131
1278
|
let lastLabel = label;
|
|
1132
|
-
if (!
|
|
1279
|
+
if (!isTty2) {
|
|
1133
1280
|
output.write(`${label}
|
|
1134
1281
|
`);
|
|
1135
1282
|
const update2 = (next) => {
|
|
@@ -1147,8 +1294,8 @@ async function withSpinner(label, work, options = {}) {
|
|
|
1147
1294
|
const spinner = createTtySpinner({
|
|
1148
1295
|
label,
|
|
1149
1296
|
output,
|
|
1150
|
-
frames:
|
|
1151
|
-
styleFrame: (frame) =>
|
|
1297
|
+
frames: MICRO_DRONE_FRAMES,
|
|
1298
|
+
styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
|
|
1152
1299
|
});
|
|
1153
1300
|
const update = (next) => {
|
|
1154
1301
|
lastLabel = next;
|
|
@@ -1170,8 +1317,8 @@ async function withSpinner(label, work, options = {}) {
|
|
|
1170
1317
|
}
|
|
1171
1318
|
|
|
1172
1319
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
1173
|
-
import { mkdtempSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1174
|
-
import { tmpdir } from "os";
|
|
1320
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1321
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
1175
1322
|
import { join } from "path";
|
|
1176
1323
|
import { main as runPiMain } from "@earendil-works/pi-coding-agent";
|
|
1177
1324
|
import createPiRigExtension from "@rig/pi-rig";
|
|
@@ -1194,6 +1341,7 @@ function buildOperatorPiEnv(input) {
|
|
|
1194
1341
|
return {
|
|
1195
1342
|
PI_CODING_AGENT_SESSION_DIR: input.sessionDir,
|
|
1196
1343
|
PI_SKIP_VERSION_CHECK: "1",
|
|
1344
|
+
PI_HIDDEN_COMMANDS: "import,fork,clone,tree,new,resume,trust",
|
|
1197
1345
|
RIG_PI_OPERATOR_SESSION: "1",
|
|
1198
1346
|
RIG_RUN_ID: input.runId,
|
|
1199
1347
|
RIG_SERVER_URL: input.serverUrl,
|
|
@@ -1203,6 +1351,10 @@ function buildOperatorPiEnv(input) {
|
|
|
1203
1351
|
}
|
|
1204
1352
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
1205
1353
|
const server = await ensureServerForCli(context.projectRoot);
|
|
1354
|
+
const localCwd = join(homedir2(), ".rig", "drones", runId.slice(0, 8));
|
|
1355
|
+
mkdirSync2(localCwd, { recursive: true });
|
|
1356
|
+
trustDroneCwd(localCwd);
|
|
1357
|
+
installRigPiTheme();
|
|
1206
1358
|
let sessionFileArg = [];
|
|
1207
1359
|
try {
|
|
1208
1360
|
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/session-file`);
|
|
@@ -1216,7 +1368,7 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
1216
1368
|
try {
|
|
1217
1369
|
const header = JSON.parse(line);
|
|
1218
1370
|
if (header.type === "session" && typeof header.cwd === "string") {
|
|
1219
|
-
return JSON.stringify({ ...header, cwd:
|
|
1371
|
+
return JSON.stringify({ ...header, cwd: localCwd });
|
|
1220
1372
|
}
|
|
1221
1373
|
} catch {}
|
|
1222
1374
|
return line;
|
|
@@ -1228,6 +1380,105 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
1228
1380
|
} catch {}
|
|
1229
1381
|
return { server, sessionFileArg };
|
|
1230
1382
|
}
|
|
1383
|
+
var RIG_PI_THEME = {
|
|
1384
|
+
$schema: "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
1385
|
+
name: "rig",
|
|
1386
|
+
vars: {
|
|
1387
|
+
acid: "#ccff4d",
|
|
1388
|
+
acidDim: "#a9d63f",
|
|
1389
|
+
cyan: "#56d8ff",
|
|
1390
|
+
red: "#ff5d5d",
|
|
1391
|
+
yellow: "#ffd24d",
|
|
1392
|
+
ink: "#f2f3f6",
|
|
1393
|
+
ink2: "#aeb0ba",
|
|
1394
|
+
ink3: "#6c6e79",
|
|
1395
|
+
ink4: "#44464f",
|
|
1396
|
+
panel: "#101115",
|
|
1397
|
+
panelUser: "#14161b",
|
|
1398
|
+
toolPending: "#0e1013",
|
|
1399
|
+
toolSuccess: "#10150c",
|
|
1400
|
+
toolError: "#1a0f0f",
|
|
1401
|
+
customMsg: "#0f1410"
|
|
1402
|
+
},
|
|
1403
|
+
colors: {
|
|
1404
|
+
accent: "acid",
|
|
1405
|
+
border: "ink4",
|
|
1406
|
+
borderAccent: "acid",
|
|
1407
|
+
borderMuted: "ink4",
|
|
1408
|
+
success: "acid",
|
|
1409
|
+
error: "red",
|
|
1410
|
+
warning: "yellow",
|
|
1411
|
+
muted: "ink3",
|
|
1412
|
+
dim: "ink4",
|
|
1413
|
+
text: "ink",
|
|
1414
|
+
thinkingText: "ink3",
|
|
1415
|
+
selectedBg: "panel",
|
|
1416
|
+
userMessageBg: "panelUser",
|
|
1417
|
+
userMessageText: "ink",
|
|
1418
|
+
customMessageBg: "customMsg",
|
|
1419
|
+
customMessageText: "ink2",
|
|
1420
|
+
customMessageLabel: "acidDim",
|
|
1421
|
+
toolPendingBg: "toolPending",
|
|
1422
|
+
toolSuccessBg: "toolSuccess",
|
|
1423
|
+
toolErrorBg: "toolError",
|
|
1424
|
+
toolTitle: "ink",
|
|
1425
|
+
toolOutput: "ink3",
|
|
1426
|
+
mdHeading: "acid",
|
|
1427
|
+
mdLink: "cyan",
|
|
1428
|
+
mdLinkUrl: "ink4",
|
|
1429
|
+
mdCode: "acidDim",
|
|
1430
|
+
mdCodeBlock: "ink2",
|
|
1431
|
+
mdCodeBlockBorder: "ink4",
|
|
1432
|
+
mdQuote: "ink3",
|
|
1433
|
+
mdQuoteBorder: "ink4",
|
|
1434
|
+
mdHr: "ink4",
|
|
1435
|
+
mdListBullet: "acid",
|
|
1436
|
+
toolDiffAdded: "acid",
|
|
1437
|
+
toolDiffRemoved: "red",
|
|
1438
|
+
toolDiffContext: "ink3",
|
|
1439
|
+
syntaxComment: "ink3",
|
|
1440
|
+
syntaxKeyword: "cyan",
|
|
1441
|
+
syntaxFunction: "acid",
|
|
1442
|
+
syntaxVariable: "ink",
|
|
1443
|
+
syntaxString: "acidDim",
|
|
1444
|
+
syntaxNumber: "yellow",
|
|
1445
|
+
syntaxType: "cyan",
|
|
1446
|
+
syntaxOperator: "ink2",
|
|
1447
|
+
syntaxPunctuation: "ink3",
|
|
1448
|
+
thinkingOff: "ink4",
|
|
1449
|
+
thinkingMinimal: "ink3",
|
|
1450
|
+
thinkingLow: "ink2",
|
|
1451
|
+
thinkingMedium: "cyan",
|
|
1452
|
+
thinkingHigh: "acidDim",
|
|
1453
|
+
thinkingXhigh: "acid",
|
|
1454
|
+
bashMode: "cyan"
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1457
|
+
function trustDroneCwd(localCwd) {
|
|
1458
|
+
try {
|
|
1459
|
+
const agentDir = join(homedir2(), ".pi", "agent");
|
|
1460
|
+
mkdirSync2(agentDir, { recursive: true });
|
|
1461
|
+
const trustPath = join(agentDir, "trust.json");
|
|
1462
|
+
const store = existsSync3(trustPath) ? JSON.parse(readFileSync3(trustPath, "utf8")) : {};
|
|
1463
|
+
if (store[localCwd] !== true) {
|
|
1464
|
+
store[localCwd] = true;
|
|
1465
|
+
writeFileSync2(trustPath, `${JSON.stringify(store, null, "\t")}
|
|
1466
|
+
`);
|
|
1467
|
+
}
|
|
1468
|
+
} catch {}
|
|
1469
|
+
}
|
|
1470
|
+
function installRigPiTheme() {
|
|
1471
|
+
try {
|
|
1472
|
+
const themesDir = join(homedir2(), ".pi", "agent", "themes");
|
|
1473
|
+
mkdirSync2(themesDir, { recursive: true });
|
|
1474
|
+
const themePath = join(themesDir, "rig.json");
|
|
1475
|
+
const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
|
|
1476
|
+
`;
|
|
1477
|
+
if (!existsSync3(themePath) || readFileSync3(themePath, "utf8") !== next) {
|
|
1478
|
+
writeFileSync2(themePath, next);
|
|
1479
|
+
}
|
|
1480
|
+
} catch {}
|
|
1481
|
+
}
|
|
1231
1482
|
async function attachRunBundledPiFrontend(context, input) {
|
|
1232
1483
|
const tempSessionDir = mkdtempSync(join(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
1233
1484
|
const { server, sessionFileArg } = await withSpinner(`Opening Pi console for run ${input.runId}\u2026`, () => prepareOperatorConsole(context, input.runId, tempSessionDir), { outputMode: context.outputMode });
|
|
@@ -1365,8 +1616,9 @@ async function attachRunOperatorView(context, input) {
|
|
|
1365
1616
|
}
|
|
1366
1617
|
|
|
1367
1618
|
// packages/cli/src/commands/_cli-format.ts
|
|
1368
|
-
import { log, note } from "@clack/prompts";
|
|
1369
1619
|
import pc2 from "picocolors";
|
|
1620
|
+
var themeDim = (value) => ink3(value);
|
|
1621
|
+
var themeFaint = (value) => ink4(value);
|
|
1370
1622
|
function stringField(record, key, fallback = "") {
|
|
1371
1623
|
const value = record[key];
|
|
1372
1624
|
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
@@ -1395,15 +1647,15 @@ function pad(value, width) {
|
|
|
1395
1647
|
}
|
|
1396
1648
|
function statusColor(status) {
|
|
1397
1649
|
const normalized = status.toLowerCase();
|
|
1398
|
-
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
|
|
1399
|
-
return
|
|
1650
|
+
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved", "running"].includes(normalized))
|
|
1651
|
+
return accent;
|
|
1400
1652
|
if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
|
|
1401
|
-
return
|
|
1402
|
-
if (["
|
|
1403
|
-
return
|
|
1404
|
-
if (["ready", "open", "queued", "created", "
|
|
1405
|
-
return
|
|
1406
|
-
return
|
|
1653
|
+
return red;
|
|
1654
|
+
if (["reviewing", "validating", "in_progress", "in-progress", "remote", "preparing", "closing-out"].includes(normalized))
|
|
1655
|
+
return cyan;
|
|
1656
|
+
if (["ready", "open", "queued", "created", "local", "pending"].includes(normalized))
|
|
1657
|
+
return yellow;
|
|
1658
|
+
return themeDim;
|
|
1407
1659
|
}
|
|
1408
1660
|
function compactValue(value) {
|
|
1409
1661
|
if (value === null || value === undefined)
|
|
@@ -1424,27 +1676,24 @@ function printFormattedOutput(message2, options = {}) {
|
|
|
1424
1676
|
console.log(message2);
|
|
1425
1677
|
return;
|
|
1426
1678
|
}
|
|
1427
|
-
|
|
1428
|
-
note(message2, options.title);
|
|
1429
|
-
else
|
|
1430
|
-
log.message(message2);
|
|
1679
|
+
droneNote(message2, options.title);
|
|
1431
1680
|
}
|
|
1432
1681
|
function formatStatusPill(status) {
|
|
1433
1682
|
const label = status || "unknown";
|
|
1434
1683
|
return statusColor(label)(`\u25CF ${label}`);
|
|
1435
1684
|
}
|
|
1436
1685
|
function formatSection(title, subtitle) {
|
|
1437
|
-
return `${pc2.bold(
|
|
1686
|
+
return `${pc2.bold(accent("\u25C6"))} ${pc2.bold(title)}${subtitle ? themeDim(` \u2014 ${subtitle}`) : ""}`;
|
|
1438
1687
|
}
|
|
1439
1688
|
function formatSuccessCard(title, rows = []) {
|
|
1440
|
-
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${
|
|
1689
|
+
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${themeFaint("\u2502")} ${themeDim(key.padEnd(12))} ${value}`);
|
|
1441
1690
|
return [formatSection(title), ...body].join(`
|
|
1442
1691
|
`);
|
|
1443
1692
|
}
|
|
1444
1693
|
function formatNextSteps(steps) {
|
|
1445
1694
|
if (steps.length === 0)
|
|
1446
1695
|
return [];
|
|
1447
|
-
return [pc2.bold("Next"), ...steps.map((step) => `${
|
|
1696
|
+
return [pc2.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
|
|
1448
1697
|
}
|
|
1449
1698
|
function formatTaskList(tasks, options = {}) {
|
|
1450
1699
|
if (options.raw)
|
|
@@ -1466,8 +1715,8 @@ function formatTaskList(tasks, options = {}) {
|
|
|
1466
1715
|
const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
|
|
1467
1716
|
const header = `${pc2.bold(pad("TASK", idWidth))} ${pc2.bold(pad("STATUS", statusWidth))} ${pc2.bold("TITLE")}`;
|
|
1468
1717
|
const body = rows.map((row) => {
|
|
1469
|
-
const labels = row.labels.length > 0 ?
|
|
1470
|
-
const source = row.source ?
|
|
1718
|
+
const labels = row.labels.length > 0 ? themeDim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
|
|
1719
|
+
const source = row.source ? themeDim(` ${row.source}`) : "";
|
|
1471
1720
|
return [
|
|
1472
1721
|
pc2.bold(pad(truncate(row.id, idWidth), idWidth)),
|
|
1473
1722
|
statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
|
|
@@ -1572,7 +1821,6 @@ async function printPendingInboxFooter(context) {
|
|
|
1572
1821
|
}
|
|
1573
1822
|
|
|
1574
1823
|
// packages/cli/src/commands/_help-catalog.ts
|
|
1575
|
-
import { intro, log as log2, note as note2, outro } from "@clack/prompts";
|
|
1576
1824
|
import pc3 from "picocolors";
|
|
1577
1825
|
var TOP_LEVEL_SECTIONS = [
|
|
1578
1826
|
{
|
|
@@ -1875,25 +2123,6 @@ var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
|
|
|
1875
2123
|
function heading(title) {
|
|
1876
2124
|
return pc3.bold(pc3.cyan(title));
|
|
1877
2125
|
}
|
|
1878
|
-
function renderRigBanner(version) {
|
|
1879
|
-
const m = (s) => pc3.bold(pc3.magenta(s));
|
|
1880
|
-
const c = (s) => pc3.bold(pc3.cyan(s));
|
|
1881
|
-
const y = (s) => pc3.yellow(s);
|
|
1882
|
-
const d = (s) => pc3.dim(s);
|
|
1883
|
-
const lines = [
|
|
1884
|
-
m(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + d(" \u2591\u2592\u2593\u2588 "),
|
|
1885
|
-
m(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ") + d("\u2593\u2592\u2591"),
|
|
1886
|
-
c(" \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557") + d(" \u2591\u2592"),
|
|
1887
|
-
c(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551") + d(" \u2588\u2593\u2591"),
|
|
1888
|
-
y(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + d(" \u2592\u2591"),
|
|
1889
|
-
y(" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "),
|
|
1890
|
-
"",
|
|
1891
|
-
` ${c("\u25E2\u25E4")} ${pc3.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
|
|
1892
|
-
version ? ` ${d(`v${version} \xB7 jack in: rig task run --next`)}` : ` ${d("jack in: rig task run --next")}`
|
|
1893
|
-
];
|
|
1894
|
-
return lines.join(`
|
|
1895
|
-
`);
|
|
1896
|
-
}
|
|
1897
2126
|
function commandLine(command, description) {
|
|
1898
2127
|
const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
|
|
1899
2128
|
return `${pc3.dim("\u2502")} ${pc3.bold(commandColumn)} ${description}`;
|
|
@@ -1947,67 +2176,8 @@ function renderGroupHelp(groupName) {
|
|
|
1947
2176
|
const group = ALL_GROUPS.find((candidate) => candidate.name === groupName);
|
|
1948
2177
|
return group ? renderGroup(group) : null;
|
|
1949
2178
|
}
|
|
1950
|
-
function shouldUseClackOutput2() {
|
|
1951
|
-
return Boolean(process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
|
|
1952
|
-
}
|
|
1953
|
-
function printTopLevelHelp(state = {}) {
|
|
1954
|
-
if (!shouldUseClackOutput2()) {
|
|
1955
|
-
console.log(renderTopLevelHelp());
|
|
1956
|
-
return;
|
|
1957
|
-
}
|
|
1958
|
-
console.log(renderRigBanner(state.version));
|
|
1959
|
-
console.log("");
|
|
1960
|
-
if (state.projectInitialized === false) {
|
|
1961
|
-
intro("no rig project in this directory");
|
|
1962
|
-
note2([
|
|
1963
|
-
commandLine("rig init", "Set this repo up: config, GitHub auth, task source, server, Pi."),
|
|
1964
|
-
commandLine("rig init --yes", "Same, non-interactive, sensible defaults."),
|
|
1965
|
-
commandLine("rig doctor", "Already initialized somewhere else? Check the wiring.")
|
|
1966
|
-
].join(`
|
|
1967
|
-
`), "Get started");
|
|
1968
|
-
outro("After init: rig task run --next puts an agent on your next task.");
|
|
1969
|
-
return;
|
|
1970
|
-
}
|
|
1971
|
-
intro(state.selectedServer ? `server: ${state.selectedServer}` : "rig");
|
|
1972
|
-
for (const section of TOP_LEVEL_SECTIONS) {
|
|
1973
|
-
note2(renderCommandBlock(section.commands), `${section.title} \u2014 ${section.subtitle}`);
|
|
1974
|
-
}
|
|
1975
|
-
log2.info("More: rig help --advanced \xB7 rig <group> --help \xB7 rig --version");
|
|
1976
|
-
note2([
|
|
1977
|
-
commandLine("--project <path>", "Use a project root instead of auto-discovery."),
|
|
1978
|
-
commandLine("--json", "Emit structured output for scripts/agents."),
|
|
1979
|
-
commandLine("--dry-run", "Print the command plan without mutating state.")
|
|
1980
|
-
].join(`
|
|
1981
|
-
`), "Global options");
|
|
1982
|
-
outro("init \u2192 task run \u2192 attach (Pi console: watch + steer live) \u2192 inbox \u2192 merged.");
|
|
1983
|
-
}
|
|
1984
2179
|
function printGroupHelpDocument(groupName) {
|
|
1985
|
-
|
|
1986
|
-
if (!shouldUseClackOutput2()) {
|
|
1987
|
-
console.log(rendered);
|
|
1988
|
-
return;
|
|
1989
|
-
}
|
|
1990
|
-
const group = ALL_GROUPS.find((candidate) => candidate.name === groupName);
|
|
1991
|
-
if (!group) {
|
|
1992
|
-
printTopLevelHelp();
|
|
1993
|
-
return;
|
|
1994
|
-
}
|
|
1995
|
-
intro(`rig ${group.name}`);
|
|
1996
|
-
note2(group.summary, "Purpose");
|
|
1997
|
-
note2(group.usage.join(`
|
|
1998
|
-
`), "Usage");
|
|
1999
|
-
note2(group.commands.map((entry) => commandLine(entry.command, entry.description)).join(`
|
|
2000
|
-
`), "Commands");
|
|
2001
|
-
if (group.examples?.length)
|
|
2002
|
-
note2(group.examples.map((line) => `$ ${line}`).join(`
|
|
2003
|
-
`), "Examples");
|
|
2004
|
-
if (group.next?.length)
|
|
2005
|
-
note2(group.next.map((line) => `\u203A ${line}`).join(`
|
|
2006
|
-
`), "Next steps");
|
|
2007
|
-
if (group.advanced?.length)
|
|
2008
|
-
log2.info(group.advanced.join(`
|
|
2009
|
-
`));
|
|
2010
|
-
outro("Run with --json when scripts need structured output.");
|
|
2180
|
+
console.log(renderGroupHelp(groupName) ?? renderTopLevelHelp());
|
|
2011
2181
|
}
|
|
2012
2182
|
|
|
2013
2183
|
// packages/cli/src/commands/task.ts
|
|
@@ -2113,12 +2283,12 @@ async function resolveDirtyBaselineForTaskRun(context, explicit) {
|
|
|
2113
2283
|
if (explicit)
|
|
2114
2284
|
return { mode: explicit, state };
|
|
2115
2285
|
if (context.outputMode === "text" && process.stdin.isTTY && process.stdout.isTTY) {
|
|
2116
|
-
const answer = await
|
|
2286
|
+
const answer = await droneConfirm({
|
|
2117
2287
|
message: "Include current uncommitted changes in run baseline?",
|
|
2118
2288
|
initialValue: false
|
|
2119
2289
|
});
|
|
2120
|
-
if (
|
|
2121
|
-
|
|
2290
|
+
if (answer === null) {
|
|
2291
|
+
droneCancel("Run cancelled.");
|
|
2122
2292
|
throw new CliError("Run cancelled by user.", 1);
|
|
2123
2293
|
}
|
|
2124
2294
|
return { mode: answer ? "dirty-snapshot" : "head", state };
|
|
@@ -2273,7 +2443,7 @@ async function executeTask(context, args, options) {
|
|
|
2273
2443
|
const fileFlag = takeOption(rest.slice(1), "--file");
|
|
2274
2444
|
let content;
|
|
2275
2445
|
if (fileFlag.value) {
|
|
2276
|
-
content =
|
|
2446
|
+
content = readFileSync4(resolve3(context.projectRoot, fileFlag.value), "utf-8");
|
|
2277
2447
|
} else {
|
|
2278
2448
|
content = await readStdin();
|
|
2279
2449
|
}
|
|
@@ -2497,5 +2667,6 @@ async function executeTask(context, args, options) {
|
|
|
2497
2667
|
}
|
|
2498
2668
|
}
|
|
2499
2669
|
export {
|
|
2670
|
+
loadTaskRunProjectDefaults,
|
|
2500
2671
|
executeTask
|
|
2501
2672
|
};
|