@h-rig/cli 0.0.6-alpha.66 → 0.0.6-alpha.68

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.
@@ -0,0 +1,141 @@
1
+ // @bun
2
+ // packages/cli/src/commands/_async-ui.ts
3
+ import pc from "picocolors";
4
+
5
+ // packages/cli/src/commands/_spinner.ts
6
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
7
+ function createTtySpinner(input) {
8
+ const output = input.output ?? process.stdout;
9
+ const isTty = output.isTTY === true;
10
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
11
+ let label = input.label;
12
+ let frame = 0;
13
+ let paused = false;
14
+ let stopped = false;
15
+ let lastPrintedLabel = "";
16
+ const render = () => {
17
+ if (stopped || paused)
18
+ return;
19
+ if (!isTty) {
20
+ if (label !== lastPrintedLabel) {
21
+ output.write(`${label}
22
+ `);
23
+ lastPrintedLabel = label;
24
+ }
25
+ return;
26
+ }
27
+ frame = (frame + 1) % frames.length;
28
+ const glyph = frames[frame] ?? frames[0] ?? "";
29
+ output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
30
+ };
31
+ const clearLine = () => {
32
+ if (isTty)
33
+ output.write("\r\x1B[2K");
34
+ };
35
+ render();
36
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
37
+ return {
38
+ setLabel(next) {
39
+ label = next;
40
+ render();
41
+ },
42
+ pause() {
43
+ paused = true;
44
+ clearLine();
45
+ },
46
+ resume() {
47
+ if (stopped)
48
+ return;
49
+ paused = false;
50
+ render();
51
+ },
52
+ stop(finalLine) {
53
+ if (stopped)
54
+ return;
55
+ stopped = true;
56
+ if (timer)
57
+ clearInterval(timer);
58
+ clearLine();
59
+ if (finalLine)
60
+ output.write(`${finalLine}
61
+ `);
62
+ }
63
+ };
64
+ }
65
+
66
+ // packages/cli/src/runner.ts
67
+ import { EventBus } from "@rig/runtime/control-plane/runtime/events";
68
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
69
+ import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
70
+ import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
71
+
72
+ // packages/cli/src/commands/_server-client.ts
73
+ import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
74
+ var scopedGitHubBearerTokens = new Map;
75
+ var serverPhaseListener = null;
76
+ function setServerPhaseListener(listener) {
77
+ const previous = serverPhaseListener;
78
+ serverPhaseListener = listener;
79
+ return previous;
80
+ }
81
+ var serverReachabilityCache = new Map;
82
+
83
+ // packages/cli/src/commands/_async-ui.ts
84
+ var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
85
+ var DONE_SYMBOL = pc.green("\u25C7");
86
+ var FAIL_SYMBOL = pc.red("\u25A0");
87
+ var activeUpdate = null;
88
+ async function withSpinner(label, work, options = {}) {
89
+ if (options.outputMode === "json") {
90
+ return work(() => {});
91
+ }
92
+ if (activeUpdate) {
93
+ const outer = activeUpdate;
94
+ outer(label);
95
+ return work(outer);
96
+ }
97
+ const output = options.output ?? process.stderr;
98
+ const isTty = output.isTTY === true;
99
+ let lastLabel = label;
100
+ if (!isTty) {
101
+ output.write(`${label}
102
+ `);
103
+ const update2 = (next) => {
104
+ lastLabel = next;
105
+ };
106
+ activeUpdate = update2;
107
+ const previousListener2 = setServerPhaseListener(update2);
108
+ try {
109
+ return await work(update2);
110
+ } finally {
111
+ activeUpdate = null;
112
+ setServerPhaseListener(previousListener2);
113
+ }
114
+ }
115
+ const spinner = createTtySpinner({
116
+ label,
117
+ output,
118
+ frames: CLACK_SPINNER_FRAMES,
119
+ styleFrame: (frame) => pc.magenta(frame)
120
+ });
121
+ const update = (next) => {
122
+ lastLabel = next;
123
+ spinner.setLabel(next);
124
+ };
125
+ activeUpdate = update;
126
+ const previousListener = setServerPhaseListener(update);
127
+ try {
128
+ const result = await work(update);
129
+ spinner.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
130
+ return result;
131
+ } catch (error) {
132
+ spinner.stop(`${FAIL_SYMBOL} ${lastLabel}`);
133
+ throw error;
134
+ } finally {
135
+ activeUpdate = null;
136
+ setServerPhaseListener(previousListener);
137
+ }
138
+ }
139
+ export {
140
+ withSpinner
141
+ };
@@ -125,6 +125,9 @@ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
125
125
  return;
