@h-rig/cli 0.0.6-alpha.67 → 0.0.6-alpha.69
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 +266 -75
- package/dist/src/commands/_async-ui.js +152 -0
- package/dist/src/commands/_doctor-checks.js +29 -0
- package/dist/src/commands/_operator-view.js +154 -4
- package/dist/src/commands/_pi-frontend.js +24 -1
- package/dist/src/commands/_preflight.js +18 -0
- package/dist/src/commands/_server-client.js +46 -0
- package/dist/src/commands/_snapshot-upload.js +18 -0
- package/dist/src/commands/_spinner.js +4 -2
- package/dist/src/commands/agent.js +11 -0
- package/dist/src/commands/doctor.js +156 -1
- package/dist/src/commands/github.js +148 -3
- package/dist/src/commands/inbox.js +150 -6
- package/dist/src/commands/init.js +29 -0
- package/dist/src/commands/inspect.js +158 -8
- package/dist/src/commands/queue.js +11 -0
- package/dist/src/commands/run.js +207 -35
- package/dist/src/commands/server.js +18 -0
- package/dist/src/commands/setup.js +161 -6
- package/dist/src/commands/stats.js +167 -22
- package/dist/src/commands/task-run-driver.js +18 -0
- package/dist/src/commands/task.js +197 -47
- package/dist/src/commands.js +266 -75
- package/dist/src/index.js +266 -75
- package/package.json +8 -8
package/dist/bin/rig.js
CHANGED
|
@@ -2933,6 +2933,15 @@ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
|
2933
2933
|
import { resolve as resolve11 } from "path";
|
|
2934
2934
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
2935
2935
|
var scopedGitHubBearerTokens = new Map;
|
|
2936
|
+
var serverPhaseListener = null;
|
|
2937
|
+
function setServerPhaseListener(listener) {
|
|
2938
|
+
const previous = serverPhaseListener;
|
|
2939
|
+
serverPhaseListener = listener;
|
|
2940
|
+
return previous;
|
|
2941
|
+
}
|
|
2942
|
+
function reportServerPhase(label) {
|
|
2943
|
+
serverPhaseListener?.(label);
|
|
2944
|
+
}
|
|
2936
2945
|
function cleanToken(value) {
|
|
2937
2946
|
const trimmed = value?.trim();
|
|
2938
2947
|
return trimmed ? trimmed : null;
|
|
@@ -2979,6 +2988,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
2979
2988
|
try {
|
|
2980
2989
|
const selected = resolveSelectedConnection(projectRoot);
|
|
2981
2990
|
if (selected?.connection.kind === "remote") {
|
|
2991
|
+
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
2982
2992
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
2983
2993
|
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
2984
2994
|
return {
|
|
@@ -2988,6 +2998,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
2988
2998
|
serverProjectRoot
|
|
2989
2999
|
};
|
|
2990
3000
|
}
|
|
3001
|
+
reportServerPhase("Starting local Rig server\u2026");
|
|
2991
3002
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
2992
3003
|
return {
|
|
2993
3004
|
baseUrl: connection.baseUrl,
|
|
@@ -3104,6 +3115,7 @@ async function requestServerJson(context, pathname, init = {}) {
|
|
|
3104
3115
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
3105
3116
|
if (server.serverProjectRoot)
|
|
3106
3117
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
3118
|
+
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
3107
3119
|
let response;
|
|
3108
3120
|
try {
|
|
3109
3121
|
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
@@ -3281,6 +3293,38 @@ async function updateWorkspaceTaskViaServer(context, input) {
|
|
|
3281
3293
|
});
|
|
3282
3294
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
|
|
3283
3295
|
}
|
|
3296
|
+
var RESUMABLE_RUN_STATUSES = new Set([
|
|
3297
|
+
"created",
|
|
3298
|
+
"preparing",
|
|
3299
|
+
"running",
|
|
3300
|
+
"validating",
|
|
3301
|
+
"reviewing",
|
|
3302
|
+
"stopped",
|
|
3303
|
+
"failed",
|
|
3304
|
+
"needs-attention",
|
|
3305
|
+
"needs_attention"
|
|
3306
|
+
]);
|
|
3307
|
+
async function resumeRunViaServer(context, runId, options) {
|
|
3308
|
+
let targetRunId = runId?.trim() || null;
|
|
3309
|
+
if (!targetRunId) {
|
|
3310
|
+
const candidates = (await listRunsViaServer(context)).filter((run) => RESUMABLE_RUN_STATUSES.has(String(run.status ?? ""))).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")));
|
|
3311
|
+
targetRunId = typeof candidates[0]?.runId === "string" ? candidates[0].runId : null;
|
|
3312
|
+
}
|
|
3313
|
+
if (!targetRunId) {
|
|
3314
|
+
throw new CliError(options.restart ? "No run is available to restart." : "No resumable run is available.", 2, { hint: "List runs with `rig run list`, then pass an explicit id: `rig run resume <run-id>`." });
|
|
3315
|
+
}
|
|
3316
|
+
const payload = await requestServerJson(context, "/api/runs/resume", {
|
|
3317
|
+
method: "POST",
|
|
3318
|
+
headers: { "content-type": "application/json" },
|
|
3319
|
+
body: JSON.stringify({ runId: targetRunId, createdAt: new Date().toISOString(), restart: options.restart })
|
|
3320
|
+
});
|
|
3321
|
+
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
3322
|
+
if (record.ok === false) {
|
|
3323
|
+
const message = typeof record.error === "string" && record.error.trim() ? record.error : "run resume failed";
|
|
3324
|
+
throw new CliError(`${options.restart ? "restart" : "resume"} failed for ${targetRunId}: ${message}`, 1);
|
|
3325
|
+
}
|
|
3326
|
+
return { ok: true, runId: targetRunId, ...record };
|
|
3327
|
+
}
|
|
3284
3328
|
async function stopRunViaServer(context, runId) {
|
|
3285
3329
|
const payload = await requestServerJson(context, "/api/runs/stop", {
|
|
3286
3330
|
method: "POST",
|
|
@@ -4624,6 +4668,127 @@ function formatConnectionStatus(selected, connections) {
|
|
|
4624
4668
|
`);
|
|
4625
4669
|
}
|
|
4626
4670
|
|
|
4671
|
+
// packages/cli/src/commands/_async-ui.ts
|
|
4672
|
+
import pc4 from "picocolors";
|
|
4673
|
+
|
|
4674
|
+
// packages/cli/src/commands/_spinner.ts
|
|
4675
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
4676
|
+
function createTtySpinner(input) {
|
|
4677
|
+
const output = input.output ?? process.stdout;
|
|
4678
|
+
const isTty = output.isTTY === true;
|
|
4679
|
+
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
4680
|
+
let label = input.label;
|
|
4681
|
+
let frame = 0;
|
|
4682
|
+
let paused = false;
|
|
4683
|
+
let stopped = false;
|
|
4684
|
+
let lastPrintedLabel = "";
|
|
4685
|
+
const render = () => {
|
|
4686
|
+
if (stopped || paused)
|
|
4687
|
+
return;
|
|
4688
|
+
if (!isTty) {
|
|
4689
|
+
if (label !== lastPrintedLabel) {
|
|
4690
|
+
output.write(`${label}
|
|
4691
|
+
`);
|
|
4692
|
+
lastPrintedLabel = label;
|
|
4693
|
+
}
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
4696
|
+
frame = (frame + 1) % frames.length;
|
|
4697
|
+
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
4698
|
+
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
4699
|
+
};
|
|
4700
|
+
const clearLine = () => {
|
|
4701
|
+
if (isTty)
|
|
4702
|
+
output.write("\r\x1B[2K");
|
|
4703
|
+
};
|
|
4704
|
+
render();
|
|
4705
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
4706
|
+
return {
|
|
4707
|
+
setLabel(next) {
|
|
4708
|
+
label = next;
|
|
4709
|
+
render();
|
|
4710
|
+
},
|
|
4711
|
+
pause() {
|
|
4712
|
+
paused = true;
|
|
4713
|
+
clearLine();
|
|
4714
|
+
},
|
|
4715
|
+
resume() {
|
|
4716
|
+
if (stopped)
|
|
4717
|
+
return;
|
|
4718
|
+
paused = false;
|
|
4719
|
+
render();
|
|
4720
|
+
},
|
|
4721
|
+
stop(finalLine) {
|
|
4722
|
+
if (stopped)
|
|
4723
|
+
return;
|
|
4724
|
+
stopped = true;
|
|
4725
|
+
if (timer)
|
|
4726
|
+
clearInterval(timer);
|
|
4727
|
+
clearLine();
|
|
4728
|
+
if (finalLine)
|
|
4729
|
+
output.write(`${finalLine}
|
|
4730
|
+
`);
|
|
4731
|
+
}
|
|
4732
|
+
};
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
// packages/cli/src/commands/_async-ui.ts
|
|
4736
|
+
var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
|
|
4737
|
+
var DONE_SYMBOL = pc4.green("\u25C7");
|
|
4738
|
+
var FAIL_SYMBOL = pc4.red("\u25A0");
|
|
4739
|
+
var activeUpdate = null;
|
|
4740
|
+
async function withSpinner(label, work, options = {}) {
|
|
4741
|
+
if (options.outputMode === "json") {
|
|
4742
|
+
return work(() => {});
|
|
4743
|
+
}
|
|
4744
|
+
if (activeUpdate) {
|
|
4745
|
+
const outer = activeUpdate;
|
|
4746
|
+
outer(label);
|
|
4747
|
+
return work(outer);
|
|
4748
|
+
}
|
|
4749
|
+
const output = options.output ?? process.stderr;
|
|
4750
|
+
const isTty = output.isTTY === true;
|
|
4751
|
+
let lastLabel = label;
|
|
4752
|
+
if (!isTty) {
|
|
4753
|
+
output.write(`${label}
|
|
4754
|
+
`);
|
|
4755
|
+
const update2 = (next) => {
|
|
4756
|
+
lastLabel = next;
|
|
4757
|
+
};
|
|
4758
|
+
activeUpdate = update2;
|
|
4759
|
+
const previousListener2 = setServerPhaseListener(update2);
|
|
4760
|
+
try {
|
|
4761
|
+
return await work(update2);
|
|
4762
|
+
} finally {
|
|
4763
|
+
activeUpdate = null;
|
|
4764
|
+
setServerPhaseListener(previousListener2);
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
const spinner2 = createTtySpinner({
|
|
4768
|
+
label,
|
|
4769
|
+
output,
|
|
4770
|
+
frames: CLACK_SPINNER_FRAMES,
|
|
4771
|
+
styleFrame: (frame) => pc4.magenta(frame)
|
|
4772
|
+
});
|
|
4773
|
+
const update = (next) => {
|
|
4774
|
+
lastLabel = next;
|
|
4775
|
+
spinner2.setLabel(next);
|
|
4776
|
+
};
|
|
4777
|
+
activeUpdate = update;
|
|
4778
|
+
const previousListener = setServerPhaseListener(update);
|
|
4779
|
+
try {
|
|
4780
|
+
const result = await work(update);
|
|
4781
|
+
spinner2.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
|
|
4782
|
+
return result;
|
|
4783
|
+
} catch (error) {
|
|
4784
|
+
spinner2.stop(`${FAIL_SYMBOL} ${lastLabel}`);
|
|
4785
|
+
throw error;
|
|
4786
|
+
} finally {
|
|
4787
|
+
activeUpdate = null;
|
|
4788
|
+
setServerPhaseListener(previousListener);
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
|
|
4627
4792
|
// packages/cli/src/commands/inbox.ts
|
|
4628
4793
|
async function listInboxRecords(context, kind, filters) {
|
|
4629
4794
|
const params = new URLSearchParams;
|
|
@@ -4728,7 +4893,7 @@ async function executeInbox(context, args) {
|
|
|
4728
4893
|
const task = takeOption(pending, "--task");
|
|
4729
4894
|
pending = task.rest;
|
|
4730
4895
|
requireNoExtraArgs(pending, "rig inbox approvals [--run <id>] [--task <id>]");
|
|
4731
|
-
const approvals = await listInboxRecords(context, "approvals", { run: run.value, task: task.value });
|
|
4896
|
+
const approvals = await withSpinner("Reading approvals from server\u2026", () => listInboxRecords(context, "approvals", { run: run.value, task: task.value }), { outputMode: context.outputMode });
|
|
4732
4897
|
renderList(context, "approvals", approvals);
|
|
4733
4898
|
return { ok: true, group: "inbox", command, details: { approvals } };
|
|
4734
4899
|
}
|
|
@@ -4739,7 +4904,7 @@ async function executeInbox(context, args) {
|
|
|
4739
4904
|
const task = takeOption(pending, "--task");
|
|
4740
4905
|
pending = task.rest;
|
|
4741
4906
|
requireNoExtraArgs(pending, "rig inbox inputs [--run <id>] [--task <id>]");
|
|
4742
|
-
const requests = await listInboxRecords(context, "inputs", { run: run.value, task: task.value });
|
|
4907
|
+
const requests = await withSpinner("Reading input requests from server\u2026", () => listInboxRecords(context, "inputs", { run: run.value, task: task.value }), { outputMode: context.outputMode });
|
|
4743
4908
|
renderList(context, "inputs", requests);
|
|
4744
4909
|
return { ok: true, group: "inbox", command, details: { requests } };
|
|
4745
4910
|
}
|
|
@@ -4760,7 +4925,7 @@ async function executeInbox(context, args) {
|
|
|
4760
4925
|
if (decision.value !== "approve" && decision.value !== "reject") {
|
|
4761
4926
|
throw new CliError("decision must be approve or reject.", 1, { hint: "Re-run as `rig inbox approve --run <id> --request <id> --decision approve|reject`." });
|
|
4762
4927
|
}
|
|
4763
|
-
const result = await requestServerJson(context, "/api/inbox/approvals/resolve", {
|
|
4928
|
+
const result = await withSpinner(`Resolving approval ${request.value}\u2026`, () => requestServerJson(context, "/api/inbox/approvals/resolve", {
|
|
4764
4929
|
method: "POST",
|
|
4765
4930
|
headers: { "content-type": "application/json" },
|
|
4766
4931
|
body: JSON.stringify({
|
|
@@ -4769,7 +4934,7 @@ async function executeInbox(context, args) {
|
|
|
4769
4934
|
decision: decision.value,
|
|
4770
4935
|
note: note4.value ?? null
|
|
4771
4936
|
})
|
|
4772
|
-
});
|
|
4937
|
+
}), { outputMode: context.outputMode });
|
|
4773
4938
|
return { ok: true, group: "inbox", command, details: { result } };
|
|
4774
4939
|
}
|
|
4775
4940
|
case "respond": {
|
|
@@ -4803,7 +4968,7 @@ async function executeInbox(context, args) {
|
|
|
4803
4968
|
const [key, ...restValue] = entry.split("=");
|
|
4804
4969
|
return [key, restValue.join("=")];
|
|
4805
4970
|
}));
|
|
4806
|
-
const result = await requestServerJson(context, "/api/inbox/inputs/respond", {
|
|
4971
|
+
const result = await withSpinner(`Sending response for ${request.value}\u2026`, () => requestServerJson(context, "/api/inbox/inputs/respond", {
|
|
4807
4972
|
method: "POST",
|
|
4808
4973
|
headers: { "content-type": "application/json" },
|
|
4809
4974
|
body: JSON.stringify({
|
|
@@ -4811,7 +4976,7 @@ async function executeInbox(context, args) {
|
|
|
4811
4976
|
requestId: request.value,
|
|
4812
4977
|
answers: parsedAnswers
|
|
4813
4978
|
})
|
|
4814
|
-
});
|
|
4979
|
+
}), { outputMode: context.outputMode });
|
|
4815
4980
|
return { ok: true, group: "inbox", command, details: { result } };
|
|
4816
4981
|
}
|
|
4817
4982
|
case "watch": {
|
|
@@ -5228,7 +5393,10 @@ async function runRigDoctorChecks(options) {
|
|
|
5228
5393
|
const bunVersion = options.bunVersion ?? Bun.version;
|
|
5229
5394
|
const request = options.requestJson ?? ((pathname, init) => requestServerJson({ projectRoot }, pathname, init));
|
|
5230
5395
|
const loadConfig = options.loadConfig ?? loadRigConfigOrNull;
|
|
5396
|
+
const progress = options.onProgress ?? (() => {});
|
|
5397
|
+
progress("Checking local toolchain\u2026");
|
|
5231
5398
|
checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
|
|
5399
|
+
progress("Loading rig.config\u2026");
|
|
5232
5400
|
const loadedConfig = await loadConfig(projectRoot).catch(() => null);
|
|
5233
5401
|
const config = loadedConfig ?? loadFallbackConfig(projectRoot);
|
|
5234
5402
|
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync11(resolve17(projectRoot, name)));
|
|
@@ -5247,6 +5415,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5247
5415
|
checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig server list` and `rig server use <alias|local>`." : undefined));
|
|
5248
5416
|
let server = null;
|
|
5249
5417
|
try {
|
|
5418
|
+
progress("Connecting to the selected Rig server\u2026");
|
|
5250
5419
|
server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
|
|
5251
5420
|
checks.push(check("server", "Rig server reachable", "pass", `${server.connectionKind} ${server.baseUrl}`));
|
|
5252
5421
|
} catch (error) {
|
|
@@ -5254,18 +5423,21 @@ async function runRigDoctorChecks(options) {
|
|
|
5254
5423
|
}
|
|
5255
5424
|
if (server || options.requestJson) {
|
|
5256
5425
|
try {
|
|
5426
|
+
progress("Checking server status\u2026");
|
|
5257
5427
|
const status = await request("/api/server/status");
|
|
5258
5428
|
checks.push(check("server-status", "server project status", "pass", JSON.stringify(status).slice(0, 180)));
|
|
5259
5429
|
} catch (error) {
|
|
5260
5430
|
checks.push(check("server-status", "server project status", "fail", errorMessage(error), "Run `rig doctor` after the selected server is reachable."));
|
|
5261
5431
|
}
|
|
5262
5432
|
try {
|
|
5433
|
+
progress("Checking GitHub auth\u2026");
|
|
5263
5434
|
const auth = await request("/api/github/auth/status");
|
|
5264
5435
|
checks.push(isAuthenticated2(auth) ? check("github-auth", "GitHub auth", "pass") : check("github-auth", "GitHub auth", "fail", "not authenticated", "Run `rig github auth import-gh` or `rig github auth token --token <token>`."));
|
|
5265
5436
|
} catch (error) {
|
|
5266
5437
|
checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig and ensure the server exposes auth status."));
|
|
5267
5438
|
}
|
|
5268
5439
|
try {
|
|
5440
|
+
progress("Checking GitHub repo permissions\u2026");
|
|
5269
5441
|
const permissions = await request("/api/github/repo/permissions");
|
|
5270
5442
|
const allowed = permissionAllowsPr2(permissions);
|
|
5271
5443
|
checks.push(allowed === true ? check("github-repo-permissions", "GitHub repo PR permissions", "pass", JSON.stringify(permissions).slice(0, 180)) : allowed === false ? check("github-repo-permissions", "GitHub repo PR permissions", "fail", JSON.stringify(permissions).slice(0, 180), "Grant the selected GitHub token permission to push branches, open PRs, and merge according to repo rules.") : check("github-repo-permissions", "GitHub repo PR permissions", "warn", JSON.stringify(permissions).slice(0, 180), "Confirm the selected token can push branches and open PRs."));
|
|
@@ -5273,6 +5445,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5273
5445
|
checks.push(check("github-repo-permissions", "GitHub repo PR permissions", "warn", errorMessage(error), "Ensure the server exposes repo permission checks and the token can open PRs."));
|
|
5274
5446
|
}
|
|
5275
5447
|
try {
|
|
5448
|
+
progress("Checking GitHub issue labels\u2026");
|
|
5276
5449
|
const labels = await request("/api/workspace/task-labels");
|
|
5277
5450
|
const ready = labelsReady(labels);
|
|
5278
5451
|
checks.push(ready === false ? check("task-labels", "GitHub issue labels", "fail", JSON.stringify(labels).slice(0, 180), "Let Rig create required labels or create the configured lifecycle labels manually.") : check("task-labels", "GitHub issue labels", ready === true ? "pass" : "warn", JSON.stringify(labels).slice(0, 180), "Confirm required Rig lifecycle labels exist."));
|
|
@@ -5280,6 +5453,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5280
5453
|
checks.push(check("task-labels", "GitHub issue labels", "warn", errorMessage(error), "Run `rig init`/`rig doctor` after label setup is wired on the server."));
|
|
5281
5454
|
}
|
|
5282
5455
|
try {
|
|
5456
|
+
progress("Checking task projection\u2026");
|
|
5283
5457
|
const projection = await request("/api/workspace/task-projection");
|
|
5284
5458
|
checks.push(check("task-projection", "task projection", "pass", JSON.stringify(projection).slice(0, 180)));
|
|
5285
5459
|
} catch (error) {
|
|
@@ -5288,6 +5462,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5288
5462
|
const slug = projectStatusSlug(projectRoot, config);
|
|
5289
5463
|
if (slug) {
|
|
5290
5464
|
try {
|
|
5465
|
+
progress("Checking server project checkout\u2026");
|
|
5291
5466
|
const project = await request(`/api/projects/${encodeURIComponent(slug)}`);
|
|
5292
5467
|
checks.push(check("remote-checkout", "server project checkout", "pass", JSON.stringify(project).slice(0, 180)));
|
|
5293
5468
|
} catch (error) {
|
|
@@ -5302,6 +5477,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5302
5477
|
}
|
|
5303
5478
|
checks.push(githubProjectsCheck(config));
|
|
5304
5479
|
checks.push(prMergeCheck(config));
|
|
5480
|
+
progress("Checking Pi installation\u2026");
|
|
5305
5481
|
const piChecks = await (options.piChecks ?? (() => buildPiSetupChecks()))().catch((error) => [{
|
|
5306
5482
|
ok: false,
|
|
5307
5483
|
label: "pi/pi-rig checks",
|
|
@@ -6224,7 +6400,7 @@ async function executeGithub(context, args) {
|
|
|
6224
6400
|
case "status": {
|
|
6225
6401
|
if (rest.length > 0)
|
|
6226
6402
|
throw new CliError("Usage: rig github auth status", 1);
|
|
6227
|
-
const status = await getGitHubAuthStatusViaServer(context);
|
|
6403
|
+
const status = await withSpinner("Checking GitHub auth on the server\u2026", () => getGitHubAuthStatusViaServer(context), { outputMode: context.outputMode });
|
|
6228
6404
|
printPayload(context, status, `GitHub auth: ${status.authenticated ? "authenticated" : "unauthenticated"}`);
|
|
6229
6405
|
return { ok: true, group: "github", command: "auth status", details: status };
|
|
6230
6406
|
}
|
|
@@ -6235,14 +6411,15 @@ async function executeGithub(context, args) {
|
|
|
6235
6411
|
const token = parsed.value?.trim();
|
|
6236
6412
|
if (!token)
|
|
6237
6413
|
throw new CliError("Missing --token value.", 1, { hint: "Re-run as `rig github auth token --token <token>`." });
|
|
6238
|
-
const result = await postGitHubTokenViaServer(context, token);
|
|
6414
|
+
const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token), { outputMode: context.outputMode });
|
|
6239
6415
|
printPayload(context, result, "GitHub token stored on the selected Rig server.");
|
|
6240
6416
|
return { ok: true, group: "github", command: "auth token", details: result };
|
|
6241
6417
|
}
|
|
6242
6418
|
case "import-gh": {
|
|
6243
6419
|
if (rest.length > 0)
|
|
6244
6420
|
throw new CliError("Usage: rig github auth import-gh", 1);
|
|
6245
|
-
const
|
|
6421
|
+
const importedToken = readGhToken();
|
|
6422
|
+
const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken), { outputMode: context.outputMode });
|
|
6246
6423
|
printPayload(context, result, "GitHub token imported from gh and stored on the selected Rig server.");
|
|
6247
6424
|
return { ok: true, group: "github", command: "auth import-gh", details: result };
|
|
6248
6425
|
}
|
|
@@ -6255,7 +6432,7 @@ async function executeGithub(context, args) {
|
|
|
6255
6432
|
init_runner();
|
|
6256
6433
|
async function executeDoctor(context, args) {
|
|
6257
6434
|
requireNoExtraArgs(args, "rig doctor");
|
|
6258
|
-
const checks = await runRigDoctorChecks({ projectRoot: context.projectRoot });
|
|
6435
|
+
const checks = await withSpinner("Running doctor checks\u2026", (update) => runRigDoctorChecks({ projectRoot: context.projectRoot, onProgress: update }), { outputMode: context.outputMode });
|
|
6259
6436
|
if (context.outputMode === "text") {
|
|
6260
6437
|
console.log(formatDoctorChecks(checks));
|
|
6261
6438
|
}
|
|
@@ -6562,13 +6739,19 @@ async function executeInspect(context, args) {
|
|
|
6562
6739
|
const requiredTask = requireTask(task, "rig inspect logs --task <task-id>");
|
|
6563
6740
|
const latestRun = listAuthorityRuns(context.projectRoot).map((entry) => readAuthorityRun3(context.projectRoot, entry.runId)).filter((run) => Boolean(run)).filter((run) => run.taskId === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
|
|
6564
6741
|
if (!latestRun) {
|
|
6565
|
-
const
|
|
6566
|
-
|
|
6567
|
-
|
|
6742
|
+
const fallback = await withSpinner(`Finding runs for ${requiredTask} on the server\u2026`, async (update) => {
|
|
6743
|
+
const serverRuns = await listRunsViaServer(context, { limit: 200 }).catch(() => []);
|
|
6744
|
+
const serverRun = serverRuns.filter((run) => String(run.taskId ?? "") === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
|
|
6745
|
+
if (!serverRun || typeof serverRun.runId !== "string")
|
|
6746
|
+
return null;
|
|
6747
|
+
update(`Reading logs for run ${serverRun.runId}\u2026`);
|
|
6748
|
+
const page = await getRunLogsViaServer(context, serverRun.runId, { limit: 500 });
|
|
6749
|
+
return { runId: serverRun.runId, page };
|
|
6750
|
+
}, { outputMode: context.outputMode });
|
|
6751
|
+
if (!fallback) {
|
|
6568
6752
|
throw new CliError(`No runs found for ${requiredTask} (local or on the selected server).`, 1, { hint: "Start one with `rig task run --task <id>`, or check `rig run list`." });
|
|
6569
6753
|
}
|
|
6570
|
-
const
|
|
6571
|
-
const entries = Array.isArray(page.entries) ? page.entries : [];
|
|
6754
|
+
const entries = Array.isArray(fallback.page.entries) ? fallback.page.entries : [];
|
|
6572
6755
|
if (context.outputMode === "text") {
|
|
6573
6756
|
for (const entry of entries) {
|
|
6574
6757
|
const record = entry && typeof entry === "object" ? entry : {};
|
|
@@ -6577,9 +6760,9 @@ async function executeInspect(context, args) {
|
|
|
6577
6760
|
console.log([title, detail].filter(Boolean).join(" \u2014 "));
|
|
6578
6761
|
}
|
|
6579
6762
|
if (entries.length === 0)
|
|
6580
|
-
console.log(`(no log entries for run ${
|
|
6763
|
+
console.log(`(no log entries for run ${fallback.runId})`);
|
|
6581
6764
|
}
|
|
6582
|
-
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId:
|
|
6765
|
+
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: fallback.runId, source: "server", entries } };
|
|
6583
6766
|
}
|
|
6584
6767
|
const logsPath = resolve20(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
6585
6768
|
if (!existsSync13(logsPath)) {
|
|
@@ -6637,7 +6820,7 @@ async function executeInspect(context, args) {
|
|
|
6637
6820
|
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
6638
6821
|
requireNoExtraArgs(remaining, "rig inspect diff [--task <task-id>]");
|
|
6639
6822
|
if (task) {
|
|
6640
|
-
const files = changedFilesForTask(context.projectRoot, task, false);
|
|
6823
|
+
const files = await withSpinner(`Computing changed files for ${task}\u2026`, async () => changedFilesForTask(context.projectRoot, task, false), { outputMode: context.outputMode });
|
|
6641
6824
|
for (const file of files) {
|
|
6642
6825
|
console.log(file);
|
|
6643
6826
|
}
|
|
@@ -7318,8 +7501,6 @@ import {
|
|
|
7318
7501
|
deleteRunState,
|
|
7319
7502
|
listOpenEpics,
|
|
7320
7503
|
resolveDefaultEpic,
|
|
7321
|
-
runResume,
|
|
7322
|
-
runRestart,
|
|
7323
7504
|
runStatus,
|
|
7324
7505
|
runStop,
|
|
7325
7506
|
startRun,
|
|
@@ -7725,7 +7906,12 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
7725
7906
|
};
|
|
7726
7907
|
let detached = false;
|
|
7727
7908
|
try {
|
|
7728
|
-
await runPiMain([
|
|
7909
|
+
await runPiMain([
|
|
7910
|
+
"--no-extensions",
|
|
7911
|
+
"--no-skills",
|
|
7912
|
+
"--no-prompt-templates",
|
|
7913
|
+
"--no-context-files"
|
|
7914
|
+
], {
|
|
7729
7915
|
extensionFactories: [piRigExtensionFactory]
|
|
7730
7916
|
});
|
|
7731
7917
|
detached = true;
|
|
@@ -7790,8 +7976,9 @@ async function readOperatorSnapshot(context, runId, options = {}) {
|
|
|
7790
7976
|
}
|
|
7791
7977
|
async function attachRunOperatorView(context, input) {
|
|
7792
7978
|
let steered = false;
|
|
7793
|
-
|
|
7794
|
-
|
|
7979
|
+
const attachMessage = input.message?.trim();
|
|
7980
|
+
if (attachMessage) {
|
|
7981
|
+
await withSpinner("Queueing steering message\u2026", () => sendRunPiPromptViaServer(context, input.runId, attachMessage, "steer").catch(() => steerRunViaServer(context, input.runId, attachMessage)), { outputMode: context.outputMode });
|
|
7795
7982
|
steered = true;
|
|
7796
7983
|
}
|
|
7797
7984
|
if (input.follow && !input.once && input.interactive !== false && context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
@@ -7801,7 +7988,7 @@ async function attachRunOperatorView(context, input) {
|
|
|
7801
7988
|
});
|
|
7802
7989
|
}
|
|
7803
7990
|
const surface = createOperatorSurface({ interactive: input.interactive !== false });
|
|
7804
|
-
let snapshot = await readOperatorSnapshot(context, input.runId);
|
|
7991
|
+
let snapshot = await withSpinner(`Connecting to run ${input.runId}\u2026`, () => readOperatorSnapshot(context, input.runId), { outputMode: context.outputMode });
|
|
7805
7992
|
if (context.outputMode === "text") {
|
|
7806
7993
|
surface.renderSnapshot(snapshot);
|
|
7807
7994
|
surface.renderTimeline(snapshot.timeline);
|
|
@@ -7932,7 +8119,7 @@ async function executeRun(context, args) {
|
|
|
7932
8119
|
switch (command) {
|
|
7933
8120
|
case "list": {
|
|
7934
8121
|
requireNoExtraArgs(rest, "rig run list");
|
|
7935
|
-
const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
|
|
8122
|
+
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 });
|
|
7936
8123
|
if (context.outputMode === "text") {
|
|
7937
8124
|
printFormattedOutput(formatRunList(runs, { source }));
|
|
7938
8125
|
await printPendingInboxFooter(context);
|
|
@@ -8005,7 +8192,7 @@ async function executeRun(context, args) {
|
|
|
8005
8192
|
if (!runId) {
|
|
8006
8193
|
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>`." });
|
|
8007
8194
|
}
|
|
8008
|
-
const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, runId).catch(() => ({})));
|
|
8195
|
+
const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await withSpinner(`Reading run ${runId} from server\u2026`, () => getRunDetailsViaServer(context, runId).catch(() => ({})), { outputMode: context.outputMode }));
|
|
8009
8196
|
if (!record) {
|
|
8010
8197
|
throw new CliError(`Run not found: ${runId}`, 2, { hint: "Run `rig run list` to see recorded runs." });
|
|
8011
8198
|
}
|
|
@@ -8026,7 +8213,8 @@ async function executeRun(context, args) {
|
|
|
8026
8213
|
}
|
|
8027
8214
|
const renderer = createPiRunStreamRenderer();
|
|
8028
8215
|
let cursor = null;
|
|
8029
|
-
const
|
|
8216
|
+
const timelineRunId = run.value;
|
|
8217
|
+
const page = await withSpinner(`Reading timeline for ${timelineRunId}\u2026`, () => getRunTimelineViaServer(context, timelineRunId, { limit: 500 }), { outputMode: context.outputMode });
|
|
8030
8218
|
const events = Array.isArray(page.entries) ? page.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
8031
8219
|
cursor = typeof page.nextCursor === "string" ? page.nextCursor : null;
|
|
8032
8220
|
if (context.outputMode === "text") {
|
|
@@ -8103,8 +8291,9 @@ async function executeRun(context, args) {
|
|
|
8103
8291
|
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`." });
|
|
8104
8292
|
}
|
|
8105
8293
|
let steered = false;
|
|
8106
|
-
|
|
8107
|
-
|
|
8294
|
+
const steerMessage = messageOption.value?.trim();
|
|
8295
|
+
if (steerMessage) {
|
|
8296
|
+
await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, steerMessage), { outputMode: context.outputMode });
|
|
8108
8297
|
steered = true;
|
|
8109
8298
|
}
|
|
8110
8299
|
const attached = await attachRunOperatorView(context, {
|
|
@@ -8124,7 +8313,7 @@ async function executeRun(context, args) {
|
|
|
8124
8313
|
}
|
|
8125
8314
|
return { ok: true, group: "run", command };
|
|
8126
8315
|
}
|
|
8127
|
-
const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
|
|
8316
|
+
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);
|
|
8128
8317
|
const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
8129
8318
|
const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
8130
8319
|
if (context.outputMode === "text") {
|
|
@@ -8213,7 +8402,7 @@ async function executeRun(context, args) {
|
|
|
8213
8402
|
}
|
|
8214
8403
|
return { ok: true, group: "run", command };
|
|
8215
8404
|
}
|
|
8216
|
-
const resumed = await
|
|
8405
|
+
const resumed = await withSpinner(targetRunId ? `Resuming run ${targetRunId}\u2026` : "Resuming latest resumable run\u2026", () => resumeRunViaServer(context, targetRunId, { restart: false }), { outputMode: context.outputMode });
|
|
8217
8406
|
if (context.outputMode === "text") {
|
|
8218
8407
|
console.log(`Resumed run: ${resumed.runId}`);
|
|
8219
8408
|
}
|
|
@@ -8232,7 +8421,7 @@ async function executeRun(context, args) {
|
|
|
8232
8421
|
}
|
|
8233
8422
|
return { ok: true, group: "run", command };
|
|
8234
8423
|
}
|
|
8235
|
-
const restarted = await
|
|
8424
|
+
const restarted = await withSpinner(targetRunId ? `Restarting run ${targetRunId}\u2026` : "Restarting latest run\u2026", () => resumeRunViaServer(context, targetRunId, { restart: true }), { outputMode: context.outputMode });
|
|
8236
8425
|
if (context.outputMode === "text") {
|
|
8237
8426
|
console.log(`Restarted run: ${restarted.runId}`);
|
|
8238
8427
|
}
|
|
@@ -8259,7 +8448,8 @@ async function executeRun(context, args) {
|
|
|
8259
8448
|
}
|
|
8260
8449
|
return { ok: true, group: "run", command, details: { runId, dryRun: true } };
|
|
8261
8450
|
}
|
|
8262
|
-
|
|
8451
|
+
const trimmedMessage = message2.trim();
|
|
8452
|
+
await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, trimmedMessage), { outputMode: context.outputMode });
|
|
8263
8453
|
if (context.outputMode === "text") {
|
|
8264
8454
|
console.log(`Steering message queued for ${runId}.`);
|
|
8265
8455
|
}
|
|
@@ -8280,7 +8470,7 @@ async function executeRun(context, args) {
|
|
|
8280
8470
|
};
|
|
8281
8471
|
}
|
|
8282
8472
|
if (runId) {
|
|
8283
|
-
const stopped = await stopRunViaServer(context, runId);
|
|
8473
|
+
const stopped = await withSpinner(`Requesting stop for ${runId}\u2026`, () => stopRunViaServer(context, runId), { outputMode: context.outputMode });
|
|
8284
8474
|
if (context.outputMode === "text")
|
|
8285
8475
|
console.log(`Stop requested: ${runId}`);
|
|
8286
8476
|
return { ok: true, group: "run", command, details: stopped };
|
|
@@ -8526,12 +8716,12 @@ async function executeServer(context, args, options) {
|
|
|
8526
8716
|
|
|
8527
8717
|
// packages/cli/src/commands/stats.ts
|
|
8528
8718
|
init_runner();
|
|
8529
|
-
import
|
|
8719
|
+
import pc6 from "picocolors";
|
|
8530
8720
|
import { computeRigStats } from "@rig/runtime/control-plane/native/run-stats";
|
|
8531
8721
|
|
|
8532
8722
|
// packages/cli/src/commands/_help-catalog.ts
|
|
8533
8723
|
import { intro as intro3, log as log4, note as note4, outro as outro3 } from "@clack/prompts";
|
|
8534
|
-
import
|
|
8724
|
+
import pc5 from "picocolors";
|
|
8535
8725
|
var TOP_LEVEL_SECTIONS = [
|
|
8536
8726
|
{
|
|
8537
8727
|
title: "Start here",
|
|
@@ -8819,13 +9009,13 @@ var ADVANCED_COMMANDS = [
|
|
|
8819
9009
|
];
|
|
8820
9010
|
var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
|
|
8821
9011
|
function heading(title) {
|
|
8822
|
-
return
|
|
9012
|
+
return pc5.bold(pc5.cyan(title));
|
|
8823
9013
|
}
|
|
8824
9014
|
function renderRigBanner(version) {
|
|
8825
|
-
const m = (s) =>
|
|
8826
|
-
const c = (s) =>
|
|
8827
|
-
const y = (s) =>
|
|
8828
|
-
const d = (s) =>
|
|
9015
|
+
const m = (s) => pc5.bold(pc5.magenta(s));
|
|
9016
|
+
const c = (s) => pc5.bold(pc5.cyan(s));
|
|
9017
|
+
const y = (s) => pc5.yellow(s);
|
|
9018
|
+
const d = (s) => pc5.dim(s);
|
|
8829
9019
|
const lines = [
|
|
8830
9020
|
m(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + d(" \u2591\u2592\u2593\u2588 "),
|
|
8831
9021
|
m(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ") + d("\u2593\u2592\u2591"),
|
|
@@ -8834,7 +9024,7 @@ function renderRigBanner(version) {
|
|
|
8834
9024
|
y(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + d(" \u2592\u2591"),
|
|
8835
9025
|
y(" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "),
|
|
8836
9026
|
"",
|
|
8837
|
-
` ${c("\u25E2\u25E4")} ${
|
|
9027
|
+
` ${c("\u25E2\u25E4")} ${pc5.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
|
|
8838
9028
|
version ? ` ${d(`v${version} \xB7 jack in: rig task run --next`)}` : ` ${d("jack in: rig task run --next")}`
|
|
8839
9029
|
];
|
|
8840
9030
|
return lines.join(`
|
|
@@ -8842,7 +9032,7 @@ function renderRigBanner(version) {
|
|
|
8842
9032
|
}
|
|
8843
9033
|
function commandLine(command, description) {
|
|
8844
9034
|
const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
|
|
8845
|
-
return `${
|
|
9035
|
+
return `${pc5.dim("\u2502")} ${pc5.bold(commandColumn)} ${description}`;
|
|
8846
9036
|
}
|
|
8847
9037
|
function renderCommandBlock(commands) {
|
|
8848
9038
|
return commands.map((entry) => commandLine(entry.command, entry.description)).join(`
|
|
@@ -8852,37 +9042,37 @@ function renderGroup(group) {
|
|
|
8852
9042
|
const lines = [
|
|
8853
9043
|
`${heading(`rig ${group.name}`)} \u2014 ${group.summary}`,
|
|
8854
9044
|
"",
|
|
8855
|
-
|
|
9045
|
+
pc5.bold("Usage"),
|
|
8856
9046
|
...group.usage.map((line) => ` ${line}`),
|
|
8857
9047
|
"",
|
|
8858
|
-
|
|
9048
|
+
pc5.bold("Commands"),
|
|
8859
9049
|
...group.commands.map((entry) => commandLine(entry.command, entry.description))
|
|
8860
9050
|
];
|
|
8861
9051
|
if (group.examples?.length) {
|
|
8862
|
-
lines.push("",
|
|
9052
|
+
lines.push("", pc5.bold("Examples"), ...group.examples.map((line) => ` ${pc5.dim("$")} ${line}`));
|
|
8863
9053
|
}
|
|
8864
9054
|
if (group.next?.length) {
|
|
8865
|
-
lines.push("",
|
|
9055
|
+
lines.push("", pc5.bold("Next steps"), ...group.next.map((line) => ` ${pc5.dim("\u203A")} ${line}`));
|
|
8866
9056
|
}
|
|
8867
9057
|
if (group.advanced?.length) {
|
|
8868
|
-
lines.push("",
|
|
9058
|
+
lines.push("", pc5.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc5.dim("\u203A")} ${line}`));
|
|
8869
9059
|
}
|
|
8870
9060
|
return lines.join(`
|
|
8871
9061
|
`);
|
|
8872
9062
|
}
|
|
8873
9063
|
function renderTopLevelHelp() {
|
|
8874
9064
|
return [
|
|
8875
|
-
`${heading("rig")} ${
|
|
8876
|
-
|
|
9065
|
+
`${heading("rig")} ${pc5.dim("\u2014 server-owned task/run control plane for Pi-backed engineering work")}`,
|
|
9066
|
+
pc5.dim("Current path: select a server, choose a task, submit a run, attach with native Pi, clear inbox gates."),
|
|
8877
9067
|
"",
|
|
8878
9068
|
...TOP_LEVEL_SECTIONS.flatMap((section) => [
|
|
8879
|
-
`${
|
|
9069
|
+
`${pc5.bold(pc5.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc5.dim(section.subtitle)}`,
|
|
8880
9070
|
renderCommandBlock(section.commands),
|
|
8881
9071
|
""
|
|
8882
9072
|
]),
|
|
8883
|
-
|
|
9073
|
+
pc5.dim("More: `rig help --advanced` for dev/compatibility commands; `rig <group> --help` for rich per-group help; `rig --version` for the installed version."),
|
|
8884
9074
|
"",
|
|
8885
|
-
|
|
9075
|
+
pc5.bold("Global options"),
|
|
8886
9076
|
commandLine("--project <path>", "Use a project root instead of auto-discovery."),
|
|
8887
9077
|
commandLine("--json", "Emit structured output for scripts/agents."),
|
|
8888
9078
|
commandLine("--dry-run", "Print the command plan without mutating state.")
|
|
@@ -8893,16 +9083,16 @@ function renderAdvancedHelp() {
|
|
|
8893
9083
|
return [
|
|
8894
9084
|
`${heading("rig advanced")} \u2014 compatibility, diagnostics, and internal surfaces`,
|
|
8895
9085
|
"",
|
|
8896
|
-
|
|
9086
|
+
pc5.bold("Primary groups"),
|
|
8897
9087
|
" init, server, task, run, inbox, repo, plugin, inspect, stats, doctor, github",
|
|
8898
9088
|
"",
|
|
8899
|
-
|
|
9089
|
+
pc5.bold("Advanced commands"),
|
|
8900
9090
|
...ADVANCED_COMMANDS.map((entry) => commandLine(entry.command, entry.description)),
|
|
8901
9091
|
"",
|
|
8902
|
-
|
|
9092
|
+
pc5.bold("Advanced groups"),
|
|
8903
9093
|
...ADVANCED_GROUPS.map((group) => commandLine(group.name, group.summary)),
|
|
8904
9094
|
"",
|
|
8905
|
-
|
|
9095
|
+
pc5.dim("All groups remain callable. Prefer `rig server`, `rig task`, `rig run`, and `rig inbox` for day-to-day work.")
|
|
8906
9096
|
].join(`
|
|
8907
9097
|
`);
|
|
8908
9098
|
}
|
|
@@ -9050,11 +9240,11 @@ function formatStatsReport(stats) {
|
|
|
9050
9240
|
const keyWidth = Math.max(...rows.map(([key]) => key.length));
|
|
9051
9241
|
const lines = [
|
|
9052
9242
|
formatSection("Fleet stats", window),
|
|
9053
|
-
...rows.map(([key, value]) => `${
|
|
9243
|
+
...rows.map(([key, value]) => `${pc6.dim("\u2502")} ${pc6.dim(key.padEnd(keyWidth + 2))} ${value}`)
|
|
9054
9244
|
];
|
|
9055
9245
|
const otherStatuses = Object.entries(stats.statusCounts).filter(([status]) => !["completed", "failed", "needs-attention"].includes(status)).sort(([, left], [, right]) => right - left);
|
|
9056
9246
|
if (otherStatuses.length > 0) {
|
|
9057
|
-
lines.push(`${
|
|
9247
|
+
lines.push(`${pc6.dim("\u2502")} ${pc6.dim("other".padEnd(keyWidth + 2))} ${otherStatuses.map(([status, count]) => `${status}:${count}`).join(" ")}`);
|
|
9058
9248
|
}
|
|
9059
9249
|
lines.push("", ...formatNextSteps([
|
|
9060
9250
|
"Inspect a run: `rig run list` then `rig run show <run-id>`",
|
|
@@ -9073,7 +9263,8 @@ async function executeStats(context, args) {
|
|
|
9073
9263
|
const sinceResult = takeOption(pending, "--since");
|
|
9074
9264
|
requireNoExtraArgs(sinceResult.rest, "rig stats [show] [--since <7d|30d|ISO date>]");
|
|
9075
9265
|
const since = parseSinceOption(sinceResult.value);
|
|
9076
|
-
const
|
|
9266
|
+
const remoteStats = isRemoteConnectionSelected(context.projectRoot);
|
|
9267
|
+
const stats = await withSpinner(remoteStats ? "Computing fleet stats on the server\u2026" : "Scanning local run state\u2026", async () => remoteStats ? await requestServerJson(context, `/api/stats${since ? `?since=${encodeURIComponent(since.toISOString())}` : ""}`) : computeRigStats(context.projectRoot, { since }), { outputMode: context.outputMode });
|
|
9077
9268
|
if (context.outputMode === "text") {
|
|
9078
9269
|
printFormattedOutput(formatStatsReport(stats));
|
|
9079
9270
|
}
|
|
@@ -9328,7 +9519,7 @@ async function executeTask(context, args, options) {
|
|
|
9328
9519
|
pending = rawResult.rest;
|
|
9329
9520
|
const { filters, rest: remaining } = parseTaskFilters(pending);
|
|
9330
9521
|
requireNoExtraArgs(remaining, "rig task list [--raw] [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
|
|
9331
|
-
const tasks = await listWorkspaceTasksViaServer(context, filters);
|
|
9522
|
+
const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filters), { outputMode: context.outputMode });
|
|
9332
9523
|
if (context.outputMode === "text") {
|
|
9333
9524
|
const renderedTasks = rawResult.value ? tasks.map((task) => summarizeTask(task, { raw: true })) : tasks.map((task) => summarizeTask(task));
|
|
9334
9525
|
printFormattedOutput(formatTaskList(renderedTasks, { raw: rawResult.value }));
|
|
@@ -9352,7 +9543,7 @@ async function executeTask(context, args, options) {
|
|
|
9352
9543
|
const taskId3 = normalizeTaskRunTaskId(taskOption.value ?? positional);
|
|
9353
9544
|
if (!taskId3)
|
|
9354
9545
|
throw new CliError("task show requires a task id.", 2, { hint: "Run `rig task list` to find ids, then `rig task show <id>`." });
|
|
9355
|
-
const task = await getWorkspaceTaskViaServer(context, taskId3);
|
|
9546
|
+
const task = await withSpinner(`Reading task ${taskId3} from server\u2026`, () => getWorkspaceTaskViaServer(context, taskId3), { outputMode: context.outputMode });
|
|
9356
9547
|
if (!task)
|
|
9357
9548
|
throw new CliError(`Task not found: ${taskId3}`, 3, { hint: "Run `rig task list` to see available tasks." });
|
|
9358
9549
|
const summary = summarizeTask(task, { raw: true });
|
|
@@ -9364,7 +9555,7 @@ async function executeTask(context, args, options) {
|
|
|
9364
9555
|
case "next": {
|
|
9365
9556
|
const { filters, rest: remaining } = parseTaskFilters(rest);
|
|
9366
9557
|
requireNoExtraArgs(remaining, "rig task next [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
|
|
9367
|
-
const selected = await selectNextWorkspaceTaskViaServer(context, filters);
|
|
9558
|
+
const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filters), { outputMode: context.outputMode });
|
|
9368
9559
|
if (context.outputMode === "text") {
|
|
9369
9560
|
if (selected.task) {
|
|
9370
9561
|
printFormattedOutput(formatTaskCard(summarizeTask(selected.task, { raw: true }), { title: "Selected task", selected: true }));
|
|
@@ -9514,7 +9705,7 @@ async function executeTask(context, args, options) {
|
|
|
9514
9705
|
let selectedTask = null;
|
|
9515
9706
|
let selectedTaskId = normalizeTaskRunTaskId(taskResult.value) ?? positionalTaskId;
|
|
9516
9707
|
if (nextResult.value) {
|
|
9517
|
-
const selected = await selectNextWorkspaceTaskViaServer(context, filterResult.filters);
|
|
9708
|
+
const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filterResult.filters), { outputMode: context.outputMode });
|
|
9518
9709
|
selectedTask = selected.task;
|
|
9519
9710
|
selectedTaskId = selected.task ? readTaskId(selected.task) : null;
|
|
9520
9711
|
if (!selectedTaskId) {
|
|
@@ -9525,7 +9716,7 @@ async function executeTask(context, args, options) {
|
|
|
9525
9716
|
if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
9526
9717
|
throw new CliError("task run requires an interactive terminal to pick a task; pass --next, --task <id>, or --initial-prompt/--title for an ad hoc run.", 2);
|
|
9527
9718
|
}
|
|
9528
|
-
const tasks = await listWorkspaceTasksViaServer(context, filterResult.filters);
|
|
9719
|
+
const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filterResult.filters), { outputMode: context.outputMode });
|
|
9529
9720
|
selectedTask = await selectTaskWithTextPicker(tasks);
|
|
9530
9721
|
selectedTaskId = selectedTask ? readTaskId(selectedTask) : null;
|
|
9531
9722
|
if (!selectedTaskId) {
|
|
@@ -9535,13 +9726,13 @@ async function executeTask(context, args, options) {
|
|
|
9535
9726
|
await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
|
|
9536
9727
|
const projectDefaults = await loadTaskRunProjectDefaults(context.projectRoot);
|
|
9537
9728
|
const runtimeAdapter = normalizeRuntimeAdapter(runtimeAdapterResult.value ?? projectDefaults.runtimeAdapter);
|
|
9538
|
-
await runFastTaskRunPreflight(context, {
|
|
9729
|
+
await withSpinner("Running task-run preflight\u2026", () => runFastTaskRunPreflight(context, {
|
|
9539
9730
|
taskId: selectedTaskId,
|
|
9540
9731
|
runtimeAdapter
|
|
9541
|
-
});
|
|
9732
|
+
}), { outputMode: context.outputMode });
|
|
9542
9733
|
const dirtyBaseline = await resolveDirtyBaselineForTaskRun(context, dirtyBaselineResult.value);
|
|
9543
9734
|
const prMode = noPrResult.value ? "off" : normalizePrMode(prResult.value) ?? projectDefaults.prMode;
|
|
9544
|
-
const submitted = await submitTaskRunViaServer(context, {
|
|
9735
|
+
const submitted = await withSpinner("Dispatching run\u2026", () => submitTaskRunViaServer(context, {
|
|
9545
9736
|
runId: context.runId,
|
|
9546
9737
|
taskId: selectedTaskId ?? undefined,
|
|
9547
9738
|
title: titleResult.value ?? undefined,
|
|
@@ -9552,7 +9743,7 @@ async function executeTask(context, args, options) {
|
|
|
9552
9743
|
initialPrompt: initialPromptResult.value ?? undefined,
|
|
9553
9744
|
baselineMode: dirtyBaseline.mode,
|
|
9554
9745
|
prMode
|
|
9555
|
-
});
|
|
9746
|
+
}), { outputMode: context.outputMode });
|
|
9556
9747
|
let attachDetails = null;
|
|
9557
9748
|
if (!detachResult.value && context.outputMode === "text") {
|
|
9558
9749
|
printFormattedOutput(formatSubmittedRun({
|
|
@@ -11730,7 +11921,7 @@ async function executeSetup(context, args) {
|
|
|
11730
11921
|
case "check":
|
|
11731
11922
|
requireNoExtraArgs(rest, `rig setup ${command}`);
|
|
11732
11923
|
{
|
|
11733
|
-
const checks = await withMutedConsole(context.outputMode === "json", () => runSetupCheck(context.projectRoot));
|
|
11924
|
+
const checks = await withMutedConsole(context.outputMode === "json", () => runSetupCheck(context.projectRoot, context.outputMode));
|
|
11734
11925
|
return { ok: true, group: "setup", command, details: { checks, failures: countDoctorFailures(checks) } };
|
|
11735
11926
|
}
|
|
11736
11927
|
case "setup":
|
|
@@ -11739,7 +11930,7 @@ async function executeSetup(context, args) {
|
|
|
11739
11930
|
return { ok: true, group: "setup", command };
|
|
11740
11931
|
case "preflight":
|
|
11741
11932
|
requireNoExtraArgs(rest, "rig setup preflight");
|
|
11742
|
-
await withMutedConsole(context.outputMode === "json", () => runSetupPreflight(context.projectRoot));
|
|
11933
|
+
await withMutedConsole(context.outputMode === "json", () => runSetupPreflight(context.projectRoot, context.outputMode));
|
|
11743
11934
|
return { ok: true, group: "setup", command };
|
|
11744
11935
|
default:
|
|
11745
11936
|
throw new CliError(`Unknown setup command: ${command}`, 1, { hint: "Run `rig setup --help` \u2014 commands are bootstrap|check|preflight." });
|
|
@@ -11760,8 +11951,8 @@ function runSetupInit(projectRoot) {
|
|
|
11760
11951
|
}
|
|
11761
11952
|
console.log("Harness directories ready.");
|
|
11762
11953
|
}
|
|
11763
|
-
async function runSetupCheck(projectRoot) {
|
|
11764
|
-
const doctorChecks = await runRigDoctorChecks({ projectRoot });
|
|
11954
|
+
async function runSetupCheck(projectRoot, outputMode = "text") {
|
|
11955
|
+
const doctorChecks = await withSpinner("Running setup checks\u2026", (update) => runRigDoctorChecks({ projectRoot, onProgress: update }), { outputMode });
|
|
11765
11956
|
console.log(formatDoctorChecks(doctorChecks));
|
|
11766
11957
|
const failures = countDoctorFailures(doctorChecks);
|
|
11767
11958
|
if (failures > 0) {
|
|
@@ -11769,8 +11960,8 @@ async function runSetupCheck(projectRoot) {
|
|
|
11769
11960
|
}
|
|
11770
11961
|
return doctorChecks;
|
|
11771
11962
|
}
|
|
11772
|
-
async function runSetupPreflight(projectRoot) {
|
|
11773
|
-
await runSetupCheck(projectRoot);
|
|
11963
|
+
async function runSetupPreflight(projectRoot, outputMode = "text") {
|
|
11964
|
+
await runSetupCheck(projectRoot, outputMode);
|
|
11774
11965
|
const validationRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
11775
11966
|
if (existsSync16(validationRoot)) {
|
|
11776
11967
|
const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|