@h-rig/cli 0.0.6-alpha.66 → 0.0.6-alpha.68
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 +250 -166
- package/dist/src/commands/_async-ui.js +141 -0
- package/dist/src/commands/_connection-state.js +5 -1
- package/dist/src/commands/_doctor-checks.js +18 -0
- package/dist/src/commands/_operator-view.js +143 -4
- package/dist/src/commands/_pi-frontend.js +13 -1
- package/dist/src/commands/_preflight.js +7 -0
- package/dist/src/commands/_server-client.js +13 -0
- package/dist/src/commands/_snapshot-upload.js +7 -0
- package/dist/src/commands/_spinner.js +4 -2
- package/dist/src/commands/doctor.js +145 -1
- package/dist/src/commands/github.js +137 -3
- package/dist/src/commands/inbox.js +139 -6
- package/dist/src/commands/init.js +18 -0
- package/dist/src/commands/inspect.js +147 -8
- package/dist/src/commands/run.js +190 -38
- package/dist/src/commands/server.js +7 -0
- package/dist/src/commands/setup.js +150 -6
- package/dist/src/commands/stats.js +448 -110
- package/dist/src/commands/task-run-driver.js +7 -0
- package/dist/src/commands/task.js +186 -47
- package/dist/src/commands.js +250 -166
- package/dist/src/index.js +250 -166
- package/package.json +8 -8
package/dist/src/commands/run.js
CHANGED
|
@@ -188,9 +188,21 @@ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
|
188
188
|
return;
|
|
189
189
|
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
190
190
|
}
|
|
191
|
+
function isRemoteConnectionSelected(projectRoot) {
|
|
192
|
+
return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
|
|
193
|
+
}
|
|
191
194
|
|
|
192
195
|
// packages/cli/src/commands/_server-client.ts
|
|
193
196
|
var scopedGitHubBearerTokens = new Map;
|
|
197
|
+
var serverPhaseListener = null;
|
|
198
|
+
function setServerPhaseListener(listener) {
|
|
199
|
+
const previous = serverPhaseListener;
|
|
200
|
+
serverPhaseListener = listener;
|
|
201
|
+
return previous;
|
|
202
|
+
}
|
|
203
|
+
function reportServerPhase(label) {
|
|
204
|
+
serverPhaseListener?.(label);
|
|
205
|
+
}
|
|
194
206
|
function cleanToken(value) {
|
|
195
207
|
const trimmed = value?.trim();
|
|
196
208
|
return trimmed ? trimmed : null;
|
|
@@ -233,6 +245,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
233
245
|
try {
|
|
234
246
|
const selected = resolveSelectedConnection(projectRoot);
|
|
235
247
|
if (selected?.connection.kind === "remote") {
|
|
248
|
+
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
236
249
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
237
250
|
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
238
251
|
return {
|
|
@@ -242,6 +255,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
242
255
|
serverProjectRoot
|
|
243
256
|
};
|
|
244
257
|
}
|
|
258
|
+
reportServerPhase("Starting local Rig server\u2026");
|
|
245
259
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
246
260
|
return {
|
|
247
261
|
baseUrl: connection.baseUrl,
|
|
@@ -348,6 +362,7 @@ async function requestServerJson(context, pathname, init = {}) {
|
|
|
348
362
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
349
363
|
if (server.serverProjectRoot)
|
|
350
364
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
365
|
+
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
351
366
|
let response;
|
|
352
367
|
try {
|
|
353
368
|
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
@@ -808,7 +823,12 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
808
823
|
};
|
|
809
824
|
let detached = false;
|
|
810
825
|
try {
|
|
811
|
-
await runPiMain([
|
|
826
|
+
await runPiMain([
|
|
827
|
+
"--no-extensions",
|
|
828
|
+
"--no-skills",
|
|
829
|
+
"--no-prompt-templates",
|
|
830
|
+
"--no-context-files"
|
|
831
|
+
], {
|
|
812
832
|
extensionFactories: [piRigExtensionFactory]
|
|
813
833
|
});
|
|
814
834
|
detached = true;
|
|
@@ -831,6 +851,127 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
831
851
|
};
|
|
832
852
|
}
|
|
833
853
|
|
|
854
|
+
// packages/cli/src/commands/_async-ui.ts
|
|
855
|
+
import pc from "picocolors";
|
|
856
|
+
|
|
857
|
+
// packages/cli/src/commands/_spinner.ts
|
|
858
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
859
|
+
function createTtySpinner(input) {
|
|
860
|
+
const output = input.output ?? process.stdout;
|
|
861
|
+
const isTty = output.isTTY === true;
|
|
862
|
+
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
863
|
+
let label = input.label;
|
|
864
|
+
let frame = 0;
|
|
865
|
+
let paused = false;
|
|
866
|
+
let stopped = false;
|
|
867
|
+
let lastPrintedLabel = "";
|
|
868
|
+
const render = () => {
|
|
869
|
+
if (stopped || paused)
|
|
870
|
+
return;
|
|
871
|
+
if (!isTty) {
|
|
872
|
+
if (label !== lastPrintedLabel) {
|
|
873
|
+
output.write(`${label}
|
|
874
|
+
`);
|
|
875
|
+
lastPrintedLabel = label;
|
|
876
|
+
}
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
frame = (frame + 1) % frames.length;
|
|
880
|
+
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
881
|
+
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
882
|
+
};
|
|
883
|
+
const clearLine = () => {
|
|
884
|
+
if (isTty)
|
|
885
|
+
output.write("\r\x1B[2K");
|
|
886
|
+
};
|
|
887
|
+
render();
|
|
888
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
889
|
+
return {
|
|
890
|
+
setLabel(next) {
|
|
891
|
+
label = next;
|
|
892
|
+
render();
|
|
893
|
+
},
|
|
894
|
+
pause() {
|
|
895
|
+
paused = true;
|
|
896
|
+
clearLine();
|
|
897
|
+
},
|
|
898
|
+
resume() {
|
|
899
|
+
if (stopped)
|
|
900
|
+
return;
|
|
901
|
+
paused = false;
|
|
902
|
+
render();
|
|
903
|
+
},
|
|
904
|
+
stop(finalLine) {
|
|
905
|
+
if (stopped)
|
|
906
|
+
return;
|
|
907
|
+
stopped = true;
|
|
908
|
+
if (timer)
|
|
909
|
+
clearInterval(timer);
|
|
910
|
+
clearLine();
|
|
911
|
+
if (finalLine)
|
|
912
|
+
output.write(`${finalLine}
|
|
913
|
+
`);
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// packages/cli/src/commands/_async-ui.ts
|
|
919
|
+
var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
|
|
920
|
+
var DONE_SYMBOL = pc.green("\u25C7");
|
|
921
|
+
var FAIL_SYMBOL = pc.red("\u25A0");
|
|
922
|
+
var activeUpdate = null;
|
|
923
|
+
async function withSpinner(label, work, options = {}) {
|
|
924
|
+
if (options.outputMode === "json") {
|
|
925
|
+
return work(() => {});
|
|
926
|
+
}
|
|
927
|
+
if (activeUpdate) {
|
|
928
|
+
const outer = activeUpdate;
|
|
929
|
+
outer(label);
|
|
930
|
+
return work(outer);
|
|
931
|
+
}
|
|
932
|
+
const output = options.output ?? process.stderr;
|
|
933
|
+
const isTty = output.isTTY === true;
|
|
934
|
+
let lastLabel = label;
|
|
935
|
+
if (!isTty) {
|
|
936
|
+
output.write(`${label}
|
|
937
|
+
`);
|
|
938
|
+
const update2 = (next) => {
|
|
939
|
+
lastLabel = next;
|
|
940
|
+
};
|
|
941
|
+
activeUpdate = update2;
|
|
942
|
+
const previousListener2 = setServerPhaseListener(update2);
|
|
943
|
+
try {
|
|
944
|
+
return await work(update2);
|
|
945
|
+
} finally {
|
|
946
|
+
activeUpdate = null;
|
|
947
|
+
setServerPhaseListener(previousListener2);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
const spinner = createTtySpinner({
|
|
951
|
+
label,
|
|
952
|
+
output,
|
|
953
|
+
frames: CLACK_SPINNER_FRAMES,
|
|
954
|
+
styleFrame: (frame) => pc.magenta(frame)
|
|
955
|
+
});
|
|
956
|
+
const update = (next) => {
|
|
957
|
+
lastLabel = next;
|
|
958
|
+
spinner.setLabel(next);
|
|
959
|
+
};
|
|
960
|
+
activeUpdate = update;
|
|
961
|
+
const previousListener = setServerPhaseListener(update);
|
|
962
|
+
try {
|
|
963
|
+
const result = await work(update);
|
|
964
|
+
spinner.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
|
|
965
|
+
return result;
|
|
966
|
+
} catch (error) {
|
|
967
|
+
spinner.stop(`${FAIL_SYMBOL} ${lastLabel}`);
|
|
968
|
+
throw error;
|
|
969
|
+
} finally {
|
|
970
|
+
activeUpdate = null;
|
|
971
|
+
setServerPhaseListener(previousListener);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
834
975
|
// packages/cli/src/commands/_operator-view.ts
|
|
835
976
|
var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
836
977
|
function runStatusFromPayload(payload) {
|
|
@@ -873,8 +1014,9 @@ async function readOperatorSnapshot(context, runId, options = {}) {
|
|
|
873
1014
|
}
|
|
874
1015
|
async function attachRunOperatorView(context, input) {
|
|
875
1016
|
let steered = false;
|
|
876
|
-
|
|
877
|
-
|
|
1017
|
+
const attachMessage = input.message?.trim();
|
|
1018
|
+
if (attachMessage) {
|
|
1019
|
+
await withSpinner("Queueing steering message\u2026", () => sendRunPiPromptViaServer(context, input.runId, attachMessage, "steer").catch(() => steerRunViaServer(context, input.runId, attachMessage)), { outputMode: context.outputMode });
|
|
878
1020
|
steered = true;
|
|
879
1021
|
}
|
|
880
1022
|
if (input.follow && !input.once && input.interactive !== false && context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
@@ -884,7 +1026,7 @@ async function attachRunOperatorView(context, input) {
|
|
|
884
1026
|
});
|
|
885
1027
|
}
|
|
886
1028
|
const surface = createOperatorSurface({ interactive: input.interactive !== false });
|
|
887
|
-
let snapshot = await readOperatorSnapshot(context, input.runId);
|
|
1029
|
+
let snapshot = await withSpinner(`Connecting to run ${input.runId}\u2026`, () => readOperatorSnapshot(context, input.runId), { outputMode: context.outputMode });
|
|
888
1030
|
if (context.outputMode === "text") {
|
|
889
1031
|
surface.renderSnapshot(snapshot);
|
|
890
1032
|
surface.renderTimeline(snapshot.timeline);
|
|
@@ -924,7 +1066,7 @@ async function attachRunOperatorView(context, input) {
|
|
|
924
1066
|
|
|
925
1067
|
// packages/cli/src/commands/_cli-format.ts
|
|
926
1068
|
import { log, note } from "@clack/prompts";
|
|
927
|
-
import
|
|
1069
|
+
import pc2 from "picocolors";
|
|
928
1070
|
function stringField(record, key, fallback = "") {
|
|
929
1071
|
const value = record[key];
|
|
930
1072
|
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
@@ -946,14 +1088,14 @@ function pad(value, width) {
|
|
|
946
1088
|
function statusColor(status) {
|
|
947
1089
|
const normalized = status.toLowerCase();
|
|
948
1090
|
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
|
|
949
|
-
return
|
|
1091
|
+
return pc2.green;
|
|
950
1092
|
if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
|
|
951
|
-
return
|
|
1093
|
+
return pc2.red;
|
|
952
1094
|
if (["running", "reviewing", "validating", "in_progress", "in-progress", "remote"].includes(normalized))
|
|
953
|
-
return
|
|
1095
|
+
return pc2.cyan;
|
|
954
1096
|
if (["ready", "open", "queued", "created", "preparing", "local", "pending"].includes(normalized))
|
|
955
|
-
return
|
|
956
|
-
return
|
|
1097
|
+
return pc2.yellow;
|
|
1098
|
+
return pc2.dim;
|
|
957
1099
|
}
|
|
958
1100
|
function compactDate(value) {
|
|
959
1101
|
if (!value.trim())
|
|
@@ -998,23 +1140,23 @@ function formatStatusPill(status) {
|
|
|
998
1140
|
return statusColor(label)(`\u25CF ${label}`);
|
|
999
1141
|
}
|
|
1000
1142
|
function formatSection(title, subtitle) {
|
|
1001
|
-
return `${
|
|
1143
|
+
return `${pc2.bold(pc2.cyan("\u25C6"))} ${pc2.bold(title)}${subtitle ? pc2.dim(` \u2014 ${subtitle}`) : ""}`;
|
|
1002
1144
|
}
|
|
1003
1145
|
function formatSuccessCard(title, rows = []) {
|
|
1004
|
-
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${
|
|
1146
|
+
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${pc2.dim("\u2502")} ${pc2.dim(key.padEnd(12))} ${value}`);
|
|
1005
1147
|
return [formatSection(title), ...body].join(`
|
|
1006
1148
|
`);
|
|
1007
1149
|
}
|
|
1008
1150
|
function formatNextSteps(steps) {
|
|
1009
1151
|
if (steps.length === 0)
|
|
1010
1152
|
return [];
|
|
1011
|
-
return [
|
|
1153
|
+
return [pc2.bold("Next"), ...steps.map((step) => `${pc2.dim("\u203A")} ${step}`)];
|
|
1012
1154
|
}
|
|
1013
1155
|
function formatRunList(runs, options = {}) {
|
|
1014
1156
|
if (runs.length === 0) {
|
|
1015
1157
|
return [
|
|
1016
1158
|
formatSection("Runs", "none recorded"),
|
|
1017
|
-
options.source === "server" ?
|
|
1159
|
+
options.source === "server" ? pc2.dim("No runs recorded on the selected Rig server.") : pc2.dim("No runs recorded in .rig/runs."),
|
|
1018
1160
|
"",
|
|
1019
1161
|
...formatNextSteps(["Start one: `rig task run --next`", "Check server: `rig server status`"])
|
|
1020
1162
|
].join(`
|
|
@@ -1030,11 +1172,11 @@ function formatRunList(runs, options = {}) {
|
|
|
1030
1172
|
});
|
|
1031
1173
|
const idWidth = Math.min(36, Math.max(6, ...rows.map((row) => row.runId.length)));
|
|
1032
1174
|
const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
|
|
1033
|
-
const header = `${
|
|
1175
|
+
const header = `${pc2.bold(pad("RUN", idWidth))} ${pc2.bold(pad("STATUS", statusWidth))} ${pc2.bold("TITLE")}`;
|
|
1034
1176
|
const body = rows.map((row) => [
|
|
1035
|
-
|
|
1177
|
+
pc2.bold(pad(truncate(row.runId, idWidth), idWidth)),
|
|
1036
1178
|
statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
|
|
1037
|
-
`${row.title}${row.runtime ?
|
|
1179
|
+
`${row.title}${row.runtime ? pc2.dim(` ${row.runtime}`) : ""}`
|
|
1038
1180
|
].join(" "));
|
|
1039
1181
|
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(`
|
|
1040
1182
|
`);
|
|
@@ -1059,7 +1201,7 @@ function formatRunCard(run, options = {}) {
|
|
|
1059
1201
|
const approvals = Array.isArray(merged.approvals) ? merged.approvals.length : null;
|
|
1060
1202
|
const inputs = Array.isArray(merged.userInputs) ? merged.userInputs.length : null;
|
|
1061
1203
|
const rows = [
|
|
1062
|
-
["run",
|
|
1204
|
+
["run", pc2.bold(runId)],
|
|
1063
1205
|
["status", formatStatusPill(status)],
|
|
1064
1206
|
["task", taskId],
|
|
1065
1207
|
["title", title],
|
|
@@ -1085,17 +1227,17 @@ function formatRunStatus(summary, options = {}) {
|
|
|
1085
1227
|
const activeRuns = summary.activeRuns ?? [];
|
|
1086
1228
|
const recentRuns = summary.recentRuns ?? [];
|
|
1087
1229
|
const lines = [formatSection("Run status", options.source === "server" ? "selected server" : "local state")];
|
|
1088
|
-
lines.push("",
|
|
1230
|
+
lines.push("", pc2.bold(`Active runs (${activeRuns.length})`));
|
|
1089
1231
|
if (activeRuns.length === 0) {
|
|
1090
|
-
lines.push(
|
|
1232
|
+
lines.push(pc2.dim("No active runs."));
|
|
1091
1233
|
} else {
|
|
1092
1234
|
for (const run of activeRuns) {
|
|
1093
1235
|
lines.push(formatRunSummaryLine(run));
|
|
1094
1236
|
}
|
|
1095
1237
|
}
|
|
1096
|
-
lines.push("",
|
|
1238
|
+
lines.push("", pc2.bold(`Recent runs (${recentRuns.length})`));
|
|
1097
1239
|
if (recentRuns.length === 0) {
|
|
1098
|
-
lines.push(
|
|
1240
|
+
lines.push(pc2.dim("No recent terminal runs."));
|
|
1099
1241
|
} else {
|
|
1100
1242
|
for (const run of recentRuns.slice(0, 10)) {
|
|
1101
1243
|
lines.push(formatRunSummaryLine(run));
|
|
@@ -1113,7 +1255,7 @@ function formatRunSummaryLine(run) {
|
|
|
1113
1255
|
const title = runTitleOf(record);
|
|
1114
1256
|
const runtime = firstString(record, ["runtimeAdapter", "runtime", "adapter"]);
|
|
1115
1257
|
const descriptor = [taskId, title].filter(Boolean).join(" \xB7 ");
|
|
1116
|
-
return `${
|
|
1258
|
+
return `${pc2.dim("\u2502")} ${pc2.bold(runId)} ${formatStatusPill(status)} ${descriptor}${runtime ? pc2.dim(` ${runtime}`) : ""}`;
|
|
1117
1259
|
}
|
|
1118
1260
|
|
|
1119
1261
|
// packages/cli/src/commands/inbox.ts
|
|
@@ -1167,9 +1309,6 @@ function normalizeRemoteRunDetails(payload) {
|
|
|
1167
1309
|
};
|
|
1168
1310
|
}
|
|
1169
1311
|
var REMOTE_TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged"]);
|
|
1170
|
-
function isRemoteConnectionSelected(projectRoot) {
|
|
1171
|
-
return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
|
|
1172
|
-
}
|
|
1173
1312
|
async function listRunsForSelectedConnection(context, options = {}) {
|
|
1174
1313
|
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
1175
1314
|
return { runs: await listRunsViaServer(context, options), source: "server" };
|
|
@@ -1250,7 +1389,7 @@ async function executeRun(context, args) {
|
|
|
1250
1389
|
switch (command) {
|
|
1251
1390
|
case "list": {
|
|
1252
1391
|
requireNoExtraArgs(rest, "rig run list");
|
|
1253
|
-
const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
|
|
1392
|
+
const { runs, source } = isRemoteConnectionSelected(context.projectRoot) ? await withSpinner("Reading runs from server\u2026", () => listRunsForSelectedConnection(context, { limit: 100 }), { outputMode: context.outputMode }) : await listRunsForSelectedConnection(context, { limit: 100 });
|
|
1254
1393
|
if (context.outputMode === "text") {
|
|
1255
1394
|
printFormattedOutput(formatRunList(runs, { source }));
|
|
1256
1395
|
await printPendingInboxFooter(context);
|
|
@@ -1323,7 +1462,7 @@ async function executeRun(context, args) {
|
|
|
1323
1462
|
if (!runId) {
|
|
1324
1463
|
throw new CliError("run show requires a run id.", 1, { hint: "Run `rig run list` to find run ids, then `rig run show <run-id>`." });
|
|
1325
1464
|
}
|
|
1326
|
-
const record = readAuthorityRun2(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, runId).catch(() => ({})));
|
|
1465
|
+
const record = readAuthorityRun2(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await withSpinner(`Reading run ${runId} from server\u2026`, () => getRunDetailsViaServer(context, runId).catch(() => ({})), { outputMode: context.outputMode }));
|
|
1327
1466
|
if (!record) {
|
|
1328
1467
|
throw new CliError(`Run not found: ${runId}`, 2, { hint: "Run `rig run list` to see recorded runs." });
|
|
1329
1468
|
}
|
|
@@ -1344,7 +1483,8 @@ async function executeRun(context, args) {
|
|
|
1344
1483
|
}
|
|
1345
1484
|
const renderer = createPiRunStreamRenderer();
|
|
1346
1485
|
let cursor = null;
|
|
1347
|
-
const
|
|
1486
|
+
const timelineRunId = run.value;
|
|
1487
|
+
const page = await withSpinner(`Reading timeline for ${timelineRunId}\u2026`, () => getRunTimelineViaServer(context, timelineRunId, { limit: 500 }), { outputMode: context.outputMode });
|
|
1348
1488
|
const events = Array.isArray(page.entries) ? page.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
1349
1489
|
cursor = typeof page.nextCursor === "string" ? page.nextCursor : null;
|
|
1350
1490
|
if (context.outputMode === "text") {
|
|
@@ -1421,8 +1561,9 @@ async function executeRun(context, args) {
|
|
|
1421
1561
|
throw new CliError("run attach requires a run id.", 2, { hint: "Run `rig run list` to find run ids, then `rig run attach <run-id> --follow`." });
|
|
1422
1562
|
}
|
|
1423
1563
|
let steered = false;
|
|
1424
|
-
|
|
1425
|
-
|
|
1564
|
+
const steerMessage = messageOption.value?.trim();
|
|
1565
|
+
if (steerMessage) {
|
|
1566
|
+
await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, steerMessage), { outputMode: context.outputMode });
|
|
1426
1567
|
steered = true;
|
|
1427
1568
|
}
|
|
1428
1569
|
const attached = await attachRunOperatorView(context, {
|
|
@@ -1442,7 +1583,7 @@ async function executeRun(context, args) {
|
|
|
1442
1583
|
}
|
|
1443
1584
|
return { ok: true, group: "run", command };
|
|
1444
1585
|
}
|
|
1445
|
-
const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
|
|
1586
|
+
const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await withSpinner("Reading run status from server\u2026", () => listRunsViaServer(context, { limit: 100 }), { outputMode: context.outputMode })) : runStatus(context.projectRoot, runtimeContext);
|
|
1446
1587
|
const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
1447
1588
|
const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
1448
1589
|
if (context.outputMode === "text") {
|
|
@@ -1519,28 +1660,38 @@ async function executeRun(context, args) {
|
|
|
1519
1660
|
};
|
|
1520
1661
|
}
|
|
1521
1662
|
case "resume": {
|
|
1522
|
-
|
|
1663
|
+
let pending = rest;
|
|
1664
|
+
const runOpt = takeOption(pending, "--run");
|
|
1665
|
+
pending = runOpt.rest;
|
|
1666
|
+
const positional = pending[0] && !pending[0].startsWith("-") ? pending.shift() : undefined;
|
|
1667
|
+
requireNoExtraArgs(pending, "rig run resume [<run-id>] [--run <id>]");
|
|
1668
|
+
const targetRunId = runOpt.value ?? positional ?? null;
|
|
1523
1669
|
if (context.dryRun) {
|
|
1524
1670
|
if (context.outputMode === "text") {
|
|
1525
1671
|
console.log("[dry-run] rig run resume");
|
|
1526
1672
|
}
|
|
1527
1673
|
return { ok: true, group: "run", command };
|
|
1528
1674
|
}
|
|
1529
|
-
const resumed = await runResume(context.projectRoot, runtimeContext);
|
|
1675
|
+
const resumed = await runResume(context.projectRoot, runtimeContext, targetRunId);
|
|
1530
1676
|
if (context.outputMode === "text") {
|
|
1531
1677
|
console.log(`Resumed run: ${resumed.runId}`);
|
|
1532
1678
|
}
|
|
1533
1679
|
return { ok: true, group: "run", command, details: resumed };
|
|
1534
1680
|
}
|
|
1535
1681
|
case "restart": {
|
|
1536
|
-
|
|
1682
|
+
let pending = rest;
|
|
1683
|
+
const runOpt = takeOption(pending, "--run");
|
|
1684
|
+
pending = runOpt.rest;
|
|
1685
|
+
const positional = pending[0] && !pending[0].startsWith("-") ? pending.shift() : undefined;
|
|
1686
|
+
requireNoExtraArgs(pending, "rig run restart [<run-id>] [--run <id>]");
|
|
1687
|
+
const targetRunId = runOpt.value ?? positional ?? null;
|
|
1537
1688
|
if (context.dryRun) {
|
|
1538
1689
|
if (context.outputMode === "text") {
|
|
1539
1690
|
console.log("[dry-run] rig run restart");
|
|
1540
1691
|
}
|
|
1541
1692
|
return { ok: true, group: "run", command };
|
|
1542
1693
|
}
|
|
1543
|
-
const restarted = await runRestart(context.projectRoot, runtimeContext);
|
|
1694
|
+
const restarted = await runRestart(context.projectRoot, runtimeContext, targetRunId);
|
|
1544
1695
|
if (context.outputMode === "text") {
|
|
1545
1696
|
console.log(`Restarted run: ${restarted.runId}`);
|
|
1546
1697
|
}
|
|
@@ -1567,7 +1718,8 @@ async function executeRun(context, args) {
|
|
|
1567
1718
|
}
|
|
1568
1719
|
return { ok: true, group: "run", command, details: { runId, dryRun: true } };
|
|
1569
1720
|
}
|
|
1570
|
-
|
|
1721
|
+
const trimmedMessage = message.trim();
|
|
1722
|
+
await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, trimmedMessage), { outputMode: context.outputMode });
|
|
1571
1723
|
if (context.outputMode === "text") {
|
|
1572
1724
|
console.log(`Steering message queued for ${runId}.`);
|
|
1573
1725
|
}
|
|
@@ -1588,7 +1740,7 @@ async function executeRun(context, args) {
|
|
|
1588
1740
|
};
|
|
1589
1741
|
}
|
|
1590
1742
|
if (runId) {
|
|
1591
|
-
const stopped = await stopRunViaServer(context, runId);
|
|
1743
|
+
const stopped = await withSpinner(`Requesting stop for ${runId}\u2026`, () => stopRunViaServer(context, runId), { outputMode: context.outputMode });
|
|
1592
1744
|
if (context.outputMode === "text")
|
|
1593
1745
|
console.log(`Stop requested: ${runId}`);
|
|
1594
1746
|
return { ok: true, group: "run", command, details: stopped };
|
|
@@ -361,6 +361,10 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
|
361
361
|
import { resolve as resolve2 } from "path";
|
|
362
362
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
363
363
|
var scopedGitHubBearerTokens = new Map;
|
|
364
|
+
var serverPhaseListener = null;
|
|
365
|
+
function reportServerPhase(label) {
|
|
366
|
+
serverPhaseListener?.(label);
|
|
367
|
+
}
|
|
364
368
|
function cleanToken(value) {
|
|
365
369
|
const trimmed = value?.trim();
|
|
366
370
|
return trimmed ? trimmed : null;
|
|
@@ -403,6 +407,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
403
407
|
try {
|
|
404
408
|
const selected = resolveSelectedConnection(projectRoot);
|
|
405
409
|
if (selected?.connection.kind === "remote") {
|
|
410
|
+
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
406
411
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
407
412
|
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
408
413
|
return {
|
|
@@ -412,6 +417,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
412
417
|
serverProjectRoot
|
|
413
418
|
};
|
|
414
419
|
}
|
|
420
|
+
reportServerPhase("Starting local Rig server\u2026");
|
|
415
421
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
416
422
|
return {
|
|
417
423
|
baseUrl: connection.baseUrl,
|
|
@@ -518,6 +524,7 @@ async function requestServerJson(context, pathname, init = {}) {
|
|
|
518
524
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
519
525
|
if (server.serverProjectRoot)
|
|
520
526
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
527
|
+
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
521
528
|
let response;
|
|
522
529
|
try {
|
|
523
530
|
response = await fetch(`${server.baseUrl}${pathname}`, {
|