@gh-symphony/cli 0.0.14 → 0.0.16

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 (102) hide show
  1. package/dist/chunk-5NV3LSAJ.js +11 -0
  2. package/dist/chunk-6HBZC3BE.js +468 -0
  3. package/dist/chunk-76QPITKI.js +109 -0
  4. package/dist/chunk-EFMFGOWM.js +3575 -0
  5. package/dist/chunk-IWR4UQEJ.js +2250 -0
  6. package/dist/chunk-JO3AXHQI.js +130 -0
  7. package/dist/chunk-MHIWAIVD.js +876 -0
  8. package/dist/chunk-MVRF7BES.js +68 -0
  9. package/dist/chunk-ROGRTUFI.js +108 -0
  10. package/dist/chunk-TF3QNWNC.js +1121 -0
  11. package/dist/chunk-TH5QPO3Y.js +67 -0
  12. package/dist/config-cmd-AZ7POMAA.js +110 -0
  13. package/dist/index.d.ts +5 -4
  14. package/dist/index.js +568 -356
  15. package/dist/init-EZXQAXZM.js +17 -0
  16. package/dist/logs-6LNGT2GF.js +188 -0
  17. package/dist/project-557FE2GD.js +679 -0
  18. package/dist/recover-LVBI2TGH.js +131 -0
  19. package/dist/repo-R3XBIVAX.js +121 -0
  20. package/dist/run-WITYAYFZ.js +108 -0
  21. package/dist/start-JUFKNL3N.js +16 -0
  22. package/dist/status-3WK5BWRZ.js +11 -0
  23. package/dist/stop-AA3AP5M6.js +9 -0
  24. package/dist/version-VBB62JWI.js +30 -0
  25. package/dist/worker-entry.js +1828 -0
  26. package/package.json +9 -4
  27. package/dist/ansi.d.ts +0 -15
  28. package/dist/ansi.js +0 -53
  29. package/dist/commands/config-cmd.d.ts +0 -3
  30. package/dist/commands/config-cmd.js +0 -90
  31. package/dist/commands/help.d.ts +0 -3
  32. package/dist/commands/help.js +0 -55
  33. package/dist/commands/init.d.ts +0 -34
  34. package/dist/commands/init.js +0 -477
  35. package/dist/commands/logs.d.ts +0 -3
  36. package/dist/commands/logs.js +0 -184
  37. package/dist/commands/project.d.ts +0 -3
  38. package/dist/commands/project.js +0 -649
  39. package/dist/commands/recover.d.ts +0 -3
  40. package/dist/commands/recover.js +0 -119
  41. package/dist/commands/repo.d.ts +0 -3
  42. package/dist/commands/repo.js +0 -103
  43. package/dist/commands/run.d.ts +0 -3
  44. package/dist/commands/run.js +0 -95
  45. package/dist/commands/start.d.ts +0 -20
  46. package/dist/commands/start.js +0 -344
  47. package/dist/commands/status-refresh.d.ts +0 -9
  48. package/dist/commands/status-refresh.js +0 -27
  49. package/dist/commands/status.d.ts +0 -3
  50. package/dist/commands/status.js +0 -237
  51. package/dist/commands/stop.d.ts +0 -3
  52. package/dist/commands/stop.js +0 -92
  53. package/dist/commands/version.d.ts +0 -3
  54. package/dist/commands/version.js +0 -21
  55. package/dist/completion.d.ts +0 -1
  56. package/dist/completion.js +0 -204
  57. package/dist/config.d.ts +0 -38
  58. package/dist/config.js +0 -82
  59. package/dist/context/context-types.d.ts +0 -36
  60. package/dist/context/context-types.js +0 -1
  61. package/dist/context/generate-context-yaml.d.ts +0 -15
  62. package/dist/context/generate-context-yaml.js +0 -129
  63. package/dist/dashboard/renderer.d.ts +0 -9
  64. package/dist/dashboard/renderer.js +0 -220
  65. package/dist/detection/environment-detector.d.ts +0 -11
  66. package/dist/detection/environment-detector.js +0 -140
  67. package/dist/github/client.d.ts +0 -71
  68. package/dist/github/client.js +0 -348
  69. package/dist/github/gh-auth.d.ts +0 -34
  70. package/dist/github/gh-auth.js +0 -110
  71. package/dist/mapping/smart-defaults.d.ts +0 -17
  72. package/dist/mapping/smart-defaults.js +0 -86
  73. package/dist/orchestrator-runtime.d.ts +0 -1
  74. package/dist/orchestrator-runtime.js +0 -4
  75. package/dist/orchestrator-status-endpoint.d.ts +0 -5
  76. package/dist/orchestrator-status-endpoint.js +0 -27
  77. package/dist/project-selection.d.ts +0 -8
  78. package/dist/project-selection.js +0 -56
  79. package/dist/skills/skill-writer.d.ts +0 -14
  80. package/dist/skills/skill-writer.js +0 -62
  81. package/dist/skills/templates/commit.d.ts +0 -2
  82. package/dist/skills/templates/commit.js +0 -45
  83. package/dist/skills/templates/document.d.ts +0 -7
  84. package/dist/skills/templates/document.js +0 -16
  85. package/dist/skills/templates/gh-project.d.ts +0 -2
  86. package/dist/skills/templates/gh-project.js +0 -88
  87. package/dist/skills/templates/gh-symphony.d.ts +0 -2
  88. package/dist/skills/templates/gh-symphony.js +0 -125
  89. package/dist/skills/templates/index.d.ts +0 -8
  90. package/dist/skills/templates/index.js +0 -28
  91. package/dist/skills/templates/land.d.ts +0 -2
  92. package/dist/skills/templates/land.js +0 -59
  93. package/dist/skills/templates/pull.d.ts +0 -2
  94. package/dist/skills/templates/pull.js +0 -41
  95. package/dist/skills/templates/push.d.ts +0 -2
  96. package/dist/skills/templates/push.js +0 -36
  97. package/dist/skills/types.d.ts +0 -23
  98. package/dist/skills/types.js +0 -1
  99. package/dist/workflow/generate-reference-workflow.d.ts +0 -9
  100. package/dist/workflow/generate-reference-workflow.js +0 -261
  101. package/dist/workflow/generate-workflow-md.d.ts +0 -12
  102. package/dist/workflow/generate-workflow-md.js +0 -134
