@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/src/index.js
CHANGED
|
@@ -2929,6 +2929,15 @@ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
|
2929
2929
|
import { resolve as resolve11 } from "path";
|
|
2930
2930
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
2931
2931
|
var scopedGitHubBearerTokens = new Map;
|
|
2932
|
+
var serverPhaseListener = null;
|
|
2933
|
+
function setServerPhaseListener(listener) {
|
|
2934
|
+
const previous = serverPhaseListener;
|
|
2935
|
+
serverPhaseListener = listener;
|
|
2936
|
+
return previous;
|
|
2937
|
+
}
|
|
2938
|
+
function reportServerPhase(label) {
|
|
2939
|
+
serverPhaseListener?.(label);
|
|
2940
|
+
}
|
|
2932
2941
|
function cleanToken(value) {
|
|
2933
2942
|
const trimmed = value?.trim();
|
|
2934
2943
|
return trimmed ? trimmed : null;
|
|
@@ -2975,6 +2984,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
2975
2984
|
try {
|
|
2976
2985
|
const selected = resolveSelectedConnection(projectRoot);
|
|
2977
2986
|
if (selected?.connection.kind === "remote") {
|
|
2987
|
+
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
2978
2988
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
2979
2989
|
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
2980
2990
|
return {
|
|
@@ -2984,6 +2994,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
2984
2994
|
serverProjectRoot
|
|
2985
2995
|
};
|
|
2986
2996
|
}
|
|
2997
|
+
reportServerPhase("Starting local Rig server\u2026");
|
|
2987
2998
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
2988
2999
|
return {
|
|
2989
3000
|
baseUrl: connection.baseUrl,
|
|
@@ -3100,6 +3111,7 @@ async function requestServerJson(context, pathname, init = {}) {
|
|
|
3100
3111
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
3101
3112
|
if (server.serverProjectRoot)
|
|
3102
3113
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
3114
|
+
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
3103
3115
|
let response;
|
|
3104
3116
|
try {
|
|
3105
3117
|
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
@@ -3277,6 +3289,38 @@ async function updateWorkspaceTaskViaServer(context, input) {
|
|
|
3277
3289
|
});
|
|
3278
3290
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
|
|
3279
3291
|
}
|
|
3292
|
+
var RESUMABLE_RUN_STATUSES = new Set([
|
|
3293
|
+
"created",
|
|
3294
|
+
"preparing",
|
|
3295
|
+
"running",
|
|
3296
|
+
"validating",
|
|
3297
|
+
"reviewing",
|
|
3298
|
+
"stopped",
|
|
3299
|
+
"failed",
|
|
3300
|
+
"needs-attention",
|
|
3301
|
+
"needs_attention"
|
|
3302
|
+
]);
|
|
3303
|
+
async function resumeRunViaServer(context, runId, options) {
|
|
3304
|
+
let targetRunId = runId?.trim() || null;
|
|
3305
|
+
if (!targetRunId) {
|
|
3306
|
+
const candidates = (await listRunsViaServer(context)).filter((run) => RESUMABLE_RUN_STATUSES.has(String(run.status ?? ""))).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")));
|
|
3307
|
+
targetRunId = typeof candidates[0]?.runId === "string" ? candidates[0].runId : null;
|
|
3308
|
+
}
|
|
3309
|
+
if (!targetRunId) {
|
|
3310
|
+
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>`." });
|
|
3311
|
+
}
|
|
3312
|
+
const payload = await requestServerJson(context, "/api/runs/resume", {
|
|
3313
|
+
method: "POST",
|
|
3314
|
+
headers: { "content-type": "application/json" },
|
|
3315
|
+
body: JSON.stringify({ runId: targetRunId, createdAt: new Date().toISOString(), restart: options.restart })
|
|
3316
|
+
});
|
|
3317
|
+
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
3318
|
+
if (record.ok === false) {
|
|
3319
|
+
const message = typeof record.error === "string" && record.error.trim() ? record.error : "run resume failed";
|
|
3320
|
+
throw new CliError(`${options.restart ? "restart" : "resume"} failed for ${targetRunId}: ${message}`, 1);
|
|
3321
|
+
}
|
|
3322
|
+
return { ok: true, runId: targetRunId, ...record };
|
|
3323
|
+
}
|
|
3280
3324
|
async function stopRunViaServer(context, runId) {
|
|
3281
3325
|
const payload = await requestServerJson(context, "/api/runs/stop", {
|
|
3282
3326
|
method: "POST",
|
|
@@ -4620,6 +4664,127 @@ function formatConnectionStatus(selected, connections) {
|
|
|
4620
4664
|
`);
|
|
4621
4665
|
}
|
|
4622
4666
|
|
|
4667
|
+
// packages/cli/src/commands/_async-ui.ts
|
|
4668
|
+
import pc4 from "picocolors";
|
|
4669
|
+
|
|
4670
|
+
// packages/cli/src/commands/_spinner.ts
|
|
4671
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
4672
|
+
function createTtySpinner(input) {
|
|
4673
|
+
const output = input.output ?? process.stdout;
|
|
4674
|
+
const isTty = output.isTTY === true;
|
|
4675
|
+
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
4676
|
+
let label = input.label;
|
|
4677
|
+
let frame = 0;
|
|
4678
|
+
let paused = false;
|
|
4679
|
+
let stopped = false;
|
|
4680
|
+
let lastPrintedLabel = "";
|
|
4681
|
+
const render = () => {
|
|
4682
|
+
if (stopped || paused)
|
|
4683
|
+
return;
|
|
4684
|
+
if (!isTty) {
|
|
4685
|
+
if (label !== lastPrintedLabel) {
|
|
4686
|
+
output.write(`${label}
|
|
4687
|
+
`);
|
|
4688
|
+
lastPrintedLabel = label;
|
|
4689
|
+
}
|
|
4690
|
+
return;
|
|
4691
|
+
}
|
|
4692
|
+
frame = (frame + 1) % frames.length;
|
|
4693
|
+
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
4694
|
+
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
4695
|
+
};
|
|
4696
|
+
const clearLine = () => {
|
|
4697
|
+
if (isTty)
|
|
4698
|
+
output.write("\r\x1B[2K");
|
|
4699
|
+
};
|
|
4700
|
+
render();
|
|
4701
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
4702
|
+
return {
|
|
4703
|
+
setLabel(next) {
|
|
4704
|
+
label = next;
|
|
4705
|
+
render();
|
|
4706
|
+
},
|
|
4707
|
+
pause() {
|
|
4708
|
+
paused = true;
|
|
4709
|
+
clearLine();
|
|
4710
|
+
},
|
|
4711
|
+
resume() {
|
|
4712
|
+
if (stopped)
|
|
4713
|
+
return;
|
|
4714
|
+
paused = false;
|
|
4715
|
+
render();
|
|
4716
|
+
},
|
|
4717
|
+
stop(finalLine) {
|
|
4718
|
+
if (stopped)
|
|
4719
|
+
return;
|
|
4720
|
+
stopped = true;
|
|
4721
|
+
if (timer)
|
|
4722
|
+
clearInterval(timer);
|
|
4723
|
+
clearLine();
|
|
4724
|
+
if (finalLine)
|
|
4725
|
+
output.write(`${finalLine}
|
|
4726
|
+
`);
|
|
4727
|
+
}
|
|
4728
|
+
};
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4731
|
+
// packages/cli/src/commands/_async-ui.ts
|
|
4732
|
+
var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
|
|
4733
|
+
var DONE_SYMBOL = pc4.green("\u25C7");
|
|
4734
|
+
var FAIL_SYMBOL = pc4.red("\u25A0");
|
|
4735
|
+
var activeUpdate = null;
|
|
4736
|
+
async function withSpinner(label, work, options = {}) {
|
|
4737
|
+
if (options.outputMode === "json") {
|
|
4738
|
+
return work(() => {});
|
|
4739
|
+
}
|
|
4740
|
+
if (activeUpdate) {
|
|
4741
|
+
const outer = activeUpdate;
|
|
4742
|
+
outer(label);
|
|
4743
|
+
return work(outer);
|
|
4744
|
+
}
|
|
4745
|
+
const output = options.output ?? process.stderr;
|
|
4746
|
+
const isTty = output.isTTY === true;
|
|
4747
|
+
let lastLabel = label;
|
|
4748
|
+
if (!isTty) {
|
|
4749
|
+
output.write(`${label}
|
|
4750
|
+
`);
|
|
4751
|
+
const update2 = (next) => {
|
|
4752
|
+
lastLabel = next;
|
|
4753
|
+
};
|
|
4754
|
+
activeUpdate = update2;
|
|
4755
|
+
const previousListener2 = setServerPhaseListener(update2);
|
|
4756
|
+
try {
|
|
4757
|
+
return await work(update2);
|
|
4758
|
+
} finally {
|
|
4759
|
+
activeUpdate = null;
|
|
4760
|
+
setServerPhaseListener(previousListener2);
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
const spinner2 = createTtySpinner({
|
|
4764
|
+
label,
|
|
4765
|
+
output,
|
|
4766
|
+
frames: CLACK_SPINNER_FRAMES,
|
|
4767
|
+
styleFrame: (frame) => pc4.magenta(frame)
|
|
4768
|
+
});
|
|
4769
|
+
const update = (next) => {
|
|
4770
|
+
lastLabel = next;
|
|
4771
|
+
spinner2.setLabel(next);
|
|
4772
|
+
};
|
|
4773
|
+
activeUpdate = update;
|
|
4774
|
+
const previousListener = setServerPhaseListener(update);
|
|
4775
|
+
try {
|
|
4776
|
+
const result = await work(update);
|
|
4777
|
+
spinner2.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
|
|
4778
|
+
return result;
|
|
4779
|
+
} catch (error) {
|
|
4780
|
+
spinner2.stop(`${FAIL_SYMBOL} ${lastLabel}`);
|
|
4781
|
+
throw error;
|
|
4782
|
+
} finally {
|
|
4783
|
+
activeUpdate = null;
|
|
4784
|
+
setServerPhaseListener(previousListener);
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
|
|
4623
4788
|
// packages/cli/src/commands/inbox.ts
|
|
4624
4789
|
async function listInboxRecords(context, kind, filters) {
|
|
4625
4790
|
const params = new URLSearchParams;
|
|
@@ -4724,7 +4889,7 @@ async function executeInbox(context, args) {
|
|
|
4724
4889
|
const task = takeOption(pending, "--task");
|
|
4725
4890
|
pending = task.rest;
|
|
4726
4891
|
requireNoExtraArgs(pending, "rig inbox approvals [--run <id>] [--task <id>]");
|
|
4727
|
-
const approvals = await listInboxRecords(context, "approvals", { run: run.value, task: task.value });
|
|
4892
|
+
const approvals = await withSpinner("Reading approvals from server\u2026", () => listInboxRecords(context, "approvals", { run: run.value, task: task.value }), { outputMode: context.outputMode });
|
|
4728
4893
|
renderList(context, "approvals", approvals);
|
|
4729
4894
|
return { ok: true, group: "inbox", command, details: { approvals } };
|
|
4730
4895
|
}
|
|
@@ -4735,7 +4900,7 @@ async function executeInbox(context, args) {
|
|
|
4735
4900
|
const task = takeOption(pending, "--task");
|
|
4736
4901
|
pending = task.rest;
|
|
4737
4902
|
requireNoExtraArgs(pending, "rig inbox inputs [--run <id>] [--task <id>]");
|
|
4738
|
-
const requests = await listInboxRecords(context, "inputs", { run: run.value, task: task.value });
|
|
4903
|
+
const requests = await withSpinner("Reading input requests from server\u2026", () => listInboxRecords(context, "inputs", { run: run.value, task: task.value }), { outputMode: context.outputMode });
|
|
4739
4904
|
renderList(context, "inputs", requests);
|
|
4740
4905
|
return { ok: true, group: "inbox", command, details: { requests } };
|
|
4741
4906
|
}
|
|
@@ -4756,7 +4921,7 @@ async function executeInbox(context, args) {
|
|
|
4756
4921
|
if (decision.value !== "approve" && decision.value !== "reject") {
|
|
4757
4922
|
throw new CliError("decision must be approve or reject.", 1, { hint: "Re-run as `rig inbox approve --run <id> --request <id> --decision approve|reject`." });
|
|
4758
4923
|
}
|
|
4759
|
-
const result = await requestServerJson(context, "/api/inbox/approvals/resolve", {
|
|
4924
|
+
const result = await withSpinner(`Resolving approval ${request.value}\u2026`, () => requestServerJson(context, "/api/inbox/approvals/resolve", {
|
|
4760
4925
|
method: "POST",
|
|
4761
4926
|
headers: { "content-type": "application/json" },
|
|
4762
4927
|
body: JSON.stringify({
|
|
@@ -4765,7 +4930,7 @@ async function executeInbox(context, args) {
|
|
|
4765
4930
|
decision: decision.value,
|
|
4766
4931
|
note: note4.value ?? null
|
|
4767
4932
|
})
|
|
4768
|
-
});
|
|
4933
|
+
}), { outputMode: context.outputMode });
|
|
4769
4934
|
return { ok: true, group: "inbox", command, details: { result } };
|
|
4770
4935
|
}
|
|
4771
4936
|
case "respond": {
|
|
@@ -4799,7 +4964,7 @@ async function executeInbox(context, args) {
|
|
|
4799
4964
|
const [key, ...restValue] = entry.split("=");
|
|
4800
4965
|
return [key, restValue.join("=")];
|
|
4801
4966
|
}));
|
|
4802
|
-
const result = await requestServerJson(context, "/api/inbox/inputs/respond", {
|
|
4967
|
+
const result = await withSpinner(`Sending response for ${request.value}\u2026`, () => requestServerJson(context, "/api/inbox/inputs/respond", {
|
|
4803
4968
|
method: "POST",
|
|
4804
4969
|
headers: { "content-type": "application/json" },
|
|
4805
4970
|
body: JSON.stringify({
|
|
@@ -4807,7 +4972,7 @@ async function executeInbox(context, args) {
|
|
|
4807
4972
|
requestId: request.value,
|
|
4808
4973
|
answers: parsedAnswers
|
|
4809
4974
|
})
|
|
4810
|
-
});
|
|
4975
|
+
}), { outputMode: context.outputMode });
|
|
4811
4976
|
return { ok: true, group: "inbox", command, details: { result } };
|
|
4812
4977
|
}
|
|
4813
4978
|
case "watch": {
|
|
@@ -5224,7 +5389,10 @@ async function runRigDoctorChecks(options) {
|
|
|
5224
5389
|
const bunVersion = options.bunVersion ?? Bun.version;
|
|
5225
5390
|
const request = options.requestJson ?? ((pathname, init) => requestServerJson({ projectRoot }, pathname, init));
|
|
5226
5391
|
const loadConfig = options.loadConfig ?? loadRigConfigOrNull;
|
|
5392
|
+
const progress = options.onProgress ?? (() => {});
|
|
5393
|
+
progress("Checking local toolchain\u2026");
|
|
5227
5394
|
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`)."));
|
|
5395
|
+
progress("Loading rig.config\u2026");
|
|
5228
5396
|
const loadedConfig = await loadConfig(projectRoot).catch(() => null);
|
|
5229
5397
|
const config = loadedConfig ?? loadFallbackConfig(projectRoot);
|
|
5230
5398
|
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync11(resolve17(projectRoot, name)));
|
|
@@ -5243,6 +5411,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5243
5411
|
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));
|
|
5244
5412
|
let server = null;
|
|
5245
5413
|
try {
|
|
5414
|
+
progress("Connecting to the selected Rig server\u2026");
|
|
5246
5415
|
server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
|
|
5247
5416
|
checks.push(check("server", "Rig server reachable", "pass", `${server.connectionKind} ${server.baseUrl}`));
|
|
5248
5417
|
} catch (error) {
|
|
@@ -5250,18 +5419,21 @@ async function runRigDoctorChecks(options) {
|
|
|
5250
5419
|
}
|
|
5251
5420
|
if (server || options.requestJson) {
|
|
5252
5421
|
try {
|
|
5422
|
+
progress("Checking server status\u2026");
|
|
5253
5423
|
const status = await request("/api/server/status");
|
|
5254
5424
|
checks.push(check("server-status", "server project status", "pass", JSON.stringify(status).slice(0, 180)));
|
|
5255
5425
|
} catch (error) {
|
|
5256
5426
|
checks.push(check("server-status", "server project status", "fail", errorMessage(error), "Run `rig doctor` after the selected server is reachable."));
|
|
5257
5427
|
}
|
|
5258
5428
|
try {
|
|
5429
|
+
progress("Checking GitHub auth\u2026");
|
|
5259
5430
|
const auth = await request("/api/github/auth/status");
|
|
5260
5431
|
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>`."));
|
|
5261
5432
|
} catch (error) {
|
|
5262
5433
|
checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig and ensure the server exposes auth status."));
|
|
5263
5434
|
}
|
|
5264
5435
|
try {
|
|
5436
|
+
progress("Checking GitHub repo permissions\u2026");
|
|
5265
5437
|
const permissions = await request("/api/github/repo/permissions");
|
|
5266
5438
|
const allowed = permissionAllowsPr2(permissions);
|
|
5267
5439
|
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."));
|
|
@@ -5269,6 +5441,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5269
5441
|
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."));
|
|
5270
5442
|
}
|
|
5271
5443
|
try {
|
|
5444
|
+
progress("Checking GitHub issue labels\u2026");
|
|
5272
5445
|
const labels = await request("/api/workspace/task-labels");
|
|
5273
5446
|
const ready = labelsReady(labels);
|
|
5274
5447
|
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."));
|
|
@@ -5276,6 +5449,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5276
5449
|
checks.push(check("task-labels", "GitHub issue labels", "warn", errorMessage(error), "Run `rig init`/`rig doctor` after label setup is wired on the server."));
|
|
5277
5450
|
}
|
|
5278
5451
|
try {
|
|
5452
|
+
progress("Checking task projection\u2026");
|
|
5279
5453
|
const projection = await request("/api/workspace/task-projection");
|
|
5280
5454
|
checks.push(check("task-projection", "task projection", "pass", JSON.stringify(projection).slice(0, 180)));
|
|
5281
5455
|
} catch (error) {
|
|
@@ -5284,6 +5458,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5284
5458
|
const slug = projectStatusSlug(projectRoot, config);
|
|
5285
5459
|
if (slug) {
|
|
5286
5460
|
try {
|
|
5461
|
+
progress("Checking server project checkout\u2026");
|
|
5287
5462
|
const project = await request(`/api/projects/${encodeURIComponent(slug)}`);
|
|
5288
5463
|
checks.push(check("remote-checkout", "server project checkout", "pass", JSON.stringify(project).slice(0, 180)));
|
|
5289
5464
|
} catch (error) {
|
|
@@ -5298,6 +5473,7 @@ async function runRigDoctorChecks(options) {
|
|
|
5298
5473
|
}
|
|
5299
5474
|
checks.push(githubProjectsCheck(config));
|
|
5300
5475
|
checks.push(prMergeCheck(config));
|
|
5476
|
+
progress("Checking Pi installation\u2026");
|
|
5301
5477
|
const piChecks = await (options.piChecks ?? (() => buildPiSetupChecks()))().catch((error) => [{
|
|
5302
5478
|
ok: false,
|
|
5303
5479
|
label: "pi/pi-rig checks",
|
|
@@ -6220,7 +6396,7 @@ async function executeGithub(context, args) {
|
|
|
6220
6396
|
case "status": {
|
|
6221
6397
|
if (rest.length > 0)
|
|
6222
6398
|
throw new CliError("Usage: rig github auth status", 1);
|
|
6223
|
-
const status = await getGitHubAuthStatusViaServer(context);
|
|
6399
|
+
const status = await withSpinner("Checking GitHub auth on the server\u2026", () => getGitHubAuthStatusViaServer(context), { outputMode: context.outputMode });
|
|
6224
6400
|
printPayload(context, status, `GitHub auth: ${status.authenticated ? "authenticated" : "unauthenticated"}`);
|
|
6225
6401
|
return { ok: true, group: "github", command: "auth status", details: status };
|
|
6226
6402
|
}
|
|
@@ -6231,14 +6407,15 @@ async function executeGithub(context, args) {
|
|
|
6231
6407
|
const token = parsed.value?.trim();
|
|
6232
6408
|
if (!token)
|
|
6233
6409
|
throw new CliError("Missing --token value.", 1, { hint: "Re-run as `rig github auth token --token <token>`." });
|
|
6234
|
-
const result = await postGitHubTokenViaServer(context, token);
|
|
6410
|
+
const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token), { outputMode: context.outputMode });
|
|
6235
6411
|
printPayload(context, result, "GitHub token stored on the selected Rig server.");
|
|
6236
6412
|
return { ok: true, group: "github", command: "auth token", details: result };
|
|
6237
6413
|
}
|
|
6238
6414
|
case "import-gh": {
|
|
6239
6415
|
if (rest.length > 0)
|
|
6240
6416
|
throw new CliError("Usage: rig github auth import-gh", 1);
|
|
6241
|
-
const
|
|
6417
|
+
const importedToken = readGhToken();
|
|
6418
|
+
const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken), { outputMode: context.outputMode });
|
|
6242
6419
|
printPayload(context, result, "GitHub token imported from gh and stored on the selected Rig server.");
|
|
6243
6420
|
return { ok: true, group: "github", command: "auth import-gh", details: result };
|
|
6244
6421
|
}
|
|
@@ -6251,7 +6428,7 @@ async function executeGithub(context, args) {
|
|
|
6251
6428
|
init_runner();
|
|
6252
6429
|
async function executeDoctor(context, args) {
|
|
6253
6430
|
requireNoExtraArgs(args, "rig doctor");
|
|
6254
|
-
const checks = await runRigDoctorChecks({ projectRoot: context.projectRoot });
|
|
6431
|
+
const checks = await withSpinner("Running doctor checks\u2026", (update) => runRigDoctorChecks({ projectRoot: context.projectRoot, onProgress: update }), { outputMode: context.outputMode });
|
|
6255
6432
|
if (context.outputMode === "text") {
|
|
6256
6433
|
console.log(formatDoctorChecks(checks));
|
|
6257
6434
|
}
|
|
@@ -6558,13 +6735,19 @@ async function executeInspect(context, args) {
|
|
|
6558
6735
|
const requiredTask = requireTask(task, "rig inspect logs --task <task-id>");
|
|
6559
6736
|
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];
|
|
6560
6737
|
if (!latestRun) {
|
|
6561
|
-
const
|
|
6562
|
-
|
|
6563
|
-
|
|
6738
|
+
const fallback = await withSpinner(`Finding runs for ${requiredTask} on the server\u2026`, async (update) => {
|
|
6739
|
+
const serverRuns = await listRunsViaServer(context, { limit: 200 }).catch(() => []);
|
|
6740
|
+
const serverRun = serverRuns.filter((run) => String(run.taskId ?? "") === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
|
|
6741
|
+
if (!serverRun || typeof serverRun.runId !== "string")
|
|
6742
|
+
return null;
|
|
6743
|
+
update(`Reading logs for run ${serverRun.runId}\u2026`);
|
|
6744
|
+
const page = await getRunLogsViaServer(context, serverRun.runId, { limit: 500 });
|
|
6745
|
+
return { runId: serverRun.runId, page };
|
|
6746
|
+
}, { outputMode: context.outputMode });
|
|
6747
|
+
if (!fallback) {
|
|
6564
6748
|
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`." });
|
|
6565
6749
|
}
|
|
6566
|
-
const
|
|
6567
|
-
const entries = Array.isArray(page.entries) ? page.entries : [];
|
|
6750
|
+
const entries = Array.isArray(fallback.page.entries) ? fallback.page.entries : [];
|
|
6568
6751
|
if (context.outputMode === "text") {
|
|
6569
6752
|
for (const entry of entries) {
|
|
6570
6753
|
const record = entry && typeof entry === "object" ? entry : {};
|
|
@@ -6573,9 +6756,9 @@ async function executeInspect(context, args) {
|
|
|
6573
6756
|
console.log([title, detail].filter(Boolean).join(" \u2014 "));
|
|
6574
6757
|
}
|
|
6575
6758
|
if (entries.length === 0)
|
|
6576
|
-
console.log(`(no log entries for run ${
|
|
6759
|
+
console.log(`(no log entries for run ${fallback.runId})`);
|
|
6577
6760
|
}
|
|
6578
|
-
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId:
|
|
6761
|
+
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: fallback.runId, source: "server", entries } };
|
|
6579
6762
|
}
|
|
6580
6763
|
const logsPath = resolve20(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
6581
6764
|
if (!existsSync13(logsPath)) {
|
|
@@ -6633,7 +6816,7 @@ async function executeInspect(context, args) {
|
|
|
6633
6816
|
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
6634
6817
|
requireNoExtraArgs(remaining, "rig inspect diff [--task <task-id>]");
|
|
6635
6818
|
if (task) {
|
|
6636
|
-
const files = changedFilesForTask(context.projectRoot, task, false);
|
|
6819
|
+
const files = await withSpinner(`Computing changed files for ${task}\u2026`, async () => changedFilesForTask(context.projectRoot, task, false), { outputMode: context.outputMode });
|
|
6637
6820
|
for (const file of files) {
|
|
6638
6821
|
console.log(file);
|
|
6639
6822
|
}
|
|
@@ -7314,8 +7497,6 @@ import {
|
|
|
7314
7497
|
deleteRunState,
|
|
7315
7498
|
listOpenEpics,
|
|
7316
7499
|
resolveDefaultEpic,
|
|
7317
|
-
runResume,
|
|
7318
|
-
runRestart,
|
|
7319
7500
|
runStatus,
|
|
7320
7501
|
runStop,
|
|
7321
7502
|
startRun,
|
|
@@ -7721,7 +7902,12 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
7721
7902
|
};
|
|
7722
7903
|
let detached = false;
|
|
7723
7904
|
try {
|
|
7724
|
-
await runPiMain([
|
|
7905
|
+
await runPiMain([
|
|
7906
|
+
"--no-extensions",
|
|
7907
|
+
"--no-skills",
|
|
7908
|
+
"--no-prompt-templates",
|
|
7909
|
+
"--no-context-files"
|
|
7910
|
+
], {
|
|
7725
7911
|
extensionFactories: [piRigExtensionFactory]
|
|
7726
7912
|
});
|
|
7727
7913
|
detached = true;
|
|
@@ -7786,8 +7972,9 @@ async function readOperatorSnapshot(context, runId, options = {}) {
|
|
|
7786
7972
|
}
|
|
7787
7973
|
async function attachRunOperatorView(context, input) {
|
|
7788
7974
|
let steered = false;
|
|
7789
|
-
|
|
7790
|
-
|
|
7975
|
+
const attachMessage = input.message?.trim();
|
|
7976
|
+
if (attachMessage) {
|
|
7977
|
+
await withSpinner("Queueing steering message\u2026", () => sendRunPiPromptViaServer(context, input.runId, attachMessage, "steer").catch(() => steerRunViaServer(context, input.runId, attachMessage)), { outputMode: context.outputMode });
|
|
7791
7978
|
steered = true;
|
|
7792
7979
|
}
|
|
7793
7980
|
if (input.follow && !input.once && input.interactive !== false && context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
@@ -7797,7 +7984,7 @@ async function attachRunOperatorView(context, input) {
|
|
|
7797
7984
|
});
|
|
7798
7985
|
}
|
|
7799
7986
|
const surface = createOperatorSurface({ interactive: input.interactive !== false });
|
|
7800
|
-
let snapshot = await readOperatorSnapshot(context, input.runId);
|
|
7987
|
+
let snapshot = await withSpinner(`Connecting to run ${input.runId}\u2026`, () => readOperatorSnapshot(context, input.runId), { outputMode: context.outputMode });
|
|
7801
7988
|
if (context.outputMode === "text") {
|
|
7802
7989
|
surface.renderSnapshot(snapshot);
|
|
7803
7990
|
surface.renderTimeline(snapshot.timeline);
|
|
@@ -7928,7 +8115,7 @@ async function executeRun(context, args) {
|
|
|
7928
8115
|
switch (command) {
|
|
7929
8116
|
case "list": {
|
|
7930
8117
|
requireNoExtraArgs(rest, "rig run list");
|
|
7931
|
-
const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
|
|
8118
|
+
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 });
|
|
7932
8119
|
if (context.outputMode === "text") {
|
|
7933
8120
|
printFormattedOutput(formatRunList(runs, { source }));
|
|
7934
8121
|
await printPendingInboxFooter(context);
|
|
@@ -8001,7 +8188,7 @@ async function executeRun(context, args) {
|
|
|
8001
8188
|
if (!runId) {
|
|
8002
8189
|
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>`." });
|
|
8003
8190
|
}
|
|
8004
|
-
const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, runId).catch(() => ({})));
|
|
8191
|
+
const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await withSpinner(`Reading run ${runId} from server\u2026`, () => getRunDetailsViaServer(context, runId).catch(() => ({})), { outputMode: context.outputMode }));
|
|
8005
8192
|
if (!record) {
|
|
8006
8193
|
throw new CliError(`Run not found: ${runId}`, 2, { hint: "Run `rig run list` to see recorded runs." });
|
|
8007
8194
|
}
|
|
@@ -8022,7 +8209,8 @@ async function executeRun(context, args) {
|
|
|
8022
8209
|
}
|
|
8023
8210
|
const renderer = createPiRunStreamRenderer();
|
|
8024
8211
|
let cursor = null;
|
|
8025
|
-
const
|
|
8212
|
+
const timelineRunId = run.value;
|
|
8213
|
+
const page = await withSpinner(`Reading timeline for ${timelineRunId}\u2026`, () => getRunTimelineViaServer(context, timelineRunId, { limit: 500 }), { outputMode: context.outputMode });
|
|
8026
8214
|
const events = Array.isArray(page.entries) ? page.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
8027
8215
|
cursor = typeof page.nextCursor === "string" ? page.nextCursor : null;
|
|
8028
8216
|
if (context.outputMode === "text") {
|
|
@@ -8099,8 +8287,9 @@ async function executeRun(context, args) {
|
|
|
8099
8287
|
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`." });
|
|
8100
8288
|
}
|
|
8101
8289
|
let steered = false;
|
|
8102
|
-
|
|
8103
|
-
|
|
8290
|
+
const steerMessage = messageOption.value?.trim();
|
|
8291
|
+
if (steerMessage) {
|
|
8292
|
+
await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, steerMessage), { outputMode: context.outputMode });
|
|
8104
8293
|
steered = true;
|
|
8105
8294
|
}
|
|
8106
8295
|
const attached = await attachRunOperatorView(context, {
|
|
@@ -8120,7 +8309,7 @@ async function executeRun(context, args) {
|
|
|
8120
8309
|
}
|
|
8121
8310
|
return { ok: true, group: "run", command };
|
|
8122
8311
|
}
|
|
8123
|
-
const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
|
|
8312
|
+
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);
|
|
8124
8313
|
const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
8125
8314
|
const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
8126
8315
|
if (context.outputMode === "text") {
|
|
@@ -8209,7 +8398,7 @@ async function executeRun(context, args) {
|
|
|
8209
8398
|
}
|
|
8210
8399
|
return { ok: true, group: "run", command };
|
|
8211
8400
|
}
|
|
8212
|
-
const resumed = await
|
|
8401
|
+
const resumed = await withSpinner(targetRunId ? `Resuming run ${targetRunId}\u2026` : "Resuming latest resumable run\u2026", () => resumeRunViaServer(context, targetRunId, { restart: false }), { outputMode: context.outputMode });
|
|
8213
8402
|
if (context.outputMode === "text") {
|
|
8214
8403
|
console.log(`Resumed run: ${resumed.runId}`);
|
|
8215
8404
|
}
|
|
@@ -8228,7 +8417,7 @@ async function executeRun(context, args) {
|
|
|
8228
8417
|
}
|
|
8229
8418
|
return { ok: true, group: "run", command };
|
|
8230
8419
|
}
|
|
8231
|
-
const restarted = await
|
|
8420
|
+
const restarted = await withSpinner(targetRunId ? `Restarting run ${targetRunId}\u2026` : "Restarting latest run\u2026", () => resumeRunViaServer(context, targetRunId, { restart: true }), { outputMode: context.outputMode });
|
|
8232
8421
|
if (context.outputMode === "text") {
|
|
8233
8422
|
console.log(`Restarted run: ${restarted.runId}`);
|
|
8234
8423
|
}
|
|
@@ -8255,7 +8444,8 @@ async function executeRun(context, args) {
|
|
|
8255
8444
|
}
|
|
8256
8445
|
return { ok: true, group: "run", command, details: { runId, dryRun: true } };
|
|
8257
8446
|
}
|
|
8258
|
-
|
|
8447
|
+
const trimmedMessage = message2.trim();
|
|
8448
|
+
await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, trimmedMessage), { outputMode: context.outputMode });
|
|
8259
8449
|
if (context.outputMode === "text") {
|
|
8260
8450
|
console.log(`Steering message queued for ${runId}.`);
|
|
8261
8451
|
}
|
|
@@ -8276,7 +8466,7 @@ async function executeRun(context, args) {
|
|
|
8276
8466
|
};
|
|
8277
8467
|
}
|
|
8278
8468
|
if (runId) {
|
|
8279
|
-
const stopped = await stopRunViaServer(context, runId);
|
|
8469
|
+
const stopped = await withSpinner(`Requesting stop for ${runId}\u2026`, () => stopRunViaServer(context, runId), { outputMode: context.outputMode });
|
|
8280
8470
|
if (context.outputMode === "text")
|
|
8281
8471
|
console.log(`Stop requested: ${runId}`);
|
|
8282
8472
|
return { ok: true, group: "run", command, details: stopped };
|
|
@@ -8522,12 +8712,12 @@ async function executeServer(context, args, options) {
|
|
|
8522
8712
|
|
|
8523
8713
|
// packages/cli/src/commands/stats.ts
|
|
8524
8714
|
init_runner();
|
|
8525
|
-
import
|
|
8715
|
+
import pc6 from "picocolors";
|
|
8526
8716
|
import { computeRigStats } from "@rig/runtime/control-plane/native/run-stats";
|
|
8527
8717
|
|
|
8528
8718
|
// packages/cli/src/commands/_help-catalog.ts
|
|
8529
8719
|
import { intro as intro3, log as log4, note as note4, outro as outro3 } from "@clack/prompts";
|
|
8530
|
-
import
|
|
8720
|
+
import pc5 from "picocolors";
|
|
8531
8721
|
var TOP_LEVEL_SECTIONS = [
|
|
8532
8722
|
{
|
|
8533
8723
|
title: "Start here",
|
|
@@ -8815,13 +9005,13 @@ var ADVANCED_COMMANDS = [
|
|
|
8815
9005
|
];
|
|
8816
9006
|
var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
|
|
8817
9007
|
function heading(title) {
|
|
8818
|
-
return
|
|
9008
|
+
return pc5.bold(pc5.cyan(title));
|
|
8819
9009
|
}
|
|
8820
9010
|
function renderRigBanner(version) {
|
|
8821
|
-
const m = (s) =>
|
|
8822
|
-
const c = (s) =>
|
|
8823
|
-
const y = (s) =>
|
|
8824
|
-
const d = (s) =>
|
|
9011
|
+
const m = (s) => pc5.bold(pc5.magenta(s));
|
|
9012
|
+
const c = (s) => pc5.bold(pc5.cyan(s));
|
|
9013
|
+
const y = (s) => pc5.yellow(s);
|
|
9014
|
+
const d = (s) => pc5.dim(s);
|
|
8825
9015
|
const lines = [
|
|
8826
9016
|
m(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + d(" \u2591\u2592\u2593\u2588 "),
|
|
8827
9017
|
m(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ") + d("\u2593\u2592\u2591"),
|
|
@@ -8830,7 +9020,7 @@ function renderRigBanner(version) {
|
|
|
8830
9020
|
y(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + d(" \u2592\u2591"),
|
|
8831
9021
|
y(" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "),
|
|
8832
9022
|
"",
|
|
8833
|
-
` ${c("\u25E2\u25E4")} ${
|
|
9023
|
+
` ${c("\u25E2\u25E4")} ${pc5.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
|
|
8834
9024
|
version ? ` ${d(`v${version} \xB7 jack in: rig task run --next`)}` : ` ${d("jack in: rig task run --next")}`
|
|
8835
9025
|
];
|
|
8836
9026
|
return lines.join(`
|
|
@@ -8838,7 +9028,7 @@ function renderRigBanner(version) {
|
|
|
8838
9028
|
}
|
|
8839
9029
|
function commandLine(command, description) {
|
|
8840
9030
|
const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
|
|
8841
|
-
return `${
|
|
9031
|
+
return `${pc5.dim("\u2502")} ${pc5.bold(commandColumn)} ${description}`;
|
|
8842
9032
|
}
|
|
8843
9033
|
function renderCommandBlock(commands) {
|
|
8844
9034
|
return commands.map((entry) => commandLine(entry.command, entry.description)).join(`
|
|
@@ -8848,37 +9038,37 @@ function renderGroup(group) {
|
|
|
8848
9038
|
const lines = [
|
|
8849
9039
|
`${heading(`rig ${group.name}`)} \u2014 ${group.summary}`,
|
|
8850
9040
|
"",
|
|
8851
|
-
|
|
9041
|
+
pc5.bold("Usage"),
|
|
8852
9042
|
...group.usage.map((line) => ` ${line}`),
|
|
8853
9043
|
"",
|
|
8854
|
-
|
|
9044
|
+
pc5.bold("Commands"),
|
|
8855
9045
|
...group.commands.map((entry) => commandLine(entry.command, entry.description))
|
|
8856
9046
|
];
|
|
8857
9047
|
if (group.examples?.length) {
|
|
8858
|
-
lines.push("",
|
|
9048
|
+
lines.push("", pc5.bold("Examples"), ...group.examples.map((line) => ` ${pc5.dim("$")} ${line}`));
|
|
8859
9049
|
}
|
|
8860
9050
|
if (group.next?.length) {
|
|
8861
|
-
lines.push("",
|
|
9051
|
+
lines.push("", pc5.bold("Next steps"), ...group.next.map((line) => ` ${pc5.dim("\u203A")} ${line}`));
|
|
8862
9052
|
}
|
|
8863
9053
|
if (group.advanced?.length) {
|
|
8864
|
-
lines.push("",
|
|
9054
|
+
lines.push("", pc5.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc5.dim("\u203A")} ${line}`));
|
|
8865
9055
|
}
|
|
8866
9056
|
return lines.join(`
|
|
8867
9057
|
`);
|
|
8868
9058
|
}
|
|
8869
9059
|
function renderTopLevelHelp() {
|
|
8870
9060
|
return [
|
|
8871
|
-
`${heading("rig")} ${
|
|
8872
|
-
|
|
9061
|
+
`${heading("rig")} ${pc5.dim("\u2014 server-owned task/run control plane for Pi-backed engineering work")}`,
|
|
9062
|
+
pc5.dim("Current path: select a server, choose a task, submit a run, attach with native Pi, clear inbox gates."),
|
|
8873
9063
|
"",
|
|
8874
9064
|
...TOP_LEVEL_SECTIONS.flatMap((section) => [
|
|
8875
|
-
`${
|
|
9065
|
+
`${pc5.bold(pc5.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc5.dim(section.subtitle)}`,
|
|
8876
9066
|
renderCommandBlock(section.commands),
|
|
8877
9067
|
""
|
|
8878
9068
|
]),
|
|
8879
|
-
|
|
9069
|
+
pc5.dim("More: `rig help --advanced` for dev/compatibility commands; `rig <group> --help` for rich per-group help; `rig --version` for the installed version."),
|
|
8880
9070
|
"",
|
|
8881
|
-
|
|
9071
|
+
pc5.bold("Global options"),
|
|
8882
9072
|
commandLine("--project <path>", "Use a project root instead of auto-discovery."),
|
|
8883
9073
|
commandLine("--json", "Emit structured output for scripts/agents."),
|
|
8884
9074
|
commandLine("--dry-run", "Print the command plan without mutating state.")
|
|
@@ -8889,16 +9079,16 @@ function renderAdvancedHelp() {
|
|
|
8889
9079
|
return [
|
|
8890
9080
|
`${heading("rig advanced")} \u2014 compatibility, diagnostics, and internal surfaces`,
|
|
8891
9081
|
"",
|
|
8892
|
-
|
|
9082
|
+
pc5.bold("Primary groups"),
|
|
8893
9083
|
" init, server, task, run, inbox, repo, plugin, inspect, stats, doctor, github",
|
|
8894
9084
|
"",
|
|
8895
|
-
|
|
9085
|
+
pc5.bold("Advanced commands"),
|
|
8896
9086
|
...ADVANCED_COMMANDS.map((entry) => commandLine(entry.command, entry.description)),
|
|
8897
9087
|
"",
|
|
8898
|
-
|
|
9088
|
+
pc5.bold("Advanced groups"),
|
|
8899
9089
|
...ADVANCED_GROUPS.map((group) => commandLine(group.name, group.summary)),
|
|
8900
9090
|
"",
|
|
8901
|
-
|
|
9091
|
+
pc5.dim("All groups remain callable. Prefer `rig server`, `rig task`, `rig run`, and `rig inbox` for day-to-day work.")
|
|
8902
9092
|
].join(`
|
|
8903
9093
|
`);
|
|
8904
9094
|
}
|
|
@@ -9046,11 +9236,11 @@ function formatStatsReport(stats) {
|
|
|
9046
9236
|
const keyWidth = Math.max(...rows.map(([key]) => key.length));
|
|
9047
9237
|
const lines = [
|
|
9048
9238
|
formatSection("Fleet stats", window),
|
|
9049
|
-
...rows.map(([key, value]) => `${
|
|
9239
|
+
...rows.map(([key, value]) => `${pc6.dim("\u2502")} ${pc6.dim(key.padEnd(keyWidth + 2))} ${value}`)
|
|
9050
9240
|
];
|
|
9051
9241
|
const otherStatuses = Object.entries(stats.statusCounts).filter(([status]) => !["completed", "failed", "needs-attention"].includes(status)).sort(([, left], [, right]) => right - left);
|
|
9052
9242
|
if (otherStatuses.length > 0) {
|
|
9053
|
-
lines.push(`${
|
|
9243
|
+
lines.push(`${pc6.dim("\u2502")} ${pc6.dim("other".padEnd(keyWidth + 2))} ${otherStatuses.map(([status, count]) => `${status}:${count}`).join(" ")}`);
|
|
9054
9244
|
}
|
|
9055
9245
|
lines.push("", ...formatNextSteps([
|
|
9056
9246
|
"Inspect a run: `rig run list` then `rig run show <run-id>`",
|
|
@@ -9069,7 +9259,8 @@ async function executeStats(context, args) {
|
|
|
9069
9259
|
const sinceResult = takeOption(pending, "--since");
|
|
9070
9260
|
requireNoExtraArgs(sinceResult.rest, "rig stats [show] [--since <7d|30d|ISO date>]");
|
|
9071
9261
|
const since = parseSinceOption(sinceResult.value);
|
|
9072
|
-
const
|
|
9262
|
+
const remoteStats = isRemoteConnectionSelected(context.projectRoot);
|
|
9263
|
+
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 });
|
|
9073
9264
|
if (context.outputMode === "text") {
|
|
9074
9265
|
printFormattedOutput(formatStatsReport(stats));
|
|
9075
9266
|
}
|
|
@@ -9324,7 +9515,7 @@ async function executeTask(context, args, options) {
|
|
|
9324
9515
|
pending = rawResult.rest;
|
|
9325
9516
|
const { filters, rest: remaining } = parseTaskFilters(pending);
|
|
9326
9517
|
requireNoExtraArgs(remaining, "rig task list [--raw] [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
|
|
9327
|
-
const tasks = await listWorkspaceTasksViaServer(context, filters);
|
|
9518
|
+
const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filters), { outputMode: context.outputMode });
|
|
9328
9519
|
if (context.outputMode === "text") {
|
|
9329
9520
|
const renderedTasks = rawResult.value ? tasks.map((task) => summarizeTask(task, { raw: true })) : tasks.map((task) => summarizeTask(task));
|
|
9330
9521
|
printFormattedOutput(formatTaskList(renderedTasks, { raw: rawResult.value }));
|
|
@@ -9348,7 +9539,7 @@ async function executeTask(context, args, options) {
|
|
|
9348
9539
|
const taskId3 = normalizeTaskRunTaskId(taskOption.value ?? positional);
|
|
9349
9540
|
if (!taskId3)
|
|
9350
9541
|
throw new CliError("task show requires a task id.", 2, { hint: "Run `rig task list` to find ids, then `rig task show <id>`." });
|
|
9351
|
-
const task = await getWorkspaceTaskViaServer(context, taskId3);
|
|
9542
|
+
const task = await withSpinner(`Reading task ${taskId3} from server\u2026`, () => getWorkspaceTaskViaServer(context, taskId3), { outputMode: context.outputMode });
|
|
9352
9543
|
if (!task)
|
|
9353
9544
|
throw new CliError(`Task not found: ${taskId3}`, 3, { hint: "Run `rig task list` to see available tasks." });
|
|
9354
9545
|
const summary = summarizeTask(task, { raw: true });
|
|
@@ -9360,7 +9551,7 @@ async function executeTask(context, args, options) {
|
|
|
9360
9551
|
case "next": {
|
|
9361
9552
|
const { filters, rest: remaining } = parseTaskFilters(rest);
|
|
9362
9553
|
requireNoExtraArgs(remaining, "rig task next [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
|
|
9363
|
-
const selected = await selectNextWorkspaceTaskViaServer(context, filters);
|
|
9554
|
+
const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filters), { outputMode: context.outputMode });
|
|
9364
9555
|
if (context.outputMode === "text") {
|
|
9365
9556
|
if (selected.task) {
|
|
9366
9557
|
printFormattedOutput(formatTaskCard(summarizeTask(selected.task, { raw: true }), { title: "Selected task", selected: true }));
|
|
@@ -9510,7 +9701,7 @@ async function executeTask(context, args, options) {
|
|
|
9510
9701
|
let selectedTask = null;
|
|
9511
9702
|
let selectedTaskId = normalizeTaskRunTaskId(taskResult.value) ?? positionalTaskId;
|
|
9512
9703
|
if (nextResult.value) {
|
|
9513
|
-
const selected = await selectNextWorkspaceTaskViaServer(context, filterResult.filters);
|
|
9704
|
+
const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filterResult.filters), { outputMode: context.outputMode });
|
|
9514
9705
|
selectedTask = selected.task;
|
|
9515
9706
|
selectedTaskId = selected.task ? readTaskId(selected.task) : null;
|
|
9516
9707
|
if (!selectedTaskId) {
|
|
@@ -9521,7 +9712,7 @@ async function executeTask(context, args, options) {
|
|
|
9521
9712
|
if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
9522
9713
|
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);
|
|
9523
9714
|
}
|
|
9524
|
-
const tasks = await listWorkspaceTasksViaServer(context, filterResult.filters);
|
|
9715
|
+
const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filterResult.filters), { outputMode: context.outputMode });
|
|
9525
9716
|
selectedTask = await selectTaskWithTextPicker(tasks);
|
|
9526
9717
|
selectedTaskId = selectedTask ? readTaskId(selectedTask) : null;
|
|
9527
9718
|
if (!selectedTaskId) {
|
|
@@ -9531,13 +9722,13 @@ async function executeTask(context, args, options) {
|
|
|
9531
9722
|
await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
|
|
9532
9723
|
const projectDefaults = await loadTaskRunProjectDefaults(context.projectRoot);
|
|
9533
9724
|
const runtimeAdapter = normalizeRuntimeAdapter(runtimeAdapterResult.value ?? projectDefaults.runtimeAdapter);
|
|
9534
|
-
await runFastTaskRunPreflight(context, {
|
|
9725
|
+
await withSpinner("Running task-run preflight\u2026", () => runFastTaskRunPreflight(context, {
|
|
9535
9726
|
taskId: selectedTaskId,
|
|
9536
9727
|
runtimeAdapter
|
|
9537
|
-
});
|
|
9728
|
+
}), { outputMode: context.outputMode });
|
|
9538
9729
|
const dirtyBaseline = await resolveDirtyBaselineForTaskRun(context, dirtyBaselineResult.value);
|
|
9539
9730
|
const prMode = noPrResult.value ? "off" : normalizePrMode(prResult.value) ?? projectDefaults.prMode;
|
|
9540
|
-
const submitted = await submitTaskRunViaServer(context, {
|
|
9731
|
+
const submitted = await withSpinner("Dispatching run\u2026", () => submitTaskRunViaServer(context, {
|
|
9541
9732
|
runId: context.runId,
|
|
9542
9733
|
taskId: selectedTaskId ?? undefined,
|
|
9543
9734
|
title: titleResult.value ?? undefined,
|
|
@@ -9548,7 +9739,7 @@ async function executeTask(context, args, options) {
|
|
|
9548
9739
|
initialPrompt: initialPromptResult.value ?? undefined,
|
|
9549
9740
|
baselineMode: dirtyBaseline.mode,
|
|
9550
9741
|
prMode
|
|
9551
|
-
});
|
|
9742
|
+
}), { outputMode: context.outputMode });
|
|
9552
9743
|
let attachDetails = null;
|
|
9553
9744
|
if (!detachResult.value && context.outputMode === "text") {
|
|
9554
9745
|
printFormattedOutput(formatSubmittedRun({
|
|
@@ -11726,7 +11917,7 @@ async function executeSetup(context, args) {
|
|
|
11726
11917
|
case "check":
|
|
11727
11918
|
requireNoExtraArgs(rest, `rig setup ${command}`);
|
|
11728
11919
|
{
|
|
11729
|
-
const checks = await withMutedConsole(context.outputMode === "json", () => runSetupCheck(context.projectRoot));
|
|
11920
|
+
const checks = await withMutedConsole(context.outputMode === "json", () => runSetupCheck(context.projectRoot, context.outputMode));
|
|
11730
11921
|
return { ok: true, group: "setup", command, details: { checks, failures: countDoctorFailures(checks) } };
|
|
11731
11922
|
}
|
|
11732
11923
|
case "setup":
|
|
@@ -11735,7 +11926,7 @@ async function executeSetup(context, args) {
|
|
|
11735
11926
|
return { ok: true, group: "setup", command };
|
|
11736
11927
|
case "preflight":
|
|
11737
11928
|
requireNoExtraArgs(rest, "rig setup preflight");
|
|
11738
|
-
await withMutedConsole(context.outputMode === "json", () => runSetupPreflight(context.projectRoot));
|
|
11929
|
+
await withMutedConsole(context.outputMode === "json", () => runSetupPreflight(context.projectRoot, context.outputMode));
|
|
11739
11930
|
return { ok: true, group: "setup", command };
|
|
11740
11931
|
default:
|
|
11741
11932
|
throw new CliError(`Unknown setup command: ${command}`, 1, { hint: "Run `rig setup --help` \u2014 commands are bootstrap|check|preflight." });
|
|
@@ -11756,8 +11947,8 @@ function runSetupInit(projectRoot) {
|
|
|
11756
11947
|
}
|
|
11757
11948
|
console.log("Harness directories ready.");
|
|
11758
11949
|
}
|
|
11759
|
-
async function runSetupCheck(projectRoot) {
|
|
11760
|
-
const doctorChecks = await runRigDoctorChecks({ projectRoot });
|
|
11950
|
+
async function runSetupCheck(projectRoot, outputMode = "text") {
|
|
11951
|
+
const doctorChecks = await withSpinner("Running setup checks\u2026", (update) => runRigDoctorChecks({ projectRoot, onProgress: update }), { outputMode });
|
|
11761
11952
|
console.log(formatDoctorChecks(doctorChecks));
|
|
11762
11953
|
const failures = countDoctorFailures(doctorChecks);
|
|
11763
11954
|
if (failures > 0) {
|
|
@@ -11765,8 +11956,8 @@ async function runSetupCheck(projectRoot) {
|
|
|
11765
11956
|
}
|
|
11766
11957
|
return doctorChecks;
|
|
11767
11958
|
}
|
|
11768
|
-
async function runSetupPreflight(projectRoot) {
|
|
11769
|
-
await runSetupCheck(projectRoot);
|
|
11959
|
+
async function runSetupPreflight(projectRoot, outputMode = "text") {
|
|
11960
|
+
await runSetupCheck(projectRoot, outputMode);
|
|
11770
11961
|
const validationRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
11771
11962
|
if (existsSync16(validationRoot)) {
|
|
11772
11963
|
const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|