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

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 (231) hide show
  1. package/dist/bin/build-rig-binaries.js +8 -40
  2. package/dist/bin/rig.js +12519 -26675
  3. package/dist/src/app/board.js +74 -693
  4. package/dist/src/app/drone-ui.js +1 -1
  5. package/dist/src/app/theme.js +0 -1
  6. package/dist/src/commands/_async-ui.js +1 -1
  7. package/dist/src/commands/_authority-runs.d.ts +1 -1
  8. package/dist/src/commands/_authority-runs.js +12 -2
  9. package/dist/src/commands/_cli-format.d.ts +1 -10
  10. package/dist/src/commands/_cli-format.js +2 -5
  11. package/dist/src/commands/_connection-state.d.ts +1 -11
  12. package/dist/src/commands/_connection-state.js +5 -50
  13. package/dist/src/commands/_doctor-checks.js +40 -501
  14. package/dist/src/commands/_help-catalog.js +17 -99
  15. package/dist/src/commands/_json-output.js +0 -4
  16. package/dist/src/commands/_operator-view.js +54 -575
  17. package/dist/src/commands/_pi-frontend.d.ts +0 -27
  18. package/dist/src/commands/_pi-frontend.js +52 -576
  19. package/dist/src/commands/_preflight.js +66 -553
  20. package/dist/src/commands/_server-client.d.ts +0 -33
  21. package/dist/src/commands/_server-client.js +46 -541
  22. package/dist/src/commands/_snapshot-upload.js +42 -503
  23. package/dist/src/commands/_spinner.js +1 -1
  24. package/dist/src/commands/agent.js +12 -2
  25. package/dist/src/commands/browser.js +1 -1
  26. package/dist/src/commands/connect.js +15 -626
  27. package/dist/src/commands/doctor.js +41 -502
  28. package/dist/src/commands/github.js +51 -584
  29. package/dist/src/commands/inbox.js +41 -502
  30. package/dist/src/commands/init.js +74 -561
  31. package/dist/src/commands/inspect.js +41 -502
  32. package/dist/src/commands/run.js +54 -578
  33. package/dist/src/commands/server.js +163 -692
  34. package/dist/src/commands/setup.js +46 -507
  35. package/dist/src/commands/stats.js +58 -601
  36. package/dist/src/commands/task-run-driver.js +58 -509
  37. package/dist/src/commands/task.js +110 -729
  38. package/dist/src/commands.js +237 -1112
  39. package/dist/src/index.js +244 -1123
  40. package/dist/src/launcher.js +0 -4
  41. package/package.json +9 -13
  42. package/dist/src/app-opentui/adapters/command.d.ts +0 -2
  43. package/dist/src/app-opentui/adapters/command.js +0 -329
  44. package/dist/src/app-opentui/adapters/common.d.ts +0 -56
  45. package/dist/src/app-opentui/adapters/common.js +0 -153
  46. package/dist/src/app-opentui/adapters/doctor.d.ts +0 -9
  47. package/dist/src/app-opentui/adapters/doctor.js +0 -1217
  48. package/dist/src/app-opentui/adapters/family.d.ts +0 -62
  49. package/dist/src/app-opentui/adapters/family.js +0 -14855
  50. package/dist/src/app-opentui/adapters/fleet.d.ts +0 -14
  51. package/dist/src/app-opentui/adapters/fleet.js +0 -1335
  52. package/dist/src/app-opentui/adapters/inbox.d.ts +0 -43
  53. package/dist/src/app-opentui/adapters/inbox.js +0 -1944
  54. package/dist/src/app-opentui/adapters/init.d.ts +0 -11
  55. package/dist/src/app-opentui/adapters/init.js +0 -2818
  56. package/dist/src/app-opentui/adapters/inspect.d.ts +0 -52
  57. package/dist/src/app-opentui/adapters/inspect.js +0 -1455
  58. package/dist/src/app-opentui/adapters/pi-attach.d.ts +0 -32
  59. package/dist/src/app-opentui/adapters/pi-attach.js +0 -2101
  60. package/dist/src/app-opentui/adapters/pi.d.ts +0 -23
  61. package/dist/src/app-opentui/adapters/pi.js +0 -363
  62. package/dist/src/app-opentui/adapters/plugin.d.ts +0 -84
  63. package/dist/src/app-opentui/adapters/plugin.js +0 -544
  64. package/dist/src/app-opentui/adapters/repo.d.ts +0 -37
  65. package/dist/src/app-opentui/adapters/repo.js +0 -186
  66. package/dist/src/app-opentui/adapters/run-detail.d.ts +0 -27
  67. package/dist/src/app-opentui/adapters/run-detail.js +0 -1441
  68. package/dist/src/app-opentui/adapters/server.d.ts +0 -48
  69. package/dist/src/app-opentui/adapters/server.js +0 -1561
  70. package/dist/src/app-opentui/adapters/tasks.d.ts +0 -64
  71. package/dist/src/app-opentui/adapters/tasks.js +0 -4524
  72. package/dist/src/app-opentui/adapters/workspace.d.ts +0 -49
  73. package/dist/src/app-opentui/adapters/workspace.js +0 -333
  74. package/dist/src/app-opentui/autocomplete.d.ts +0 -20
  75. package/dist/src/app-opentui/autocomplete.js +0 -578
  76. package/dist/src/app-opentui/bootstrap.d.ts +0 -11
  77. package/dist/src/app-opentui/bootstrap.js +0 -27833
  78. package/dist/src/app-opentui/command-palette.d.ts +0 -3
  79. package/dist/src/app-opentui/command-palette.js +0 -1038
  80. package/dist/src/app-opentui/command-pty-host.d.ts +0 -62
  81. package/dist/src/app-opentui/command-pty-host.js +0 -248
  82. package/dist/src/app-opentui/drone.d.ts +0 -12
  83. package/dist/src/app-opentui/drone.js +0 -230
  84. package/dist/src/app-opentui/events.d.ts +0 -7
  85. package/dist/src/app-opentui/events.js +0 -28
  86. package/dist/src/app-opentui/fleet-stats.d.ts +0 -32
  87. package/dist/src/app-opentui/fleet-stats.js +0 -114
  88. package/dist/src/app-opentui/focus-manager.d.ts +0 -14
  89. package/dist/src/app-opentui/focus-manager.js +0 -24
  90. package/dist/src/app-opentui/index.d.ts +0 -8
  91. package/dist/src/app-opentui/index.js +0 -5260
  92. package/dist/src/app-opentui/intent.d.ts +0 -3
  93. package/dist/src/app-opentui/intent.js +0 -365
  94. package/dist/src/app-opentui/keymap.d.ts +0 -21
  95. package/dist/src/app-opentui/keymap.js +0 -1377
  96. package/dist/src/app-opentui/launch-routing.d.ts +0 -16
  97. package/dist/src/app-opentui/launch-routing.js +0 -55
  98. package/dist/src/app-opentui/layout.d.ts +0 -22
  99. package/dist/src/app-opentui/layout.js +0 -51
  100. package/dist/src/app-opentui/list-search.d.ts +0 -36
  101. package/dist/src/app-opentui/list-search.js +0 -130
  102. package/dist/src/app-opentui/pi-host-child.d.ts +0 -2
  103. package/dist/src/app-opentui/pi-host-child.js +0 -1299
  104. package/dist/src/app-opentui/pi-pty-host.d.ts +0 -28
  105. package/dist/src/app-opentui/pi-pty-host.js +0 -10
  106. package/dist/src/app-opentui/react/App.d.ts +0 -9
  107. package/dist/src/app-opentui/react/App.js +0 -3866
  108. package/dist/src/app-opentui/react/Backdrop.d.ts +0 -5
  109. package/dist/src/app-opentui/react/Backdrop.js +0 -823
  110. package/dist/src/app-opentui/react/ChromeHost.d.ts +0 -5
  111. package/dist/src/app-opentui/react/ChromeHost.js +0 -1539
  112. package/dist/src/app-opentui/react/SceneFrameView.d.ts +0 -7
  113. package/dist/src/app-opentui/react/SceneFrameView.js +0 -579
  114. package/dist/src/app-opentui/react/context.d.ts +0 -17
  115. package/dist/src/app-opentui/react/context.js +0 -37
  116. package/dist/src/app-opentui/react/launch.d.ts +0 -2
  117. package/dist/src/app-opentui/react/launch.js +0 -4897
  118. package/dist/src/app-opentui/react/nav.d.ts +0 -18
  119. package/dist/src/app-opentui/react/nav.js +0 -54
  120. package/dist/src/app-opentui/react/scroll.d.ts +0 -12
  121. package/dist/src/app-opentui/react/scroll.js +0 -21
  122. package/dist/src/app-opentui/react/syntax.d.ts +0 -2
  123. package/dist/src/app-opentui/react/syntax.js +0 -65
  124. package/dist/src/app-opentui/registry.d.ts +0 -4
  125. package/dist/src/app-opentui/registry.js +0 -22876
  126. package/dist/src/app-opentui/remote-link.d.ts +0 -10
  127. package/dist/src/app-opentui/remote-link.js +0 -47
  128. package/dist/src/app-opentui/render/ascii-fleet.d.ts +0 -15
  129. package/dist/src/app-opentui/render/ascii-fleet.js +0 -82
  130. package/dist/src/app-opentui/render/constants.d.ts +0 -30
  131. package/dist/src/app-opentui/render/constants.js +0 -64
  132. package/dist/src/app-opentui/render/graphics.d.ts +0 -40
  133. package/dist/src/app-opentui/render/graphics.js +0 -713
  134. package/dist/src/app-opentui/render/hover.d.ts +0 -11
  135. package/dist/src/app-opentui/render/hover.js +0 -34
  136. package/dist/src/app-opentui/render/native-host.d.ts +0 -37
  137. package/dist/src/app-opentui/render/native-host.js +0 -180
  138. package/dist/src/app-opentui/render/panel-layout.d.ts +0 -38
  139. package/dist/src/app-opentui/render/panel-layout.js +0 -48
  140. package/dist/src/app-opentui/render/panels.d.ts +0 -12
  141. package/dist/src/app-opentui/render/panels.js +0 -288
  142. package/dist/src/app-opentui/render/preloader.d.ts +0 -10
  143. package/dist/src/app-opentui/render/preloader.js +0 -166
  144. package/dist/src/app-opentui/render/scene.d.ts +0 -68
  145. package/dist/src/app-opentui/render/scene.js +0 -300
  146. package/dist/src/app-opentui/render/terminal-handoff.d.ts +0 -16
  147. package/dist/src/app-opentui/render/terminal-handoff.js +0 -14
  148. package/dist/src/app-opentui/render/text.d.ts +0 -29
  149. package/dist/src/app-opentui/render/text.js +0 -177
  150. package/dist/src/app-opentui/render/type-bar.d.ts +0 -15
  151. package/dist/src/app-opentui/render/type-bar.js +0 -212
  152. package/dist/src/app-opentui/runtime-resources.d.ts +0 -16
  153. package/dist/src/app-opentui/runtime-resources.js +0 -62
  154. package/dist/src/app-opentui/runtime.d.ts +0 -45
  155. package/dist/src/app-opentui/runtime.js +0 -5232
  156. package/dist/src/app-opentui/scenes/command.d.ts +0 -3
  157. package/dist/src/app-opentui/scenes/command.js +0 -118
  158. package/dist/src/app-opentui/scenes/doctor.d.ts +0 -3
  159. package/dist/src/app-opentui/scenes/doctor.js +0 -296
  160. package/dist/src/app-opentui/scenes/error.d.ts +0 -2
  161. package/dist/src/app-opentui/scenes/error.js +0 -277
  162. package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +0 -2
  163. package/dist/src/app-opentui/scenes/family-domains/agent.js +0 -349
  164. package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +0 -2
  165. package/dist/src/app-opentui/scenes/family-domains/browser.js +0 -196
  166. package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +0 -2
  167. package/dist/src/app-opentui/scenes/family-domains/dist.js +0 -244
  168. package/dist/src/app-opentui/scenes/family-domains/git.d.ts +0 -2
  169. package/dist/src/app-opentui/scenes/family-domains/git.js +0 -196
  170. package/dist/src/app-opentui/scenes/family-domains/github.d.ts +0 -2
  171. package/dist/src/app-opentui/scenes/family-domains/github.js +0 -275
  172. package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +0 -2
  173. package/dist/src/app-opentui/scenes/family-domains/harness.js +0 -153
  174. package/dist/src/app-opentui/scenes/family-domains/index.d.ts +0 -4
  175. package/dist/src/app-opentui/scenes/family-domains/index.js +0 -1680
  176. package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +0 -76
  177. package/dist/src/app-opentui/scenes/family-domains/kit.js +0 -306
  178. package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +0 -2
  179. package/dist/src/app-opentui/scenes/family-domains/profile.js +0 -213
  180. package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +0 -2
  181. package/dist/src/app-opentui/scenes/family-domains/queue.js +0 -147
  182. package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +0 -2
  183. package/dist/src/app-opentui/scenes/family-domains/remote.js +0 -519
  184. package/dist/src/app-opentui/scenes/family-domains/review.d.ts +0 -2
  185. package/dist/src/app-opentui/scenes/family-domains/review.js +0 -281
  186. package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +0 -2
  187. package/dist/src/app-opentui/scenes/family-domains/setup.js +0 -268
  188. package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +0 -2
  189. package/dist/src/app-opentui/scenes/family-domains/stats.js +0 -371
  190. package/dist/src/app-opentui/scenes/family.d.ts +0 -3
  191. package/dist/src/app-opentui/scenes/family.js +0 -2199
  192. package/dist/src/app-opentui/scenes/fleet.d.ts +0 -3
  193. package/dist/src/app-opentui/scenes/fleet.js +0 -766
  194. package/dist/src/app-opentui/scenes/handoff.d.ts +0 -2
  195. package/dist/src/app-opentui/scenes/handoff.js +0 -455
  196. package/dist/src/app-opentui/scenes/help.d.ts +0 -3
  197. package/dist/src/app-opentui/scenes/help.js +0 -725
  198. package/dist/src/app-opentui/scenes/inbox.d.ts +0 -3
  199. package/dist/src/app-opentui/scenes/inbox.js +0 -427
  200. package/dist/src/app-opentui/scenes/init.d.ts +0 -3
  201. package/dist/src/app-opentui/scenes/init.js +0 -181
  202. package/dist/src/app-opentui/scenes/inspect.d.ts +0 -3
  203. package/dist/src/app-opentui/scenes/inspect.js +0 -794
  204. package/dist/src/app-opentui/scenes/main.d.ts +0 -3
  205. package/dist/src/app-opentui/scenes/main.js +0 -332
  206. package/dist/src/app-opentui/scenes/pi.d.ts +0 -3
  207. package/dist/src/app-opentui/scenes/pi.js +0 -509
  208. package/dist/src/app-opentui/scenes/plugin.d.ts +0 -3
  209. package/dist/src/app-opentui/scenes/plugin.js +0 -487
  210. package/dist/src/app-opentui/scenes/repo.d.ts +0 -3
  211. package/dist/src/app-opentui/scenes/repo.js +0 -425
  212. package/dist/src/app-opentui/scenes/run-detail.d.ts +0 -3
  213. package/dist/src/app-opentui/scenes/run-detail.js +0 -467
  214. package/dist/src/app-opentui/scenes/server.d.ts +0 -3
  215. package/dist/src/app-opentui/scenes/server.js +0 -378
  216. package/dist/src/app-opentui/scenes/tasks.d.ts +0 -3
  217. package/dist/src/app-opentui/scenes/tasks.js +0 -768
  218. package/dist/src/app-opentui/scenes/workspace.d.ts +0 -3
  219. package/dist/src/app-opentui/scenes/workspace.js +0 -427
  220. package/dist/src/app-opentui/selectable.d.ts +0 -19
  221. package/dist/src/app-opentui/selectable.js +0 -80
  222. package/dist/src/app-opentui/state.d.ts +0 -4
  223. package/dist/src/app-opentui/state.js +0 -399
  224. package/dist/src/app-opentui/surface-catalog.d.ts +0 -20
  225. package/dist/src/app-opentui/surface-catalog.js +0 -542
  226. package/dist/src/app-opentui/theme.d.ts +0 -59
  227. package/dist/src/app-opentui/theme.js +0 -142
  228. package/dist/src/app-opentui/types.d.ts +0 -313
  229. package/dist/src/app-opentui/types.js +0 -1
  230. package/dist/src/commands/_server-events.d.ts +0 -26
  231. package/dist/src/commands/_server-events.js +0 -715
