@h-rig/cli 0.0.6-alpha.18 → 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 CHANGED
@@ -2886,6 +2886,14 @@ async function switchServerProjectRootViaServer(context, projectRoot, options =
2886
2886
  }
2887
2887
  throw new CliError2(`Rig server did not switch to ${projectRoot} before timeout (${lastError instanceof Error ? lastError.message : String(lastError ?? "no status")}).`, 1);
2888
2888
  }
2889
+ async function listRunsViaServer(context, options = {}) {
2890
+ const url = new URL("http://rig.local/api/runs");
2891
+ if (options.limit !== undefined)
2892
+ url.searchParams.set("limit", String(options.limit));
2893
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
2894
+ const runs = Array.isArray(payload) ? payload : payload && typeof payload === "object" && !Array.isArray(payload) && Array.isArray(payload.runs) ? payload.runs : [];
2895
+ return runs.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
2896
+ }
2889
2897
  async function getRunDetailsViaServer(context, runId) {
2890
2898
  const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}`);
2891
2899
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
@@ -6406,6 +6414,42 @@ var CANONICAL_STAGES = [
6406
6414
  function logDetail(log3) {
6407
6415
  return typeof log3.detail === "string" ? log3.detail.trim() : "";
6408
6416
  }
6417
+ function parseProviderProtocolLog(title, detail) {
6418
+ if (title.trim().toLowerCase() !== "agent output")
6419
+ return null;
6420
+ if (!detail.startsWith("{") || !detail.endsWith("}"))
6421
+ return null;
6422
+ try {
6423
+ const record = JSON.parse(detail);
6424
+ if (!record || typeof record !== "object" || Array.isArray(record))
6425
+ return null;
6426
+ const type = record.type;
6427
+ return typeof type === "string" && [
6428
+ "assistant",
6429
+ "message_start",
6430
+ "message_update",
6431
+ "message_end",
6432
+ "stream_event",
6433
+ "tool_result",
6434
+ "tool_execution_start",
6435
+ "tool_execution_update",
6436
+ "tool_execution_end",
6437
+ "turn_start",
6438
+ "turn_end"
6439
+ ].includes(type) ? record : null;
6440
+ } catch {
6441
+ return null;
6442
+ }
6443
+ }
6444
+ function renderProviderProtocolLog(record) {
6445
+ const type = typeof record.type === "string" ? record.type : "";
6446
+ if (type === "tool_execution_start" || type === "tool_execution_update" || type === "tool_execution_end") {
6447
+ const toolName = String(record.toolName ?? record.name ?? "tool");
6448
+ 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";
6449
+ return `[Pi tool] ${toolName} ${status}`;
6450
+ }
6451
+ return null;
6452
+ }
6409
6453
  function entryId(entry, fallback) {
6410
6454
  return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
6411
6455
  }
@@ -6450,12 +6494,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
6450
6494
  if (entry.type === "assistant_message" && typeof entry.text === "string") {
6451
6495
  const text2 = entry.text;
6452
6496
  const previousText = assistantTextById.get(id) ?? "";
6497
+ if (!previousText && text2.trim()) {
6498
+ writeLine("[Pi assistant]");
6499
+ }
6453
6500
  if (text2.startsWith(previousText)) {
6454
6501
  const delta = text2.slice(previousText.length);
6455
6502
  if (delta)
6456
6503
  output.write(delta);
6457
6504
  } else if (text2.trim() && text2 !== previousText) {
6458
- writeLine(`
6505
+ if (previousText)
6506
+ writeLine(`
6459
6507
  [Pi assistant]`);
6460
6508
  output.write(text2);
6461
6509
  }
@@ -6486,6 +6534,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
6486
6534
  const detail = logDetail(entry);
6487
6535
  if (!detail)
6488
6536
  continue;
6537
+ const protocolRecord = parseProviderProtocolLog(title, detail);
6538
+ if (protocolRecord) {
6539
+ const protocolLine = renderProviderProtocolLog(protocolRecord);
6540
+ if (protocolLine)
6541
+ writeLine(protocolLine);
6542
+ continue;
6543
+ }
6489
6544
  writeLine(`[${title || "Rig log"}] ${detail}`);
6490
6545
  }
6491
6546
  }
@@ -6633,6 +6688,28 @@ function normalizeRemoteRunDetails(payload) {
6633
6688
  ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6634
6689
  };
6635
6690
  }
