@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.
- package/dist/bin/build-rig-binaries.js +8 -40
- package/dist/bin/rig.js +12519 -26675
- package/dist/src/app/board.js +74 -693
- package/dist/src/app/drone-ui.js +1 -1
- package/dist/src/app/theme.js +0 -1
- package/dist/src/commands/_async-ui.js +1 -1
- package/dist/src/commands/_authority-runs.d.ts +1 -1
- package/dist/src/commands/_authority-runs.js +12 -2
- package/dist/src/commands/_cli-format.d.ts +1 -10
- package/dist/src/commands/_cli-format.js +2 -5
- package/dist/src/commands/_connection-state.d.ts +1 -11
- package/dist/src/commands/_connection-state.js +5 -50
- package/dist/src/commands/_doctor-checks.js +40 -501
- package/dist/src/commands/_help-catalog.js +17 -99
- package/dist/src/commands/_json-output.js +0 -4
- package/dist/src/commands/_operator-view.js +54 -575
- package/dist/src/commands/_pi-frontend.d.ts +0 -27
- package/dist/src/commands/_pi-frontend.js +52 -576
- package/dist/src/commands/_preflight.js +66 -553
- package/dist/src/commands/_server-client.d.ts +0 -33
- package/dist/src/commands/_server-client.js +46 -541
- package/dist/src/commands/_snapshot-upload.js +42 -503
- package/dist/src/commands/_spinner.js +1 -1
- package/dist/src/commands/agent.js +12 -2
- package/dist/src/commands/browser.js +1 -1
- package/dist/src/commands/connect.js +15 -626
- package/dist/src/commands/doctor.js +41 -502
- package/dist/src/commands/github.js +51 -584
- package/dist/src/commands/inbox.js +41 -502
- package/dist/src/commands/init.js +74 -561
- package/dist/src/commands/inspect.js +41 -502
- package/dist/src/commands/run.js +54 -578
- package/dist/src/commands/server.js +163 -692
- package/dist/src/commands/setup.js +46 -507
- package/dist/src/commands/stats.js +58 -601
- package/dist/src/commands/task-run-driver.js +58 -509
- package/dist/src/commands/task.js +110 -729
- package/dist/src/commands.js +237 -1112
- package/dist/src/index.js +244 -1123
- package/dist/src/launcher.js +0 -4
- package/package.json +9 -13
- package/dist/src/app-opentui/adapters/command.d.ts +0 -2
- package/dist/src/app-opentui/adapters/command.js +0 -329
- package/dist/src/app-opentui/adapters/common.d.ts +0 -56
- package/dist/src/app-opentui/adapters/common.js +0 -153
- package/dist/src/app-opentui/adapters/doctor.d.ts +0 -9
- package/dist/src/app-opentui/adapters/doctor.js +0 -1217
- package/dist/src/app-opentui/adapters/family.d.ts +0 -62
- package/dist/src/app-opentui/adapters/family.js +0 -14855
- package/dist/src/app-opentui/adapters/fleet.d.ts +0 -14
- package/dist/src/app-opentui/adapters/fleet.js +0 -1335
- package/dist/src/app-opentui/adapters/inbox.d.ts +0 -43
- package/dist/src/app-opentui/adapters/inbox.js +0 -1944
- package/dist/src/app-opentui/adapters/init.d.ts +0 -11
- package/dist/src/app-opentui/adapters/init.js +0 -2818
- package/dist/src/app-opentui/adapters/inspect.d.ts +0 -52
- package/dist/src/app-opentui/adapters/inspect.js +0 -1455
- package/dist/src/app-opentui/adapters/pi-attach.d.ts +0 -32
- package/dist/src/app-opentui/adapters/pi-attach.js +0 -2101
- package/dist/src/app-opentui/adapters/pi.d.ts +0 -23
- package/dist/src/app-opentui/adapters/pi.js +0 -363
- package/dist/src/app-opentui/adapters/plugin.d.ts +0 -84
- package/dist/src/app-opentui/adapters/plugin.js +0 -544
- package/dist/src/app-opentui/adapters/repo.d.ts +0 -37
- package/dist/src/app-opentui/adapters/repo.js +0 -186
- package/dist/src/app-opentui/adapters/run-detail.d.ts +0 -27
- package/dist/src/app-opentui/adapters/run-detail.js +0 -1441
- package/dist/src/app-opentui/adapters/server.d.ts +0 -48
- package/dist/src/app-opentui/adapters/server.js +0 -1561
- package/dist/src/app-opentui/adapters/tasks.d.ts +0 -64
- package/dist/src/app-opentui/adapters/tasks.js +0 -4524
- package/dist/src/app-opentui/adapters/workspace.d.ts +0 -49
- package/dist/src/app-opentui/adapters/workspace.js +0 -333
- package/dist/src/app-opentui/autocomplete.d.ts +0 -20
- package/dist/src/app-opentui/autocomplete.js +0 -578
- package/dist/src/app-opentui/bootstrap.d.ts +0 -11
- package/dist/src/app-opentui/bootstrap.js +0 -27833
- package/dist/src/app-opentui/command-palette.d.ts +0 -3
- package/dist/src/app-opentui/command-palette.js +0 -1038
- package/dist/src/app-opentui/command-pty-host.d.ts +0 -62
- package/dist/src/app-opentui/command-pty-host.js +0 -248
- package/dist/src/app-opentui/drone.d.ts +0 -12
- package/dist/src/app-opentui/drone.js +0 -230
- package/dist/src/app-opentui/events.d.ts +0 -7
- package/dist/src/app-opentui/events.js +0 -28
- package/dist/src/app-opentui/fleet-stats.d.ts +0 -32
- package/dist/src/app-opentui/fleet-stats.js +0 -114
- package/dist/src/app-opentui/focus-manager.d.ts +0 -14
- package/dist/src/app-opentui/focus-manager.js +0 -24
- package/dist/src/app-opentui/index.d.ts +0 -8
- package/dist/src/app-opentui/index.js +0 -5260
- package/dist/src/app-opentui/intent.d.ts +0 -3
- package/dist/src/app-opentui/intent.js +0 -365
- package/dist/src/app-opentui/keymap.d.ts +0 -21
- package/dist/src/app-opentui/keymap.js +0 -1377
- package/dist/src/app-opentui/launch-routing.d.ts +0 -16
- package/dist/src/app-opentui/launch-routing.js +0 -55
- package/dist/src/app-opentui/layout.d.ts +0 -22
- package/dist/src/app-opentui/layout.js +0 -51
- package/dist/src/app-opentui/list-search.d.ts +0 -36
- package/dist/src/app-opentui/list-search.js +0 -130
- package/dist/src/app-opentui/pi-host-child.d.ts +0 -2
- package/dist/src/app-opentui/pi-host-child.js +0 -1299
- package/dist/src/app-opentui/pi-pty-host.d.ts +0 -28
- package/dist/src/app-opentui/pi-pty-host.js +0 -10
- package/dist/src/app-opentui/react/App.d.ts +0 -9
- package/dist/src/app-opentui/react/App.js +0 -3866
- package/dist/src/app-opentui/react/Backdrop.d.ts +0 -5
- package/dist/src/app-opentui/react/Backdrop.js +0 -823
- package/dist/src/app-opentui/react/ChromeHost.d.ts +0 -5
- package/dist/src/app-opentui/react/ChromeHost.js +0 -1539
- package/dist/src/app-opentui/react/SceneFrameView.d.ts +0 -7
- package/dist/src/app-opentui/react/SceneFrameView.js +0 -579
- package/dist/src/app-opentui/react/context.d.ts +0 -17
- package/dist/src/app-opentui/react/context.js +0 -37
- package/dist/src/app-opentui/react/launch.d.ts +0 -2
- package/dist/src/app-opentui/react/launch.js +0 -4897
- package/dist/src/app-opentui/react/nav.d.ts +0 -18
- package/dist/src/app-opentui/react/nav.js +0 -54
- package/dist/src/app-opentui/react/scroll.d.ts +0 -12
- package/dist/src/app-opentui/react/scroll.js +0 -21
- package/dist/src/app-opentui/react/syntax.d.ts +0 -2
- package/dist/src/app-opentui/react/syntax.js +0 -65
- package/dist/src/app-opentui/registry.d.ts +0 -4
- package/dist/src/app-opentui/registry.js +0 -22876
- package/dist/src/app-opentui/remote-link.d.ts +0 -10
- package/dist/src/app-opentui/remote-link.js +0 -47
- package/dist/src/app-opentui/render/ascii-fleet.d.ts +0 -15
- package/dist/src/app-opentui/render/ascii-fleet.js +0 -82
- package/dist/src/app-opentui/render/constants.d.ts +0 -30
- package/dist/src/app-opentui/render/constants.js +0 -64
- package/dist/src/app-opentui/render/graphics.d.ts +0 -40
- package/dist/src/app-opentui/render/graphics.js +0 -713
- package/dist/src/app-opentui/render/hover.d.ts +0 -11
- package/dist/src/app-opentui/render/hover.js +0 -34
- package/dist/src/app-opentui/render/native-host.d.ts +0 -37
- package/dist/src/app-opentui/render/native-host.js +0 -180
- package/dist/src/app-opentui/render/panel-layout.d.ts +0 -38
- package/dist/src/app-opentui/render/panel-layout.js +0 -48
- package/dist/src/app-opentui/render/panels.d.ts +0 -12
- package/dist/src/app-opentui/render/panels.js +0 -288
- package/dist/src/app-opentui/render/preloader.d.ts +0 -10
- package/dist/src/app-opentui/render/preloader.js +0 -166
- package/dist/src/app-opentui/render/scene.d.ts +0 -68
- package/dist/src/app-opentui/render/scene.js +0 -300
- package/dist/src/app-opentui/render/terminal-handoff.d.ts +0 -16
- package/dist/src/app-opentui/render/terminal-handoff.js +0 -14
- package/dist/src/app-opentui/render/text.d.ts +0 -29
- package/dist/src/app-opentui/render/text.js +0 -177
- package/dist/src/app-opentui/render/type-bar.d.ts +0 -15
- package/dist/src/app-opentui/render/type-bar.js +0 -212
- package/dist/src/app-opentui/runtime-resources.d.ts +0 -16
- package/dist/src/app-opentui/runtime-resources.js +0 -62
- package/dist/src/app-opentui/runtime.d.ts +0 -45
- package/dist/src/app-opentui/runtime.js +0 -5232
- package/dist/src/app-opentui/scenes/command.d.ts +0 -3
- package/dist/src/app-opentui/scenes/command.js +0 -118
- package/dist/src/app-opentui/scenes/doctor.d.ts +0 -3
- package/dist/src/app-opentui/scenes/doctor.js +0 -296
- package/dist/src/app-opentui/scenes/error.d.ts +0 -2
- package/dist/src/app-opentui/scenes/error.js +0 -277
- package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/agent.js +0 -349
- package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/browser.js +0 -196
- package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/dist.js +0 -244
- package/dist/src/app-opentui/scenes/family-domains/git.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/git.js +0 -196
- package/dist/src/app-opentui/scenes/family-domains/github.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/github.js +0 -275
- package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/harness.js +0 -153
- package/dist/src/app-opentui/scenes/family-domains/index.d.ts +0 -4
- package/dist/src/app-opentui/scenes/family-domains/index.js +0 -1680
- package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +0 -76
- package/dist/src/app-opentui/scenes/family-domains/kit.js +0 -306
- package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/profile.js +0 -213
- package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/queue.js +0 -147
- package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/remote.js +0 -519
- package/dist/src/app-opentui/scenes/family-domains/review.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/review.js +0 -281
- package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/setup.js +0 -268
- package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/stats.js +0 -371
- package/dist/src/app-opentui/scenes/family.d.ts +0 -3
- package/dist/src/app-opentui/scenes/family.js +0 -2199
- package/dist/src/app-opentui/scenes/fleet.d.ts +0 -3
- package/dist/src/app-opentui/scenes/fleet.js +0 -766
- package/dist/src/app-opentui/scenes/handoff.d.ts +0 -2
- package/dist/src/app-opentui/scenes/handoff.js +0 -455
- package/dist/src/app-opentui/scenes/help.d.ts +0 -3
- package/dist/src/app-opentui/scenes/help.js +0 -725
- package/dist/src/app-opentui/scenes/inbox.d.ts +0 -3
- package/dist/src/app-opentui/scenes/inbox.js +0 -427
- package/dist/src/app-opentui/scenes/init.d.ts +0 -3
- package/dist/src/app-opentui/scenes/init.js +0 -181
- package/dist/src/app-opentui/scenes/inspect.d.ts +0 -3
- package/dist/src/app-opentui/scenes/inspect.js +0 -794
- package/dist/src/app-opentui/scenes/main.d.ts +0 -3
- package/dist/src/app-opentui/scenes/main.js +0 -332
- package/dist/src/app-opentui/scenes/pi.d.ts +0 -3
- package/dist/src/app-opentui/scenes/pi.js +0 -509
- package/dist/src/app-opentui/scenes/plugin.d.ts +0 -3
- package/dist/src/app-opentui/scenes/plugin.js +0 -487
- package/dist/src/app-opentui/scenes/repo.d.ts +0 -3
- package/dist/src/app-opentui/scenes/repo.js +0 -425
- package/dist/src/app-opentui/scenes/run-detail.d.ts +0 -3
- package/dist/src/app-opentui/scenes/run-detail.js +0 -467
- package/dist/src/app-opentui/scenes/server.d.ts +0 -3
- package/dist/src/app-opentui/scenes/server.js +0 -378
- package/dist/src/app-opentui/scenes/tasks.d.ts +0 -3
- package/dist/src/app-opentui/scenes/tasks.js +0 -768
- package/dist/src/app-opentui/scenes/workspace.d.ts +0 -3
- package/dist/src/app-opentui/scenes/workspace.js +0 -427
- package/dist/src/app-opentui/selectable.d.ts +0 -19
- package/dist/src/app-opentui/selectable.js +0 -80
- package/dist/src/app-opentui/state.d.ts +0 -4
- package/dist/src/app-opentui/state.js +0 -399
- package/dist/src/app-opentui/surface-catalog.d.ts +0 -20
- package/dist/src/app-opentui/surface-catalog.js +0 -542
- package/dist/src/app-opentui/theme.d.ts +0 -59
- package/dist/src/app-opentui/theme.js +0 -142
- package/dist/src/app-opentui/types.d.ts +0 -313
- package/dist/src/app-opentui/types.js +0 -1
- package/dist/src/commands/_server-events.d.ts +0 -26
- package/dist/src/commands/_server-events.js +0 -715
package/dist/src/app/board.js
CHANGED
|
@@ -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|
|
|
199
|
+
usage: ["rig server <status|list|add|use|start> [options]"],
|
|
201
200
|
commands: [
|
|
202
|
-
{ command: "status", description: "Show the selected server
|
|
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
|
-
|
|
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
|
|
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
|
|
422
|
-
usage: ["rig browser <help|explain|demo|hp-next
|
|
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`)."
|
|
425
|
-
{ command: "explain", description: "Explain the browser-required task contract
|
|
426
|
-
{ command: "demo
|
|
427
|
-
{ command: "
|
|
428
|
-
{ command: "hp-next
|
|
429
|
-
|
|
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
|
-
|
|
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,
|
|
521
|
-
import {
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
756
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
1271
|
-
headers.set("x-rig-project-root",
|
|
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(
|
|
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(
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
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
|
|
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 =
|
|
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 (
|
|
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(
|
|
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 = {}) {
|