@h-rig/cli 0.0.6-alpha.10 → 0.0.6-alpha.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +18 -19
  2. package/dist/bin/build-rig-binaries.d.ts +2 -0
  3. package/dist/bin/build-rig-binaries.js +22 -10
  4. package/dist/bin/rig.d.ts +72 -0
  5. package/dist/bin/rig.js +15683 -7361
  6. package/dist/config/rig-default-config.yml +5 -0
  7. package/dist/src/app/drone-ui.d.ts +34 -0
  8. package/dist/src/app/drone-ui.js +278 -0
  9. package/dist/src/commands/_async-ui.d.ts +10 -0
  10. package/dist/src/commands/_async-ui.js +121 -0
  11. package/dist/src/commands/_cli-format.d.ts +56 -0
  12. package/dist/src/commands/_cli-format.js +319 -0
  13. package/dist/src/commands/_config-env.d.ts +18 -0
  14. package/dist/src/commands/_config-env.js +22 -0
  15. package/dist/src/commands/_connection-state.d.ts +54 -0
  16. package/dist/src/commands/_connection-state.js +75 -11
  17. package/dist/src/commands/_doctor-checks.d.ts +46 -0
  18. package/dist/src/commands/_doctor-checks.js +100 -267
  19. package/dist/src/commands/_help-catalog.d.ts +29 -0
  20. package/dist/src/commands/_help-catalog.js +146 -0
  21. package/dist/src/commands/_inprocess-services.d.ts +33 -0
  22. package/dist/src/commands/_inprocess-services.js +102 -0
  23. package/dist/src/commands/_json-output.d.ts +11 -0
  24. package/dist/src/commands/_json-output.js +60 -0
  25. package/dist/src/commands/_lazy-reconcile.d.ts +34 -0
  26. package/dist/src/commands/_lazy-reconcile.js +102 -0
  27. package/dist/src/commands/_parsers.d.ts +15 -0
  28. package/dist/src/commands/_parsers.js +18 -11
  29. package/dist/src/commands/_paths.d.ts +11 -0
  30. package/dist/src/commands/_paths.js +1 -1
  31. package/dist/src/commands/_pi-frontend.d.ts +35 -0
  32. package/dist/src/commands/_pi-frontend.js +64 -0
  33. package/dist/src/commands/_pi-install.d.ts +42 -0
  34. package/dist/src/commands/_pi-install.js +19 -36
  35. package/dist/src/commands/_policy.d.ts +8 -0
  36. package/dist/src/commands/_policy.js +67 -19
  37. package/dist/src/commands/_probes.d.ts +1 -0
  38. package/dist/src/commands/_run-bridge.d.ts +114 -0
  39. package/dist/src/commands/_run-bridge.js +387 -0
  40. package/dist/src/commands/_run-diagnostics.d.ts +9 -0
  41. package/dist/src/commands/_run-diagnostics.js +51 -0
  42. package/dist/src/commands/_run-driver-helpers.d.ts +26 -0
  43. package/dist/src/commands/_run-driver-helpers.js +79 -230
  44. package/dist/src/commands/_run-projection.d.ts +50 -0
  45. package/dist/src/commands/_run-projection.js +349 -0
  46. package/dist/src/commands/_run-subcommands.d.ts +3 -0
  47. package/dist/src/commands/_run-subcommands.js +31 -0
  48. package/dist/src/commands/_spinner.d.ts +25 -0
  49. package/dist/src/commands/_spinner.js +65 -0
  50. package/dist/src/commands/agent.d.ts +3 -0
  51. package/dist/src/commands/agent.js +8690 -236
  52. package/dist/src/commands/config.d.ts +3 -0
  53. package/dist/src/commands/config.js +181 -0
  54. package/dist/src/commands/dist.d.ts +28 -0
  55. package/dist/src/commands/dist.js +44 -29
  56. package/dist/src/commands/doctor.d.ts +3 -0
  57. package/dist/src/commands/doctor.js +219 -268
  58. package/dist/src/commands/github.d.ts +3 -0
  59. package/dist/src/commands/github.js +236 -188
  60. package/dist/src/commands/inbox.d.ts +28 -0
  61. package/dist/src/commands/inbox.js +530 -111
  62. package/dist/src/commands/init.d.ts +64 -0
  63. package/dist/src/commands/init.js +912 -705
  64. package/dist/src/commands/inspect.d.ts +20 -0
  65. package/dist/src/commands/inspect.js +709 -119
  66. package/dist/src/commands/pi.d.ts +3 -0
  67. package/dist/src/commands/pi.js +177 -0
  68. package/dist/src/commands/plugin.d.ts +16 -0
  69. package/dist/src/commands/plugin.js +576 -29
  70. package/dist/src/commands/profile-and-review.d.ts +4 -0
  71. package/dist/src/commands/profile-and-review.js +112 -67
  72. package/dist/src/commands/queue.d.ts +3 -0
  73. package/dist/src/commands/queue.js +20 -20
  74. package/dist/src/commands/remote.d.ts +3 -0
  75. package/dist/src/commands/remote.js +883 -50
  76. package/dist/src/commands/repo-git-harness.d.ts +5 -0
  77. package/dist/src/commands/repo-git-harness.js +78 -28
  78. package/dist/src/commands/run.d.ts +21 -0
  79. package/dist/src/commands/run.js +17731 -661
  80. package/dist/src/commands/server.d.ts +3 -0
  81. package/dist/src/commands/server.js +166 -303
  82. package/dist/src/commands/setup.d.ts +16 -0
  83. package/dist/src/commands/setup.js +244 -299
  84. package/dist/src/commands/stats.d.ts +15 -0
  85. package/dist/src/commands/stats.js +632 -0
  86. package/dist/src/commands/task-run-driver.d.ts +94 -0
  87. package/dist/src/commands/task-run-driver.js +116 -1961
  88. package/dist/src/commands/task.d.ts +35 -0
  89. package/dist/src/commands/task.js +676 -1201
  90. package/dist/src/commands/test.d.ts +3 -0
  91. package/dist/src/commands/test.js +15 -8
  92. package/dist/src/commands/triage.d.ts +11 -0
  93. package/dist/src/commands/triage.js +227 -0
  94. package/dist/src/commands/workspace.d.ts +3 -0
  95. package/dist/src/commands/workspace.js +18 -11
  96. package/dist/src/commands.d.ts +13 -0
  97. package/dist/src/commands.js +16812 -8045
  98. package/dist/src/index.d.ts +4 -0
  99. package/dist/src/index.js +16817 -8377
  100. package/dist/src/launcher.d.ts +61 -0
  101. package/dist/src/launcher.js +77 -11
  102. package/dist/src/operator-cli.d.ts +2 -0
  103. package/dist/src/operator-cli.js +17867 -0
  104. package/dist/src/operator-entry.d.ts +1 -0
  105. package/dist/src/operator-entry.js +3 -0
  106. package/dist/src/runner.d.ts +47 -0
  107. package/dist/src/runner.js +16 -22
  108. package/dist/src/withMutedConsole.d.ts +2 -0
  109. package/package.json +21 -8
  110. package/dist/src/commands/_authority-runs.js +0 -111
  111. package/dist/src/commands/_operator-view.js +0 -340
  112. package/dist/src/commands/_preflight.js +0 -478
  113. package/dist/src/commands/_server-client.js +0 -382
  114. package/dist/src/commands/_snapshot-upload.js +0 -331
  115. package/dist/src/commands/_task-picker.js +0 -48
  116. package/dist/src/commands/browser.js +0 -890
  117. package/dist/src/commands/connect.js +0 -180
  118. package/dist/src/commands/inspector.js +0 -256
  119. package/dist/src/commands/task-report-bug.js +0 -1083
  120. package/dist/src/report-bug.js +0 -260
