@h-rig/cli 0.0.6-alpha.88 → 0.0.6-alpha.89

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.
Files changed (70) hide show
  1. package/dist/bin/rig.js +1159 -292
  2. package/dist/src/app/board.js +462 -48
  3. package/dist/src/app-opentui/adapters/doctor.js +458 -46
  4. package/dist/src/app-opentui/adapters/family.js +670 -147
  5. package/dist/src/app-opentui/adapters/fleet.js +477 -46
  6. package/dist/src/app-opentui/adapters/inbox.js +477 -46
  7. package/dist/src/app-opentui/adapters/init.js +497 -74
  8. package/dist/src/app-opentui/adapters/inspect.js +477 -46
  9. package/dist/src/app-opentui/adapters/pi-attach.js +484 -53
  10. package/dist/src/app-opentui/adapters/run-detail.js +477 -46
  11. package/dist/src/app-opentui/adapters/server.d.ts +26 -0
  12. package/dist/src/app-opentui/adapters/server.js +676 -59
  13. package/dist/src/app-opentui/adapters/tasks.js +539 -81
  14. package/dist/src/app-opentui/autocomplete.js +4 -2
  15. package/dist/src/app-opentui/bootstrap.js +1155 -288
  16. package/dist/src/app-opentui/command-palette.js +37 -10
  17. package/dist/src/app-opentui/index.js +566 -89
  18. package/dist/src/app-opentui/intent.js +33 -8
  19. package/dist/src/app-opentui/keymap.js +43 -29
  20. package/dist/src/app-opentui/pi-host-child.js +465 -53
  21. package/dist/src/app-opentui/react/App.js +104 -44
  22. package/dist/src/app-opentui/react/ChromeHost.js +16 -4
  23. package/dist/src/app-opentui/react/launch.js +555 -88
  24. package/dist/src/app-opentui/react/nav.js +1 -1
  25. package/dist/src/app-opentui/registry.js +1062 -237
  26. package/dist/src/app-opentui/remote-link.d.ts +10 -0
  27. package/dist/src/app-opentui/remote-link.js +47 -0
  28. package/dist/src/app-opentui/runtime.js +566 -89
  29. package/dist/src/app-opentui/scenes/doctor.js +1 -1
  30. package/dist/src/app-opentui/scenes/error.js +50 -4
  31. package/dist/src/app-opentui/scenes/family.js +60 -6
  32. package/dist/src/app-opentui/scenes/fleet.js +65 -13
  33. package/dist/src/app-opentui/scenes/help.js +4 -2
  34. package/dist/src/app-opentui/scenes/init.js +12 -12
  35. package/dist/src/app-opentui/scenes/main.js +7 -7
  36. package/dist/src/app-opentui/scenes/server.js +83 -11
  37. package/dist/src/app-opentui/scenes/tasks.js +79 -16
  38. package/dist/src/app-opentui/state.js +25 -5
  39. package/dist/src/app-opentui/surface-catalog.js +4 -2
  40. package/dist/src/app-opentui/types.d.ts +1 -1
  41. package/dist/src/commands/_cli-format.d.ts +10 -1
  42. package/dist/src/commands/_cli-format.js +5 -2
  43. package/dist/src/commands/_connection-state.d.ts +11 -1
  44. package/dist/src/commands/_connection-state.js +50 -5
  45. package/dist/src/commands/_doctor-checks.js +458 -46
  46. package/dist/src/commands/_help-catalog.js +4 -2
  47. package/dist/src/commands/_json-output.js +4 -0
  48. package/dist/src/commands/_operator-view.js +465 -53
  49. package/dist/src/commands/_pi-frontend.js +465 -53
  50. package/dist/src/commands/_preflight.js +509 -72
  51. package/dist/src/commands/_server-client.d.ts +33 -0
  52. package/dist/src/commands/_server-client.js +477 -46
  53. package/dist/src/commands/_server-events.js +446 -41
  54. package/dist/src/commands/_snapshot-upload.js +460 -48
  55. package/dist/src/commands/connect.js +620 -15
  56. package/dist/src/commands/doctor.js +458 -46
  57. package/dist/src/commands/github.js +462 -50
  58. package/dist/src/commands/inbox.js +458 -46
  59. package/dist/src/commands/init.js +497 -74
  60. package/dist/src/commands/inspect.js +458 -46
  61. package/dist/src/commands/run.js +465 -53
  62. package/dist/src/commands/server.js +647 -163
  63. package/dist/src/commands/setup.js +463 -51
  64. package/dist/src/commands/stats.js +462 -48
  65. package/dist/src/commands/task-run-driver.js +464 -52
  66. package/dist/src/commands/task.js +520 -81
  67. package/dist/src/commands.js +670 -147
  68. package/dist/src/index.js +674 -147
  69. package/dist/src/launcher.js +4 -0
  70. package/package.json +8 -8
