@gh-symphony/cli 0.0.16 → 0.0.18

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getGhToken
4
- } from "./chunk-JO3AXHQI.js";
4
+ } from "./chunk-7UBUBSMH.js";
5
5
  import {
6
6
  bold,
7
7
  cyan,
@@ -17,7 +17,7 @@ import {
17
17
  createStore,
18
18
  releaseProjectLock,
19
19
  resolveOrchestratorLogLevel
20
- } from "./chunk-EFMFGOWM.js";
20
+ } from "./chunk-LZE6YUSB.js";
21
21
  import {
22
22
  deriveIssueWorkspaceKeyFromIdentifier,
23
23
  isFileMissing,
@@ -26,14 +26,14 @@ import {
26
26
  parseRecentEvents,
27
27
  readJsonFile,
28
28
  safeReadDir
29
- } from "./chunk-TF3QNWNC.js";
29
+ } from "./chunk-OL73UN2X.js";
30
30
  import {
31
31
  resolveRuntimeRoot
32
32
  } from "./chunk-5NV3LSAJ.js";
33
33
  import {
34
34
  handleMissingManagedProjectConfig,
35
35
  resolveManagedProjectConfig
36
- } from "./chunk-TH5QPO3Y.js";
36
+ } from "./chunk-C7G7RJ4G.js";
37
37
  import {
38
38
  daemonPidPath,
39
39
  httpStatusPath,
@@ -91,7 +91,8 @@ var DashboardFsReader = class {
91
91
  if (issues) {
92
92
  return issues.map((issue) => ({
93
93
  ...issue,
94
- completedOnce: issue.completedOnce ?? false
94
+ completedOnce: issue.completedOnce ?? false,
95
+ failureRetryCount: issue.failureRetryCount ?? 0
95
96
  }));
96
97
  }
97
98
  const legacyLeases = await readJsonFile(join(this.projectDir(), "leases.json")) ?? [];
@@ -100,6 +101,7 @@ var DashboardFsReader = class {
100
101
  identifier: lease.issueIdentifier,
101
102
  workspaceKey: deriveIssueWorkspaceKeyFromIdentifier(lease.issueIdentifier),
102
103
  completedOnce: false,
104
+ failureRetryCount: 0,
103
105
  state: lease.status === "active" ? "claimed" : "released",
104
106
  currentRunId: lease.status === "active" ? lease.runId : null,
105
107
  retryEntry: null,
@@ -114,6 +116,24 @@ var DashboardFsReader = class {
114
116
  const runs = await mapWithConcurrency(runIds, RUN_RECORD_LOAD_CONCURRENCY, (runId) => this.loadRun(runId));
115
117
  return runs.filter((run) => Boolean(run));
116
118
  }
119
+ async loadRunsForIssue(issueId, issueIdentifier) {
120
+ const runIds = await safeReadDir(join(this.projectDir(), "runs"));
121
+ const runs = await mapWithConcurrency(runIds, RUN_RECORD_LOAD_CONCURRENCY, async (runId) => {
122
+ try {
123
+ const run = await this.loadRun(runId);
124
+ if (!run) {
125
+ return null;
126
+ }
127
+ return run.issueId === issueId || run.issueIdentifier === issueIdentifier ? run : null;
128
+ } catch (error) {
129
+ if (isFileMissing(error)) {
130
+ return null;
131
+ }
132
+ return null;
133
+ }
134
+ });
135
+ return runs.filter((run) => Boolean(run));
136
+ }
117
137
  async loadRecentRunEvents(runId, limit = DEFAULT_RECENT_EVENT_LIMIT) {
118
138
  if (limit <= 0) {
119
139
  return [];
@@ -170,64 +190,81 @@ async function statusForIssue(reader, issueIdentifier) {
170
190
  return null;
171
191
  }
172
192
  const currentRunCandidate = issueRecord.currentRunId ? await reader.loadRun(issueRecord.currentRunId) : null;
173
- const currentRun = isMatchingIssueRun(currentRunCandidate, reader.projectId, issueRecord.issueId, issueIdentifier) ? currentRunCandidate : await findLatestRunForIssue(reader, issueRecord.issueId, issueIdentifier);
174
- const recentEvents = currentRun === null ? [] : await reader.loadRecentRunEvents(currentRun.runId);
193
+ const currentRun = isMatchingIssueRun(currentRunCandidate, reader.projectId, issueRecord.issueId, issueIdentifier) ? currentRunCandidate : null;
194
+ const issueRuns = currentRun === null ? await reader.loadRunsForIssue(issueRecord.issueId, issueIdentifier) : currentRun.tokenUsage ? await reader.loadRunsForIssue(issueRecord.issueId, issueIdentifier) : null;
195
+ const resolvedRun = currentRun ?? findLatestRunForIssue(issueRuns ?? []);
196
+ const recentEvents = resolvedRun === null ? [] : await reader.loadRecentRunEvents(resolvedRun.runId);
197
+ const cumulativeTokens = aggregateIssueTokenUsage(issueRuns ?? []);
175
198
  const latestEventMessage = recentEvents[recentEvents.length - 1]?.message ?? null;
176
- const currentAttempt = currentRun?.attempt ?? issueRecord.retryEntry?.attempt ?? 0;
199
+ const currentAttempt = resolvedRun?.attempt ?? issueRecord.retryEntry?.attempt ?? 0;
177
200
  return {
178
201
  issue_identifier: issueRecord.identifier,
179
202
  issue_id: issueRecord.issueId,
180
- status: currentRun?.status ?? mapIssueOrchestrationStateToStatus(issueRecord.state),
203
+ status: resolvedRun?.status ?? mapIssueOrchestrationStateToStatus(issueRecord.state),
181
204
  workspace: {
182
- path: currentRun?.workingDirectory ?? null
205
+ path: resolvedRun?.workingDirectory ?? null
183
206
  },
184
207
  attempts: {
185
208
  restart_count: Math.max(0, currentAttempt - 1),
186
209
  current_retry_attempt: currentAttempt
187
210
  },
188
- running: currentRun === null ? null : {
189
- session_id: currentRun.runtimeSession?.sessionId ?? null,
190
- turn_count: currentRun.turnCount ?? null,
191
- state: currentRun.issueState ?? null,
192
- started_at: currentRun.startedAt ?? null,
193
- last_event: currentRun.lastEvent ?? null,
211
+ running: resolvedRun === null ? null : {
212
+ session_id: resolvedRun.runtimeSession?.sessionId ?? null,
213
+ turn_count: resolvedRun.turnCount ?? null,
214
+ state: resolvedRun.issueState ?? null,
215
+ started_at: resolvedRun.startedAt ?? null,
216
+ last_event: resolvedRun.lastEvent ?? null,
194
217
  last_message: latestEventMessage,
195
- last_event_at: currentRun.lastEventAt ?? null,
196
- tokens: currentRun.tokenUsage ? {
197
- input_tokens: currentRun.tokenUsage.inputTokens,
198
- output_tokens: currentRun.tokenUsage.outputTokens,
199
- total_tokens: currentRun.tokenUsage.totalTokens
218
+ last_event_at: resolvedRun.lastEventAt ?? null,
219
+ tokens: resolvedRun.tokenUsage ? {
220
+ input_tokens: resolvedRun.tokenUsage.inputTokens,
221
+ output_tokens: resolvedRun.tokenUsage.outputTokens,
222
+ total_tokens: resolvedRun.tokenUsage.totalTokens,
223
+ cumulative_input_tokens: cumulativeTokens.inputTokens,
224
+ cumulative_output_tokens: cumulativeTokens.outputTokens,
225
+ cumulative_total_tokens: cumulativeTokens.totalTokens
200
226
  } : null
201
227
  },
202
- retry: currentRun?.nextRetryAt ?? issueRecord.retryEntry?.dueAt ? {
203
- due_at: currentRun?.nextRetryAt ?? issueRecord.retryEntry?.dueAt ?? "",
204
- kind: currentRun?.retryKind ?? null,
205
- error: currentRun?.lastError ?? issueRecord.retryEntry?.error ?? null
228
+ retry: resolvedRun?.nextRetryAt ?? issueRecord.retryEntry?.dueAt ? {
229
+ due_at: resolvedRun?.nextRetryAt ?? issueRecord.retryEntry?.dueAt ?? "",
230
+ kind: resolvedRun?.retryKind ?? null,
231
+ error: resolvedRun?.lastError ?? issueRecord.retryEntry?.error ?? null
206
232
  } : null,
207
233
  logs: {
208
- codex_session_logs: currentRun === null ? [] : [
234
+ codex_session_logs: resolvedRun === null ? [] : [
209
235
  {
210
236
  label: "worker",
211
- path: join(reader.runDir(currentRun.runId), "worker.log"),
237
+ path: join(reader.runDir(resolvedRun.runId), "worker.log"),
212
238
  url: null
213
239
  }
214
240
  ]
215
241
  },
216
242
  recent_events: recentEvents,
217
- last_error: currentRun?.lastError ?? issueRecord.retryEntry?.error ?? null,
243
+ last_error: resolvedRun?.lastError ?? issueRecord.retryEntry?.error ?? null,
218
244
  tracked: {
219
245
  issue_orchestration_state: issueRecord.state,
220
246
  current_run_id: issueRecord.currentRunId,
221
247
  workspace_key: issueRecord.workspaceKey,
222
248
  completed_once: issueRecord.completedOnce,
223
- run_phase: currentRun?.runPhase ?? null,
224
- execution_phase: currentRun?.executionPhase ?? null
249
+ run_phase: resolvedRun?.runPhase ?? null,
250
+ execution_phase: resolvedRun?.executionPhase ?? null
225
251
  }
226
252
  };
227
253
  }
228
- async function findLatestRunForIssue(reader, issueId, issueIdentifier) {
229
- const matchingRuns = (await reader.loadAllRuns()).filter((run) => run.issueId === issueId || run.issueIdentifier === issueIdentifier).sort((left, right) => new Date(right.updatedAt).getTime() - new Date(left.updatedAt).getTime());
230
- return matchingRuns[0] ?? null;
254
+ function aggregateIssueTokenUsage(runs) {
255
+ return runs.reduce((total, run) => ({
256
+ inputTokens: total.inputTokens + (run.tokenUsage?.inputTokens ?? 0),
257
+ outputTokens: total.outputTokens + (run.tokenUsage?.outputTokens ?? 0),
258
+ totalTokens: total.totalTokens + (run.tokenUsage?.totalTokens ?? 0)
259
+ }), {
260
+ inputTokens: 0,
261
+ outputTokens: 0,
262
+ totalTokens: 0
263
+ });
264
+ }
265
+ function findLatestRunForIssue(matchingRuns) {
266
+ const sortedRuns = [...matchingRuns].sort((left, right) => new Date(right.updatedAt).getTime() - new Date(left.updatedAt).getTime());
267
+ return sortedRuns[0] ?? null;
231
268
  }
232
269
  function assertValidDashboardProjectId(projectId) {
233
270
  if (projectId.length === 0 || projectId === "." || projectId === ".." || projectId.includes("/") || projectId.includes("\\")) {