@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
|
@@ -41,24 +41,171 @@ Usage: ${usage}`);
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// packages/cli/src/app/drone-ui.ts
|
|
45
|
+
import { ProcessTerminal, TUI, Text, Input, SelectList, matchesKey } from "@earendil-works/pi-tui";
|
|
46
|
+
|
|
47
|
+
// packages/cli/src/app/theme.ts
|
|
48
|
+
var RIG_PALETTE = {
|
|
49
|
+
ink: "#f2f3f6",
|
|
50
|
+
ink2: "#aeb0ba",
|
|
51
|
+
ink3: "#6c6e79",
|
|
52
|
+
ink4: "#44464f",
|
|
53
|
+
accent: "#ccff4d",
|
|
54
|
+
accentDim: "#a9d63f",
|
|
55
|
+
cyan: "#56d8ff",
|
|
56
|
+
red: "#ff5d5d",
|
|
57
|
+
yellow: "#ffd24d"
|
|
58
|
+
};
|
|
59
|
+
function hexToRgb(hex) {
|
|
60
|
+
const value = hex.replace("#", "");
|
|
61
|
+
return [
|
|
62
|
+
Number.parseInt(value.slice(0, 2), 16),
|
|
63
|
+
Number.parseInt(value.slice(2, 4), 16),
|
|
64
|
+
Number.parseInt(value.slice(4, 6), 16)
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
function fg(hex) {
|
|
68
|
+
const [r, g, b] = hexToRgb(hex);
|
|
69
|
+
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
70
|
+
}
|
|
71
|
+
var ink = fg(RIG_PALETTE.ink);
|
|
72
|
+
var ink2 = fg(RIG_PALETTE.ink2);
|
|
73
|
+
var ink3 = fg(RIG_PALETTE.ink3);
|
|
74
|
+
var ink4 = fg(RIG_PALETTE.ink4);
|
|
75
|
+
var accent = fg(RIG_PALETTE.accent);
|
|
76
|
+
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
77
|
+
var cyan = fg(RIG_PALETTE.cyan);
|
|
78
|
+
var red = fg(RIG_PALETTE.red);
|
|
79
|
+
var yellow = fg(RIG_PALETTE.yellow);
|
|
80
|
+
function bold(text) {
|
|
81
|
+
return `\x1B[1m${text}\x1B[22m`;
|
|
82
|
+
}
|
|
83
|
+
var DRONE_ART = [
|
|
84
|
+
" .-=-. .-=-. ",
|
|
85
|
+
" ( !!! ) ( !!! ) ",
|
|
86
|
+
" '-=-'._ _.'-=-' ",
|
|
87
|
+
" '._ _.' ",
|
|
88
|
+
" '=$$$$$$$=.' ",
|
|
89
|
+
" =$$$$$$$$$$$= ",
|
|
90
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
91
|
+
" $$$@@ @@$$$ ",
|
|
92
|
+
" $$@ ? @$$$ ",
|
|
93
|
+
" $$$@ '-' @$$$ ",
|
|
94
|
+
" $$$@@ @@$$$ ",
|
|
95
|
+
" $$$@@@@@@@@@@$$$ ",
|
|
96
|
+
" =$$$$$$$$$$$= ",
|
|
97
|
+
" '=$$$$$$$=.' ",
|
|
98
|
+
" _.' '._ ",
|
|
99
|
+
" .-=-.' '.-=-. ",
|
|
100
|
+
" ( !!! ) ( !!! ) ",
|
|
101
|
+
" '-=-' '-=-' "
|
|
102
|
+
];
|
|
103
|
+
var EYE_FRAMES = ["@", "o", "."];
|
|
104
|
+
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
105
|
+
var DRONE_HEIGHT = DRONE_ART.length;
|
|
106
|
+
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
107
|
+
function microDroneFrame(tick) {
|
|
108
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
109
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
110
|
+
return `(${blade})${eye}(${blade})`;
|
|
111
|
+
}
|
|
112
|
+
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
113
|
+
function renderMicroDroneFrame(tick) {
|
|
114
|
+
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
115
|
+
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
116
|
+
return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// packages/cli/src/commands/_spinner.ts
|
|
120
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
121
|
+
function createTtySpinner(input) {
|
|
122
|
+
const output = input.output ?? process.stdout;
|
|
123
|
+
const isTty = output.isTTY === true;
|
|
124
|
+
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
125
|
+
let label = input.label;
|
|
126
|
+
let frame = 0;
|
|
127
|
+
let paused = false;
|
|
128
|
+
let stopped = false;
|
|
129
|
+
let lastPrintedLabel = "";
|
|
130
|
+
const render = () => {
|
|
131
|
+
if (stopped || paused)
|
|
132
|
+
return;
|
|
133
|
+
if (!isTty) {
|
|
134
|
+
if (label !== lastPrintedLabel) {
|
|
135
|
+
output.write(`${label}
|
|
136
|
+
`);
|
|
137
|
+
lastPrintedLabel = label;
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
frame = (frame + 1) % frames.length;
|
|
142
|
+
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
143
|
+
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
144
|
+
};
|
|
145
|
+
const clearLine = () => {
|
|
146
|
+
if (isTty)
|
|
147
|
+
output.write("\r\x1B[2K");
|
|
148
|
+
};
|
|
149
|
+
render();
|
|
150
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
151
|
+
return {
|
|
152
|
+
setLabel(next) {
|
|
153
|
+
label = next;
|
|
154
|
+
render();
|
|
155
|
+
},
|
|
156
|
+
pause() {
|
|
157
|
+
paused = true;
|
|
158
|
+
clearLine();
|
|
159
|
+
},
|
|
160
|
+
resume() {
|
|
161
|
+
if (stopped)
|
|
162
|
+
return;
|
|
163
|
+
paused = false;
|
|
164
|
+
render();
|
|
165
|
+
},
|
|
166
|
+
stop(finalLine) {
|
|
167
|
+
if (stopped)
|
|
168
|
+
return;
|
|
169
|
+
stopped = true;
|
|
170
|
+
if (timer)
|
|
171
|
+
clearInterval(timer);
|
|
172
|
+
clearLine();
|
|
173
|
+
if (finalLine)
|
|
174
|
+
output.write(`${finalLine}
|
|
175
|
+
`);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// packages/cli/src/app/drone-ui.ts
|
|
181
|
+
function droneNote(message, title) {
|
|
182
|
+
if (title)
|
|
183
|
+
console.log(` ${accentDim("\u25C7")} ${bold(ink2(title))}`);
|
|
184
|
+
for (const line of message.split(`
|
|
185
|
+
`)) {
|
|
186
|
+
console.log(` ${ink4("\u2502")} ${line}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
44
190
|
// packages/cli/src/commands/_cli-format.ts
|
|
45
|
-
import { log, note } from "@clack/prompts";
|
|
46
191
|
import pc from "picocolors";
|
|
192
|
+
var themeDim = (value) => ink3(value);
|
|
193
|
+
var themeFaint = (value) => ink4(value);
|
|
47
194
|
function stringField(record, key, fallback = "") {
|
|
48
195
|
const value = record[key];
|
|
49
196
|
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
50
197
|
}
|
|
51
198
|
function statusColor(status) {
|
|
52
199
|
const normalized = status.toLowerCase();
|
|
53
|
-
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
|
|
54
|
-
return
|
|
200
|
+
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved", "running"].includes(normalized))
|
|
201
|
+
return accent;
|
|
55
202
|
if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
|
|
56
|
-
return
|
|
57
|
-
if (["
|
|
58
|
-
return
|
|
59
|
-
if (["ready", "open", "queued", "created", "
|
|
60
|
-
return
|
|
61
|
-
return
|
|
203
|
+
return red;
|
|
204
|
+
if (["reviewing", "validating", "in_progress", "in-progress", "remote", "preparing", "closing-out"].includes(normalized))
|
|
205
|
+
return cyan;
|
|
206
|
+
if (["ready", "open", "queued", "created", "local", "pending"].includes(normalized))
|
|
207
|
+
return yellow;
|
|
208
|
+
return themeDim;
|
|
62
209
|
}
|
|
63
210
|
function firstString(record, keys, fallback = "") {
|
|
64
211
|
for (const key of keys) {
|
|
@@ -79,29 +226,26 @@ function printFormattedOutput(message, options = {}) {
|
|
|
79
226
|
console.log(message);
|
|
80
227
|
return;
|
|
81
228
|
}
|
|
82
|
-
|
|
83
|
-
note(message, options.title);
|
|
84
|
-
else
|
|
85
|
-
log.message(message);
|
|
229
|
+
droneNote(message, options.title);
|
|
86
230
|
}
|
|
87
231
|
function formatStatusPill(status) {
|
|
88
232
|
const label = status || "unknown";
|
|
89
233
|
return statusColor(label)(`\u25CF ${label}`);
|
|
90
234
|
}
|
|
91
235
|
function formatSection(title, subtitle) {
|
|
92
|
-
return `${pc.bold(
|
|
236
|
+
return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? themeDim(` \u2014 ${subtitle}`) : ""}`;
|
|
93
237
|
}
|
|
94
238
|
function formatNextSteps(steps) {
|
|
95
239
|
if (steps.length === 0)
|
|
96
240
|
return [];
|
|
97
|
-
return [pc.bold("Next"), ...steps.map((step) => `${
|
|
241
|
+
return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
|
|
98
242
|
}
|
|
99
243
|
function formatInboxList(kind, entries) {
|
|
100
244
|
const title = kind === "approvals" ? "Approval inbox" : "Input inbox";
|
|
101
245
|
if (entries.length === 0) {
|
|
102
246
|
return [
|
|
103
247
|
formatSection(title, "empty"),
|
|
104
|
-
|
|
248
|
+
themeDim(kind === "approvals" ? "No pending approvals." : "No pending user-input requests."),
|
|
105
249
|
"",
|
|
106
250
|
...formatNextSteps(["Check runs: `rig run status`", "Start work: `rig task run --next`"])
|
|
107
251
|
].join(`
|
|
@@ -115,8 +259,8 @@ function formatInboxList(kind, entries) {
|
|
|
115
259
|
const requestId = requestIdOf(record);
|
|
116
260
|
const status = firstString(record, ["status", "state"], "pending");
|
|
117
261
|
const prompt = firstString(record, ["prompt", "message", "reason", "title", "summary"], kind === "approvals" ? "Approval requested" : "Input requested");
|
|
118
|
-
lines.push(`${
|
|
119
|
-
lines.push(`${
|
|
262
|
+
lines.push(`${themeFaint("\u2502")} ${pc.bold(requestId)} ${formatStatusPill(status)} ${prompt}`);
|
|
263
|
+
lines.push(`${themeFaint("\u2502")} ${themeDim("run ")} ${runId || "(unknown-run)"}${taskId ? themeDim(` task ${taskId}`) : ""}`);
|
|
120
264
|
}
|
|
121
265
|
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`"]));
|
|
122
266
|
return lines.join(`
|
|
@@ -417,7 +561,9 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
417
561
|
})() : null;
|
|
418
562
|
if (!response.ok) {
|
|
419
563
|
const diagnostics = diagnosticMessage(payload);
|
|
420
|
-
const
|
|
564
|
+
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
565
|
+
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
566
|
+
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
421
567
|
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
422
568
|
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
423
569
|
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
@@ -438,70 +584,6 @@ var RESUMABLE_RUN_STATUSES = new Set([
|
|
|
438
584
|
|
|
439
585
|
// packages/cli/src/commands/_async-ui.ts
|
|
440
586
|
import pc2 from "picocolors";
|
|
441
|
-
|
|
442
|
-
// packages/cli/src/commands/_spinner.ts
|
|
443
|
-
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
444
|
-
function createTtySpinner(input) {
|
|
445
|
-
const output = input.output ?? process.stdout;
|
|
446
|
-
const isTty = output.isTTY === true;
|
|
447
|
-
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
448
|
-
let label = input.label;
|
|
449
|
-
let frame = 0;
|
|
450
|
-
let paused = false;
|
|
451
|
-
let stopped = false;
|
|
452
|
-
let lastPrintedLabel = "";
|
|
453
|
-
const render = () => {
|
|
454
|
-
if (stopped || paused)
|
|
455
|
-
return;
|
|
456
|
-
if (!isTty) {
|
|
457
|
-
if (label !== lastPrintedLabel) {
|
|
458
|
-
output.write(`${label}
|
|
459
|
-
`);
|
|
460
|
-
lastPrintedLabel = label;
|
|
461
|
-
}
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
frame = (frame + 1) % frames.length;
|
|
465
|
-
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
466
|
-
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
467
|
-
};
|
|
468
|
-
const clearLine = () => {
|
|
469
|
-
if (isTty)
|
|
470
|
-
output.write("\r\x1B[2K");
|
|
471
|
-
};
|
|
472
|
-
render();
|
|
473
|
-
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
474
|
-
return {
|
|
475
|
-
setLabel(next) {
|
|
476
|
-
label = next;
|
|
477
|
-
render();
|
|
478
|
-
},
|
|
479
|
-
pause() {
|
|
480
|
-
paused = true;
|
|
481
|
-
clearLine();
|
|
482
|
-
},
|
|
483
|
-
resume() {
|
|
484
|
-
if (stopped)
|
|
485
|
-
return;
|
|
486
|
-
paused = false;
|
|
487
|
-
render();
|
|
488
|
-
},
|
|
489
|
-
stop(finalLine) {
|
|
490
|
-
if (stopped)
|
|
491
|
-
return;
|
|
492
|
-
stopped = true;
|
|
493
|
-
if (timer)
|
|
494
|
-
clearInterval(timer);
|
|
495
|
-
clearLine();
|
|
496
|
-
if (finalLine)
|
|
497
|
-
output.write(`${finalLine}
|
|
498
|
-
`);
|
|
499
|
-
}
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// packages/cli/src/commands/_async-ui.ts
|
|
504
|
-
var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
|
|
505
587
|
var DONE_SYMBOL = pc2.green("\u25C7");
|
|
506
588
|
var FAIL_SYMBOL = pc2.red("\u25A0");
|
|
507
589
|
var activeUpdate = null;
|
|
@@ -535,8 +617,8 @@ async function withSpinner(label, work, options = {}) {
|
|
|
535
617
|
const spinner = createTtySpinner({
|
|
536
618
|
label,
|
|
537
619
|
output,
|
|
538
|
-
frames:
|
|
539
|
-
styleFrame: (frame) =>
|
|
620
|
+
frames: MICRO_DRONE_FRAMES,
|
|
621
|
+
styleFrame: (frame) => renderMicroDroneFrame(Math.max(0, MICRO_DRONE_FRAMES.indexOf(frame)))
|
|
540
622
|
});
|
|
541
623
|
const update = (next) => {
|
|
542
624
|
lastLabel = next;
|
|
@@ -684,8 +766,8 @@ async function executeInbox(context, args) {
|
|
|
684
766
|
pending = request.rest;
|
|
685
767
|
const decision = takeOption(pending, "--decision");
|
|
686
768
|
pending = decision.rest;
|
|
687
|
-
const
|
|
688
|
-
pending =
|
|
769
|
+
const note = takeOption(pending, "--note");
|
|
770
|
+
pending = note.rest;
|
|
689
771
|
requireNoExtraArgs(pending, "rig inbox approve --run <id> --request <id> --decision approve|reject [--note <text>]");
|
|
690
772
|
if (!run.value || !request.value || !decision.value) {
|
|
691
773
|
throw new CliError("approve requires --run, --request, and --decision. List pending requests with `rig inbox approvals`.");
|
|
@@ -700,7 +782,7 @@ async function executeInbox(context, args) {
|
|
|
700
782
|
runId: run.value,
|
|
701
783
|
requestId: request.value,
|
|
702
784
|
decision: decision.value,
|
|
703
|
-
note:
|
|
785
|
+
note: note.value ?? null
|
|
704
786
|
})
|
|
705
787
|
}), { outputMode: context.outputMode });
|
|
706
788
|
return { ok: true, group: "inbox", command, details: { result } };
|
|
@@ -763,5 +845,6 @@ async function executeInbox(context, args) {
|
|
|
763
845
|
export {
|
|
764
846
|
readPendingInboxCounts,
|
|
765
847
|
printPendingInboxFooter,
|
|
848
|
+
listInboxRecords,
|
|
766
849
|
executeInbox
|
|
767
850
|
};
|