126
126
  writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
127
127
  }
128
+ function isRemoteConnectionSelected(projectRoot) {
129
+ return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
130
+ }
128
131
  export {
129
132
  writeRepoServerProjectRoot,
130
133
  writeRepoConnection,
@@ -134,5 +137,6 @@ export {
134
137
  resolveRepoConnectionPath,
135
138
  resolveGlobalConnectionsPath,
136
139
  readRepoConnection,
137
- readGlobalConnections
140
+ readGlobalConnections,
141
+ isRemoteConnectionSelected
138
142
  };
@@ -126,6 +126,10 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
126
126
  import { resolve as resolve2 } from "path";
127
127
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
128
128
  var scopedGitHubBearerTokens = new Map;
129
+ var serverPhaseListener = null;
130
+ function reportServerPhase(label) {
131
+ serverPhaseListener?.(label);
132
+ }
129
133
  function cleanToken(value) {
130
134
  const trimmed = value?.trim();
131
135
  return trimmed ? trimmed : null;
@@ -168,6 +172,7 @@ async function ensureServerForCli(projectRoot) {
168
172
  try {
169
173
  const selected = resolveSelectedConnection(projectRoot);
170
174
  if (selected?.connection.kind === "remote") {
175
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
171
176
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
172
177
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
173
178
  return {
@@ -177,6 +182,7 @@ async function ensureServerForCli(projectRoot) {
177
182
  serverProjectRoot
178
183
  };
179
184
  }
185
+ reportServerPhase("Starting local Rig server\u2026");
180
186
  const connection = await ensureLocalRigServerConnection(projectRoot);
181
187
  return {
182
188
  baseUrl: connection.baseUrl,
@@ -283,6 +289,7 @@ async function requestServerJson(context, pathname, init = {}) {
283
289
  const headers = mergeHeaders(init.headers, server.authToken);
284
290
  if (server.serverProjectRoot)
285
291
  headers.set("x-rig-project-root", server.serverProjectRoot);
292
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
286
293
  let response;
287
294
  try {
288
295
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -514,7 +521,10 @@ async function runRigDoctorChecks(options) {
514
521
  const bunVersion = options.bunVersion ?? Bun.version;
515
522
  const request = options.requestJson ?? ((pathname, init) => requestServerJson({ projectRoot }, pathname, init));
516
523
  const loadConfig = options.loadConfig ?? loadRigConfigOrNull;
524
+ const progress = options.onProgress ?? (() => {});
525
+ progress("Checking local toolchain\u2026");
517
526
  checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
527
+ progress("Loading rig.config\u2026");
518
528
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
519
529
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
520
530
  const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync4(resolve4(projectRoot, name)));
@@ -533,6 +543,7 @@ async function runRigDoctorChecks(options) {
533
543
  checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig server list` and `rig server use <alias|local>`." : undefined));
534
544
  let server = null;
535
545
  try {
546
+ progress("Connecting to the selected Rig server\u2026");
536
547
  server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
537
548
  checks.push(check("server", "Rig server reachable", "pass", `${server.connectionKind} ${server.baseUrl}`));
538
549
  } catch (error) {
@@ -540,18 +551,21 @@ async function runRigDoctorChecks(options) {
540
551
  }
541
552
  if (server || options.requestJson) {
542
553
  try {
554
+ progress("Checking server status\u2026");
543
555
  const status = await request("/api/server/status");
544
556
  checks.push(check("server-status", "server project status", "pass", JSON.stringify(status).slice(0, 180)));
545
557
  } catch (error) {
546
558
  checks.push(check("server-status", "server project status", "fail", errorMessage(error), "Run `rig doctor` after the selected server is reachable."));
547
559
  }
548
560
  try {
561
+ progress("Checking GitHub auth\u2026");
549
562
  const auth = await request("/api/github/auth/status");
550
563
  checks.push(isAuthenticated(auth) ? check("github-auth", "GitHub auth", "pass") : check("github-auth", "GitHub auth", "fail", "not authenticated", "Run `rig github auth import-gh` or `rig github auth token --token <token>`."));
551
564
  } catch (error) {
552
565
  checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig and ensure the server exposes auth status."));
553
566
  }
554
567
  try {
568
+ progress("Checking GitHub repo permissions\u2026");
555
569
  const permissions = await request("/api/github/repo/permissions");
556
570
  const allowed = permissionAllowsPr(permissions);
557
571
  checks.push(allowed === true ? check("github-repo-permissions", "GitHub repo PR permissions", "pass", JSON.stringify(permissions).slice(0, 180)) : allowed === false ? check("github-repo-permissions", "GitHub repo PR permissions", "fail", JSON.stringify(permissions).slice(0, 180), "Grant the selected GitHub token permission to push branches, open PRs, and merge according to repo rules.") : check("github-repo-permissions", "GitHub repo PR permissions", "warn", JSON.stringify(permissions).slice(0, 180), "Confirm the selected token can push branches and open PRs."));
@@ -559,6 +573,7 @@ async function runRigDoctorChecks(options) {
559
573
  checks.push(check("github-repo-permissions", "GitHub repo PR permissions", "warn", errorMessage(error), "Ensure the server exposes repo permission checks and the token can open PRs."));
560
574
  }
561
575
  try {
576
+ progress("Checking GitHub issue labels\u2026");
562
577
  const labels = await request("/api/workspace/task-labels");
563
578
  const ready = labelsReady(labels);
564
579
  checks.push(ready === false ? check("task-labels", "GitHub issue labels", "fail", JSON.stringify(labels).slice(0, 180), "Let Rig create required labels or create the configured lifecycle labels manually.") : check("task-labels", "GitHub issue labels", ready === true ? "pass" : "warn", JSON.stringify(labels).slice(0, 180), "Confirm required Rig lifecycle labels exist."));
@@ -566,6 +581,7 @@ async function runRigDoctorChecks(options) {
566
581
  checks.push(check("task-labels", "GitHub issue labels", "warn", errorMessage(error), "Run `rig init`/`rig doctor` after label setup is wired on the server."));
567
582
  }
568
583
  try {
584
+ progress("Checking task projection\u2026");
569
585
  const projection = await request("/api/workspace/task-projection");
570
586
  checks.push(check("task-projection", "task projection", "pass", JSON.stringify(projection).slice(0, 180)));
571
587
  } catch (error) {
@@ -574,6 +590,7 @@ async function runRigDoctorChecks(options) {
574
590
  const slug = projectStatusSlug(projectRoot, config);
575
591
  if (slug) {
576
592
  try {
593
+ progress("Checking server project checkout\u2026");
577
594
  const project = await request(`/api/projects/${encodeURIComponent(slug)}`);
578
595
  checks.push(check("remote-checkout", "server project checkout", "pass", JSON.stringify(project).slice(0, 180)));
579
596
  } catch (error) {
@@ -588,6 +605,7 @@ async function runRigDoctorChecks(options) {
588
605
  }
589
606
  checks.push(githubProjectsCheck(config));
590
607
  checks.push(prMergeCheck(config));
608
+ progress("Checking Pi installation\u2026");
591
609
  const piChecks = await (options.piChecks ?? (() => buildPiSetupChecks()))().catch((error) => [{
592
610
  ok: false,
593
611
  label: "pi/pi-rig checks",
@@ -121,6 +121,15 @@ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
121
121
 
122
122
  // packages/cli/src/commands/_server-client.ts
123
123
  var scopedGitHubBearerTokens = new Map;
124
+ var serverPhaseListener = null;
125
+ function setServerPhaseListener(listener) {
126
+ const previous = serverPhaseListener;
127
+ serverPhaseListener = listener;
128
+ return previous;
129
+ }
130
+ function reportServerPhase(label) {
131
+ serverPhaseListener?.(label);
132
+ }
124
133
  function cleanToken(value) {
125
134
  const trimmed = value?.trim();
126
135
  return trimmed ? trimmed : null;
@@ -163,6 +172,7 @@ async function ensureServerForCli(projectRoot) {
163
172
  try {
164
173
  const selected = resolveSelectedConnection(projectRoot);
165
174
  if (selected?.connection.kind === "remote") {
175
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
166
176
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
167
177
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
168
178
  return {
@@ -172,6 +182,7 @@ async function ensureServerForCli(projectRoot) {
172
182
  serverProjectRoot
173
183
  };
174
184
  }
185
+ reportServerPhase("Starting local Rig server\u2026");
175
186
  const connection = await ensureLocalRigServerConnection(projectRoot);
176
187
  return {
177
188
  baseUrl: connection.baseUrl,
@@ -278,6 +289,7 @@ async function requestServerJson(context, pathname, init = {}) {
278
289
  const headers = mergeHeaders(init.headers, server.authToken);
279
290
  if (server.serverProjectRoot)
280
291
  headers.set("x-rig-project-root", server.serverProjectRoot);
292
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
281
293
  let response;
282
294
  try {
283
295
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -592,7 +604,12 @@ async function attachRunBundledPiFrontend(context, input) {
592
604
  };
593
605
  let detached = false;
594
606
  try {
595
- await runPiMain([], {
607
+ await runPiMain([
608
+ "--no-extensions",
609
+ "--no-skills",
610
+ "--no-prompt-templates",
611
+ "--no-context-files"
612
+ ], {
596
613
  extensionFactories: [piRigExtensionFactory]
597
614
  });
598
615
  detached = true;
@@ -615,6 +632,127 @@ async function attachRunBundledPiFrontend(context, input) {
615
632
  };
616
633
  }
617
634
 
635
+ // packages/cli/src/commands/_async-ui.ts
636
+ import pc from "picocolors";
637
+
638
+ // packages/cli/src/commands/_spinner.ts
639
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
640
+ function createTtySpinner(input) {
641
+ const output = input.output ?? process.stdout;
642
+ const isTty = output.isTTY === true;
643
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
644
+ let label = input.label;
645
+ let frame = 0;
646
+ let paused = false;
647
+ let stopped = false;
648
+ let lastPrintedLabel = "";
649
+ const render = () => {
650
+ if (stopped || paused)
651
+ return;
652
+ if (!isTty) {
653
+ if (label !== lastPrintedLabel) {
654
+ output.write(`${label}
655
+ `);
656
+ lastPrintedLabel = label;
657
+ }
658
+ return;
659
+ }
660
+ frame = (frame + 1) % frames.length;
661
+ const glyph = frames[frame] ?? frames[0] ?? "";
662
+ output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
663
+ };
664
+ const clearLine = () => {
665
+ if (isTty)
666
+ output.write("\r\x1B[2K");
667
+ };
668
+ render();
669
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
670
+ return {
671
+ setLabel(next) {
672
+ label = next;
673
+ render();
674
+ },
675
+ pause() {
676
+ paused = true;
677
+ clearLine();
678
+ },
679
+ resume() {
680
+ if (stopped)
681
+ return;
682
+ paused = false;
683
+ render();
684
+ },
685
+ stop(finalLine) {
686
+ if (stopped)
687
+ return;
688
+ stopped = true;
689
+ if (timer)
690
+ clearInterval(timer);
691
+ clearLine();
692
+ if (finalLine)
693
+ output.write(`${finalLine}
694
+ `);
695
+ }
696
+ };
697
+ }
698
+
699
+ // packages/cli/src/commands/_async-ui.ts
700
+ var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
701
+ var DONE_SYMBOL = pc.green("\u25C7");
702
+ var FAIL_SYMBOL = pc.red("\u25A0");
703
+ var activeUpdate = null;
704
+ async function withSpinner(label, work, options = {}) {
705
+ if (options.outputMode === "json") {
706
+ return work(() => {});
707
+ }
708
+ if (activeUpdate) {
709
+ const outer = activeUpdate;
710
+ outer(label);
711
+ return work(outer);
712
+ }
713
+ const output = options.output ?? process.stderr;
714
+ const isTty = output.isTTY === true;
715
+ let lastLabel = label;
716
+ if (!isTty) {
717
+ output.write(`${label}
718
+ `);
719
+ const update2 = (next) => {
720
+ lastLabel = next;
721
+ };
722
+ activeUpdate = update2;
723
+ const previousListener2 = setServerPhaseListener(update2);
724
+ try {
725
+ return await work(update2);
726
+ } finally {
727
+ activeUpdate = null;
728
+ setServerPhaseListener(previousListener2);
729
+ }
730
+ }
731
+ const spinner = createTtySpinner({
732
+ label,
733
+ output,
734
+ frames: CLACK_SPINNER_FRAMES,
735
+ styleFrame: (frame) => pc.magenta(frame)
736
+ });
737
+ const update = (next) => {
738
+ lastLabel = next;
739
+ spinner.setLabel(next);
740
+ };
741
+ activeUpdate = update;
742
+ const previousListener = setServerPhaseListener(update);
743
+ try {
744
+ const result = await work(update);
745
+ spinner.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
746
+ return result;
747
+ } catch (error) {
748
+ spinner.stop(`${FAIL_SYMBOL} ${lastLabel}`);
749
+ throw error;
750
+ } finally {
751
+ activeUpdate = null;
752
+ setServerPhaseListener(previousListener);
753
+ }
754
+ }
755
+
618
756
  // packages/cli/src/commands/_operator-view.ts
619
757
  var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
620
758
  function runStatusFromPayload(payload) {
@@ -657,8 +795,9 @@ async function readOperatorSnapshot(context, runId, options = {}) {
657
795
  }
658
796
  async function attachRunOperatorView(context, input) {
659
797
  let steered = false;
660
- if (input.message?.trim()) {
661
- await sendRunPiPromptViaServer(context, input.runId, input.message.trim(), "steer").catch(() => steerRunViaServer(context, input.runId, input.message.trim()));
798
+ const attachMessage = input.message?.trim();
799
+ if (attachMessage) {
800
+ await withSpinner("Queueing steering message\u2026", () => sendRunPiPromptViaServer(context, input.runId, attachMessage, "steer").catch(() => steerRunViaServer(context, input.runId, attachMessage)), { outputMode: context.outputMode });
662
801
  steered = true;
663
802
  }
664
803
  if (input.follow && !input.once && input.interactive !== false && context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
@@ -668,7 +807,7 @@ async function attachRunOperatorView(context, input) {
668
807
  });
669
808
  }
670
809
  const surface = createOperatorSurface({ interactive: input.interactive !== false });
671
- let snapshot = await readOperatorSnapshot(context, input.runId);
810
+ let snapshot = await withSpinner(`Connecting to run ${input.runId}\u2026`, () => readOperatorSnapshot(context, input.runId), { outputMode: context.outputMode });
672
811
  if (context.outputMode === "text") {
673
812
  surface.renderSnapshot(snapshot);
674
813
  surface.renderTimeline(snapshot.timeline);
@@ -128,6 +128,10 @@ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
128
128
 
129
129
  // packages/cli/src/commands/_server-client.ts
130
130
  var scopedGitHubBearerTokens = new Map;
131
+ var serverPhaseListener = null;
132
+ function reportServerPhase(label) {
133
+ serverPhaseListener?.(label);
134
+ }
131
135
  function cleanToken(value) {
132
136
  const trimmed = value?.trim();
133
137
  return trimmed ? trimmed : null;
@@ -170,6 +174,7 @@ async function ensureServerForCli(projectRoot) {
170
174
  try {
171
175
  const selected = resolveSelectedConnection(projectRoot);
172
176
  if (selected?.connection.kind === "remote") {
177
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
173
178
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
174
179
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
175
180
  return {
@@ -179,6 +184,7 @@ async function ensureServerForCli(projectRoot) {
179
184
  serverProjectRoot
180
185
  };
181
186
  }
187
+ reportServerPhase("Starting local Rig server\u2026");
182
188
  const connection = await ensureLocalRigServerConnection(projectRoot);
183
189
  return {
184
190
  baseUrl: connection.baseUrl,
@@ -285,6 +291,7 @@ async function requestServerJson(context, pathname, init = {}) {
285
291
  const headers = mergeHeaders(init.headers, server.authToken);
286
292
  if (server.serverProjectRoot)
287
293
  headers.set("x-rig-project-root", server.serverProjectRoot);
294
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
288
295
  let response;
289
296
  try {
290
297
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -360,7 +367,12 @@ async function attachRunBundledPiFrontend(context, input) {
360
367
  };
361
368
  let detached = false;
362
369
  try {
363
- await runPiMain([], {
370
+ await runPiMain([
371
+ "--no-extensions",
372
+ "--no-skills",
373
+ "--no-prompt-templates",
374
+ "--no-context-files"
375
+ ], {
364
376
  extensionFactories: [piRigExtensionFactory]
365
377
  });
366
378
  detached = true;
@@ -120,6 +120,10 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
120
120
  import { resolve as resolve2 } from "path";
121
121
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
122
122
  var scopedGitHubBearerTokens = new Map;
123
+ var serverPhaseListener = null;
124
+ function reportServerPhase(label) {
125
+ serverPhaseListener?.(label);
126
+ }
123
127
  function cleanToken(value) {
124
128
  const trimmed = value?.trim();
125
129
  return trimmed ? trimmed : null;
@@ -162,6 +166,7 @@ async function ensureServerForCli(projectRoot) {
162
166
  try {
163
167
  const selected = resolveSelectedConnection(projectRoot);
164
168
  if (selected?.connection.kind === "remote") {
169
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
165
170
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
166
171
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
167
172
  return {
@@ -171,6 +176,7 @@ async function ensureServerForCli(projectRoot) {
171
176
  serverProjectRoot
172
177
  };
173
178
  }
179
+ reportServerPhase("Starting local Rig server\u2026");
174
180
  const connection = await ensureLocalRigServerConnection(projectRoot);
175
181
  return {
176
182
  baseUrl: connection.baseUrl,
@@ -277,6 +283,7 @@ async function requestServerJson(context, pathname, init = {}) {
277
283
  const headers = mergeHeaders(init.headers, server.authToken);
278
284
  if (server.serverProjectRoot)
279
285
  headers.set("x-rig-project-root", server.serverProjectRoot);
286
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
280
287
  let response;
281
288
  try {
282
289
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -121,6 +121,15 @@ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
121
121
 
122
122
  // packages/cli/src/commands/_server-client.ts
123
123
  var scopedGitHubBearerTokens = new Map;
124
+ var serverPhaseListener = null;
125
+ function setServerPhaseListener(listener) {
126
+ const previous = serverPhaseListener;
127
+ serverPhaseListener = listener;
128
+ return previous;
129
+ }
130
+ function reportServerPhase(label) {
131
+ serverPhaseListener?.(label);
132
+ }
124
133
  function cleanToken(value) {
125
134
  const trimmed = value?.trim();
126
135
  return trimmed ? trimmed : null;
@@ -167,6 +176,7 @@ async function ensureServerForCli(projectRoot) {
167
176
  try {
168
177
  const selected = resolveSelectedConnection(projectRoot);
169
178
  if (selected?.connection.kind === "remote") {
179
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
170
180
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
171
181
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
172
182
  return {
@@ -176,6 +186,7 @@ async function ensureServerForCli(projectRoot) {
176
186
  serverProjectRoot
177
187
  };
178
188
  }
189
+ reportServerPhase("Starting local Rig server\u2026");
179
190
  const connection = await ensureLocalRigServerConnection(projectRoot);
180
191
  return {
181
192
  baseUrl: connection.baseUrl,
@@ -292,6 +303,7 @@ async function requestServerJson(context, pathname, init = {}) {
292
303
  const headers = mergeHeaders(init.headers, server.authToken);
293
304
  if (server.serverProjectRoot)
294
305
  headers.set("x-rig-project-root", server.serverProjectRoot);
306
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
295
307
  let response;
296
308
  try {
297
309
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -588,6 +600,7 @@ export {
588
600
  submitTaskRunViaServer,
589
601
  stopRunViaServer,
590
602
  steerRunViaServer,
603
+ setServerPhaseListener,
591
604
  setGitHubBearerTokenForCurrentProcess,
592
605
  sendRunPiShellViaServer,
593
606
  sendRunPiPromptViaServer,
@@ -125,6 +125,10 @@ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
125
125
 
126
126
  // packages/cli/src/commands/_server-client.ts
127
127
  var scopedGitHubBearerTokens = new Map;
128
+ var serverPhaseListener = null;
129
+ function reportServerPhase(label) {
130
+ serverPhaseListener?.(label);
131
+ }
128
132
  function cleanToken(value) {
129
133
  const trimmed = value?.trim();
130
134
  return trimmed ? trimmed : null;
@@ -167,6 +171,7 @@ async function ensureServerForCli(projectRoot) {
167
171
  try {
168
172
  const selected = resolveSelectedConnection(projectRoot);
169
173
  if (selected?.connection.kind === "remote") {
174
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
170
175
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
171
176
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
172
177
  return {
@@ -176,6 +181,7 @@ async function ensureServerForCli(projectRoot) {
176
181
  serverProjectRoot
177
182
  };
178
183
  }
184
+ reportServerPhase("Starting local Rig server\u2026");
179
185
  const connection = await ensureLocalRigServerConnection(projectRoot);
180
186
  return {
181
187
  baseUrl: connection.baseUrl,
@@ -282,6 +288,7 @@ async function requestServerJson(context, pathname, init = {}) {
282
288
  const headers = mergeHeaders(init.headers, server.authToken);
283
289
  if (server.serverProjectRoot)
284
290
  headers.set("x-rig-project-root", server.serverProjectRoot);
291
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
285
292
  let response;
286
293
  try {
287
294
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -4,6 +4,7 @@ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834"
4
4
  function createTtySpinner(input) {
5
5
  const output = input.output ?? process.stdout;
6
6
  const isTty = output.isTTY === true;
7
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
7
8
  let label = input.label;
8
9
  let frame = 0;
9
10
  let paused = false;
@@ -20,8 +21,9 @@ function createTtySpinner(input) {
20
21
  }
21
22
  return;
22
23
  }
23
- frame = (frame + 1) % SPINNER_FRAMES.length;
24
- output.write(`\r\x1B[2K${SPINNER_FRAMES[frame]} ${label}`);
24
+ frame = (frame + 1) % frames.length;
25
+ const glyph = frames[frame] ?? frames[0] ?? "";
26
+ output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
25
27
  };
26
28
  const clearLine = () => {
27
29
  if (isTty)