@@ -0,0 +1,349 @@
1
+ // @bun
2
+ // packages/cli/src/commands/_run-projection.ts
3
+ import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
4
+ import { resolve as resolve2 } from "path";
5
+ import {
6
+ foldRunSessionEntries,
7
+ sessionIdFromSessionFile as sessionIdFromSessionFile2
8
+ } from "@rig/contracts";
9
+ import { listAgentRuntimes as listAgentRuntimes2 } from "@rig/runtime/control-plane/runtime/isolation";
10
+
11
+ // packages/cli/src/commands/_run-bridge.ts
12
+ import { existsSync, readdirSync, readFileSync } from "fs";
13
+ import { dirname, resolve } from "path";
14
+ import { CUSTOM_TYPE_FOR, sessionIdFromSessionFile } from "@rig/contracts";
15
+ import { createPluginHost } from "@rig/core";
16
+ import { loadConfig } from "@rig/core/load-config";
17
+ import { resolveOwnerNamespaceKey, resolveRegistryBaseUrl, resolveRegistrySecret, resolveSelectedRemote } from "@rig/runtime/control-plane/remote";
18
+ import { listAgentRuntimes } from "@rig/runtime/control-plane/runtime/isolation";
19
+ import { createRegistryClient } from "@rig/relay-registry";
20
+ import {
21
+ listActiveCollabSessions as ompListActiveCollabSessions
22
+ } from "@oh-my-pi/pi-coding-agent/collab/api";
23
+ function registrySecret(env = process.env) {
24
+ return resolveRegistrySecret(process.cwd(), env) ?? null;
25
+ }
26
+ function registryBaseUrl(env = process.env) {
27
+ return resolveRegistryBaseUrl(process.cwd(), env);
28
+ }
29
+ function collabFromRegistryEntry(entry) {
30
+ return {
31
+ sessionId: entry.roomId,
32
+ sessionPath: "",
33
+ cwd: "",
34
+ title: entry.title,
35
+ joinLink: entry.joinLink,
36
+ webLink: entry.webLink,
37
+ relayUrl: entry.relayUrl,
38
+ owner: entry.owner,
39
+ selectedRepo: entry.repo,
40
+ startedAt: entry.startedAt,
41
+ updatedAt: entry.heartbeatAt,
42
+ ...entry.pid === undefined ? {} : { pid: entry.pid },
43
+ stale: entry.stale
44
+ };
45
+ }
46
+ function isRecord(value) {
47
+ return typeof value === "object" && value !== null;
48
+ }
49
+ function readLocalRunCollab(runtime) {
50
+ if (!runtime.sessionDir || !existsSync(runtime.sessionDir))
51
+ return null;
52
+ let files;
53
+ try {
54
+ files = readdirSync(runtime.sessionDir).filter((f) => f.endsWith(".jsonl")).sort().reverse();
55
+ } catch {
56
+ return null;
57
+ }
58
+ for (const file of files) {
59
+ let lines;
60
+ try {
61
+ lines = readFileSync(resolve(runtime.sessionDir, file), "utf8").split(`
62
+ `);
63
+ } catch {
64
+ continue;
65
+ }
66
+ let host = null;
67
+ for (const line of lines) {
68
+ if (!line.includes("collab-host-started"))
69
+ continue;
70
+ let entry;
71
+ try {
72
+ entry = JSON.parse(line);
73
+ } catch {
74
+ continue;
75
+ }
76
+ if (!isRecord(entry) || entry.customType !== CUSTOM_TYPE_FOR["timeline-entry"] || !isRecord(entry.data))
77
+ continue;
78
+ const payload = isRecord(entry.data.payload) ? entry.data.payload : entry.data;
79
+ if (payload.type !== "collab-host-started")
80
+ continue;
81
+ host = {
82
+ roomId: typeof payload.roomId === "string" ? payload.roomId : undefined,
83
+ joinLink: typeof payload.joinLink === "string" ? payload.joinLink : undefined,
84
+ webLink: typeof payload.webLink === "string" ? payload.webLink : undefined,
85
+ relayUrl: typeof payload.relayUrl === "string" ? payload.relayUrl : undefined,
86
+ at: typeof entry.data.at === "string" ? entry.data.at : undefined
87
+ };
88
+ }
89
+ if (!host?.joinLink)
90
+ continue;
91
+ const at = host.at ?? "";
92
+ const sessionId = host.roomId ?? sessionIdFromSessionFile(resolve(runtime.sessionDir, file)) ?? runtime.id;
93
+ return {
94
+ sessionId,
95
+ sessionPath: resolve(runtime.sessionDir, file),
96
+ cwd: runtime.workspaceDir,
97
+ joinLink: host.joinLink,
98
+ webLink: host.webLink ?? "",
99
+ relayUrl: host.relayUrl ?? "",
100
+ title: runtime.taskId ? `[${runtime.taskId}] Rig run ${sessionId}` : `Rig run ${sessionId}`,
101
+ startedAt: at,
102
+ updatedAt: at,
103
+ stale: false
104
+ };
105
+ }
106
+ return null;
107
+ }
108
+ async function listLocalRunCollabSessions(projectRoot) {
109
+ let runtimes;
110
+ try {
111
+ runtimes = await listAgentRuntimes(projectRoot);
112
+ } catch {
113
+ return [];
114
+ }
115
+ const out = [];
116
+ for (const runtime of runtimes) {
117
+ const collab = readLocalRunCollab(runtime);
118
+ if (collab)
119
+ out.push(collab);
120
+ }
121
+ return out;
122
+ }
123
+ async function listActiveRunCollab(filter) {
124
+ return defaultListActiveCollabSessions(filter);
125
+ }
126
+ async function defaultListActiveCollabSessions(filter) {
127
+ const projectRoot = process.cwd();
128
+ const local = await listLocalRunCollabSessions(projectRoot);
129
+ const namespaceKey = filter.namespaceKey ?? resolveOwnerNamespaceKey(projectRoot);
130
+ const secret = registrySecret();
131
+ const remote = namespaceKey && secret ? (await createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey, secret }).listRoomsByOwner(filter)).map(collabFromRegistryEntry) : await ompListActiveCollabSessions(filter);
132
+ const seen = new Set(local.map((c) => c.sessionId));
133
+ return [...local, ...remote.filter((c) => !seen.has(c.sessionId))];
134
+ }
135
+
136
+ // packages/cli/src/commands/_run-diagnostics.ts
137
+ function normalizeString(value) {
138
+ if (typeof value !== "string")
139
+ return null;
140
+ const normalized = value.replace(/\s+/g, " ").trim();
141
+ return normalized.length > 0 ? normalized : null;
142
+ }
143
+ function isGenericRunFailure(value) {
144
+ const text = normalizeString(value);
145
+ return Boolean(text && /^Task run failed \([^)]*\)$/i.test(text));
146
+ }
147
+ function appendCandidate(candidates, value) {
148
+ const text = normalizeString(value);
149
+ if (text && !candidates.includes(text))
150
+ candidates.push(text);
151
+ }
152
+ function categorizeUsefulRunError(lines) {
153
+ const taskSourceFailure = lines.find((line) => /failed to update task source/i.test(line));
154
+ if (taskSourceFailure)
155
+ return `Task source update failed: ${taskSourceFailure}`;
156
+ const moduleFailure = lines.find((line) => /cannot find module/i.test(line));
157
+ if (moduleFailure)
158
+ return `Runtime module resolution failed: ${moduleFailure}`;
159
+ const providerFailure = lines.find((line) => /no api key found|unauthorized|authentication failed|invalid api key/i.test(line));
160
+ if (providerFailure)
161
+ return `Provider authentication failed: ${providerFailure}`;
162
+ return null;
163
+ }
164
+ function summarizeUsefulRunError(projection) {
165
+ if (projection.status !== "failed")
166
+ return null;
167
+ const candidates = [];
168
+ for (const anomaly of projection.anomalies) {
169
+ appendCandidate(candidates, `Journal anomaly (${anomaly.kind}): ${anomaly.detail}`);
170
+ }
171
+ for (const phase of projection.closeoutPhases) {
172
+ if (phase.outcome === "failed")
173
+ appendCandidate(candidates, phase.detail);
174
+ }
175
+ for (const entry of projection.statusHistory) {
176
+ appendCandidate(candidates, entry.reason);
177
+ }
178
+ appendCandidate(candidates, projection.record.statusDetail);
179
+ appendCandidate(candidates, projection.record.errorText);
180
+ const nonGeneric = candidates.filter((candidate) => !isGenericRunFailure(candidate));
181
+ return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
182
+ }
183
+
184
+ // packages/cli/src/commands/_run-projection.ts
185
+ var EMPTY_PROJECTION = foldRunSessionEntries([], "");
186
+ function stringOrNull(value) {
187
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
188
+ }
189
+ function newestSessionFile(sessionDir) {
190
+ if (!sessionDir || !existsSync2(sessionDir))
191
+ return null;
192
+ try {
193
+ const files = readdirSync2(sessionDir).filter((file) => file.endsWith(".jsonl")).sort().reverse();
194
+ return files[0] ? resolve2(sessionDir, files[0]) : null;
195
+ } catch {
196
+ return null;
197
+ }
198
+ }
199
+ function readSessionRunEntries(sessionPath) {
200
+ if (!sessionPath || !existsSync2(sessionPath))
201
+ return [];
202
+ let raw;
203
+ try {
204
+ raw = readFileSync2(sessionPath, "utf8");
205
+ } catch {
206
+ return [];
207
+ }
208
+ const entries = [];
209
+ for (const line of raw.split(`
210
+ `)) {
211
+ if (!line.trim())
212
+ continue;
213
+ let parsed;
214
+ try {
215
+ parsed = JSON.parse(line);
216
+ } catch {
217
+ continue;
218
+ }
219
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
220
+ continue;
221
+ entries.push({
222
+ type: "type" in parsed && typeof parsed.type === "string" ? parsed.type : "",
223
+ ..."customType" in parsed && typeof parsed.customType === "string" ? { customType: parsed.customType } : {},
224
+ ..."data" in parsed ? { data: parsed.data } : {}
225
+ });
226
+ }
227
+ return entries;
228
+ }
229
+ function recordFromProjection(runId, projection, presence) {
230
+ const record = projection.record;
231
+ const status = projection.status ?? (presence.stale ? "stale" : presence.live ? "running" : "unknown");
232
+ const taskId = stringOrNull(record.taskId) ?? presence.fallbackTaskId ?? null;
233
+ const title = stringOrNull(record.title) ?? stringOrNull(presence.title) ?? (taskId ? `Run ${taskId}` : `Rig run ${runId}`);
234
+ return {
235
+ runId,
236
+ taskId,
237
+ title,
238
+ status,
239
+ source: presence.source,
240
+ live: presence.live,
241
+ stale: presence.stale,
242
+ startedAt: stringOrNull(record.startedAt) ?? presence.startedAt ?? null,
243
+ updatedAt: stringOrNull(record.updatedAt) ?? presence.updatedAt ?? projection.lastEventAt ?? null,
244
+ completedAt: stringOrNull(record.completedAt),
245
+ joinLink: presence.joinLink ?? null,
246
+ webLink: presence.webLink ?? null,
247
+ relayUrl: presence.relayUrl ?? null,
248
+ sessionPath: stringOrNull(record.sessionPath) ?? presence.sessionPath ?? null,
249
+ prUrl: stringOrNull(record.prUrl),
250
+ worktreePath: stringOrNull(record.worktreePath),
251
+ pendingApprovals: projection.pendingApprovals.length,
252
+ pendingInputs: projection.pendingUserInputs.length,
253
+ steeringCount: projection.steeringCount,
254
+ stallCount: projection.stallCount,
255
+ errorSummary: summarizeUsefulRunError(projection),
256
+ projection
257
+ };
258
+ }
259
+ function recordFromLiveCollab(collab) {
260
+ const runId = collab.sessionId;
261
+ const sessionPath = stringOrNull(collab.sessionPath);
262
+ const projection = sessionPath ? foldRunSessionEntries(readSessionRunEntries(sessionPath), runId) : EMPTY_PROJECTION;
263
+ return recordFromProjection(runId, projection, {
264
+ source: sessionPath ? "local" : "remote",
265
+ live: !collab.stale,
266
+ stale: Boolean(collab.stale),
267
+ title: collab.title,
268
+ joinLink: stringOrNull(collab.joinLink),
269
+ webLink: stringOrNull(collab.webLink),
270
+ relayUrl: stringOrNull(collab.relayUrl),
271
+ sessionPath,
272
+ startedAt: stringOrNull(collab.startedAt),
273
+ updatedAt: stringOrNull(collab.updatedAt)
274
+ });
275
+ }
276
+ function recordFromRuntime(runtime) {
277
+ const sessionPath = newestSessionFile(runtime.sessionDir ?? "");
278
+ if (!sessionPath)
279
+ return null;
280
+ const projection = foldRunSessionEntries(readSessionRunEntries(sessionPath), runtime.id);
281
+ if (projection.lastSeq === 0)
282
+ return null;
283
+ return recordFromProjection(sessionIdFromSessionFile2(sessionPath) ?? runtime.id, projection, {
284
+ source: "local",
285
+ live: false,
286
+ stale: false,
287
+ sessionPath,
288
+ fallbackTaskId: stringOrNull(runtime.taskId)
289
+ });
290
+ }
291
+ function sortByRecency(records) {
292
+ return [...records].sort((a, b) => {
293
+ const at = Date.parse(b.updatedAt ?? b.startedAt ?? "") || 0;
294
+ const bt = Date.parse(a.updatedAt ?? a.startedAt ?? "") || 0;
295
+ return at - bt;
296
+ });
297
+ }
298
+ async function listRunProjections(projectRoot, filter = {}) {
299
+ const byRunId = new Map;
300
+ let live = [];
301
+ try {
302
+ live = await listActiveRunCollab(filter);
303
+ } catch {
304
+ live = [];
305
+ }
306
+ for (const collab of live) {
307
+ const record = recordFromLiveCollab(collab);
308
+ byRunId.set(record.runId, record);
309
+ }
310
+ let runtimes = [];
311
+ try {
312
+ runtimes = await listAgentRuntimes2(projectRoot);
313
+ } catch {
314
+ runtimes = [];
315
+ }
316
+ for (const runtime of runtimes) {
317
+ const record = recordFromRuntime(runtime);
318
+ if (!record)
319
+ continue;
320
+ const sessionId = sessionIdFromSessionFile2(record.sessionPath);
321
+ const liveMatch = sessionId ? byRunId.get(sessionId) : undefined;
322
+ if (liveMatch) {
323
+ if (liveMatch.source === "remote" || !liveMatch.sessionPath) {
324
+ byRunId.set(liveMatch.runId, { ...liveMatch, sessionPath: record.sessionPath, source: "local" });
325
+ }
326
+ continue;
327
+ }
328
+ if (byRunId.has(runtime.id))
329
+ continue;
330
+ byRunId.set(record.runId, record);
331
+ }
332
+ return sortByRecency([...byRunId.values()]);
333
+ }
334
+ async function getRunProjection(projectRoot, runId, filter = {}) {
335
+ const runs = await listRunProjections(projectRoot, filter);
336
+ return runs.find((run) => run.runId === runId) ?? runs.find((run) => run.runId.startsWith(runId)) ?? runs.find((run) => run.taskId === runId) ?? null;
337
+ }
338
+ async function resolveRunJoinTarget(projectRoot, runId, filter = {}) {
339
+ const run = await getRunProjection(projectRoot, runId, filter);
340
+ if (!run || !run.joinLink)
341
+ return null;
342
+ return { runId: run.runId, taskId: run.taskId, joinLink: run.joinLink, cwd: run.sessionPath, stale: run.stale };
343
+ }
344
+ export {
345
+ resolveRunJoinTarget,
346
+ readSessionRunEntries,
347
+ listRunProjections,
348
+ getRunProjection
349
+ };
@@ -0,0 +1,3 @@
1
+ export declare const RUN_GROUP_SUBCOMMANDS: readonly string[];
2
+ /** True when `rig run <first>` addresses the observe/control group (not a task dispatch). */
3
+ export declare function isRunGroupInvocation(first: string | undefined): boolean;
@@ -0,0 +1,31 @@
1
+ // @bun
2
+ // packages/cli/src/commands/_run-subcommands.ts
3
+ var RUN_GROUP_SUBCOMMANDS = [
4
+ "list",
5
+ "status",
6
+ "start",
7
+ "start-serial",
8
+ "start-parallel",
9
+ "show",
10
+ "timeline",
11
+ "replay",
12
+ "attach",
13
+ "steer",
14
+ "stop",
15
+ "resume",
16
+ "restart",
17
+ "delete",
18
+ "cleanup"
19
+ ];
20
+ var RUN_GROUP_SUBCOMMAND_SET = new Set(RUN_GROUP_SUBCOMMANDS);
21
+ function isRunGroupInvocation(first) {
22
+ if (first === undefined)
23
+ return true;
24
+ if (first === "--help" || first === "-h" || first === "help")
25
+ return true;
26
+ return RUN_GROUP_SUBCOMMAND_SET.has(first);
27
+ }
28
+ export {
29
+ isRunGroupInvocation,
30
+ RUN_GROUP_SUBCOMMANDS
31
+ };
@@ -0,0 +1,25 @@
1
+ export declare const SPINNER_FRAMES: readonly ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
2
+ export type TtySpinner = {
3
+ setLabel(label: string): void;
4
+ /** Erase the spinner line so other output can print cleanly. */
5
+ pause(): void;
6
+ /** Resume rendering after pause(). */
7
+ resume(): void;
8
+ /** Stop for good; optionally leave a final line. */
9
+ stop(finalLine?: string): void;
10
+ };
11
+ /**
12
+ * A line-rewriting spinner for async CLI waits. On non-TTY outputs it prints
13
+ * the label once (and label changes) so logs stay readable without ANSI.
14
+ */
15
+ export declare function createTtySpinner(input: {
16
+ label: string;
17
+ output?: Pick<NodeJS.WriteStream, "write"> & {
18
+ readonly isTTY?: boolean;
19
+ };
20
+ intervalMs?: number;
21
+ /** Frame glyph cycle; defaults to SPINNER_FRAMES. */
22
+ frames?: readonly string[];
23
+ /** Optional glyph decorator (e.g. color), applied on TTY renders only. */
24
+ styleFrame?: (frame: string) => string;
25
+ }): TtySpinner;
@@ -0,0 +1,65 @@
1
+ // @bun
2
+ // packages/cli/src/commands/_spinner.ts
3
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4
+ function createTtySpinner(input) {
5
+ const output = input.output ?? process.stdout;
6
+ const isTty = output.isTTY === true;
7
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
8
+ let label = input.label;
9
+ let frame = 0;
10
+ let paused = false;
11
+ let stopped = false;
12
+ let lastPrintedLabel = "";
13
+ const render = () => {
14
+ if (stopped || paused)
15
+ return;
16
+ if (!isTty) {
17
+ if (label !== lastPrintedLabel) {
18
+ output.write(`${label}
19
+ `);
20
+ lastPrintedLabel = label;
21
+ }
22
+ return;
23
+ }
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}`);
27
+ };
28
+ const clearLine = () => {
29
+ if (isTty)
30
+ output.write("\r\x1B[2K");
31
+ };
32
+ render();
33
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 16) : null;
34
+ return {
35
+ setLabel(next) {
36
+ label = next;
37
+ render();
38
+ },
39
+ pause() {
40
+ paused = true;
41
+ clearLine();
42
+ },
43
+ resume() {
44
+ if (stopped)
45
+ return;
46
+ paused = false;
47
+ render();
48
+ },
49
+ stop(finalLine) {
50
+ if (stopped)
51
+ return;
52
+ stopped = true;
53
+ if (timer)
54
+ clearInterval(timer);
55
+ clearLine();
56
+ if (finalLine)
57
+ output.write(`${finalLine}
58
+ `);
59
+ }
60
+ };
61
+ }
62
+ export {
63
+ createTtySpinner,
64
+ SPINNER_FRAMES
65
+ };
@@ -0,0 +1,3 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import type { CommandOutcome } from "@rig/runtime";
3
+ export declare function executeAgent(context: RunnerContext, args: string[]): Promise<CommandOutcome>;