@gh-symphony/cli 0.0.22 → 0.1.2

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 (36) hide show
  1. package/README.md +72 -77
  2. package/dist/{chunk-IWFX2FMA.js → chunk-6I753NYO.js} +4 -1
  3. package/dist/{workflow-L3KT6HB7.js → chunk-B4ZJMAZL.js} +27 -19
  4. package/dist/{chunk-2TSM3INR.js → chunk-DLZAJXZL.js} +575 -12
  5. package/dist/chunk-GHVDABFO.js +235 -0
  6. package/dist/{chunk-EEQQWTXS.js → chunk-GPRCOJDJ.js} +158 -75
  7. package/dist/{chunk-36KYEDEO.js → chunk-MVRF7BES.js} +1 -10
  8. package/dist/{chunk-2UW7NQLX.js → chunk-VFHMHHZW.js} +1 -1
  9. package/dist/{chunk-HMLBBZNY.js → chunk-WM2B6BJ7.js} +16 -71
  10. package/dist/{chunk-QIRE2VXS.js → chunk-WOVNN5NW.js} +16 -17
  11. package/dist/{chunk-C67H3OUL.js → chunk-Z3NZOPLZ.js} +0 -81
  12. package/dist/{config-cmd-Z3A7V6NC.js → config-cmd-2ADPUYWA.js} +1 -1
  13. package/dist/{doctor-EJUMPBMW.js → doctor-EEPNFCGF.js} +464 -40
  14. package/dist/index.js +340 -294
  15. package/dist/{chunk-PUDXVBSN.js → repo-RX4OK7XH.js} +5944 -3001
  16. package/dist/{setup-TZJSM3QV.js → setup-XNHHRBGU.js} +57 -92
  17. package/dist/{upgrade-O33S2SJK.js → upgrade-NS53EO2B.js} +2 -2
  18. package/dist/{version-CW54Q7BK.js → version-2RHFZ5CI.js} +1 -1
  19. package/dist/worker-entry.js +10 -5
  20. package/dist/workflow-26QNZZWH.js +22 -0
  21. package/package.json +4 -4
  22. package/dist/chunk-DDL4BWSL.js +0 -146
  23. package/dist/chunk-DFLXHNYQ.js +0 -482
  24. package/dist/chunk-E7HYEEZD.js +0 -1318
  25. package/dist/chunk-GDE6FYN4.js +0 -26
  26. package/dist/chunk-GSX2FV3M.js +0 -103
  27. package/dist/chunk-ZHOKYUO3.js +0 -1047
  28. package/dist/init-54HMKNYI.js +0 -38
  29. package/dist/logs-GTZ4U5JE.js +0 -188
  30. package/dist/project-RMYMZSFV.js +0 -25
  31. package/dist/recover-LTLKMTRX.js +0 -133
  32. package/dist/repo-WI7GF6XQ.js +0 -749
  33. package/dist/run-IHN3ZL35.js +0 -122
  34. package/dist/start-RTAHQMR2.js +0 -19
  35. package/dist/status-F4D52OVK.js +0 -12
  36. package/dist/stop-MDKMJPVR.js +0 -10
