@h-rig/cli 0.0.6-alpha.64 → 0.0.6-alpha.66
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 +1349 -1599
- package/dist/src/commands/_connection-state.js +14 -5
- package/dist/src/commands/_doctor-checks.js +71 -11
- package/dist/src/commands/_help-catalog.js +99 -60
- package/dist/src/commands/_json-output.js +56 -0
- package/dist/src/commands/_operator-view.js +97 -784
- package/dist/src/commands/_parsers.js +18 -9
- package/dist/src/commands/_pi-frontend.js +96 -788
- package/dist/src/commands/_policy.js +12 -3
- package/dist/src/commands/_preflight.js +73 -13
- package/dist/src/commands/_run-driver-helpers.js +31 -5
- package/dist/src/commands/_run-replay.js +2 -2
- package/dist/src/commands/_server-client.js +76 -16
- package/dist/src/commands/_snapshot-upload.js +70 -10
- package/dist/src/commands/agent.js +21 -11
- package/dist/src/commands/browser.js +24 -15
- package/dist/src/commands/connect.js +22 -17
- package/dist/src/commands/dist.js +15 -6
- package/dist/src/commands/doctor.js +70 -10
- package/dist/src/commands/github.js +79 -19
- package/dist/src/commands/inbox.js +215 -131
- package/dist/src/commands/init.js +202 -35
- package/dist/src/commands/inspect.js +77 -17
- package/dist/src/commands/inspector.js +18 -9
- package/dist/src/commands/pi.js +18 -9
- package/dist/src/commands/plugin.js +19 -10
- package/dist/src/commands/profile-and-review.js +22 -13
- package/dist/src/commands/queue.js +19 -9
- package/dist/src/commands/remote.js +25 -16
- package/dist/src/commands/repo-git-harness.js +18 -9
- package/dist/src/commands/run.js +158 -805
- package/dist/src/commands/server.js +85 -25
- package/dist/src/commands/setup.js +73 -13
- package/dist/src/commands/stats.js +681 -0
- package/dist/src/commands/task-report-bug.js +24 -15
- package/dist/src/commands/task-run-driver.js +121 -49
- package/dist/src/commands/task.js +254 -893
- package/dist/src/commands/test.js +12 -3
- package/dist/src/commands/workspace.js +14 -5
- package/dist/src/commands.js +1339 -1650
- package/dist/src/index.js +1349 -1599
- package/dist/src/launcher.js +72 -10
- package/dist/src/runner.js +14 -5
- package/package.json +10 -7
- package/dist/src/commands/_pi-remote-session.js +0 -771
- package/dist/src/commands/_pi-worker-bridge-extension.js +0 -834
|
@@ -7,10 +7,19 @@ import pc from "picocolors";
|
|
|
7
7
|
|
|
8
8
|
// packages/cli/src/runner.ts
|
|
9
9
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
10
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
10
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
11
11
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
12
12
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
class CliError extends RuntimeCliError {
|
|
15
|
+
hint;
|
|
16
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
17
|
+
super(message, exitCode);
|
|
18
|
+
if (options.hint?.trim()) {
|
|
19
|
+
this.hint = options.hint.trim();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
14
23
|
function formatCommand(parts) {
|
|
15
24
|
return parts.map((part) => /[^a-zA-Z0-9_./:-]/.test(part) ? JSON.stringify(part) : part).join(" ");
|
|
16
25
|
}
|
|
@@ -34,7 +43,7 @@ function takeOption(args, option) {
|
|
|
34
43
|
if (current === option) {
|
|
35
44
|
const next = args[index + 1];
|
|
36
45
|
if (!next || next.startsWith("-")) {
|
|
37
|
-
throw new CliError(`Missing value for ${option}`);
|
|
46
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
38
47
|
}
|
|
39
48
|
value = next;
|
|
40
49
|
index += 1;
|
|
@@ -342,7 +351,7 @@ async function executeTaskReportBug(context, args) {
|
|
|
342
351
|
const noBrowserFlag = takeFlag(pending, "--no-browser");
|
|
343
352
|
pending = noBrowserFlag.rest;
|
|
344
353
|
if (browserFlag.value && noBrowserFlag.value) {
|
|
345
|
-
throw new
|
|
354
|
+
throw new CliError("Pass only one of --browser or --no-browser.", 1, { hint: "Re-run `rig task report-bug` with just one of the flags." });
|
|
346
355
|
}
|
|
347
356
|
const overwriteFlag = takeFlag(pending, "--overwrite");
|
|
348
357
|
pending = overwriteFlag.rest;
|
|
@@ -426,7 +435,7 @@ async function executeTaskReportBug(context, args) {
|
|
|
426
435
|
const shouldPrompt = !noPromptFlag.value;
|
|
427
436
|
if (shouldPrompt) {
|
|
428
437
|
if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
429
|
-
throw new
|
|
438
|
+
throw new CliError("Interactive bug reporting requires a TTY in text mode. Pass --no-prompt with flags for automation.");
|
|
430
439
|
}
|
|
431
440
|
draft = await promptForBugReportDetails(draft);
|
|
432
441
|
}
|
|
@@ -530,7 +539,7 @@ function validateBugReportInputFiles(input) {
|
|
|
530
539
|
for (const { path, label } of files.map((item) => ({ ...item, path: item.path.trim() })).filter((item) => item.path)) {
|
|
531
540
|
const source = resolve3(input.projectRoot, path);
|
|
532
541
|
if (!existsSync2(source)) {
|
|
533
|
-
throw new
|
|
542
|
+
throw new CliError(`${label} does not exist: ${source}`, 1, { hint: "Check the path and re-run `rig task report-bug` with an existing file." });
|
|
534
543
|
}
|
|
535
544
|
}
|
|
536
545
|
}
|
|
@@ -570,7 +579,7 @@ function createBugReportBeadsTask(monorepoRoot, input, draft) {
|
|
|
570
579
|
const issue = tryRunBrJson(monorepoRoot, command);
|
|
571
580
|
if (!issue.ok) {
|
|
572
581
|
if (!isRecoverableBeadsJsonlFailure(issue.error)) {
|
|
573
|
-
throw new
|
|
582
|
+
throw new CliError(issue.error);
|
|
574
583
|
}
|
|
575
584
|
return {
|
|
576
585
|
issueId: generateBugReportIssueId(monorepoRoot, input.title),
|
|
@@ -581,7 +590,7 @@ function createBugReportBeadsTask(monorepoRoot, input, draft) {
|
|
|
581
590
|
}
|
|
582
591
|
const issueId = issue.value.id?.trim();
|
|
583
592
|
if (!issueId) {
|
|
584
|
-
throw new
|
|
593
|
+
throw new CliError("br create did not return an issue id.", 1, { hint: "Re-run `rig task report-bug`; if it persists, file the bug via your task source directly." });
|
|
585
594
|
}
|
|
586
595
|
return {
|
|
587
596
|
issueId,
|
|
@@ -688,12 +697,12 @@ ${serializedEntry}
|
|
|
688
697
|
}
|
|
689
698
|
const insertAt = raw.lastIndexOf("}");
|
|
690
699
|
if (insertAt < 0) {
|
|
691
|
-
throw new
|
|
700
|
+
throw new CliError(`Invalid task config JSON object: ${taskConfigPath}`, 1, { hint: "Fix or reset that file (it must be a JSON object), then re-run `rig task report-bug`." });
|
|
692
701
|
}
|
|
693
702
|
const before = raw.slice(0, insertAt).replace(/\s*$/, "");
|
|
694
703
|
const after = raw.slice(insertAt + 1).trim();
|
|
695
704
|
if (after) {
|
|
696
|
-
throw new
|
|
705
|
+
throw new CliError(`Invalid trailing content in task config: ${taskConfigPath}`, 1, { hint: "Remove the trailing content so the file is a single JSON object, then retry." });
|
|
697
706
|
}
|
|
698
707
|
const comma = before.trim() === "{" ? "" : ",";
|
|
699
708
|
writeFileSync2(taskConfigPath, `${before}${comma}
|
|
@@ -761,7 +770,7 @@ function generateBugReportIssueId(monorepoRoot, title) {
|
|
|
761
770
|
return id;
|
|
762
771
|
}
|
|
763
772
|
}
|
|
764
|
-
throw new
|
|
773
|
+
throw new CliError("Could not generate a unique bug task id.", 1, { hint: "Re-run `rig task report-bug`; pass an explicit title to vary the generated id." });
|
|
765
774
|
}
|
|
766
775
|
function isRecoverableBeadsJsonlFailure(message) {
|
|
767
776
|
return /Invalid JSON|missing field|JSONL is newer than DB|stale database/i.test(message);
|
|
@@ -769,7 +778,7 @@ function isRecoverableBeadsJsonlFailure(message) {
|
|
|
769
778
|
function runBrJson(cwd, command) {
|
|
770
779
|
const result = tryRunBrJson(cwd, command);
|
|
771
780
|
if (!result.ok) {
|
|
772
|
-
throw new
|
|
781
|
+
throw new CliError(result.error);
|
|
773
782
|
}
|
|
774
783
|
return result.value;
|
|
775
784
|
}
|
|
@@ -967,7 +976,7 @@ async function promptBugSelect(message, options, initialValue) {
|
|
|
967
976
|
function unwrapClackPrompt(result) {
|
|
968
977
|
if (clack.isCancel(result)) {
|
|
969
978
|
clack.cancel("Bug report cancelled.");
|
|
970
|
-
throw new
|
|
979
|
+
throw new CliError("Bug report cancelled by user.");
|
|
971
980
|
}
|
|
972
981
|
return result;
|
|
973
982
|
}
|
|
@@ -977,7 +986,7 @@ function normalizeBugEnvironmentChoice(environment) {
|
|
|
977
986
|
function requireReportBugValue(value, option) {
|
|
978
987
|
const normalized = value?.trim();
|
|
979
988
|
if (!normalized) {
|
|
980
|
-
throw new
|
|
989
|
+
throw new CliError(`Missing ${option}. Run interactively or pass ${option} <value>.`);
|
|
981
990
|
}
|
|
982
991
|
return normalized;
|
|
983
992
|
}
|
|
@@ -1058,7 +1067,7 @@ function takeRepeatedOption(args, option) {
|
|
|
1058
1067
|
if (current === option) {
|
|
1059
1068
|
const next = args[index + 1];
|
|
1060
1069
|
if (!next || next.startsWith("-")) {
|
|
1061
|
-
throw new
|
|
1070
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
1062
1071
|
}
|
|
1063
1072
|
values.push(next);
|
|
1064
1073
|
index += 1;
|
|
@@ -7,10 +7,19 @@ import { createInterface as createLineInterface } from "readline";
|
|
|
7
7
|
|
|
8
8
|
// packages/cli/src/runner.ts
|
|
9
9
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
10
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
10
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
11
11
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
12
12
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
class CliError extends RuntimeCliError {
|
|
15
|
+
hint;
|
|
16
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
17
|
+
super(message, exitCode);
|
|
18
|
+
if (options.hint?.trim()) {
|
|
19
|
+
this.hint = options.hint.trim();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
14
23
|
function formatCommand(parts) {
|
|
15
24
|
return parts.map((part) => /[^a-zA-Z0-9_./:-]/.test(part) ? JSON.stringify(part) : part).join(" ");
|
|
16
25
|
}
|
|
@@ -52,12 +61,13 @@ import {
|
|
|
52
61
|
import { readFileSync } from "fs";
|
|
53
62
|
import { resolve as resolve3 } from "path";
|
|
54
63
|
import {
|
|
55
|
-
|
|
64
|
+
appendRunJournalEvent,
|
|
56
65
|
appendRunLogEntry,
|
|
57
66
|
appendRunTimelineEntry,
|
|
58
67
|
patchAuthorityRunRecord,
|
|
59
68
|
readAuthorityRun as readAuthorityRun2,
|
|
60
69
|
resolveAuthorityRunDir,
|
|
70
|
+
setAuthorityRunStatus,
|
|
61
71
|
writeJsonFile
|
|
62
72
|
} from "@rig/runtime/control-plane/authority-files";
|
|
63
73
|
import { taskLookup } from "@rig/runtime/control-plane/native/task-ops";
|
|
@@ -177,7 +187,17 @@ function upsertAgentAuthorityRun(projectRoot, input) {
|
|
|
177
187
|
function patchAuthorityRun(projectRoot, runId, patch) {
|
|
178
188
|
const next = patchAuthorityRunRecord(projectRoot, runId, patch);
|
|
179
189
|
if (!next) {
|
|
180
|
-
throw new
|
|
190
|
+
throw new CliError(`Run not found: ${runId}`, 2, { hint: "Run `rig run list` to see recorded runs." });
|
|
191
|
+
}
|
|
192
|
+
return next;
|
|
193
|
+
}
|
|
194
|
+
function setRunStatusOrFail(projectRoot, runId, to, options = {}) {
|
|
195
|
+
const next = setAuthorityRunStatus(projectRoot, runId, to, {
|
|
196
|
+
...options,
|
|
197
|
+
actor: { kind: "agent" }
|
|
198
|
+
});
|
|
199
|
+
if (!next) {
|
|
200
|
+
throw new CliError(`Run not found: ${runId}`, 2, { hint: "Run `rig run list` to see recorded runs." });
|
|
181
201
|
}
|
|
182
202
|
return next;
|
|
183
203
|
}
|
|
@@ -282,7 +302,12 @@ function emitServerRunEvent(event) {
|
|
|
282
302
|
console.log(`__RIG_RUN_EVENT__${JSON.stringify({ ...event, at: new Date().toISOString() })}`);
|
|
283
303
|
if (runEventSinkProjectRoot) {
|
|
284
304
|
try {
|
|
285
|
-
|
|
305
|
+
if (event.type === "status" || event.type === "completed" || event.type === "failed") {
|
|
306
|
+
appendRunJournalEvent(runEventSinkProjectRoot, event.runId, {
|
|
307
|
+
type: "timeline-entry",
|
|
308
|
+
payload: { kind: "driver-event", ...event }
|
|
309
|
+
});
|
|
310
|
+
}
|
|
286
311
|
} catch {}
|
|
287
312
|
ringServerRunDoorbell(event.runId);
|
|
288
313
|
}
|
|
@@ -441,7 +466,7 @@ function readJsonFile(path) {
|
|
|
441
466
|
try {
|
|
442
467
|
return JSON.parse(readFileSync2(path, "utf8"));
|
|
443
468
|
} catch (error) {
|
|
444
|
-
throw new
|
|
469
|
+
throw new CliError(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1, { hint: "Fix or delete that file, then re-select a server with `rig server use <alias|local>`." });
|
|
445
470
|
}
|
|
446
471
|
}
|
|
447
472
|
function writeJsonFile2(path, value) {
|
|
@@ -505,7 +530,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
505
530
|
const global = readGlobalConnections(options);
|
|
506
531
|
const connection = global.connections[repo.selected];
|
|
507
532
|
if (!connection) {
|
|
508
|
-
throw new
|
|
533
|
+
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
509
534
|
}
|
|
510
535
|
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
511
536
|
}
|
|
@@ -578,7 +603,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
578
603
|
};
|
|
579
604
|
} catch (error) {
|
|
580
605
|
if (error instanceof Error) {
|
|
581
|
-
throw new
|
|
606
|
+
throw new CliError(error.message, 1);
|
|
582
607
|
}
|
|
583
608
|
throw error;
|
|
584
609
|
}
|
|
@@ -628,15 +653,64 @@ function diagnosticMessage(payload) {
|
|
|
628
653
|
});
|
|
629
654
|
return messages.length > 0 ? messages.join("; ") : null;
|
|
630
655
|
}
|
|
656
|
+
var serverReachabilityCache = new Map;
|
|
657
|
+
async function probeServerReachability(baseUrl, authToken) {
|
|
658
|
+
try {
|
|
659
|
+
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/server/status`, {
|
|
660
|
+
headers: mergeHeaders(undefined, authToken),
|
|
661
|
+
signal: AbortSignal.timeout(1500)
|
|
662
|
+
});
|
|
663
|
+
return response.ok;
|
|
664
|
+
} catch {
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function cachedServerReachability(projectRoot, baseUrl, authToken) {
|
|
669
|
+
const key = resolve5(projectRoot);
|
|
670
|
+
const cached = serverReachabilityCache.get(key);
|
|
671
|
+
if (cached)
|
|
672
|
+
return cached;
|
|
673
|
+
const probe = probeServerReachability(baseUrl, authToken);
|
|
674
|
+
serverReachabilityCache.set(key, probe);
|
|
675
|
+
return probe;
|
|
676
|
+
}
|
|
677
|
+
function describeSelectedServer(projectRoot, server) {
|
|
678
|
+
try {
|
|
679
|
+
const selected = resolveSelectedConnection(projectRoot);
|
|
680
|
+
if (selected) {
|
|
681
|
+
return {
|
|
682
|
+
alias: selected.alias,
|
|
683
|
+
target: selected.connection.kind === "remote" ? selected.connection.baseUrl : server.baseUrl
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
} catch {}
|
|
687
|
+
return { alias: server.connectionKind === "remote" ? "remote" : "local", target: server.baseUrl };
|
|
688
|
+
}
|
|
689
|
+
async function buildServerFailureContext(projectRoot, server) {
|
|
690
|
+
const { alias, target } = describeSelectedServer(projectRoot, server);
|
|
691
|
+
const reachable = await cachedServerReachability(projectRoot, server.baseUrl, server.authToken);
|
|
692
|
+
const reachability = reachable ? "server is reachable" : "server is unreachable";
|
|
693
|
+
return {
|
|
694
|
+
contextLine: `Currently connected to: ${alias} at ${target} (${reachability}).`,
|
|
695
|
+
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
696
|
+
};
|
|
697
|
+
}
|
|
631
698
|
async function requestServerJson(context, pathname, init = {}) {
|
|
632
699
|
const server = await ensureServerForCli(context.projectRoot);
|
|
633
700
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
634
701
|
if (server.serverProjectRoot)
|
|
635
702
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
703
|
+
let response;
|
|
704
|
+
try {
|
|
705
|
+
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
706
|
+
...init,
|
|
707
|
+
headers
|
|
708
|
+
});
|
|
709
|
+
} catch (error) {
|
|
710
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
711
|
+
throw new CliError(`Rig server request failed: ${error instanceof Error ? error.message : String(error)}
|
|
712
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
713
|
+
}
|
|
640
714
|
const text = await response.text();
|
|
641
715
|
const payload = text.trim().length > 0 ? (() => {
|
|
642
716
|
try {
|
|
@@ -648,7 +722,9 @@ async function requestServerJson(context, pathname, init = {}) {
|
|
|
648
722
|
if (!response.ok) {
|
|
649
723
|
const diagnostics = diagnosticMessage(payload);
|
|
650
724
|
const detail = diagnostics ?? (text || response.statusText);
|
|
651
|
-
|
|
725
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
726
|
+
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
727
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
652
728
|
}
|
|
653
729
|
return payload;
|
|
654
730
|
}
|
|
@@ -1164,7 +1240,7 @@ function parsePositiveInt(value, option, fallback) {
|
|
|
1164
1240
|
}
|
|
1165
1241
|
const parsed = Number.parseInt(value, 10);
|
|
1166
1242
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
1167
|
-
throw new
|
|
1243
|
+
throw new CliError(`Invalid ${option} value: ${value}`, 1, { hint: `Pass a positive integer, e.g. \`${option} 10\`.` });
|
|
1168
1244
|
}
|
|
1169
1245
|
return parsed;
|
|
1170
1246
|
}
|
|
@@ -1581,8 +1657,8 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
1581
1657
|
runtimeAdapter: input.runtimeAdapter,
|
|
1582
1658
|
status: resumeMode ? "preparing" : "created"
|
|
1583
1659
|
});
|
|
1660
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "preparing", { reason: "driver-start" });
|
|
1584
1661
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
1585
|
-
status: "preparing",
|
|
1586
1662
|
startedAt,
|
|
1587
1663
|
completedAt: null,
|
|
1588
1664
|
errorText: null,
|
|
@@ -1720,7 +1796,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
1720
1796
|
if (verificationStarted)
|
|
1721
1797
|
return;
|
|
1722
1798
|
verificationStarted = true;
|
|
1723
|
-
|
|
1799
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "validating");
|
|
1724
1800
|
emitServerRunEvent({ type: "status", runId: input.runId, status: "validating", detail: detail ?? null, ...sessionAnchor() });
|
|
1725
1801
|
verificationAction = startRunAction(context.projectRoot, input.runId, {
|
|
1726
1802
|
actionId: `action:${input.runId}:completion-verification`,
|
|
@@ -1733,7 +1809,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
1733
1809
|
if (reviewStarted)
|
|
1734
1810
|
return;
|
|
1735
1811
|
reviewStarted = true;
|
|
1736
|
-
|
|
1812
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "reviewing");
|
|
1737
1813
|
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: detail ?? null, ...sessionAnchor() });
|
|
1738
1814
|
reviewAction = startRunAction(context.projectRoot, input.runId, {
|
|
1739
1815
|
actionId: `action:${input.runId}:review-closeout`,
|
|
@@ -1767,8 +1843,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
1767
1843
|
logsDir: latestLogsDir,
|
|
1768
1844
|
contextFile: payload.contextFile ?? null
|
|
1769
1845
|
});
|
|
1846
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "running");
|
|
1770
1847
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
1771
|
-
status: "running",
|
|
1772
1848
|
worktreePath: latestRuntimeWorkspace,
|
|
1773
1849
|
artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve6(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
|
|
1774
1850
|
logRoot: latestLogsDir,
|
|
@@ -2258,7 +2334,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
2258
2334
|
}
|
|
2259
2335
|
process.off("SIGTERM", forwardSigterm);
|
|
2260
2336
|
if (attemptExit.error) {
|
|
2261
|
-
throw new
|
|
2337
|
+
throw new CliError(`Task run failed to start: ${attemptExit.error.message}`, 1);
|
|
2262
2338
|
}
|
|
2263
2339
|
const retryContext = resolveTaskRunRetryContext({
|
|
2264
2340
|
projectRoot: context.projectRoot,
|
|
@@ -2280,8 +2356,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
2280
2356
|
currentPrompt = [retryContext.nextPrompt, "", "Rig Pi steering message:", retrySteering].join(`
|
|
2281
2357
|
`);
|
|
2282
2358
|
reviewFailureDetail = failureDetail;
|
|
2359
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "validating", { reason: "validation-retry" });
|
|
2283
2360
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
2284
|
-
status: "validating",
|
|
2285
2361
|
completedAt: null,
|
|
2286
2362
|
errorText: null
|
|
2287
2363
|
});
|
|
@@ -2317,10 +2393,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
2317
2393
|
break;
|
|
2318
2394
|
}
|
|
2319
2395
|
if (!exit) {
|
|
2320
|
-
throw new
|
|
2396
|
+
throw new CliError(`Task run for ${runtimeTaskId} exhausted ${maxAttempts} attempts without a terminal result.`, 1);
|
|
2321
2397
|
}
|
|
2322
2398
|
if (exit.error) {
|
|
2323
|
-
throw new
|
|
2399
|
+
throw new CliError(`Task run failed to start: ${exit.error.message}`, 1);
|
|
2324
2400
|
}
|
|
2325
2401
|
if (assistantText.trim()) {
|
|
2326
2402
|
appendRunTimeline(context.projectRoot, input.runId, {
|
|
@@ -2347,9 +2423,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
2347
2423
|
reviewAction.fail(failureDetail);
|
|
2348
2424
|
}
|
|
2349
2425
|
let terminalFailureDetail = failureDetail;
|
|
2350
|
-
const terminalRunStatus = reviewFailureDetail ? "
|
|
2426
|
+
const terminalRunStatus = reviewFailureDetail ? "needs-attention" : "failed";
|
|
2351
2427
|
try {
|
|
2352
|
-
await updateTaskSourceAfterDriverRun(context.projectRoot, input.runId, input.taskId, sourceTask, "failed", terminalRunStatus === "
|
|
2428
|
+
await updateTaskSourceAfterDriverRun(context.projectRoot, input.runId, input.taskId, sourceTask, "failed", terminalRunStatus === "needs-attention" ? "Rig task run needs attention." : "Rig task run failed.", {
|
|
2353
2429
|
latestRuntimeWorkspace,
|
|
2354
2430
|
latestLogsDir,
|
|
2355
2431
|
latestSessionDir,
|
|
@@ -2359,14 +2435,14 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
2359
2435
|
terminalFailureDetail = `${failureDetail}
|
|
2360
2436
|
Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
2361
2437
|
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
completedAt: failedAt,
|
|
2438
|
+
setRunStatusOrFail(context.projectRoot, input.runId, terminalRunStatus, {
|
|
2439
|
+
reason: "driver-terminal-failure",
|
|
2365
2440
|
errorText: terminalFailureDetail
|
|
2366
2441
|
});
|
|
2442
|
+
patchAuthorityRun(context.projectRoot, input.runId, { completedAt: failedAt });
|
|
2367
2443
|
appendRunLog(context.projectRoot, input.runId, {
|
|
2368
2444
|
id: `log:${input.runId}:${terminalRunStatus}`,
|
|
2369
|
-
title: terminalRunStatus === "
|
|
2445
|
+
title: terminalRunStatus === "needs-attention" ? "Task run needs attention" : "Task run failed",
|
|
2370
2446
|
detail: terminalFailureDetail,
|
|
2371
2447
|
tone: "error",
|
|
2372
2448
|
status: terminalRunStatus,
|
|
@@ -2377,7 +2453,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2377
2453
|
runId: input.runId,
|
|
2378
2454
|
error: terminalFailureDetail
|
|
2379
2455
|
});
|
|
2380
|
-
throw new
|
|
2456
|
+
throw new CliError(terminalFailureDetail, exit.code ?? 1);
|
|
2381
2457
|
}
|
|
2382
2458
|
if (planningClassification.planningRequired) {
|
|
2383
2459
|
const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
|
|
@@ -2385,11 +2461,11 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2385
2461
|
if (!existsSync4(expectedPlanPath)) {
|
|
2386
2462
|
const failedAt = new Date().toISOString();
|
|
2387
2463
|
const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
completedAt: failedAt,
|
|
2464
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "needs-attention", {
|
|
2465
|
+
reason: "plan-artifact-missing",
|
|
2391
2466
|
errorText: failureDetail
|
|
2392
2467
|
});
|
|
2468
|
+
patchAuthorityRun(context.projectRoot, input.runId, { completedAt: failedAt });
|
|
2393
2469
|
appendRunLog(context.projectRoot, input.runId, {
|
|
2394
2470
|
id: `log:${input.runId}:plan-artifact-missing`,
|
|
2395
2471
|
title: "Required plan artifact missing",
|
|
@@ -2399,7 +2475,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2399
2475
|
createdAt: failedAt
|
|
2400
2476
|
});
|
|
2401
2477
|
emitServerRunEvent({ type: "failed", runId: input.runId, error: failureDetail });
|
|
2402
|
-
throw new
|
|
2478
|
+
throw new CliError(failureDetail, 1);
|
|
2403
2479
|
}
|
|
2404
2480
|
}
|
|
2405
2481
|
if (process.env.RIG_SERVER_OWNS_CLOSEOUT === "1") {
|
|
@@ -2420,14 +2496,13 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2420
2496
|
reviewAction.complete("Provider work accepted; server-owned closeout requested.");
|
|
2421
2497
|
}
|
|
2422
2498
|
const requestedAt = new Date().toISOString();
|
|
2499
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "closing-out", { reason: "server-closeout-requested" });
|
|
2423
2500
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
2424
|
-
status: "reviewing",
|
|
2425
2501
|
completedAt: null,
|
|
2426
2502
|
errorText: null,
|
|
2427
2503
|
serverCloseout: {
|
|
2428
2504
|
status: "pending",
|
|
2429
2505
|
phase: "queued",
|
|
2430
|
-
requestedAt,
|
|
2431
2506
|
updatedAt: requestedAt,
|
|
2432
2507
|
runtimeWorkspace: latestRuntimeWorkspace,
|
|
2433
2508
|
branch: latestRuntimeBranch,
|
|
@@ -2444,7 +2519,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2444
2519
|
payload: { runtimeWorkspace: latestRuntimeWorkspace, branch: latestRuntimeBranch }
|
|
2445
2520
|
});
|
|
2446
2521
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Server-owned closeout requested" });
|
|
2447
|
-
emitServerRunEvent({ type: "status", runId: input.runId, status: "
|
|
2522
|
+
emitServerRunEvent({ type: "status", runId: input.runId, status: "closing-out", detail: "Server-owned closeout requested.", ...sessionAnchor() });
|
|
2448
2523
|
await context.emitEvent("command.finished", {
|
|
2449
2524
|
command: [
|
|
2450
2525
|
"rig",
|
|
@@ -2612,25 +2687,25 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2612
2687
|
const failureDetail = postValidation.pr?.actionableFeedback.join(`
|
|
2613
2688
|
`) || "PR automation needs attention.";
|
|
2614
2689
|
const failedAt = new Date().toISOString();
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
completedAt: failedAt,
|
|
2690
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "needs-attention", {
|
|
2691
|
+
reason: "pr-automation-needs-attention",
|
|
2618
2692
|
errorText: failureDetail
|
|
2619
2693
|
});
|
|
2694
|
+
patchAuthorityRun(context.projectRoot, input.runId, { completedAt: failedAt });
|
|
2620
2695
|
emitServerRunEvent({ type: "failed", runId: input.runId, error: failureDetail });
|
|
2621
|
-
throw new
|
|
2696
|
+
throw new CliError(failureDetail, 1);
|
|
2622
2697
|
}
|
|
2623
2698
|
} catch (error) {
|
|
2624
|
-
if (error instanceof
|
|
2699
|
+
if (error instanceof CliError) {
|
|
2625
2700
|
throw error;
|
|
2626
2701
|
}
|
|
2627
2702
|
const failureDetail = `Failed to complete PR/issue closeout for ${input.taskId ?? runtimeTaskId}: ${error instanceof Error ? error.message : String(error)}`;
|
|
2628
2703
|
const failedAt = new Date().toISOString();
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
completedAt: failedAt,
|
|
2704
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "failed", {
|
|
2705
|
+
reason: "pr-closeout-failed",
|
|
2632
2706
|
errorText: failureDetail
|
|
2633
2707
|
});
|
|
2708
|
+
patchAuthorityRun(context.projectRoot, input.runId, { completedAt: failedAt });
|
|
2634
2709
|
appendRunLog(context.projectRoot, input.runId, {
|
|
2635
2710
|
id: `log:${input.runId}:pr-closeout-failed`,
|
|
2636
2711
|
title: "PR/issue closeout failed",
|
|
@@ -2640,7 +2715,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2640
2715
|
createdAt: failedAt
|
|
2641
2716
|
});
|
|
2642
2717
|
emitServerRunEvent({ type: "failed", runId: input.runId, error: failureDetail });
|
|
2643
|
-
throw new
|
|
2718
|
+
throw new CliError(failureDetail, 1);
|
|
2644
2719
|
}
|
|
2645
2720
|
if (verificationAction && !reviewStarted) {
|
|
2646
2721
|
verificationAction.complete("Completion verification checks finished.");
|
|
@@ -2651,10 +2726,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
2651
2726
|
if (reviewAction) {
|
|
2652
2727
|
reviewAction.complete("Run marked completed.");
|
|
2653
2728
|
}
|
|
2654
|
-
|
|
2655
|
-
status: "completed",
|
|
2656
|
-
completedAt: new Date().toISOString()
|
|
2657
|
-
});
|
|
2729
|
+
setRunStatusOrFail(context.projectRoot, input.runId, "completed", { reason: "driver-completed" });
|
|
2658
2730
|
emitServerRunEvent({ type: "completed", runId: input.runId });
|
|
2659
2731
|
await context.emitEvent("command.finished", {
|
|
2660
2732
|
command: [
|