@h-rig/cli 0.0.6-alpha.17 → 0.0.6-alpha.19
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 +192 -35
- package/dist/src/commands/_operator-surface.js +48 -1
- package/dist/src/commands/_operator-view.js +48 -1
- package/dist/src/commands/_server-client.js +9 -0
- package/dist/src/commands/init.js +74 -23
- package/dist/src/commands/run.js +91 -12
- package/dist/src/commands/task-run-driver.js +27 -0
- package/dist/src/commands/task.js +48 -1
- package/dist/src/commands.js +192 -35
- package/dist/src/index.js +192 -35
- package/package.json +5 -5
package/dist/src/commands.js
CHANGED
|
@@ -2679,6 +2679,14 @@ async function switchServerProjectRootViaServer(context, projectRoot, options =
|
|
|
2679
2679
|
}
|
|
2680
2680
|
throw new CliError2(`Rig server did not switch to ${projectRoot} before timeout (${lastError instanceof Error ? lastError.message : String(lastError ?? "no status")}).`, 1);
|
|
2681
2681
|
}
|
|
2682
|
+
async function listRunsViaServer(context, options = {}) {
|
|
2683
|
+
const url = new URL("http://rig.local/api/runs");
|
|
2684
|
+
if (options.limit !== undefined)
|
|
2685
|
+
url.searchParams.set("limit", String(options.limit));
|
|
2686
|
+
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
2687
|
+
const runs = Array.isArray(payload) ? payload : payload && typeof payload === "object" && !Array.isArray(payload) && Array.isArray(payload.runs) ? payload.runs : [];
|
|
2688
|
+
return runs.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
2689
|
+
}
|
|
2682
2690
|
async function getRunDetailsViaServer(context, runId) {
|
|
2683
2691
|
const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}`);
|
|
2684
2692
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
@@ -4322,6 +4330,7 @@ function countDoctorFailures(checks) {
|
|
|
4322
4330
|
|
|
4323
4331
|
// packages/cli/src/commands/init.ts
|
|
4324
4332
|
var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
|
|
4333
|
+
var DEFAULT_REMOTE_RIG_URL = "https://where.rig-does.work";
|
|
4325
4334
|
var RIG_CONFIG_DEV_DEPENDENCIES = {
|
|
4326
4335
|
"@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
|
|
4327
4336
|
"@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
|
|
@@ -4426,6 +4435,19 @@ function readGhAuthToken() {
|
|
|
4426
4435
|
}
|
|
4427
4436
|
return result.stdout.trim();
|
|
4428
4437
|
}
|
|
4438
|
+
function refreshGhProjectScopesAndReadToken() {
|
|
4439
|
+
const result = spawnSync("gh", ["auth", "refresh", "--scopes", "read:project"], {
|
|
4440
|
+
encoding: "utf8",
|
|
4441
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
4442
|
+
});
|
|
4443
|
+
if (result.status !== 0)
|
|
4444
|
+
return null;
|
|
4445
|
+
try {
|
|
4446
|
+
return readGhAuthToken();
|
|
4447
|
+
} catch {
|
|
4448
|
+
return null;
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4429
4451
|
async function loadClackPrompts() {
|
|
4430
4452
|
return await import("@clack/prompts");
|
|
4431
4453
|
}
|
|
@@ -4521,12 +4543,27 @@ async function promptManualProjectStatusMapping(prompts) {
|
|
|
4521
4543
|
}
|
|
4522
4544
|
return statuses;
|
|
4523
4545
|
}
|
|
4524
|
-
|
|
4546
|
+
function projectScopeError(value) {
|
|
4547
|
+
const text2 = typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
4548
|
+
return /INSUFFICIENT_SCOPES|read:project|required scopes/i.test(text2);
|
|
4549
|
+
}
|
|
4550
|
+
function optionName(option) {
|
|
4551
|
+
return String(option.name ?? option.label ?? option.id ?? "").trim();
|
|
4552
|
+
}
|
|
4553
|
+
function autoProjectStatusValue(options, key, label) {
|
|
4554
|
+
const candidates = [DEFAULT_PROJECT_STATUS_OPTIONS[key], label].filter((value) => Boolean(value)).map((value) => value.trim().toLowerCase());
|
|
4555
|
+
const match = options.find((option) => candidates.includes(optionName(option).toLowerCase()));
|
|
4556
|
+
if (!match)
|
|
4557
|
+
return null;
|
|
4558
|
+
return String(match.id ?? match.name);
|
|
4559
|
+
}
|
|
4560
|
+
async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, refreshProjectToken) {
|
|
4525
4561
|
const projectChoice = await promptSelect(prompts, {
|
|
4526
4562
|
message: "GitHub Projects status sync",
|
|
4563
|
+
initialValue: "select",
|
|
4527
4564
|
options: [
|
|
4528
|
-
{ value: "off", label: "Off" },
|
|
4529
4565
|
{ value: "select", label: "Select accessible ProjectV2" },
|
|
4566
|
+
{ value: "off", label: "Off" },
|
|
4530
4567
|
{ value: "manual", label: "Enter ProjectV2 ids manually" }
|
|
4531
4568
|
]
|
|
4532
4569
|
});
|
|
@@ -4542,16 +4579,22 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4542
4579
|
const owner = repoOwnerFromSlug(repoSlug);
|
|
4543
4580
|
if (!owner)
|
|
4544
4581
|
throw new CliError2(`Cannot derive GitHub owner from repo slug ${repoSlug}.`, 1);
|
|
4545
|
-
|
|
4546
|
-
|
|
4582
|
+
let activeToken = githubToken?.trim() || null;
|
|
4583
|
+
let projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4584
|
+
let projects = recordArray(projectsPayload, "projects");
|
|
4585
|
+
if (projects.length === 0 && projectScopeError(projectsPayload.error) && refreshProjectToken) {
|
|
4586
|
+
prompts.outro?.("GitHub token is missing read:project; refreshing gh auth scopes and retrying Projects.");
|
|
4587
|
+
const refreshedToken = refreshProjectToken();
|
|
4588
|
+
if (refreshedToken) {
|
|
4589
|
+
activeToken = refreshedToken;
|
|
4590
|
+
projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4591
|
+
projects = recordArray(projectsPayload, "projects");
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4547
4594
|
if (projects.length === 0) {
|
|
4548
|
-
const error = typeof projectsPayload.error === "string" ? ` (${projectsPayload.error})` : "";
|
|
4549
|
-
prompts.outro?.(`No accessible GitHub Projects were returned${error};
|
|
4550
|
-
return {
|
|
4551
|
-
githubProject: await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }),
|
|
4552
|
-
githubProjectStatusField: await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }),
|
|
4553
|
-
githubProjectStatuses: await promptManualProjectStatusMapping(prompts)
|
|
4554
|
-
};
|
|
4595
|
+
const error = typeof projectsPayload.error === "string" ? ` (${String(projectsPayload.error).replace(/\s+/g, " ").slice(0, 240)})` : "";
|
|
4596
|
+
prompts.outro?.(`No accessible GitHub Projects were returned${error}; continuing with GitHub Projects status sync off.`);
|
|
4597
|
+
return { githubProject: "off", ...activeToken ? { githubToken: activeToken } : {} };
|
|
4555
4598
|
}
|
|
4556
4599
|
const selectedProjectId = await promptSelect(prompts, {
|
|
4557
4600
|
message: "GitHub ProjectV2 project",
|
|
@@ -4565,23 +4608,34 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4565
4608
|
]
|
|
4566
4609
|
});
|
|
4567
4610
|
const projectId = selectedProjectId === "manual" ? await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }) : selectedProjectId;
|
|
4568
|
-
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId,
|
|
4611
|
+
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
4569
4612
|
const fieldPayloadRecord = fieldPayload && typeof fieldPayload === "object" && !Array.isArray(fieldPayload) ? fieldPayload : {};
|
|
4570
4613
|
const rawField = fieldPayloadRecord.field;
|
|
4571
4614
|
const field = rawField && typeof rawField === "object" && !Array.isArray(rawField) ? rawField : null;
|
|
4572
4615
|
const fieldId = typeof field?.id === "string" && field.id.trim() ? field.id : await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" });
|
|
4573
4616
|
const options = Array.isArray(field?.options) ? field.options.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
4574
4617
|
if (options.length === 0) {
|
|
4575
|
-
return {
|
|
4618
|
+
return {
|
|
4619
|
+
githubProject: projectId,
|
|
4620
|
+
githubProjectStatusField: fieldId,
|
|
4621
|
+
githubProjectStatuses: await promptManualProjectStatusMapping(prompts),
|
|
4622
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4623
|
+
};
|
|
4576
4624
|
}
|
|
4577
4625
|
const statuses = {};
|
|
4578
4626
|
for (const [key, label] of Object.entries(PROJECT_STATUS_PROMPTS)) {
|
|
4579
|
-
|
|
4627
|
+
const auto = autoProjectStatusValue(options, key, label);
|
|
4628
|
+
statuses[key] = auto ?? await promptSelect(prompts, {
|
|
4580
4629
|
message: `Project status option for ${label}`,
|
|
4581
|
-
options: options.map((option) => ({ value: String(option.id ?? option.name), label:
|
|
4630
|
+
options: options.map((option) => ({ value: String(option.id ?? option.name), label: optionName(option) }))
|
|
4582
4631
|
});
|
|
4583
4632
|
}
|
|
4584
|
-
return {
|
|
4633
|
+
return {
|
|
4634
|
+
githubProject: projectId,
|
|
4635
|
+
githubProjectStatusField: fieldId,
|
|
4636
|
+
githubProjectStatuses: Object.keys(statuses).length > 0 ? statuses : undefined,
|
|
4637
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4638
|
+
};
|
|
4585
4639
|
}
|
|
4586
4640
|
function sleep2(ms) {
|
|
4587
4641
|
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
@@ -4912,12 +4966,13 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
4912
4966
|
});
|
|
4913
4967
|
const serverChoice = await promptSelect(prompts, {
|
|
4914
4968
|
message: "Rig server",
|
|
4969
|
+
initialValue: "remote",
|
|
4915
4970
|
options: [
|
|
4916
|
-
{ value: "
|
|
4917
|
-
{ value: "
|
|
4971
|
+
{ value: "remote", label: "Remote server", hint: "connect to an HTTPS Rig server" },
|
|
4972
|
+
{ value: "local", label: "Local server", hint: "run on this machine" }
|
|
4918
4973
|
]
|
|
4919
4974
|
});
|
|
4920
|
-
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder:
|
|
4975
|
+
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder: DEFAULT_REMOTE_RIG_URL, initialValue: DEFAULT_REMOTE_RIG_URL }) : undefined;
|
|
4921
4976
|
let remoteCheckout;
|
|
4922
4977
|
if (serverChoice === "remote") {
|
|
4923
4978
|
const checkout = await promptSelect(prompts, {
|
|
@@ -4949,31 +5004,35 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
4949
5004
|
{ value: "skip", label: "Skip for now" }
|
|
4950
5005
|
]
|
|
4951
5006
|
});
|
|
5007
|
+
let remoteGhTokenConfirmed = false;
|
|
4952
5008
|
if (serverChoice === "remote" && authMethod === "gh") {
|
|
4953
5009
|
if (!prompts.confirm)
|
|
4954
5010
|
throw new CliError2("Remote gh-token import requires explicit confirmation.", 1);
|
|
4955
5011
|
const confirmed = await prompts.confirm({
|
|
4956
5012
|
message: `This sends a GitHub token from this machine to ${remoteUrl}. Continue?`,
|
|
4957
|
-
initialValue:
|
|
5013
|
+
initialValue: true
|
|
4958
5014
|
});
|
|
4959
5015
|
if (prompts.isCancel(confirmed) || confirmed !== true) {
|
|
4960
5016
|
throw new CliError2("Remote gh-token import cancelled.", 1);
|
|
4961
5017
|
}
|
|
5018
|
+
remoteGhTokenConfirmed = true;
|
|
4962
5019
|
}
|
|
4963
5020
|
const githubToken = authMethod === "token" ? await promptRequiredText(prompts, { message: "GitHub token", placeholder: "ghp_..." }) : authMethod === "gh" ? readGhAuthToken() : undefined;
|
|
4964
|
-
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken);
|
|
5021
|
+
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, authMethod === "gh" ? refreshGhProjectScopesAndReadToken : undefined);
|
|
5022
|
+
const effectiveGithubToken = projectConfig.githubToken ?? githubToken;
|
|
4965
5023
|
const result = await runControlPlaneInit(context, {
|
|
4966
5024
|
server: serverChoice,
|
|
4967
5025
|
remoteUrl,
|
|
4968
5026
|
repoSlug,
|
|
4969
|
-
githubToken,
|
|
5027
|
+
githubToken: effectiveGithubToken,
|
|
4970
5028
|
githubAuthMethod: authMethod,
|
|
4971
5029
|
githubProject: projectConfig.githubProject,
|
|
4972
5030
|
githubProjectStatusField: projectConfig.githubProjectStatusField,
|
|
4973
5031
|
githubProjectStatuses: projectConfig.githubProjectStatuses,
|
|
4974
5032
|
remoteCheckout,
|
|
4975
5033
|
repair,
|
|
4976
|
-
privateStateOnly
|
|
5034
|
+
privateStateOnly,
|
|
5035
|
+
yes: remoteGhTokenConfirmed || undefined
|
|
4977
5036
|
});
|
|
4978
5037
|
const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
|
|
4979
5038
|
const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
|
|
@@ -6148,6 +6207,42 @@ var CANONICAL_STAGES = [
|
|
|
6148
6207
|
function logDetail(log3) {
|
|
6149
6208
|
return typeof log3.detail === "string" ? log3.detail.trim() : "";
|
|
6150
6209
|
}
|
|
6210
|
+
function parseProviderProtocolLog(title, detail) {
|
|
6211
|
+
if (title.trim().toLowerCase() !== "agent output")
|
|
6212
|
+
return null;
|
|
6213
|
+
if (!detail.startsWith("{") || !detail.endsWith("}"))
|
|
6214
|
+
return null;
|
|
6215
|
+
try {
|
|
6216
|
+
const record = JSON.parse(detail);
|
|
6217
|
+
if (!record || typeof record !== "object" || Array.isArray(record))
|
|
6218
|
+
return null;
|
|
6219
|
+
const type = record.type;
|
|
6220
|
+
return typeof type === "string" && [
|
|
6221
|
+
"assistant",
|
|
6222
|
+
"message_start",
|
|
6223
|
+
"message_update",
|
|
6224
|
+
"message_end",
|
|
6225
|
+
"stream_event",
|
|
6226
|
+
"tool_result",
|
|
6227
|
+
"tool_execution_start",
|
|
6228
|
+
"tool_execution_update",
|
|
6229
|
+
"tool_execution_end",
|
|
6230
|
+
"turn_start",
|
|
6231
|
+
"turn_end"
|
|
6232
|
+
].includes(type) ? record : null;
|
|
6233
|
+
} catch {
|
|
6234
|
+
return null;
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
function renderProviderProtocolLog(record) {
|
|
6238
|
+
const type = typeof record.type === "string" ? record.type : "";
|
|
6239
|
+
if (type === "tool_execution_start" || type === "tool_execution_update" || type === "tool_execution_end") {
|
|
6240
|
+
const toolName = String(record.toolName ?? record.name ?? "tool");
|
|
6241
|
+
const status = type === "tool_execution_start" ? "started" : type === "tool_execution_end" ? record.isError === true || record.result && typeof record.result === "object" && !Array.isArray(record.result) && record.result.isError === true ? "failed" : "completed" : "running";
|
|
6242
|
+
return `[Pi tool] ${toolName} ${status}`;
|
|
6243
|
+
}
|
|
6244
|
+
return null;
|
|
6245
|
+
}
|
|
6151
6246
|
function entryId(entry, fallback) {
|
|
6152
6247
|
return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
|
|
6153
6248
|
}
|
|
@@ -6192,12 +6287,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
6192
6287
|
if (entry.type === "assistant_message" && typeof entry.text === "string") {
|
|
6193
6288
|
const text2 = entry.text;
|
|
6194
6289
|
const previousText = assistantTextById.get(id) ?? "";
|
|
6290
|
+
if (!previousText && text2.trim()) {
|
|
6291
|
+
writeLine("[Pi assistant]");
|
|
6292
|
+
}
|
|
6195
6293
|
if (text2.startsWith(previousText)) {
|
|
6196
6294
|
const delta = text2.slice(previousText.length);
|
|
6197
6295
|
if (delta)
|
|
6198
6296
|
output.write(delta);
|
|
6199
6297
|
} else if (text2.trim() && text2 !== previousText) {
|
|
6200
|
-
|
|
6298
|
+
if (previousText)
|
|
6299
|
+
writeLine(`
|
|
6201
6300
|
[Pi assistant]`);
|
|
6202
6301
|
output.write(text2);
|
|
6203
6302
|
}
|
|
@@ -6228,6 +6327,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
6228
6327
|
const detail = logDetail(entry);
|
|
6229
6328
|
if (!detail)
|
|
6230
6329
|
continue;
|
|
6330
|
+
const protocolRecord = parseProviderProtocolLog(title, detail);
|
|
6331
|
+
if (protocolRecord) {
|
|
6332
|
+
const protocolLine = renderProviderProtocolLog(protocolRecord);
|
|
6333
|
+
if (protocolLine)
|
|
6334
|
+
writeLine(protocolLine);
|
|
6335
|
+
continue;
|
|
6336
|
+
}
|
|
6231
6337
|
writeLine(`[${title || "Rig log"}] ${detail}`);
|
|
6232
6338
|
}
|
|
6233
6339
|
}
|
|
@@ -6375,6 +6481,28 @@ function normalizeRemoteRunDetails(payload) {
|
|
|
6375
6481
|
...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
|
|
6376
6482
|
};
|
|
6377
6483
|
}
|
|
6484
|
+
var REMOTE_TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged"]);
|
|
6485
|
+
function isRemoteConnectionSelected(projectRoot) {
|
|
6486
|
+
return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
|
|
6487
|
+
}
|
|
6488
|
+
async function listRunsForSelectedConnection(context, options = {}) {
|
|
6489
|
+
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
6490
|
+
return { runs: await listRunsViaServer(context, options), source: "server" };
|
|
6491
|
+
}
|
|
6492
|
+
return { runs: listAuthorityRuns3(context.projectRoot), source: "local" };
|
|
6493
|
+
}
|
|
6494
|
+
function runStringField(run, key, fallback = "") {
|
|
6495
|
+
const value = run[key];
|
|
6496
|
+
return typeof value === "string" && value.trim() ? value : fallback;
|
|
6497
|
+
}
|
|
6498
|
+
function runDisplayTitle(run) {
|
|
6499
|
+
return runStringField(run, "title", runStringField(run, "taskId", "(untitled)"));
|
|
6500
|
+
}
|
|
6501
|
+
function buildServerRunStatus(runs) {
|
|
6502
|
+
const activeRuns = runs.filter((run) => !REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
|
|
6503
|
+
const recentRuns = runs.filter((run) => REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
|
|
6504
|
+
return { activeRuns, recentRuns, runs };
|
|
6505
|
+
}
|
|
6378
6506
|
function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
|
|
6379
6507
|
if (noEpicPrompt) {
|
|
6380
6508
|
return false;
|
|
@@ -6440,17 +6568,17 @@ async function executeRun(context, args) {
|
|
|
6440
6568
|
switch (command) {
|
|
6441
6569
|
case "list": {
|
|
6442
6570
|
requireNoExtraArgs(rest, "bun run rig run list");
|
|
6443
|
-
const runs =
|
|
6571
|
+
const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
|
|
6444
6572
|
if (context.outputMode === "text") {
|
|
6445
6573
|
if (runs.length === 0) {
|
|
6446
|
-
console.log("No runs recorded in .rig/runs.");
|
|
6574
|
+
console.log(source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
|
|
6447
6575
|
} else {
|
|
6448
6576
|
for (const run of runs) {
|
|
6449
|
-
console.log(`- ${run
|
|
6577
|
+
console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runDisplayTitle(run)}`);
|
|
6450
6578
|
}
|
|
6451
6579
|
}
|
|
6452
6580
|
}
|
|
6453
|
-
return { ok: true, group: "run", command, details: { runs } };
|
|
6581
|
+
return { ok: true, group: "run", command, details: { runs, source } };
|
|
6454
6582
|
}
|
|
6455
6583
|
case "delete": {
|
|
6456
6584
|
let pending = rest;
|
|
@@ -6587,17 +6715,19 @@ async function executeRun(context, args) {
|
|
|
6587
6715
|
}
|
|
6588
6716
|
return { ok: true, group: "run", command };
|
|
6589
6717
|
}
|
|
6590
|
-
const summary = runStatus(context.projectRoot, runtimeContext);
|
|
6718
|
+
const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
|
|
6719
|
+
const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
6720
|
+
const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
6591
6721
|
if (context.outputMode === "text") {
|
|
6592
|
-
console.log(`Active runs: ${
|
|
6593
|
-
for (const run of
|
|
6594
|
-
console.log(`- ${run
|
|
6722
|
+
console.log(`Active runs: ${activeRuns.length}`);
|
|
6723
|
+
for (const run of activeRuns) {
|
|
6724
|
+
console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
|
|
6595
6725
|
}
|
|
6596
|
-
if (
|
|
6726
|
+
if (recentRuns.length > 0) {
|
|
6597
6727
|
console.log("");
|
|
6598
6728
|
console.log("Recent runs:");
|
|
6599
|
-
for (const run of
|
|
6600
|
-
console.log(`- ${run
|
|
6729
|
+
for (const run of recentRuns) {
|
|
6730
|
+
console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
|
|
6601
6731
|
}
|
|
6602
6732
|
}
|
|
6603
6733
|
}
|
|
@@ -8033,6 +8163,26 @@ function appendAssistantTimelineFromRecord(input) {
|
|
|
8033
8163
|
}
|
|
8034
8164
|
return nextAssistantText;
|
|
8035
8165
|
}
|
|
8166
|
+
function appendPiToolTimelineFromRecord(input) {
|
|
8167
|
+
const type = typeof input.record.type === "string" ? input.record.type : "";
|
|
8168
|
+
if (type !== "tool_execution_start" && type !== "tool_execution_update" && type !== "tool_execution_end")
|
|
8169
|
+
return false;
|
|
8170
|
+
const toolCallId = typeof input.record.toolCallId === "string" && input.record.toolCallId.trim() ? input.record.toolCallId.trim() : `${Date.now()}`;
|
|
8171
|
+
const toolName = typeof input.record.toolName === "string" && input.record.toolName.trim() ? input.record.toolName.trim() : "tool";
|
|
8172
|
+
const result = input.record.result && typeof input.record.result === "object" && !Array.isArray(input.record.result) ? input.record.result : null;
|
|
8173
|
+
appendRunTimeline(input.projectRoot, input.runId, {
|
|
8174
|
+
id: `tool:${toolCallId}:${type}`,
|
|
8175
|
+
type,
|
|
8176
|
+
toolName,
|
|
8177
|
+
status: type === "tool_execution_end" ? input.record.isError === true || result?.isError === true ? "failed" : "completed" : "running",
|
|
8178
|
+
createdAt: new Date().toISOString()
|
|
8179
|
+
});
|
|
8180
|
+
return true;
|
|
8181
|
+
}
|
|
8182
|
+
function isNonRenderablePiProtocolRecord(record) {
|
|
8183
|
+
const type = typeof record.type === "string" ? record.type : "";
|
|
8184
|
+
return type === "message_start" || type === "message_end" || type === "turn_start" || type === "turn_end" || type === "tool_result" || type === "message_update" && (!record.assistantMessageEvent || typeof record.assistantMessageEvent !== "object" || Array.isArray(record.assistantMessageEvent) || record.assistantMessageEvent.type !== "text_delta");
|
|
8185
|
+
}
|
|
8036
8186
|
function appendToolTimelineFromLog(input) {
|
|
8037
8187
|
const title = typeof input.log.title === "string" ? input.log.title : "";
|
|
8038
8188
|
if (title !== "Tool activity")
|
|
@@ -8558,6 +8708,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
8558
8708
|
try {
|
|
8559
8709
|
const record = JSON.parse(trimmed);
|
|
8560
8710
|
const liveLogStatus = reviewStarted ? "reviewing" : verificationStarted ? "validating" : "running";
|
|
8711
|
+
if (input.runtimeAdapter === "pi" && appendPiToolTimelineFromRecord({ projectRoot: context.projectRoot, runId: input.runId, record })) {
|
|
8712
|
+
emitServerRunEvent({ type: "timeline", runId: input.runId });
|
|
8713
|
+
return;
|
|
8714
|
+
}
|
|
8561
8715
|
const providerLogs = input.runtimeAdapter === "codex" ? buildCodexLogsFromRecord({
|
|
8562
8716
|
runId: input.runId,
|
|
8563
8717
|
record,
|
|
@@ -8629,6 +8783,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
8629
8783
|
return;
|
|
8630
8784
|
}
|
|
8631
8785
|
}
|
|
8786
|
+
if (input.runtimeAdapter === "pi" && isNonRenderablePiProtocolRecord(record)) {
|
|
8787
|
+
return;
|
|
8788
|
+
}
|
|
8632
8789
|
if (record.type === "assistant") {
|
|
8633
8790
|
const message2 = record.message && typeof record.message === "object" ? record.message : record;
|
|
8634
8791
|
const content = Array.isArray(message2.content) ? message2.content : [];
|