@gh-symphony/cli 0.0.15 → 0.0.17

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,1086 +1,46 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_WORKFLOW_LIFECYCLE,
4
+ WorkflowConfigStore,
5
+ buildHookEnv,
6
+ buildProjectSnapshot,
7
+ buildPromptVariables,
8
+ createDefaultWorkflowResolution,
9
+ createInvalidWorkflowResolution,
10
+ deriveIssueWorkspaceKey,
11
+ deriveIssueWorkspaceKeyFromIdentifier,
12
+ deriveLegacyIssueWorkspaceKey,
13
+ executeWorkspaceHook,
14
+ isFileMissing,
15
+ isMatchingIssueRun,
16
+ isOrchestratorChannelEvent,
17
+ isStateActive,
18
+ isStateTerminal,
19
+ mapIssueOrchestrationStateToStatus,
20
+ matchesWorkflowState,
21
+ parseRecentEvents,
22
+ readEnvFile,
23
+ readJsonFile,
24
+ renderPrompt,
25
+ resolveIssueWorkspaceDirectory,
26
+ safeReadDir,
27
+ scheduleRetryAt
28
+ } from "./chunk-TF3QNWNC.js";
2
29
 
3
30
  // ../orchestrator/dist/service.js
4
- import { mkdir as mkdir3, readFile as readFile5, rm as rm3, writeFile as writeFile3 } from "fs/promises";
31
+ import { mkdir as mkdir3, readFile as readFile3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
5
32
  import { createWriteStream, mkdirSync } from "fs";
6
- import { spawn as spawn3 } from "child_process";
7
- import { join as join4 } from "path";
33
+ import { spawn as spawn2 } from "child_process";
34
+ import { join as join3 } from "path";
8
35
  import { StringDecoder } from "string_decoder";
9
36
  import { fileURLToPath } from "url";
10
37
 
11
- // ../core/dist/contracts/status-surface.js
12
- var WORKFLOW_EXECUTION_PHASES = [
13
- "planning",
14
- "human-review",
15
- "implementation",
16
- "awaiting-merge",
17
- "completed"
18
- ];
19
- function isWorkflowExecutionPhase(value) {
20
- return typeof value === "string" && WORKFLOW_EXECUTION_PHASES.includes(value);
21
- }
22
- var SESSION_EXIT_CLASSIFICATIONS = [
23
- "completed",
24
- "budget-exceeded",
25
- "convergence-detected",
26
- "max-turns-reached",
27
- "user-input-required",
28
- "timeout",
29
- "error"
30
- ];
31
- function isSessionExitClassification(value) {
32
- return typeof value === "string" && SESSION_EXIT_CLASSIFICATIONS.includes(value);
33
- }
34
-
35
- // ../core/dist/contracts/run-attempt-phase.js
36
- var RUN_ATTEMPT_PHASES = [
37
- "preparing_workspace",
38
- "building_prompt",
39
- "launching_agent",
40
- "initializing_session",
41
- "streaming_turn",
42
- "finishing",
43
- "succeeded",
44
- "failed",
45
- "timed_out",
46
- "stalled",
47
- "canceled_by_reconciliation"
48
- ];
49
- function isRunAttemptPhase(value) {
50
- return typeof value === "string" && RUN_ATTEMPT_PHASES.includes(value);
51
- }
52
-
53
- // ../core/dist/contracts/orchestrator-channel.js
54
- function isRecord(value) {
55
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
56
- }
57
- function isTokenUsage(value) {
58
- if (!isRecord(value)) {
59
- return false;
60
- }
61
- return typeof value.inputTokens === "number" && typeof value.outputTokens === "number" && typeof value.totalTokens === "number";
62
- }
63
- function isSessionInfo(value) {
64
- if (!isRecord(value)) {
65
- return false;
66
- }
67
- return (typeof value.threadId === "string" || value.threadId === null) && (typeof value.turnId === "string" || value.turnId === null) && typeof value.turnCount === "number" && (typeof value.sessionId === "string" || value.sessionId === null) && (!("exitClassification" in value) || value.exitClassification === void 0 || value.exitClassification === null || isSessionExitClassification(value.exitClassification));
68
- }
69
- function isNullableString(value) {
70
- return typeof value === "string" || value === null;
71
- }
72
- function isTurnEventBase(value) {
73
- return typeof value.startedAt === "string" && isNullableString(value.threadId) && isNullableString(value.turnId) && typeof value.turnCount === "number" && isNullableString(value.sessionId);
74
- }
75
- function isOrchestratorChannelEvent(value) {
76
- if (!isRecord(value)) {
77
- return false;
78
- }
79
- if (typeof value.issueId !== "string") {
80
- return false;
81
- }
82
- if (value.type === "codex_update") {
83
- if (typeof value.lastEventAt !== "string") {
84
- return false;
85
- }
86
- if ("event" in value && value.event !== void 0 && typeof value.event !== "string") {
87
- return false;
88
- }
89
- if ("tokenUsage" in value && value.tokenUsage !== void 0 && !isTokenUsage(value.tokenUsage)) {
90
- return false;
91
- }
92
- if ("rateLimits" in value && value.rateLimits !== void 0 && !isRecord(value.rateLimits)) {
93
- return false;
94
- }
95
- if ("sessionInfo" in value && value.sessionInfo !== void 0 && !isSessionInfo(value.sessionInfo)) {
96
- return false;
97
- }
98
- if ("executionPhase" in value && value.executionPhase !== void 0 && value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
99
- return false;
100
- }
101
- if ("runPhase" in value && value.runPhase !== void 0 && value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
102
- return false;
103
- }
104
- if ("lastError" in value && value.lastError !== void 0 && value.lastError !== null && typeof value.lastError !== "string") {
105
- return false;
106
- }
107
- return true;
108
- }
109
- if (value.type === "heartbeat") {
110
- if (value.lastEventAt !== null && typeof value.lastEventAt !== "string") {
111
- return false;
112
- }
113
- if (!isTokenUsage(value.tokenUsage)) {
114
- return false;
115
- }
116
- if (value.rateLimits !== null && !isRecord(value.rateLimits)) {
117
- return false;
118
- }
119
- if (value.sessionInfo !== null && !isSessionInfo(value.sessionInfo)) {
120
- return false;
121
- }
122
- if (value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
123
- return false;
124
- }
125
- if (value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
126
- return false;
127
- }
128
- if (value.lastError !== null && typeof value.lastError !== "string") {
129
- return false;
130
- }
131
- return true;
132
- }
133
- if (value.type === "turn_started") {
134
- return isTurnEventBase(value);
135
- }
136
- if (value.type === "turn_completed") {
137
- return isTurnEventBase(value) && typeof value.completedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage);
138
- }
139
- if (value.type === "turn_failed") {
140
- return isTurnEventBase(value) && typeof value.failedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage) && isNullableString(value.error);
141
- }
142
- return false;
143
- }
144
-
145
- // ../core/dist/workflow/lifecycle.js
146
- var DEFAULT_WORKFLOW_LIFECYCLE = {
147
- stateFieldName: "Status",
148
- activeStates: ["Todo", "In Progress"],
149
- terminalStates: ["Done"],
150
- blockerCheckStates: ["Todo"]
151
- };
152
- function isStateActive(state, lifecycle) {
153
- return matchesWorkflowState(state, lifecycle.activeStates);
154
- }
155
- function isStateTerminal(state, lifecycle) {
156
- return matchesWorkflowState(state, lifecycle.terminalStates);
157
- }
158
- function matchesWorkflowState(state, candidates) {
159
- const normalizedState = normalizeWorkflowState(state);
160
- return candidates.some((candidate) => normalizeWorkflowState(candidate) === normalizedState);
161
- }
162
- function normalizeWorkflowState(state) {
163
- return state.trim().toLowerCase();
164
- }
165
-
166
- // ../core/dist/workflow/config.js
167
- var DEFAULT_CODEX_COMMAND = "codex app-server";
168
- var DEFAULT_AGENT_COMMAND = DEFAULT_CODEX_COMMAND;
169
- var DEFAULT_HOOK_TIMEOUT_MS = 6e4;
170
- var DEFAULT_POLL_INTERVAL_MS = 3e4;
171
- var DEFAULT_MAX_RETRY_BACKOFF_MS = 3e5;
172
- var DEFAULT_MAX_DELAY_MS = DEFAULT_MAX_RETRY_BACKOFF_MS;
173
- var DEFAULT_BASE_DELAY_MS = 1e4;
174
- var DEFAULT_MAX_TURNS = 20;
175
- var DEFAULT_READ_TIMEOUT_MS = 5e3;
176
- var DEFAULT_TURN_TIMEOUT_MS = 36e5;
177
- var DEFAULT_STALL_TIMEOUT_MS = 3e5;
178
- var DEFAULT_MAX_CONCURRENT_AGENTS = 10;
179
- var DEFAULT_WORKFLOW_HOOKS = {
180
- afterCreate: null,
181
- beforeRun: null,
182
- afterRun: null,
183
- beforeRemove: null,
184
- timeoutMs: DEFAULT_HOOK_TIMEOUT_MS
185
- };
186
- var DEFAULT_WORKFLOW_TRACKER = {
187
- kind: null,
188
- endpoint: null,
189
- apiKey: null,
190
- projectSlug: null,
191
- activeStates: DEFAULT_WORKFLOW_LIFECYCLE.activeStates,
192
- terminalStates: DEFAULT_WORKFLOW_LIFECYCLE.terminalStates,
193
- projectId: null,
194
- stateFieldName: DEFAULT_WORKFLOW_LIFECYCLE.stateFieldName,
195
- priorityFieldName: null,
196
- blockerCheckStates: DEFAULT_WORKFLOW_LIFECYCLE.blockerCheckStates
197
- };
198
- var DEFAULT_WORKFLOW_WORKSPACE = {
199
- root: null
200
- };
201
- var DEFAULT_WORKFLOW_AGENT = {
202
- maxConcurrentAgents: DEFAULT_MAX_CONCURRENT_AGENTS,
203
- maxRetryBackoffMs: DEFAULT_MAX_RETRY_BACKOFF_MS,
204
- maxConcurrentAgentsByState: {},
205
- maxTurns: DEFAULT_MAX_TURNS,
206
- retryBaseDelayMs: DEFAULT_BASE_DELAY_MS
207
- };
208
- var DEFAULT_WORKFLOW_CODEX = {
209
- command: DEFAULT_CODEX_COMMAND,
210
- approvalPolicy: null,
211
- threadSandbox: null,
212
- turnSandboxPolicy: null,
213
- turnTimeoutMs: DEFAULT_TURN_TIMEOUT_MS,
214
- readTimeoutMs: DEFAULT_READ_TIMEOUT_MS,
215
- stallTimeoutMs: DEFAULT_STALL_TIMEOUT_MS
216
- };
217
- var DEFAULT_WORKFLOW_DEFINITION = {
218
- promptTemplate: "",
219
- continuationGuidance: null,
220
- tracker: DEFAULT_WORKFLOW_TRACKER,
221
- polling: {
222
- intervalMs: DEFAULT_POLL_INTERVAL_MS
223
- },
224
- workspace: DEFAULT_WORKFLOW_WORKSPACE,
225
- hooks: DEFAULT_WORKFLOW_HOOKS,
226
- agent: DEFAULT_WORKFLOW_AGENT,
227
- codex: DEFAULT_WORKFLOW_CODEX,
228
- lifecycle: DEFAULT_WORKFLOW_LIFECYCLE,
229
- format: "default",
230
- githubProjectId: null,
231
- agentCommand: DEFAULT_CODEX_COMMAND,
232
- hookPath: null,
233
- maxConcurrentByState: {}
234
- };
235
-
236
- // ../core/dist/workflow/parser.js
237
- function parseWorkflowMarkdown(markdown, env = process.env, options = {}) {
238
- const compatibilityMode = options.compatibilityMode ?? "strict";
239
- const frontMatterMatch = markdown.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
240
- if (!frontMatterMatch) {
241
- if (compatibilityMode === "legacy") {
242
- return parseLegacyWorkflowMarkdown(markdown);
243
- }
244
- throw new Error("WORKFLOW.md must use YAML front matter.");
245
- }
246
- const [, rawFrontMatter, rawPromptTemplate = ""] = frontMatterMatch;
247
- const frontMatter = parseFrontMatter(rawFrontMatter);
248
- const promptTemplate = rawPromptTemplate.trim();
249
- const tracker = readRequiredObject(frontMatter, "tracker");
250
- const polling = readObject(frontMatter, "polling");
251
- const workspace = readObject(frontMatter, "workspace");
252
- const hooks = readObject(frontMatter, "hooks");
253
- const agent = readObject(frontMatter, "agent");
254
- const codex = readRequiredObject(frontMatter, "codex");
255
- const trackerKind = readRequiredString(tracker, "kind", env);
256
- const activeStates = readStringList(tracker, "active_states") ?? DEFAULT_WORKFLOW_TRACKER.activeStates;
257
- const terminalStates = readStringList(tracker, "terminal_states") ?? DEFAULT_WORKFLOW_TRACKER.terminalStates;
258
- const blockerCheckStates = readStringList(tracker, "blocker_check_states") ?? DEFAULT_WORKFLOW_TRACKER.blockerCheckStates;
259
- const maxConcurrentAgentsByState = readNumberMap(agent, "max_concurrent_agents_by_state");
260
- const command = readOptionalString(codex, "command", env) ?? DEFAULT_AGENT_COMMAND;
261
- const parsed = {
262
- promptTemplate,
263
- continuationGuidance: readOptionalWorkflowString(frontMatter, "continuationGuidance", "continuation_guidance", env),
264
- tracker: {
265
- kind: trackerKind,
266
- endpoint: readOptionalString(tracker, "endpoint", env),
267
- apiKey: readOptionalString(tracker, "api_key", env),
268
- projectSlug: readOptionalString(tracker, "project_slug", env),
269
- activeStates,
270
- terminalStates,
271
- projectId: readOptionalString(tracker, "project_id", env),
272
- stateFieldName: readOptionalString(tracker, "state_field", env) ?? DEFAULT_WORKFLOW_TRACKER.stateFieldName,
273
- priorityFieldName: readOptionalString(tracker, "priority_field", env),
274
- blockerCheckStates
275
- },
276
- polling: {
277
- intervalMs: readOptionalIntegerLike(polling, "interval_ms") ?? DEFAULT_POLL_INTERVAL_MS
278
- },
279
- workspace: {
280
- root: readOptionalString(workspace, "root", env)
281
- },
282
- hooks: {
283
- afterCreate: readOptionalString(hooks, "after_create", env),
284
- beforeRun: readOptionalString(hooks, "before_run", env),
285
- afterRun: readOptionalString(hooks, "after_run", env),
286
- beforeRemove: readOptionalString(hooks, "before_remove", env),
287
- timeoutMs: readOptionalIntegerLike(hooks, "timeout_ms") ?? DEFAULT_HOOK_TIMEOUT_MS
288
- },
289
- agent: {
290
- maxConcurrentAgents: readOptionalIntegerLike(agent, "max_concurrent_agents") ?? DEFAULT_MAX_CONCURRENT_AGENTS,
291
- maxRetryBackoffMs: readOptionalIntegerLike(agent, "max_retry_backoff_ms") ?? DEFAULT_MAX_RETRY_BACKOFF_MS,
292
- maxConcurrentAgentsByState,
293
- maxTurns: readOptionalIntegerLike(agent, "max_turns") ?? DEFAULT_MAX_TURNS,
294
- retryBaseDelayMs: readOptionalIntegerLike(agent, "retry_base_delay_ms") ?? DEFAULT_BASE_DELAY_MS
295
- },
296
- codex: {
297
- command,
298
- approvalPolicy: readOptionalString(codex, "approval_policy", env),
299
- threadSandbox: readOptionalString(codex, "thread_sandbox", env),
300
- turnSandboxPolicy: readOptionalString(codex, "turn_sandbox_policy", env),
301
- turnTimeoutMs: readOptionalIntegerLike(codex, "turn_timeout_ms") ?? DEFAULT_TURN_TIMEOUT_MS,
302
- readTimeoutMs: readOptionalIntegerLike(codex, "read_timeout_ms") ?? DEFAULT_READ_TIMEOUT_MS,
303
- stallTimeoutMs: readOptionalIntegerLike(codex, "stall_timeout_ms") ?? DEFAULT_STALL_TIMEOUT_MS
304
- },
305
- lifecycle: {
306
- stateFieldName: readOptionalString(tracker, "state_field", env) ?? DEFAULT_WORKFLOW_TRACKER.stateFieldName,
307
- activeStates,
308
- terminalStates,
309
- blockerCheckStates
310
- },
311
- format: "front-matter",
312
- githubProjectId: readOptionalString(tracker, "project_id", env),
313
- agentCommand: command,
314
- hookPath: readOptionalString(hooks, "after_create", env),
315
- maxConcurrentByState: maxConcurrentAgentsByState
316
- };
317
- return parsed;
318
- }
319
- function parseLegacyWorkflowMarkdown(markdown) {
320
- const promptGuidelines = matchOptionalSection(markdown, "Prompt Guidelines") ?? "";
321
- return {
322
- ...DEFAULT_WORKFLOW_DEFINITION,
323
- promptTemplate: promptGuidelines,
324
- format: "legacy-sectioned"
325
- };
326
- }
327
- function parseFrontMatter(frontMatter) {
328
- const lines = frontMatter.replace(/\r\n/g, "\n").split("\n");
329
- const [value] = parseBlock(lines, 0, 0);
330
- if (!value || Array.isArray(value) || typeof value !== "object") {
331
- throw new Error("Workflow front matter must be a YAML object.");
332
- }
333
- return value;
334
- }
335
- function parseBlock(lines, startIndex, indent) {
336
- let index = startIndex;
337
- let collectionType = null;
338
- const arrayValues = [];
339
- const objectValues = {};
340
- while (index < lines.length) {
341
- const line = lines[index] ?? "";
342
- if (!line.trim()) {
343
- index += 1;
344
- continue;
345
- }
346
- const lineIndent = countIndent(line);
347
- if (lineIndent < indent) {
348
- break;
349
- }
350
- if (lineIndent > indent) {
351
- throw new Error(`Invalid workflow front matter indentation near "${line.trim()}".`);
352
- }
353
- const trimmed = line.trim();
354
- if (trimmed.startsWith("- ")) {
355
- if (collectionType === "object") {
356
- throw new Error("Cannot mix array and object values in workflow front matter.");
357
- }
358
- collectionType = "array";
359
- const itemText = trimmed.slice(2).trim();
360
- if (itemText === "|" || itemText === "|-") {
361
- const [multiline, nextIndex3] = parseMultilineScalar(lines, index + 1, indent + 2);
362
- arrayValues.push(multiline);
363
- index = nextIndex3;
364
- continue;
365
- }
366
- if (itemText) {
367
- arrayValues.push(parseScalar(itemText));
368
- index += 1;
369
- continue;
370
- }
371
- const [child2, nextIndex2] = parseBlock(lines, index + 1, indent + 2);
372
- arrayValues.push(child2);
373
- index = nextIndex2;
374
- continue;
375
- }
376
- if (collectionType === "array") {
377
- throw new Error("Cannot mix object and array values in workflow front matter.");
378
- }
379
- collectionType = "object";
380
- const separatorIndex = trimmed.indexOf(":");
381
- if (separatorIndex < 0) {
382
- throw new Error(`Invalid workflow front matter line "${trimmed}".`);
383
- }
384
- const key = trimmed.slice(0, separatorIndex).trim();
385
- const remainder = trimmed.slice(separatorIndex + 1).trim();
386
- if (remainder === "|" || remainder === "|-") {
387
- const [multiline, nextIndex2] = parseMultilineScalar(lines, index + 1, indent + 2);
388
- objectValues[key] = multiline;
389
- index = nextIndex2;
390
- continue;
391
- }
392
- if (remainder) {
393
- objectValues[key] = parseScalar(remainder);
394
- index += 1;
395
- continue;
396
- }
397
- const [child, nextIndex] = parseBlock(lines, index + 1, indent + 2);
398
- objectValues[key] = child;
399
- index = nextIndex;
400
- }
401
- return [collectionType === "array" ? arrayValues : objectValues, index];
402
- }
403
- function parseMultilineScalar(lines, startIndex, indent) {
404
- let index = startIndex;
405
- const collected = [];
406
- while (index < lines.length) {
407
- const line = lines[index] ?? "";
408
- if (!line.trim()) {
409
- collected.push("");
410
- index += 1;
411
- continue;
412
- }
413
- const lineIndent = countIndent(line);
414
- if (lineIndent < indent) {
415
- break;
416
- }
417
- collected.push(line.slice(indent));
418
- index += 1;
419
- }
420
- return [collected.join("\n").trimEnd(), index];
421
- }
422
- function countIndent(line) {
423
- return line.match(/^ */)?.[0].length ?? 0;
424
- }
425
- function parseScalar(value) {
426
- if (value === "null")
427
- return null;
428
- if (value === "true")
429
- return true;
430
- if (value === "false")
431
- return false;
432
- if (/^-?\d+$/.test(value))
433
- return Number.parseInt(value, 10);
434
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
435
- return value.slice(1, -1);
436
- }
437
- return value;
438
- }
439
- function readObject(input, key) {
440
- const value = input[key];
441
- if (value === void 0 || value === null) {
442
- return {};
443
- }
444
- if (typeof value !== "object" || Array.isArray(value)) {
445
- throw new Error(`Workflow front matter field "${key}" must be an object.`);
446
- }
447
- return value;
448
- }
449
- function readRequiredObject(input, key) {
450
- if (!(key in input)) {
451
- throw new Error(`Workflow front matter field "${key}" is required.`);
452
- }
453
- return readObject(input, key);
454
- }
455
- function readOptionalString(input, key, env) {
456
- const value = input[key];
457
- if (value === void 0 || value === null) {
458
- return null;
459
- }
460
- if (typeof value !== "string") {
461
- throw new Error(`Workflow front matter field "${key}" must be a string.`);
462
- }
463
- return resolveEnvironmentValue(value, env);
464
- }
465
- function readOptionalWorkflowString(input, primaryKey, fallbackKey, env) {
466
- return readOptionalString(input, primaryKey, env) ?? readOptionalString(input, fallbackKey, env);
467
- }
468
- function readRequiredString(input, key, env) {
469
- const value = readOptionalString(input, key, env);
470
- if (!value) {
471
- throw new Error(`Workflow front matter field "${key}" is required.`);
472
- }
473
- return value;
474
- }
475
- function readStringList(input, key) {
476
- const value = input[key];
477
- if (value === void 0 || value === null) {
478
- return void 0;
479
- }
480
- if (typeof value === "string") {
481
- return value.split(",").map((entry) => entry.trim()).filter(Boolean);
482
- }
483
- if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
484
- throw new Error(`Workflow front matter field "${key}" must be an array of strings or comma-separated string.`);
485
- }
486
- return value;
487
- }
488
- function readOptionalIntegerLike(input, key) {
489
- const value = input[key];
490
- if (value === void 0 || value === null) {
491
- return null;
492
- }
493
- if (typeof value === "number") {
494
- return value;
495
- }
496
- if (typeof value === "string" && /^-?\d+$/.test(value)) {
497
- return Number.parseInt(value, 10);
498
- }
499
- throw new Error(`Workflow front matter field "${key}" must be an integer.`);
500
- }
501
- function readNumberMap(input, key) {
502
- const value = input[key];
503
- if (value === void 0 || value === null) {
504
- return {};
505
- }
506
- if (typeof value !== "object" || Array.isArray(value)) {
507
- throw new Error(`Workflow front matter field "${key}" must be an object.`);
508
- }
509
- const result = {};
510
- for (const [entryKey, entryValue] of Object.entries(value)) {
511
- if (typeof entryValue === "number") {
512
- result[entryKey] = entryValue;
513
- continue;
514
- }
515
- if (typeof entryValue === "string" && /^\d+$/.test(entryValue)) {
516
- result[entryKey] = Number.parseInt(entryValue, 10);
517
- continue;
518
- }
519
- throw new Error(`Workflow front matter field "${key}.${entryKey}" must be an integer.`);
520
- }
521
- return result;
522
- }
523
- function resolveEnvironmentValue(value, env) {
524
- const envTokenMatch = value.match(/^(?:env:)?([A-Z0-9_]+)$/);
525
- if (value.startsWith("env:") && envTokenMatch) {
526
- const resolved = env[envTokenMatch[1]];
527
- if (!resolved) {
528
- throw new Error(`Workflow front matter requires environment variable ${envTokenMatch[1]}.`);
529
- }
530
- return resolved;
531
- }
532
- return value.replace(/\$\{([A-Z0-9_]+)\}/g, (_, name) => {
533
- const resolved = env[name];
534
- if (!resolved) {
535
- throw new Error(`Workflow front matter requires environment variable ${name}.`);
536
- }
537
- return resolved;
538
- });
539
- }
540
- function matchOptionalSection(markdown, heading) {
541
- const escapedHeading = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
542
- const pattern = new RegExp(`## ${escapedHeading}\\n\\n([\\s\\S]*?)(?=\\n## |$)`);
543
- const match = markdown.match(pattern);
544
- return match?.[1]?.trim() ?? null;
545
- }
546
-
547
- // ../core/dist/workflow/loader.js
548
- import { createHash } from "crypto";
549
- import { access, readFile, stat } from "fs/promises";
550
- import { constants } from "fs";
551
- var WorkflowConfigStore = class {
552
- cache = /* @__PURE__ */ new Map();
553
- async load(workflowPath, env = process.env) {
554
- await access(workflowPath, constants.R_OK);
555
- const fileStat = await stat(workflowPath);
556
- const fingerprint = `${fileStat.mtimeMs}:${fileStat.size}`;
557
- const cached = this.cache.get(workflowPath);
558
- if (cached && cached.fingerprint === fingerprint) {
559
- return toWorkflowResolution(workflowPath, cached.workflow, {
560
- isValid: true,
561
- usedLastKnownGood: false,
562
- validationError: null
563
- });
564
- }
565
- const markdown = await readFile(workflowPath, "utf8");
566
- try {
567
- const workflow = parseWorkflowMarkdown(markdown, env);
568
- this.cache.set(workflowPath, {
569
- fingerprint,
570
- workflow,
571
- loadedAt: (/* @__PURE__ */ new Date()).toISOString()
572
- });
573
- return toWorkflowResolution(workflowPath, workflow, {
574
- isValid: true,
575
- usedLastKnownGood: false,
576
- validationError: null
577
- });
578
- } catch (error) {
579
- if (cached) {
580
- return toWorkflowResolution(workflowPath, cached.workflow, {
581
- isValid: false,
582
- usedLastKnownGood: true,
583
- validationError: error instanceof Error ? error.message : "Invalid workflow definition."
584
- });
585
- }
586
- throw error;
587
- }
588
- }
589
- };
590
- function createDefaultWorkflowResolution() {
591
- return createInvalidWorkflowResolution(null, "missing_workflow_file");
592
- }
593
- function createInvalidWorkflowResolution(workflowPath, validationError) {
594
- return toWorkflowResolution(workflowPath, DEFAULT_WORKFLOW_DEFINITION, {
595
- isValid: false,
596
- usedLastKnownGood: false,
597
- validationError
598
- });
599
- }
600
- function toWorkflowResolution(workflowPath, workflow, metadata) {
601
- return {
602
- workflowPath,
603
- workflow,
604
- lifecycle: workflow.lifecycle,
605
- promptTemplate: workflow.promptTemplate,
606
- agentCommand: workflow.agentCommand,
607
- hookPath: workflow.hookPath ?? "",
608
- isValid: metadata.isValid,
609
- usedLastKnownGood: metadata.usedLastKnownGood,
610
- validationError: metadata.validationError
611
- };
612
- }
613
-
614
- // ../core/dist/workflow/render.js
615
- import { Liquid, ParseError, RenderError, TokenizationError, UndefinedVariableError } from "liquidjs";
616
- function buildPromptVariables(issue, options) {
617
- return {
618
- issue: {
619
- id: issue.id,
620
- identifier: issue.identifier,
621
- number: issue.number,
622
- title: issue.title,
623
- description: issue.description,
624
- priority: issue.priority,
625
- url: issue.url,
626
- state: issue.state,
627
- labels: issue.labels,
628
- blocked_by: issue.blockedBy,
629
- branch_name: issue.branchName,
630
- created_at: issue.createdAt,
631
- updated_at: issue.updatedAt,
632
- repository: `${issue.repository.owner}/${issue.repository.name}`
633
- },
634
- attempt: options.attempt
635
- };
636
- }
637
- var STRICT_LIQUID_ENGINE = new Liquid({
638
- strictVariables: true,
639
- strictFilters: true,
640
- ownPropertyOnly: true
641
- });
642
- function renderPrompt(template, variables, options = {}) {
643
- const strict = options.strict ?? true;
644
- if (!strict) {
645
- return renderLegacyPrompt(template, variables);
646
- }
647
- try {
648
- return STRICT_LIQUID_ENGINE.parseAndRenderSync(template, variables);
649
- } catch (error) {
650
- throw normalizeTemplateError(error);
651
- }
652
- }
653
- function normalizeTemplateError(error) {
654
- const message = error instanceof Error ? error.message : String(error);
655
- if (error instanceof UndefinedVariableError || error instanceof RenderError || error instanceof ParseError && message.startsWith("undefined filter:")) {
656
- return new Error(`template_render_error: ${message}`, { cause: error });
657
- }
658
- if (error instanceof ParseError || error instanceof TokenizationError) {
659
- return new Error(`template_parse_error: ${message}`, { cause: error });
660
- }
661
- return new Error(`template_render_error: ${message}`, { cause: error });
662
- }
663
- function flattenVariables(obj, prefix = "") {
664
- const result = /* @__PURE__ */ new Map();
665
- for (const [key, value] of Object.entries(obj)) {
666
- const fullKey = prefix ? `${prefix}.${key}` : key;
667
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
668
- for (const [nestedKey, nestedValue] of flattenVariables(value, fullKey)) {
669
- result.set(nestedKey, nestedValue);
670
- }
671
- } else {
672
- result.set(fullKey, value);
673
- }
674
- }
675
- return result;
676
- }
677
- function renderLegacyPrompt(template, variables) {
678
- const flatVars = flattenVariables(variables);
679
- return template.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_.]*)\}\}/g, (match, key) => {
680
- const value = flatVars.get(key);
681
- if (value === void 0) {
682
- return match;
683
- }
684
- if (value === null) {
685
- return "";
686
- }
687
- return String(value);
688
- });
689
- }
690
-
691
- // ../core/dist/orchestration/retry-policy.js
692
- function calculateRetryDelay(attempt, options = {}) {
693
- const baseDelayMs = options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
694
- const maxDelayMs = options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
695
- const normalizedAttempt = Math.max(1, attempt);
696
- const delay2 = baseDelayMs * 2 ** (normalizedAttempt - 1);
697
- return Math.min(delay2, maxDelayMs);
698
- }
699
- function scheduleRetryAt(now, attempt, options = {}) {
700
- return new Date(now.getTime() + calculateRetryDelay(attempt, options));
701
- }
702
-
703
- // ../core/dist/workspace/env-file.js
704
- import { existsSync, readFileSync } from "fs";
705
- function readEnvFile(path) {
706
- if (!existsSync(path)) {
707
- return {};
708
- }
709
- return readFileSync(path, "utf8").split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && line.includes("=")).reduce((result, line) => {
710
- const separatorIndex = line.indexOf("=");
711
- const key = line.slice(0, separatorIndex).trim();
712
- const value = line.slice(separatorIndex + 1).trim();
713
- if (key) {
714
- result[key] = value;
715
- }
716
- return result;
717
- }, {});
718
- }
719
-
720
- // ../core/dist/workspace/safety.js
721
- import { resolve } from "path";
722
-
723
- // ../core/dist/workspace/identity.js
724
- import { resolve as resolve2, join } from "path";
725
- import { createHash as createHash2 } from "crypto";
726
- function deriveIssueWorkspaceKey(identity, issueIdentifier) {
727
- if (issueIdentifier) {
728
- return deriveIssueWorkspaceKeyFromIdentifier(issueIdentifier);
729
- }
730
- return deriveLegacyIssueWorkspaceKey(identity);
731
- }
732
- function deriveIssueWorkspaceKeyFromIdentifier(issueIdentifier) {
733
- const sanitized = issueIdentifier.replace(/[^A-Za-z0-9._-]+/g, "_").replace(/^_+|_+$/g, "");
734
- if (!sanitized || /^[.]+$/.test(sanitized)) {
735
- return "issue";
736
- }
737
- return sanitized;
738
- }
739
- function deriveLegacyIssueWorkspaceKey(identity) {
740
- const input = [
741
- identity.projectId,
742
- identity.adapter,
743
- identity.issueSubjectId
744
- ].join(":");
745
- return createHash2("sha256").update(input).digest("hex").slice(0, 16);
746
- }
747
- function resolveIssueWorkspaceDirectory(projectDirectory, workspaceKey) {
748
- const normalizedProjectDirectory = resolve2(projectDirectory);
749
- const candidate = resolve2(normalizedProjectDirectory, "issues", workspaceKey);
750
- if (!candidate.startsWith(`${normalizedProjectDirectory}/`)) {
751
- throw new Error("Issue workspace path escapes the configured project directory.");
752
- }
753
- return candidate;
754
- }
755
-
756
- // ../core/dist/workspace/hooks.js
757
- import { spawn } from "child_process";
758
- var DEFAULT_HOOK_TIMEOUT_MS2 = 6e4;
759
- async function executeHook(options) {
760
- const { kind, command, cwd, env, timeoutMs } = options;
761
- const start = Date.now();
762
- const normalizedCommand = normalizeHookCommand(command);
763
- return new Promise((resolveResult) => {
764
- let timedOut = false;
765
- let timer = null;
766
- const child = spawn("bash", ["-lc", normalizedCommand], {
767
- cwd,
768
- env: { ...process.env, ...env },
769
- stdio: "pipe"
770
- });
771
- const stderrChunks = [];
772
- child.stderr?.on("data", (chunk) => {
773
- stderrChunks.push(chunk);
774
- });
775
- if (timeoutMs > 0) {
776
- timer = setTimeout(() => {
777
- timedOut = true;
778
- child.kill("SIGTERM");
779
- setTimeout(() => {
780
- try {
781
- child.kill("SIGKILL");
782
- } catch {
783
- }
784
- }, 5e3);
785
- }, timeoutMs);
786
- }
787
- child.on("close", (code) => {
788
- if (timer) {
789
- clearTimeout(timer);
790
- }
791
- const durationMs = Date.now() - start;
792
- const stderr = Buffer.concat(stderrChunks).toString("utf8").trim();
793
- if (timedOut) {
794
- resolveResult({
795
- kind,
796
- outcome: "timeout",
797
- exitCode: code,
798
- durationMs,
799
- error: `Hook "${kind}" timed out after ${timeoutMs}ms`
800
- });
801
- return;
802
- }
803
- if (code !== 0) {
804
- resolveResult({
805
- kind,
806
- outcome: "failure",
807
- exitCode: code,
808
- durationMs,
809
- error: stderr || `Hook "${kind}" exited with code ${code}`
810
- });
811
- return;
812
- }
813
- resolveResult({
814
- kind,
815
- outcome: "success",
816
- exitCode: 0,
817
- durationMs,
818
- error: null
819
- });
820
- });
821
- child.on("error", (err) => {
822
- if (timer) {
823
- clearTimeout(timer);
824
- }
825
- resolveResult({
826
- kind,
827
- outcome: "failure",
828
- exitCode: null,
829
- durationMs: Date.now() - start,
830
- error: err.message
831
- });
832
- });
833
- });
834
- }
835
- function buildHookEnv(context) {
836
- const env = {
837
- SYMPHONY_PROJECT_ID: context.projectId,
838
- SYMPHONY_ISSUE_WORKSPACE_KEY: context.workspaceKey,
839
- SYMPHONY_ISSUE_SUBJECT_ID: context.issueSubjectId,
840
- SYMPHONY_ISSUE_IDENTIFIER: context.issueIdentifier,
841
- SYMPHONY_WORKSPACE_PATH: context.workspacePath,
842
- SYMPHONY_REPOSITORY_PATH: context.repositoryPath
843
- };
844
- if (context.runId) {
845
- env.SYMPHONY_RUN_ID = context.runId;
846
- }
847
- if (context.state) {
848
- env.SYMPHONY_ISSUE_STATE = context.state;
849
- }
850
- return env;
851
- }
852
- function resolveHookCommand(hooks, kind) {
853
- switch (kind) {
854
- case "after_create":
855
- return hooks.afterCreate;
856
- case "before_run":
857
- return hooks.beforeRun;
858
- case "after_run":
859
- return hooks.afterRun;
860
- case "before_remove":
861
- return hooks.beforeRemove;
862
- }
863
- }
864
- async function executeWorkspaceHook(options) {
865
- const hookCommand = resolveHookCommand(options.hooks, options.kind);
866
- if (!hookCommand) {
867
- return {
868
- kind: options.kind,
869
- outcome: "skipped",
870
- exitCode: null,
871
- durationMs: 0,
872
- error: null
873
- };
874
- }
875
- return executeHook({
876
- kind: options.kind,
877
- command: hookCommand,
878
- cwd: options.repositoryPath,
879
- env: options.env,
880
- timeoutMs: options.timeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS2
881
- });
882
- }
883
- function normalizeHookCommand(command) {
884
- const trimmed = command.trim();
885
- if (trimmed.includes("/") && !trimmed.startsWith("/") && !trimmed.startsWith("./") && !trimmed.startsWith("../") && !/\s/.test(trimmed)) {
886
- return `bash ./${trimmed}`;
887
- }
888
- return command;
889
- }
890
-
891
- // ../core/dist/observability/snapshot-builder.js
892
- function buildProjectSnapshot(input) {
893
- const { project, activeRuns, allRuns, summary, lastTickAt, lastError, rateLimits } = input;
894
- return {
895
- projectId: project.projectId,
896
- slug: project.slug,
897
- tracker: {
898
- adapter: project.tracker.adapter,
899
- bindingId: project.tracker.bindingId
900
- },
901
- lastTickAt,
902
- health: lastError ? "degraded" : activeRuns.length > 0 ? "running" : "idle",
903
- summary: {
904
- dispatched: summary.dispatched,
905
- suppressed: summary.suppressed,
906
- recovered: summary.recovered,
907
- activeRuns: activeRuns.length
908
- },
909
- activeRuns: activeRuns.map((run) => ({
910
- runId: run.runId,
911
- issueIdentifier: run.issueIdentifier,
912
- issueState: run.issueState,
913
- status: run.status,
914
- retryKind: run.retryKind,
915
- port: run.port,
916
- runtimeSession: run.runtimeSession ?? null,
917
- // New fields from live worker data
918
- processId: run.processId ?? null,
919
- turnCount: run.turnCount,
920
- startedAt: run.startedAt ?? null,
921
- lastEvent: run.lastEvent ?? null,
922
- lastEventAt: run.lastEventAt ?? null,
923
- executionPhase: run.executionPhase ?? null,
924
- runPhase: run.runPhase ?? null,
925
- tokenUsage: run.tokenUsage
926
- })),
927
- retryQueue: activeRuns.filter((run) => run.status === "retrying" && run.retryKind).map((run) => ({
928
- runId: run.runId,
929
- issueIdentifier: run.issueIdentifier,
930
- retryKind: run.retryKind ?? "failure",
931
- nextRetryAt: run.nextRetryAt
932
- })),
933
- lastError,
934
- codexTotals: aggregateTokenUsage(allRuns ?? activeRuns, lastTickAt),
935
- rateLimits: rateLimits ?? null
936
- };
937
- }
938
- function aggregateTokenUsage(runs, lastTickAt) {
939
- let inputTokens = 0;
940
- let outputTokens = 0;
941
- let totalTokens = 0;
942
- let earliestStart = null;
943
- let latestEnd = null;
944
- for (const run of runs) {
945
- if (run.tokenUsage) {
946
- inputTokens += run.tokenUsage.inputTokens;
947
- outputTokens += run.tokenUsage.outputTokens;
948
- totalTokens += run.tokenUsage.totalTokens;
949
- }
950
- if (run.startedAt) {
951
- const start = new Date(run.startedAt).getTime();
952
- if (earliestStart === null || start < earliestStart) {
953
- earliestStart = start;
954
- }
955
- }
956
- const end = run.completedAt ? new Date(run.completedAt).getTime() : new Date(lastTickAt).getTime();
957
- if (latestEnd === null || end > latestEnd) {
958
- latestEnd = end;
959
- }
960
- }
961
- const secondsRunning = earliestStart !== null && latestEnd !== null ? Math.max(0, Math.round((latestEnd - earliestStart) / 1e3)) : 0;
962
- return { inputTokens, outputTokens, totalTokens, secondsRunning };
963
- }
964
-
965
- // ../core/dist/observability/fs-reader.js
966
- import { readFile as readFile2, readdir } from "fs/promises";
967
- async function readJsonFile(path) {
968
- try {
969
- const raw = await readFile2(path, "utf8");
970
- return JSON.parse(raw);
971
- } catch (error) {
972
- if (isFileMissing(error)) {
973
- return null;
974
- }
975
- throw error;
976
- }
977
- }
978
- async function safeReadDir(path) {
979
- try {
980
- return await readdir(path);
981
- } catch (error) {
982
- if (isFileMissing(error)) {
983
- return [];
984
- }
985
- throw error;
986
- }
987
- }
988
- function isFileMissing(error) {
989
- return Boolean(error && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"));
990
- }
991
-
992
- // ../core/dist/observability/event-formatter.js
993
- function formatEventMessage(event) {
994
- switch (event.event) {
995
- case "run-dispatched":
996
- return event.issueState ? `Dispatched from ${event.issueState}` : "Dispatched";
997
- case "run-recovered":
998
- return "Recovered existing run";
999
- case "run-retried":
1000
- return `Retry ${event.attempt} scheduled (${event.retryKind})`;
1001
- case "run-failed":
1002
- return event.lastError;
1003
- case "run-suppressed":
1004
- return event.reason;
1005
- case "hook-executed":
1006
- return `${event.hook}: ${event.outcome}`;
1007
- case "hook-failed":
1008
- return event.error;
1009
- case "workspace-cleanup":
1010
- return event.error ? `${event.outcome}: ${event.error}` : event.outcome;
1011
- case "worker-error":
1012
- return event.error;
1013
- case "turn_started":
1014
- return `Turn ${event.turnCount} started`;
1015
- case "turn_completed":
1016
- return `Turn ${event.turnCount} completed in ${event.durationMs}ms`;
1017
- case "turn_failed":
1018
- return event.error ?? `Turn ${event.turnCount} failed`;
1019
- default:
1020
- return null;
1021
- }
1022
- }
1023
- function parseRecentEvents(raw, limit, options) {
1024
- const lines = raw.split("\n");
1025
- if (options.allowPartialFirstLine) {
1026
- lines.shift();
1027
- }
1028
- const events = [];
1029
- for (let index = lines.length - 1; index >= 0; index -= 1) {
1030
- const line = lines[index]?.trim();
1031
- if (!line) {
1032
- continue;
1033
- }
1034
- const event = parseRunEventLine(line);
1035
- if (!event) {
1036
- continue;
1037
- }
1038
- events.push({
1039
- at: event.at,
1040
- event: event.event,
1041
- message: formatEventMessage(event)
1042
- });
1043
- if (events.length === limit) {
1044
- break;
1045
- }
1046
- }
1047
- return events.reverse();
1048
- }
1049
- function parseRunEventLine(line) {
1050
- try {
1051
- return JSON.parse(line);
1052
- } catch {
1053
- return null;
1054
- }
1055
- }
1056
-
1057
- // ../core/dist/observability/status-assembler.js
1058
- function isMatchingIssueRun(run, projectId, issueId, issueIdentifier) {
1059
- return Boolean(run && run.projectId === projectId && (run.issueId === issueId || run.issueIdentifier === issueIdentifier));
1060
- }
1061
- function mapIssueOrchestrationStateToStatus(state) {
1062
- switch (state) {
1063
- case "claimed":
1064
- return "starting";
1065
- case "running":
1066
- return "running";
1067
- case "retry_queued":
1068
- return "retrying";
1069
- case "released":
1070
- return "released";
1071
- case "unclaimed":
1072
- return "pending";
1073
- default:
1074
- return state;
1075
- }
1076
- }
1077
-
1078
38
  // ../orchestrator/dist/git.js
1079
- import { spawn as spawn2 } from "child_process";
39
+ import { spawn } from "child_process";
1080
40
  import { randomUUID } from "crypto";
1081
- import { access as access2, mkdir, readFile as readFile3, rename, rm, stat as stat2, writeFile } from "fs/promises";
1082
- import { constants as constants2 } from "fs";
1083
- import { join as join2 } from "path";
41
+ import { access, mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
42
+ import { constants } from "fs";
43
+ import { join } from "path";
1084
44
  var workflowConfigStore = new WorkflowConfigStore();
1085
45
  var LOCK_RETRY_MS = 100;
1086
46
  var LOCK_STALE_MS = 30 * 60 * 1e3;
@@ -1091,12 +51,12 @@ async function cloneRepositoryForRun(input) {
1091
51
  }
1092
52
  async function syncRepositoryForRun(input) {
1093
53
  await mkdir(input.targetDirectory, { recursive: true });
1094
- const repositoryDirectory = join2(input.targetDirectory, "repository");
1095
- const lockDirectory = join2(input.targetDirectory, "repository.lock");
54
+ const repositoryDirectory = join(input.targetDirectory, "repository");
55
+ const lockDirectory = join(input.targetDirectory, "repository.lock");
1096
56
  return withRepositoryLock(lockDirectory, async () => {
1097
57
  let hasGit = false;
1098
58
  try {
1099
- await access2(join2(repositoryDirectory, ".git"), constants2.R_OK);
59
+ await access(join(repositoryDirectory, ".git"), constants.R_OK);
1100
60
  hasGit = true;
1101
61
  } catch {
1102
62
  }
@@ -1120,7 +80,7 @@ async function syncRepositoryForRun(input) {
1120
80
  } else {
1121
81
  await rm(repositoryDirectory, { recursive: true, force: true });
1122
82
  }
1123
- const tempRepositoryDirectory = join2(input.targetDirectory, `repository.tmp-${process.pid}-${Date.now()}`);
83
+ const tempRepositoryDirectory = join(input.targetDirectory, `repository.tmp-${process.pid}-${Date.now()}`);
1124
84
  await rm(tempRepositoryDirectory, { recursive: true, force: true });
1125
85
  try {
1126
86
  await runCommand("git", [
@@ -1147,7 +107,7 @@ async function ensureIssueWorkspaceRepository(input) {
1147
107
  });
1148
108
  }
1149
109
  async function loadRepositoryWorkflow(repositoryDirectory, _repository) {
1150
- const workflowPath = join2(repositoryDirectory, "WORKFLOW.md");
110
+ const workflowPath = join(repositoryDirectory, "WORKFLOW.md");
1151
111
  try {
1152
112
  return await workflowConfigStore.load(workflowPath);
1153
113
  } catch (error) {
@@ -1158,8 +118,8 @@ async function loadRepositoryWorkflow(repositoryDirectory, _repository) {
1158
118
  }
1159
119
  }
1160
120
  function runCommand(command, args) {
1161
- return new Promise((resolve6, reject) => {
1162
- const child = spawn2(command, args, {
121
+ return new Promise((resolve4, reject) => {
122
+ const child = spawn(command, args, {
1163
123
  stdio: "pipe"
1164
124
  });
1165
125
  let stderr = "";
@@ -1169,7 +129,7 @@ function runCommand(command, args) {
1169
129
  child.once("error", reject);
1170
130
  child.once("exit", (code) => {
1171
131
  if (code === 0) {
1172
- resolve6();
132
+ resolve4();
1173
133
  return;
1174
134
  }
1175
135
  reject(new Error(stderr.trim() || `${command} exited with code ${code ?? "unknown"}`));
@@ -1189,8 +149,8 @@ async function readGitHead(repositoryDirectory) {
1189
149
  }
1190
150
  }
1191
151
  function runCommandCapture(command, args) {
1192
- return new Promise((resolve6, reject) => {
1193
- const child = spawn2(command, args, {
152
+ return new Promise((resolve4, reject) => {
153
+ const child = spawn(command, args, {
1194
154
  stdio: ["ignore", "pipe", "pipe"]
1195
155
  });
1196
156
  let stdout = "";
@@ -1204,7 +164,7 @@ function runCommandCapture(command, args) {
1204
164
  child.once("error", reject);
1205
165
  child.once("exit", (code) => {
1206
166
  if (code === 0) {
1207
- resolve6(stdout.trim());
167
+ resolve4(stdout.trim());
1208
168
  return;
1209
169
  }
1210
170
  reject(new Error(stderr.trim() || `${command} exited with code ${code ?? "unknown"}`));
@@ -1225,7 +185,7 @@ async function acquireRepositoryLock(lockDirectory) {
1225
185
  for (; ; ) {
1226
186
  try {
1227
187
  await mkdir(lockDirectory);
1228
- await writeFile(join2(lockDirectory, "owner"), `${ownerToken}
188
+ await writeFile(join(lockDirectory, "owner"), `${ownerToken}
1229
189
  ${(/* @__PURE__ */ new Date()).toISOString()}
1230
190
  `, "utf8");
1231
191
  return ownerToken;
@@ -1261,7 +221,7 @@ async function releaseRepositoryLock(lockDirectory, ownerToken) {
1261
221
  }
1262
222
  async function isStaleLock(lockDirectory) {
1263
223
  try {
1264
- const details = await stat2(lockDirectory);
224
+ const details = await stat(lockDirectory);
1265
225
  return Date.now() - details.mtimeMs >= LOCK_STALE_MS;
1266
226
  } catch (error) {
1267
227
  if (isMissingFileError(error)) {
@@ -1274,13 +234,13 @@ function isAlreadyExistsError(error) {
1274
234
  return Boolean(error && typeof error === "object" && "code" in error && error.code === "EEXIST");
1275
235
  }
1276
236
  async function readLockOwner(lockDirectory) {
1277
- await access2(join2(lockDirectory, "owner"), constants2.R_OK);
1278
- const owner = await readFile3(join2(lockDirectory, "owner"), "utf8");
237
+ await access(join(lockDirectory, "owner"), constants.R_OK);
238
+ const owner = await readFile(join(lockDirectory, "owner"), "utf8");
1279
239
  return owner.split("\n", 1)[0] || null;
1280
240
  }
1281
241
  function wait(ms) {
1282
- return new Promise((resolve6) => {
1283
- setTimeout(resolve6, ms);
242
+ return new Promise((resolve4) => {
243
+ setTimeout(resolve4, ms);
1284
244
  });
1285
245
  }
1286
246
  function isMissingFileError(error) {
@@ -1288,40 +248,40 @@ function isMissingFileError(error) {
1288
248
  }
1289
249
 
1290
250
  // ../orchestrator/dist/fs-store.js
1291
- import { mkdir as mkdir2, open, rename as rename2, rm as rm2, stat as stat3, writeFile as writeFile2, appendFile } from "fs/promises";
1292
- import { dirname, join as join3, relative, resolve as resolve3 } from "path";
251
+ import { mkdir as mkdir2, open, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile2, appendFile } from "fs/promises";
252
+ import { dirname, join as join2, relative, resolve } from "path";
1293
253
  var OrchestratorFsStore = class {
1294
254
  runtimeRoot;
1295
255
  resolvedRuntimeRoot;
1296
256
  resolvedEventsMirrorRoot;
1297
257
  constructor(runtimeRoot, options = {}) {
1298
258
  this.runtimeRoot = runtimeRoot;
1299
- this.resolvedRuntimeRoot = resolve3(runtimeRoot);
1300
- this.resolvedEventsMirrorRoot = options.eventsMirrorRoot ? resolve3(options.eventsMirrorRoot) : null;
259
+ this.resolvedRuntimeRoot = resolve(runtimeRoot);
260
+ this.resolvedEventsMirrorRoot = options.eventsMirrorRoot ? resolve(options.eventsMirrorRoot) : null;
1301
261
  }
1302
262
  projectsRoot() {
1303
- return join3(this.runtimeRoot, "projects");
263
+ return join2(this.runtimeRoot, "projects");
1304
264
  }
1305
265
  projectDir(projectId) {
1306
- return join3(this.projectsRoot(), projectId);
266
+ return join2(this.projectsRoot(), projectId);
1307
267
  }
1308
268
  projectRunsDir(projectId) {
1309
- return join3(this.projectDir(projectId), "runs");
269
+ return join2(this.projectDir(projectId), "runs");
1310
270
  }
1311
271
  runDir(runId, projectId) {
1312
272
  if (!projectId) {
1313
- return join3(this.runtimeRoot, "projects", "__unknown__", "runs", runId);
273
+ return join2(this.runtimeRoot, "projects", "__unknown__", "runs", runId);
1314
274
  }
1315
- return join3(this.projectRunsDir(projectId), runId);
275
+ return join2(this.projectRunsDir(projectId), runId);
1316
276
  }
1317
277
  async loadProjectConfig(projectId) {
1318
- return readJsonFile(join3(this.projectDir(projectId), "project.json"));
278
+ return readJsonFile(join2(this.projectDir(projectId), "project.json"));
1319
279
  }
1320
280
  async saveProjectConfig(config) {
1321
- await writeJsonFile(join3(this.projectDir(config.projectId), "project.json"), config);
281
+ await writeJsonFile(join2(this.projectDir(config.projectId), "project.json"), config);
1322
282
  }
1323
283
  async loadProjectIssueOrchestrations(projectId) {
1324
- const issuesPath = join3(this.projectDir(projectId), "issues.json");
284
+ const issuesPath = join2(this.projectDir(projectId), "issues.json");
1325
285
  const issues = await readJsonFile(issuesPath);
1326
286
  if (issues) {
1327
287
  return issues.map((issue) => ({
@@ -1329,7 +289,7 @@ var OrchestratorFsStore = class {
1329
289
  completedOnce: issue.completedOnce ?? false
1330
290
  }));
1331
291
  }
1332
- const legacyLeases = await readJsonFile(join3(this.projectDir(projectId), "leases.json")) ?? [];
292
+ const legacyLeases = await readJsonFile(join2(this.projectDir(projectId), "leases.json")) ?? [];
1333
293
  if (legacyLeases.length === 0) {
1334
294
  return [];
1335
295
  }
@@ -1347,20 +307,20 @@ var OrchestratorFsStore = class {
1347
307
  return migratedIssues;
1348
308
  }
1349
309
  async saveProjectIssueOrchestrations(projectId, issues) {
1350
- await writeJsonFile(join3(this.projectDir(projectId), "issues.json"), issues);
310
+ await writeJsonFile(join2(this.projectDir(projectId), "issues.json"), issues);
1351
311
  }
1352
312
  async saveProjectStatus(status) {
1353
- await writeJsonFile(join3(this.projectDir(status.projectId), "status.json"), status);
313
+ await writeJsonFile(join2(this.projectDir(status.projectId), "status.json"), status);
1354
314
  }
1355
315
  async loadProjectStatus(projectId) {
1356
- return await readJsonFile(join3(this.projectDir(projectId), "status.json")) ?? null;
316
+ return await readJsonFile(join2(this.projectDir(projectId), "status.json")) ?? null;
1357
317
  }
1358
318
  async loadRun(runId, projectId) {
1359
319
  const runDirectory = projectId !== void 0 ? this.runDir(runId, projectId) : await this.findRunDir(runId);
1360
320
  if (!runDirectory) {
1361
321
  return null;
1362
322
  }
1363
- return await readJsonFile(join3(runDirectory, "run.json")) ?? null;
323
+ return await readJsonFile(join2(runDirectory, "run.json")) ?? null;
1364
324
  }
1365
325
  async loadAllRuns() {
1366
326
  const projectIds = await safeReadDir(this.projectsRoot());
@@ -1368,11 +328,11 @@ var OrchestratorFsStore = class {
1368
328
  const entries = await safeReadDir(this.projectRunsDir(projectId));
1369
329
  return entries.map((entry) => this.runDir(entry, projectId));
1370
330
  }));
1371
- const runs = await Promise.all(runDirectories.flat().map((directory) => readJsonFile(join3(directory, "run.json"))));
331
+ const runs = await Promise.all(runDirectories.flat().map((directory) => readJsonFile(join2(directory, "run.json"))));
1372
332
  return runs.filter((run) => Boolean(run));
1373
333
  }
1374
334
  async saveRun(run) {
1375
- await writeJsonFile(join3(this.runDir(run.runId, run.projectId), "run.json"), run);
335
+ await writeJsonFile(join2(this.runDir(run.runId, run.projectId), "run.json"), run);
1376
336
  }
1377
337
  async appendRunEvent(runId, event) {
1378
338
  const resolvedProjectId = "projectId" in event && typeof event.projectId === "string" ? event.projectId : void 0;
@@ -1380,8 +340,8 @@ var OrchestratorFsStore = class {
1380
340
  if (!runDirectory) {
1381
341
  throw new Error(`Unable to resolve run directory for event append: ${runId}`);
1382
342
  }
1383
- const path = join3(runDirectory, "events.ndjson");
1384
- const resolvedPath = resolve3(path);
343
+ const path = join2(runDirectory, "events.ndjson");
344
+ const resolvedPath = resolve(path);
1385
345
  const serializedEvent = JSON.stringify(event) + "\n";
1386
346
  await mkdir2(dirname(path), { recursive: true });
1387
347
  await appendFile(path, serializedEvent, {
@@ -1407,7 +367,7 @@ var OrchestratorFsStore = class {
1407
367
  if (!runDirectory) {
1408
368
  return [];
1409
369
  }
1410
- const path = join3(runDirectory, "events.ndjson");
370
+ const path = join2(runDirectory, "events.ndjson");
1411
371
  try {
1412
372
  if (limit <= 0) {
1413
373
  return [];
@@ -1444,19 +404,19 @@ var OrchestratorFsStore = class {
1444
404
  }
1445
405
  }
1446
406
  issueWorkspaceDir(projectId, workspaceKey) {
1447
- return join3(this.projectDir(projectId), "issues", workspaceKey);
407
+ return join2(this.projectDir(projectId), "issues", workspaceKey);
1448
408
  }
1449
409
  async loadIssueWorkspace(projectId, workspaceKey) {
1450
- return await readJsonFile(join3(this.issueWorkspaceDir(projectId, workspaceKey), "workspace.json")) ?? null;
410
+ return await readJsonFile(join2(this.issueWorkspaceDir(projectId, workspaceKey), "workspace.json")) ?? null;
1451
411
  }
1452
412
  async loadIssueWorkspaces(projectId) {
1453
- const issuesDir = join3(this.projectDir(projectId), "issues");
413
+ const issuesDir = join2(this.projectDir(projectId), "issues");
1454
414
  const entries = await safeReadDir(issuesDir);
1455
415
  const records = await Promise.all(entries.map((entry) => this.loadIssueWorkspace(projectId, entry)));
1456
416
  return records.filter((record) => Boolean(record));
1457
417
  }
1458
418
  async saveIssueWorkspace(record) {
1459
- await writeJsonFile(join3(this.issueWorkspaceDir(record.projectId, record.workspaceKey), "workspace.json"), record);
419
+ await writeJsonFile(join2(this.issueWorkspaceDir(record.projectId, record.workspaceKey), "workspace.json"), record);
1460
420
  }
1461
421
  async removeIssueWorkspace(projectId, workspaceKey) {
1462
422
  const dir = this.issueWorkspaceDir(projectId, workspaceKey);
@@ -1466,8 +426,8 @@ var OrchestratorFsStore = class {
1466
426
  const projectIds = await safeReadDir(this.projectsRoot());
1467
427
  for (const projectId of projectIds) {
1468
428
  const candidate = this.runDir(runId, projectId);
1469
- const run = await readJsonFile(join3(candidate, "run.json"));
1470
- if (run || await pathExists(join3(candidate, "events.ndjson"))) {
429
+ const run = await readJsonFile(join2(candidate, "run.json"));
430
+ if (run || await pathExists(join2(candidate, "events.ndjson"))) {
1471
431
  return candidate;
1472
432
  }
1473
433
  }
@@ -1481,7 +441,7 @@ var OrchestratorFsStore = class {
1481
441
  if (relativePath.startsWith("..")) {
1482
442
  return null;
1483
443
  }
1484
- const mirrorPath = join3(this.resolvedEventsMirrorRoot, relativePath);
444
+ const mirrorPath = join2(this.resolvedEventsMirrorRoot, relativePath);
1485
445
  return mirrorPath === primaryPath ? null : mirrorPath;
1486
446
  }
1487
447
  };
@@ -1493,7 +453,7 @@ async function writeJsonFile(path, value) {
1493
453
  }
1494
454
  async function pathExists(path) {
1495
455
  try {
1496
- await stat3(path);
456
+ await stat2(path);
1497
457
  return true;
1498
458
  } catch (error) {
1499
459
  if (isFileMissing(error)) {
@@ -2126,7 +1086,7 @@ var ISSUE_PROJECT_ITEMS_PAGE_QUERY = `
2126
1086
  `;
2127
1087
 
2128
1088
  // ../tracker-github/dist/orchestrator-adapter.js
2129
- import { createHash as createHash3 } from "crypto";
1089
+ import { createHash } from "crypto";
2130
1090
  var githubProjectTrackerAdapter = {
2131
1091
  async listIssues(project, dependencies = {}) {
2132
1092
  return listProjectIssues(project, dependencies);
@@ -2214,7 +1174,7 @@ function hashToken(token) {
2214
1174
  if (!token) {
2215
1175
  return null;
2216
1176
  }
2217
- return createHash3("sha256").update(token).digest("hex");
1177
+ return createHash("sha256").update(token).digest("hex");
2218
1178
  }
2219
1179
  var trackerAdapters = {
2220
1180
  "github-project": githubProjectTrackerAdapter
@@ -2263,7 +1223,7 @@ function parseIssueNumber(identifier) {
2263
1223
  }
2264
1224
 
2265
1225
  // ../tracker-file/dist/file-tracker-adapter.js
2266
- import { readFile as readFile4 } from "fs/promises";
1226
+ import { readFile as readFile2 } from "fs/promises";
2267
1227
  function requireTrackerSetting2(project, key) {
2268
1228
  const value = project.tracker.settings?.[key];
2269
1229
  if (typeof value !== "string" || value.length === 0) {
@@ -2285,7 +1245,7 @@ var fileTrackerAdapter = {
2285
1245
  async listIssues(project) {
2286
1246
  const issuesPath = requireTrackerSetting2(project, "issuesPath");
2287
1247
  try {
2288
- const raw = await readFile4(issuesPath, "utf-8");
1248
+ const raw = await readFile2(issuesPath, "utf-8");
2289
1249
  const parsed = JSON.parse(raw);
2290
1250
  if (!Array.isArray(parsed)) {
2291
1251
  throw new Error(`Expected an array of issues in ${issuesPath}, got ${typeof parsed}`);
@@ -2369,7 +1329,7 @@ function resolveTrackerAdapter2(tracker) {
2369
1329
  }
2370
1330
 
2371
1331
  // ../orchestrator/dist/service.js
2372
- var DEFAULT_POLL_INTERVAL_MS2 = 3e4;
1332
+ var DEFAULT_POLL_INTERVAL_MS = 3e4;
2373
1333
  var DEFAULT_CONCURRENCY = 3;
2374
1334
  var DEFAULT_RETRY_BACKOFF_MS = 3e4;
2375
1335
  var CONTINUATION_RETRY_DELAY_MS = 1e3;
@@ -2479,7 +1439,7 @@ var OrchestratorService = class {
2479
1439
  codex_session_logs: currentRun === null ? [] : [
2480
1440
  {
2481
1441
  label: "worker",
2482
- path: join4(this.store.runDir(currentRun.runId, currentRun.projectId), "worker.log"),
1442
+ path: join3(this.store.runDir(currentRun.runId, currentRun.projectId), "worker.log"),
2483
1443
  url: null
2484
1444
  }
2485
1445
  ]
@@ -2542,7 +1502,7 @@ var OrchestratorService = class {
2542
1502
  return this.dependencies.pollIntervalMs;
2543
1503
  }
2544
1504
  const configuredIntervals = [...this.projectPollIntervals.values()].filter((value) => Number.isFinite(value) && value > 0);
2545
- return configuredIntervals.length ? Math.min(...configuredIntervals) : DEFAULT_POLL_INTERVAL_MS2;
1505
+ return configuredIntervals.length ? Math.min(...configuredIntervals) : DEFAULT_POLL_INTERVAL_MS;
2546
1506
  }
2547
1507
  async reconcileProject(tenant, issueIdentifier, trackerDependencies = {}) {
2548
1508
  const trackerAdapter = resolveTrackerAdapter2(tenant.tracker);
@@ -2551,7 +1511,7 @@ var OrchestratorService = class {
2551
1511
  let dispatched = 0;
2552
1512
  let suppressed = 0;
2553
1513
  let recovered = 0;
2554
- let pollIntervalMs = DEFAULT_POLL_INTERVAL_MS2;
1514
+ let pollIntervalMs = DEFAULT_POLL_INTERVAL_MS;
2555
1515
  let rateLimits = null;
2556
1516
  let issueRecords = await this.store.loadProjectIssueOrchestrations(tenant.projectId);
2557
1517
  const allRuns = (await this.store.loadAllRuns()).filter((run) => run.projectId === tenant.projectId);
@@ -2870,8 +1830,8 @@ var OrchestratorService = class {
2870
1830
  async runSerialized(operation) {
2871
1831
  const previous = this.reconcilePromise;
2872
1832
  let release;
2873
- this.reconcilePromise = new Promise((resolve6) => {
2874
- release = resolve6;
1833
+ this.reconcilePromise = new Promise((resolve4) => {
1834
+ release = resolve4;
2875
1835
  });
2876
1836
  await previous;
2877
1837
  try {
@@ -2967,7 +1927,7 @@ var OrchestratorService = class {
2967
1927
  return this.loadProjectWorkflowUncached(tenant, repository);
2968
1928
  }
2969
1929
  async loadProjectWorkflowUncached(tenant, repository) {
2970
- const cacheRoot = join4(this.store.projectDir(tenant.projectId), "cache", repository.owner, repository.name);
1930
+ const cacheRoot = join3(this.store.projectDir(tenant.projectId), "cache", repository.owner, repository.name);
2971
1931
  const { repositoryDirectory, changed } = await syncRepositoryForRun({
2972
1932
  repository,
2973
1933
  targetDirectory: cacheRoot
@@ -3055,7 +2015,7 @@ var OrchestratorService = class {
3055
2015
  state: issue.state
3056
2016
  });
3057
2017
  mkdirSync(runDir, { recursive: true });
3058
- const workerLogStream = (this.dependencies.createWriteStreamImpl ?? createWriteStream)(join4(runDir, "worker.log"), {
2018
+ const workerLogStream = (this.dependencies.createWriteStreamImpl ?? createWriteStream)(join3(runDir, "worker.log"), {
3059
2019
  flags: "a"
3060
2020
  });
3061
2021
  let workerLogAvailable = true;
@@ -3078,7 +2038,7 @@ var OrchestratorService = class {
3078
2038
  const message = error instanceof Error ? error.message : String(error ?? "unknown");
3079
2039
  this.writeStderr(`[orchestrator] failed to write worker log for ${runId}: ${message}`);
3080
2040
  };
3081
- const child = (this.dependencies.spawnImpl ?? spawn3)("bash", ["-lc", resolveWorkerCommand()], {
2041
+ const child = (this.dependencies.spawnImpl ?? spawn2)("bash", ["-lc", resolveWorkerCommand()], {
3082
2042
  cwd: process.cwd(),
3083
2043
  env: this.buildProjectExecutionEnv(tenant.projectId, {
3084
2044
  GITHUB_GRAPHQL_TOKEN: process.env.GITHUB_GRAPHQL_TOKEN ?? "",
@@ -3624,11 +2584,11 @@ var OrchestratorService = class {
3624
2584
  this.sleepResolver = null;
3625
2585
  }
3626
2586
  createPendingSleepPromise() {
3627
- return new Promise((resolve6) => {
2587
+ return new Promise((resolve4) => {
3628
2588
  this.sleepResolver = () => {
3629
2589
  this.sleepResolver = null;
3630
2590
  this.sleepTimer = null;
3631
- resolve6();
2591
+ resolve4();
3632
2592
  };
3633
2593
  });
3634
2594
  }
@@ -3709,12 +2669,12 @@ var OrchestratorService = class {
3709
2669
  }
3710
2670
  async readPersistedWorkerTokenUsage(run) {
3711
2671
  const artifactPaths = [
3712
- join4(run.workspaceRuntimeDir, "token-usage.json"),
3713
- join4(run.workspaceRuntimeDir, ".orchestrator", "runs", run.runId, "token-usage.json")
2672
+ join3(run.workspaceRuntimeDir, "token-usage.json"),
2673
+ join3(run.workspaceRuntimeDir, ".orchestrator", "runs", run.runId, "token-usage.json")
3714
2674
  ];
3715
2675
  for (const artifactPath of artifactPaths) {
3716
2676
  try {
3717
- const raw = await readFile5(artifactPath, "utf8");
2677
+ const raw = await readFile3(artifactPath, "utf8");
3718
2678
  const tokenUsage = JSON.parse(raw);
3719
2679
  if (hasTokenUsage(tokenUsage)) {
3720
2680
  return tokenUsage;
@@ -3749,7 +2709,7 @@ var OrchestratorService = class {
3749
2709
  }
3750
2710
  }
3751
2711
  readProjectEnv(projectId) {
3752
- const envPath = join4(this.store.projectDir(projectId), ".env");
2712
+ const envPath = join3(this.store.projectDir(projectId), ".env");
3753
2713
  try {
3754
2714
  return readEnvFile(envPath);
3755
2715
  } catch (error) {
@@ -3844,7 +2804,7 @@ var OrchestratorService = class {
3844
2804
  return isUsableWorkflowResolution(resolution) ? resolution.workflow.polling.intervalMs : NaN;
3845
2805
  }));
3846
2806
  const validIntervals = intervals.filter((value) => Number.isFinite(value) && value > 0);
3847
- return validIntervals.length ? Math.min(...validIntervals) : DEFAULT_POLL_INTERVAL_MS2;
2807
+ return validIntervals.length ? Math.min(...validIntervals) : DEFAULT_POLL_INTERVAL_MS;
3848
2808
  }
3849
2809
  async loadProjectMaxConcurrentByState(tenant) {
3850
2810
  const result = {};
@@ -3952,13 +2912,13 @@ var OrchestratorService = class {
3952
2912
  return null;
3953
2913
  }
3954
2914
  const snapshotPath = this.lastKnownGoodWorkflowPath(cacheRoot);
3955
- const markdown = await readFile5(resolution.workflowPath, "utf8");
3956
- await mkdir3(join4(cacheRoot, "last-known-good"), { recursive: true });
2915
+ const markdown = await readFile3(resolution.workflowPath, "utf8");
2916
+ await mkdir3(join3(cacheRoot, "last-known-good"), { recursive: true });
3957
2917
  await writeFile3(snapshotPath, markdown, "utf8");
3958
2918
  return snapshotPath;
3959
2919
  }
3960
2920
  lastKnownGoodWorkflowPath(cacheRoot) {
3961
- return join4(cacheRoot, "last-known-good", "WORKFLOW.md");
2921
+ return join3(cacheRoot, "last-known-good", "WORKFLOW.md");
3962
2922
  }
3963
2923
  workflowCacheKey(repository) {
3964
2924
  return `${repository.owner}/${repository.name}:${this.normalizeRepositoryCloneUrl(repository.cloneUrl)}`;
@@ -4064,14 +3024,14 @@ var OrchestratorService = class {
4064
3024
  function hasTokenUsage(tokenUsage) {
4065
3025
  return Boolean(tokenUsage && (tokenUsage.inputTokens > 0 || tokenUsage.outputTokens > 0 || tokenUsage.totalTokens > 0));
4066
3026
  }
4067
- function isRecord2(value) {
3027
+ function isRecord(value) {
4068
3028
  return !!value && typeof value === "object" && !Array.isArray(value);
4069
3029
  }
4070
3030
  function resolveProjectRateLimits(runs, issues) {
4071
3031
  let latestRunRateLimits = null;
4072
3032
  let latestRunTimestamp = -Infinity;
4073
3033
  for (const run of runs) {
4074
- if (!isRecord2(run.rateLimits)) {
3034
+ if (!isRecord(run.rateLimits)) {
4075
3035
  continue;
4076
3036
  }
4077
3037
  const timestamp = parseTimestampMs(run.lastEventAt ?? run.updatedAt ?? run.startedAt);
@@ -4085,7 +3045,7 @@ function resolveProjectRateLimits(runs, issues) {
4085
3045
  return latestRunRateLimits;
4086
3046
  }
4087
3047
  for (const issue of issues) {
4088
- if (isRecord2(issue.rateLimits)) {
3048
+ if (isRecord(issue.rateLimits)) {
4089
3049
  return issue.rateLimits;
4090
3050
  }
4091
3051
  }
@@ -4191,7 +3151,12 @@ function resolveWorkerCommand() {
4191
3151
  const workerUrl = import.meta.resolve("@gh-symphony/worker");
4192
3152
  return `node ${fileURLToPath(workerUrl)}`;
4193
3153
  } catch {
4194
- return DEFAULT_WORKER_COMMAND;
3154
+ try {
3155
+ const bundledWorker = join3(fileURLToPath(new URL(".", import.meta.url)), "worker-entry.js");
3156
+ return `node ${bundledWorker}`;
3157
+ } catch {
3158
+ return DEFAULT_WORKER_COMMAND;
3159
+ }
4195
3160
  }
4196
3161
  }
4197
3162
  function createStore(runtimeRoot = ".runtime", options = {}) {
@@ -4234,7 +3199,7 @@ function createProjectItemsCache() {
4234
3199
  };
4235
3200
  }
4236
3201
  function wait2(ms) {
4237
- return new Promise((resolve6) => setTimeout(resolve6, ms));
3202
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
4238
3203
  }
4239
3204
  function createRunId(now, projectId, issueIdentifier) {
4240
3205
  return [
@@ -4272,8 +3237,8 @@ function isActiveRunStatus(status) {
4272
3237
 
4273
3238
  // ../orchestrator/dist/lock.js
4274
3239
  import { randomUUID as randomUUID2 } from "crypto";
4275
- import { mkdir as mkdir4, open as open2, readFile as readFile6, rm as rm4 } from "fs/promises";
4276
- import { dirname as dirname2, isAbsolute, join as join5, relative as relative2, resolve as resolve4 } from "path";
3240
+ import { mkdir as mkdir4, open as open2, readFile as readFile4, rm as rm4 } from "fs/promises";
3241
+ import { dirname as dirname2, isAbsolute, join as join4, relative as relative2, resolve as resolve2 } from "path";
4277
3242
  import { setTimeout as delay } from "timers/promises";
4278
3243
  var LOCK_READ_RETRY_DELAY_MS = 10;
4279
3244
  var LOCK_READ_RETRY_LIMIT = 20;
@@ -4339,7 +3304,7 @@ async function releaseProjectLock(lock) {
4339
3304
  }
4340
3305
  async function readProjectLock(lockPath) {
4341
3306
  try {
4342
- const raw = await readFile6(lockPath, "utf8");
3307
+ const raw = await readFile4(lockPath, "utf8");
4343
3308
  const record = parseProjectLock(raw);
4344
3309
  if (!record) {
4345
3310
  return { status: "invalid" };
@@ -4359,13 +3324,13 @@ function assertValidProjectId(projectId) {
4359
3324
  }
4360
3325
  function resolveProjectLockPath(runtimeRoot, projectId) {
4361
3326
  const store = new OrchestratorFsStore(runtimeRoot);
4362
- const projectsRoot = resolve4(runtimeRoot, "projects");
4363
- const projectDir = resolve4(store.projectDir(projectId));
3327
+ const projectsRoot = resolve2(runtimeRoot, "projects");
3328
+ const projectDir = resolve2(store.projectDir(projectId));
4364
3329
  const relativeProjectDir = relative2(projectsRoot, projectDir);
4365
3330
  if (relativeProjectDir.length === 0 || relativeProjectDir.startsWith("..") || isAbsolute(relativeProjectDir)) {
4366
3331
  throw new Error(`Invalid project ID "${projectId}". Project lock path must stay within "${projectsRoot}".`);
4367
3332
  }
4368
- return join5(projectDir, ".lock");
3333
+ return join4(projectDir, ".lock");
4369
3334
  }
4370
3335
  function parseProjectLock(raw) {
4371
3336
  try {
@@ -4399,7 +3364,7 @@ function isMissingFileError2(error) {
4399
3364
 
4400
3365
  // ../orchestrator/dist/index.js
4401
3366
  import { pathToFileURL } from "url";
4402
- import { resolve as resolve5 } from "path";
3367
+ import { resolve as resolve3 } from "path";
4403
3368
  function resolveOrchestratorLogLevel(value) {
4404
3369
  if (!value || value === "normal") {
4405
3370
  return "normal";
@@ -4415,7 +3380,7 @@ async function runCli(argv, dependencies = {}) {
4415
3380
  if (parsed.projectId) {
4416
3381
  assertValidProjectId(parsed.projectId);
4417
3382
  }
4418
- const runtimeRoot = resolve5(parsed.runtimeRoot ?? ".runtime");
3383
+ const runtimeRoot = resolve3(parsed.runtimeRoot ?? ".runtime");
4419
3384
  const stderr = dependencies.stderr ?? process.stderr;
4420
3385
  const eventsDir = resolveOptionalPath(parsed.eventsDir ?? process.env.SYMPHONY_EVENTS_DIR);
4421
3386
  const logLevel = resolveOrchestratorLogLevel(parsed.logLevel ?? process.env.SYMPHONY_LOG_LEVEL);
@@ -4590,7 +3555,7 @@ function resolveOptionalPath(value) {
4590
3555
  if (!value || value.trim().length === 0) {
4591
3556
  return void 0;
4592
3557
  }
4593
- return resolve5(value.trim());
3558
+ return resolve3(value.trim());
4594
3559
  }
4595
3560
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
4596
3561
  main().catch((error) => {
@@ -4601,13 +3566,6 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
4601
3566
  }
4602
3567
 
4603
3568
  export {
4604
- deriveIssueWorkspaceKeyFromIdentifier,
4605
- readJsonFile,
4606
- safeReadDir,
4607
- isFileMissing,
4608
- parseRecentEvents,
4609
- isMatchingIssueRun,
4610
- mapIssueOrchestrationStateToStatus,
4611
3569
  OrchestratorService,
4612
3570
  createStore,
4613
3571
  acquireProjectLock,