@h-rig/cli 0.0.6-alpha.60 → 0.0.6-alpha.61
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 +316 -134
- package/dist/src/commands/_authority-runs.js +2 -3
- package/dist/src/commands/_help-catalog.js +1 -0
- package/dist/src/commands/_run-driver-helpers.js +12 -17
- package/dist/src/commands/_run-replay.js +142 -0
- package/dist/src/commands/agent.js +2 -3
- package/dist/src/commands/run.js +216 -38
- package/dist/src/commands/server.js +4 -5
- package/dist/src/commands/task-run-driver.js +29 -26
- package/dist/src/commands/task.js +4 -4
- package/dist/src/commands.js +308 -126
- package/dist/src/index.js +316 -134
- package/package.json +7 -7
package/dist/bin/rig.js
CHANGED
|
@@ -531,10 +531,10 @@ import { loadPolicy as loadPolicy3 } from "@rig/runtime/control-plane/runtime/gu
|
|
|
531
531
|
// packages/cli/src/commands.ts
|
|
532
532
|
init_runner();
|
|
533
533
|
import {
|
|
534
|
-
existsSync as
|
|
534
|
+
existsSync as existsSync17,
|
|
535
535
|
readFileSync as readFileSync12
|
|
536
536
|
} from "fs";
|
|
537
|
-
import { resolve as
|
|
537
|
+
import { resolve as resolve26 } from "path";
|
|
538
538
|
import { readBuildConfig } from "@rig/runtime/build-time-config";
|
|
539
539
|
|
|
540
540
|
// packages/cli/src/commands/browser.ts
|
|
@@ -3621,8 +3621,7 @@ import { resolve as resolve12 } from "path";
|
|
|
3621
3621
|
import {
|
|
3622
3622
|
readAuthorityRun,
|
|
3623
3623
|
readJsonlFile as readJsonlFile2,
|
|
3624
|
-
|
|
3625
|
-
writeJsonFile as writeJsonFile3
|
|
3624
|
+
writeAuthorityRunRecord
|
|
3626
3625
|
} from "@rig/runtime/control-plane/authority-files";
|
|
3627
3626
|
var RIG_WORKSPACE_ID = "rig-local-workspace";
|
|
3628
3627
|
function normalizeRuntimeAdapter(value) {
|
|
@@ -3708,7 +3707,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
|
|
|
3708
3707
|
} else if ("errorText" in next) {
|
|
3709
3708
|
delete next.errorText;
|
|
3710
3709
|
}
|
|
3711
|
-
|
|
3710
|
+
writeAuthorityRunRecord(projectRoot, input.runId, next);
|
|
3712
3711
|
return next;
|
|
3713
3712
|
}
|
|
3714
3713
|
|
|
@@ -4272,7 +4271,7 @@ import { resolve as resolve15 } from "path";
|
|
|
4272
4271
|
import {
|
|
4273
4272
|
listAuthorityRuns,
|
|
4274
4273
|
readJsonlFile as readJsonlFile3,
|
|
4275
|
-
resolveAuthorityRunDir
|
|
4274
|
+
resolveAuthorityRunDir
|
|
4276
4275
|
} from "@rig/runtime/control-plane/authority-files";
|
|
4277
4276
|
|
|
4278
4277
|
// packages/cli/src/commands/_cli-format.ts
|
|
@@ -4670,7 +4669,7 @@ async function listRemoteInboxRecords(context, kind, filters) {
|
|
|
4670
4669
|
function listLocalInboxRecords(context, kind, filters) {
|
|
4671
4670
|
const fileName = kind === "approvals" ? "approvals.jsonl" : "user-input.jsonl";
|
|
4672
4671
|
const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!filters.run || entry.runId === filters.run) && (!filters.task || entry.taskId === filters.task));
|
|
4673
|
-
return runs.flatMap((entry) => readJsonlFile3(resolve15(
|
|
4672
|
+
return runs.flatMap((entry) => readJsonlFile3(resolve15(resolveAuthorityRunDir(context.projectRoot, entry.runId), fileName)).map((record) => ({
|
|
4674
4673
|
runId: entry.runId,
|
|
4675
4674
|
taskId: entry.taskId ?? undefined,
|
|
4676
4675
|
record
|
|
@@ -4718,7 +4717,7 @@ async function executeInbox(context, args) {
|
|
|
4718
4717
|
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
4719
4718
|
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);
|
|
4720
4719
|
}
|
|
4721
|
-
const approvalsPath = resolve15(
|
|
4720
|
+
const approvalsPath = resolve15(resolveAuthorityRunDir(context.projectRoot, run.value), "approvals.jsonl");
|
|
4722
4721
|
const approvals = readJsonlFile3(approvalsPath);
|
|
4723
4722
|
const resolvedAt = new Date().toISOString();
|
|
4724
4723
|
const next = approvals.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", decision: decision.value, note: note4.value ?? null, resolvedAt } : entry);
|
|
@@ -4774,7 +4773,7 @@ async function executeInbox(context, args) {
|
|
|
4774
4773
|
const [key, ...restValue] = entry.split("=");
|
|
4775
4774
|
return [key, restValue.join("=")];
|
|
4776
4775
|
}));
|
|
4777
|
-
const requestsPath = resolve15(
|
|
4776
|
+
const requestsPath = resolve15(resolveAuthorityRunDir(context.projectRoot, run.value), "user-input.jsonl");
|
|
4778
4777
|
const requests = readJsonlFile3(requestsPath);
|
|
4779
4778
|
const resolvedAt = new Date().toISOString();
|
|
4780
4779
|
const next = requests.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", answers: parsedAnswers, respondedAt: resolvedAt, resolvedAt } : entry);
|
|
@@ -6241,27 +6240,23 @@ init_runner();
|
|
|
6241
6240
|
import { readFileSync as readFileSync8 } from "fs";
|
|
6242
6241
|
import { resolve as resolve20 } from "path";
|
|
6243
6242
|
import {
|
|
6244
|
-
appendJsonlRecord as appendJsonlRecord2,
|
|
6245
6243
|
appendRunLifecycleEvent,
|
|
6244
|
+
appendRunLogEntry,
|
|
6245
|
+
appendRunTimelineEntry,
|
|
6246
|
+
patchAuthorityRunRecord,
|
|
6246
6247
|
readAuthorityRun as readAuthorityRun2,
|
|
6247
|
-
resolveAuthorityRunDir as
|
|
6248
|
-
writeJsonFile as
|
|
6248
|
+
resolveAuthorityRunDir as resolveAuthorityRunDir2,
|
|
6249
|
+
writeJsonFile as writeJsonFile3
|
|
6249
6250
|
} from "@rig/runtime/control-plane/authority-files";
|
|
6250
6251
|
import { taskLookup } from "@rig/runtime/control-plane/native/task-ops";
|
|
6251
6252
|
import { readPriorPrProgressPromptSection } from "@rig/runtime/control-plane/prompt-context";
|
|
6252
6253
|
import { buildProviderTaskRunInstructionLines } from "@rig/runtime/control-plane/provider/runtime-instructions";
|
|
6253
6254
|
import { loadRigTaskRunSkillBody } from "@rig/runtime/control-plane/provider/rig-task-run-skill";
|
|
6254
6255
|
function patchAuthorityRun(projectRoot, runId, patch) {
|
|
6255
|
-
const
|
|
6256
|
-
if (!
|
|
6256
|
+
const next = patchAuthorityRunRecord(projectRoot, runId, patch);
|
|
6257
|
+
if (!next) {
|
|
6257
6258
|
throw new CliError2(`Run not found: ${runId}`, 2);
|
|
6258
6259
|
}
|
|
6259
|
-
const next = {
|
|
6260
|
-
...current,
|
|
6261
|
-
...patch,
|
|
6262
|
-
updatedAt: new Date().toISOString()
|
|
6263
|
-
};
|
|
6264
|
-
writeJsonFile4(resolve20(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
|
|
6265
6260
|
return next;
|
|
6266
6261
|
}
|
|
6267
6262
|
function touchAuthorityRun(projectRoot, runId) {
|
|
@@ -6269,21 +6264,21 @@ function touchAuthorityRun(projectRoot, runId) {
|
|
|
6269
6264
|
if (!current) {
|
|
6270
6265
|
return;
|
|
6271
6266
|
}
|
|
6272
|
-
|
|
6267
|
+
writeJsonFile3(resolve20(resolveAuthorityRunDir2(projectRoot, runId), "run.json"), {
|
|
6273
6268
|
...current,
|
|
6274
6269
|
updatedAt: new Date().toISOString()
|
|
6275
6270
|
});
|
|
6276
6271
|
}
|
|
6277
6272
|
function appendRunTimeline(projectRoot, runId, value) {
|
|
6278
|
-
|
|
6273
|
+
appendRunTimelineEntry(projectRoot, runId, value);
|
|
6279
6274
|
touchAuthorityRun(projectRoot, runId);
|
|
6280
6275
|
}
|
|
6281
6276
|
function appendRunLog(projectRoot, runId, value) {
|
|
6282
|
-
|
|
6277
|
+
appendRunLogEntry(projectRoot, runId, value);
|
|
6283
6278
|
touchAuthorityRun(projectRoot, runId);
|
|
6284
6279
|
}
|
|
6285
6280
|
function appendRunAction(projectRoot, runId, value) {
|
|
6286
|
-
|
|
6281
|
+
appendRunTimelineEntry(projectRoot, runId, {
|
|
6287
6282
|
id: value.id,
|
|
6288
6283
|
type: "action",
|
|
6289
6284
|
actionType: value.actionType,
|
|
@@ -6504,7 +6499,7 @@ import { resolve as resolve21 } from "path";
|
|
|
6504
6499
|
import {
|
|
6505
6500
|
listAuthorityRuns as listAuthorityRuns2,
|
|
6506
6501
|
readAuthorityRun as readAuthorityRun3,
|
|
6507
|
-
resolveAuthorityRunDir as
|
|
6502
|
+
resolveAuthorityRunDir as resolveAuthorityRunDir3,
|
|
6508
6503
|
resolveTaskArtifactDirs
|
|
6509
6504
|
} from "@rig/runtime/control-plane/authority-files";
|
|
6510
6505
|
import { changedFilesForTask } from "@rig/runtime/control-plane/native/task-ops";
|
|
@@ -6538,7 +6533,7 @@ async function executeInspect(context, args) {
|
|
|
6538
6533
|
}
|
|
6539
6534
|
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: serverRun.runId, source: "server", entries } };
|
|
6540
6535
|
}
|
|
6541
|
-
const logsPath = resolve21(
|
|
6536
|
+
const logsPath = resolve21(resolveAuthorityRunDir3(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
6542
6537
|
if (!existsSync13(logsPath)) {
|
|
6543
6538
|
throw new CliError2(`No logs found for run ${latestRun.runId}.`);
|
|
6544
6539
|
}
|
|
@@ -7268,7 +7263,7 @@ init__parsers();
|
|
|
7268
7263
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
7269
7264
|
import {
|
|
7270
7265
|
listAuthorityRuns as listAuthorityRuns3,
|
|
7271
|
-
readAuthorityRun as
|
|
7266
|
+
readAuthorityRun as readAuthorityRun5
|
|
7272
7267
|
} from "@rig/runtime/control-plane/authority-files";
|
|
7273
7268
|
import {
|
|
7274
7269
|
cleanupRunState,
|
|
@@ -7284,6 +7279,144 @@ import {
|
|
|
7284
7279
|
} from "@rig/runtime/control-plane/native/run-ops";
|
|
7285
7280
|
import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
|
|
7286
7281
|
|
|
7282
|
+
// packages/cli/src/commands/_run-replay.ts
|
|
7283
|
+
import { existsSync as existsSync14, readdirSync as readdirSync2 } from "fs";
|
|
7284
|
+
import { join as join2, resolve as resolve22 } from "path";
|
|
7285
|
+
import {
|
|
7286
|
+
readAuthorityRun as readAuthorityRun4,
|
|
7287
|
+
readJsonlFile as readJsonlFile4,
|
|
7288
|
+
runLifecycleLogPath
|
|
7289
|
+
} from "@rig/runtime/control-plane/authority-files";
|
|
7290
|
+
function asRecord(value) {
|
|
7291
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7292
|
+
}
|
|
7293
|
+
function text2(value) {
|
|
7294
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
7295
|
+
}
|
|
7296
|
+
function snippet(value, max = 120) {
|
|
7297
|
+
const raw = text2(value);
|
|
7298
|
+
if (!raw)
|
|
7299
|
+
return null;
|
|
7300
|
+
const flat = raw.replace(/\s+/g, " ");
|
|
7301
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
7302
|
+
}
|
|
7303
|
+
function summarizeLifecycleEntry(entry) {
|
|
7304
|
+
const type = text2(entry.type) ?? "event";
|
|
7305
|
+
switch (type) {
|
|
7306
|
+
case "status": {
|
|
7307
|
+
const anchor = text2(entry.sessionId);
|
|
7308
|
+
return [
|
|
7309
|
+
`status \u2192 ${text2(entry.status) ?? "(unknown)"}`,
|
|
7310
|
+
snippet(entry.detail) ? `\u2014 ${snippet(entry.detail)}` : null,
|
|
7311
|
+
anchor ? `[session ${anchor}]` : null
|
|
7312
|
+
].filter(Boolean).join(" ");
|
|
7313
|
+
}
|
|
7314
|
+
case "timeline-entry": {
|
|
7315
|
+
const payload = asRecord(entry.payload) ?? {};
|
|
7316
|
+
const kind = text2(payload.type) ?? "entry";
|
|
7317
|
+
const body = snippet(payload.title) ?? snippet(payload.text) ?? snippet(payload.detail);
|
|
7318
|
+
const state = text2(payload.state);
|
|
7319
|
+
return [`timeline ${kind}`, body ? `\u2014 ${body}` : null, state ? `(${state})` : null].filter(Boolean).join(" ");
|
|
7320
|
+
}
|
|
7321
|
+
case "log-entry": {
|
|
7322
|
+
const payload = asRecord(entry.payload) ?? {};
|
|
7323
|
+
const title = snippet(payload.title) ?? "log";
|
|
7324
|
+
const detail = snippet(payload.detail);
|
|
7325
|
+
return [`log ${title}`, detail ? `\u2014 ${detail}` : null].filter(Boolean).join(" ");
|
|
7326
|
+
}
|
|
7327
|
+
case "record-patch": {
|
|
7328
|
+
const patch = asRecord(entry.patch) ?? {};
|
|
7329
|
+
const keys = Object.keys(patch);
|
|
7330
|
+
const shown = keys.slice(0, 8).join(", ");
|
|
7331
|
+
return `record-patch {${shown}${keys.length > 8 ? `, +${keys.length - 8} more` : ""}}`;
|
|
7332
|
+
}
|
|
7333
|
+
case "timeline":
|
|
7334
|
+
return "timeline updated (signal)";
|
|
7335
|
+
case "log":
|
|
7336
|
+
return `log signal${snippet(entry.title) ? ` \u2014 ${snippet(entry.title)}` : ""}`;
|
|
7337
|
+
case "completed":
|
|
7338
|
+
return "run completed";
|
|
7339
|
+
case "failed":
|
|
7340
|
+
return `run failed${snippet(entry.error) ? ` \u2014 ${snippet(entry.error)}` : ""}`;
|
|
7341
|
+
default:
|
|
7342
|
+
return type;
|
|
7343
|
+
}
|
|
7344
|
+
}
|
|
7345
|
+
function summarizeSessionEntry(entry) {
|
|
7346
|
+
const type = text2(entry.type) ?? "entry";
|
|
7347
|
+
const message2 = asRecord(entry.message);
|
|
7348
|
+
const role = text2(message2?.role);
|
|
7349
|
+
const content = message2?.content;
|
|
7350
|
+
let body = null;
|
|
7351
|
+
if (typeof content === "string") {
|
|
7352
|
+
body = snippet(content);
|
|
7353
|
+
} else if (Array.isArray(content)) {
|
|
7354
|
+
body = snippet(content.map((part) => text2(asRecord(part)?.text) ?? "").filter(Boolean).join(" "));
|
|
7355
|
+
}
|
|
7356
|
+
return [
|
|
7357
|
+
`pi ${type}`,
|
|
7358
|
+
role ? `(${role})` : null,
|
|
7359
|
+
body ? `\u2014 ${body}` : null
|
|
7360
|
+
].filter(Boolean).join(" ");
|
|
7361
|
+
}
|
|
7362
|
+
function sessionEntryTimestamp(entry) {
|
|
7363
|
+
return text2(entry.timestamp) ?? text2(entry.at) ?? text2(entry.createdAt) ?? null;
|
|
7364
|
+
}
|
|
7365
|
+
function resolveRunSessionFile(record) {
|
|
7366
|
+
const piSession = record?.piSession ?? null;
|
|
7367
|
+
if (!piSession)
|
|
7368
|
+
return null;
|
|
7369
|
+
const recorded = text2(piSession.sessionFile);
|
|
7370
|
+
if (recorded && existsSync14(recorded)) {
|
|
7371
|
+
return recorded;
|
|
7372
|
+
}
|
|
7373
|
+
const cwd = text2(piSession.cwd);
|
|
7374
|
+
const sessionId = text2(piSession.sessionId);
|
|
7375
|
+
if (!cwd || !sessionId)
|
|
7376
|
+
return null;
|
|
7377
|
+
const sessionDir = resolve22(cwd, ".rig", "session");
|
|
7378
|
+
try {
|
|
7379
|
+
const match = readdirSync2(sessionDir).find((name) => name.endsWith(`_${sessionId}.jsonl`));
|
|
7380
|
+
return match ? join2(sessionDir, match) : null;
|
|
7381
|
+
} catch {
|
|
7382
|
+
return null;
|
|
7383
|
+
}
|
|
7384
|
+
}
|
|
7385
|
+
function buildRunReplay(projectRoot, runId, options = {}) {
|
|
7386
|
+
const logPath = runLifecycleLogPath(projectRoot, runId);
|
|
7387
|
+
const record = readAuthorityRun4(projectRoot, runId);
|
|
7388
|
+
const lifecycleEntries = readJsonlFile4(logPath).map((entry) => asRecord(entry)).filter((entry) => entry !== null);
|
|
7389
|
+
const merged = lifecycleEntries.map((entry) => ({
|
|
7390
|
+
at: text2(entry.at),
|
|
7391
|
+
source: "run",
|
|
7392
|
+
summary: summarizeLifecycleEntry(entry)
|
|
7393
|
+
}));
|
|
7394
|
+
let sessionFile = null;
|
|
7395
|
+
let sessionEntryCount = 0;
|
|
7396
|
+
if (options.withSession) {
|
|
7397
|
+
sessionFile = resolveRunSessionFile(record);
|
|
7398
|
+
if (sessionFile) {
|
|
7399
|
+
let lastSeenAt = null;
|
|
7400
|
+
const sessionLines = readJsonlFile4(sessionFile).map((entry) => asRecord(entry)).filter((entry) => entry !== null).map((entry) => {
|
|
7401
|
+
lastSeenAt = sessionEntryTimestamp(entry) ?? lastSeenAt;
|
|
7402
|
+
return { at: lastSeenAt, source: "session", summary: summarizeSessionEntry(entry) };
|
|
7403
|
+
});
|
|
7404
|
+
sessionEntryCount = sessionLines.length;
|
|
7405
|
+
merged.push(...sessionLines);
|
|
7406
|
+
merged.sort((left, right) => (left.at ?? "").localeCompare(right.at ?? ""));
|
|
7407
|
+
}
|
|
7408
|
+
}
|
|
7409
|
+
const lines = merged.map((line) => `${line.at ?? "(no timestamp) "} ${line.source === "run" ? "run " : "session"} ${line.summary}`);
|
|
7410
|
+
return {
|
|
7411
|
+
runId,
|
|
7412
|
+
logPath,
|
|
7413
|
+
sessionFile,
|
|
7414
|
+
entryCount: lifecycleEntries.length,
|
|
7415
|
+
sessionEntryCount,
|
|
7416
|
+
lines
|
|
7417
|
+
};
|
|
7418
|
+
}
|
|
7419
|
+
|
|
7287
7420
|
// packages/cli/src/commands/_operator-surface.ts
|
|
7288
7421
|
import { createInterface } from "readline";
|
|
7289
7422
|
import { createInterface as createPromptInterface } from "readline/promises";
|
|
@@ -7382,22 +7515,22 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
7382
7515
|
for (const [index, entry] of entries.entries()) {
|
|
7383
7516
|
const id = entryId(entry, `timeline:${index}:${String(entry.cursor ?? "")}`);
|
|
7384
7517
|
if (entry.type === "assistant_message" && typeof entry.text === "string") {
|
|
7385
|
-
const
|
|
7518
|
+
const text3 = entry.text;
|
|
7386
7519
|
const previousText = assistantTextById.get(id) ?? "";
|
|
7387
|
-
if (!previousText &&
|
|
7520
|
+
if (!previousText && text3.trim()) {
|
|
7388
7521
|
writeLine("[Pi assistant]");
|
|
7389
7522
|
}
|
|
7390
|
-
if (
|
|
7391
|
-
const delta =
|
|
7523
|
+
if (text3.startsWith(previousText)) {
|
|
7524
|
+
const delta = text3.slice(previousText.length);
|
|
7392
7525
|
if (delta)
|
|
7393
7526
|
output.write(delta);
|
|
7394
|
-
} else if (
|
|
7527
|
+
} else if (text3.trim() && text3 !== previousText) {
|
|
7395
7528
|
if (previousText)
|
|
7396
7529
|
writeLine(`
|
|
7397
7530
|
[Pi assistant]`);
|
|
7398
|
-
output.write(
|
|
7531
|
+
output.write(text3);
|
|
7399
7532
|
}
|
|
7400
|
-
assistantTextById.set(id,
|
|
7533
|
+
assistantTextById.set(id, text3);
|
|
7401
7534
|
continue;
|
|
7402
7535
|
}
|
|
7403
7536
|
if (seenTimeline.has(id))
|
|
@@ -7412,15 +7545,15 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
7412
7545
|
continue;
|
|
7413
7546
|
}
|
|
7414
7547
|
if (entry.type === "action") {
|
|
7415
|
-
const
|
|
7416
|
-
if (
|
|
7417
|
-
writeLine(`[Rig action] ${
|
|
7548
|
+
const text3 = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
7549
|
+
if (text3)
|
|
7550
|
+
writeLine(`[Rig action] ${text3}`);
|
|
7418
7551
|
continue;
|
|
7419
7552
|
}
|
|
7420
7553
|
if (entry.type === "user_message") {
|
|
7421
|
-
const
|
|
7422
|
-
if (
|
|
7423
|
-
writeLine(`[Operator] ${
|
|
7554
|
+
const text3 = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
7555
|
+
if (text3)
|
|
7556
|
+
writeLine(`[Operator] ${text3}`);
|
|
7424
7557
|
continue;
|
|
7425
7558
|
}
|
|
7426
7559
|
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
@@ -7500,7 +7633,7 @@ async function promptForTaskSelection(question) {
|
|
|
7500
7633
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
7501
7634
|
import { mkdtempSync, rmSync as rmSync5 } from "fs";
|
|
7502
7635
|
import { tmpdir } from "os";
|
|
7503
|
-
import { join as
|
|
7636
|
+
import { join as join3 } from "path";
|
|
7504
7637
|
import {
|
|
7505
7638
|
createAgentSessionFromServices,
|
|
7506
7639
|
createAgentSessionServices,
|
|
@@ -7632,15 +7765,15 @@ class RigRemoteSessionController {
|
|
|
7632
7765
|
for (const compaction of this.pendingCompactions.splice(0))
|
|
7633
7766
|
compaction.reject(new Error("Remote session closed."));
|
|
7634
7767
|
}
|
|
7635
|
-
async sendPrompt(
|
|
7636
|
-
await this.transport.sendPrompt(this.context, this.runId,
|
|
7768
|
+
async sendPrompt(text3, streamingBehavior) {
|
|
7769
|
+
await this.transport.sendPrompt(this.context, this.runId, text3, streamingBehavior);
|
|
7637
7770
|
}
|
|
7638
|
-
async sendCommand(
|
|
7639
|
-
const result = await this.transport.runCommand(this.context, this.runId,
|
|
7771
|
+
async sendCommand(text3) {
|
|
7772
|
+
const result = await this.transport.runCommand(this.context, this.runId, text3);
|
|
7640
7773
|
return typeof result.message === "string" ? result.message : "worker command accepted";
|
|
7641
7774
|
}
|
|
7642
|
-
async sendShell(
|
|
7643
|
-
await this.transport.sendShell(this.context, this.runId,
|
|
7775
|
+
async sendShell(text3) {
|
|
7776
|
+
await this.transport.sendShell(this.context, this.runId, text3);
|
|
7644
7777
|
}
|
|
7645
7778
|
async abort() {
|
|
7646
7779
|
await this.transport.abort(this.context, this.runId);
|
|
@@ -7792,8 +7925,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7792
7925
|
replaceRemoteMessages(messages) {
|
|
7793
7926
|
this.agent.state.messages = messages;
|
|
7794
7927
|
}
|
|
7795
|
-
async expandLocalInput(
|
|
7796
|
-
let current =
|
|
7928
|
+
async expandLocalInput(text3) {
|
|
7929
|
+
let current = text3;
|
|
7797
7930
|
const runner = this.extensionRunner;
|
|
7798
7931
|
if (runner.hasHandlers("input")) {
|
|
7799
7932
|
const result = await runner.emitInput(current, undefined, "interactive");
|
|
@@ -7806,8 +7939,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7806
7939
|
current = expandPromptTemplate(current, [...this.promptTemplates]);
|
|
7807
7940
|
return current;
|
|
7808
7941
|
}
|
|
7809
|
-
async prompt(
|
|
7810
|
-
const trimmed =
|
|
7942
|
+
async prompt(text3, options) {
|
|
7943
|
+
const trimmed = text3.trim();
|
|
7811
7944
|
if (!trimmed)
|
|
7812
7945
|
return;
|
|
7813
7946
|
if (trimmed.startsWith("/")) {
|
|
@@ -7836,8 +7969,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7836
7969
|
options?.preflightResult?.(true);
|
|
7837
7970
|
await this.remote.sendPrompt(expanded, behavior);
|
|
7838
7971
|
}
|
|
7839
|
-
async steer(
|
|
7840
|
-
const trimmed =
|
|
7972
|
+
async steer(text3) {
|
|
7973
|
+
const trimmed = text3.trim();
|
|
7841
7974
|
if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
|
|
7842
7975
|
return;
|
|
7843
7976
|
const expanded = await this.expandLocalInput(trimmed);
|
|
@@ -7845,8 +7978,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7845
7978
|
return;
|
|
7846
7979
|
await this.remote.sendPrompt(expanded, "steer");
|
|
7847
7980
|
}
|
|
7848
|
-
async followUp(
|
|
7849
|
-
const trimmed =
|
|
7981
|
+
async followUp(text3) {
|
|
7982
|
+
const trimmed = text3.trim();
|
|
7850
7983
|
if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
|
|
7851
7984
|
return;
|
|
7852
7985
|
const expanded = await this.expandLocalInput(trimmed);
|
|
@@ -7858,8 +7991,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7858
7991
|
await this.remote.abort();
|
|
7859
7992
|
}
|
|
7860
7993
|
async compact(customInstructions) {
|
|
7861
|
-
const pending = new Promise((
|
|
7862
|
-
this.remote.registerPendingCompaction({ resolve:
|
|
7994
|
+
const pending = new Promise((resolve23, reject) => {
|
|
7995
|
+
this.remote.registerPendingCompaction({ resolve: resolve23, reject });
|
|
7863
7996
|
});
|
|
7864
7997
|
await this.remote.sendCommand(`/compact${customInstructions ? ` ${customInstructions}` : ""}`);
|
|
7865
7998
|
return pending;
|
|
@@ -7928,8 +8061,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7928
8061
|
function createRemoteBashOperations(controller, excludeFromContext) {
|
|
7929
8062
|
return {
|
|
7930
8063
|
exec(command, _cwd, execOptions) {
|
|
7931
|
-
return new Promise((
|
|
7932
|
-
const pending = { onData: execOptions.onData, resolve:
|
|
8064
|
+
return new Promise((resolve23, reject) => {
|
|
8065
|
+
const pending = { onData: execOptions.onData, resolve: resolve23, reject, sawChunk: false };
|
|
7933
8066
|
const cleanup = () => {
|
|
7934
8067
|
execOptions.signal?.removeEventListener("abort", onAbort);
|
|
7935
8068
|
if (timer)
|
|
@@ -8093,8 +8226,8 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
8093
8226
|
const prefix = busy ? `${SPINNER_FRAMES[frame]} ` : connected ? "\u25CF " : "\u25CB ";
|
|
8094
8227
|
ctx.ui.setStatus("rig-worker-pi", `${prefix}${statusText}`);
|
|
8095
8228
|
};
|
|
8096
|
-
const setStatus = (ctx,
|
|
8097
|
-
statusText =
|
|
8229
|
+
const setStatus = (ctx, text3, isBusy) => {
|
|
8230
|
+
statusText = text3;
|
|
8098
8231
|
busy = isBusy;
|
|
8099
8232
|
renderStatus(ctx);
|
|
8100
8233
|
};
|
|
@@ -8138,7 +8271,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
8138
8271
|
ctx.ui.notify("Initial message sent to the worker Pi daemon.", "info");
|
|
8139
8272
|
const nativeUi = ctx.ui;
|
|
8140
8273
|
options.controller.setUiHooks({
|
|
8141
|
-
onStatusText: (
|
|
8274
|
+
onStatusText: (text3) => setStatus(ctx, text3, !connected),
|
|
8142
8275
|
onActivity: (label, detail) => {
|
|
8143
8276
|
const active = label !== "idle" && !/complete|ready/i.test(label);
|
|
8144
8277
|
setStatus(ctx, [label, detail].filter(Boolean).join(" \u2014 "), active);
|
|
@@ -8195,7 +8328,7 @@ function setTemporaryEnv(updates) {
|
|
|
8195
8328
|
};
|
|
8196
8329
|
}
|
|
8197
8330
|
async function attachRunBundledPiFrontend(context, input) {
|
|
8198
|
-
const tempSessionDir = mkdtempSync(
|
|
8331
|
+
const tempSessionDir = mkdtempSync(join3(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
8199
8332
|
const restoreEnv = setTemporaryEnv({
|
|
8200
8333
|
PI_CODING_AGENT_SESSION_DIR: tempSessionDir,
|
|
8201
8334
|
PI_SKIP_VERSION_CHECK: "1",
|
|
@@ -8515,7 +8648,7 @@ async function executeRun(context, args) {
|
|
|
8515
8648
|
if (!runId) {
|
|
8516
8649
|
throw new CliError2("run show requires a run id.");
|
|
8517
8650
|
}
|
|
8518
|
-
const record =
|
|
8651
|
+
const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails2(await getRunDetailsViaServer(context, runId).catch(() => ({})));
|
|
8519
8652
|
if (!record) {
|
|
8520
8653
|
throw new CliError2(`Run not found: ${runId}`, 2);
|
|
8521
8654
|
}
|
|
@@ -8553,6 +8686,46 @@ async function executeRun(context, args) {
|
|
|
8553
8686
|
}
|
|
8554
8687
|
return { ok: true, group: "run", command, details: { runId: run.value, events, cursor } };
|
|
8555
8688
|
}
|
|
8689
|
+
case "replay": {
|
|
8690
|
+
let pending = rest;
|
|
8691
|
+
const run = takeOption(pending, "--run");
|
|
8692
|
+
pending = run.rest;
|
|
8693
|
+
const withSession = takeFlag(pending, "--with-session");
|
|
8694
|
+
pending = withSession.rest;
|
|
8695
|
+
const positionalRunId = pending.length > 0 && pending[0] && !pending[0].startsWith("-") ? pending[0] : undefined;
|
|
8696
|
+
const extra = positionalRunId ? pending.slice(1) : pending;
|
|
8697
|
+
requireNoExtraArgs(extra, "rig run replay <id>|--run <id> [--with-session]");
|
|
8698
|
+
const runId = run.value ?? positionalRunId;
|
|
8699
|
+
if (!runId) {
|
|
8700
|
+
throw new CliError2("run replay requires a run id.", 2);
|
|
8701
|
+
}
|
|
8702
|
+
const replay = buildRunReplay(context.projectRoot, runId, { withSession: withSession.value });
|
|
8703
|
+
if (replay.entryCount === 0 && replay.sessionEntryCount === 0) {
|
|
8704
|
+
throw new CliError2(`No run.jsonl lifecycle log found for ${runId} (looked at ${replay.logPath}).`, 2);
|
|
8705
|
+
}
|
|
8706
|
+
if (context.outputMode === "text") {
|
|
8707
|
+
console.log(`Replay of ${runId} (${replay.entryCount} lifecycle entries${withSession.value ? `, ${replay.sessionEntryCount} session entries` : ""}):`);
|
|
8708
|
+
for (const line of replay.lines) {
|
|
8709
|
+
console.log(line);
|
|
8710
|
+
}
|
|
8711
|
+
if (withSession.value && !replay.sessionFile) {
|
|
8712
|
+
console.log("(no Pi session file resolvable from the run record; showing run.jsonl only)");
|
|
8713
|
+
}
|
|
8714
|
+
}
|
|
8715
|
+
return {
|
|
8716
|
+
ok: true,
|
|
8717
|
+
group: "run",
|
|
8718
|
+
command,
|
|
8719
|
+
details: {
|
|
8720
|
+
runId,
|
|
8721
|
+
logPath: replay.logPath,
|
|
8722
|
+
sessionFile: replay.sessionFile,
|
|
8723
|
+
entryCount: replay.entryCount,
|
|
8724
|
+
sessionEntryCount: replay.sessionEntryCount,
|
|
8725
|
+
lines: replay.lines
|
|
8726
|
+
}
|
|
8727
|
+
};
|
|
8728
|
+
}
|
|
8556
8729
|
case "attach": {
|
|
8557
8730
|
let pending = rest;
|
|
8558
8731
|
const runOption = takeOption(pending, "--run");
|
|
@@ -8875,7 +9048,7 @@ async function executeServer(context, args, options) {
|
|
|
8875
9048
|
init_runner();
|
|
8876
9049
|
import { readFileSync as readFileSync10 } from "fs";
|
|
8877
9050
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
8878
|
-
import { resolve as
|
|
9051
|
+
import { resolve as resolve23 } from "path";
|
|
8879
9052
|
import { cancel as cancel4, confirm as confirm2, isCancel as isCancel4 } from "@clack/prompts";
|
|
8880
9053
|
import {
|
|
8881
9054
|
taskArtifactDir,
|
|
@@ -9053,6 +9226,7 @@ var PRIMARY_GROUPS = [
|
|
|
9053
9226
|
{ command: "stop [<run-id>|--run <id>]", description: "Request stop for one run or local active runs.", primary: true },
|
|
9054
9227
|
{ command: "steer <run-id> --message <text>", description: "Queue a steering message into a live worker without attaching." },
|
|
9055
9228
|
{ command: "timeline --run <id> [--follow]", description: "Stream raw run timeline events." },
|
|
9229
|
+
{ command: "replay <run-id>|--run <id> [--with-session]", description: "Print the run's consolidated run.jsonl as a merged timeline; --with-session interleaves the Pi session log." },
|
|
9056
9230
|
{ command: "resume", description: "Resume the most recent interrupted local run." },
|
|
9057
9231
|
{ command: "restart", description: "Restart the most recent local run from a clean runtime." },
|
|
9058
9232
|
{ command: "delete|cleanup", description: "Remove completed run records/artifacts." }
|
|
@@ -9640,7 +9814,7 @@ async function executeTask(context, args, options) {
|
|
|
9640
9814
|
const fileFlag = takeOption(rest.slice(1), "--file");
|
|
9641
9815
|
let content;
|
|
9642
9816
|
if (fileFlag.value) {
|
|
9643
|
-
content = readFileSync10(
|
|
9817
|
+
content = readFileSync10(resolve23(context.projectRoot, fileFlag.value), "utf-8");
|
|
9644
9818
|
} else {
|
|
9645
9819
|
content = await readStdin();
|
|
9646
9820
|
}
|
|
@@ -9874,8 +10048,8 @@ async function executeTask(context, args, options) {
|
|
|
9874
10048
|
|
|
9875
10049
|
// packages/cli/src/commands/task-run-driver.ts
|
|
9876
10050
|
init_runner();
|
|
9877
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
9878
|
-
import { resolve as
|
|
10051
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
10052
|
+
import { resolve as resolve24 } from "path";
|
|
9879
10053
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
9880
10054
|
import { createInterface as createLineInterface } from "readline";
|
|
9881
10055
|
import { loadConfig as loadConfig2 } from "@rig/core/load-config";
|
|
@@ -9899,7 +10073,7 @@ import {
|
|
|
9899
10073
|
isCodexExecRecord
|
|
9900
10074
|
} from "@rig/runtime/control-plane/provider/codex-exec-records";
|
|
9901
10075
|
import { resolvePreferredShellBinary } from "@rig/runtime/control-plane/native/run-ops";
|
|
9902
|
-
import { readAuthorityRun as
|
|
10076
|
+
import { readAuthorityRun as readAuthorityRun6, readJsonFile as readJsonFile3, resolveTaskArtifactDirs as resolveTaskArtifactDirs2 } from "@rig/runtime/control-plane/authority-files";
|
|
9903
10077
|
import {
|
|
9904
10078
|
buildTaskRunLifecycleComment
|
|
9905
10079
|
} from "@rig/runtime/control-plane/tasks/source-lifecycle";
|
|
@@ -9959,12 +10133,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
9959
10133
|
return 0;
|
|
9960
10134
|
let copied = 0;
|
|
9961
10135
|
for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
|
|
9962
|
-
const sourcePath =
|
|
9963
|
-
const targetPath =
|
|
10136
|
+
const sourcePath = resolve24(sourceRoot, relativePath);
|
|
10137
|
+
const targetPath = resolve24(targetRoot, relativePath);
|
|
9964
10138
|
try {
|
|
9965
10139
|
if (!statSync2(sourcePath).isFile())
|
|
9966
10140
|
continue;
|
|
9967
|
-
mkdirSync9(
|
|
10141
|
+
mkdirSync9(resolve24(targetPath, ".."), { recursive: true });
|
|
9968
10142
|
copyFileSync3(sourcePath, targetPath);
|
|
9969
10143
|
copied += 1;
|
|
9970
10144
|
} catch {}
|
|
@@ -10003,7 +10177,7 @@ function buildDirtyBaselineHandshakeEnv(input) {
|
|
|
10003
10177
|
return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
|
|
10004
10178
|
return {
|
|
10005
10179
|
RIG_BASELINE_MODE: "dirty-snapshot",
|
|
10006
|
-
RIG_DIRTY_BASELINE_READY_FILE:
|
|
10180
|
+
RIG_DIRTY_BASELINE_READY_FILE: resolve24(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
|
|
10007
10181
|
};
|
|
10008
10182
|
}
|
|
10009
10183
|
function positiveInt(value, fallback) {
|
|
@@ -10108,9 +10282,9 @@ function createCommandRunner(binary) {
|
|
|
10108
10282
|
const stderrChunks = [];
|
|
10109
10283
|
child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
10110
10284
|
child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
10111
|
-
return await new Promise((
|
|
10112
|
-
child.once("error", (error) =>
|
|
10113
|
-
child.once("close", (code) =>
|
|
10285
|
+
return await new Promise((resolve25) => {
|
|
10286
|
+
child.once("error", (error) => resolve25({ exitCode: 1, stderr: error.message }));
|
|
10287
|
+
child.once("close", (code) => resolve25({
|
|
10114
10288
|
exitCode: code ?? 1,
|
|
10115
10289
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
10116
10290
|
stderr: Buffer.concat(stderrChunks).toString("utf8")
|
|
@@ -10184,7 +10358,7 @@ async function runTaskRunPostValidationLifecycle(input) {
|
|
|
10184
10358
|
config,
|
|
10185
10359
|
sourceTask: input.sourceTask,
|
|
10186
10360
|
uploadedSnapshot: input.uploadedSnapshot,
|
|
10187
|
-
artifactRoot:
|
|
10361
|
+
artifactRoot: resolve24(input.projectRoot, "artifacts", taskId3),
|
|
10188
10362
|
command: ghCommand,
|
|
10189
10363
|
gitCommand,
|
|
10190
10364
|
steerPi,
|
|
@@ -10314,7 +10488,7 @@ function summarizeValidationFailure(projectRoot, taskId3) {
|
|
|
10314
10488
|
return null;
|
|
10315
10489
|
}
|
|
10316
10490
|
for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId3)) {
|
|
10317
|
-
const summary = readJsonFile3(
|
|
10491
|
+
const summary = readJsonFile3(resolve24(artifactDir, "validation-summary.json"), null);
|
|
10318
10492
|
if (!summary || summary.status !== "fail") {
|
|
10319
10493
|
continue;
|
|
10320
10494
|
}
|
|
@@ -10395,9 +10569,9 @@ function readTaskRunAcceptedArtifactState(input) {
|
|
|
10395
10569
|
if (!input.taskId || !input.workspaceDir) {
|
|
10396
10570
|
return { accepted: false, reason: null };
|
|
10397
10571
|
}
|
|
10398
|
-
const artifactDir =
|
|
10399
|
-
const reviewStatusPath =
|
|
10400
|
-
const taskResultPath =
|
|
10572
|
+
const artifactDir = resolve24(input.workspaceDir, "artifacts", input.taskId);
|
|
10573
|
+
const reviewStatusPath = resolve24(artifactDir, "review-status.txt");
|
|
10574
|
+
const taskResultPath = resolve24(artifactDir, "task-result.json");
|
|
10401
10575
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
10402
10576
|
if (reviewStatus !== "APPROVED") {
|
|
10403
10577
|
return { accepted: false, reason: null };
|
|
@@ -10434,12 +10608,12 @@ function resolveTaskRunRetryContext(input) {
|
|
|
10434
10608
|
if (!input.taskId || !input.workspaceDir) {
|
|
10435
10609
|
return { shouldRetry: false, failureDetail: null, nextPrompt: null };
|
|
10436
10610
|
}
|
|
10437
|
-
const artifactDir =
|
|
10438
|
-
const reviewStatePath =
|
|
10439
|
-
const reviewFeedbackPath =
|
|
10440
|
-
const reviewStatusPath =
|
|
10441
|
-
const failedApproachesPath =
|
|
10442
|
-
const validationSummaryPath =
|
|
10611
|
+
const artifactDir = resolve24(input.workspaceDir, "artifacts", input.taskId);
|
|
10612
|
+
const reviewStatePath = resolve24(artifactDir, "review-state.json");
|
|
10613
|
+
const reviewFeedbackPath = resolve24(artifactDir, "review-feedback.md");
|
|
10614
|
+
const reviewStatusPath = resolve24(artifactDir, "review-status.txt");
|
|
10615
|
+
const failedApproachesPath = resolve24(input.workspaceDir, ".rig", "state", "failed_approaches.md");
|
|
10616
|
+
const validationSummaryPath = resolve24(artifactDir, "validation-summary.json");
|
|
10443
10617
|
const reviewState = readJsonFile3(reviewStatePath, null);
|
|
10444
10618
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
10445
10619
|
const reviewRejected = isTaskRunReviewRejected(reviewState);
|
|
@@ -10625,7 +10799,7 @@ function appendToolTimelineFromLog(input) {
|
|
|
10625
10799
|
});
|
|
10626
10800
|
}
|
|
10627
10801
|
function readTaskRunReviewStatus(reviewStatusPath) {
|
|
10628
|
-
if (!
|
|
10802
|
+
if (!existsSync15(reviewStatusPath)) {
|
|
10629
10803
|
return null;
|
|
10630
10804
|
}
|
|
10631
10805
|
try {
|
|
@@ -10705,7 +10879,7 @@ async function updateTaskSourceAfterDriverRun(projectRoot, runId, taskId3, sourc
|
|
|
10705
10879
|
}
|
|
10706
10880
|
}
|
|
10707
10881
|
function readRunSourceTaskContract(projectRoot, runId, taskId3) {
|
|
10708
|
-
const run =
|
|
10882
|
+
const run = readAuthorityRun6(projectRoot, runId);
|
|
10709
10883
|
const raw = run?.sourceTask;
|
|
10710
10884
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
10711
10885
|
return null;
|
|
@@ -10746,8 +10920,10 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
10746
10920
|
process.stderr.on("error", () => {});
|
|
10747
10921
|
configureRunEventSink(context.projectRoot);
|
|
10748
10922
|
const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
|
|
10749
|
-
const existingRunRecord =
|
|
10923
|
+
const existingRunRecord = readAuthorityRun6(context.projectRoot, input.runId);
|
|
10750
10924
|
const resumeMode = process.env.RIG_RUN_RESUME === "1";
|
|
10925
|
+
let latestPiSessionId = typeof existingRunRecord?.piSession?.sessionId === "string" && existingRunRecord.piSession.sessionId.trim() ? existingRunRecord.piSession.sessionId : null;
|
|
10926
|
+
const sessionAnchor = () => latestPiSessionId ? { sessionId: latestPiSessionId } : {};
|
|
10751
10927
|
const resumePreviousStatus = String(existingRunRecord?.status ?? "").toLowerCase();
|
|
10752
10928
|
const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
|
|
10753
10929
|
let prompt = buildRunPrompt({
|
|
@@ -10820,7 +10996,8 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
10820
10996
|
type: "status",
|
|
10821
10997
|
runId: input.runId,
|
|
10822
10998
|
status: "preparing",
|
|
10823
|
-
detail: input.taskId ?? input.title ?? runtimeTaskId
|
|
10999
|
+
detail: input.taskId ?? input.title ?? runtimeTaskId,
|
|
11000
|
+
...sessionAnchor()
|
|
10824
11001
|
});
|
|
10825
11002
|
appendRunLog(context.projectRoot, input.runId, {
|
|
10826
11003
|
id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
|
|
@@ -10846,15 +11023,15 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
10846
11023
|
const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
|
|
10847
11024
|
const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
|
|
10848
11025
|
const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
|
|
10849
|
-
const planningArtifactPath =
|
|
11026
|
+
const planningArtifactPath = resolve24("artifacts", runtimeTaskId, "implementation-plan.md");
|
|
10850
11027
|
const persistedPlanning = {
|
|
10851
11028
|
...planningClassification,
|
|
10852
11029
|
classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
|
|
10853
11030
|
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
10854
11031
|
classifiedAt: new Date().toISOString()
|
|
10855
11032
|
};
|
|
10856
|
-
mkdirSync9(
|
|
10857
|
-
writeFileSync7(
|
|
11033
|
+
mkdirSync9(resolve24(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
|
|
11034
|
+
writeFileSync7(resolve24(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
|
|
10858
11035
|
`, "utf8");
|
|
10859
11036
|
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
10860
11037
|
prompt = `${prompt}
|
|
@@ -10904,7 +11081,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10904
11081
|
let verificationStarted = false;
|
|
10905
11082
|
let reviewStarted = false;
|
|
10906
11083
|
let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
|
|
10907
|
-
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ?
|
|
11084
|
+
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve24(existingRunRecord.sessionPath, "..") : null;
|
|
10908
11085
|
let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
|
|
10909
11086
|
let latestProviderCommand = null;
|
|
10910
11087
|
let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
|
|
@@ -10941,7 +11118,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10941
11118
|
return;
|
|
10942
11119
|
verificationStarted = true;
|
|
10943
11120
|
patchAuthorityRun(context.projectRoot, input.runId, { status: "validating" });
|
|
10944
|
-
emitServerRunEvent({ type: "status", runId: input.runId, status: "validating", detail: detail ?? null });
|
|
11121
|
+
emitServerRunEvent({ type: "status", runId: input.runId, status: "validating", detail: detail ?? null, ...sessionAnchor() });
|
|
10945
11122
|
verificationAction = startRunAction(context.projectRoot, input.runId, {
|
|
10946
11123
|
actionId: `action:${input.runId}:completion-verification`,
|
|
10947
11124
|
actionType: "completion-verification",
|
|
@@ -10954,7 +11131,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10954
11131
|
return;
|
|
10955
11132
|
reviewStarted = true;
|
|
10956
11133
|
patchAuthorityRun(context.projectRoot, input.runId, { status: "reviewing" });
|
|
10957
|
-
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: detail ?? null });
|
|
11134
|
+
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: detail ?? null, ...sessionAnchor() });
|
|
10958
11135
|
reviewAction = startRunAction(context.projectRoot, input.runId, {
|
|
10959
11136
|
actionId: `action:${input.runId}:review-closeout`,
|
|
10960
11137
|
actionType: "run.review",
|
|
@@ -10990,10 +11167,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10990
11167
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
10991
11168
|
status: "running",
|
|
10992
11169
|
worktreePath: latestRuntimeWorkspace,
|
|
10993
|
-
artifactRoot: latestRuntimeWorkspace && input.taskId ?
|
|
11170
|
+
artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve24(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
|
|
10994
11171
|
logRoot: latestLogsDir,
|
|
10995
|
-
sessionPath: latestSessionDir ?
|
|
10996
|
-
sessionLogPath: latestLogsDir ?
|
|
11172
|
+
sessionPath: latestSessionDir ? resolve24(latestSessionDir, "session.json") : null,
|
|
11173
|
+
sessionLogPath: latestLogsDir ? resolve24(latestLogsDir, "agent-stdout.log") : null,
|
|
10997
11174
|
branch: runtimeId
|
|
10998
11175
|
});
|
|
10999
11176
|
if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
|
|
@@ -11001,7 +11178,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11001
11178
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
11002
11179
|
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
11003
11180
|
if (readyFile) {
|
|
11004
|
-
mkdirSync9(
|
|
11181
|
+
mkdirSync9(resolve24(readyFile, ".."), { recursive: true });
|
|
11005
11182
|
writeFileSync7(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
11006
11183
|
`, "utf8");
|
|
11007
11184
|
}
|
|
@@ -11044,7 +11221,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11044
11221
|
type: "status",
|
|
11045
11222
|
runId: input.runId,
|
|
11046
11223
|
status: "running",
|
|
11047
|
-
detail: latestRuntimeWorkspace
|
|
11224
|
+
detail: latestRuntimeWorkspace,
|
|
11225
|
+
...sessionAnchor()
|
|
11048
11226
|
});
|
|
11049
11227
|
return true;
|
|
11050
11228
|
}
|
|
@@ -11127,6 +11305,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11127
11305
|
piSessionPrivate: privateMetadata
|
|
11128
11306
|
});
|
|
11129
11307
|
const sessionId = typeof publicMetadata?.sessionId === "string" ? publicMetadata.sessionId : typeof privateMetadata.public === "object" && privateMetadata.public && !Array.isArray(privateMetadata.public) ? String(privateMetadata.public.sessionId ?? "") : "";
|
|
11308
|
+
if (sessionId) {
|
|
11309
|
+
latestPiSessionId = sessionId;
|
|
11310
|
+
}
|
|
11130
11311
|
appendRunLog(context.projectRoot, input.runId, {
|
|
11131
11312
|
id: `log:${input.runId}:pi-session-ready`,
|
|
11132
11313
|
title: "Worker Pi session ready",
|
|
@@ -11386,7 +11567,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11386
11567
|
let acceptedArtifactObservedAt = null;
|
|
11387
11568
|
let acceptedArtifactPollTimer = null;
|
|
11388
11569
|
let acceptedArtifactKillTimer = null;
|
|
11389
|
-
const attemptExit = await new Promise((
|
|
11570
|
+
const attemptExit = await new Promise((resolve25) => {
|
|
11390
11571
|
let settled = false;
|
|
11391
11572
|
const settle = (result) => {
|
|
11392
11573
|
if (settled)
|
|
@@ -11394,7 +11575,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11394
11575
|
settled = true;
|
|
11395
11576
|
if (acceptedArtifactPollTimer)
|
|
11396
11577
|
clearInterval(acceptedArtifactPollTimer);
|
|
11397
|
-
|
|
11578
|
+
resolve25(result);
|
|
11398
11579
|
};
|
|
11399
11580
|
const pollAcceptedArtifacts = () => {
|
|
11400
11581
|
const artifactState = readTaskRunAcceptedArtifactState({
|
|
@@ -11521,7 +11702,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11521
11702
|
type: "status",
|
|
11522
11703
|
runId: input.runId,
|
|
11523
11704
|
status: "validating",
|
|
11524
|
-
detail: failureDetail
|
|
11705
|
+
detail: failureDetail,
|
|
11706
|
+
...sessionAnchor()
|
|
11525
11707
|
});
|
|
11526
11708
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Validate failed" });
|
|
11527
11709
|
emitServerRunEvent({ type: "log", runId: input.runId, title: `Steering Pi to retry validation (attempt ${attempt + 1}/${maxAttempts})` });
|
|
@@ -11596,8 +11778,8 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11596
11778
|
}
|
|
11597
11779
|
if (planningClassification.planningRequired) {
|
|
11598
11780
|
const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
|
|
11599
|
-
const expectedPlanPath =
|
|
11600
|
-
if (!
|
|
11781
|
+
const expectedPlanPath = resolve24(planWorkspace, planningArtifactPath);
|
|
11782
|
+
if (!existsSync15(expectedPlanPath)) {
|
|
11601
11783
|
const failedAt = new Date().toISOString();
|
|
11602
11784
|
const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
|
|
11603
11785
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
@@ -11659,7 +11841,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11659
11841
|
payload: { runtimeWorkspace: latestRuntimeWorkspace, branch: latestRuntimeBranch }
|
|
11660
11842
|
});
|
|
11661
11843
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Server-owned closeout requested" });
|
|
11662
|
-
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: "Server-owned closeout requested." });
|
|
11844
|
+
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: "Server-owned closeout requested.", ...sessionAnchor() });
|
|
11663
11845
|
await context.emitEvent("command.finished", {
|
|
11664
11846
|
command: [
|
|
11665
11847
|
"rig",
|
|
@@ -11767,9 +11949,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11767
11949
|
});
|
|
11768
11950
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
|
|
11769
11951
|
});
|
|
11770
|
-
const exitCode = await new Promise((
|
|
11771
|
-
child.once("error", () =>
|
|
11772
|
-
child.once("close", (code) =>
|
|
11952
|
+
const exitCode = await new Promise((resolve25) => {
|
|
11953
|
+
child.once("error", () => resolve25(1));
|
|
11954
|
+
child.once("close", (code) => resolve25(code ?? 1));
|
|
11773
11955
|
});
|
|
11774
11956
|
for (const pendingLog of flushPendingClaudeToolUseLogs({
|
|
11775
11957
|
runId: input.runId,
|
|
@@ -11911,8 +12093,8 @@ async function executeTest(context, args) {
|
|
|
11911
12093
|
|
|
11912
12094
|
// packages/cli/src/commands/setup.ts
|
|
11913
12095
|
init_runner();
|
|
11914
|
-
import { existsSync as
|
|
11915
|
-
import { resolve as
|
|
12096
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync10, readdirSync as readdirSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
12097
|
+
import { resolve as resolve25 } from "path";
|
|
11916
12098
|
import { createPluginHost } from "@rig/core";
|
|
11917
12099
|
import {
|
|
11918
12100
|
isSupportedBunVersion as isSupportedBunVersion2,
|
|
@@ -11970,8 +12152,8 @@ function runSetupInit(projectRoot) {
|
|
|
11970
12152
|
mkdirSync10(stateDir, { recursive: true });
|
|
11971
12153
|
mkdirSync10(logsDir, { recursive: true });
|
|
11972
12154
|
mkdirSync10(artifactsDir, { recursive: true });
|
|
11973
|
-
const failuresPath =
|
|
11974
|
-
if (!
|
|
12155
|
+
const failuresPath = resolve25(stateDir, "failed_approaches.md");
|
|
12156
|
+
if (!existsSync16(failuresPath)) {
|
|
11975
12157
|
writeFileSync8(failuresPath, `# Failed Approaches
|
|
11976
12158
|
|
|
11977
12159
|
`, "utf-8");
|
|
@@ -11989,19 +12171,19 @@ async function runSetupCheck(projectRoot) {
|
|
|
11989
12171
|
}
|
|
11990
12172
|
async function runSetupPreflight(projectRoot) {
|
|
11991
12173
|
await runSetupCheck(projectRoot);
|
|
11992
|
-
const validationRoot =
|
|
11993
|
-
if (
|
|
11994
|
-
const validators =
|
|
12174
|
+
const validationRoot = resolve25(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
12175
|
+
if (existsSync16(validationRoot)) {
|
|
12176
|
+
const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
11995
12177
|
for (const validator of validators) {
|
|
11996
|
-
const script =
|
|
11997
|
-
if (
|
|
12178
|
+
const script = resolve25(validationRoot, validator.name, "validate.sh");
|
|
12179
|
+
if (existsSync16(script)) {
|
|
11998
12180
|
console.log(`OK: validator script ${script}`);
|
|
11999
12181
|
}
|
|
12000
12182
|
}
|
|
12001
12183
|
}
|
|
12002
|
-
const hooksRoot =
|
|
12003
|
-
if (
|
|
12004
|
-
const hooks =
|
|
12184
|
+
const hooksRoot = resolve25(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
|
|
12185
|
+
if (existsSync16(hooksRoot)) {
|
|
12186
|
+
const hooks = readdirSync3(hooksRoot).filter((name) => name.endsWith(".sh"));
|
|
12005
12187
|
for (const hook of hooks) {
|
|
12006
12188
|
console.log(`OK: hook ${hook}`);
|
|
12007
12189
|
}
|
|
@@ -12145,7 +12327,7 @@ var PROJECT_REQUIRED_GROUPS = new Set([
|
|
|
12145
12327
|
]);
|
|
12146
12328
|
var RIG_CONFIG_FILENAMES = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
|
|
12147
12329
|
function hasInitializedRigProject(projectRoot) {
|
|
12148
|
-
return RIG_CONFIG_FILENAMES.some((name) =>
|
|
12330
|
+
return RIG_CONFIG_FILENAMES.some((name) => existsSync17(resolve26(projectRoot, name))) || existsSync17(resolve26(projectRoot, ".rig"));
|
|
12149
12331
|
}
|
|
12150
12332
|
function requireInitializedRigProject(context, group) {
|
|
12151
12333
|
if (hasInitializedRigProject(context.projectRoot)) {
|
|
@@ -12198,8 +12380,8 @@ function resolveTopLevelLaunchState(context) {
|
|
|
12198
12380
|
let selectedServer = null;
|
|
12199
12381
|
if (projectInitialized) {
|
|
12200
12382
|
try {
|
|
12201
|
-
const statePath =
|
|
12202
|
-
if (
|
|
12383
|
+
const statePath = resolve26(context.projectRoot, ".rig", "state", "connection.json");
|
|
12384
|
+
if (existsSync17(statePath)) {
|
|
12203
12385
|
const parsed = JSON.parse(readFileSync12(statePath, "utf-8"));
|
|
12204
12386
|
selectedServer = parsed.remoteUrl || parsed.url || parsed.selected || null;
|
|
12205
12387
|
}
|
|
@@ -12362,8 +12544,8 @@ async function executeGroup(context, group, args) {
|
|
|
12362
12544
|
}
|
|
12363
12545
|
}
|
|
12364
12546
|
// packages/cli/src/launcher.ts
|
|
12365
|
-
import { existsSync as
|
|
12366
|
-
import { basename as basename3, resolve as
|
|
12547
|
+
import { existsSync as existsSync18 } from "fs";
|
|
12548
|
+
import { basename as basename3, resolve as resolve27 } from "path";
|
|
12367
12549
|
import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
|
|
12368
12550
|
import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
|
|
12369
12551
|
function parsePolicyMode(value) {
|
|
@@ -12376,7 +12558,7 @@ function parsePolicyMode(value) {
|
|
|
12376
12558
|
throw new Error(`Invalid --policy-mode value: ${value}. Use off|observe|enforce.`);
|
|
12377
12559
|
}
|
|
12378
12560
|
function hasRigProjectMarker(candidate) {
|
|
12379
|
-
return
|
|
12561
|
+
return existsSync18(resolve27(candidate, RIG_DEFINITION_DIRNAME)) || existsSync18(resolve27(candidate, RIG_STATE_DIRNAME)) || existsSync18(resolve27(candidate, "rig.config.ts")) || existsSync18(resolve27(candidate, "rig.config.json")) || existsSync18(resolve27(candidate, ".git"));
|
|
12380
12562
|
}
|
|
12381
12563
|
function resolveProjectRoot({
|
|
12382
12564
|
envProjectRoot,
|
|
@@ -12385,19 +12567,19 @@ function resolveProjectRoot({
|
|
|
12385
12567
|
cwd = process.cwd()
|
|
12386
12568
|
}) {
|
|
12387
12569
|
if (envProjectRoot) {
|
|
12388
|
-
return
|
|
12570
|
+
return resolve27(cwd, envProjectRoot);
|
|
12389
12571
|
}
|
|
12390
12572
|
const fallbackImportDir = importDir ?? cwd;
|
|
12391
12573
|
const execName = basename3(execPath).toLowerCase();
|
|
12392
|
-
const execCandidates = execName === "rig" || execName === "rig.exe" ? [
|
|
12393
|
-
const candidates = [cwd, ...execCandidates,
|
|
12574
|
+
const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve27(execPath, "..", "..")] : [];
|
|
12575
|
+
const candidates = [cwd, ...execCandidates, resolve27(fallbackImportDir, "..")];
|
|
12394
12576
|
for (const candidate of candidates) {
|
|
12395
12577
|
const nearest = resolveNearestRigProjectRoot(candidate);
|
|
12396
12578
|
if (hasRigProjectMarker(nearest)) {
|
|
12397
12579
|
return nearest;
|
|
12398
12580
|
}
|
|
12399
12581
|
}
|
|
12400
|
-
return
|
|
12582
|
+
return resolve27(cwd);
|
|
12401
12583
|
}
|
|
12402
12584
|
function normalizeCliErrorCode(message2, isCliError) {
|
|
12403
12585
|
if (message2.startsWith("Invalid --policy-mode value:")) {
|
|
@@ -12464,7 +12646,7 @@ async function runRigCli(module, options = {}) {
|
|
|
12464
12646
|
runId: context.runId,
|
|
12465
12647
|
outcome,
|
|
12466
12648
|
eventsFile: context.eventBus.getEventsFile(),
|
|
12467
|
-
policyFile:
|
|
12649
|
+
policyFile: resolve27(projectRoot, "rig", "policy", "policy.json"),
|
|
12468
12650
|
policyMode: context.policyMode ?? policyMode ?? module.loadPolicy(projectRoot).mode
|
|
12469
12651
|
}, null, 2));
|
|
12470
12652
|
}
|