@@ -0,0 +1,1121 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ../core/dist/contracts/status-surface.js
4
+ var WORKFLOW_EXECUTION_PHASES = [
5
+ "planning",
6
+ "human-review",
7
+ "implementation",
8
+ "awaiting-merge",
9
+ "completed"
10
+ ];
11
+ function isWorkflowExecutionPhase(value) {
12
+ return typeof value === "string" && WORKFLOW_EXECUTION_PHASES.includes(value);
13
+ }
14
+ var SESSION_EXIT_CLASSIFICATIONS = [
15
+ "completed",
16
+ "budget-exceeded",
17
+ "convergence-detected",
18
+ "max-turns-reached",
19
+ "user-input-required",
20
+ "timeout",
21
+ "error"
22
+ ];
23
+ function isSessionExitClassification(value) {
24
+ return typeof value === "string" && SESSION_EXIT_CLASSIFICATIONS.includes(value);
25
+ }
26
+
27
+ // ../core/dist/contracts/run-attempt-phase.js
28
+ var RUN_ATTEMPT_PHASES = [
29
+ "preparing_workspace",
30
+ "building_prompt",
31
+ "launching_agent",
32
+ "initializing_session",
33
+ "streaming_turn",
34
+ "finishing",
35
+ "succeeded",
36
+ "failed",
37
+ "timed_out",
38
+ "stalled",
39
+ "canceled_by_reconciliation"
40
+ ];
41
+ function isRunAttemptPhase(value) {
42
+ return typeof value === "string" && RUN_ATTEMPT_PHASES.includes(value);
43
+ }
44
+
45
+ // ../core/dist/contracts/orchestrator-channel.js
46
+ function isRecord(value) {
47
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
48
+ }
49
+ function isTokenUsage(value) {
50
+ if (!isRecord(value)) {
51
+ return false;
52
+ }
53
+ return typeof value.inputTokens === "number" && typeof value.outputTokens === "number" && typeof value.totalTokens === "number";
54
+ }
55
+ function isSessionInfo(value) {
56
+ if (!isRecord(value)) {
57
+ return false;
58
+ }
59
+ 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));
60
+ }
61
+ function isNullableString(value) {
62
+ return typeof value === "string" || value === null;
63
+ }
64
+ function isTurnEventBase(value) {
65
+ return typeof value.startedAt === "string" && isNullableString(value.threadId) && isNullableString(value.turnId) && typeof value.turnCount === "number" && isNullableString(value.sessionId);
66
+ }
67
+ function isOrchestratorChannelEvent(value) {
68
+ if (!isRecord(value)) {
69
+ return false;
70
+ }
71
+ if (typeof value.issueId !== "string") {
72
+ return false;
73
+ }
74
+ if (value.type === "codex_update") {
75
+ if (typeof value.lastEventAt !== "string") {
76
+ return false;
77
+ }
78
+ if ("event" in value && value.event !== void 0 && typeof value.event !== "string") {
79
+ return false;
80
+ }
81
+ if ("tokenUsage" in value && value.tokenUsage !== void 0 && !isTokenUsage(value.tokenUsage)) {
82
+ return false;
83
+ }
84
+ if ("rateLimits" in value && value.rateLimits !== void 0 && !isRecord(value.rateLimits)) {
85
+ return false;
86
+ }
87
+ if ("sessionInfo" in value && value.sessionInfo !== void 0 && !isSessionInfo(value.sessionInfo)) {
88
+ return false;
89
+ }
90
+ if ("executionPhase" in value && value.executionPhase !== void 0 && value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
91
+ return false;
92
+ }
93
+ if ("runPhase" in value && value.runPhase !== void 0 && value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
94
+ return false;
95
+ }
96
+ if ("lastError" in value && value.lastError !== void 0 && value.lastError !== null && typeof value.lastError !== "string") {
97
+ return false;
98
+ }
99
+ return true;
100
+ }
101
+ if (value.type === "heartbeat") {
102
+ if (value.lastEventAt !== null && typeof value.lastEventAt !== "string") {
103
+ return false;
104
+ }
105
+ if (!isTokenUsage(value.tokenUsage)) {
106
+ return false;
107
+ }
108
+ if (value.rateLimits !== null && !isRecord(value.rateLimits)) {
109
+ return false;
110
+ }
111
+ if (value.sessionInfo !== null && !isSessionInfo(value.sessionInfo)) {
112
+ return false;
113
+ }
114
+ if (value.executionPhase !== null && !isWorkflowExecutionPhase(value.executionPhase)) {
115
+ return false;
116
+ }
117
+ if (value.runPhase !== null && !isRunAttemptPhase(value.runPhase)) {
118
+ return false;
119
+ }
120
+ if (value.lastError !== null && typeof value.lastError !== "string") {
121
+ return false;
122
+ }
123
+ return true;
124
+ }
125
+ if (value.type === "turn_started") {
126
+ return isTurnEventBase(value);
127
+ }
128
+ if (value.type === "turn_completed") {
129
+ return isTurnEventBase(value) && typeof value.completedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage);
130
+ }
131
+ if (value.type === "turn_failed") {
132
+ return isTurnEventBase(value) && typeof value.failedAt === "string" && typeof value.durationMs === "number" && isTokenUsage(value.tokenUsage) && isNullableString(value.error);
133
+ }
134
+ return false;
135
+ }
136
+
137
+ // ../core/dist/workflow/lifecycle.js
138
+ var DEFAULT_WORKFLOW_LIFECYCLE = {
139
+ stateFieldName: "Status",
140
+ activeStates: ["Todo", "In Progress"],
141
+ terminalStates: ["Done"],
142
+ blockerCheckStates: ["Todo"]
143
+ };
144
+ function isStateActive(state, lifecycle) {
145
+ return matchesWorkflowState(state, lifecycle.activeStates);
146
+ }
147
+ function isStateTerminal(state, lifecycle) {
148
+ return matchesWorkflowState(state, lifecycle.terminalStates);
149
+ }
150
+ function matchesWorkflowState(state, candidates) {
151
+ const normalizedState = normalizeWorkflowState(state);
152
+ return candidates.some((candidate) => normalizeWorkflowState(candidate) === normalizedState);
153
+ }
154
+ function normalizeWorkflowState(state) {
155
+ return state.trim().toLowerCase();
156
+ }
157
+
158
+ // ../core/dist/workflow/config.js
159
+ var DEFAULT_CODEX_COMMAND = "codex app-server";
160
+ var DEFAULT_AGENT_COMMAND = DEFAULT_CODEX_COMMAND;
161
+ var DEFAULT_HOOK_TIMEOUT_MS = 6e4;
162
+ var DEFAULT_POLL_INTERVAL_MS = 3e4;
163
+ var DEFAULT_MAX_RETRY_BACKOFF_MS = 3e5;
164
+ var DEFAULT_MAX_DELAY_MS = DEFAULT_MAX_RETRY_BACKOFF_MS;
165
+ var DEFAULT_BASE_DELAY_MS = 1e4;
166
+ var DEFAULT_MAX_TURNS = 20;
167
+ var DEFAULT_READ_TIMEOUT_MS = 5e3;
168
+ var DEFAULT_TURN_TIMEOUT_MS = 36e5;
169
+ var DEFAULT_STALL_TIMEOUT_MS = 3e5;
170
+ var DEFAULT_MAX_CONCURRENT_AGENTS = 10;
171
+ var DEFAULT_WORKFLOW_HOOKS = {
172
+ afterCreate: null,
173
+ beforeRun: null,
174
+ afterRun: null,
175
+ beforeRemove: null,
176
+ timeoutMs: DEFAULT_HOOK_TIMEOUT_MS
177
+ };
178
+ var DEFAULT_WORKFLOW_TRACKER = {
179
+ kind: null,
180
+ endpoint: null,
181
+ apiKey: null,
182
+ projectSlug: null,
183
+ activeStates: DEFAULT_WORKFLOW_LIFECYCLE.activeStates,
184
+ terminalStates: DEFAULT_WORKFLOW_LIFECYCLE.terminalStates,
185
+ projectId: null,
186
+ stateFieldName: DEFAULT_WORKFLOW_LIFECYCLE.stateFieldName,
187
+ priorityFieldName: null,
188
+ blockerCheckStates: DEFAULT_WORKFLOW_LIFECYCLE.blockerCheckStates
189
+ };
190
+ var DEFAULT_WORKFLOW_WORKSPACE = {
191
+ root: null
192
+ };
193
+ var DEFAULT_WORKFLOW_AGENT = {
194
+ maxConcurrentAgents: DEFAULT_MAX_CONCURRENT_AGENTS,
195
+ maxRetryBackoffMs: DEFAULT_MAX_RETRY_BACKOFF_MS,
196
+ maxConcurrentAgentsByState: {},
197
+ maxTurns: DEFAULT_MAX_TURNS,
198
+ retryBaseDelayMs: DEFAULT_BASE_DELAY_MS
199
+ };
200
+ var DEFAULT_WORKFLOW_CODEX = {
201
+ command: DEFAULT_CODEX_COMMAND,
202
+ approvalPolicy: null,
203
+ threadSandbox: null,
204
+ turnSandboxPolicy: null,
205
+ turnTimeoutMs: DEFAULT_TURN_TIMEOUT_MS,
206
+ readTimeoutMs: DEFAULT_READ_TIMEOUT_MS,
207
+ stallTimeoutMs: DEFAULT_STALL_TIMEOUT_MS
208
+ };
209
+ var DEFAULT_WORKFLOW_DEFINITION = {
210
+ promptTemplate: "",
211
+ continuationGuidance: null,
212
+ tracker: DEFAULT_WORKFLOW_TRACKER,
213
+ polling: {
214
+ intervalMs: DEFAULT_POLL_INTERVAL_MS
215
+ },
216
+ workspace: DEFAULT_WORKFLOW_WORKSPACE,
217
+ hooks: DEFAULT_WORKFLOW_HOOKS,
218
+ agent: DEFAULT_WORKFLOW_AGENT,
219
+ codex: DEFAULT_WORKFLOW_CODEX,
220
+ lifecycle: DEFAULT_WORKFLOW_LIFECYCLE,
221
+ format: "default",
222
+ githubProjectId: null,
223
+ agentCommand: DEFAULT_CODEX_COMMAND,
224
+ hookPath: null,
225
+ maxConcurrentByState: {}
226
+ };
227
+
228
+ // ../core/dist/workflow/parser.js
229
+ function parseWorkflowMarkdown(markdown, env = process.env, options = {}) {
230
+ const compatibilityMode = options.compatibilityMode ?? "strict";
231
+ const frontMatterMatch = markdown.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
232
+ if (!frontMatterMatch) {
233
+ if (compatibilityMode === "legacy") {
234
+ return parseLegacyWorkflowMarkdown(markdown);
235
+ }
236
+ throw new Error("WORKFLOW.md must use YAML front matter.");
237
+ }
238
+ const [, rawFrontMatter, rawPromptTemplate = ""] = frontMatterMatch;
239
+ const frontMatter = parseFrontMatter(rawFrontMatter);
240
+ const promptTemplate = rawPromptTemplate.trim();
241
+ const tracker = readRequiredObject(frontMatter, "tracker");
242
+ const polling = readObject(frontMatter, "polling");
243
+ const workspace = readObject(frontMatter, "workspace");
244
+ const hooks = readObject(frontMatter, "hooks");
245
+ const agent = readObject(frontMatter, "agent");
246
+ const codex = readRequiredObject(frontMatter, "codex");
247
+ const trackerKind = readRequiredString(tracker, "kind", env);
248
+ const activeStates = readStringList(tracker, "active_states") ?? DEFAULT_WORKFLOW_TRACKER.activeStates;
249
+ const terminalStates = readStringList(tracker, "terminal_states") ?? DEFAULT_WORKFLOW_TRACKER.terminalStates;
250
+ const blockerCheckStates = readStringList(tracker, "blocker_check_states") ?? DEFAULT_WORKFLOW_TRACKER.blockerCheckStates;
251
+ const maxConcurrentAgentsByState = readNumberMap(agent, "max_concurrent_agents_by_state");
252
+ const command = readOptionalString(codex, "command", env) ?? DEFAULT_AGENT_COMMAND;
253
+ const parsed = {
254
+ promptTemplate,
255
+ continuationGuidance: readOptionalWorkflowString(frontMatter, "continuationGuidance", "continuation_guidance", env),
256
+ tracker: {
257
+ kind: trackerKind,
258
+ endpoint: readOptionalString(tracker, "endpoint", env),
259
+ apiKey: readOptionalString(tracker, "api_key", env),
260
+ projectSlug: readOptionalString(tracker, "project_slug", env),
261
+ activeStates,
262
+ terminalStates,
263
+ projectId: readOptionalString(tracker, "project_id", env),
264
+ stateFieldName: readOptionalString(tracker, "state_field", env) ?? DEFAULT_WORKFLOW_TRACKER.stateFieldName,
265
+ priorityFieldName: readOptionalString(tracker, "priority_field", env),
266
+ blockerCheckStates
267
+ },
268
+ polling: {
269
+ intervalMs: readOptionalIntegerLike(polling, "interval_ms") ?? DEFAULT_POLL_INTERVAL_MS
270
+ },
271
+ workspace: {
272
+ root: readOptionalString(workspace, "root", env)
273
+ },
274
+ hooks: {
275
+ afterCreate: readOptionalString(hooks, "after_create", env),
276
+ beforeRun: readOptionalString(hooks, "before_run", env),
277
+ afterRun: readOptionalString(hooks, "after_run", env),
278
+ beforeRemove: readOptionalString(hooks, "before_remove", env),
279
+ timeoutMs: readOptionalIntegerLike(hooks, "timeout_ms") ?? DEFAULT_HOOK_TIMEOUT_MS
280
+ },
281
+ agent: {
282
+ maxConcurrentAgents: readOptionalIntegerLike(agent, "max_concurrent_agents") ?? DEFAULT_MAX_CONCURRENT_AGENTS,
283
+ maxRetryBackoffMs: readOptionalIntegerLike(agent, "max_retry_backoff_ms") ?? DEFAULT_MAX_RETRY_BACKOFF_MS,
284
+ maxConcurrentAgentsByState,
285
+ maxTurns: readOptionalIntegerLike(agent, "max_turns") ?? DEFAULT_MAX_TURNS,
286
+ retryBaseDelayMs: readOptionalIntegerLike(agent, "retry_base_delay_ms") ?? DEFAULT_BASE_DELAY_MS
287
+ },
288
+ codex: {
289
+ command,
290
+ approvalPolicy: readOptionalString(codex, "approval_policy", env),
291
+ threadSandbox: readOptionalString(codex, "thread_sandbox", env),
292
+ turnSandboxPolicy: readOptionalString(codex, "turn_sandbox_policy", env),
293
+ turnTimeoutMs: readOptionalIntegerLike(codex, "turn_timeout_ms") ?? DEFAULT_TURN_TIMEOUT_MS,
294
+ readTimeoutMs: readOptionalIntegerLike(codex, "read_timeout_ms") ?? DEFAULT_READ_TIMEOUT_MS,
295
+ stallTimeoutMs: readOptionalIntegerLike(codex, "stall_timeout_ms") ?? DEFAULT_STALL_TIMEOUT_MS
296
+ },
297
+ lifecycle: {
298
+ stateFieldName: readOptionalString(tracker, "state_field", env) ?? DEFAULT_WORKFLOW_TRACKER.stateFieldName,
299
+ activeStates,
300
+ terminalStates,
301
+ blockerCheckStates
302
+ },
303
+ format: "front-matter",
304
+ githubProjectId: readOptionalString(tracker, "project_id", env),
305
+ agentCommand: command,
306
+ hookPath: readOptionalString(hooks, "after_create", env),
307
+ maxConcurrentByState: maxConcurrentAgentsByState
308
+ };
309
+ return parsed;
310
+ }
311
+ function parseLegacyWorkflowMarkdown(markdown) {
312
+ const promptGuidelines = matchOptionalSection(markdown, "Prompt Guidelines") ?? "";
313
+ return {
314
+ ...DEFAULT_WORKFLOW_DEFINITION,
315
+ promptTemplate: promptGuidelines,
316
+ format: "legacy-sectioned"
317
+ };
318
+ }
319
+ function parseFrontMatter(frontMatter) {
320
+ const lines = frontMatter.replace(/\r\n/g, "\n").split("\n");
321
+ const [value] = parseBlock(lines, 0, 0);
322
+ if (!value || Array.isArray(value) || typeof value !== "object") {
323
+ throw new Error("Workflow front matter must be a YAML object.");
324
+ }
325
+ return value;
326
+ }
327
+ function parseBlock(lines, startIndex, indent) {
328
+ let index = startIndex;
329
+ let collectionType = null;
330
+ const arrayValues = [];
331
+ const objectValues = {};
332
+ while (index < lines.length) {
333
+ const line = lines[index] ?? "";
334
+ if (!line.trim()) {
335
+ index += 1;
336
+ continue;
337
+ }
338
+ const lineIndent = countIndent(line);
339
+ if (lineIndent < indent) {
340
+ break;
341
+ }
342
+ if (lineIndent > indent) {
343
+ throw new Error(`Invalid workflow front matter indentation near "${line.trim()}".`);
344
+ }
345
+ const trimmed = line.trim();
346
+ if (trimmed.startsWith("- ")) {
347
+ if (collectionType === "object") {
348
+ throw new Error("Cannot mix array and object values in workflow front matter.");
349
+ }
350
+ collectionType = "array";
351
+ const itemText = trimmed.slice(2).trim();
352
+ if (itemText === "|" || itemText === "|-") {
353
+ const [multiline, nextIndex3] = parseMultilineScalar(lines, index + 1, indent + 2);
354
+ arrayValues.push(multiline);
355
+ index = nextIndex3;
356
+ continue;
357
+ }
358
+ if (itemText) {
359
+ arrayValues.push(parseScalar(itemText));
360
+ index += 1;
361
+ continue;
362
+ }
363
+ const [child2, nextIndex2] = parseBlock(lines, index + 1, indent + 2);
364
+ arrayValues.push(child2);
365
+ index = nextIndex2;
366
+ continue;
367
+ }
368
+ if (collectionType === "array") {
369
+ throw new Error("Cannot mix object and array values in workflow front matter.");
370
+ }
371
+ collectionType = "object";
372
+ const separatorIndex = trimmed.indexOf(":");
373
+ if (separatorIndex < 0) {
374
+ throw new Error(`Invalid workflow front matter line "${trimmed}".`);
375
+ }
376
+ const key = trimmed.slice(0, separatorIndex).trim();
377
+ const remainder = trimmed.slice(separatorIndex + 1).trim();
378
+ if (remainder === "|" || remainder === "|-") {
379
+ const [multiline, nextIndex2] = parseMultilineScalar(lines, index + 1, indent + 2);
380
+ objectValues[key] = multiline;
381
+ index = nextIndex2;
382
+ continue;
383
+ }
384
+ if (remainder) {
385
+ objectValues[key] = parseScalar(remainder);
386
+ index += 1;
387
+ continue;
388
+ }
389
+ const [child, nextIndex] = parseBlock(lines, index + 1, indent + 2);
390
+ objectValues[key] = child;
391
+ index = nextIndex;
392
+ }
393
+ return [collectionType === "array" ? arrayValues : objectValues, index];
394
+ }
395
+ function parseMultilineScalar(lines, startIndex, indent) {
396
+ let index = startIndex;
397
+ const collected = [];
398
+ while (index < lines.length) {
399
+ const line = lines[index] ?? "";
400
+ if (!line.trim()) {
401
+ collected.push("");
402
+ index += 1;
403
+ continue;
404
+ }
405
+ const lineIndent = countIndent(line);
406
+ if (lineIndent < indent) {
407
+ break;
408
+ }
409
+ collected.push(line.slice(indent));
410
+ index += 1;
411
+ }
412
+ return [collected.join("\n").trimEnd(), index];
413
+ }
414
+ function countIndent(line) {
415
+ return line.match(/^ */)?.[0].length ?? 0;
416
+ }
417
+ function parseScalar(value) {
418
+ if (value === "null")
419
+ return null;
420
+ if (value === "true")
421
+ return true;
422
+ if (value === "false")
423
+ return false;
424
+ if (/^-?\d+$/.test(value))
425
+ return Number.parseInt(value, 10);
426
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
427
+ return value.slice(1, -1);
428
+ }
429
+ return value;
430
+ }
431
+ function readObject(input, key) {
432
+ const value = input[key];
433
+ if (value === void 0 || value === null) {
434
+ return {};
435
+ }
436
+ if (typeof value !== "object" || Array.isArray(value)) {
437
+ throw new Error(`Workflow front matter field "${key}" must be an object.`);
438
+ }
439
+ return value;
440
+ }
441
+ function readRequiredObject(input, key) {
442
+ if (!(key in input)) {
443
+ throw new Error(`Workflow front matter field "${key}" is required.`);
444
+ }
445
+ return readObject(input, key);
446
+ }
447
+ function readOptionalString(input, key, env) {
448
+ const value = input[key];
449
+ if (value === void 0 || value === null) {
450
+ return null;
451
+ }
452
+ if (typeof value !== "string") {
453
+ throw new Error(`Workflow front matter field "${key}" must be a string.`);
454
+ }
455
+ return resolveEnvironmentValue(value, env);
456
+ }
457
+ function readOptionalWorkflowString(input, primaryKey, fallbackKey, env) {
458
+ return readOptionalString(input, primaryKey, env) ?? readOptionalString(input, fallbackKey, env);
459
+ }
460
+ function readRequiredString(input, key, env) {
461
+ const value = readOptionalString(input, key, env);
462
+ if (!value) {
463
+ throw new Error(`Workflow front matter field "${key}" is required.`);
464
+ }
465
+ return value;
466
+ }
467
+ function readStringList(input, key) {
468
+ const value = input[key];
469
+ if (value === void 0 || value === null) {
470
+ return void 0;
471
+ }
472
+ if (typeof value === "string") {
473
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
474
+ }
475
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
476
+ throw new Error(`Workflow front matter field "${key}" must be an array of strings or comma-separated string.`);
477
+ }
478
+ return value;
479
+ }
480
+ function readOptionalIntegerLike(input, key) {
481
+ const value = input[key];
482
+ if (value === void 0 || value === null) {
483
+ return null;
484
+ }
485
+ if (typeof value === "number") {
486
+ return value;
487
+ }
488
+ if (typeof value === "string" && /^-?\d+$/.test(value)) {
489
+ return Number.parseInt(value, 10);
490
+ }
491
+ throw new Error(`Workflow front matter field "${key}" must be an integer.`);
492
+ }
493
+ function readNumberMap(input, key) {
494
+ const value = input[key];
495
+ if (value === void 0 || value === null) {
496
+ return {};
497
+ }
498
+ if (typeof value !== "object" || Array.isArray(value)) {
499
+ throw new Error(`Workflow front matter field "${key}" must be an object.`);
500
+ }
501
+ const result = {};
502
+ for (const [entryKey, entryValue] of Object.entries(value)) {
503
+ if (typeof entryValue === "number") {
504
+ result[entryKey] = entryValue;
505
+ continue;
506
+ }
507
+ if (typeof entryValue === "string" && /^\d+$/.test(entryValue)) {
508
+ result[entryKey] = Number.parseInt(entryValue, 10);
509
+ continue;
510
+ }
511
+ throw new Error(`Workflow front matter field "${key}.${entryKey}" must be an integer.`);
512
+ }
513
+ return result;
514
+ }
515
+ function resolveEnvironmentValue(value, env) {
516
+ const envTokenMatch = value.match(/^(?:env:)?([A-Z0-9_]+)$/);
517
+ if (value.startsWith("env:") && envTokenMatch) {
518
+ const resolved = env[envTokenMatch[1]];
519
+ if (!resolved) {
520
+ throw new Error(`Workflow front matter requires environment variable ${envTokenMatch[1]}.`);
521
+ }
522
+ return resolved;
523
+ }
524
+ return value.replace(/\$\{([A-Z0-9_]+)\}/g, (_, name) => {
525
+ const resolved = env[name];
526
+ if (!resolved) {
527
+ throw new Error(`Workflow front matter requires environment variable ${name}.`);
528
+ }
529
+ return resolved;
530
+ });
531
+ }
532
+ function matchOptionalSection(markdown, heading) {
533
+ const escapedHeading = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
534
+ const pattern = new RegExp(`## ${escapedHeading}\\n\\n([\\s\\S]*?)(?=\\n## |$)`);
535
+ const match = markdown.match(pattern);
536
+ return match?.[1]?.trim() ?? null;
537
+ }
538
+
539
+ // ../core/dist/workflow/render.js
540
+ import { Liquid, ParseError, RenderError, TokenizationError, UndefinedVariableError } from "liquidjs";
541
+ function buildPromptVariables(issue, options) {
542
+ return {
543
+ issue: {
544
+ id: issue.id,
545
+ identifier: issue.identifier,
546
+ number: issue.number,
547
+ title: issue.title,
548
+ description: issue.description,
549
+ priority: issue.priority,
550
+ url: issue.url,
551
+ state: issue.state,
552
+ labels: issue.labels,
553
+ blocked_by: issue.blockedBy,
554
+ branch_name: issue.branchName,
555
+ created_at: issue.createdAt,
556
+ updated_at: issue.updatedAt,
557
+ repository: `${issue.repository.owner}/${issue.repository.name}`
558
+ },
559
+ attempt: options.attempt
560
+ };
561
+ }
562
+ var STRICT_LIQUID_ENGINE = new Liquid({
563
+ strictVariables: true,
564
+ strictFilters: true,
565
+ ownPropertyOnly: true
566
+ });
567
+ function renderPrompt(template, variables, options = {}) {
568
+ const strict = options.strict ?? true;
569
+ if (!strict) {
570
+ return renderLegacyPrompt(template, variables);
571
+ }
572
+ try {
573
+ return STRICT_LIQUID_ENGINE.parseAndRenderSync(template, variables);
574
+ } catch (error) {
575
+ throw normalizeTemplateError(error);
576
+ }
577
+ }
578
+ function normalizeTemplateError(error) {
579
+ const message = error instanceof Error ? error.message : String(error);
580
+ if (error instanceof UndefinedVariableError || error instanceof RenderError || error instanceof ParseError && message.startsWith("undefined filter:")) {
581
+ return new Error(`template_render_error: ${message}`, { cause: error });
582
+ }
583
+ if (error instanceof ParseError || error instanceof TokenizationError) {
584
+ return new Error(`template_parse_error: ${message}`, { cause: error });
585
+ }
586
+ return new Error(`template_render_error: ${message}`, { cause: error });
587
+ }
588
+ function flattenVariables(obj, prefix = "") {
589
+ const result = /* @__PURE__ */ new Map();
590
+ for (const [key, value] of Object.entries(obj)) {
591
+ const fullKey = prefix ? `${prefix}.${key}` : key;
592
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
593
+ for (const [nestedKey, nestedValue] of flattenVariables(value, fullKey)) {
594
+ result.set(nestedKey, nestedValue);
595
+ }
596
+ } else {
597
+ result.set(fullKey, value);
598
+ }
599
+ }
600
+ return result;
601
+ }
602
+ function renderLegacyPrompt(template, variables) {
603
+ const flatVars = flattenVariables(variables);
604
+ return template.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_.]*)\}\}/g, (match, key) => {
605
+ const value = flatVars.get(key);
606
+ if (value === void 0) {
607
+ return match;
608
+ }
609
+ if (value === null) {
610
+ return "";
611
+ }
612
+ return String(value);
613
+ });
614
+ }
615
+
616
+ // ../core/dist/workflow/exit-classification.js
617
+ function classifySessionExit(params) {
618
+ if (params.userInputRequired) {
619
+ return "user-input-required";
620
+ }
621
+ if (params.budgetExceeded) {
622
+ return "budget-exceeded";
623
+ }
624
+ if (params.convergenceDetected) {
625
+ return "convergence-detected";
626
+ }
627
+ if (params.runPhase === "timed_out" || params.runPhase === "stalled") {
628
+ return "timeout";
629
+ }
630
+ if (params.maxTurnsReached) {
631
+ return "max-turns-reached";
632
+ }
633
+ if (params.runPhase === "succeeded") {
634
+ return "completed";
635
+ }
636
+ return "error";
637
+ }
638
+
639
+ // ../core/dist/orchestration/retry-policy.js
640
+ function calculateRetryDelay(attempt, options = {}) {
641
+ const baseDelayMs = options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
642
+ const maxDelayMs = options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
643
+ const normalizedAttempt = Math.max(1, attempt);
644
+ const delay = baseDelayMs * 2 ** (normalizedAttempt - 1);
645
+ return Math.min(delay, maxDelayMs);
646
+ }
647
+ function scheduleRetryAt(now, attempt, options = {}) {
648
+ return new Date(now.getTime() + calculateRetryDelay(attempt, options));
649
+ }
650
+
651
+ // ../core/dist/workspace/env-file.js
652
+ import { existsSync, readFileSync } from "fs";
653
+ function readEnvFile(path) {
654
+ if (!existsSync(path)) {
655
+ return {};
656
+ }
657
+ return readFileSync(path, "utf8").split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#") && line.includes("=")).reduce((result, line) => {
658
+ const separatorIndex = line.indexOf("=");
659
+ const key = line.slice(0, separatorIndex).trim();
660
+ const value = line.slice(separatorIndex + 1).trim();
661
+ if (key) {
662
+ result[key] = value;
663
+ }
664
+ return result;
665
+ }, {});
666
+ }
667
+
668
+ // ../core/dist/workspace/identity.js
669
+ import { resolve, join } from "path";
670
+ import { createHash } from "crypto";
671
+ function deriveIssueWorkspaceKey(identity, issueIdentifier) {
672
+ if (issueIdentifier) {
673
+ return deriveIssueWorkspaceKeyFromIdentifier(issueIdentifier);
674
+ }
675
+ return deriveLegacyIssueWorkspaceKey(identity);
676
+ }
677
+ function deriveIssueWorkspaceKeyFromIdentifier(issueIdentifier) {
678
+ const sanitized = issueIdentifier.replace(/[^A-Za-z0-9._-]+/g, "_").replace(/^_+|_+$/g, "");
679
+ if (!sanitized || /^[.]+$/.test(sanitized)) {
680
+ return "issue";
681
+ }
682
+ return sanitized;
683
+ }
684
+ function deriveLegacyIssueWorkspaceKey(identity) {
685
+ const input = [
686
+ identity.projectId,
687
+ identity.adapter,
688
+ identity.issueSubjectId
689
+ ].join(":");
690
+ return createHash("sha256").update(input).digest("hex").slice(0, 16);
691
+ }
692
+ function resolveIssueWorkspaceDirectory(projectDirectory, workspaceKey) {
693
+ const normalizedProjectDirectory = resolve(projectDirectory);
694
+ const candidate = resolve(normalizedProjectDirectory, "issues", workspaceKey);
695
+ if (!candidate.startsWith(`${normalizedProjectDirectory}/`)) {
696
+ throw new Error("Issue workspace path escapes the configured project directory.");
697
+ }
698
+ return candidate;
699
+ }
700
+
701
+ // ../core/dist/workspace/hooks.js
702
+ import { spawn } from "child_process";
703
+ var DEFAULT_HOOK_TIMEOUT_MS2 = 6e4;
704
+ async function executeHook(options) {
705
+ const { kind, command, cwd, env, timeoutMs } = options;
706
+ const start = Date.now();
707
+ const normalizedCommand = normalizeHookCommand(command);
708
+ return new Promise((resolveResult) => {
709
+ let timedOut = false;
710
+ let timer = null;
711
+ const child = spawn("bash", ["-lc", normalizedCommand], {
712
+ cwd,
713
+ env: { ...process.env, ...env },
714
+ stdio: "pipe"
715
+ });
716
+ const stderrChunks = [];
717
+ child.stderr?.on("data", (chunk) => {
718
+ stderrChunks.push(chunk);
719
+ });
720
+ if (timeoutMs > 0) {
721
+ timer = setTimeout(() => {
722
+ timedOut = true;
723
+ child.kill("SIGTERM");
724
+ setTimeout(() => {
725
+ try {
726
+ child.kill("SIGKILL");
727
+ } catch {
728
+ }
729
+ }, 5e3);
730
+ }, timeoutMs);
731
+ }
732
+ child.on("close", (code) => {
733
+ if (timer) {
734
+ clearTimeout(timer);
735
+ }
736
+ const durationMs = Date.now() - start;
737
+ const stderr = Buffer.concat(stderrChunks).toString("utf8").trim();
738
+ if (timedOut) {
739
+ resolveResult({
740
+ kind,
741
+ outcome: "timeout",
742
+ exitCode: code,
743
+ durationMs,
744
+ error: `Hook "${kind}" timed out after ${timeoutMs}ms`
745
+ });
746
+ return;
747
+ }
748
+ if (code !== 0) {
749
+ resolveResult({
750
+ kind,
751
+ outcome: "failure",
752
+ exitCode: code,
753
+ durationMs,
754
+ error: stderr || `Hook "${kind}" exited with code ${code}`
755
+ });
756
+ return;
757
+ }
758
+ resolveResult({
759
+ kind,
760
+ outcome: "success",
761
+ exitCode: 0,
762
+ durationMs,
763
+ error: null
764
+ });
765
+ });
766
+ child.on("error", (err) => {
767
+ if (timer) {
768
+ clearTimeout(timer);
769
+ }
770
+ resolveResult({
771
+ kind,
772
+ outcome: "failure",
773
+ exitCode: null,
774
+ durationMs: Date.now() - start,
775
+ error: err.message
776
+ });
777
+ });
778
+ });
779
+ }
780
+ function buildHookEnv(context) {
781
+ const env = {
782
+ SYMPHONY_PROJECT_ID: context.projectId,
783
+ SYMPHONY_ISSUE_WORKSPACE_KEY: context.workspaceKey,
784
+ SYMPHONY_ISSUE_SUBJECT_ID: context.issueSubjectId,
785
+ SYMPHONY_ISSUE_IDENTIFIER: context.issueIdentifier,
786
+ SYMPHONY_WORKSPACE_PATH: context.workspacePath,
787
+ SYMPHONY_REPOSITORY_PATH: context.repositoryPath
788
+ };
789
+ if (context.runId) {
790
+ env.SYMPHONY_RUN_ID = context.runId;
791
+ }
792
+ if (context.state) {
793
+ env.SYMPHONY_ISSUE_STATE = context.state;
794
+ }
795
+ return env;
796
+ }
797
+ function resolveHookCommand(hooks, kind) {
798
+ switch (kind) {
799
+ case "after_create":
800
+ return hooks.afterCreate;
801
+ case "before_run":
802
+ return hooks.beforeRun;
803
+ case "after_run":
804
+ return hooks.afterRun;
805
+ case "before_remove":
806
+ return hooks.beforeRemove;
807
+ }
808
+ }
809
+ async function executeWorkspaceHook(options) {
810
+ const hookCommand = resolveHookCommand(options.hooks, options.kind);
811
+ if (!hookCommand) {
812
+ return {
813
+ kind: options.kind,
814
+ outcome: "skipped",
815
+ exitCode: null,
816
+ durationMs: 0,
817
+ error: null
818
+ };
819
+ }
820
+ return executeHook({
821
+ kind: options.kind,
822
+ command: hookCommand,
823
+ cwd: options.repositoryPath,
824
+ env: options.env,
825
+ timeoutMs: options.timeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS2
826
+ });
827
+ }
828
+ function normalizeHookCommand(command) {
829
+ const trimmed = command.trim();
830
+ if (trimmed.includes("/") && !trimmed.startsWith("/") && !trimmed.startsWith("./") && !trimmed.startsWith("../") && !/\s/.test(trimmed)) {
831
+ return `bash ./${trimmed}`;
832
+ }
833
+ return command;
834
+ }
835
+
836
+ // ../core/dist/observability/snapshot-builder.js
837
+ function buildProjectSnapshot(input) {
838
+ const { project, activeRuns, allRuns, summary, lastTickAt, lastError, rateLimits } = input;
839
+ return {
840
+ projectId: project.projectId,
841
+ slug: project.slug,
842
+ tracker: {
843
+ adapter: project.tracker.adapter,
844
+ bindingId: project.tracker.bindingId
845
+ },
846
+ lastTickAt,
847
+ health: lastError ? "degraded" : activeRuns.length > 0 ? "running" : "idle",
848
+ summary: {
849
+ dispatched: summary.dispatched,
850
+ suppressed: summary.suppressed,
851
+ recovered: summary.recovered,
852
+ activeRuns: activeRuns.length
853
+ },
854
+ activeRuns: activeRuns.map((run) => ({
855
+ runId: run.runId,
856
+ issueIdentifier: run.issueIdentifier,
857
+ issueState: run.issueState,
858
+ status: run.status,
859
+ retryKind: run.retryKind,
860
+ port: run.port,
861
+ runtimeSession: run.runtimeSession ?? null,
862
+ // New fields from live worker data
863
+ processId: run.processId ?? null,
864
+ turnCount: run.turnCount,
865
+ startedAt: run.startedAt ?? null,
866
+ lastEvent: run.lastEvent ?? null,
867
+ lastEventAt: run.lastEventAt ?? null,
868
+ executionPhase: run.executionPhase ?? null,
869
+ runPhase: run.runPhase ?? null,
870
+ tokenUsage: run.tokenUsage
871
+ })),
872
+ retryQueue: activeRuns.filter((run) => run.status === "retrying" && run.retryKind).map((run) => ({
873
+ runId: run.runId,
874
+ issueIdentifier: run.issueIdentifier,
875
+ retryKind: run.retryKind ?? "failure",
876
+ nextRetryAt: run.nextRetryAt
877
+ })),
878
+ lastError,
879
+ codexTotals: aggregateTokenUsage(allRuns ?? activeRuns, lastTickAt),
880
+ rateLimits: rateLimits ?? null
881
+ };
882
+ }
883
+ function aggregateTokenUsage(runs, lastTickAt) {
884
+ let inputTokens = 0;
885
+ let outputTokens = 0;
886
+ let totalTokens = 0;
887
+ let earliestStart = null;
888
+ let latestEnd = null;
889
+ for (const run of runs) {
890
+ if (run.tokenUsage) {
891
+ inputTokens += run.tokenUsage.inputTokens;
892
+ outputTokens += run.tokenUsage.outputTokens;
893
+ totalTokens += run.tokenUsage.totalTokens;
894
+ }
895
+ if (run.startedAt) {
896
+ const start = new Date(run.startedAt).getTime();
897
+ if (earliestStart === null || start < earliestStart) {
898
+ earliestStart = start;
899
+ }
900
+ }
901
+ const end = run.completedAt ? new Date(run.completedAt).getTime() : new Date(lastTickAt).getTime();
902
+ if (latestEnd === null || end > latestEnd) {
903
+ latestEnd = end;
904
+ }
905
+ }
906
+ const secondsRunning = earliestStart !== null && latestEnd !== null ? Math.max(0, Math.round((latestEnd - earliestStart) / 1e3)) : 0;
907
+ return { inputTokens, outputTokens, totalTokens, secondsRunning };
908
+ }
909
+
910
+ // ../core/dist/observability/fs-reader.js
911
+ import { readFile, readdir } from "fs/promises";
912
+ async function readJsonFile(path) {
913
+ try {
914
+ const raw = await readFile(path, "utf8");
915
+ return JSON.parse(raw);
916
+ } catch (error) {
917
+ if (isFileMissing(error)) {
918
+ return null;
919
+ }
920
+ throw error;
921
+ }
922
+ }
923
+ async function safeReadDir(path) {
924
+ try {
925
+ return await readdir(path);
926
+ } catch (error) {
927
+ if (isFileMissing(error)) {
928
+ return [];
929
+ }
930
+ throw error;
931
+ }
932
+ }
933
+ function isFileMissing(error) {
934
+ return Boolean(error && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"));
935
+ }
936
+
937
+ // ../core/dist/observability/event-formatter.js
938
+ function formatEventMessage(event) {
939
+ switch (event.event) {
940
+ case "run-dispatched":
941
+ return event.issueState ? `Dispatched from ${event.issueState}` : "Dispatched";
942
+ case "run-recovered":
943
+ return "Recovered existing run";
944
+ case "run-retried":
945
+ return `Retry ${event.attempt} scheduled (${event.retryKind})`;
946
+ case "run-failed":
947
+ return event.lastError;
948
+ case "run-suppressed":
949
+ return event.reason;
950
+ case "hook-executed":
951
+ return `${event.hook}: ${event.outcome}`;
952
+ case "hook-failed":
953
+ return event.error;
954
+ case "workspace-cleanup":
955
+ return event.error ? `${event.outcome}: ${event.error}` : event.outcome;
956
+ case "worker-error":
957
+ return event.error;
958
+ case "turn_started":
959
+ return `Turn ${event.turnCount} started`;
960
+ case "turn_completed":
961
+ return `Turn ${event.turnCount} completed in ${event.durationMs}ms`;
962
+ case "turn_failed":
963
+ return event.error ?? `Turn ${event.turnCount} failed`;
964
+ default:
965
+ return null;
966
+ }
967
+ }
968
+ function parseRecentEvents(raw, limit, options) {
969
+ const lines = raw.split("\n");
970
+ if (options.allowPartialFirstLine) {
971
+ lines.shift();
972
+ }
973
+ const events = [];
974
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
975
+ const line = lines[index]?.trim();
976
+ if (!line) {
977
+ continue;
978
+ }
979
+ const event = parseRunEventLine(line);
980
+ if (!event) {
981
+ continue;
982
+ }
983
+ events.push({
984
+ at: event.at,
985
+ event: event.event,
986
+ message: formatEventMessage(event)
987
+ });
988
+ if (events.length === limit) {
989
+ break;
990
+ }
991
+ }
992
+ return events.reverse();
993
+ }
994
+ function parseRunEventLine(line) {
995
+ try {
996
+ return JSON.parse(line);
997
+ } catch {
998
+ return null;
999
+ }
1000
+ }
1001
+
1002
+ // ../core/dist/observability/status-assembler.js
1003
+ function isMatchingIssueRun(run, projectId, issueId, issueIdentifier) {
1004
+ return Boolean(run && run.projectId === projectId && (run.issueId === issueId || run.issueIdentifier === issueIdentifier));
1005
+ }
1006
+ function mapIssueOrchestrationStateToStatus(state) {
1007
+ switch (state) {
1008
+ case "claimed":
1009
+ return "starting";
1010
+ case "running":
1011
+ return "running";
1012
+ case "retry_queued":
1013
+ return "retrying";
1014
+ case "released":
1015
+ return "released";
1016
+ case "unclaimed":
1017
+ return "pending";
1018
+ default:
1019
+ return state;
1020
+ }
1021
+ }
1022
+
1023
+ // ../core/dist/workflow/loader.js
1024
+ import { createHash as createHash2 } from "crypto";
1025
+ import { access, readFile as readFile2, stat } from "fs/promises";
1026
+ import { constants } from "fs";
1027
+ var WorkflowConfigStore = class {
1028
+ cache = /* @__PURE__ */ new Map();
1029
+ async load(workflowPath, env = process.env) {
1030
+ await access(workflowPath, constants.R_OK);
1031
+ const fileStat = await stat(workflowPath);
1032
+ const fingerprint = `${fileStat.mtimeMs}:${fileStat.size}`;
1033
+ const cached = this.cache.get(workflowPath);
1034
+ if (cached && cached.fingerprint === fingerprint) {
1035
+ return toWorkflowResolution(workflowPath, cached.workflow, {
1036
+ isValid: true,
1037
+ usedLastKnownGood: false,
1038
+ validationError: null
1039
+ });
1040
+ }
1041
+ const markdown = await readFile2(workflowPath, "utf8");
1042
+ try {
1043
+ const workflow = parseWorkflowMarkdown(markdown, env);
1044
+ this.cache.set(workflowPath, {
1045
+ fingerprint,
1046
+ workflow,
1047
+ loadedAt: (/* @__PURE__ */ new Date()).toISOString()
1048
+ });
1049
+ return toWorkflowResolution(workflowPath, workflow, {
1050
+ isValid: true,
1051
+ usedLastKnownGood: false,
1052
+ validationError: null
1053
+ });
1054
+ } catch (error) {
1055
+ if (cached) {
1056
+ return toWorkflowResolution(workflowPath, cached.workflow, {
1057
+ isValid: false,
1058
+ usedLastKnownGood: true,
1059
+ validationError: error instanceof Error ? error.message : "Invalid workflow definition."
1060
+ });
1061
+ }
1062
+ throw error;
1063
+ }
1064
+ }
1065
+ };
1066
+ function createDefaultWorkflowResolution() {
1067
+ return createInvalidWorkflowResolution(null, "missing_workflow_file");
1068
+ }
1069
+ function createInvalidWorkflowResolution(workflowPath, validationError) {
1070
+ return toWorkflowResolution(workflowPath, DEFAULT_WORKFLOW_DEFINITION, {
1071
+ isValid: false,
1072
+ usedLastKnownGood: false,
1073
+ validationError
1074
+ });
1075
+ }
1076
+ function toWorkflowResolution(workflowPath, workflow, metadata) {
1077
+ return {
1078
+ workflowPath,
1079
+ workflow,
1080
+ lifecycle: workflow.lifecycle,
1081
+ promptTemplate: workflow.promptTemplate,
1082
+ agentCommand: workflow.agentCommand,
1083
+ hookPath: workflow.hookPath ?? "",
1084
+ isValid: metadata.isValid,
1085
+ usedLastKnownGood: metadata.usedLastKnownGood,
1086
+ validationError: metadata.validationError
1087
+ };
1088
+ }
1089
+
1090
+ // ../core/dist/workspace/safety.js
1091
+ import { resolve as resolve2 } from "path";
1092
+
1093
+ export {
1094
+ isOrchestratorChannelEvent,
1095
+ DEFAULT_WORKFLOW_LIFECYCLE,
1096
+ isStateActive,
1097
+ isStateTerminal,
1098
+ matchesWorkflowState,
1099
+ parseWorkflowMarkdown,
1100
+ WorkflowConfigStore,
1101
+ createDefaultWorkflowResolution,
1102
+ createInvalidWorkflowResolution,
1103
+ buildPromptVariables,
1104
+ renderPrompt,
1105
+ classifySessionExit,
1106
+ scheduleRetryAt,
1107
+ readEnvFile,
1108
+ deriveIssueWorkspaceKey,
1109
+ deriveIssueWorkspaceKeyFromIdentifier,
1110
+ deriveLegacyIssueWorkspaceKey,
1111
+ resolveIssueWorkspaceDirectory,
1112
+ buildHookEnv,
1113
+ executeWorkspaceHook,
1114
+ buildProjectSnapshot,
1115
+ readJsonFile,
1116
+ safeReadDir,
1117
+ isFileMissing,
1118
+ parseRecentEvents,
1119
+ isMatchingIssueRun,
1120
+ mapIssueOrchestrationStateToStatus
1121
+ };