@@ -1,482 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- blue,
4
- bold,
5
- clearScreen,
6
- cyan,
7
- dim,
8
- formatRepositoryDisplay,
9
- green,
10
- hideCursor,
11
- magenta,
12
- red,
13
- showCursor,
14
- stripAnsi,
15
- yellow
16
- } from "./chunk-36KYEDEO.js";
17
- import {
18
- resolveRuntimeRoot
19
- } from "./chunk-IWFX2FMA.js";
20
- import {
21
- rejectRemovedProjectId
22
- } from "./chunk-GDE6FYN4.js";
23
- import {
24
- handleMissingManagedProjectConfig,
25
- resolveManagedProjectConfig
26
- } from "./chunk-DDL4BWSL.js";
27
-
28
- // src/commands/status.ts
29
- import { readFile } from "fs/promises";
30
- import { join } from "path";
31
-
32
- // src/dashboard/renderer.ts
33
- var COL_ID = 24;
34
- var COL_STATUS = 14;
35
- var COL_PID = 8;
36
- var COL_AGE_TURN = 12;
37
- var COL_TOKENS = 17;
38
- var COL_SESSION = 14;
39
- var COL_ID_HEADER = COL_ID + 2;
40
- var identity = (s) => s;
41
- function makeColors(noColor) {
42
- if (noColor) {
43
- return {
44
- bold: identity,
45
- dim: identity,
46
- green: identity,
47
- red: identity,
48
- yellow: identity,
49
- cyan: identity,
50
- magenta: identity,
51
- blue: identity
52
- };
53
- }
54
- return { bold, dim, green, red, yellow, cyan, magenta, blue };
55
- }
56
- function pad(s, width, align = "left") {
57
- const visible = stripAnsi(s);
58
- if (visible.length >= width) return visible.slice(0, width);
59
- const padding = " ".repeat(width - visible.length);
60
- return align === "right" ? padding + s : s + padding;
61
- }
62
- function compactSessionId(id) {
63
- if (!id) return "\u2014";
64
- if (id.length <= 10) return id;
65
- return `${id.slice(0, 4)}...${id.slice(-6)}`;
66
- }
67
- function fmtTokens(n) {
68
- return n.toLocaleString("en-US");
69
- }
70
- function fmtTokenPair(delta, cumulative) {
71
- const left = fmtTokens(delta ?? 0);
72
- const right = fmtTokens(cumulative ?? delta ?? 0);
73
- return `${left} / ${right}`;
74
- }
75
- function fmtAge(startedAt, now) {
76
- if (!startedAt) return "0m";
77
- const diffMs = now - new Date(startedAt).getTime();
78
- if (diffMs < 0) return "0m";
79
- const totalMin = Math.floor(diffMs / 6e4);
80
- if (totalMin < 60) return `${totalMin}m`;
81
- const h = Math.floor(totalMin / 60);
82
- const m = totalMin % 60;
83
- return `${h}h ${m}m`;
84
- }
85
- function fmtRuntime(ms) {
86
- if (ms <= 0) return "0h 0m";
87
- const totalMin = Math.floor(ms / 6e4);
88
- const h = Math.floor(totalMin / 60);
89
- const m = totalMin % 60;
90
- return `${h}h ${m}m`;
91
- }
92
- function fmtRetryTime(nextRetryAt, now) {
93
- if (!nextRetryAt) return "\u2014";
94
- const diffMs = new Date(nextRetryAt).getTime() - now;
95
- if (diffMs <= 0) return "now";
96
- const totalSec = Math.ceil(diffMs / 1e3);
97
- if (totalSec < 60) return `${totalSec}s`;
98
- const m = Math.floor(totalSec / 60);
99
- const s = totalSec % 60;
100
- return s > 0 ? `${m}m ${s}s` : `${m}m`;
101
- }
102
- var COL_SEPARATORS = 6;
103
- function eventColWidth(termWidth) {
104
- const fixed = 2 + COL_ID_HEADER + COL_STATUS + COL_PID + COL_AGE_TURN + COL_TOKENS + COL_SESSION + COL_SEPARATORS;
105
- return Math.max(5, termWidth - fixed);
106
- }
107
- function statusDot(run, c) {
108
- const event = run.lastEvent;
109
- if (event === null || event === void 0 || run.status === "failed")
110
- return c.red("\u25CF");
111
- if (event === "token_count") return c.yellow("\u25CF");
112
- if (event === "task_started") return c.green("\u25CF");
113
- if (event === "turn_completed") return c.magenta("\u25CF");
114
- return c.blue("\u25CF");
115
- }
116
- function titleBar(width, c) {
117
- const title = " gh-symphony ";
118
- const side = Math.max(0, Math.floor((width - title.length) / 2));
119
- const right = Math.max(0, width - side - title.length);
120
- return c.bold("\u2550".repeat(side) + title + "\u2550".repeat(right));
121
- }
122
- function sectionDivider(label, width, c) {
123
- const prefix = `\u2500\u2500 ${label} `;
124
- const fill = "\u2500".repeat(Math.max(0, width - prefix.length));
125
- return c.dim(prefix + fill);
126
- }
127
- function buildSummaryLines(snapshots, options, c) {
128
- const now = options.now ?? Date.now();
129
- const lines = [];
130
- const totalActive = snapshots.reduce(
131
- (sum, s) => sum + s.summary.activeRuns,
132
- 0
133
- );
134
- const agentStr = options.maxAgents != null ? `${totalActive}/${options.maxAgents}` : `${totalActive}`;
135
- const totIn = snapshots.reduce(
136
- (sum, s) => sum + (s.codexTotals?.inputTokens ?? 0),
137
- 0
138
- );
139
- const totOut = snapshots.reduce(
140
- (sum, s) => sum + (s.codexTotals?.outputTokens ?? 0),
141
- 0
142
- );
143
- const totAll = snapshots.reduce(
144
- (sum, s) => sum + (s.codexTotals?.totalTokens ?? 0),
145
- 0
146
- );
147
- const allStarts = snapshots.flatMap((s) => s.activeRuns).map((r) => r.startedAt).filter((t) => t != null).map((t) => new Date(t).getTime());
148
- const runtimeMs = allStarts.length > 0 ? now - Math.min(...allStarts) : 0;
149
- const runtime = fmtRuntime(runtimeMs);
150
- lines.push(
151
- ` ${c.dim("Agents")} ${c.bold(agentStr)} ${c.dim("Runtime")} ${c.bold(runtime)} ${c.dim("Tokens")} ${fmtTokens(totIn)} in / ${fmtTokens(totOut)} out / ${c.bold(fmtTokens(totAll))} total`
152
- );
153
- const hasLimits = snapshots.some((s) => s.rateLimits != null);
154
- const limitStr = hasLimits ? "active" : "standard";
155
- lines.push(` ${c.dim("Rate Limits")} ${limitStr}`);
156
- return lines;
157
- }
158
- function tableHeaderRow(c) {
159
- const cols = [
160
- pad("ID", COL_ID_HEADER),
161
- pad("STATUS", COL_STATUS),
162
- pad("PID", COL_PID),
163
- pad("AGE/TURN", COL_AGE_TURN),
164
- pad("TOKENS", COL_TOKENS),
165
- pad("SESSION", COL_SESSION),
166
- "EVENT"
167
- ].join(" ");
168
- return ` ${c.dim(cols)}`;
169
- }
170
- function activeRunRow(run, now, evtWidth, c) {
171
- const dot = statusDot(run, c);
172
- const id = pad(run.issueIdentifier, COL_ID);
173
- const status = pad(
174
- run.issueState ?? run.executionPhase ?? "\u2014",
175
- COL_STATUS
176
- );
177
- const pid = pad(
178
- run.processId != null ? String(run.processId) : "\u2014",
179
- COL_PID
180
- );
181
- const age = fmtAge(run.startedAt, now);
182
- const turn = run.turnCount ?? 0;
183
- const ageTurn = pad(`${age}/${turn}`, COL_AGE_TURN);
184
- const tokens = pad(
185
- fmtTokenPair(
186
- run.tokenUsage?.totalTokens,
187
- run.tokenUsage?.cumulativeTotalTokens
188
- ),
189
- COL_TOKENS,
190
- "right"
191
- );
192
- const sessionId = run.runtimeSession?.sessionId ?? run.runtimeSession?.threadId ?? null;
193
- const session = pad(compactSessionId(sessionId), COL_SESSION);
194
- const event = pad(run.lastEvent ?? "\u2014", evtWidth);
195
- const columns = [id, status, pid, ageTurn, tokens, session, event].join(" ");
196
- return ` ${dot} ${columns}`;
197
- }
198
- function retryRow(entry, snapshot, now, c) {
199
- const id = entry.issueIdentifier;
200
- const kind = entry.retryKind;
201
- const timeStr = fmtRetryTime(entry.nextRetryAt, now);
202
- const matchingRun = snapshot.activeRuns.find((r) => r.runId === entry.runId);
203
- const errorHint = matchingRun?.lastEvent ?? "";
204
- return ` ${c.yellow("\u21BB")} ${id} ${kind} retrying in ${timeStr}${errorHint ? " " + errorHint : ""}`;
205
- }
206
- function renderDashboard(snapshots, options) {
207
- const width = options.terminalWidth || 115;
208
- const now = options.now ?? Date.now();
209
- const c = makeColors(options.noColor);
210
- const evtWidth = eventColWidth(width);
211
- const lines = [];
212
- lines.push(titleBar(width, c));
213
- lines.push(...buildSummaryLines(snapshots, options, c));
214
- lines.push("");
215
- for (const snap of snapshots) {
216
- const hasActiveRuns = snap.activeRuns.length > 0;
217
- const hasRetries = snap.retryQueue.length > 0;
218
- if (!hasActiveRuns && !hasRetries) continue;
219
- lines.push(
220
- sectionDivider(formatRepositoryDisplay(snap), width, c)
221
- );
222
- if (hasActiveRuns) {
223
- lines.push(tableHeaderRow(c));
224
- for (const rawRun of snap.activeRuns) {
225
- const run = rawRun;
226
- lines.push(activeRunRow(run, now, evtWidth, c));
227
- }
228
- }
229
- lines.push("");
230
- }
231
- const allRetries = [];
232
- for (const snap of snapshots) {
233
- for (const entry of snap.retryQueue) {
234
- allRetries.push({ entry, snapshot: snap });
235
- }
236
- }
237
- if (allRetries.length > 0) {
238
- lines.push(sectionDivider("Backoff Queue", width, c));
239
- for (const { entry, snapshot } of allRetries) {
240
- lines.push(retryRow(entry, snapshot, now, c));
241
- }
242
- lines.push("");
243
- }
244
- const result = lines.map((line) => {
245
- const visible = stripAnsi(line);
246
- if (visible.length <= width) return line;
247
- return visible.slice(0, width);
248
- });
249
- return result.join("\n");
250
- }
251
-
252
- // src/commands/status.ts
253
- function healthIcon(health) {
254
- switch (health) {
255
- case "idle":
256
- case "running":
257
- return green("\u25CF");
258
- case "degraded":
259
- return red("\u25CF");
260
- }
261
- }
262
- function relativeTime(isoString) {
263
- const now = /* @__PURE__ */ new Date();
264
- const then = new Date(isoString);
265
- const diffMs = now.getTime() - then.getTime();
266
- const diffS = Math.floor(diffMs / 1e3);
267
- const diffM = Math.floor(diffS / 60);
268
- const diffH = Math.floor(diffM / 60);
269
- if (diffS < 60) return `${diffS}s ago`;
270
- if (diffM < 60) return `${diffM}m ago`;
271
- return `${diffH}h ago`;
272
- }
273
- function truncate(s, len) {
274
- if (s.length <= len) return s;
275
- return s.slice(0, len - 3) + "...";
276
- }
277
- function formatTokenPair(delta, cumulative) {
278
- return `${delta.toLocaleString("en-US")} / ${cumulative.toLocaleString("en-US")}`;
279
- }
280
- function resolveProjectTokenDelta(snapshot) {
281
- return snapshot.activeRuns.reduce(
282
- (sum, run) => sum + (run.tokenUsage?.totalTokens ?? 0),
283
- 0
284
- );
285
- }
286
- function renderLegacyStatus(snapshot, noColor) {
287
- const apply = noColor ? (s) => stripAnsi(s) : (s) => s;
288
- const lines = [];
289
- const headerTitle = `gh-symphony \u2219 ${formatRepositoryDisplay(snapshot)}`;
290
- const headerWidth = 45;
291
- const headerPadding = Math.max(
292
- 0,
293
- headerWidth - stripAnsi(headerTitle).length
294
- );
295
- lines.push("\u256D" + "\u2500".repeat(headerWidth) + "\u256E");
296
- lines.push(
297
- "\u2502 " + apply(bold(headerTitle)) + " ".repeat(headerPadding) + "\u2502"
298
- );
299
- lines.push("\u2570" + "\u2500".repeat(headerWidth) + "\u256F");
300
- lines.push("");
301
- const healthStr = apply(
302
- `${healthIcon(snapshot.health)} Health ${snapshot.health}`
303
- );
304
- const lastTickStr = apply(`Last tick ${relativeTime(snapshot.lastTickAt)}`);
305
- lines.push(
306
- ` ${healthStr}${" ".repeat(Math.max(0, 30 - stripAnsi(healthStr).length))}${lastTickStr}`
307
- );
308
- lines.push("");
309
- const dispatchedStr = apply(`Dispatched ${snapshot.summary.dispatched}`);
310
- const activeRunsStr = apply(`Active Runs ${snapshot.summary.activeRuns}`);
311
- const suppressedStr = apply(`Suppressed ${snapshot.summary.suppressed}`);
312
- const recoveredStr = apply(`Recovered ${snapshot.summary.recovered}`);
313
- lines.push(
314
- ` ${dispatchedStr}${" ".repeat(Math.max(0, 20 - stripAnsi(dispatchedStr).length))}${activeRunsStr}`
315
- );
316
- lines.push(
317
- ` ${suppressedStr}${" ".repeat(Math.max(0, 20 - stripAnsi(suppressedStr).length))}${recoveredStr}`
318
- );
319
- lines.push("");
320
- if (snapshot.activeRuns.length > 0) {
321
- lines.push(" Active Runs:");
322
- for (const run of snapshot.activeRuns) {
323
- const runIdDisplay = truncate(run.runId, 12);
324
- const stateStr = apply(cyan(run.issueState));
325
- const statusColor = run.status === "running" ? green : run.status === "failed" ? red : run.status === "succeeded" ? green : dim;
326
- const statusStr = apply(statusColor(run.status));
327
- lines.push(
328
- ` ${runIdDisplay} ${run.issueIdentifier} ${stateStr} ${statusStr}`
329
- );
330
- }
331
- lines.push("");
332
- } else {
333
- lines.push(" No active runs.");
334
- lines.push("");
335
- }
336
- if (snapshot.retryQueue.length > 0) {
337
- lines.push(" Retry Queue:");
338
- for (const retry of snapshot.retryQueue) {
339
- const runIdDisplay = truncate(retry.runId, 12);
340
- const nextRetryDisplay = retry.nextRetryAt ? relativeTime(retry.nextRetryAt) : "pending";
341
- lines.push(
342
- ` ${runIdDisplay} ${retry.issueIdentifier} ${apply(yellow(retry.retryKind))} ${nextRetryDisplay}`
343
- );
344
- }
345
- lines.push("");
346
- }
347
- if (snapshot.lastError) {
348
- lines.push(apply(red(` \u2717 ${snapshot.lastError}`)));
349
- lines.push("");
350
- }
351
- if (snapshot.codexTotals) {
352
- const tokenDelta = resolveProjectTokenDelta(snapshot);
353
- const tokenStr = apply(
354
- `Tokens: ${formatTokenPair(tokenDelta, snapshot.codexTotals.totalTokens)} total`
355
- );
356
- lines.push(` ${tokenStr}`);
357
- } else {
358
- lines.push(" Tokens: 0 / 0 total");
359
- }
360
- return lines.join("\n");
361
- }
362
- function parseStatusArgs(args) {
363
- const parsed = {
364
- watch: false
365
- };
366
- for (let i = 0; i < args.length; i += 1) {
367
- const arg = args[i];
368
- if (arg === "--watch" || arg === "-w") {
369
- parsed.watch = true;
370
- continue;
371
- }
372
- if (arg?.startsWith("-")) {
373
- parsed.error = `Unknown option '${arg}'`;
374
- return parsed;
375
- }
376
- }
377
- return parsed;
378
- }
379
- async function readStatusSnapshot(runtimeRoot, projectId) {
380
- for (const statusPath of [
381
- join(runtimeRoot, "status.json"),
382
- join(runtimeRoot, "projects", projectId, "status.json")
383
- ]) {
384
- try {
385
- const content = await readFile(statusPath, "utf-8");
386
- return JSON.parse(content);
387
- } catch {
388
- }
389
- }
390
- return null;
391
- }
392
- var handler = async (args, options) => {
393
- if (rejectRemovedProjectId(args)) {
394
- return;
395
- }
396
- const parsed = parseStatusArgs(args);
397
- if (parsed.error) {
398
- process.stderr.write(`${parsed.error}
399
- `);
400
- process.stderr.write("Usage: gh-symphony status [--watch]\n");
401
- process.exitCode = 2;
402
- return;
403
- }
404
- const projectConfig = await resolveManagedProjectConfig({
405
- configDir: options.configDir,
406
- requestedProjectId: void 0
407
- });
408
- if (!projectConfig) {
409
- handleMissingManagedProjectConfig();
410
- return;
411
- }
412
- const runtimeRoot = resolveRuntimeRoot(options.configDir);
413
- const projectId = projectConfig.projectId;
414
- if (parsed.watch) {
415
- const isTTY = process.stdout.isTTY === true;
416
- let terminalWidth = process.stdout.columns ?? 115;
417
- let runPromise = null;
418
- const run = async () => {
419
- const snapshot2 = await readStatusSnapshot(runtimeRoot, projectId);
420
- if (options.json || !isTTY) {
421
- process.stdout.write(JSON.stringify(snapshot2, null, 2) + "\n");
422
- } else {
423
- if (!snapshot2) {
424
- process.stdout.write(
425
- clearScreen() + "Unable to read status snapshot.\n"
426
- );
427
- return;
428
- }
429
- process.stdout.write(
430
- clearScreen() + renderDashboard([snapshot2], {
431
- terminalWidth,
432
- noColor: options.noColor
433
- }) + "\n"
434
- );
435
- }
436
- };
437
- const tick = () => {
438
- if (runPromise) {
439
- return;
440
- }
441
- runPromise = run().finally(() => {
442
- runPromise = null;
443
- });
444
- };
445
- if (isTTY) {
446
- process.stdout.write(hideCursor());
447
- }
448
- tick();
449
- await runPromise;
450
- const interval = setInterval(tick, 2e3);
451
- process.on("SIGWINCH", () => {
452
- terminalWidth = process.stdout.columns ?? terminalWidth;
453
- });
454
- const shutdown = () => {
455
- clearInterval(interval);
456
- process.stdout.write(showCursor() + "\n");
457
- process.exit(0);
458
- };
459
- process.on("SIGINT", shutdown);
460
- process.on("SIGTERM", shutdown);
461
- await new Promise(() => {
462
- });
463
- }
464
- const snapshot = await readStatusSnapshot(runtimeRoot, projectId);
465
- if (snapshot) {
466
- if (options.json) {
467
- process.stdout.write(JSON.stringify(snapshot, null, 2) + "\n");
468
- } else {
469
- process.stdout.write(
470
- renderLegacyStatus(snapshot, options.noColor) + "\n"
471
- );
472
- }
473
- } else {
474
- process.stderr.write("Unable to read status snapshot.\n");
475
- process.exitCode = 1;
476
- }
477
- };
478
- var status_default = handler;
479
-
480
- export {
481
- status_default
482
- };