@h-rig/cli 0.0.6-alpha.64 → 0.0.6-alpha.65
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
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// packages/cli/src/commands/inbox.ts
|
|
3
|
-
import { writeFileSync as writeFileSync2 } from "fs";
|
|
4
|
-
import { resolve as resolve3 } from "path";
|
|
5
|
-
|
|
6
2
|
// packages/cli/src/runner.ts
|
|
7
3
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
8
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
4
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
9
5
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
10
6
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
11
|
-
|
|
7
|
+
|
|
8
|
+
class CliError extends RuntimeCliError {
|
|
9
|
+
hint;
|
|
10
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
11
|
+
super(message, exitCode);
|
|
12
|
+
if (options.hint?.trim()) {
|
|
13
|
+
this.hint = options.hint.trim();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
12
17
|
function takeOption(args, option) {
|
|
13
18
|
const rest = [];
|
|
14
19
|
let value;
|
|
@@ -17,7 +22,7 @@ function takeOption(args, option) {
|
|
|
17
22
|
if (current === option) {
|
|
18
23
|
const next = args[index + 1];
|
|
19
24
|
if (!next || next.startsWith("-")) {
|
|
20
|
-
throw new CliError(`Missing value for ${option}`);
|
|
25
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
21
26
|
}
|
|
22
27
|
value = next;
|
|
23
28
|
index += 1;
|
|
@@ -36,13 +41,6 @@ Usage: ${usage}`);
|
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
// packages/cli/src/commands/inbox.ts
|
|
40
|
-
import {
|
|
41
|
-
listAuthorityRuns,
|
|
42
|
-
readJsonlFile,
|
|
43
|
-
resolveAuthorityRunDir
|
|
44
|
-
} from "@rig/runtime/control-plane/authority-files";
|
|
45
|
-
|
|
46
44
|
// packages/cli/src/commands/_cli-format.ts
|
|
47
45
|
import { log, note } from "@clack/prompts";
|
|
48
46
|
import pc from "picocolors";
|
|
@@ -125,6 +123,11 @@ function formatInboxList(kind, entries) {
|
|
|
125
123
|
`);
|
|
126
124
|
}
|
|
127
125
|
|
|
126
|
+
// packages/cli/src/commands/_server-client.ts
|
|
127
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
128
|
+
import { resolve as resolve2 } from "path";
|
|
129
|
+
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
130
|
+
|
|
128
131
|
// packages/cli/src/commands/_connection-state.ts
|
|
129
132
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
130
133
|
import { homedir } from "os";
|
|
@@ -147,7 +150,7 @@ function readJsonFile(path) {
|
|
|
147
150
|
try {
|
|
148
151
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
149
152
|
} catch (error) {
|
|
150
|
-
throw new
|
|
153
|
+
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>`." });
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
156
|
function writeJsonFile(path, value) {
|
|
@@ -211,7 +214,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
211
214
|
const global = readGlobalConnections(options);
|
|
212
215
|
const connection = global.connections[repo.selected];
|
|
213
216
|
if (!connection) {
|
|
214
|
-
throw new
|
|
217
|
+
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
215
218
|
}
|
|
216
219
|
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
217
220
|
}
|
|
@@ -223,9 +226,6 @@ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
|
223
226
|
}
|
|
224
227
|
|
|
225
228
|
// packages/cli/src/commands/_server-client.ts
|
|
226
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
227
|
-
import { resolve as resolve2 } from "path";
|
|
228
|
-
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
229
229
|
var scopedGitHubBearerTokens = new Map;
|
|
230
230
|
function cleanToken(value) {
|
|
231
231
|
const trimmed = value?.trim();
|
|
@@ -287,7 +287,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
287
287
|
};
|
|
288
288
|
} catch (error) {
|
|
289
289
|
if (error instanceof Error) {
|
|
290
|
-
throw new
|
|
290
|
+
throw new CliError(error.message, 1);
|
|
291
291
|
}
|
|
292
292
|
throw error;
|
|
293
293
|
}
|
|
@@ -337,15 +337,64 @@ function diagnosticMessage(payload) {
|
|
|
337
337
|
});
|
|
338
338
|
return messages.length > 0 ? messages.join("; ") : null;
|
|
339
339
|
}
|
|
340
|
+
var serverReachabilityCache = new Map;
|
|
341
|
+
async function probeServerReachability(baseUrl, authToken) {
|
|
342
|
+
try {
|
|
343
|
+
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/server/status`, {
|
|
344
|
+
headers: mergeHeaders(undefined, authToken),
|
|
345
|
+
signal: AbortSignal.timeout(1500)
|
|
346
|
+
});
|
|
347
|
+
return response.ok;
|
|
348
|
+
} catch {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function cachedServerReachability(projectRoot, baseUrl, authToken) {
|
|
353
|
+
const key = resolve2(projectRoot);
|
|
354
|
+
const cached = serverReachabilityCache.get(key);
|
|
355
|
+
if (cached)
|
|
356
|
+
return cached;
|
|
357
|
+
const probe = probeServerReachability(baseUrl, authToken);
|
|
358
|
+
serverReachabilityCache.set(key, probe);
|
|
359
|
+
return probe;
|
|
360
|
+
}
|
|
361
|
+
function describeSelectedServer(projectRoot, server) {
|
|
362
|
+
try {
|
|
363
|
+
const selected = resolveSelectedConnection(projectRoot);
|
|
364
|
+
if (selected) {
|
|
365
|
+
return {
|
|
366
|
+
alias: selected.alias,
|
|
367
|
+
target: selected.connection.kind === "remote" ? selected.connection.baseUrl : server.baseUrl
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
} catch {}
|
|
371
|
+
return { alias: server.connectionKind === "remote" ? "remote" : "local", target: server.baseUrl };
|
|
372
|
+
}
|
|
373
|
+
async function buildServerFailureContext(projectRoot, server) {
|
|
374
|
+
const { alias, target } = describeSelectedServer(projectRoot, server);
|
|
375
|
+
const reachable = await cachedServerReachability(projectRoot, server.baseUrl, server.authToken);
|
|
376
|
+
const reachability = reachable ? "server is reachable" : "server is unreachable";
|
|
377
|
+
return {
|
|
378
|
+
contextLine: `Currently connected to: ${alias} at ${target} (${reachability}).`,
|
|
379
|
+
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
380
|
+
};
|
|
381
|
+
}
|
|
340
382
|
async function requestServerJson(context, pathname, init = {}) {
|
|
341
383
|
const server = await ensureServerForCli(context.projectRoot);
|
|
342
384
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
343
385
|
if (server.serverProjectRoot)
|
|
344
386
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
387
|
+
let response;
|
|
388
|
+
try {
|
|
389
|
+
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
390
|
+
...init,
|
|
391
|
+
headers
|
|
392
|
+
});
|
|
393
|
+
} catch (error) {
|
|
394
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
395
|
+
throw new CliError(`Rig server request failed: ${error instanceof Error ? error.message : String(error)}
|
|
396
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
397
|
+
}
|
|
349
398
|
const text = await response.text();
|
|
350
399
|
const payload = text.trim().length > 0 ? (() => {
|
|
351
400
|
try {
|
|
@@ -357,77 +406,106 @@ async function requestServerJson(context, pathname, init = {}) {
|
|
|
357
406
|
if (!response.ok) {
|
|
358
407
|
const diagnostics = diagnosticMessage(payload);
|
|
359
408
|
const detail = diagnostics ?? (text || response.statusText);
|
|
360
|
-
|
|
409
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
410
|
+
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
411
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
361
412
|
}
|
|
362
413
|
return payload;
|
|
363
414
|
}
|
|
364
|
-
async function listRunsViaServer(context, options = {}) {
|
|
365
|
-
const url = new URL("http://rig.local/api/runs");
|
|
366
|
-
if (options.limit !== undefined)
|
|
367
|
-
url.searchParams.set("limit", String(options.limit));
|
|
368
|
-
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
369
|
-
const runs = Array.isArray(payload) ? payload : payload && typeof payload === "object" && !Array.isArray(payload) && Array.isArray(payload.runs) ? payload.runs : [];
|
|
370
|
-
return runs.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
371
|
-
}
|
|
372
|
-
async function getRunDetailsViaServer(context, runId) {
|
|
373
|
-
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}`);
|
|
374
|
-
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
375
|
-
}
|
|
376
415
|
|
|
377
416
|
// packages/cli/src/commands/inbox.ts
|
|
378
|
-
function
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
417
|
+
async function listInboxRecords(context, kind, filters) {
|
|
418
|
+
const params = new URLSearchParams;
|
|
419
|
+
if (filters.run)
|
|
420
|
+
params.set("runId", filters.run);
|
|
421
|
+
if (filters.task)
|
|
422
|
+
params.set("taskId", filters.task);
|
|
423
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
424
|
+
const payload = await requestServerJson(context, `/api/inbox/${kind}${query}`);
|
|
425
|
+
const records = Array.isArray(payload) ? payload : [];
|
|
426
|
+
return filters.pendingOnly ? records.filter((entry) => (entry.status ?? "pending") !== "resolved") : records;
|
|
427
|
+
}
|
|
428
|
+
async function readPendingInboxCounts(context) {
|
|
429
|
+
try {
|
|
430
|
+
const [approvals, inputs] = await Promise.all([
|
|
431
|
+
listInboxRecords(context, "approvals", { pendingOnly: true }),
|
|
432
|
+
listInboxRecords(context, "inputs", { pendingOnly: true })
|
|
433
|
+
]);
|
|
434
|
+
return { approvals: approvals.length, inputs: inputs.length };
|
|
435
|
+
} catch {
|
|
436
|
+
return null;
|
|
395
437
|
}
|
|
396
|
-
return payload;
|
|
397
438
|
}
|
|
398
|
-
function
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
439
|
+
async function printPendingInboxFooter(context) {
|
|
440
|
+
if (context.outputMode !== "text")
|
|
441
|
+
return;
|
|
442
|
+
const counts = await readPendingInboxCounts(context);
|
|
443
|
+
if (!counts || counts.approvals === 0 && counts.inputs === 0)
|
|
444
|
+
return;
|
|
445
|
+
const parts = [];
|
|
446
|
+
if (counts.approvals > 0)
|
|
447
|
+
parts.push(`${counts.approvals} approval${counts.approvals === 1 ? "" : "s"}`);
|
|
448
|
+
if (counts.inputs > 0)
|
|
449
|
+
parts.push(`${counts.inputs} input request${counts.inputs === 1 ? "" : "s"}`);
|
|
450
|
+
console.log(`
|
|
451
|
+
\u26A0 ${parts.join(" and ")} pending \u2014 run \`rig inbox\` to review.`);
|
|
452
|
+
}
|
|
453
|
+
function renderList(context, kind, records) {
|
|
454
|
+
if (context.outputMode === "text") {
|
|
455
|
+
printFormattedOutput(formatInboxList(kind, records));
|
|
414
456
|
}
|
|
415
|
-
return records;
|
|
416
457
|
}
|
|
417
|
-
function
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
458
|
+
async function watchInbox(context, filters) {
|
|
459
|
+
const render = async () => {
|
|
460
|
+
const [approvals, inputs] = await Promise.all([
|
|
461
|
+
listInboxRecords(context, "approvals", { ...filters, pendingOnly: true }),
|
|
462
|
+
listInboxRecords(context, "inputs", { ...filters, pendingOnly: true })
|
|
463
|
+
]);
|
|
464
|
+
console.clear();
|
|
465
|
+
console.log(`rig inbox \u2014 watching (Ctrl-C to stop) \u2014 ${new Date().toLocaleTimeString()}`);
|
|
466
|
+
renderList(context, "approvals", approvals);
|
|
467
|
+
renderList(context, "inputs", inputs);
|
|
468
|
+
if (approvals.length === 0 && inputs.length === 0) {
|
|
469
|
+
console.log("Nothing pending.");
|
|
470
|
+
} else {
|
|
471
|
+
console.log(`
|
|
472
|
+
Resolve with: rig inbox approve --run <id> --request <id> --decision approve|reject`);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
await render();
|
|
476
|
+
const server = await ensureServerForCli(context.projectRoot);
|
|
477
|
+
const relevant = /"type":"rig\.(approval|user-input)\./;
|
|
478
|
+
const fallbackTimer = setInterval(() => {
|
|
479
|
+
render();
|
|
480
|
+
}, 30000);
|
|
481
|
+
fallbackTimer.unref?.();
|
|
482
|
+
for (;; ) {
|
|
483
|
+
try {
|
|
484
|
+
const response = await fetch(`${server.baseUrl}/api/server/events`, {
|
|
485
|
+
headers: {
|
|
486
|
+
...server.authToken ? { authorization: `Bearer ${server.authToken}` } : {},
|
|
487
|
+
...server.serverProjectRoot ? { "x-rig-project-root": server.serverProjectRoot } : {},
|
|
488
|
+
accept: "text/event-stream"
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
if (!response.ok || !response.body)
|
|
492
|
+
throw new Error(`SSE ${response.status}`);
|
|
493
|
+
const reader = response.body.getReader();
|
|
494
|
+
const decoder = new TextDecoder;
|
|
495
|
+
for (;; ) {
|
|
496
|
+
const { done, value } = await reader.read();
|
|
497
|
+
if (done)
|
|
498
|
+
break;
|
|
499
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
500
|
+
if (relevant.test(chunk)) {
|
|
501
|
+
await render();
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
} catch {
|
|
505
|
+
await render();
|
|
506
|
+
await new Promise((resolveSleep) => setTimeout(resolveSleep, 2000));
|
|
507
|
+
}
|
|
429
508
|
}
|
|
430
|
-
return listLocalInboxRecords(context, kind, filters);
|
|
431
509
|
}
|
|
432
510
|
async function executeInbox(context, args) {
|
|
433
511
|
const [command = "approvals", ...rest] = args;
|
|
@@ -440,11 +518,20 @@ async function executeInbox(context, args) {
|
|
|
440
518
|
pending = task.rest;
|
|
441
519
|
requireNoExtraArgs(pending, "rig inbox approvals [--run <id>] [--task <id>]");
|
|
442
520
|
const approvals = await listInboxRecords(context, "approvals", { run: run.value, task: task.value });
|
|
443
|
-
|
|
444
|
-
printFormattedOutput(formatInboxList("approvals", approvals));
|
|
445
|
-
}
|
|
521
|
+
renderList(context, "approvals", approvals);
|
|
446
522
|
return { ok: true, group: "inbox", command, details: { approvals } };
|
|
447
523
|
}
|
|
524
|
+
case "inputs": {
|
|
525
|
+
let pending = rest;
|
|
526
|
+
const run = takeOption(pending, "--run");
|
|
527
|
+
pending = run.rest;
|
|
528
|
+
const task = takeOption(pending, "--task");
|
|
529
|
+
pending = task.rest;
|
|
530
|
+
requireNoExtraArgs(pending, "rig inbox inputs [--run <id>] [--task <id>]");
|
|
531
|
+
const requests = await listInboxRecords(context, "inputs", { run: run.value, task: task.value });
|
|
532
|
+
renderList(context, "inputs", requests);
|
|
533
|
+
return { ok: true, group: "inbox", command, details: { requests } };
|
|
534
|
+
}
|
|
448
535
|
case "approve": {
|
|
449
536
|
let pending = rest;
|
|
450
537
|
const run = takeOption(pending, "--run");
|
|
@@ -457,35 +544,22 @@ async function executeInbox(context, args) {
|
|
|
457
544
|
pending = note2.rest;
|
|
458
545
|
requireNoExtraArgs(pending, "rig inbox approve --run <id> --request <id> --decision approve|reject [--note <text>]");
|
|
459
546
|
if (!run.value || !request.value || !decision.value) {
|
|
460
|
-
throw new
|
|
547
|
+
throw new CliError("approve requires --run, --request, and --decision. List pending requests with `rig inbox approvals`.");
|
|
461
548
|
}
|
|
462
549
|
if (decision.value !== "approve" && decision.value !== "reject") {
|
|
463
|
-
throw new
|
|
464
|
-
}
|
|
465
|
-
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
466
|
-
throw new CliError2("Remote approval resolution is not available from this CLI yet; use the server UI/API or switch to local state for direct JSONL edits.", 2);
|
|
550
|
+
throw new CliError("decision must be approve or reject.", 1, { hint: "Re-run as `rig inbox approve --run <id> --request <id> --decision approve|reject`." });
|
|
467
551
|
}
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
const run = takeOption(pending, "--run");
|
|
480
|
-
pending = run.rest;
|
|
481
|
-
const task = takeOption(pending, "--task");
|
|
482
|
-
pending = task.rest;
|
|
483
|
-
requireNoExtraArgs(pending, "rig inbox inputs [--run <id>] [--task <id>]");
|
|
484
|
-
const requests = await listInboxRecords(context, "inputs", { run: run.value, task: task.value });
|
|
485
|
-
if (context.outputMode === "text") {
|
|
486
|
-
printFormattedOutput(formatInboxList("inputs", requests));
|
|
487
|
-
}
|
|
488
|
-
return { ok: true, group: "inbox", command, details: { requests } };
|
|
552
|
+
const result = await requestServerJson(context, "/api/inbox/approvals/resolve", {
|
|
553
|
+
method: "POST",
|
|
554
|
+
headers: { "content-type": "application/json" },
|
|
555
|
+
body: JSON.stringify({
|
|
556
|
+
runId: run.value,
|
|
557
|
+
requestId: request.value,
|
|
558
|
+
decision: decision.value,
|
|
559
|
+
note: note2.value ?? null
|
|
560
|
+
})
|
|
561
|
+
});
|
|
562
|
+
return { ok: true, group: "inbox", command, details: { result } };
|
|
489
563
|
}
|
|
490
564
|
case "respond": {
|
|
491
565
|
let pending = rest;
|
|
@@ -498,11 +572,11 @@ async function executeInbox(context, args) {
|
|
|
498
572
|
for (let index = 0;index < pending.length; index += 1) {
|
|
499
573
|
const current = pending[index];
|
|
500
574
|
if (current === "--answer") {
|
|
501
|
-
const
|
|
502
|
-
if (!
|
|
503
|
-
throw new
|
|
575
|
+
const next = pending[index + 1];
|
|
576
|
+
if (!next || next.startsWith("-")) {
|
|
577
|
+
throw new CliError("Missing value for --answer", 1, { hint: "Pass key=value pairs, e.g. `rig inbox respond --run <id> --request <id> --answer key=value`." });
|
|
504
578
|
}
|
|
505
|
-
answers.push(
|
|
579
|
+
answers.push(next);
|
|
506
580
|
index += 1;
|
|
507
581
|
continue;
|
|
508
582
|
}
|
|
@@ -512,28 +586,38 @@ async function executeInbox(context, args) {
|
|
|
512
586
|
}
|
|
513
587
|
requireNoExtraArgs(remaining, "rig inbox respond --run <id> --request <id> --answer key=value [--answer key=value]");
|
|
514
588
|
if (!run.value || !request.value || answers.length === 0) {
|
|
515
|
-
throw new
|
|
516
|
-
}
|
|
517
|
-
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
518
|
-
throw new CliError2("Remote input responses are not available from this CLI yet; use the server UI/API or switch to local state for direct JSONL edits.", 2);
|
|
589
|
+
throw new CliError("respond requires --run, --request, and at least one --answer. List pending requests with `rig inbox inputs`.");
|
|
519
590
|
}
|
|
520
591
|
const parsedAnswers = Object.fromEntries(answers.map((entry) => {
|
|
521
592
|
const [key, ...restValue] = entry.split("=");
|
|
522
593
|
return [key, restValue.join("=")];
|
|
523
594
|
}));
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
595
|
+
const result = await requestServerJson(context, "/api/inbox/inputs/respond", {
|
|
596
|
+
method: "POST",
|
|
597
|
+
headers: { "content-type": "application/json" },
|
|
598
|
+
body: JSON.stringify({
|
|
599
|
+
runId: run.value,
|
|
600
|
+
requestId: request.value,
|
|
601
|
+
answers: parsedAnswers
|
|
602
|
+
})
|
|
603
|
+
});
|
|
604
|
+
return { ok: true, group: "inbox", command, details: { result } };
|
|
605
|
+
}
|
|
606
|
+
case "watch": {
|
|
607
|
+
let pending = rest;
|
|
608
|
+
const run = takeOption(pending, "--run");
|
|
609
|
+
pending = run.rest;
|
|
610
|
+
const task = takeOption(pending, "--task");
|
|
611
|
+
pending = task.rest;
|
|
612
|
+
requireNoExtraArgs(pending, "rig inbox watch [--run <id>] [--task <id>]");
|
|
613
|
+
return await watchInbox(context, { run: run.value, task: task.value });
|
|
532
614
|
}
|
|
533
615
|
default:
|
|
534
|
-
throw new
|
|
616
|
+
throw new CliError(`Unknown inbox command: ${command}. Use approvals|inputs|approve|respond|watch.`);
|
|
535
617
|
}
|
|
536
618
|
}
|
|
537
619
|
export {
|
|
620
|
+
readPendingInboxCounts,
|
|
621
|
+
printPendingInboxFooter,
|
|
538
622
|
executeInbox
|
|
539
623
|
};
|