@@ -219,7 +219,7 @@ function selectableDeckRow(deck, item) {
219
219
  var DOCTOR_ACTIONS = [
220
220
  { detail: "run diagnostics now", item: { id: "run", label: "run", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "run diagnostics" } },
221
221
  { detail: "open server controls", item: { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "open server controls" } },
222
- { detail: "repair project/server/auth link", item: { id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair project link" } }, message: "repair project link" } },
222
+ { detail: "repair project/server/auth link", item: { id: "repair", label: "repair", intent: { scene: "init", argv: ["init", "--repair", "--yes"], action: { kind: "init-start", label: "Repair project link" } }, message: "repair project link natively" } },
223
223
  { detail: "open tasks", item: { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks" } }
224
224
  ];
225
225
  function checks(state) {
@@ -158,6 +158,48 @@ function errorDrone(tick) {
158
158
  }));
159
159
  }
160
160
 
161
+ // packages/cli/src/app-opentui/remote-link.ts
162
+ var REPAIRABLE_REMOTE_LINK_STATUSES = new Set([
163
+ "auth_required",
164
+ "project_not_registered",
165
+ "no_server_checkout",
166
+ "invalid_root",
167
+ "needs_prepare",
168
+ "error"
169
+ ]);
170
+ function remoteProjectLinkError(message) {
171
+ return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(message ?? "");
172
+ }
173
+ function serverRecordForRemoteLink(state) {
174
+ const server = state.data.server;
175
+ return server && typeof server === "object" && !Array.isArray(server) ? server : null;
176
+ }
177
+ function remoteProjectLinkState(state) {
178
+ const serverRecord = serverRecordForRemoteLink(state);
179
+ if (!serverRecord || serverRecord.kind !== "remote")
180
+ return null;
181
+ const link = serverRecord.remoteProjectLink;
182
+ if (link && typeof link === "object" && !Array.isArray(link))
183
+ return link;
184
+ const direct = state.data.remoteProjectLink;
185
+ if (direct && typeof direct === "object" && !Array.isArray(direct))
186
+ return direct;
187
+ return null;
188
+ }
189
+ function shouldOfferRemoteLinkRepair(state, message) {
190
+ const link = remoteProjectLinkState(state);
191
+ if (link) {
192
+ if (link.ok === true)
193
+ return false;
194
+ const status = link.status ?? "";
195
+ return REPAIRABLE_REMOTE_LINK_STATUSES.has(status);
196
+ }
197
+ const serverRecord = serverRecordForRemoteLink(state);
198
+ if (serverRecord && serverRecord.kind !== "remote")
199
+ return false;
200
+ return remoteProjectLinkError(message ?? state.error?.message);
201
+ }
202
+
161
203
  // packages/cli/src/app-opentui/render/scene.ts
162
204
  function line(text, options = {}) {
163
205
  return { text, ...options };
@@ -185,13 +227,17 @@ function selectableDeckRow(deck, item) {
185
227
  var ERROR_ACTIONS = [
186
228
  { detail: "return to dashboard", item: { id: "main", label: "main", intent: { scene: "main", argv: [], action: { kind: "refresh", label: "Back to dashboard" } }, message: "back to dashboard" } },
187
229
  { detail: "run diagnostics", item: { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "run diagnostics" } },
188
- { detail: "open server controls", item: { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "open server controls" } },
189
- { detail: "repair project/server/auth link", item: { id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair project link" } }, message: "repair project link" } }
230
+ { detail: "open server controls", item: { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "open server controls" } }
190
231
  ];
232
+ var ERROR_REPAIR_LINK_ACTION = { detail: "backfill or prepare selected remote project-root link", item: { id: "repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "server" } } }, message: "repair remote project link" } };
233
+ function errorActions(state) {
234
+ return shouldOfferRemoteLinkRepair(state, state.error?.message) ? [...ERROR_ACTIONS, ERROR_REPAIR_LINK_ACTION] : ERROR_ACTIONS;
235
+ }
191
236
  function renderErrorScene(state) {
192
237
  const message = state.error?.message ?? "Unknown app error";
193
238
  const hint = state.error?.hint ?? "Use the actions below to recover.";
194
- const selected = Math.max(0, Math.min(3, state.selection.index));
239
+ const actions = errorActions(state);
240
+ const selected = Math.max(0, Math.min(actions.length - 1, state.selection.index));
195
241
  return makeSceneFrame({
196
242
  scene: "error",
197
243
  title: "Error",
@@ -209,7 +255,7 @@ function renderErrorScene(state) {
209
255
  ...hint ? [line(hint, { fg: RIG_UI.yellow })] : [],
210
256
  line("", { fg: RIG_UI.ink3 }),
211
257
  line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
212
- ...ERROR_ACTIONS.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item))
258
+ ...actions.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item))
213
259
  ],
214
260
  backgroundColor: RIG_UI.panel,
215
261
  backgroundAlpha: 184,
@@ -284,6 +284,48 @@ function withSelectable(line2, item) {
284
284
  return { ...line2, selectable: item, activateOnClick: true };
285
285
  }
286
286
 
287
+ // packages/cli/src/app-opentui/remote-link.ts
288
+ var REPAIRABLE_REMOTE_LINK_STATUSES = new Set([
289
+ "auth_required",
290
+ "project_not_registered",
291
+ "no_server_checkout",
292
+ "invalid_root",
293
+ "needs_prepare",
294
+ "error"
295
+ ]);
296
+ function remoteProjectLinkError(message) {
297
+ return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(message ?? "");
298
+ }
299
+ function serverRecordForRemoteLink(state) {
300
+ const server = state.data.server;
301
+ return server && typeof server === "object" && !Array.isArray(server) ? server : null;
302
+ }
303
+ function remoteProjectLinkState(state) {
304
+ const serverRecord = serverRecordForRemoteLink(state);
305
+ if (!serverRecord || serverRecord.kind !== "remote")
306
+ return null;
307
+ const link = serverRecord.remoteProjectLink;
308
+ if (link && typeof link === "object" && !Array.isArray(link))
309
+ return link;
310
+ const direct = state.data.remoteProjectLink;
311
+ if (direct && typeof direct === "object" && !Array.isArray(direct))
312
+ return direct;
313
+ return null;
314
+ }
315
+ function shouldOfferRemoteLinkRepair(state, message) {
316
+ const link = remoteProjectLinkState(state);
317
+ if (link) {
318
+ if (link.ok === true)
319
+ return false;
320
+ const status = link.status ?? "";
321
+ return REPAIRABLE_REMOTE_LINK_STATUSES.has(status);
322
+ }
323
+ const serverRecord = serverRecordForRemoteLink(state);
324
+ if (serverRecord && serverRecord.kind !== "remote")
325
+ return false;
326
+ return remoteProjectLinkError(message ?? state.error?.message);
327
+ }
328
+
287
329
  // packages/cli/src/app-opentui/fleet-stats.ts
288
330
  var ACTIVE_STATUSES = new Set([
289
331
  "running",
@@ -2092,13 +2134,18 @@ function overviewBody(state, family, snap, layout) {
2092
2134
  function familyRecoveryRows(state, family, errorMessage) {
2093
2135
  const selected = Math.max(0, state.selection.index);
2094
2136
  const intro = errorMessage ? line(`\u2717 couldn't load ${family || "this family"} \u2014 ${errorMessage}`, { fg: RIG_UI.red, bold: true }) : line(`No data for ${family || "this family"} yet.`, { fg: RIG_UI.ink2 });
2095
- return [
2137
+ const repairRemote = shouldOfferRemoteLinkRepair(state, errorMessage);
2138
+ const rows = [
2096
2139
  intro,
2097
- blank(),
2098
- selectableDeckRow({ label: "retry", detail: `reload ${family || "the family"}`, index: 0, active: selected === 0 }, { id: "family-retry", label: "retry", intent: { scene: "family", argv: [family], action: { kind: "refresh", label: `Reload ${family}`, payload: { family } } }, message: "reload this family" }),
2099
- selectableDeckRow({ label: "cockpit", detail: "back to the project cockpit", index: 1, active: selected === 1 }, { id: "family-home", label: "cockpit", intent: { scene: "main", argv: [], action: { kind: "refresh", label: "Home" } }, message: "back to the cockpit" }),
2100
- selectableDeckRow({ label: "doctor", detail: "diagnose project/setup", index: 2, active: selected === 2 }, { id: "family-doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose setup" })
2140
+ blank()
2101
2141
  ];
2142
+ let index = 0;
2143
+ if (repairRemote) {
2144
+ rows.push(selectableDeckRow({ label: "repair link", detail: "backfill/prepare selected remote checkout link", index, active: selected === index }, { id: "family-repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "family", family } } }, message: "repair remote project link" }));
2145
+ index += 1;
2146
+ }
2147
+ rows.push(selectableDeckRow({ label: "retry", detail: `reload ${family || "the family"}`, index, active: selected === index }, { id: "family-retry", label: "retry", intent: { scene: "family", argv: [family], action: { kind: "refresh", label: `Reload ${family}`, payload: { family } } }, message: "reload this family" }), selectableDeckRow({ label: "cockpit", detail: "back to the project cockpit", index: index + 1, active: selected === index + 1 }, { id: "family-home", label: "cockpit", intent: { scene: "main", argv: [], action: { kind: "refresh", label: "Home" } }, message: "back to the cockpit" }), selectableDeckRow({ label: "doctor", detail: "diagnose project/setup", index: index + 2, active: selected === index + 2 }, { id: "family-doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose setup" }));
2148
+ return rows;
2102
2149
  }
2103
2150
  function renderFamilyScene(state, layout) {
2104
2151
  const family = typeof state.data.familyName === "string" ? state.data.familyName : "";
@@ -2107,9 +2154,16 @@ function renderFamilyScene(state, layout) {
2107
2154
  const loading = state.status === "loading" && !snap;
2108
2155
  const errorMessage = state.error?.message ?? lastRefreshError(state) ?? undefined;
2109
2156
  const probeFailed = snap ? snap.state.ran === false && Boolean(state.error) : Boolean(state.error);
2157
+ const selected = Math.max(0, state.selection.index);
2110
2158
  const body = [
2111
2159
  ...loading ? loadingRows(family || "family", state.tick) : snap ? [
2112
- ...probeFailed && errorMessage ? [...errorBanner(errorMessage), blank()] : [],
2160
+ ...probeFailed && errorMessage ? [
2161
+ ...errorBanner(errorMessage),
2162
+ ...shouldOfferRemoteLinkRepair(state, errorMessage) ? [
2163
+ selectableDeckRow({ label: "repair link", detail: "backfill/prepare selected remote checkout link", index: 0, active: selected === 0 }, { id: "family-repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "family", family } } }, message: "repair remote project link" })
2164
+ ] : [],
2165
+ blank()
2166
+ ] : [],
2113
2167
  ...current.subId ? formView(state, family, snap, current).lines : overviewBody(state, family, snap, layout)
2114
2168
  ] : familyRecoveryRows(state, family, errorMessage)
2115
2169
  ];
@@ -435,13 +435,55 @@ function statusSegments(stats, width) {
435
435
  };
436
436
  }
437
437
 
438
+ // packages/cli/src/app-opentui/remote-link.ts
439
+ var REPAIRABLE_REMOTE_LINK_STATUSES = new Set([
440
+ "auth_required",
441
+ "project_not_registered",
442
+ "no_server_checkout",
443
+ "invalid_root",
444
+ "needs_prepare",
445
+ "error"
446
+ ]);
447
+ function remoteProjectLinkError(message) {
448
+ return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(message ?? "");
449
+ }
450
+ function serverRecordForRemoteLink(state) {
451
+ const server = state.data.server;
452
+ return server && typeof server === "object" && !Array.isArray(server) ? server : null;
453
+ }
454
+ function remoteProjectLinkState(state) {
455
+ const serverRecord = serverRecordForRemoteLink(state);
456
+ if (!serverRecord || serverRecord.kind !== "remote")
457
+ return null;
458
+ const link = serverRecord.remoteProjectLink;
459
+ if (link && typeof link === "object" && !Array.isArray(link))
460
+ return link;
461
+ const direct = state.data.remoteProjectLink;
462
+ if (direct && typeof direct === "object" && !Array.isArray(direct))
463
+ return direct;
464
+ return null;
465
+ }
466
+ function shouldOfferRemoteLinkRepair(state, message) {
467
+ const link = remoteProjectLinkState(state);
468
+ if (link) {
469
+ if (link.ok === true)
470
+ return false;
471
+ const status = link.status ?? "";
472
+ return REPAIRABLE_REMOTE_LINK_STATUSES.has(status);
473
+ }
474
+ const serverRecord = serverRecordForRemoteLink(state);
475
+ if (serverRecord && serverRecord.kind !== "remote")
476
+ return false;
477
+ return remoteProjectLinkError(message ?? state.error?.message);
478
+ }
479
+
438
480
  // packages/cli/src/app-opentui/scenes/fleet.ts
439
- var FLEET_RECOVERY_ITEMS = [
481
+ var BASE_FLEET_RECOVERY_ITEMS = [
440
482
  { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks and dispatch work" },
441
- { id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair project link" } }, message: "repair project/server/auth link" },
442
483
  { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
443
484
  { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose project" }
444
485
  ];
486
+ var FLEET_REPAIR_LINK_ITEM = { id: "repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "fleet" } } }, message: "backfill or prepare remote project link" };
445
487
  var COL = {
446
488
  glyph: 1,
447
489
  runId: 8,
@@ -606,33 +648,43 @@ function runRow(width, run, active, optimistic) {
606
648
  const item = runSelectableItem(run);
607
649
  return item ? withSelectable(row, item) : row;
608
650
  }
609
- var RECOVERY_DECKS = [
651
+ var BASE_RECOVERY_DECKS = [
610
652
  { label: "tasks", detail: "open tasks and dispatch work" },
611
- { label: "repair", detail: "repair project/server/auth link" },
612
653
  { label: "server", detail: "open server controls" },
613
654
  { label: "doctor", detail: "diagnose project" }
614
655
  ];
615
- function recoveryRows(selected, reason) {
656
+ function fleetRecoveryItems(state) {
657
+ if (!shouldOfferRemoteLinkRepair(state))
658
+ return BASE_FLEET_RECOVERY_ITEMS;
659
+ return [BASE_FLEET_RECOVERY_ITEMS[0], FLEET_REPAIR_LINK_ITEM, ...BASE_FLEET_RECOVERY_ITEMS.slice(1)];
660
+ }
661
+ function fleetRecoveryDecks(state) {
662
+ if (!shouldOfferRemoteLinkRepair(state))
663
+ return BASE_RECOVERY_DECKS;
664
+ return [BASE_RECOVERY_DECKS[0], { label: "repair link", detail: "backfill/prepare remote project-root link" }, ...BASE_RECOVERY_DECKS.slice(1)];
665
+ }
666
+ function recoveryRows(state, selected, reason) {
667
+ const items = fleetRecoveryItems(state);
616
668
  return [
617
669
  ...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
618
670
  line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
619
- ...RECOVERY_DECKS.map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, FLEET_RECOVERY_ITEMS[index]))
671
+ ...fleetRecoveryDecks(state).map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, items[index]))
620
672
  ];
621
673
  }
622
- function emptyRows(query, total, selected) {
674
+ function emptyRows(state, query, total, selected) {
623
675
  if (!query.trim() && total === 0)
624
- return recoveryRows(selected, "No runs yet.");
676
+ return recoveryRows(state, selected, "No runs yet.");
625
677
  if (query.trim() && total > 0) {
626
678
  return [
627
- ...recoveryRows(selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
679
+ ...recoveryRows(state, selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
628
680
  ];
629
681
  }
630
- return recoveryRows(selected, "No runs are visible with this filter.");
682
+ return recoveryRows(state, selected, "No runs are visible with this filter.");
631
683
  }
632
684
  function degradedRows(state, selected) {
633
685
  if (!state.error)
634
686
  return [];
635
- return recoveryRows(selected, state.error.message);
687
+ return recoveryRows(state, selected, state.error.message);
636
688
  }
637
689
  function renderFleetScene(state, layout) {
638
690
  const width = panelWidth(layout);
@@ -642,7 +694,7 @@ function renderFleetScene(state, layout) {
642
694
  const runs = sortRuns(filterRunsForSearch(allRuns, query), spec);
643
695
  const selectedRun = typeof state.data.selectedRunId === "string" && runs.some((run) => run.runId === state.data.selectedRunId) ? state.data.selectedRunId : runs[0]?.runId;
644
696
  const selectedIndex = Math.max(0, runs.findIndex((run) => run.runId === selectedRun));
645
- const recoveryIndex = Math.max(0, Math.min(3, state.selection.index));
697
+ const recoveryIndex = Math.max(0, Math.min(fleetRecoveryItems(state).length - 1, state.selection.index));
646
698
  const optimistic = optimisticStatuses(state);
647
699
  const updatedAgo = updatedAgoLabel(state);
648
700
  const panelTop = 0;
@@ -674,7 +726,7 @@ function renderFleetScene(state, layout) {
674
726
  ...runs.map((run, index) => runRow(contentWidth, run, index === selectedIndex, optimistic.get(run.runId)))
675
727
  ] : state.error ? degradedRows(state, recoveryIndex) : loading ? loadingRows("runs", state.tick) : [
676
728
  ...query.trim() ? [line(searchSummary("runs", query, runs.length, allRuns.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
677
- ...emptyRows(query, allRuns.length, recoveryIndex)
729
+ ...emptyRows(state, query, allRuns.length, recoveryIndex)
678
730
  ]
679
731
  ];
680
732
  return makeSceneFrame({
@@ -143,12 +143,13 @@ var PRIMARY_GROUPS = [
143
143
  {
144
144
  name: "server",
145
145
  summary: "Choose, inspect, and start the Rig server that owns tasks and runs.",
146
- usage: ["rig server <status|list|add|use|start> [options]"],
146
+ usage: ["rig server <status|list|add|use|repair-link|start> [options]"],
147
147
  commands: [
148
- { command: "status", description: "Show the selected server for this repo.", primary: true },
148
+ { command: "status", description: "Show the selected server and remote project-root link for this repo.", primary: true },
149
149
  { command: "use local", description: "Switch this repo to the local Rig server.", primary: true },
150
150
  { command: "add <alias> <url>", description: "Save a remote Rig server URL.", primary: true },
151
151
  { command: "use <alias>", description: "Select a saved remote server alias.", primary: true },
152
+ { command: "repair-link [--prepare|--backfill-only] [--repo owner/repo]", description: "Backfill or prepare the selected remote's server-host checkout link.", primary: true },
152
153
  { command: "list", description: "List saved local/remote server aliases.", primary: true },
153
154
  { command: "start [--host <host>] [--port <n>]", description: "Start a local rig-server process." }
154
155
  ],
@@ -156,6 +157,7 @@ var PRIMARY_GROUPS = [
156
157
  "rig server status",
157
158
  "rig server add prod https://where.rig-does.work",
158
159
  "rig server use prod",
160
+ "rig server repair-link --repo owner/repo",
159
161
  "rig server use local",
160
162
  "rig server start --port 3773"
161
163
  ],
@@ -79,19 +79,19 @@ function selectableDeckRow(deck, item) {
79
79
  }
80
80
 
81
81
  // packages/cli/src/app-opentui/scenes/init.ts
82
- var STEP_CONFIG_RUN = { id: "step-config", label: "run setup wizard", intent: { scene: "command", argv: ["init"], action: { kind: "command-run", label: "Run setup wizard" } }, message: "full interactive setup wizard" };
82
+ var STEP_CONFIG_RUN = { id: "step-config", label: "run init", intent: { scene: "init", argv: ["init", "--yes"], action: { kind: "init-start", label: "Run init" } }, message: "initialize without embedded CLI prompts" };
83
83
  var STEP_SERVER = { id: "step-server", label: "select server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Choose server" } }, message: "select local or remote server" };
84
- var STEP_AUTH = { id: "step-auth", label: "connect GitHub", intent: { scene: "command", argv: ["github", "auth", "import-gh"], action: { kind: "command-run", label: "Connect GitHub" } }, message: "import GitHub auth into the selected server" };
85
- var STEP_TASKS = { id: "step-tasks", label: "pick a task source", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Configure task source" } }, message: "configure or repair the task source" };
84
+ var STEP_AUTH = { id: "step-auth", label: "connect GitHub", intent: { scene: "server", argv: ["github", "auth", "status"], action: { kind: "refresh", label: "Open GitHub auth" } }, message: "open native server/auth controls" };
85
+ var STEP_TASKS = { id: "step-tasks", label: "repair task source", intent: { scene: "init", argv: ["init", "--repair", "--yes"], action: { kind: "init-start", label: "Repair task source" } }, message: "repair generated task-source config without embedded CLI prompts" };
86
86
  var SETUP_STEPS = [
87
- { id: "config", label: "Project config", detail: "rig.config + private state", done: (s) => s.configured, cta: "Run setup wizard", item: STEP_CONFIG_RUN },
87
+ { id: "config", label: "Project config", detail: "rig.config + private state", done: (s) => s.configured, cta: "Run init", item: STEP_CONFIG_RUN },
88
88
  { id: "server", label: "Server target", detail: "local or remote, reachable", done: (s) => s.serverReachable, cta: "Choose a server", item: STEP_SERVER },
89
89
  { id: "auth", label: "GitHub auth", detail: "signed in on the selected server", done: (s) => s.authSignedIn, cta: "Connect GitHub", item: STEP_AUTH },
90
90
  { id: "tasks", label: "Task source", detail: "where work comes from", done: (s) => s.taskSourceReady, cta: "Pick a task source", item: STEP_TASKS }
91
91
  ];
92
92
  var SECONDARY_ACTIONS = [
93
- { label: "repair", detail: "reconfigure generated config and private state", item: { id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Reconfigure project" } }, message: "verify or rewrite generated config" } },
94
- { label: "demo", detail: "seed an offline demo task source to explore", item: { id: "demo", label: "demo", intent: { scene: "command", argv: ["init", "--demo", "--repair"], action: { kind: "command-run", label: "Seed demo project" } }, message: "offline demo project" } },
93
+ { label: "repair", detail: "reconfigure generated config and private state", item: { id: "repair", label: "repair", intent: { scene: "init", argv: ["init", "--repair", "--yes"], action: { kind: "init-start", label: "Reconfigure project" } }, message: "verify or rewrite generated config natively" } },
94
+ { label: "demo", detail: "seed an offline demo task source to explore", item: { id: "demo", label: "demo", intent: { scene: "init", argv: ["init", "--demo", "--repair", "--yes"], action: { kind: "init-start", label: "Seed demo project" } }, message: "offline demo project without embedded CLI prompts" } },
95
95
  { label: "doctor", detail: "diagnose what is still missing", item: { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "verify setup" } }
96
96
  ];
97
97
  function record(value) {
@@ -135,11 +135,11 @@ function renderInitScene(state, layout) {
135
135
  const allDone = completed === SETUP_STEPS.length;
136
136
  const nextStep = SETUP_STEPS.find((step) => !step.done(signals));
137
137
  const selected = Math.max(0, state.selection.index);
138
- const primary = nextStep ? selectableDeckRow({ label: "next", detail: `${nextStep.cta} \u2014 recommended`, active: selected === 0 }, { ...nextStep.item, id: "init-primary" }) : selectableDeckRow({ label: "verify", detail: "Setup complete \u2014 run doctor to confirm", active: selected === 0 }, { id: "init-primary", label: "verify", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "verify setup end-to-end" });
138
+ const primary = nextStep ? selectableDeckRow({ label: "next", detail: `${nextStep.cta} \u2014 recommended`, active: selected === 0 }, { ...nextStep.item, id: "init-primary" }) : selectableDeckRow({ label: "verify", detail: "Init complete \u2014 run doctor to confirm", active: selected === 0 }, { id: "init-primary", label: "verify", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "verify setup end-to-end" });
139
139
  const secondaryRows = SECONDARY_ACTIONS.map(({ label, detail, item }, index) => selectableDeckRow({ label, detail, active: selected === index + 1 }, item));
140
140
  const progress = allDone ? "all set" : `${completed} of ${SETUP_STEPS.length} complete`;
141
141
  const panelLines = [
142
- line(allDone ? "SETUP \xB7 ready to go" : "SETUP \xB7 let's get you running", { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink, bold: true }),
142
+ line(allDone ? "INIT \xB7 ready to go" : "INIT \xB7 let's get you running", { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink, bold: true }),
143
143
  line(`progress ${progress}`, { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink2 }),
144
144
  blank(),
145
145
  line("CHECKLIST", { fg: RIG_UI.ink3, bold: true }),
@@ -151,11 +151,11 @@ function renderInitScene(state, layout) {
151
151
  line("OTHER PATHS", { fg: RIG_UI.ink3, bold: true }),
152
152
  ...secondaryRows,
153
153
  blank(),
154
- line("enter/click runs the highlighted action \xB7 esc goes back \xB7 tab switches sections", { fg: RIG_UI.ink4 })
154
+ line("enter/click runs the highlighted native action \xB7 esc goes back \xB7 tab switches sections", { fg: RIG_UI.ink4 })
155
155
  ];
156
156
  return makeSceneFrame({
157
157
  scene: "init",
158
- title: "Setup",
158
+ title: "Init",
159
159
  lines: [],
160
160
  panels: [{
161
161
  id: "init-setup",
@@ -168,11 +168,11 @@ function renderInitScene(state, layout) {
168
168
  opacity: 0.98,
169
169
  border: false,
170
170
  chrome: "ad-terminal",
171
- headerText: "rig setup \xB7 guided onboarding",
171
+ headerText: "rig init \xB7 guided onboarding",
172
172
  paddingX: 5,
173
173
  paddingY: 2
174
174
  }],
175
- footer: { message: allDone ? "setup complete" : "setup in progress" },
175
+ footer: { message: allDone ? "init complete" : "init in progress" },
176
176
  live: !allDone || state.status === "action"
177
177
  });
178
178
  }
@@ -144,7 +144,7 @@ function sparklineString(values, width) {
144
144
 
145
145
  // packages/cli/src/app-opentui/scenes/main.ts
146
146
  var CONFIGURED_MENU = [
147
- ["init", "setup, reconfigure, repair project state", { id: "init", label: "init", intent: { scene: "command", argv: ["init"], action: { kind: "command-run", label: "Run init" } }, message: "run setup/reconfigure flow" }],
147
+ ["init", "guided setup, reconfigure, repair project state", { id: "init", label: "init", intent: { scene: "init", argv: ["init"], action: { kind: "refresh", label: "Open init" } }, message: "open native init flow" }],
148
148
  ["server", "local/remote target, auth, linkage", { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Checking server" } }, message: "check selected server" }],
149
149
  ["github", "auth, selected repo, stored token", { id: "github", label: "github", intent: { scene: "server", argv: ["github", "auth", "status"], action: { kind: "refresh", label: "Checking GitHub auth" } }, message: "check GitHub auth" }],
150
150
  ["tasks", "browse, filter, dispatch, attach active work", { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Opening tasks" } }, message: "selected tasks" }],
@@ -163,10 +163,10 @@ var CONFIGURED_MENU = [
163
163
  ["help", "all actions, shortcuts, mouse controls", { id: "help", label: "help", intent: { scene: "help", argv: ["help"], action: { kind: "none", label: "Opening help" } }, message: "selected help" }]
164
164
  ];
165
165
  var ONBOARD_PRIMARY = {
166
- id: "onboard-setup",
167
- label: "Start guided setup",
168
- intent: { scene: "init", argv: ["init"], action: { kind: "refresh", label: "Setup" } },
169
- message: "open the guided setup checklist"
166
+ id: "onboard-init",
167
+ label: "Start guided init",
168
+ intent: { scene: "init", argv: ["init"], action: { kind: "refresh", label: "Init" } },
169
+ message: "open the native init checklist"
170
170
  };
171
171
  var ONBOARD_SECONDARY = [
172
172
  ["server", "select a local or remote target", { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Checking server" } }, message: "check selected server" }],
@@ -229,7 +229,7 @@ function configuredMenuRows(selectedIndex) {
229
229
  }));
230
230
  }
231
231
  function onboardingRows(selectedIndex) {
232
- const primary = selectableDeckRow({ label: "setup", detail: "Start guided setup \u2014 recommended", active: selectedIndex === 0 }, ONBOARD_PRIMARY);
232
+ const primary = selectableDeckRow({ label: "init", detail: "Start guided init \u2014 recommended", active: selectedIndex === 0 }, ONBOARD_PRIMARY);
233
233
  const secondary = ONBOARD_SECONDARY.map(([label, detail, item], index) => ({
234
234
  ...deckRow({ label, detail, index: index + 1, active: selectedIndex === index + 1, activateOnClick: true }),
235
235
  selectable: item
@@ -293,7 +293,7 @@ function renderMainScene(state, layout) {
293
293
  statusLine(state)
294
294
  ] : [
295
295
  line("WELCOME", { fg: RIG_UI.ink, bold: true }),
296
- line("This project isn't set up yet. One guided flow gets you running.", { fg: RIG_UI.ink2 }),
296
+ line("This project isn't initialized yet. One native init flow gets you running.", { fg: RIG_UI.ink2 }),
297
297
  blank(),
298
298
  line("GET STARTED", { fg: RIG_UI.ink, bold: true }),
299
299
  ...onboardingRows(actionSelected),
@@ -215,19 +215,85 @@ function selectableDeckRow(deck, item) {
215
215
  return { ...deckRow({ ...deck, activateOnClick: true }), selectable: item };
216
216
  }
217
217
 
218
+ // packages/cli/src/app-opentui/remote-link.ts
219
+ var REPAIRABLE_REMOTE_LINK_STATUSES = new Set([
220
+ "auth_required",
221
+ "project_not_registered",
222
+ "no_server_checkout",
223
+ "invalid_root",
224
+ "needs_prepare",
225
+ "error"
226
+ ]);
227
+ function remoteProjectLinkError(message) {
228
+ return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(message ?? "");
229
+ }
230
+ function serverRecordForRemoteLink(state) {
231
+ const server = state.data.server;
232
+ return server && typeof server === "object" && !Array.isArray(server) ? server : null;
233
+ }
234
+ function remoteProjectLinkState(state) {
235
+ const serverRecord = serverRecordForRemoteLink(state);
236
+ if (!serverRecord || serverRecord.kind !== "remote")
237
+ return null;
238
+ const link = serverRecord.remoteProjectLink;
239
+ if (link && typeof link === "object" && !Array.isArray(link))
240
+ return link;
241
+ const direct = state.data.remoteProjectLink;
242
+ if (direct && typeof direct === "object" && !Array.isArray(direct))
243
+ return direct;
244
+ return null;
245
+ }
246
+ function shouldOfferRemoteLinkRepair(state, message) {
247
+ const link = remoteProjectLinkState(state);
248
+ if (link) {
249
+ if (link.ok === true)
250
+ return false;
251
+ const status = link.status ?? "";
252
+ return REPAIRABLE_REMOTE_LINK_STATUSES.has(status);
253
+ }
254
+ const serverRecord = serverRecordForRemoteLink(state);
255
+ if (serverRecord && serverRecord.kind !== "remote")
256
+ return false;
257
+ return remoteProjectLinkError(message ?? state.error?.message);
258
+ }
259
+
218
260
  // packages/cli/src/app-opentui/scenes/server.ts
219
261
  var SERVER_ACTIONS = [
220
262
  { detail: "probe selected server, project root, and GitHub auth", item: { id: "refresh", label: "refresh", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Refresh server" } }, message: "refresh selected server" } },
221
- { detail: "select local server for this repo", item: { id: "local", label: "use local", intent: { scene: "command", argv: ["server", "use", "local"], action: { kind: "command-run", label: "Use local server" } }, message: "switch this repo to local" } },
222
- { detail: "choose/switch to a saved remote server alias", item: { id: "remote", label: "use remote", intent: { scene: "command", argv: ["server", "use"], action: { kind: "command-run", label: "Choose remote server" } }, message: "choose a saved remote alias" } },
223
- { detail: "show saved local/remote aliases", item: { id: "list", label: "list servers", intent: { scene: "command", argv: ["server", "list"], action: { kind: "command-run", label: "List saved servers" } }, message: "list saved server aliases" } },
224
- { detail: "open server add command workspace", item: { id: "add", label: "add remote", intent: { scene: "command", argv: ["server", "add"], action: { kind: "command-run", label: "Add remote server" } }, message: "open server add workspace" } },
263
+ { detail: "select local server for this repo", item: { id: "local", label: "use local", intent: { scene: "server", argv: ["server", "use", "local"], action: { kind: "server-use-local", label: "Use local server" } }, message: "switch this repo to local" } },
264
+ { detail: "type a saved remote alias to select", item: { id: "remote", label: "use remote", prompt: { label: "Use remote alias", scene: "server", argv: ["server", "use"], intentKind: "server-use-remote", payloadBase: {}, payloadKey: "alias" }, message: "choose a saved remote alias" } },
265
+ { detail: "show saved local/remote aliases in the status panel", item: { id: "list", label: "list servers", intent: { scene: "server", argv: ["server", "list"], action: { kind: "refresh", label: "List servers" } }, message: "list saved server aliases" } },
266
+ { detail: "add and select a remote: enter <alias> <https-url>", item: { id: "add", label: "add remote", prompt: { label: "Add remote", scene: "server", argv: ["server", "add"], intentKind: "server-add-remote", payloadBase: {}, payloadKey: "remote", appendValueToArgv: true }, message: "add a remote server alias" } },
225
267
  { detail: "spawn the local rig-server detached and return here", item: { id: "start", label: "start local", intent: { scene: "server", argv: ["server", "start"], action: { kind: "refresh", payload: { startLocal: true }, label: "Start local server" } }, message: "start local server detached" } },
226
- { detail: "import gh token into the selected server namespace", item: { id: "auth", label: "import auth", intent: { scene: "command", argv: ["github", "auth", "import-gh"], action: { kind: "command-run", label: "Import GitHub auth" } }, message: "import gh auth to selected server" } },
268
+ { detail: "import gh token into the selected server namespace", item: { id: "auth", label: "import auth", intent: { scene: "server", argv: ["github", "auth", "import-gh"], action: { kind: "github-auth-import", label: "Import GitHub auth" } }, message: "import gh auth to selected server" } },
227
269
  { detail: "diagnose server/auth/project linkage", item: { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "verify server/auth" } },
228
270
  { detail: "verify selected server can list task source", item: { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["task", "list"], action: { kind: "refresh", label: "Open tasks" } }, message: "verify task source" } },
229
271
  { detail: "verify selected server can list recent runs", item: { id: "runs", label: "runs", intent: { scene: "fleet", argv: ["run", "status"], action: { kind: "refresh", label: "Open runs" } }, message: "open recent runs" } }
230
272
  ];
273
+ function remoteAliasActions(server) {
274
+ const aliases = (server?.aliases ?? []).filter((alias) => alias.kind === "remote");
275
+ return aliases.map((alias) => ({
276
+ detail: `${alias.selected ? "selected" : "select"} ${alias.baseUrl ?? "remote endpoint"}`,
277
+ item: {
278
+ id: `remote-alias:${alias.alias}`,
279
+ label: alias.selected ? `\u2713 ${alias.alias}` : `use ${alias.alias}`,
280
+ intent: { scene: "server", argv: ["server", "use", alias.alias], action: { kind: "server-use-remote", label: `Use ${alias.alias}`, payload: { alias: alias.alias } } },
281
+ message: `select ${alias.alias}`
282
+ }
283
+ }));
284
+ }
285
+ function serverActions(state) {
286
+ const server = serverState(state);
287
+ const remoteRows = remoteAliasActions(server);
288
+ let actions = remoteRows.length > 0 ? [...SERVER_ACTIONS.slice(0, 3), ...remoteRows, ...SERVER_ACTIONS.slice(3)] : [...SERVER_ACTIONS];
289
+ if (!shouldOfferRemoteLinkRepair(state))
290
+ return actions;
291
+ const repair = { detail: "backfill or prepare the selected remote checkout/root link", item: { id: "repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link" } }, message: "prepare remote checkout link" } };
292
+ const doctorIndex = actions.findIndex((entry) => entry.item.id === "doctor");
293
+ if (doctorIndex < 0)
294
+ return [...actions, repair];
295
+ return [...actions.slice(0, doctorIndex), repair, ...actions.slice(doctorIndex)];
296
+ }
231
297
  function cleanVisible(value, fallback = "unknown") {
232
298
  return value?.trim() || fallback;
233
299
  }
@@ -252,31 +318,37 @@ function selectedIndex(state, count) {
252
318
  function statusRows(server) {
253
319
  const auth = server?.auth;
254
320
  const signedIn = auth && (auth.signedIn === true || auth.authenticated === true || auth.status === "authenticated") ? "authenticated" : "auth unknown";
321
+ const link = server?.remoteProjectLink;
322
+ const linkText = link ? link.ok ? `ready \xB7 ${link.serverProjectRoot ?? "linked"}` : `${link.status ?? "needs repair"} \xB7 ${link.hint ?? link.message ?? "run repair link"}` : server?.kind === "remote" ? "not checked" : "not required";
323
+ const selectedLinkSummary = link?.ok ? " \xB7 root link ready" : server?.kind === "remote" && link ? ` \xB7 root link ${link.status ?? "needs repair"}` : "";
255
324
  return [
256
- line(`selected ${cleanVisible(server?.label, "not checked")}`, { fg: RIG_UI.ink2 }),
325
+ line(`selected ${cleanVisible(server?.label, "not checked")}${selectedLinkSummary}`, { fg: RIG_UI.ink2 }),
257
326
  line(`target ${targetLabel(server)}`, { fg: RIG_UI.ink3 }),
258
327
  line(`mode ${server?.kind ?? "local or remote"}`, { fg: RIG_UI.ink3 }),
259
328
  line(`health ${server ? server.reachable ? "reachable" : "unreachable" : "check pending"}`, { fg: server?.reachable ? RIG_UI.limeDim : server ? RIG_UI.red : RIG_UI.yellow }),
260
329
  line(`github ${signedIn}`, { fg: signedIn === "authenticated" ? RIG_UI.limeDim : RIG_UI.ink4 }),
330
+ line(`root link ${linkText}`, { fg: link?.ok ? RIG_UI.limeDim : server?.kind === "remote" ? RIG_UI.yellow : RIG_UI.ink4 }),
331
+ ...server?.aliases && server.aliases.length > 0 ? [line(`aliases ${server.aliases.map((alias) => `${alias.selected ? "*" : ""}${alias.alias}${alias.kind === "remote" && alias.baseUrl ? `=${alias.baseUrl}` : ""}`).join(", ")}`, { fg: RIG_UI.ink4 })] : [],
261
332
  ...server?.error ? [line(`attention ${server.error}`, { fg: RIG_UI.yellow })] : []
262
333
  ];
263
334
  }
264
335
  function renderServerScene(state, layout) {
265
336
  const server = serverState(state);
266
- const selected = selectedIndex(state, 10);
337
+ const actions = serverActions(state);
338
+ const selected = selectedIndex(state, actions.length);
267
339
  const loading = state.status === "loading" && !server;
268
340
  const errorText = state.error?.message ?? lastRefreshError(state);
269
341
  const panelLines = [
270
342
  ...errorText ? errorBanner(errorText, "select refresh or doctor below to retry") : [],
271
343
  line("server controls", { fg: RIG_UI.ink3 }),
272
344
  blank(),
273
- line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
274
- ...SERVER_ACTIONS.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item)),
275
- blank(),
276
345
  line("STATUS", { fg: RIG_UI.ink3, bold: true }),
277
346
  ...loading ? loadingRows("server status", state.tick) : statusRows(server),
278
347
  blank(),
279
- line("enter/click runs action \xB7 command rows stay inside OpenTUI PTY", { fg: RIG_UI.ink4 })
348
+ line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
349
+ ...actions.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item)),
350
+ blank(),
351
+ line("enter/click runs native actions \xB7 add/use remote prompts stay in OpenTUI", { fg: RIG_UI.ink4 })
280
352
  ];
281
353
  return makeSceneFrame({
282
354
  scene: "server",