@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/src/commands.js
CHANGED
|
@@ -337,10 +337,10 @@ var init_plugin = __esm(() => {
|
|
|
337
337
|
// packages/cli/src/commands.ts
|
|
338
338
|
init_runner();
|
|
339
339
|
import {
|
|
340
|
-
existsSync as
|
|
340
|
+
existsSync as existsSync16,
|
|
341
341
|
readFileSync as readFileSync12
|
|
342
342
|
} from "fs";
|
|
343
|
-
import { resolve as
|
|
343
|
+
import { resolve as resolve25 } from "path";
|
|
344
344
|
import { readBuildConfig } from "@rig/runtime/build-time-config";
|
|
345
345
|
|
|
346
346
|
// packages/cli/src/commands/browser.ts
|
|
@@ -3427,8 +3427,7 @@ import { resolve as resolve11 } from "path";
|
|
|
3427
3427
|
import {
|
|
3428
3428
|
readAuthorityRun,
|
|
3429
3429
|
readJsonlFile as readJsonlFile2,
|
|
3430
|
-
|
|
3431
|
-
writeJsonFile as writeJsonFile3
|
|
3430
|
+
writeAuthorityRunRecord
|
|
3432
3431
|
} from "@rig/runtime/control-plane/authority-files";
|
|
3433
3432
|
var RIG_WORKSPACE_ID = "rig-local-workspace";
|
|
3434
3433
|
function normalizeRuntimeAdapter(value) {
|
|
@@ -3514,7 +3513,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
|
|
|
3514
3513
|
} else if ("errorText" in next) {
|
|
3515
3514
|
delete next.errorText;
|
|
3516
3515
|
}
|
|
3517
|
-
|
|
3516
|
+
writeAuthorityRunRecord(projectRoot, input.runId, next);
|
|
3518
3517
|
return next;
|
|
3519
3518
|
}
|
|
3520
3519
|
|
|
@@ -4078,7 +4077,7 @@ import { resolve as resolve14 } from "path";
|
|
|
4078
4077
|
import {
|
|
4079
4078
|
listAuthorityRuns,
|
|
4080
4079
|
readJsonlFile as readJsonlFile3,
|
|
4081
|
-
resolveAuthorityRunDir
|
|
4080
|
+
resolveAuthorityRunDir
|
|
4082
4081
|
} from "@rig/runtime/control-plane/authority-files";
|
|
4083
4082
|
|
|
4084
4083
|
// packages/cli/src/commands/_cli-format.ts
|
|
@@ -4476,7 +4475,7 @@ async function listRemoteInboxRecords(context, kind, filters) {
|
|
|
4476
4475
|
function listLocalInboxRecords(context, kind, filters) {
|
|
4477
4476
|
const fileName = kind === "approvals" ? "approvals.jsonl" : "user-input.jsonl";
|
|
4478
4477
|
const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!filters.run || entry.runId === filters.run) && (!filters.task || entry.taskId === filters.task));
|
|
4479
|
-
return runs.flatMap((entry) => readJsonlFile3(resolve14(
|
|
4478
|
+
return runs.flatMap((entry) => readJsonlFile3(resolve14(resolveAuthorityRunDir(context.projectRoot, entry.runId), fileName)).map((record) => ({
|
|
4480
4479
|
runId: entry.runId,
|
|
4481
4480
|
taskId: entry.taskId ?? undefined,
|
|
4482
4481
|
record
|
|
@@ -4524,7 +4523,7 @@ async function executeInbox(context, args) {
|
|
|
4524
4523
|
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
4525
4524
|
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);
|
|
4526
4525
|
}
|
|
4527
|
-
const approvalsPath = resolve14(
|
|
4526
|
+
const approvalsPath = resolve14(resolveAuthorityRunDir(context.projectRoot, run.value), "approvals.jsonl");
|
|
4528
4527
|
const approvals = readJsonlFile3(approvalsPath);
|
|
4529
4528
|
const resolvedAt = new Date().toISOString();
|
|
4530
4529
|
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);
|
|
@@ -4580,7 +4579,7 @@ async function executeInbox(context, args) {
|
|
|
4580
4579
|
const [key, ...restValue] = entry.split("=");
|
|
4581
4580
|
return [key, restValue.join("=")];
|
|
4582
4581
|
}));
|
|
4583
|
-
const requestsPath = resolve14(
|
|
4582
|
+
const requestsPath = resolve14(resolveAuthorityRunDir(context.projectRoot, run.value), "user-input.jsonl");
|
|
4584
4583
|
const requests = readJsonlFile3(requestsPath);
|
|
4585
4584
|
const resolvedAt = new Date().toISOString();
|
|
4586
4585
|
const next = requests.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", answers: parsedAnswers, respondedAt: resolvedAt, resolvedAt } : entry);
|
|
@@ -6047,27 +6046,23 @@ init_runner();
|
|
|
6047
6046
|
import { readFileSync as readFileSync8 } from "fs";
|
|
6048
6047
|
import { resolve as resolve19 } from "path";
|
|
6049
6048
|
import {
|
|
6050
|
-
appendJsonlRecord as appendJsonlRecord2,
|
|
6051
6049
|
appendRunLifecycleEvent,
|
|
6050
|
+
appendRunLogEntry,
|
|
6051
|
+
appendRunTimelineEntry,
|
|
6052
|
+
patchAuthorityRunRecord,
|
|
6052
6053
|
readAuthorityRun as readAuthorityRun2,
|
|
6053
|
-
resolveAuthorityRunDir as
|
|
6054
|
-
writeJsonFile as
|
|
6054
|
+
resolveAuthorityRunDir as resolveAuthorityRunDir2,
|
|
6055
|
+
writeJsonFile as writeJsonFile3
|
|
6055
6056
|
} from "@rig/runtime/control-plane/authority-files";
|
|
6056
6057
|
import { taskLookup } from "@rig/runtime/control-plane/native/task-ops";
|
|
6057
6058
|
import { readPriorPrProgressPromptSection } from "@rig/runtime/control-plane/prompt-context";
|
|
6058
6059
|
import { buildProviderTaskRunInstructionLines } from "@rig/runtime/control-plane/provider/runtime-instructions";
|
|
6059
6060
|
import { loadRigTaskRunSkillBody } from "@rig/runtime/control-plane/provider/rig-task-run-skill";
|
|
6060
6061
|
function patchAuthorityRun(projectRoot, runId, patch) {
|
|
6061
|
-
const
|
|
6062
|
-
if (!
|
|
6062
|
+
const next = patchAuthorityRunRecord(projectRoot, runId, patch);
|
|
6063
|
+
if (!next) {
|
|
6063
6064
|
throw new CliError2(`Run not found: ${runId}`, 2);
|
|
6064
6065
|
}
|
|
6065
|
-
const next = {
|
|
6066
|
-
...current,
|
|
6067
|
-
...patch,
|
|
6068
|
-
updatedAt: new Date().toISOString()
|
|
6069
|
-
};
|
|
6070
|
-
writeJsonFile4(resolve19(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
|
|
6071
6066
|
return next;
|
|
6072
6067
|
}
|
|
6073
6068
|
function touchAuthorityRun(projectRoot, runId) {
|
|
@@ -6075,21 +6070,21 @@ function touchAuthorityRun(projectRoot, runId) {
|
|
|
6075
6070
|
if (!current) {
|
|
6076
6071
|
return;
|
|
6077
6072
|
}
|
|
6078
|
-
|
|
6073
|
+
writeJsonFile3(resolve19(resolveAuthorityRunDir2(projectRoot, runId), "run.json"), {
|
|
6079
6074
|
...current,
|
|
6080
6075
|
updatedAt: new Date().toISOString()
|
|
6081
6076
|
});
|
|
6082
6077
|
}
|
|
6083
6078
|
function appendRunTimeline(projectRoot, runId, value) {
|
|
6084
|
-
|
|
6079
|
+
appendRunTimelineEntry(projectRoot, runId, value);
|
|
6085
6080
|
touchAuthorityRun(projectRoot, runId);
|
|
6086
6081
|
}
|
|
6087
6082
|
function appendRunLog(projectRoot, runId, value) {
|
|
6088
|
-
|
|
6083
|
+
appendRunLogEntry(projectRoot, runId, value);
|
|
6089
6084
|
touchAuthorityRun(projectRoot, runId);
|
|
6090
6085
|
}
|
|
6091
6086
|
function appendRunAction(projectRoot, runId, value) {
|
|
6092
|
-
|
|
6087
|
+
appendRunTimelineEntry(projectRoot, runId, {
|
|
6093
6088
|
id: value.id,
|
|
6094
6089
|
type: "action",
|
|
6095
6090
|
actionType: value.actionType,
|
|
@@ -6310,7 +6305,7 @@ import { resolve as resolve20 } from "path";
|
|
|
6310
6305
|
import {
|
|
6311
6306
|
listAuthorityRuns as listAuthorityRuns2,
|
|
6312
6307
|
readAuthorityRun as readAuthorityRun3,
|
|
6313
|
-
resolveAuthorityRunDir as
|
|
6308
|
+
resolveAuthorityRunDir as resolveAuthorityRunDir3,
|
|
6314
6309
|
resolveTaskArtifactDirs
|
|
6315
6310
|
} from "@rig/runtime/control-plane/authority-files";
|
|
6316
6311
|
import { changedFilesForTask } from "@rig/runtime/control-plane/native/task-ops";
|
|
@@ -6344,7 +6339,7 @@ async function executeInspect(context, args) {
|
|
|
6344
6339
|
}
|
|
6345
6340
|
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: serverRun.runId, source: "server", entries } };
|
|
6346
6341
|
}
|
|
6347
|
-
const logsPath = resolve20(
|
|
6342
|
+
const logsPath = resolve20(resolveAuthorityRunDir3(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
6348
6343
|
if (!existsSync12(logsPath)) {
|
|
6349
6344
|
throw new CliError2(`No logs found for run ${latestRun.runId}.`);
|
|
6350
6345
|
}
|
|
@@ -7074,7 +7069,7 @@ init__parsers();
|
|
|
7074
7069
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
7075
7070
|
import {
|
|
7076
7071
|
listAuthorityRuns as listAuthorityRuns3,
|
|
7077
|
-
readAuthorityRun as
|
|
7072
|
+
readAuthorityRun as readAuthorityRun5
|
|
7078
7073
|
} from "@rig/runtime/control-plane/authority-files";
|
|
7079
7074
|
import {
|
|
7080
7075
|
cleanupRunState,
|
|
@@ -7090,6 +7085,144 @@ import {
|
|
|
7090
7085
|
} from "@rig/runtime/control-plane/native/run-ops";
|
|
7091
7086
|
import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
|
|
7092
7087
|
|
|
7088
|
+
// packages/cli/src/commands/_run-replay.ts
|
|
7089
|
+
import { existsSync as existsSync13, readdirSync as readdirSync2 } from "fs";
|
|
7090
|
+
import { join as join2, resolve as resolve21 } from "path";
|
|
7091
|
+
import {
|
|
7092
|
+
readAuthorityRun as readAuthorityRun4,
|
|
7093
|
+
readJsonlFile as readJsonlFile4,
|
|
7094
|
+
runLifecycleLogPath
|
|
7095
|
+
} from "@rig/runtime/control-plane/authority-files";
|
|
7096
|
+
function asRecord(value) {
|
|
7097
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7098
|
+
}
|
|
7099
|
+
function text2(value) {
|
|
7100
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
7101
|
+
}
|
|
7102
|
+
function snippet(value, max = 120) {
|
|
7103
|
+
const raw = text2(value);
|
|
7104
|
+
if (!raw)
|
|
7105
|
+
return null;
|
|
7106
|
+
const flat = raw.replace(/\s+/g, " ");
|
|
7107
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
7108
|
+
}
|
|
7109
|
+
function summarizeLifecycleEntry(entry) {
|
|
7110
|
+
const type = text2(entry.type) ?? "event";
|
|
7111
|
+
switch (type) {
|
|
7112
|
+
case "status": {
|
|
7113
|
+
const anchor = text2(entry.sessionId);
|
|
7114
|
+
return [
|
|
7115
|
+
`status \u2192 ${text2(entry.status) ?? "(unknown)"}`,
|
|
7116
|
+
snippet(entry.detail) ? `\u2014 ${snippet(entry.detail)}` : null,
|
|
7117
|
+
anchor ? `[session ${anchor}]` : null
|
|
7118
|
+
].filter(Boolean).join(" ");
|
|
7119
|
+
}
|
|
7120
|
+
case "timeline-entry": {
|
|
7121
|
+
const payload = asRecord(entry.payload) ?? {};
|
|
7122
|
+
const kind = text2(payload.type) ?? "entry";
|
|
7123
|
+
const body = snippet(payload.title) ?? snippet(payload.text) ?? snippet(payload.detail);
|
|
7124
|
+
const state = text2(payload.state);
|
|
7125
|
+
return [`timeline ${kind}`, body ? `\u2014 ${body}` : null, state ? `(${state})` : null].filter(Boolean).join(" ");
|
|
7126
|
+
}
|
|
7127
|
+
case "log-entry": {
|
|
7128
|
+
const payload = asRecord(entry.payload) ?? {};
|
|
7129
|
+
const title = snippet(payload.title) ?? "log";
|
|
7130
|
+
const detail = snippet(payload.detail);
|
|
7131
|
+
return [`log ${title}`, detail ? `\u2014 ${detail}` : null].filter(Boolean).join(" ");
|
|
7132
|
+
}
|
|
7133
|
+
case "record-patch": {
|
|
7134
|
+
const patch = asRecord(entry.patch) ?? {};
|
|
7135
|
+
const keys = Object.keys(patch);
|
|
7136
|
+
const shown = keys.slice(0, 8).join(", ");
|
|
7137
|
+
return `record-patch {${shown}${keys.length > 8 ? `, +${keys.length - 8} more` : ""}}`;
|
|
7138
|
+
}
|
|
7139
|
+
case "timeline":
|
|
7140
|
+
return "timeline updated (signal)";
|
|
7141
|
+
case "log":
|
|
7142
|
+
return `log signal${snippet(entry.title) ? ` \u2014 ${snippet(entry.title)}` : ""}`;
|
|
7143
|
+
case "completed":
|
|
7144
|
+
return "run completed";
|
|
7145
|
+
case "failed":
|
|
7146
|
+
return `run failed${snippet(entry.error) ? ` \u2014 ${snippet(entry.error)}` : ""}`;
|
|
7147
|
+
default:
|
|
7148
|
+
return type;
|
|
7149
|
+
}
|
|
7150
|
+
}
|
|
7151
|
+
function summarizeSessionEntry(entry) {
|
|
7152
|
+
const type = text2(entry.type) ?? "entry";
|
|
7153
|
+
const message2 = asRecord(entry.message);
|
|
7154
|
+
const role = text2(message2?.role);
|
|
7155
|
+
const content = message2?.content;
|
|
7156
|
+
let body = null;
|
|
7157
|
+
if (typeof content === "string") {
|
|
7158
|
+
body = snippet(content);
|
|
7159
|
+
} else if (Array.isArray(content)) {
|
|
7160
|
+
body = snippet(content.map((part) => text2(asRecord(part)?.text) ?? "").filter(Boolean).join(" "));
|
|
7161
|
+
}
|
|
7162
|
+
return [
|
|
7163
|
+
`pi ${type}`,
|
|
7164
|
+
role ? `(${role})` : null,
|
|
7165
|
+
body ? `\u2014 ${body}` : null
|
|
7166
|
+
].filter(Boolean).join(" ");
|
|
7167
|
+
}
|
|
7168
|
+
function sessionEntryTimestamp(entry) {
|
|
7169
|
+
return text2(entry.timestamp) ?? text2(entry.at) ?? text2(entry.createdAt) ?? null;
|
|
7170
|
+
}
|
|
7171
|
+
function resolveRunSessionFile(record) {
|
|
7172
|
+
const piSession = record?.piSession ?? null;
|
|
7173
|
+
if (!piSession)
|
|
7174
|
+
return null;
|
|
7175
|
+
const recorded = text2(piSession.sessionFile);
|
|
7176
|
+
if (recorded && existsSync13(recorded)) {
|
|
7177
|
+
return recorded;
|
|
7178
|
+
}
|
|
7179
|
+
const cwd = text2(piSession.cwd);
|
|
7180
|
+
const sessionId = text2(piSession.sessionId);
|
|
7181
|
+
if (!cwd || !sessionId)
|
|
7182
|
+
return null;
|
|
7183
|
+
const sessionDir = resolve21(cwd, ".rig", "session");
|
|
7184
|
+
try {
|
|
7185
|
+
const match = readdirSync2(sessionDir).find((name) => name.endsWith(`_${sessionId}.jsonl`));
|
|
7186
|
+
return match ? join2(sessionDir, match) : null;
|
|
7187
|
+
} catch {
|
|
7188
|
+
return null;
|
|
7189
|
+
}
|
|
7190
|
+
}
|
|
7191
|
+
function buildRunReplay(projectRoot, runId, options = {}) {
|
|
7192
|
+
const logPath = runLifecycleLogPath(projectRoot, runId);
|
|
7193
|
+
const record = readAuthorityRun4(projectRoot, runId);
|
|
7194
|
+
const lifecycleEntries = readJsonlFile4(logPath).map((entry) => asRecord(entry)).filter((entry) => entry !== null);
|
|
7195
|
+
const merged = lifecycleEntries.map((entry) => ({
|
|
7196
|
+
at: text2(entry.at),
|
|
7197
|
+
source: "run",
|
|
7198
|
+
summary: summarizeLifecycleEntry(entry)
|
|
7199
|
+
}));
|
|
7200
|
+
let sessionFile = null;
|
|
7201
|
+
let sessionEntryCount = 0;
|
|
7202
|
+
if (options.withSession) {
|
|
7203
|
+
sessionFile = resolveRunSessionFile(record);
|
|
7204
|
+
if (sessionFile) {
|
|
7205
|
+
let lastSeenAt = null;
|
|
7206
|
+
const sessionLines = readJsonlFile4(sessionFile).map((entry) => asRecord(entry)).filter((entry) => entry !== null).map((entry) => {
|
|
7207
|
+
lastSeenAt = sessionEntryTimestamp(entry) ?? lastSeenAt;
|
|
7208
|
+
return { at: lastSeenAt, source: "session", summary: summarizeSessionEntry(entry) };
|
|
7209
|
+
});
|
|
7210
|
+
sessionEntryCount = sessionLines.length;
|
|
7211
|
+
merged.push(...sessionLines);
|
|
7212
|
+
merged.sort((left, right) => (left.at ?? "").localeCompare(right.at ?? ""));
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
const lines = merged.map((line) => `${line.at ?? "(no timestamp) "} ${line.source === "run" ? "run " : "session"} ${line.summary}`);
|
|
7216
|
+
return {
|
|
7217
|
+
runId,
|
|
7218
|
+
logPath,
|
|
7219
|
+
sessionFile,
|
|
7220
|
+
entryCount: lifecycleEntries.length,
|
|
7221
|
+
sessionEntryCount,
|
|
7222
|
+
lines
|
|
7223
|
+
};
|
|
7224
|
+
}
|
|
7225
|
+
|
|
7093
7226
|
// packages/cli/src/commands/_operator-surface.ts
|
|
7094
7227
|
import { createInterface } from "readline";
|
|
7095
7228
|
import { createInterface as createPromptInterface } from "readline/promises";
|
|
@@ -7188,22 +7321,22 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
7188
7321
|
for (const [index, entry] of entries.entries()) {
|
|
7189
7322
|
const id = entryId(entry, `timeline:${index}:${String(entry.cursor ?? "")}`);
|
|
7190
7323
|
if (entry.type === "assistant_message" && typeof entry.text === "string") {
|
|
7191
|
-
const
|
|
7324
|
+
const text3 = entry.text;
|
|
7192
7325
|
const previousText = assistantTextById.get(id) ?? "";
|
|
7193
|
-
if (!previousText &&
|
|
7326
|
+
if (!previousText && text3.trim()) {
|
|
7194
7327
|
writeLine("[Pi assistant]");
|
|
7195
7328
|
}
|
|
7196
|
-
if (
|
|
7197
|
-
const delta =
|
|
7329
|
+
if (text3.startsWith(previousText)) {
|
|
7330
|
+
const delta = text3.slice(previousText.length);
|
|
7198
7331
|
if (delta)
|
|
7199
7332
|
output.write(delta);
|
|
7200
|
-
} else if (
|
|
7333
|
+
} else if (text3.trim() && text3 !== previousText) {
|
|
7201
7334
|
if (previousText)
|
|
7202
7335
|
writeLine(`
|
|
7203
7336
|
[Pi assistant]`);
|
|
7204
|
-
output.write(
|
|
7337
|
+
output.write(text3);
|
|
7205
7338
|
}
|
|
7206
|
-
assistantTextById.set(id,
|
|
7339
|
+
assistantTextById.set(id, text3);
|
|
7207
7340
|
continue;
|
|
7208
7341
|
}
|
|
7209
7342
|
if (seenTimeline.has(id))
|
|
@@ -7218,15 +7351,15 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
7218
7351
|
continue;
|
|
7219
7352
|
}
|
|
7220
7353
|
if (entry.type === "action") {
|
|
7221
|
-
const
|
|
7222
|
-
if (
|
|
7223
|
-
writeLine(`[Rig action] ${
|
|
7354
|
+
const text3 = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
7355
|
+
if (text3)
|
|
7356
|
+
writeLine(`[Rig action] ${text3}`);
|
|
7224
7357
|
continue;
|
|
7225
7358
|
}
|
|
7226
7359
|
if (entry.type === "user_message") {
|
|
7227
|
-
const
|
|
7228
|
-
if (
|
|
7229
|
-
writeLine(`[Operator] ${
|
|
7360
|
+
const text3 = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
7361
|
+
if (text3)
|
|
7362
|
+
writeLine(`[Operator] ${text3}`);
|
|
7230
7363
|
continue;
|
|
7231
7364
|
}
|
|
7232
7365
|
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
@@ -7306,7 +7439,7 @@ async function promptForTaskSelection(question) {
|
|
|
7306
7439
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
7307
7440
|
import { mkdtempSync, rmSync as rmSync5 } from "fs";
|
|
7308
7441
|
import { tmpdir } from "os";
|
|
7309
|
-
import { join as
|
|
7442
|
+
import { join as join3 } from "path";
|
|
7310
7443
|
import {
|
|
7311
7444
|
createAgentSessionFromServices,
|
|
7312
7445
|
createAgentSessionServices,
|
|
@@ -7438,15 +7571,15 @@ class RigRemoteSessionController {
|
|
|
7438
7571
|
for (const compaction of this.pendingCompactions.splice(0))
|
|
7439
7572
|
compaction.reject(new Error("Remote session closed."));
|
|
7440
7573
|
}
|
|
7441
|
-
async sendPrompt(
|
|
7442
|
-
await this.transport.sendPrompt(this.context, this.runId,
|
|
7574
|
+
async sendPrompt(text3, streamingBehavior) {
|
|
7575
|
+
await this.transport.sendPrompt(this.context, this.runId, text3, streamingBehavior);
|
|
7443
7576
|
}
|
|
7444
|
-
async sendCommand(
|
|
7445
|
-
const result = await this.transport.runCommand(this.context, this.runId,
|
|
7577
|
+
async sendCommand(text3) {
|
|
7578
|
+
const result = await this.transport.runCommand(this.context, this.runId, text3);
|
|
7446
7579
|
return typeof result.message === "string" ? result.message : "worker command accepted";
|
|
7447
7580
|
}
|
|
7448
|
-
async sendShell(
|
|
7449
|
-
await this.transport.sendShell(this.context, this.runId,
|
|
7581
|
+
async sendShell(text3) {
|
|
7582
|
+
await this.transport.sendShell(this.context, this.runId, text3);
|
|
7450
7583
|
}
|
|
7451
7584
|
async abort() {
|
|
7452
7585
|
await this.transport.abort(this.context, this.runId);
|
|
@@ -7598,8 +7731,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7598
7731
|
replaceRemoteMessages(messages) {
|
|
7599
7732
|
this.agent.state.messages = messages;
|
|
7600
7733
|
}
|
|
7601
|
-
async expandLocalInput(
|
|
7602
|
-
let current =
|
|
7734
|
+
async expandLocalInput(text3) {
|
|
7735
|
+
let current = text3;
|
|
7603
7736
|
const runner = this.extensionRunner;
|
|
7604
7737
|
if (runner.hasHandlers("input")) {
|
|
7605
7738
|
const result = await runner.emitInput(current, undefined, "interactive");
|
|
@@ -7612,8 +7745,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7612
7745
|
current = expandPromptTemplate(current, [...this.promptTemplates]);
|
|
7613
7746
|
return current;
|
|
7614
7747
|
}
|
|
7615
|
-
async prompt(
|
|
7616
|
-
const trimmed =
|
|
7748
|
+
async prompt(text3, options) {
|
|
7749
|
+
const trimmed = text3.trim();
|
|
7617
7750
|
if (!trimmed)
|
|
7618
7751
|
return;
|
|
7619
7752
|
if (trimmed.startsWith("/")) {
|
|
@@ -7642,8 +7775,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7642
7775
|
options?.preflightResult?.(true);
|
|
7643
7776
|
await this.remote.sendPrompt(expanded, behavior);
|
|
7644
7777
|
}
|
|
7645
|
-
async steer(
|
|
7646
|
-
const trimmed =
|
|
7778
|
+
async steer(text3) {
|
|
7779
|
+
const trimmed = text3.trim();
|
|
7647
7780
|
if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
|
|
7648
7781
|
return;
|
|
7649
7782
|
const expanded = await this.expandLocalInput(trimmed);
|
|
@@ -7651,8 +7784,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7651
7784
|
return;
|
|
7652
7785
|
await this.remote.sendPrompt(expanded, "steer");
|
|
7653
7786
|
}
|
|
7654
|
-
async followUp(
|
|
7655
|
-
const trimmed =
|
|
7787
|
+
async followUp(text3) {
|
|
7788
|
+
const trimmed = text3.trim();
|
|
7656
7789
|
if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
|
|
7657
7790
|
return;
|
|
7658
7791
|
const expanded = await this.expandLocalInput(trimmed);
|
|
@@ -7664,8 +7797,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7664
7797
|
await this.remote.abort();
|
|
7665
7798
|
}
|
|
7666
7799
|
async compact(customInstructions) {
|
|
7667
|
-
const pending = new Promise((
|
|
7668
|
-
this.remote.registerPendingCompaction({ resolve:
|
|
7800
|
+
const pending = new Promise((resolve22, reject) => {
|
|
7801
|
+
this.remote.registerPendingCompaction({ resolve: resolve22, reject });
|
|
7669
7802
|
});
|
|
7670
7803
|
await this.remote.sendCommand(`/compact${customInstructions ? ` ${customInstructions}` : ""}`);
|
|
7671
7804
|
return pending;
|
|
@@ -7734,8 +7867,8 @@ class RigRemoteAgentSession extends PiAgentSession {
|
|
|
7734
7867
|
function createRemoteBashOperations(controller, excludeFromContext) {
|
|
7735
7868
|
return {
|
|
7736
7869
|
exec(command, _cwd, execOptions) {
|
|
7737
|
-
return new Promise((
|
|
7738
|
-
const pending = { onData: execOptions.onData, resolve:
|
|
7870
|
+
return new Promise((resolve22, reject) => {
|
|
7871
|
+
const pending = { onData: execOptions.onData, resolve: resolve22, reject, sawChunk: false };
|
|
7739
7872
|
const cleanup = () => {
|
|
7740
7873
|
execOptions.signal?.removeEventListener("abort", onAbort);
|
|
7741
7874
|
if (timer)
|
|
@@ -7899,8 +8032,8 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
7899
8032
|
const prefix = busy ? `${SPINNER_FRAMES[frame]} ` : connected ? "\u25CF " : "\u25CB ";
|
|
7900
8033
|
ctx.ui.setStatus("rig-worker-pi", `${prefix}${statusText}`);
|
|
7901
8034
|
};
|
|
7902
|
-
const setStatus = (ctx,
|
|
7903
|
-
statusText =
|
|
8035
|
+
const setStatus = (ctx, text3, isBusy) => {
|
|
8036
|
+
statusText = text3;
|
|
7904
8037
|
busy = isBusy;
|
|
7905
8038
|
renderStatus(ctx);
|
|
7906
8039
|
};
|
|
@@ -7944,7 +8077,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
7944
8077
|
ctx.ui.notify("Initial message sent to the worker Pi daemon.", "info");
|
|
7945
8078
|
const nativeUi = ctx.ui;
|
|
7946
8079
|
options.controller.setUiHooks({
|
|
7947
|
-
onStatusText: (
|
|
8080
|
+
onStatusText: (text3) => setStatus(ctx, text3, !connected),
|
|
7948
8081
|
onActivity: (label, detail) => {
|
|
7949
8082
|
const active = label !== "idle" && !/complete|ready/i.test(label);
|
|
7950
8083
|
setStatus(ctx, [label, detail].filter(Boolean).join(" \u2014 "), active);
|
|
@@ -8001,7 +8134,7 @@ function setTemporaryEnv(updates) {
|
|
|
8001
8134
|
};
|
|
8002
8135
|
}
|
|
8003
8136
|
async function attachRunBundledPiFrontend(context, input) {
|
|
8004
|
-
const tempSessionDir = mkdtempSync(
|
|
8137
|
+
const tempSessionDir = mkdtempSync(join3(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
8005
8138
|
const restoreEnv = setTemporaryEnv({
|
|
8006
8139
|
PI_CODING_AGENT_SESSION_DIR: tempSessionDir,
|
|
8007
8140
|
PI_SKIP_VERSION_CHECK: "1",
|
|
@@ -8321,7 +8454,7 @@ async function executeRun(context, args) {
|
|
|
8321
8454
|
if (!runId) {
|
|
8322
8455
|
throw new CliError2("run show requires a run id.");
|
|
8323
8456
|
}
|
|
8324
|
-
const record =
|
|
8457
|
+
const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails2(await getRunDetailsViaServer(context, runId).catch(() => ({})));
|
|
8325
8458
|
if (!record) {
|
|
8326
8459
|
throw new CliError2(`Run not found: ${runId}`, 2);
|
|
8327
8460
|
}
|
|
@@ -8359,6 +8492,46 @@ async function executeRun(context, args) {
|
|
|
8359
8492
|
}
|
|
8360
8493
|
return { ok: true, group: "run", command, details: { runId: run.value, events, cursor } };
|
|
8361
8494
|
}
|
|
8495
|
+
case "replay": {
|
|
8496
|
+
let pending = rest;
|
|
8497
|
+
const run = takeOption(pending, "--run");
|
|
8498
|
+
pending = run.rest;
|
|
8499
|
+
const withSession = takeFlag(pending, "--with-session");
|
|
8500
|
+
pending = withSession.rest;
|
|
8501
|
+
const positionalRunId = pending.length > 0 && pending[0] && !pending[0].startsWith("-") ? pending[0] : undefined;
|
|
8502
|
+
const extra = positionalRunId ? pending.slice(1) : pending;
|
|
8503
|
+
requireNoExtraArgs(extra, "rig run replay <id>|--run <id> [--with-session]");
|
|
8504
|
+
const runId = run.value ?? positionalRunId;
|
|
8505
|
+
if (!runId) {
|
|
8506
|
+
throw new CliError2("run replay requires a run id.", 2);
|
|
8507
|
+
}
|
|
8508
|
+
const replay = buildRunReplay(context.projectRoot, runId, { withSession: withSession.value });
|
|
8509
|
+
if (replay.entryCount === 0 && replay.sessionEntryCount === 0) {
|
|
8510
|
+
throw new CliError2(`No run.jsonl lifecycle log found for ${runId} (looked at ${replay.logPath}).`, 2);
|
|
8511
|
+
}
|
|
8512
|
+
if (context.outputMode === "text") {
|
|
8513
|
+
console.log(`Replay of ${runId} (${replay.entryCount} lifecycle entries${withSession.value ? `, ${replay.sessionEntryCount} session entries` : ""}):`);
|
|
8514
|
+
for (const line of replay.lines) {
|
|
8515
|
+
console.log(line);
|
|
8516
|
+
}
|
|
8517
|
+
if (withSession.value && !replay.sessionFile) {
|
|
8518
|
+
console.log("(no Pi session file resolvable from the run record; showing run.jsonl only)");
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
return {
|
|
8522
|
+
ok: true,
|
|
8523
|
+
group: "run",
|
|
8524
|
+
command,
|
|
8525
|
+
details: {
|
|
8526
|
+
runId,
|
|
8527
|
+
logPath: replay.logPath,
|
|
8528
|
+
sessionFile: replay.sessionFile,
|
|
8529
|
+
entryCount: replay.entryCount,
|
|
8530
|
+
sessionEntryCount: replay.sessionEntryCount,
|
|
8531
|
+
lines: replay.lines
|
|
8532
|
+
}
|
|
8533
|
+
};
|
|
8534
|
+
}
|
|
8362
8535
|
case "attach": {
|
|
8363
8536
|
let pending = rest;
|
|
8364
8537
|
const runOption = takeOption(pending, "--run");
|
|
@@ -8681,7 +8854,7 @@ async function executeServer(context, args, options) {
|
|
|
8681
8854
|
init_runner();
|
|
8682
8855
|
import { readFileSync as readFileSync10 } from "fs";
|
|
8683
8856
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
8684
|
-
import { resolve as
|
|
8857
|
+
import { resolve as resolve22 } from "path";
|
|
8685
8858
|
import { cancel as cancel4, confirm as confirm2, isCancel as isCancel4 } from "@clack/prompts";
|
|
8686
8859
|
import {
|
|
8687
8860
|
taskArtifactDir,
|
|
@@ -8859,6 +9032,7 @@ var PRIMARY_GROUPS = [
|
|
|
8859
9032
|
{ command: "stop [<run-id>|--run <id>]", description: "Request stop for one run or local active runs.", primary: true },
|
|
8860
9033
|
{ command: "steer <run-id> --message <text>", description: "Queue a steering message into a live worker without attaching." },
|
|
8861
9034
|
{ command: "timeline --run <id> [--follow]", description: "Stream raw run timeline events." },
|
|
9035
|
+
{ 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." },
|
|
8862
9036
|
{ command: "resume", description: "Resume the most recent interrupted local run." },
|
|
8863
9037
|
{ command: "restart", description: "Restart the most recent local run from a clean runtime." },
|
|
8864
9038
|
{ command: "delete|cleanup", description: "Remove completed run records/artifacts." }
|
|
@@ -9446,7 +9620,7 @@ async function executeTask(context, args, options) {
|
|
|
9446
9620
|
const fileFlag = takeOption(rest.slice(1), "--file");
|
|
9447
9621
|
let content;
|
|
9448
9622
|
if (fileFlag.value) {
|
|
9449
|
-
content = readFileSync10(
|
|
9623
|
+
content = readFileSync10(resolve22(context.projectRoot, fileFlag.value), "utf-8");
|
|
9450
9624
|
} else {
|
|
9451
9625
|
content = await readStdin();
|
|
9452
9626
|
}
|
|
@@ -9680,8 +9854,8 @@ async function executeTask(context, args, options) {
|
|
|
9680
9854
|
|
|
9681
9855
|
// packages/cli/src/commands/task-run-driver.ts
|
|
9682
9856
|
init_runner();
|
|
9683
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
9684
|
-
import { resolve as
|
|
9857
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
9858
|
+
import { resolve as resolve23 } from "path";
|
|
9685
9859
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
9686
9860
|
import { createInterface as createLineInterface } from "readline";
|
|
9687
9861
|
import { loadConfig as loadConfig2 } from "@rig/core/load-config";
|
|
@@ -9705,7 +9879,7 @@ import {
|
|
|
9705
9879
|
isCodexExecRecord
|
|
9706
9880
|
} from "@rig/runtime/control-plane/provider/codex-exec-records";
|
|
9707
9881
|
import { resolvePreferredShellBinary } from "@rig/runtime/control-plane/native/run-ops";
|
|
9708
|
-
import { readAuthorityRun as
|
|
9882
|
+
import { readAuthorityRun as readAuthorityRun6, readJsonFile as readJsonFile3, resolveTaskArtifactDirs as resolveTaskArtifactDirs2 } from "@rig/runtime/control-plane/authority-files";
|
|
9709
9883
|
import {
|
|
9710
9884
|
buildTaskRunLifecycleComment
|
|
9711
9885
|
} from "@rig/runtime/control-plane/tasks/source-lifecycle";
|
|
@@ -9765,12 +9939,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
9765
9939
|
return 0;
|
|
9766
9940
|
let copied = 0;
|
|
9767
9941
|
for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
|
|
9768
|
-
const sourcePath =
|
|
9769
|
-
const targetPath =
|
|
9942
|
+
const sourcePath = resolve23(sourceRoot, relativePath);
|
|
9943
|
+
const targetPath = resolve23(targetRoot, relativePath);
|
|
9770
9944
|
try {
|
|
9771
9945
|
if (!statSync2(sourcePath).isFile())
|
|
9772
9946
|
continue;
|
|
9773
|
-
mkdirSync8(
|
|
9947
|
+
mkdirSync8(resolve23(targetPath, ".."), { recursive: true });
|
|
9774
9948
|
copyFileSync3(sourcePath, targetPath);
|
|
9775
9949
|
copied += 1;
|
|
9776
9950
|
} catch {}
|
|
@@ -9809,7 +9983,7 @@ function buildDirtyBaselineHandshakeEnv(input) {
|
|
|
9809
9983
|
return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
|
|
9810
9984
|
return {
|
|
9811
9985
|
RIG_BASELINE_MODE: "dirty-snapshot",
|
|
9812
|
-
RIG_DIRTY_BASELINE_READY_FILE:
|
|
9986
|
+
RIG_DIRTY_BASELINE_READY_FILE: resolve23(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
|
|
9813
9987
|
};
|
|
9814
9988
|
}
|
|
9815
9989
|
function positiveInt(value, fallback) {
|
|
@@ -9914,9 +10088,9 @@ function createCommandRunner(binary) {
|
|
|
9914
10088
|
const stderrChunks = [];
|
|
9915
10089
|
child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
9916
10090
|
child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
9917
|
-
return await new Promise((
|
|
9918
|
-
child.once("error", (error) =>
|
|
9919
|
-
child.once("close", (code) =>
|
|
10091
|
+
return await new Promise((resolve24) => {
|
|
10092
|
+
child.once("error", (error) => resolve24({ exitCode: 1, stderr: error.message }));
|
|
10093
|
+
child.once("close", (code) => resolve24({
|
|
9920
10094
|
exitCode: code ?? 1,
|
|
9921
10095
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
9922
10096
|
stderr: Buffer.concat(stderrChunks).toString("utf8")
|
|
@@ -9990,7 +10164,7 @@ async function runTaskRunPostValidationLifecycle(input) {
|
|
|
9990
10164
|
config,
|
|
9991
10165
|
sourceTask: input.sourceTask,
|
|
9992
10166
|
uploadedSnapshot: input.uploadedSnapshot,
|
|
9993
|
-
artifactRoot:
|
|
10167
|
+
artifactRoot: resolve23(input.projectRoot, "artifacts", taskId3),
|
|
9994
10168
|
command: ghCommand,
|
|
9995
10169
|
gitCommand,
|
|
9996
10170
|
steerPi,
|
|
@@ -10120,7 +10294,7 @@ function summarizeValidationFailure(projectRoot, taskId3) {
|
|
|
10120
10294
|
return null;
|
|
10121
10295
|
}
|
|
10122
10296
|
for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId3)) {
|
|
10123
|
-
const summary = readJsonFile3(
|
|
10297
|
+
const summary = readJsonFile3(resolve23(artifactDir, "validation-summary.json"), null);
|
|
10124
10298
|
if (!summary || summary.status !== "fail") {
|
|
10125
10299
|
continue;
|
|
10126
10300
|
}
|
|
@@ -10201,9 +10375,9 @@ function readTaskRunAcceptedArtifactState(input) {
|
|
|
10201
10375
|
if (!input.taskId || !input.workspaceDir) {
|
|
10202
10376
|
return { accepted: false, reason: null };
|
|
10203
10377
|
}
|
|
10204
|
-
const artifactDir =
|
|
10205
|
-
const reviewStatusPath =
|
|
10206
|
-
const taskResultPath =
|
|
10378
|
+
const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
|
|
10379
|
+
const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
|
|
10380
|
+
const taskResultPath = resolve23(artifactDir, "task-result.json");
|
|
10207
10381
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
10208
10382
|
if (reviewStatus !== "APPROVED") {
|
|
10209
10383
|
return { accepted: false, reason: null };
|
|
@@ -10240,12 +10414,12 @@ function resolveTaskRunRetryContext(input) {
|
|
|
10240
10414
|
if (!input.taskId || !input.workspaceDir) {
|
|
10241
10415
|
return { shouldRetry: false, failureDetail: null, nextPrompt: null };
|
|
10242
10416
|
}
|
|
10243
|
-
const artifactDir =
|
|
10244
|
-
const reviewStatePath =
|
|
10245
|
-
const reviewFeedbackPath =
|
|
10246
|
-
const reviewStatusPath =
|
|
10247
|
-
const failedApproachesPath =
|
|
10248
|
-
const validationSummaryPath =
|
|
10417
|
+
const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
|
|
10418
|
+
const reviewStatePath = resolve23(artifactDir, "review-state.json");
|
|
10419
|
+
const reviewFeedbackPath = resolve23(artifactDir, "review-feedback.md");
|
|
10420
|
+
const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
|
|
10421
|
+
const failedApproachesPath = resolve23(input.workspaceDir, ".rig", "state", "failed_approaches.md");
|
|
10422
|
+
const validationSummaryPath = resolve23(artifactDir, "validation-summary.json");
|
|
10249
10423
|
const reviewState = readJsonFile3(reviewStatePath, null);
|
|
10250
10424
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
10251
10425
|
const reviewRejected = isTaskRunReviewRejected(reviewState);
|
|
@@ -10431,7 +10605,7 @@ function appendToolTimelineFromLog(input) {
|
|
|
10431
10605
|
});
|
|
10432
10606
|
}
|
|
10433
10607
|
function readTaskRunReviewStatus(reviewStatusPath) {
|
|
10434
|
-
if (!
|
|
10608
|
+
if (!existsSync14(reviewStatusPath)) {
|
|
10435
10609
|
return null;
|
|
10436
10610
|
}
|
|
10437
10611
|
try {
|
|
@@ -10511,7 +10685,7 @@ async function updateTaskSourceAfterDriverRun(projectRoot, runId, taskId3, sourc
|
|
|
10511
10685
|
}
|
|
10512
10686
|
}
|
|
10513
10687
|
function readRunSourceTaskContract(projectRoot, runId, taskId3) {
|
|
10514
|
-
const run =
|
|
10688
|
+
const run = readAuthorityRun6(projectRoot, runId);
|
|
10515
10689
|
const raw = run?.sourceTask;
|
|
10516
10690
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
10517
10691
|
return null;
|
|
@@ -10552,8 +10726,10 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
10552
10726
|
process.stderr.on("error", () => {});
|
|
10553
10727
|
configureRunEventSink(context.projectRoot);
|
|
10554
10728
|
const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
|
|
10555
|
-
const existingRunRecord =
|
|
10729
|
+
const existingRunRecord = readAuthorityRun6(context.projectRoot, input.runId);
|
|
10556
10730
|
const resumeMode = process.env.RIG_RUN_RESUME === "1";
|
|
10731
|
+
let latestPiSessionId = typeof existingRunRecord?.piSession?.sessionId === "string" && existingRunRecord.piSession.sessionId.trim() ? existingRunRecord.piSession.sessionId : null;
|
|
10732
|
+
const sessionAnchor = () => latestPiSessionId ? { sessionId: latestPiSessionId } : {};
|
|
10557
10733
|
const resumePreviousStatus = String(existingRunRecord?.status ?? "").toLowerCase();
|
|
10558
10734
|
const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
|
|
10559
10735
|
let prompt = buildRunPrompt({
|
|
@@ -10626,7 +10802,8 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
10626
10802
|
type: "status",
|
|
10627
10803
|
runId: input.runId,
|
|
10628
10804
|
status: "preparing",
|
|
10629
|
-
detail: input.taskId ?? input.title ?? runtimeTaskId
|
|
10805
|
+
detail: input.taskId ?? input.title ?? runtimeTaskId,
|
|
10806
|
+
...sessionAnchor()
|
|
10630
10807
|
});
|
|
10631
10808
|
appendRunLog(context.projectRoot, input.runId, {
|
|
10632
10809
|
id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
|
|
@@ -10652,15 +10829,15 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
10652
10829
|
const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
|
|
10653
10830
|
const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
|
|
10654
10831
|
const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
|
|
10655
|
-
const planningArtifactPath =
|
|
10832
|
+
const planningArtifactPath = resolve23("artifacts", runtimeTaskId, "implementation-plan.md");
|
|
10656
10833
|
const persistedPlanning = {
|
|
10657
10834
|
...planningClassification,
|
|
10658
10835
|
classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
|
|
10659
10836
|
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
10660
10837
|
classifiedAt: new Date().toISOString()
|
|
10661
10838
|
};
|
|
10662
|
-
mkdirSync8(
|
|
10663
|
-
writeFileSync7(
|
|
10839
|
+
mkdirSync8(resolve23(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
|
|
10840
|
+
writeFileSync7(resolve23(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
|
|
10664
10841
|
`, "utf8");
|
|
10665
10842
|
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
10666
10843
|
prompt = `${prompt}
|
|
@@ -10710,7 +10887,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10710
10887
|
let verificationStarted = false;
|
|
10711
10888
|
let reviewStarted = false;
|
|
10712
10889
|
let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
|
|
10713
|
-
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ?
|
|
10890
|
+
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve23(existingRunRecord.sessionPath, "..") : null;
|
|
10714
10891
|
let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
|
|
10715
10892
|
let latestProviderCommand = null;
|
|
10716
10893
|
let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
|
|
@@ -10747,7 +10924,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10747
10924
|
return;
|
|
10748
10925
|
verificationStarted = true;
|
|
10749
10926
|
patchAuthorityRun(context.projectRoot, input.runId, { status: "validating" });
|
|
10750
|
-
emitServerRunEvent({ type: "status", runId: input.runId, status: "validating", detail: detail ?? null });
|
|
10927
|
+
emitServerRunEvent({ type: "status", runId: input.runId, status: "validating", detail: detail ?? null, ...sessionAnchor() });
|
|
10751
10928
|
verificationAction = startRunAction(context.projectRoot, input.runId, {
|
|
10752
10929
|
actionId: `action:${input.runId}:completion-verification`,
|
|
10753
10930
|
actionType: "completion-verification",
|
|
@@ -10760,7 +10937,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10760
10937
|
return;
|
|
10761
10938
|
reviewStarted = true;
|
|
10762
10939
|
patchAuthorityRun(context.projectRoot, input.runId, { status: "reviewing" });
|
|
10763
|
-
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: detail ?? null });
|
|
10940
|
+
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: detail ?? null, ...sessionAnchor() });
|
|
10764
10941
|
reviewAction = startRunAction(context.projectRoot, input.runId, {
|
|
10765
10942
|
actionId: `action:${input.runId}:review-closeout`,
|
|
10766
10943
|
actionType: "run.review",
|
|
@@ -10796,10 +10973,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10796
10973
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
10797
10974
|
status: "running",
|
|
10798
10975
|
worktreePath: latestRuntimeWorkspace,
|
|
10799
|
-
artifactRoot: latestRuntimeWorkspace && input.taskId ?
|
|
10976
|
+
artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve23(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
|
|
10800
10977
|
logRoot: latestLogsDir,
|
|
10801
|
-
sessionPath: latestSessionDir ?
|
|
10802
|
-
sessionLogPath: latestLogsDir ?
|
|
10978
|
+
sessionPath: latestSessionDir ? resolve23(latestSessionDir, "session.json") : null,
|
|
10979
|
+
sessionLogPath: latestLogsDir ? resolve23(latestLogsDir, "agent-stdout.log") : null,
|
|
10803
10980
|
branch: runtimeId
|
|
10804
10981
|
});
|
|
10805
10982
|
if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
|
|
@@ -10807,7 +10984,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10807
10984
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
10808
10985
|
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
10809
10986
|
if (readyFile) {
|
|
10810
|
-
mkdirSync8(
|
|
10987
|
+
mkdirSync8(resolve23(readyFile, ".."), { recursive: true });
|
|
10811
10988
|
writeFileSync7(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
10812
10989
|
`, "utf8");
|
|
10813
10990
|
}
|
|
@@ -10850,7 +11027,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10850
11027
|
type: "status",
|
|
10851
11028
|
runId: input.runId,
|
|
10852
11029
|
status: "running",
|
|
10853
|
-
detail: latestRuntimeWorkspace
|
|
11030
|
+
detail: latestRuntimeWorkspace,
|
|
11031
|
+
...sessionAnchor()
|
|
10854
11032
|
});
|
|
10855
11033
|
return true;
|
|
10856
11034
|
}
|
|
@@ -10933,6 +11111,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
10933
11111
|
piSessionPrivate: privateMetadata
|
|
10934
11112
|
});
|
|
10935
11113
|
const sessionId = typeof publicMetadata?.sessionId === "string" ? publicMetadata.sessionId : typeof privateMetadata.public === "object" && privateMetadata.public && !Array.isArray(privateMetadata.public) ? String(privateMetadata.public.sessionId ?? "") : "";
|
|
11114
|
+
if (sessionId) {
|
|
11115
|
+
latestPiSessionId = sessionId;
|
|
11116
|
+
}
|
|
10936
11117
|
appendRunLog(context.projectRoot, input.runId, {
|
|
10937
11118
|
id: `log:${input.runId}:pi-session-ready`,
|
|
10938
11119
|
title: "Worker Pi session ready",
|
|
@@ -11192,7 +11373,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11192
11373
|
let acceptedArtifactObservedAt = null;
|
|
11193
11374
|
let acceptedArtifactPollTimer = null;
|
|
11194
11375
|
let acceptedArtifactKillTimer = null;
|
|
11195
|
-
const attemptExit = await new Promise((
|
|
11376
|
+
const attemptExit = await new Promise((resolve24) => {
|
|
11196
11377
|
let settled = false;
|
|
11197
11378
|
const settle = (result) => {
|
|
11198
11379
|
if (settled)
|
|
@@ -11200,7 +11381,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11200
11381
|
settled = true;
|
|
11201
11382
|
if (acceptedArtifactPollTimer)
|
|
11202
11383
|
clearInterval(acceptedArtifactPollTimer);
|
|
11203
|
-
|
|
11384
|
+
resolve24(result);
|
|
11204
11385
|
};
|
|
11205
11386
|
const pollAcceptedArtifacts = () => {
|
|
11206
11387
|
const artifactState = readTaskRunAcceptedArtifactState({
|
|
@@ -11327,7 +11508,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11327
11508
|
type: "status",
|
|
11328
11509
|
runId: input.runId,
|
|
11329
11510
|
status: "validating",
|
|
11330
|
-
detail: failureDetail
|
|
11511
|
+
detail: failureDetail,
|
|
11512
|
+
...sessionAnchor()
|
|
11331
11513
|
});
|
|
11332
11514
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Validate failed" });
|
|
11333
11515
|
emitServerRunEvent({ type: "log", runId: input.runId, title: `Steering Pi to retry validation (attempt ${attempt + 1}/${maxAttempts})` });
|
|
@@ -11402,8 +11584,8 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11402
11584
|
}
|
|
11403
11585
|
if (planningClassification.planningRequired) {
|
|
11404
11586
|
const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
|
|
11405
|
-
const expectedPlanPath =
|
|
11406
|
-
if (!
|
|
11587
|
+
const expectedPlanPath = resolve23(planWorkspace, planningArtifactPath);
|
|
11588
|
+
if (!existsSync14(expectedPlanPath)) {
|
|
11407
11589
|
const failedAt = new Date().toISOString();
|
|
11408
11590
|
const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
|
|
11409
11591
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
@@ -11465,7 +11647,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11465
11647
|
payload: { runtimeWorkspace: latestRuntimeWorkspace, branch: latestRuntimeBranch }
|
|
11466
11648
|
});
|
|
11467
11649
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Server-owned closeout requested" });
|
|
11468
|
-
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: "Server-owned closeout requested." });
|
|
11650
|
+
emitServerRunEvent({ type: "status", runId: input.runId, status: "reviewing", detail: "Server-owned closeout requested.", ...sessionAnchor() });
|
|
11469
11651
|
await context.emitEvent("command.finished", {
|
|
11470
11652
|
command: [
|
|
11471
11653
|
"rig",
|
|
@@ -11573,9 +11755,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
11573
11755
|
});
|
|
11574
11756
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
|
|
11575
11757
|
});
|
|
11576
|
-
const exitCode = await new Promise((
|
|
11577
|
-
child.once("error", () =>
|
|
11578
|
-
child.once("close", (code) =>
|
|
11758
|
+
const exitCode = await new Promise((resolve24) => {
|
|
11759
|
+
child.once("error", () => resolve24(1));
|
|
11760
|
+
child.once("close", (code) => resolve24(code ?? 1));
|
|
11579
11761
|
});
|
|
11580
11762
|
for (const pendingLog of flushPendingClaudeToolUseLogs({
|
|
11581
11763
|
runId: input.runId,
|
|
@@ -11717,8 +11899,8 @@ async function executeTest(context, args) {
|
|
|
11717
11899
|
|
|
11718
11900
|
// packages/cli/src/commands/setup.ts
|
|
11719
11901
|
init_runner();
|
|
11720
|
-
import { existsSync as
|
|
11721
|
-
import { resolve as
|
|
11902
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, readdirSync as readdirSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
11903
|
+
import { resolve as resolve24 } from "path";
|
|
11722
11904
|
import { createPluginHost } from "@rig/core";
|
|
11723
11905
|
import {
|
|
11724
11906
|
isSupportedBunVersion as isSupportedBunVersion2,
|
|
@@ -11776,8 +11958,8 @@ function runSetupInit(projectRoot) {
|
|
|
11776
11958
|
mkdirSync9(stateDir, { recursive: true });
|
|
11777
11959
|
mkdirSync9(logsDir, { recursive: true });
|
|
11778
11960
|
mkdirSync9(artifactsDir, { recursive: true });
|
|
11779
|
-
const failuresPath =
|
|
11780
|
-
if (!
|
|
11961
|
+
const failuresPath = resolve24(stateDir, "failed_approaches.md");
|
|
11962
|
+
if (!existsSync15(failuresPath)) {
|
|
11781
11963
|
writeFileSync8(failuresPath, `# Failed Approaches
|
|
11782
11964
|
|
|
11783
11965
|
`, "utf-8");
|
|
@@ -11795,19 +11977,19 @@ async function runSetupCheck(projectRoot) {
|
|
|
11795
11977
|
}
|
|
11796
11978
|
async function runSetupPreflight(projectRoot) {
|
|
11797
11979
|
await runSetupCheck(projectRoot);
|
|
11798
|
-
const validationRoot =
|
|
11799
|
-
if (
|
|
11800
|
-
const validators =
|
|
11980
|
+
const validationRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
11981
|
+
if (existsSync15(validationRoot)) {
|
|
11982
|
+
const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
11801
11983
|
for (const validator of validators) {
|
|
11802
|
-
const script =
|
|
11803
|
-
if (
|
|
11984
|
+
const script = resolve24(validationRoot, validator.name, "validate.sh");
|
|
11985
|
+
if (existsSync15(script)) {
|
|
11804
11986
|
console.log(`OK: validator script ${script}`);
|
|
11805
11987
|
}
|
|
11806
11988
|
}
|
|
11807
11989
|
}
|
|
11808
|
-
const hooksRoot =
|
|
11809
|
-
if (
|
|
11810
|
-
const hooks =
|
|
11990
|
+
const hooksRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
|
|
11991
|
+
if (existsSync15(hooksRoot)) {
|
|
11992
|
+
const hooks = readdirSync3(hooksRoot).filter((name) => name.endsWith(".sh"));
|
|
11811
11993
|
for (const hook of hooks) {
|
|
11812
11994
|
console.log(`OK: hook ${hook}`);
|
|
11813
11995
|
}
|
|
@@ -11951,7 +12133,7 @@ var PROJECT_REQUIRED_GROUPS = new Set([
|
|
|
11951
12133
|
]);
|
|
11952
12134
|
var RIG_CONFIG_FILENAMES = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
|
|
11953
12135
|
function hasInitializedRigProject(projectRoot) {
|
|
11954
|
-
return RIG_CONFIG_FILENAMES.some((name) =>
|
|
12136
|
+
return RIG_CONFIG_FILENAMES.some((name) => existsSync16(resolve25(projectRoot, name))) || existsSync16(resolve25(projectRoot, ".rig"));
|
|
11955
12137
|
}
|
|
11956
12138
|
function requireInitializedRigProject(context, group) {
|
|
11957
12139
|
if (hasInitializedRigProject(context.projectRoot)) {
|
|
@@ -12004,8 +12186,8 @@ function resolveTopLevelLaunchState(context) {
|
|
|
12004
12186
|
let selectedServer = null;
|
|
12005
12187
|
if (projectInitialized) {
|
|
12006
12188
|
try {
|
|
12007
|
-
const statePath =
|
|
12008
|
-
if (
|
|
12189
|
+
const statePath = resolve25(context.projectRoot, ".rig", "state", "connection.json");
|
|
12190
|
+
if (existsSync16(statePath)) {
|
|
12009
12191
|
const parsed = JSON.parse(readFileSync12(statePath, "utf-8"));
|
|
12010
12192
|
selectedServer = parsed.remoteUrl || parsed.url || parsed.selected || null;
|
|
12011
12193
|
}
|