@@ -50,7 +50,6 @@ function statusColor(status) {
50
50
  case "validating":
51
51
  case "reviewing":
52
52
  case "closing-out":
53
- case "stopping":
54
53
  return cyan;
55
54
  case "needs-attention":
56
55
  case "needs_attention":
@@ -197,13 +196,12 @@ var PRIMARY_GROUPS = [
197
196
  {
198
197
  name: "server",
199
198
  summary: "Choose, inspect, and start the Rig server that owns tasks and runs.",
200
- usage: ["rig server <status|list|add|use|repair-link|start> [options]"],
199
+ usage: ["rig server <status|list|add|use|start> [options]"],
201
200
  commands: [
202
- { command: "status", description: "Show the selected server and remote project-root link for this repo.", primary: true },
201
+ { command: "status", description: "Show the selected server for this repo.", primary: true },
203
202
  { command: "use local", description: "Switch this repo to the local Rig server.", primary: true },
204
203
  { command: "add <alias> <url>", description: "Save a remote Rig server URL.", primary: true },
205
204
  { command: "use <alias>", description: "Select a saved remote server alias.", primary: true },
206
- { command: "repair-link [--prepare|--backfill-only] [--repo owner/repo]", description: "Backfill or prepare the selected remote's server-host checkout link.", primary: true },
207
205
  { command: "list", description: "List saved local/remote server aliases.", primary: true },
208
206
  { command: "start [--host <host>] [--port <n>]", description: "Start a local rig-server process." }
209
207
  ],
@@ -211,7 +209,6 @@ var PRIMARY_GROUPS = [
211
209
  "rig server status",
212
210
  "rig server add prod https://where.rig-does.work",
213
211
  "rig server use prod",
214
- "rig server repair-link --repo owner/repo",
215
212
  "rig server use local",
216
213
  "rig server start --port 3773"
217
214
  ],
@@ -386,62 +383,30 @@ var PRIMARY_GROUPS = [
386
383
  }
387
384
  ];
388
385
  var ADVANCED_GROUPS = [
389
- {
390
- name: "setup",
391
- summary: "Bootstrap/check local setup.",
392
- usage: ["rig setup <bootstrap|check|preflight>"],
393
- commands: [
394
- { command: "bootstrap", description: "Bootstrap local setup dependencies.", primary: true },
395
- { command: "check", description: "Check local setup state (toolchain, deps, config).", primary: true },
396
- { command: "preflight", description: "Run preflight checks before a run.", primary: true }
397
- ]
398
- },
399
- {
400
- name: "profile",
401
- summary: "Runtime profile/model defaults.",
402
- usage: ["rig profile <show|set>"],
403
- commands: [
404
- { command: "show", description: "Show the active execution profile.", primary: true },
405
- { command: "set [--model <model>] [--runtime <runtime>] [--plugin <plugin>]", description: "Set model/runtime/plugin profile defaults.", primary: true }
406
- ]
407
- },
386
+ { name: "setup", summary: "Bootstrap/check local setup.", usage: ["rig setup <bootstrap|check|preflight>"], commands: [{ command: "bootstrap|check|preflight", description: "Setup helpers." }] },
387
+ { name: "profile", summary: "Runtime profile/model defaults.", usage: ["rig profile <show|set>"], commands: [{ command: "show", description: "Show active profile." }] },
408
388
  {
409
389
  name: "review",
410
390
  summary: "Inspect or change completion review gate policy.",
411
391
  usage: ["rig review <show|set>"],
412
392
  commands: [
413
393
  { command: "show", description: "Show current review gate settings." },
414
- { command: "set <off|advisory|required> [--provider <provider>]", description: "Change review strictness/provider (e.g. --provider greptile)." }
394
+ { command: "set <off|advisory|required> [--provider greptile]", description: "Change review strictness/provider." }
415
395
  ],
416
396
  examples: ["rig review show", "rig review set required --provider greptile"],
417
397
  next: ["Use `rig inbox approvals` for blocked run handoffs."]
418
398
  },
419
399
  {
420
400
  name: "browser",
421
- summary: "Browser workstation actions for browser-required tasks: launch, check, CDP probe, profile reset, and app-specific smokes.",
422
- usage: ["rig browser <help|explain|demo|hp-next|cdp-probe|profile-persistence|profile-lock-check|smoke-test> [options]"],
401
+ summary: "Browser/app diagnostics for browser-required tasks.",
402
+ usage: ["rig browser <help|explain|demo|app|hp-next> [options]"],
423
403
  commands: [
424
- { command: "help", description: "Rich browser command help (canonical: `rig browser help`).", primary: true },
425
- { command: "explain", description: "Explain the browser-required task contract and runtime helper commands.", primary: true },
426
- { command: "demo [--port <n>] [--profile <name>] [--state-dir <path>] [--target-url <url>] [--keep-open] [--no-build]", description: "Run a guided real browser/agent demo flow.", primary: true },
427
- { command: "hp-next dev", description: "Start hp-next Rig Browser in dev/watch mode.", primary: true },
428
- { command: "hp-next start", description: "Build/start the hp-next browser workstation without watch mode.", primary: true },
429
- { command: "hp-next check", description: "Validate the hp-next CDP endpoint on the configured port.", primary: true },
430
- { command: "hp-next e2e", description: "Run hp-next browser e2e smoke checks through Rig Browser.", primary: true },
431
- { command: "hp-next reset", description: "Reset the hp-next browser profile when stale browser state is suspected.", primary: true },
432
- { command: "cdp-probe", description: "Run an isolated CDP attach/evaluate/layout probe." },
433
- { command: "profile-persistence", description: "Verify a named browser profile persists browser state." },
434
- { command: "profile-lock-check", description: "Verify concurrent launches reject the same profile." },
435
- { command: "smoke-test", description: "Run the browser package smoke test." }
436
- ],
437
- examples: [
438
- "rig browser help",
439
- "rig browser hp-next check",
440
- "rig browser hp-next e2e",
441
- "rig browser cdp-probe",
442
- "rig browser profile-lock-check"
443
- ],
444
- next: ["Inside a task run, use rig-browser-launch, rig-browser-check, and rig-browser-attach-info from the worker PATH."]
404
+ { command: "help", description: "Rich browser command help (canonical: `rig browser help`)." },
405
+ { command: "explain", description: "Explain the browser-required task contract." },
406
+ { command: "demo", description: "Run browser demo flows against a local page." },
407
+ { command: "app", description: "Launch the Rig Browser workstation app." },
408
+ { command: "hp-next <dev|check|e2e|reset>", description: "Drive the hp-next browser test harness." }
409
+ ]
445
410
  },
446
411
  {
447
412
  name: "pi",
@@ -456,60 +421,12 @@ var ADVANCED_GROUPS = [
456
421
  examples: ["rig pi search subagents", "rig pi add pi-subagents", "rig pi list"],
457
422
  next: ["Config-managed extensions: declare `runtime: { pi: { packages: [...] } }` in rig.config.ts \u2014 workers pick them up automatically."]
458
423
  },
459
- {
460
- name: "queue",
461
- summary: "Run task queues locally.",
462
- usage: ["rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]"],
463
- commands: [
464
- { command: "run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]", description: "Process queue work: drain matching tasks with N workers, optional per-task action and isolation.", primary: true }
465
- ]
466
- },
467
- {
468
- name: "agent",
469
- summary: "Runtime agent workspace helpers.",
470
- usage: ["rig agent <list|prepare|run|cleanup>"],
471
- commands: [
472
- { command: "list", description: "List prepared agent runtimes.", primary: true },
473
- { command: "prepare [--id <id>] [--mode <mode>] [--task <task>]", description: "Prepare an isolated agent runtime workspace.", primary: true },
474
- { command: "run [--id <id>] [--mode <mode>] [--task <task>] [--skip-project-sync]", description: "Prepare (if needed) and run an agent in its workspace.", primary: true },
475
- { command: "cleanup [--all] [--id <id>]", description: "Remove prepared agent workspaces.", primary: true }
476
- ]
477
- },
424
+ { name: "queue", summary: "Run task queues locally.", usage: ["rig queue run [options]"], commands: [{ command: "run", description: "Process queue work." }] },
425
+ { name: "agent", summary: "Runtime agent workspace helpers.", usage: ["rig agent <list|prepare|run|cleanup>"], commands: [{ command: "list", description: "List prepared agents." }] },
478
426
  { name: "inspector", summary: "Event stream and drift scanners.", usage: ["rig inspector <stream|scan-upstream-drift>"], commands: [{ command: "stream", description: "Stream events." }] },
479
- {
480
- name: "dist",
481
- summary: "Build/install packaged Rig CLI.",
482
- usage: ["rig dist <build|install|doctor|rebuild-agent>"],
483
- commands: [
484
- { command: "build [--output-dir <dir>]", description: "Build the distributable Rig CLI.", primary: true },
485
- { command: "install [--scope <scope>] [--path <path>]", description: "Install the built CLI to a scope/path.", primary: true },
486
- { command: "doctor", description: "Diagnose the dist toolchain and install state.", primary: true },
487
- { command: "rebuild-agent", description: "Rebuild the agent runtime image, pruning stale images.", primary: true }
488
- ]
489
- },
427
+ { name: "dist", summary: "Build/install packaged Rig CLI.", usage: ["rig dist <build|install|doctor>"], commands: [{ command: "build", description: "Build distribution." }] },
490
428
  { name: "workspace", summary: "Workspace topology/service helpers.", usage: ["rig workspace <summary|topology|remote-hosts>"], commands: [{ command: "summary", description: "Show workspace summary." }] },
491
- {
492
- name: "remote",
493
- summary: "Compatibility remote orchestration controls.",
494
- usage: ["rig remote <status|tasks|watch|pause|resume|continue|stop|refresh|add-iterations|remove-iterations|endpoint ...>"],
495
- commands: [
496
- { command: "status [--remote <alias>]", description: "Show the remote orchestration state.", primary: true },
497
- { command: "tasks [--remote <alias>]", description: "List the remote's tracked tasks.", primary: true },
498
- { command: "watch [--remote <alias>] [--seconds <n>] [--event <type>]", description: "Stream remote orchestration events.", primary: true },
499
- { command: "pause [--remote <alias>]", description: "Pause the running remote orchestration.", primary: true },
500
- { command: "resume [--remote <alias>] [--max-workers <n>] [--max-iterations <n>] [--direct-merge]", description: "Resume the remote with optional tuning.", primary: true },
501
- { command: "continue [--remote <alias>]", description: "Continue a paused remote orchestration.", primary: true },
502
- { command: "stop [--remote <alias>]", description: "Stop the remote orchestration.", primary: true },
503
- { command: "refresh [--remote <alias>]", description: "Refresh remote state.", primary: true },
504
- { command: "add-iterations [--count <n>] [--remote <alias>]", description: "Grant the remote more iterations.", primary: true },
505
- { command: "remove-iterations [--count <n>] [--remote <alias>]", description: "Reduce the remote's iteration budget.", primary: true },
506
- { command: "endpoint list", description: "List configured remote endpoints.", primary: true },
507
- { command: "endpoint add --alias <alias> --host <host> --port <n> [--token <token>]", description: "Register a remote endpoint.", primary: true },
508
- { command: "endpoint remove --alias <alias>", description: "Remove a remote endpoint.", primary: true },
509
- { command: "endpoint test [--alias <alias>]", description: "Test connectivity to a remote endpoint.", primary: true },
510
- { command: "endpoint doctor", description: "Diagnose remote endpoint configuration.", primary: true }
511
- ]
512
- },
429
+ { name: "remote", summary: "Compatibility remote orchestration controls.", usage: ["rig remote <status|watch|pause|resume|...>"], commands: [{ command: "status", description: "Show remote state." }] },
513
430
  { name: "git", summary: "Pass through to Rig git-flow helper.", usage: ["rig git <args...>"], commands: [{ command: "<args...>", description: "Advanced git flow operations." }] },
514
431
  { name: "harness", summary: "Pass through to runtime harness CLI.", usage: ["rig harness <args...>"], commands: [{ command: "<args...>", description: "Advanced harness operations." }] },
515
432
  { name: "test", summary: "Project test wrappers.", usage: ["rig test <unit|e2e|all>"], commands: [{ command: "all", description: "Run configured project tests." }] }
@@ -517,8 +434,8 @@ var ADVANCED_GROUPS = [
517
434
  var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
518
435
 
519
436
  // packages/cli/src/commands/_server-client.ts
520
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
521
- import { dirname as dirname2, isAbsolute, resolve as resolve2 } from "path";
437
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
438
+ import { resolve as resolve2 } from "path";
522
439
 
523
440
  // packages/cli/src/runner.ts
524
441
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -610,28 +527,12 @@ function readRepoConnection(projectRoot) {
610
527
  selected,
611
528
  project: typeof record.project === "string" ? record.project : undefined,
612
529
  linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
613
- serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined,
614
- serverProjectRootAlias: typeof record.serverProjectRootAlias === "string" && record.serverProjectRootAlias.trim() ? record.serverProjectRootAlias.trim() : undefined,
615
- serverProjectRootBaseUrl: typeof record.serverProjectRootBaseUrl === "string" && record.serverProjectRootBaseUrl.trim() ? record.serverProjectRootBaseUrl.trim().replace(/\/+$/, "") : undefined
530
+ serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
616
531
  };
617
532
  }
618
533
  function writeRepoConnection(projectRoot, state) {
619
534
  writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
620
535
  }
621
- function rootAllowedForSelection(repo, connection) {
622
- const root = repo.serverProjectRoot?.trim();
623
- if (!root)
624
- return;
625
- if (connection.kind === "remote") {
626
- if (repo.serverProjectRootAlias !== repo.selected)
627
- return;
628
- if (repo.serverProjectRootBaseUrl !== connection.baseUrl)
629
- return;
630
- } else if (repo.serverProjectRootAlias && repo.serverProjectRootAlias !== repo.selected) {
631
- return;
632
- }
633
- return root;
634
- }
635
536
  function resolveSelectedConnection(projectRoot, options = {}) {
636
537
  const repo = readRepoConnection(projectRoot);
637
538
  if (!repo)
@@ -643,41 +544,13 @@ function resolveSelectedConnection(projectRoot, options = {}) {
643
544
  if (!connection) {
644
545
  throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
645
546
  }
646
- return { alias: repo.selected, connection, serverProjectRoot: rootAllowedForSelection(repo, connection) };
647
- }
648
- function writeRepoServerProjectRoot(projectRoot, serverProjectRoot, metadata = {}) {
649
- const repo = readRepoConnection(projectRoot);
650
- if (!repo)
651
- return;
652
- let inferred = metadata;
653
- if (!inferred.alias || !inferred.baseUrl) {
654
- try {
655
- const selected = resolveSelectedConnection(projectRoot);
656
- if (selected?.connection.kind === "remote") {
657
- inferred = {
658
- alias: inferred.alias ?? selected.alias,
659
- baseUrl: inferred.baseUrl ?? selected.connection.baseUrl
660
- };
661
- }
662
- } catch {}
663
- }
664
- writeRepoConnection(projectRoot, {
665
- ...repo,
666
- ...metadata.project ? { project: metadata.project } : {},
667
- serverProjectRoot,
668
- ...inferred.alias ? { serverProjectRootAlias: inferred.alias } : {},
669
- ...inferred.baseUrl ? { serverProjectRootBaseUrl: inferred.baseUrl.replace(/\/+$/, "") } : {}
670
- });
547
+ return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
671
548
  }
672
- function clearRepoServerProjectRoot(projectRoot) {
549
+ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
673
550
  const repo = readRepoConnection(projectRoot);
674
551
  if (!repo)
675
552
  return;
676
- writeRepoConnection(projectRoot, {
677
- selected: repo.selected,
678
- ...repo.project ? { project: repo.project } : {},
679
- ...repo.linkedAt ? { linkedAt: repo.linkedAt } : {}
680
- });
553
+ writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
681
554
  }
682
555
 
683
556
  // packages/cli/src/commands/_server-client.ts
@@ -690,21 +563,17 @@ function cleanToken(value) {
690
563
  const trimmed = value?.trim();
691
564
  return trimmed ? trimmed : null;
692
565
  }
693
- function readRemoteAuthState(projectRoot) {
566
+ function readPrivateRemoteSessionToken(projectRoot) {
694
567
  const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
695
568
  if (!existsSync2(path))
696
569
  return null;
697
570
  try {
698
571
  const parsed = JSON.parse(readFileSync2(path, "utf8"));
699
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
572
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
700
573
  } catch {
701
574
  return null;
702
575
  }
703
576
  }
704
- function readPrivateRemoteSessionToken(projectRoot) {
705
- const parsed = readRemoteAuthState(projectRoot);
706
- return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
707
- }
708
577
  function readGitHubBearerTokenForRemote(projectRoot) {
709
578
  const scopedKey = resolve2(projectRoot);
710
579
  if (scopedGitHubBearerTokens.has(scopedKey))
@@ -715,415 +584,18 @@ function readGitHubBearerTokenForRemote(projectRoot) {
715
584
  return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
716
585
  }
717
586
  function readStoredGitHubAuthToken(projectRoot) {
718
- const parsed = readRemoteAuthState(projectRoot);
719
- return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
720
- }
721
- function inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug) {
722
- if (!/^[^/]+\/[^/]+$/.test(repoSlug))
723
- return null;
724
- const repo = readRepoConnection(projectRoot);
725
- const auth = readRemoteAuthState(projectRoot);
726
- const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
727
- const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
728
- if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
729
- return null;
730
- const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
731
- if (!checkoutBaseDir)
732
- return null;
733
- return `${checkoutBaseDir.replace(/\/+$/, "")}/${repoSlug}`;
734
- }
735
- function readLocalConnectionFallbackToken(projectRoot) {
736
- return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
737
- }
738
- function normalizeRepoSlug(value) {
739
- const slug = value?.trim();
740
- return slug && /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
741
- }
742
- function readProjectLinkSlug(projectRoot) {
743
- const path = resolve2(projectRoot, ".rig", "state", "project-link.json");
587
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
744
588
  if (!existsSync2(path))
745
589
  return null;
746
590
  try {
747
591
  const parsed = JSON.parse(readFileSync2(path, "utf8"));
748
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
749
- return null;
750
- return normalizeRepoSlug(typeof parsed.repoSlug === "string" ? String(parsed.repoSlug) : null);
592
+ return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
751
593
  } catch {
752
594
  return null;
753
595
  }
754
596
  }
755
- function writeProjectLinkConnection(projectRoot, repoSlug, alias) {
756
- const path = resolve2(projectRoot, ".rig", "state", "project-link.json");
757
- mkdirSync2(dirname2(path), { recursive: true });
758
- writeFileSync2(path, `${JSON.stringify({ repoSlug, connection: alias, linkedAt: new Date().toISOString() }, null, 2)}
759
- `, "utf8");
760
- }
761
- function remoteLinkRepairCommand(repoSlug) {
762
- return repoSlug ? `rig server repair-link --repo ${repoSlug}` : "rig server repair-link --repo owner/repo";
763
- }
764
- function formatRemoteProjectLinkHint(resolution) {
765
- const repair = remoteLinkRepairCommand(resolution.repoSlug);
766
- if (resolution.status === "auth_required") {
767
- return `Authenticate the selected remote${resolution.alias ? ` (${resolution.alias})` : ""}, then run \`${repair}\`. Use \`rig github auth import-gh\` or \`rig init --repair --server remote --github-auth device${resolution.repoSlug ? ` --repo ${resolution.repoSlug}` : ""}\`.`;
768
- }
769
- if (resolution.status === "missing_project") {
770
- return `Record the repo slug, then run \`${repair}\` (or \`rig init --repo owner/repo --server remote --github-auth device\`).`;
771
- }
772
- if (resolution.status === "not_remote")
773
- return "Select a remote server with `rig server use <alias>` before repairing a remote project link.";
774
- return `Run \`${repair}\` to backfill or prepare a server-host checkout for the selected remote${resolution.alias ? ` (${resolution.alias})` : ""}.`;
775
- }
776
- function remoteProjectLinkFailure(input) {
777
- const partial = {
778
- status: input.status,
779
- alias: input.alias,
780
- baseUrl: input.baseUrl,
781
- repoSlug: input.repoSlug
782
- };
783
- return {
784
- ok: false,
785
- ...input,
786
- hint: formatRemoteProjectLinkHint(partial),
787
- next: remoteLinkRepairCommand(input.repoSlug)
788
- };
789
- }
790
- function remoteProjectLinkSuccess(input) {
791
- return {
792
- ok: true,
793
- status: input.status,
794
- alias: input.alias,
795
- baseUrl: input.baseUrl,
796
- repoSlug: input.repoSlug,
797
- serverProjectRoot: input.serverProjectRoot,
798
- source: input.source,
799
- prepared: input.prepared ?? input.status === "prepared",
800
- validated: input.validated ?? false,
801
- message: input.message ?? `Remote project link ready for ${input.repoSlug}.`,
802
- hint: "Remote-scoped task/run/status requests will send x-rig-project-root for this server-host checkout.",
803
- next: "rig task list"
804
- };
805
- }
806
- function localCheckoutPathCandidate(projectRoot, candidate) {
807
- try {
808
- const local = resolve2(projectRoot);
809
- const resolved = resolve2(candidate);
810
- return resolved === local || resolved.startsWith(`${local}/`);
811
- } catch {
812
- return false;
813
- }
814
- }
815
- async function requestRemoteProjectLinkJson(baseUrl, pathname, authToken, init = {}) {
816
- const requestUrl = new URL(`${baseUrl}${pathname}`);
817
- if (authToken && queryAuthFallbackEnabled())
818
- requestUrl.searchParams.set("rt", authToken);
819
- const response = await fetch(requestUrl, {
820
- ...init,
821
- headers: mergeHeaders(init.headers, authToken)
822
- });
823
- const text = await response.text();
824
- const payload = text.trim().length > 0 ? (() => {
825
- try {
826
- return JSON.parse(text);
827
- } catch {
828
- return null;
829
- }
830
- })() : null;
831
- return { ok: response.ok, status: response.status, payload, text };
832
- }
833
- function payloadError(payload, fallback) {
834
- if (payload && typeof payload === "object" && !Array.isArray(payload)) {
835
- const record = payload;
836
- const value = record.error ?? record.message ?? record.reason;
837
- if (typeof value === "string" && value.trim())
838
- return value.trim();
839
- }
840
- return fallback;
841
- }
842
- function checkoutPathsFromProjectPayload(payload) {
843
- if (!payload || typeof payload !== "object" || Array.isArray(payload))
844
- return [];
845
- const project = payload.project;
846
- if (!project || typeof project !== "object" || Array.isArray(project))
847
- return [];
848
- const checkouts = project.checkouts;
849
- if (!Array.isArray(checkouts))
850
- return [];
851
- return [...checkouts].reverse().flatMap((entry) => {
852
- if (!entry || typeof entry !== "object" || Array.isArray(entry))
853
- return [];
854
- const path = entry.path;
855
- return typeof path === "string" && path.trim() ? [path.trim()] : [];
856
- });
857
- }
858
- function checkoutPathFromPreparePayload(payload) {
859
- if (!payload || typeof payload !== "object" || Array.isArray(payload))
860
- return null;
861
- const checkout = payload.checkout;
862
- if (!checkout || typeof checkout !== "object" || Array.isArray(checkout))
863
- return null;
864
- const path = checkout.path;
865
- return typeof path === "string" && path.trim() ? path.trim() : null;
866
- }
867
- async function validateAndPersistRemoteRoot(input) {
868
- const candidate = input.candidate.trim();
869
- if (!candidate || !isAbsolute(candidate)) {
870
- return remoteProjectLinkFailure({
871
- status: "invalid_root",
872
- alias: input.alias,
873
- baseUrl: input.baseUrl,
874
- repoSlug: input.repoSlug,
875
- message: `Remote project root candidate is not an absolute server-host path: ${candidate || "(empty)"}.`
876
- });
877
- }
878
- if (localCheckoutPathCandidate(input.projectRoot, candidate)) {
879
- return remoteProjectLinkFailure({
880
- status: "invalid_root",
881
- alias: input.alias,
882
- baseUrl: input.baseUrl,
883
- repoSlug: input.repoSlug,
884
- message: `Refusing to use local checkout path ${candidate} as a remote server project root.`
885
- });
886
- }
887
- let response;
888
- try {
889
- response = await requestRemoteProjectLinkJson(input.baseUrl, "/api/server/project-root", input.authToken, {
890
- method: "POST",
891
- headers: { "content-type": "application/json" },
892
- body: JSON.stringify({ projectRoot: candidate })
893
- });
894
- } catch (error) {
895
- return remoteProjectLinkFailure({
896
- status: "error",
897
- alias: input.alias,
898
- baseUrl: input.baseUrl,
899
- repoSlug: input.repoSlug,
900
- message: `Could not validate remote project root ${candidate}: ${error instanceof Error ? error.message : String(error)}`
901
- });
902
- }
903
- if (response.status === 401 || response.status === 403) {
904
- return remoteProjectLinkFailure({
905
- status: "auth_required",
906
- alias: input.alias,
907
- baseUrl: input.baseUrl,
908
- repoSlug: input.repoSlug,
909
- statusCode: response.status,
910
- message: `Remote server ${input.alias} requires authentication before validating project root ${candidate}.`
911
- });
912
- }
913
- if (!response.ok) {
914
- return remoteProjectLinkFailure({
915
- status: "invalid_root",
916
- alias: input.alias,
917
- baseUrl: input.baseUrl,
918
- repoSlug: input.repoSlug,
919
- statusCode: response.status,
920
- message: `Remote server rejected project root ${candidate} (${response.status}): ${payloadError(response.payload, response.text || "project-root validation failed")}`
921
- });
922
- }
923
- const record = response.payload && typeof response.payload === "object" && !Array.isArray(response.payload) ? response.payload : {};
924
- if (record.ok !== true) {
925
- return remoteProjectLinkFailure({
926
- status: "invalid_root",
927
- alias: input.alias,
928
- baseUrl: input.baseUrl,
929
- repoSlug: input.repoSlug,
930
- message: `Remote server did not accept project root ${candidate}: ${payloadError(response.payload, "project-root validation failed")}`
931
- });
932
- }
933
- const accepted = typeof record.projectRoot === "string" && record.projectRoot.trim() ? record.projectRoot.trim() : typeof record.requestedProjectRoot === "string" && record.requestedProjectRoot.trim() ? record.requestedProjectRoot.trim() : candidate;
934
- writeRepoServerProjectRoot(input.projectRoot, accepted, { alias: input.alias, baseUrl: input.baseUrl, project: input.repoSlug });
935
- writeProjectLinkConnection(input.projectRoot, input.repoSlug, input.alias);
936
- const status = input.status ?? (input.prepared ? "prepared" : "backfilled");
937
- return remoteProjectLinkSuccess({
938
- status,
939
- alias: input.alias,
940
- baseUrl: input.baseUrl,
941
- repoSlug: input.repoSlug,
942
- serverProjectRoot: accepted,
943
- source: input.source,
944
- prepared: input.prepared,
945
- validated: true,
946
- message: status === "ready" ? `Remote project link already points to ${accepted} and was validated on ${input.alias}.` : input.prepared ? `Prepared and linked remote checkout ${accepted} for ${input.repoSlug}.` : `Backfilled remote checkout ${accepted} for ${input.repoSlug}.`
947
- });
948
- }
949
- async function ensureRemoteProjectRootLink(projectRoot, options = {}) {
950
- let selected;
951
- try {
952
- selected = resolveSelectedConnection(projectRoot);
953
- } catch (error) {
954
- return remoteProjectLinkFailure({ status: "error", message: error instanceof Error ? error.message : String(error) });
955
- }
956
- if (!selected || selected.connection.kind !== "remote") {
957
- return remoteProjectLinkFailure({ status: "not_remote", message: "No remote Rig server is selected for this repo." });
958
- }
959
- const repo = readRepoConnection(projectRoot);
960
- const explicitRepoRequested = options.repoSlug !== undefined;
961
- const explicitRepoSlug = explicitRepoRequested ? normalizeRepoSlug(options.repoSlug) : null;
962
- const repoProjectSlug = normalizeRepoSlug(repo?.project);
963
- const repoSlug = explicitRepoSlug ?? repoProjectSlug ?? readProjectLinkSlug(projectRoot);
964
- const alias = selected.alias;
965
- const baseUrl = selected.connection.baseUrl;
966
- const authToken = options.authToken === undefined ? readGitHubBearerTokenForRemote(projectRoot) : options.authToken;
967
- const mode = options.mode ?? "backfill-only";
968
- if (explicitRepoRequested && !explicitRepoSlug) {
969
- return remoteProjectLinkFailure({
970
- status: "missing_project",
971
- alias,
972
- baseUrl,
973
- message: `Invalid --repo value ${JSON.stringify(options.repoSlug)}. Expected owner/repo.`
974
- });
975
- }
976
- if (!repoSlug) {
977
- return remoteProjectLinkFailure({
978
- status: "missing_project",
979
- alias,
980
- baseUrl,
981
- message: `Remote server ${alias} is selected, but this checkout has no GitHub repo slug recorded.`
982
- });
983
- }
984
- const skippedCandidates = [];
985
- const storedRoot = selected.serverProjectRoot?.trim() || null;
986
- const storedRootMatchesResolvedRepo = repoProjectSlug === repoSlug;
987
- if (storedRoot && storedRootMatchesResolvedRepo) {
988
- if (localCheckoutPathCandidate(projectRoot, storedRoot)) {
989
- clearRepoServerProjectRoot(projectRoot);
990
- skippedCandidates.push(storedRoot);
991
- } else {
992
- const storedResult = await validateAndPersistRemoteRoot({
993
- projectRoot,
994
- alias,
995
- baseUrl,
996
- authToken,
997
- repoSlug,
998
- candidate: storedRoot,
999
- source: "stored",
1000
- status: "ready"
1001
- });
1002
- if (storedResult.ok || storedResult.status === "auth_required" || storedResult.status === "error")
1003
- return storedResult;
1004
- clearRepoServerProjectRoot(projectRoot);
1005
- skippedCandidates.push(storedRoot);
1006
- }
1007
- } else if (storedRoot) {
1008
- skippedCandidates.push(storedRoot);
1009
- }
1010
- const authCandidate = inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug);
1011
- if (authCandidate) {
1012
- const authResult = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: authCandidate, source: "auth-state" });
1013
- if (authResult.ok || authResult.status === "auth_required")
1014
- return authResult;
1015
- }
1016
- let registryResponse;
1017
- try {
1018
- registryResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}`, authToken);
1019
- } catch (error) {
1020
- return remoteProjectLinkFailure({
1021
- status: "error",
1022
- alias,
1023
- baseUrl,
1024
- repoSlug,
1025
- message: `Could not read remote project registry for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
1026
- });
1027
- }
1028
- if (registryResponse.status === 401 || registryResponse.status === 403) {
1029
- return remoteProjectLinkFailure({
1030
- status: "auth_required",
1031
- alias,
1032
- baseUrl,
1033
- repoSlug,
1034
- statusCode: registryResponse.status,
1035
- message: `Remote server ${alias} requires authentication before reading the ${repoSlug} project registry.`
1036
- });
1037
- }
1038
- if (registryResponse.ok) {
1039
- const candidates = checkoutPathsFromProjectPayload(registryResponse.payload);
1040
- for (const candidate of candidates) {
1041
- const result = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate, source: "registry" });
1042
- if (result.ok || result.status === "auth_required")
1043
- return result;
1044
- skippedCandidates.push(candidate);
1045
- }
1046
- if (mode === "backfill-only") {
1047
- return remoteProjectLinkFailure({
1048
- status: candidates.length > 0 ? "invalid_root" : "no_server_checkout",
1049
- alias,
1050
- baseUrl,
1051
- repoSlug,
1052
- message: candidates.length > 0 ? `Remote registry has checkout candidates for ${repoSlug}, but none validated for ${alias}.` : `Remote registry has ${repoSlug}, but no server checkout path is linked yet.`,
1053
- skippedCandidates
1054
- });
1055
- }
1056
- } else if (registryResponse.status === 404) {
1057
- if (mode === "backfill-only") {
1058
- return remoteProjectLinkFailure({
1059
- status: "project_not_registered",
1060
- alias,
1061
- baseUrl,
1062
- repoSlug,
1063
- statusCode: registryResponse.status,
1064
- message: `Remote server ${alias} has no registered project record for ${repoSlug}.`
1065
- });
1066
- }
1067
- } else {
1068
- return remoteProjectLinkFailure({
1069
- status: "error",
1070
- alias,
1071
- baseUrl,
1072
- repoSlug,
1073
- statusCode: registryResponse.status,
1074
- message: `Could not backfill ${repoSlug} from remote registry (${registryResponse.status}): ${payloadError(registryResponse.payload, registryResponse.text || "registry lookup failed")}`,
1075
- skippedCandidates
1076
- });
1077
- }
1078
- let prepareResponse;
1079
- try {
1080
- prepareResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}/prepare-checkout`, authToken, {
1081
- method: "POST",
1082
- headers: { "content-type": "application/json" },
1083
- body: JSON.stringify({ checkout: { kind: "managed-clone" }, repoUrl: `https://github.com/${repoSlug}.git` })
1084
- });
1085
- } catch (error) {
1086
- return remoteProjectLinkFailure({
1087
- status: "error",
1088
- alias,
1089
- baseUrl,
1090
- repoSlug,
1091
- message: `Could not prepare remote checkout for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
1092
- });
1093
- }
1094
- if (prepareResponse.status === 401 || prepareResponse.status === 403) {
1095
- return remoteProjectLinkFailure({
1096
- status: "auth_required",
1097
- alias,
1098
- baseUrl,
1099
- repoSlug,
1100
- statusCode: prepareResponse.status,
1101
- message: `Remote server ${alias} requires authentication before preparing ${repoSlug}.`
1102
- });
1103
- }
1104
- if (!prepareResponse.ok) {
1105
- return remoteProjectLinkFailure({
1106
- status: "error",
1107
- alias,
1108
- baseUrl,
1109
- repoSlug,
1110
- statusCode: prepareResponse.status,
1111
- message: `Remote checkout prepare failed for ${repoSlug} (${prepareResponse.status}): ${payloadError(prepareResponse.payload, prepareResponse.text || "prepare-checkout failed")}`,
1112
- skippedCandidates
1113
- });
1114
- }
1115
- const preparedPath = checkoutPathFromPreparePayload(prepareResponse.payload);
1116
- if (!preparedPath) {
1117
- return remoteProjectLinkFailure({
1118
- status: "invalid_root",
1119
- alias,
1120
- baseUrl,
1121
- repoSlug,
1122
- message: `Remote checkout prepare for ${repoSlug} did not return a checkout.path.`,
1123
- skippedCandidates
1124
- });
1125
- }
1126
- return validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: preparedPath, source: "prepare", prepared: true });
597
+ function readLocalConnectionFallbackToken(projectRoot) {
598
+ return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
1127
599
  }
1128
600
  async function ensureServerForCli(projectRoot) {
1129
601
  try {
@@ -1131,12 +603,12 @@ async function ensureServerForCli(projectRoot) {
1131
603
  if (selected?.connection.kind === "remote") {
1132
604
  reportServerPhase(`Connecting to ${selected.alias}\u2026`);
1133
605
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
1134
- const link = await ensureRemoteProjectRootLink(projectRoot, { mode: "backfill-only", authToken });
606
+ const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
1135
607
  return {
1136
608
  baseUrl: selected.connection.baseUrl,
1137
609
  authToken,
1138
610
  connectionKind: "remote",
1139
- serverProjectRoot: link.ok ? link.serverProjectRoot ?? null : null
611
+ serverProjectRoot
1140
612
  };
1141
613
  }
1142
614
  reportServerPhase("Starting local Rig server\u2026");
@@ -1154,6 +626,29 @@ async function ensureServerForCli(projectRoot) {
1154
626
  throw error;
1155
627
  }
1156
628
  }
629
+ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
630
+ const repo = readRepoConnection(projectRoot);
631
+ const slug = repo?.project?.trim();
632
+ if (!slug)
633
+ return null;
634
+ try {
635
+ const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
636
+ headers: mergeHeaders(undefined, authToken)
637
+ });
638
+ if (!response.ok)
639
+ return null;
640
+ const payload = await response.json();
641
+ const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
642
+ const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
643
+ const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
644
+ const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
645
+ if (path)
646
+ writeRepoServerProjectRoot(projectRoot, path);
647
+ return path;
648
+ } catch {
649
+ return null;
650
+ }
651
+ }
1157
652
  function appendTaskFilterParams(url, filters) {
1158
653
  if (filters.assignee)
1159
654
  url.searchParams.set("assignee", filters.assignee);
@@ -1164,23 +659,10 @@ function appendTaskFilterParams(url, filters) {
1164
659
  if (filters.limit !== undefined)
1165
660
  url.searchParams.set("limit", String(filters.limit));
1166
661
  }
1167
- function mergeCookie(existing, name, value) {
1168
- const encoded = `${name}=${encodeURIComponent(value)}`;
1169
- if (!existing?.trim())
1170
- return encoded;
1171
- const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
1172
- return [...parts, encoded].join("; ");
1173
- }
1174
- function queryAuthFallbackEnabled(env = process.env) {
1175
- return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
1176
- }
1177
662
  function mergeHeaders(headers, authToken) {
1178
663
  const merged = new Headers(headers);
1179
664
  if (authToken) {
1180
- const bearer = `Bearer ${authToken}`;
1181
- merged.set("authorization", bearer);
1182
- merged.set("x-auth", bearer);
1183
- merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
665
+ merged.set("authorization", `Bearer ${authToken}`);
1184
666
  }
1185
667
  return merged;
1186
668
  }
@@ -1241,41 +723,15 @@ async function buildServerFailureContext(projectRoot, server) {
1241
723
  hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
1242
724
  };
1243
725
  }
1244
- function isLoopbackRemoteBaseUrl(baseUrl) {
1245
- try {
1246
- const host = new URL(baseUrl).hostname.toLowerCase();
1247
- return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
1248
- } catch {
1249
- return false;
1250
- }
1251
- }
1252
- function canUseRemoteWithoutProjectRoot(pathname) {
1253
- return pathname === "/health" || pathname === "/api/health" || pathname === "/api/server/status" || pathname === "/api/server/project-root" || pathname.startsWith("/api/github/auth/") || pathname === "/api/projects" || pathname.startsWith("/api/projects/");
1254
- }
1255
726
  async function requestServerJson(context, pathname, init = {}) {
1256
727
  const server = await ensureServerForCli(context.projectRoot);
1257
- const requestUrl = new URL(`${server.baseUrl}${pathname}`);
1258
- let scopedServerProjectRoot = server.serverProjectRoot;
1259
- if (server.connectionKind === "remote" && !scopedServerProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
1260
- const link = await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only", authToken: server.authToken });
1261
- if (link.ok && link.serverProjectRoot) {
1262
- scopedServerProjectRoot = link.serverProjectRoot;
1263
- } else {
1264
- const repo = readRepoConnection(context.projectRoot);
1265
- const target = link.alias && link.baseUrl ? `${link.alias} (${link.baseUrl})` : server.baseUrl;
1266
- throw new CliError(`Remote server ${target} is selected for ${link.repoSlug ?? repo?.project ?? "this repo"}, but this checkout has no server-host project root link. ${link.message}`, 1, { hint: link.hint });
1267
- }
1268
- }
1269
728
  const headers = mergeHeaders(init.headers, server.authToken);
1270
- if (scopedServerProjectRoot)
1271
- headers.set("x-rig-project-root", scopedServerProjectRoot);
1272
- if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
1273
- requestUrl.searchParams.set("rt", server.authToken);
1274
- }
729
+ if (server.serverProjectRoot)
730
+ headers.set("x-rig-project-root", server.serverProjectRoot);
1275
731
  reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
1276
732
  let response;
1277
733
  try {
1278
- response = await fetch(requestUrl, {
734
+ response = await fetch(`${server.baseUrl}${pathname}`, {
1279
735
  ...init,
1280
736
  headers
1281
737
  });
@@ -1395,46 +851,18 @@ import {
1395
851
  import { resolveMonorepoRoot } from "@rig/runtime/control-plane/native/utils";
1396
852
 
1397
853
  // packages/cli/src/commands/_authority-runs.ts
1398
- function normalizeRuntimeAdapter(_value) {
1399
- return "pi";
1400
- }
1401
-
1402
- // packages/cli/src/commands/_server-events.ts
1403
- import { WsTransport } from "@rig/client";
1404
- import { RIG_WS_CHANNELS } from "@rig/contracts";
1405
- function buildRigWebSocketUrl(baseUrl, authToken) {
1406
- const url = new URL(baseUrl);
1407
- url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
1408
- if (authToken)
1409
- url.searchParams.set("token", authToken);
1410
- return url.toString();
1411
- }
1412
- async function connectRigServerEvents(projectRoot, handlers) {
1413
- const { baseUrl, authToken } = await ensureServerForCli(projectRoot);
1414
- const transport = new WsTransport(buildRigWebSocketUrl(baseUrl, authToken));
1415
- const unsubscribers = [];
1416
- if (handlers.onSnapshotInvalidated)
1417
- unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.snapshotInvalidated, handlers.onSnapshotInvalidated));
1418
- if (handlers.onRunLogAppended)
1419
- unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.runLogAppended, handlers.onRunLogAppended));
1420
- if (handlers.onEngineEvent)
1421
- unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.event, handlers.onEngineEvent));
1422
- let status = "connecting";
1423
- unsubscribers.push(transport.subscribeState((state) => {
1424
- status = state.status;
1425
- handlers.onStatus?.(state.status);
1426
- }));
1427
- return {
1428
- connected: () => status === "connected",
1429
- close: () => {
1430
- for (const unsubscribe of unsubscribers) {
1431
- try {
1432
- unsubscribe();
1433
- } catch {}
1434
- }
1435
- transport.dispose();
1436
- }
1437
- };
854
+ function normalizeRuntimeAdapter(value) {
855
+ const normalized = value?.trim().toLowerCase();
856
+ if (!normalized) {
857
+ return "pi";
858
+ }
859
+ if (normalized === "codex" || normalized === "codex-cli" || normalized === "codex-app-server" || normalized === "gpt-codex") {
860
+ return "codex";
861
+ }
862
+ if (normalized === "pi" || normalized === "rig-pi" || normalized === "@rig/pi") {
863
+ return "pi";
864
+ }
865
+ return "claude-code";
1438
866
  }
1439
867
 
1440
868
  // packages/cli/src/app/drone-ui.ts
@@ -1495,10 +923,9 @@ import { ensureProjectMainFreshBeforeRun } from "@rig/runtime/control-plane/proj
1495
923
  // packages/cli/src/commands/_pi-frontend.ts
1496
924
  import { main as runPiMain } from "@earendil-works/pi-coding-agent";
1497
925
  import createPiRigExtension from "@rig/pi-rig";
1498
- var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
1499
926
 
1500
927
  // packages/cli/src/commands/_operator-view.ts
1501
- var TERMINAL_RUN_STATUSES2 = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
928
+ var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
1502
929
 
1503
930
  // packages/cli/src/commands/task.ts
1504
931
  import { buildPluginHostContext } from "@rig/runtime/control-plane/plugin-host-context";
@@ -1524,7 +951,7 @@ async function loadTaskRunProjectDefaults(projectRoot) {
1524
951
 
1525
952
  // packages/cli/src/app/board.ts
1526
953
  var BOARD_REFRESH_MS = 5000;
1527
- var BOARD_TICK_MS = 16;
954
+ var BOARD_TICK_MS = 250;
1528
955
  var BOARD_TASK_PAGE = 20;
1529
956
  function oneLine(message) {
1530
957
  return message.split(`
@@ -1547,7 +974,6 @@ function statusRank(status) {
1547
974
  case "pending":
1548
975
  case "preparing":
1549
976
  case "adopted":
1550
- case "stopping":
1551
977
  return 2;
1552
978
  case "completed":
1553
979
  case "merged":
@@ -1587,10 +1013,6 @@ class RunsList {
1587
1013
  selectedRun() {
1588
1014
  return this.visibleRuns()[this.selected] ?? null;
1589
1015
  }
1590
- patchRun(runId, patch) {
1591
- this.runs = this.runs.map((run) => run.runId === runId ? { ...run, ...patch } : run);
1592
- this.clampSelection();
1593
- }
1594
1016
  cycleSort() {
1595
1017
  this.sortMode = this.sortMode === "active" ? "recent" : this.sortMode === "recent" ? "status" : "active";
1596
1018
  this.clampSelection();
@@ -1813,14 +1235,6 @@ class InboxView {
1813
1235
  selectedItem() {
1814
1236
  return this.items[this.selected] ?? null;
1815
1237
  }
1816
- patchItem(requestId, summary) {
1817
- this.items = this.items.map((item) => item.requestId === requestId ? { ...item, summary } : item);
1818
- }
1819
- removeItem(requestId) {
1820
- const previousIndex = this.selected;
1821
- this.items = this.items.filter((item) => item.requestId !== requestId);
1822
- this.selected = Math.max(0, Math.min(previousIndex, Math.max(0, this.items.length - 1)));
1823
- }
1824
1238
  invalidate() {}
1825
1239
  render(width) {
1826
1240
  return this.renderLines(width).map((line) => truncateToWidth(line, Math.max(10, width - 1)));
@@ -2042,14 +1456,9 @@ async function runOperatorBoard(context, options = {}) {
2042
1456
  tui.stop();
2043
1457
  };
2044
1458
  let refreshInFlight = false;
2045
- const refresh = async (options2 = {}) => {
1459
+ const refresh = async () => {
2046
1460
  if (refreshInFlight)
2047
1461
  return;
2048
- if (!options2.quiet) {
2049
- notice = "refreshing fleet\u2026";
2050
- renderFooter();
2051
- tui.requestRender();
2052
- }
2053
1462
  if (!hasRigProject(context.projectRoot)) {
2054
1463
  list.loading = false;
2055
1464
  list.noProject = true;
@@ -2132,7 +1541,6 @@ async function runOperatorBoard(context, options = {}) {
2132
1541
  };
2133
1542
  const resolveApproval = async (item, decision) => {
2134
1543
  notice = `${decision === "approve" ? "approving" : "rejecting"} ${item.requestId.slice(0, 12)}\u2026`;
2135
- inboxView.patchItem(item.requestId, `${decision === "approve" ? "approving" : "rejecting"}\u2026 ${item.summary}`);
2136
1544
  renderFooter();
2137
1545
  tui.requestRender();
2138
1546
  try {
@@ -2141,10 +1549,8 @@ async function runOperatorBoard(context, options = {}) {
2141
1549
  headers: { "content-type": "application/json" },
2142
1550
  body: JSON.stringify({ runId: item.runId, requestId: item.requestId, decision, note: null })
2143
1551
  });
2144
- inboxView.removeItem(item.requestId);
2145
1552
  notice = `${decision === "approve" ? "approved" : "rejected"} \u2014 drone resumes`;
2146
1553
  } catch (error) {
2147
- inboxView.patchItem(item.requestId, item.summary);
2148
1554
  notice = `resolve failed: ${oneLine(error instanceof Error ? error.message : String(error))}`;
2149
1555
  }
2150
1556
  renderFooter();
@@ -2153,7 +1559,6 @@ async function runOperatorBoard(context, options = {}) {
2153
1559
  };
2154
1560
  const answerInput = async (item, text) => {
2155
1561
  notice = `answering ${item.requestId.slice(0, 12)}\u2026`;
2156
- inboxView.patchItem(item.requestId, `answering\u2026 ${item.summary}`);
2157
1562
  renderFooter();
2158
1563
  tui.requestRender();
2159
1564
  try {
@@ -2166,10 +1571,8 @@ async function runOperatorBoard(context, options = {}) {
2166
1571
  answers: { [item.questionId ?? "response"]: text }
2167
1572
  })
2168
1573
  });
2169
- inboxView.removeItem(item.requestId);
2170
1574
  notice = "answer sent \u2014 drone resumes";
2171
1575
  } catch (error) {
2172
- inboxView.patchItem(item.requestId, item.summary);
2173
1576
  notice = `answer failed: ${oneLine(error instanceof Error ? error.message : String(error))}`;
2174
1577
  }
2175
1578
  renderFooter();
@@ -2318,7 +1721,6 @@ async function runOperatorBoard(context, options = {}) {
2318
1721
  const run = list.selectedRun();
2319
1722
  if (run) {
2320
1723
  notice = `stop requested for ${run.runId.slice(0, 8)}\u2026`;
2321
- list.patchRun(run.runId, { status: "stopping" });
2322
1724
  renderFooter();
2323
1725
  tui.requestRender();
2324
1726
  stopRunViaServer(context, run.runId).then(() => refresh()).catch(() => refresh());
@@ -2326,9 +1728,6 @@ async function runOperatorBoard(context, options = {}) {
2326
1728
  return { consume: true };
2327
1729
  }
2328
1730
  if (data === "r") {
2329
- notice = "refreshing fleet\u2026";
2330
- renderFooter();
2331
- tui.requestRender();
2332
1731
  refresh();
2333
1732
  return { consume: true };
2334
1733
  }
@@ -2354,28 +1753,11 @@ async function runOperatorBoard(context, options = {}) {
2354
1753
  tui.requestRender();
2355
1754
  }
2356
1755
  }, BOARD_TICK_MS);
2357
- const live = { subscription: null };
2358
- const refreshActiveView = () => {
2359
- refresh({ quiet: true });
2360
- if (view === "tasks")
2361
- refreshTasks();
2362
- if (view === "inbox")
2363
- refreshInbox();
2364
- };
2365
- connectRigServerEvents(context.projectRoot, {
2366
- onSnapshotInvalidated: () => refreshActiveView()
2367
- }).then((subscription) => {
2368
- live.subscription = subscription;
2369
- }).catch(() => {
2370
- live.subscription = null;
2371
- });
2372
1756
  const refreshTimer = setInterval(() => {
2373
- if (live.subscription?.connected())
2374
- return;
2375
1757
  refresh();
2376
1758
  }, BOARD_REFRESH_MS);
2377
1759
  tui.start();
2378
- refresh({ quiet: true });
1760
+ refresh();
2379
1761
  await new Promise((resolve3) => {
2380
1762
  const poll = setInterval(() => {
2381
1763
  if (stopped) {
@@ -2386,7 +1768,6 @@ async function runOperatorBoard(context, options = {}) {
2386
1768
  });
2387
1769
  clearInterval(animation);
2388
1770
  clearInterval(refreshTimer);
2389
- live.subscription?.close();
2390
1771
  return outcome;
2391
1772
  }
2392
1773
  async function runOperatorBoardLoop(context, attach, options = {}) {