6691
+ var REMOTE_TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged"]);
6692
+ function isRemoteConnectionSelected(projectRoot) {
6693
+ return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
6694
+ }
6695
+ async function listRunsForSelectedConnection(context, options = {}) {
6696
+ if (isRemoteConnectionSelected(context.projectRoot)) {
6697
+ return { runs: await listRunsViaServer(context, options), source: "server" };
6698
+ }
6699
+ return { runs: listAuthorityRuns3(context.projectRoot), source: "local" };
6700
+ }
6701
+ function runStringField(run, key, fallback = "") {
6702
+ const value = run[key];
6703
+ return typeof value === "string" && value.trim() ? value : fallback;
6704
+ }
6705
+ function runDisplayTitle(run) {
6706
+ return runStringField(run, "title", runStringField(run, "taskId", "(untitled)"));
6707
+ }
6708
+ function buildServerRunStatus(runs) {
6709
+ const activeRuns = runs.filter((run) => !REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
6710
+ const recentRuns = runs.filter((run) => REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
6711
+ return { activeRuns, recentRuns, runs };
6712
+ }
6636
6713
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
6637
6714
  if (noEpicPrompt) {
6638
6715
  return false;
@@ -6698,17 +6775,17 @@ async function executeRun(context, args) {
6698
6775
  switch (command) {
6699
6776
  case "list": {
6700
6777
  requireNoExtraArgs(rest, "bun run rig run list");
6701
- const runs = listAuthorityRuns3(context.projectRoot);
6778
+ const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
6702
6779
  if (context.outputMode === "text") {
6703
6780
  if (runs.length === 0) {
6704
- console.log("No runs recorded in .rig/runs.");
6781
+ console.log(source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
6705
6782
  } else {
6706
6783
  for (const run of runs) {
6707
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.title}`);
6784
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runDisplayTitle(run)}`);
6708
6785
  }
6709
6786
  }
6710
6787
  }
6711
- return { ok: true, group: "run", command, details: { runs } };
6788
+ return { ok: true, group: "run", command, details: { runs, source } };
6712
6789
  }
6713
6790
  case "delete": {
6714
6791
  let pending = rest;
@@ -6845,17 +6922,19 @@ async function executeRun(context, args) {
6845
6922
  }
6846
6923
  return { ok: true, group: "run", command };
6847
6924
  }
6848
- const summary = runStatus(context.projectRoot, runtimeContext);
6925
+ const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
6926
+ const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
6927
+ const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
6849
6928
  if (context.outputMode === "text") {
6850
- console.log(`Active runs: ${summary.activeRuns.length}`);
6851
- for (const run of summary.activeRuns) {
6852
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
6929
+ console.log(`Active runs: ${activeRuns.length}`);
6930
+ for (const run of activeRuns) {
6931
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
6853
6932
  }
6854
- if (summary.recentRuns.length > 0) {
6933
+ if (recentRuns.length > 0) {
6855
6934
  console.log("");
6856
6935
  console.log("Recent runs:");
6857
- for (const run of summary.recentRuns) {
6858
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
6936
+ for (const run of recentRuns) {
6937
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
6859
6938
  }
6860
6939
  }
6861
6940
  }
@@ -8291,6 +8370,26 @@ function appendAssistantTimelineFromRecord(input) {
8291
8370
  }
8292
8371
  return nextAssistantText;
8293
8372
  }
8373
+ function appendPiToolTimelineFromRecord(input) {
8374
+ const type = typeof input.record.type === "string" ? input.record.type : "";
8375
+ if (type !== "tool_execution_start" && type !== "tool_execution_update" && type !== "tool_execution_end")
8376
+ return false;
8377
+ const toolCallId = typeof input.record.toolCallId === "string" && input.record.toolCallId.trim() ? input.record.toolCallId.trim() : `${Date.now()}`;
8378
+ const toolName = typeof input.record.toolName === "string" && input.record.toolName.trim() ? input.record.toolName.trim() : "tool";
8379
+ const result = input.record.result && typeof input.record.result === "object" && !Array.isArray(input.record.result) ? input.record.result : null;
8380
+ appendRunTimeline(input.projectRoot, input.runId, {
8381
+ id: `tool:${toolCallId}:${type}`,
8382
+ type,
8383
+ toolName,
8384
+ status: type === "tool_execution_end" ? input.record.isError === true || result?.isError === true ? "failed" : "completed" : "running",
8385
+ createdAt: new Date().toISOString()
8386
+ });
8387
+ return true;
8388
+ }
8389
+ function isNonRenderablePiProtocolRecord(record) {
8390
+ const type = typeof record.type === "string" ? record.type : "";
8391
+ 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");
8392
+ }
8294
8393
  function appendToolTimelineFromLog(input) {
8295
8394
  const title = typeof input.log.title === "string" ? input.log.title : "";
8296
8395
  if (title !== "Tool activity")
@@ -8816,6 +8915,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8816
8915
  try {
8817
8916
  const record = JSON.parse(trimmed);
8818
8917
  const liveLogStatus = reviewStarted ? "reviewing" : verificationStarted ? "validating" : "running";
8918
+ if (input.runtimeAdapter === "pi" && appendPiToolTimelineFromRecord({ projectRoot: context.projectRoot, runId: input.runId, record })) {
8919
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
8920
+ return;
8921
+ }
8819
8922
  const providerLogs = input.runtimeAdapter === "codex" ? buildCodexLogsFromRecord({
8820
8923
  runId: input.runId,
8821
8924
  record,
@@ -8887,6 +8990,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8887
8990
  return;
8888
8991
  }
8889
8992
  }
8993
+ if (input.runtimeAdapter === "pi" && isNonRenderablePiProtocolRecord(record)) {
8994
+ return;
8995
+ }
8890
8996
  if (record.type === "assistant") {
8891
8997
  const message2 = record.message && typeof record.message === "object" ? record.message : record;
8892
8998
  const content = Array.isArray(message2.content) ? message2.content : [];
@@ -19,6 +19,42 @@ var CANONICAL_STAGES = [
19
19
  function logDetail(log) {
20
20
  return typeof log.detail === "string" ? log.detail.trim() : "";
21
21
  }
22
+ function parseProviderProtocolLog(title, detail) {
23
+ if (title.trim().toLowerCase() !== "agent output")
24
+ return null;
25
+ if (!detail.startsWith("{") || !detail.endsWith("}"))
26
+ return null;
27
+ try {
28
+ const record = JSON.parse(detail);
29
+ if (!record || typeof record !== "object" || Array.isArray(record))
30
+ return null;
31
+ const type = record.type;
32
+ return typeof type === "string" && [
33
+ "assistant",
34
+ "message_start",
35
+ "message_update",
36
+ "message_end",
37
+ "stream_event",
38
+ "tool_result",
39
+ "tool_execution_start",
40
+ "tool_execution_update",
41
+ "tool_execution_end",
42
+ "turn_start",
43
+ "turn_end"
44
+ ].includes(type) ? record : null;
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ function renderProviderProtocolLog(record) {
50
+ const type = typeof record.type === "string" ? record.type : "";
51
+ if (type === "tool_execution_start" || type === "tool_execution_update" || type === "tool_execution_end") {
52
+ const toolName = String(record.toolName ?? record.name ?? "tool");
53
+ 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";
54
+ return `[Pi tool] ${toolName} ${status}`;
55
+ }
56
+ return null;
57
+ }
22
58
  function entryId(entry, fallback) {
23
59
  return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
24
60
  }
@@ -63,12 +99,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
63
99
  if (entry.type === "assistant_message" && typeof entry.text === "string") {
64
100
  const text = entry.text;
65
101
  const previousText = assistantTextById.get(id) ?? "";
102
+ if (!previousText && text.trim()) {
103
+ writeLine("[Pi assistant]");
104
+ }
66
105
  if (text.startsWith(previousText)) {
67
106
  const delta = text.slice(previousText.length);
68
107
  if (delta)
69
108
  output.write(delta);
70
109
  } else if (text.trim() && text !== previousText) {
71
- writeLine(`
110
+ if (previousText)
111
+ writeLine(`
72
112
  [Pi assistant]`);
73
113
  output.write(text);
74
114
  }
@@ -99,6 +139,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
99
139
  const detail = logDetail(entry);
100
140
  if (!detail)
101
141
  continue;
142
+ const protocolRecord = parseProviderProtocolLog(title, detail);
143
+ if (protocolRecord) {
144
+ const protocolLine = renderProviderProtocolLog(protocolRecord);
145
+ if (protocolLine)
146
+ writeLine(protocolLine);
147
+ continue;
148
+ }
102
149
  writeLine(`[${title || "Rig log"}] ${detail}`);
103
150
  }
104
151
  }
@@ -247,6 +247,42 @@ var CANONICAL_STAGES = [
247
247
  function logDetail(log) {
248
248
  return typeof log.detail === "string" ? log.detail.trim() : "";
249
249
  }
250
+ function parseProviderProtocolLog(title, detail) {
251
+ if (title.trim().toLowerCase() !== "agent output")
252
+ return null;
253
+ if (!detail.startsWith("{") || !detail.endsWith("}"))
254
+ return null;
255
+ try {
256
+ const record = JSON.parse(detail);
257
+ if (!record || typeof record !== "object" || Array.isArray(record))
258
+ return null;
259
+ const type = record.type;
260
+ return typeof type === "string" && [
261
+ "assistant",
262
+ "message_start",
263
+ "message_update",
264
+ "message_end",
265
+ "stream_event",
266
+ "tool_result",
267
+ "tool_execution_start",
268
+ "tool_execution_update",
269
+ "tool_execution_end",
270
+ "turn_start",
271
+ "turn_end"
272
+ ].includes(type) ? record : null;
273
+ } catch {
274
+ return null;
275
+ }
276
+ }
277
+ function renderProviderProtocolLog(record) {
278
+ const type = typeof record.type === "string" ? record.type : "";
279
+ if (type === "tool_execution_start" || type === "tool_execution_update" || type === "tool_execution_end") {
280
+ const toolName = String(record.toolName ?? record.name ?? "tool");
281
+ 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";
282
+ return `[Pi tool] ${toolName} ${status}`;
283
+ }
284
+ return null;
285
+ }
250
286
  function entryId(entry, fallback) {
251
287
  return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
252
288
  }
@@ -291,12 +327,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
291
327
  if (entry.type === "assistant_message" && typeof entry.text === "string") {
292
328
  const text = entry.text;
293
329
  const previousText = assistantTextById.get(id) ?? "";
330
+ if (!previousText && text.trim()) {
331
+ writeLine("[Pi assistant]");
332
+ }
294
333
  if (text.startsWith(previousText)) {
295
334
  const delta = text.slice(previousText.length);
296
335
  if (delta)
297
336
  output.write(delta);
298
337
  } else if (text.trim() && text !== previousText) {
299
- writeLine(`
338
+ if (previousText)
339
+ writeLine(`
300
340
  [Pi assistant]`);
301
341
  output.write(text);
302
342
  }
@@ -327,6 +367,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
327
367
  const detail = logDetail(entry);
328
368
  if (!detail)
329
369
  continue;
370
+ const protocolRecord = parseProviderProtocolLog(title, detail);
371
+ if (protocolRecord) {
372
+ const protocolLine = renderProviderProtocolLog(protocolRecord);
373
+ if (protocolLine)
374
+ writeLine(protocolLine);
375
+ continue;
376
+ }
330
377
  writeLine(`[${title || "Rig log"}] ${detail}`);
331
378
  }
332
379
  }
@@ -310,6 +310,14 @@ async function switchServerProjectRootViaServer(context, projectRoot, options =
310
310
  }
311
311
  throw new CliError2(`Rig server did not switch to ${projectRoot} before timeout (${lastError instanceof Error ? lastError.message : String(lastError ?? "no status")}).`, 1);
312
312
  }
313
+ async function listRunsViaServer(context, options = {}) {
314
+ const url = new URL("http://rig.local/api/runs");
315
+ if (options.limit !== undefined)
316
+ url.searchParams.set("limit", String(options.limit));
317
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
318
+ const runs = Array.isArray(payload) ? payload : payload && typeof payload === "object" && !Array.isArray(payload) && Array.isArray(payload.runs) ? payload.runs : [];
319
+ return runs.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
320
+ }
313
321
  async function getRunDetailsViaServer(context, runId) {
314
322
  const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}`);
315
323
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
@@ -414,6 +422,7 @@ export {
414
422
  prepareRemoteCheckoutViaServer,
415
423
  postGitHubTokenViaServer,
416
424
  listWorkspaceTasksViaServer,
425
+ listRunsViaServer,
417
426
  listGitHubProjectsViaServer,
418
427
  getWorkspaceTaskViaServer,
419
428
  getRunTimelineViaServer,
@@ -259,6 +259,14 @@ async function requestServerJson(context, pathname, init = {}) {
259
259
  }
260
260
  return payload;
261
261
  }
262
+ async function listRunsViaServer(context, options = {}) {
263
+ const url = new URL("http://rig.local/api/runs");
264
+ if (options.limit !== undefined)
265
+ url.searchParams.set("limit", String(options.limit));
266
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
267
+ const runs = Array.isArray(payload) ? payload : payload && typeof payload === "object" && !Array.isArray(payload) && Array.isArray(payload.runs) ? payload.runs : [];
268
+ return runs.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
269
+ }
262
270
  async function getRunDetailsViaServer(context, runId) {
263
271
  const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}`);
264
272
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
@@ -317,6 +325,42 @@ var CANONICAL_STAGES = [
317
325
  function logDetail(log) {
318
326
  return typeof log.detail === "string" ? log.detail.trim() : "";
319
327
  }
328
+ function parseProviderProtocolLog(title, detail) {
329
+ if (title.trim().toLowerCase() !== "agent output")
330
+ return null;
331
+ if (!detail.startsWith("{") || !detail.endsWith("}"))
332
+ return null;
333
+ try {
334
+ const record = JSON.parse(detail);
335
+ if (!record || typeof record !== "object" || Array.isArray(record))
336
+ return null;
337
+ const type = record.type;
338
+ return typeof type === "string" && [
339
+ "assistant",
340
+ "message_start",
341
+ "message_update",
342
+ "message_end",
343
+ "stream_event",
344
+ "tool_result",
345
+ "tool_execution_start",
346
+ "tool_execution_update",
347
+ "tool_execution_end",
348
+ "turn_start",
349
+ "turn_end"
350
+ ].includes(type) ? record : null;
351
+ } catch {
352
+ return null;
353
+ }
354
+ }
355
+ function renderProviderProtocolLog(record) {
356
+ const type = typeof record.type === "string" ? record.type : "";
357
+ if (type === "tool_execution_start" || type === "tool_execution_update" || type === "tool_execution_end") {
358
+ const toolName = String(record.toolName ?? record.name ?? "tool");
359
+ 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";
360
+ return `[Pi tool] ${toolName} ${status}`;
361
+ }
362
+ return null;
363
+ }
320
364
  function entryId(entry, fallback) {
321
365
  return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
322
366
  }
@@ -361,12 +405,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
361
405
  if (entry.type === "assistant_message" && typeof entry.text === "string") {
362
406
  const text = entry.text;
363
407
  const previousText = assistantTextById.get(id) ?? "";
408
+ if (!previousText && text.trim()) {
409
+ writeLine("[Pi assistant]");
410
+ }
364
411
  if (text.startsWith(previousText)) {
365
412
  const delta = text.slice(previousText.length);
366
413
  if (delta)
367
414
  output.write(delta);
368
415
  } else if (text.trim() && text !== previousText) {
369
- writeLine(`
416
+ if (previousText)
417
+ writeLine(`
370
418
  [Pi assistant]`);
371
419
  output.write(text);
372
420
  }
@@ -397,6 +445,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
397
445
  const detail = logDetail(entry);
398
446
  if (!detail)
399
447
  continue;
448
+ const protocolRecord = parseProviderProtocolLog(title, detail);
449
+ if (protocolRecord) {
450
+ const protocolLine = renderProviderProtocolLog(protocolRecord);
451
+ if (protocolLine)
452
+ writeLine(protocolLine);
453
+ continue;
454
+ }
400
455
  writeLine(`[${title || "Rig log"}] ${detail}`);
401
456
  }
402
457
  }
@@ -524,6 +579,28 @@ function normalizeRemoteRunDetails(payload) {
524
579
  ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
525
580
  };
526
581
  }
582
+ var REMOTE_TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged"]);
583
+ function isRemoteConnectionSelected(projectRoot) {
584
+ return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
585
+ }
586
+ async function listRunsForSelectedConnection(context, options = {}) {
587
+ if (isRemoteConnectionSelected(context.projectRoot)) {
588
+ return { runs: await listRunsViaServer(context, options), source: "server" };
589
+ }
590
+ return { runs: listAuthorityRuns(context.projectRoot), source: "local" };
591
+ }
592
+ function runStringField(run, key, fallback = "") {
593
+ const value = run[key];
594
+ return typeof value === "string" && value.trim() ? value : fallback;
595
+ }
596
+ function runDisplayTitle(run) {
597
+ return runStringField(run, "title", runStringField(run, "taskId", "(untitled)"));
598
+ }
599
+ function buildServerRunStatus(runs) {
600
+ const activeRuns = runs.filter((run) => !REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
601
+ const recentRuns = runs.filter((run) => REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
602
+ return { activeRuns, recentRuns, runs };
603
+ }
527
604
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
528
605
  if (noEpicPrompt) {
529
606
  return false;
@@ -589,17 +666,17 @@ async function executeRun(context, args) {
589
666
  switch (command) {
590
667
  case "list": {
591
668
  requireNoExtraArgs(rest, "bun run rig run list");
592
- const runs = listAuthorityRuns(context.projectRoot);
669
+ const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
593
670
  if (context.outputMode === "text") {
594
671
  if (runs.length === 0) {
595
- console.log("No runs recorded in .rig/runs.");
672
+ console.log(source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
596
673
  } else {
597
674
  for (const run of runs) {
598
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.title}`);
675
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runDisplayTitle(run)}`);
599
676
  }
600
677
  }
601
678
  }
602
- return { ok: true, group: "run", command, details: { runs } };
679
+ return { ok: true, group: "run", command, details: { runs, source } };
603
680
  }
604
681
  case "delete": {
605
682
  let pending = rest;
@@ -736,17 +813,19 @@ async function executeRun(context, args) {
736
813
  }
737
814
  return { ok: true, group: "run", command };
738
815
  }
739
- const summary = runStatus(context.projectRoot, runtimeContext);
816
+ const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
817
+ const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
818
+ const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
740
819
  if (context.outputMode === "text") {
741
- console.log(`Active runs: ${summary.activeRuns.length}`);
742
- for (const run of summary.activeRuns) {
743
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
820
+ console.log(`Active runs: ${activeRuns.length}`);
821
+ for (const run of activeRuns) {
822
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
744
823
  }
745
- if (summary.recentRuns.length > 0) {
824
+ if (recentRuns.length > 0) {
746
825
  console.log("");
747
826
  console.log("Recent runs:");
748
- for (const run of summary.recentRuns) {
749
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
827
+ for (const run of recentRuns) {
828
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
750
829
  }
751
830
  }
752
831
  }
@@ -1220,6 +1220,26 @@ function appendAssistantTimelineFromRecord(input) {
1220
1220
  }
1221
1221
  return nextAssistantText;
1222
1222
  }
1223
+ function appendPiToolTimelineFromRecord(input) {
1224
+ const type = typeof input.record.type === "string" ? input.record.type : "";
1225
+ if (type !== "tool_execution_start" && type !== "tool_execution_update" && type !== "tool_execution_end")
1226
+ return false;
1227
+ const toolCallId = typeof input.record.toolCallId === "string" && input.record.toolCallId.trim() ? input.record.toolCallId.trim() : `${Date.now()}`;
1228
+ const toolName = typeof input.record.toolName === "string" && input.record.toolName.trim() ? input.record.toolName.trim() : "tool";
1229
+ const result = input.record.result && typeof input.record.result === "object" && !Array.isArray(input.record.result) ? input.record.result : null;
1230
+ appendRunTimeline(input.projectRoot, input.runId, {
1231
+ id: `tool:${toolCallId}:${type}`,
1232
+ type,
1233
+ toolName,
1234
+ status: type === "tool_execution_end" ? input.record.isError === true || result?.isError === true ? "failed" : "completed" : "running",
1235
+ createdAt: new Date().toISOString()
1236
+ });
1237
+ return true;
1238
+ }
1239
+ function isNonRenderablePiProtocolRecord(record) {
1240
+ const type = typeof record.type === "string" ? record.type : "";
1241
+ 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");
1242
+ }
1223
1243
  function appendToolTimelineFromLog(input) {
1224
1244
  const title = typeof input.log.title === "string" ? input.log.title : "";
1225
1245
  if (title !== "Tool activity")
@@ -1745,6 +1765,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
1745
1765
  try {
1746
1766
  const record = JSON.parse(trimmed);
1747
1767
  const liveLogStatus = reviewStarted ? "reviewing" : verificationStarted ? "validating" : "running";
1768
+ if (input.runtimeAdapter === "pi" && appendPiToolTimelineFromRecord({ projectRoot: context.projectRoot, runId: input.runId, record })) {
1769
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
1770
+ return;
1771
+ }
1748
1772
  const providerLogs = input.runtimeAdapter === "codex" ? buildCodexLogsFromRecord({
1749
1773
  runId: input.runId,
1750
1774
  record,
@@ -1816,6 +1840,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
1816
1840
  return;
1817
1841
  }
1818
1842
  }
1843
+ if (input.runtimeAdapter === "pi" && isNonRenderablePiProtocolRecord(record)) {
1844
+ return;
1845
+ }
1819
1846
  if (record.type === "assistant") {
1820
1847
  const message = record.message && typeof record.message === "object" ? record.message : record;
1821
1848
  const content = Array.isArray(message.content) ? message.content : [];
@@ -738,6 +738,42 @@ var CANONICAL_STAGES = [
738
738
  function logDetail(log) {
739
739
  return typeof log.detail === "string" ? log.detail.trim() : "";
740
740
  }
741
+ function parseProviderProtocolLog(title, detail) {
742
+ if (title.trim().toLowerCase() !== "agent output")
743
+ return null;
744
+ if (!detail.startsWith("{") || !detail.endsWith("}"))
745
+ return null;
746
+ try {
747
+ const record = JSON.parse(detail);
748
+ if (!record || typeof record !== "object" || Array.isArray(record))
749
+ return null;
750
+ const type = record.type;
751
+ return typeof type === "string" && [
752
+ "assistant",
753
+ "message_start",
754
+ "message_update",
755
+ "message_end",
756
+ "stream_event",
757
+ "tool_result",
758
+ "tool_execution_start",
759
+ "tool_execution_update",
760
+ "tool_execution_end",
761
+ "turn_start",
762
+ "turn_end"
763
+ ].includes(type) ? record : null;
764
+ } catch {
765
+ return null;
766
+ }
767
+ }
768
+ function renderProviderProtocolLog(record) {
769
+ const type = typeof record.type === "string" ? record.type : "";
770
+ if (type === "tool_execution_start" || type === "tool_execution_update" || type === "tool_execution_end") {
771
+ const toolName = String(record.toolName ?? record.name ?? "tool");
772
+ 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";
773
+ return `[Pi tool] ${toolName} ${status}`;
774
+ }
775
+ return null;
776
+ }
741
777
  function entryId(entry, fallback) {
742
778
  return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
743
779
  }
@@ -782,12 +818,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
782
818
  if (entry.type === "assistant_message" && typeof entry.text === "string") {
783
819
  const text = entry.text;
784
820
  const previousText = assistantTextById.get(id) ?? "";
821
+ if (!previousText && text.trim()) {
822
+ writeLine("[Pi assistant]");
823
+ }
785
824
  if (text.startsWith(previousText)) {
786
825
  const delta = text.slice(previousText.length);
787
826
  if (delta)
788
827
  output.write(delta);
789
828
  } else if (text.trim() && text !== previousText) {
790
- writeLine(`
829
+ if (previousText)
830
+ writeLine(`
791
831
  [Pi assistant]`);
792
832
  output.write(text);
793
833
  }
@@ -818,6 +858,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
818
858
  const detail = logDetail(entry);
819
859
  if (!detail)
820
860
  continue;
861
+ const protocolRecord = parseProviderProtocolLog(title, detail);
862
+ if (protocolRecord) {
863
+ const protocolLine = renderProviderProtocolLog(protocolRecord);
864
+ if (protocolLine)
865
+ writeLine(protocolLine);
866
+ continue;
867
+ }
821
868
  writeLine(`[${title || "Rig log"}] ${detail}`);
822
869
  }
823
870
  }
@@ -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 : {};
@@ -6199,6 +6207,42 @@ var CANONICAL_STAGES = [
6199
6207
  function logDetail(log3) {
6200
6208
  return typeof log3.detail === "string" ? log3.detail.trim() : "";
6201
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
+ }
6202
6246
  function entryId(entry, fallback) {
6203
6247
  return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
6204
6248
  }
@@ -6243,12 +6287,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
6243
6287
  if (entry.type === "assistant_message" && typeof entry.text === "string") {
6244
6288
  const text2 = entry.text;
6245
6289
  const previousText = assistantTextById.get(id) ?? "";
6290
+ if (!previousText && text2.trim()) {
6291
+ writeLine("[Pi assistant]");
6292
+ }
6246
6293
  if (text2.startsWith(previousText)) {
6247
6294
  const delta = text2.slice(previousText.length);
6248
6295
  if (delta)
6249
6296
  output.write(delta);
6250
6297
  } else if (text2.trim() && text2 !== previousText) {
6251
- writeLine(`
6298
+ if (previousText)
6299
+ writeLine(`
6252
6300
  [Pi assistant]`);
6253
6301
  output.write(text2);
6254
6302
  }
@@ -6279,6 +6327,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
6279
6327
  const detail = logDetail(entry);
6280
6328
  if (!detail)
6281
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
+ }
6282
6337
  writeLine(`[${title || "Rig log"}] ${detail}`);
6283
6338
  }
6284
6339
  }
@@ -6426,6 +6481,28 @@ function normalizeRemoteRunDetails(payload) {
6426
6481
  ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6427
6482
  };
6428
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
+ }
6429
6506
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
6430
6507
  if (noEpicPrompt) {
6431
6508
  return false;
@@ -6491,17 +6568,17 @@ async function executeRun(context, args) {
6491
6568
  switch (command) {
6492
6569
  case "list": {
6493
6570
  requireNoExtraArgs(rest, "bun run rig run list");
6494
- const runs = listAuthorityRuns3(context.projectRoot);
6571
+ const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
6495
6572
  if (context.outputMode === "text") {
6496
6573
  if (runs.length === 0) {
6497
- 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.");
6498
6575
  } else {
6499
6576
  for (const run of runs) {
6500
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.title}`);
6577
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runDisplayTitle(run)}`);
6501
6578
  }
6502
6579
  }
6503
6580
  }
6504
- return { ok: true, group: "run", command, details: { runs } };
6581
+ return { ok: true, group: "run", command, details: { runs, source } };
6505
6582
  }
6506
6583
  case "delete": {
6507
6584
  let pending = rest;
@@ -6638,17 +6715,19 @@ async function executeRun(context, args) {
6638
6715
  }
6639
6716
  return { ok: true, group: "run", command };
6640
6717
  }
6641
- 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))) : [];
6642
6721
  if (context.outputMode === "text") {
6643
- console.log(`Active runs: ${summary.activeRuns.length}`);
6644
- for (const run of summary.activeRuns) {
6645
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
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))}`);
6646
6725
  }
6647
- if (summary.recentRuns.length > 0) {
6726
+ if (recentRuns.length > 0) {
6648
6727
  console.log("");
6649
6728
  console.log("Recent runs:");
6650
- for (const run of summary.recentRuns) {
6651
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
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))}`);
6652
6731
  }
6653
6732
  }
6654
6733
  }
@@ -8084,6 +8163,26 @@ function appendAssistantTimelineFromRecord(input) {
8084
8163
  }
8085
8164
  return nextAssistantText;
8086
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
+ }
8087
8186
  function appendToolTimelineFromLog(input) {
8088
8187
  const title = typeof input.log.title === "string" ? input.log.title : "";
8089
8188
  if (title !== "Tool activity")
@@ -8609,6 +8708,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8609
8708
  try {
8610
8709
  const record = JSON.parse(trimmed);
8611
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
+ }
8612
8715
  const providerLogs = input.runtimeAdapter === "codex" ? buildCodexLogsFromRecord({
8613
8716
  runId: input.runId,
8614
8717
  record,
@@ -8680,6 +8783,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8680
8783
  return;
8681
8784
  }
8682
8785
  }
8786
+ if (input.runtimeAdapter === "pi" && isNonRenderablePiProtocolRecord(record)) {
8787
+ return;
8788
+ }
8683
8789
  if (record.type === "assistant") {
8684
8790
  const message2 = record.message && typeof record.message === "object" ? record.message : record;
8685
8791
  const content = Array.isArray(message2.content) ? message2.content : [];
package/dist/src/index.js CHANGED
@@ -2882,6 +2882,14 @@ async function switchServerProjectRootViaServer(context, projectRoot, options =
2882
2882
  }
2883
2883
  throw new CliError2(`Rig server did not switch to ${projectRoot} before timeout (${lastError instanceof Error ? lastError.message : String(lastError ?? "no status")}).`, 1);
2884
2884
  }
2885
+ async function listRunsViaServer(context, options = {}) {
2886
+ const url = new URL("http://rig.local/api/runs");
2887
+ if (options.limit !== undefined)
2888
+ url.searchParams.set("limit", String(options.limit));
2889
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
2890
+ const runs = Array.isArray(payload) ? payload : payload && typeof payload === "object" && !Array.isArray(payload) && Array.isArray(payload.runs) ? payload.runs : [];
2891
+ return runs.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
2892
+ }
2885
2893
  async function getRunDetailsViaServer(context, runId) {
2886
2894
  const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}`);
2887
2895
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
@@ -6402,6 +6410,42 @@ var CANONICAL_STAGES = [
6402
6410
  function logDetail(log3) {
6403
6411
  return typeof log3.detail === "string" ? log3.detail.trim() : "";
6404
6412
  }
6413
+ function parseProviderProtocolLog(title, detail) {
6414
+ if (title.trim().toLowerCase() !== "agent output")
6415
+ return null;
6416
+ if (!detail.startsWith("{") || !detail.endsWith("}"))
6417
+ return null;
6418
+ try {
6419
+ const record = JSON.parse(detail);
6420
+ if (!record || typeof record !== "object" || Array.isArray(record))
6421
+ return null;
6422
+ const type = record.type;
6423
+ return typeof type === "string" && [
6424
+ "assistant",
6425
+ "message_start",
6426
+ "message_update",
6427
+ "message_end",
6428
+ "stream_event",
6429
+ "tool_result",
6430
+ "tool_execution_start",
6431
+ "tool_execution_update",
6432
+ "tool_execution_end",
6433
+ "turn_start",
6434
+ "turn_end"
6435
+ ].includes(type) ? record : null;
6436
+ } catch {
6437
+ return null;
6438
+ }
6439
+ }
6440
+ function renderProviderProtocolLog(record) {
6441
+ const type = typeof record.type === "string" ? record.type : "";
6442
+ if (type === "tool_execution_start" || type === "tool_execution_update" || type === "tool_execution_end") {
6443
+ const toolName = String(record.toolName ?? record.name ?? "tool");
6444
+ 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";
6445
+ return `[Pi tool] ${toolName} ${status}`;
6446
+ }
6447
+ return null;
6448
+ }
6405
6449
  function entryId(entry, fallback) {
6406
6450
  return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
6407
6451
  }
@@ -6446,12 +6490,16 @@ function createPiRunStreamRenderer(output = process.stdout) {
6446
6490
  if (entry.type === "assistant_message" && typeof entry.text === "string") {
6447
6491
  const text2 = entry.text;
6448
6492
  const previousText = assistantTextById.get(id) ?? "";
6493
+ if (!previousText && text2.trim()) {
6494
+ writeLine("[Pi assistant]");
6495
+ }
6449
6496
  if (text2.startsWith(previousText)) {
6450
6497
  const delta = text2.slice(previousText.length);
6451
6498
  if (delta)
6452
6499
  output.write(delta);
6453
6500
  } else if (text2.trim() && text2 !== previousText) {
6454
- writeLine(`
6501
+ if (previousText)
6502
+ writeLine(`
6455
6503
  [Pi assistant]`);
6456
6504
  output.write(text2);
6457
6505
  }
@@ -6482,6 +6530,13 @@ function createPiRunStreamRenderer(output = process.stdout) {
6482
6530
  const detail = logDetail(entry);
6483
6531
  if (!detail)
6484
6532
  continue;
6533
+ const protocolRecord = parseProviderProtocolLog(title, detail);
6534
+ if (protocolRecord) {
6535
+ const protocolLine = renderProviderProtocolLog(protocolRecord);
6536
+ if (protocolLine)
6537
+ writeLine(protocolLine);
6538
+ continue;
6539
+ }
6485
6540
  writeLine(`[${title || "Rig log"}] ${detail}`);
6486
6541
  }
6487
6542
  }
@@ -6629,6 +6684,28 @@ function normalizeRemoteRunDetails(payload) {
6629
6684
  ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6630
6685
  };
6631
6686
  }
6687
+ var REMOTE_TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged"]);
6688
+ function isRemoteConnectionSelected(projectRoot) {
6689
+ return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
6690
+ }
6691
+ async function listRunsForSelectedConnection(context, options = {}) {
6692
+ if (isRemoteConnectionSelected(context.projectRoot)) {
6693
+ return { runs: await listRunsViaServer(context, options), source: "server" };
6694
+ }
6695
+ return { runs: listAuthorityRuns3(context.projectRoot), source: "local" };
6696
+ }
6697
+ function runStringField(run, key, fallback = "") {
6698
+ const value = run[key];
6699
+ return typeof value === "string" && value.trim() ? value : fallback;
6700
+ }
6701
+ function runDisplayTitle(run) {
6702
+ return runStringField(run, "title", runStringField(run, "taskId", "(untitled)"));
6703
+ }
6704
+ function buildServerRunStatus(runs) {
6705
+ const activeRuns = runs.filter((run) => !REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
6706
+ const recentRuns = runs.filter((run) => REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
6707
+ return { activeRuns, recentRuns, runs };
6708
+ }
6632
6709
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
6633
6710
  if (noEpicPrompt) {
6634
6711
  return false;
@@ -6694,17 +6771,17 @@ async function executeRun(context, args) {
6694
6771
  switch (command) {
6695
6772
  case "list": {
6696
6773
  requireNoExtraArgs(rest, "bun run rig run list");
6697
- const runs = listAuthorityRuns3(context.projectRoot);
6774
+ const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
6698
6775
  if (context.outputMode === "text") {
6699
6776
  if (runs.length === 0) {
6700
- console.log("No runs recorded in .rig/runs.");
6777
+ console.log(source === "server" ? "No runs recorded on the selected Rig server." : "No runs recorded in .rig/runs.");
6701
6778
  } else {
6702
6779
  for (const run of runs) {
6703
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.title}`);
6780
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runDisplayTitle(run)}`);
6704
6781
  }
6705
6782
  }
6706
6783
  }
6707
- return { ok: true, group: "run", command, details: { runs } };
6784
+ return { ok: true, group: "run", command, details: { runs, source } };
6708
6785
  }
6709
6786
  case "delete": {
6710
6787
  let pending = rest;
@@ -6841,17 +6918,19 @@ async function executeRun(context, args) {
6841
6918
  }
6842
6919
  return { ok: true, group: "run", command };
6843
6920
  }
6844
- const summary = runStatus(context.projectRoot, runtimeContext);
6921
+ const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
6922
+ const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
6923
+ const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
6845
6924
  if (context.outputMode === "text") {
6846
- console.log(`Active runs: ${summary.activeRuns.length}`);
6847
- for (const run of summary.activeRuns) {
6848
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
6925
+ console.log(`Active runs: ${activeRuns.length}`);
6926
+ for (const run of activeRuns) {
6927
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
6849
6928
  }
6850
- if (summary.recentRuns.length > 0) {
6929
+ if (recentRuns.length > 0) {
6851
6930
  console.log("");
6852
6931
  console.log("Recent runs:");
6853
- for (const run of summary.recentRuns) {
6854
- console.log(`- ${run.runId} \xB7 ${run.status} \xB7 ${run.taskId ?? run.title}`);
6932
+ for (const run of recentRuns) {
6933
+ console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
6855
6934
  }
6856
6935
  }
6857
6936
  }
@@ -8287,6 +8366,26 @@ function appendAssistantTimelineFromRecord(input) {
8287
8366
  }
8288
8367
  return nextAssistantText;
8289
8368
  }
8369
+ function appendPiToolTimelineFromRecord(input) {
8370
+ const type = typeof input.record.type === "string" ? input.record.type : "";
8371
+ if (type !== "tool_execution_start" && type !== "tool_execution_update" && type !== "tool_execution_end")
8372
+ return false;
8373
+ const toolCallId = typeof input.record.toolCallId === "string" && input.record.toolCallId.trim() ? input.record.toolCallId.trim() : `${Date.now()}`;
8374
+ const toolName = typeof input.record.toolName === "string" && input.record.toolName.trim() ? input.record.toolName.trim() : "tool";
8375
+ const result = input.record.result && typeof input.record.result === "object" && !Array.isArray(input.record.result) ? input.record.result : null;
8376
+ appendRunTimeline(input.projectRoot, input.runId, {
8377
+ id: `tool:${toolCallId}:${type}`,
8378
+ type,
8379
+ toolName,
8380
+ status: type === "tool_execution_end" ? input.record.isError === true || result?.isError === true ? "failed" : "completed" : "running",
8381
+ createdAt: new Date().toISOString()
8382
+ });
8383
+ return true;
8384
+ }
8385
+ function isNonRenderablePiProtocolRecord(record) {
8386
+ const type = typeof record.type === "string" ? record.type : "";
8387
+ 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");
8388
+ }
8290
8389
  function appendToolTimelineFromLog(input) {
8291
8390
  const title = typeof input.log.title === "string" ? input.log.title : "";
8292
8391
  if (title !== "Tool activity")
@@ -8812,6 +8911,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8812
8911
  try {
8813
8912
  const record = JSON.parse(trimmed);
8814
8913
  const liveLogStatus = reviewStarted ? "reviewing" : verificationStarted ? "validating" : "running";
8914
+ if (input.runtimeAdapter === "pi" && appendPiToolTimelineFromRecord({ projectRoot: context.projectRoot, runId: input.runId, record })) {
8915
+ emitServerRunEvent({ type: "timeline", runId: input.runId });
8916
+ return;
8917
+ }
8815
8918
  const providerLogs = input.runtimeAdapter === "codex" ? buildCodexLogsFromRecord({
8816
8919
  runId: input.runId,
8817
8920
  record,
@@ -8883,6 +8986,9 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8883
8986
  return;
8884
8987
  }
8885
8988
  }
8989
+ if (input.runtimeAdapter === "pi" && isNonRenderablePiProtocolRecord(record)) {
8990
+ return;
8991
+ }
8886
8992
  if (record.type === "assistant") {
8887
8993
  const message2 = record.message && typeof record.message === "object" ? record.message : record;
8888
8994
  const content = Array.isArray(message2.content) ? message2.content : [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h-rig/cli",
3
- "version": "0.0.6-alpha.18",
3
+ "version": "0.0.6-alpha.19",
4
4
  "type": "module",
5
5
  "description": "Rig package",
6
6
  "license": "UNLICENSED",
@@ -23,10 +23,10 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@clack/prompts": "^1.2.0",
26
- "@rig/core": "npm:@h-rig/core@0.0.6-alpha.18",
27
- "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.18",
28
- "@rig/client": "npm:@h-rig/client@0.0.6-alpha.18",
29
- "@rig/server": "npm:@h-rig/server@0.0.6-alpha.18",
26
+ "@rig/core": "npm:@h-rig/core@0.0.6-alpha.19",
27
+ "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.19",
28
+ "@rig/client": "npm:@h-rig/client@0.0.6-alpha.19",
29
+ "@rig/server": "npm:@h-rig/server@0.0.6-alpha.19",
30
30
  "picocolors": "^1.1.1"
31
31
  }
32
32
  }