@generacy-ai/orchestrator 0.0.0-preview-20260304013206

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 (274) hide show
  1. package/LICENSE +191 -0
  2. package/dist/auth/api-key.d.ts +63 -0
  3. package/dist/auth/api-key.d.ts.map +1 -0
  4. package/dist/auth/api-key.js +102 -0
  5. package/dist/auth/api-key.js.map +1 -0
  6. package/dist/auth/github-oauth.d.ts +29 -0
  7. package/dist/auth/github-oauth.d.ts.map +1 -0
  8. package/dist/auth/github-oauth.js +136 -0
  9. package/dist/auth/github-oauth.js.map +1 -0
  10. package/dist/auth/index.d.ts +5 -0
  11. package/dist/auth/index.d.ts.map +1 -0
  12. package/dist/auth/index.js +9 -0
  13. package/dist/auth/index.js.map +1 -0
  14. package/dist/auth/jwt.d.ts +34 -0
  15. package/dist/auth/jwt.d.ts.map +1 -0
  16. package/dist/auth/jwt.js +74 -0
  17. package/dist/auth/jwt.js.map +1 -0
  18. package/dist/auth/middleware.d.ts +43 -0
  19. package/dist/auth/middleware.d.ts.map +1 -0
  20. package/dist/auth/middleware.js +101 -0
  21. package/dist/auth/middleware.js.map +1 -0
  22. package/dist/config/index.d.ts +3 -0
  23. package/dist/config/index.d.ts.map +1 -0
  24. package/dist/config/index.js +5 -0
  25. package/dist/config/index.js.map +1 -0
  26. package/dist/config/loader.d.ts +21 -0
  27. package/dist/config/loader.d.ts.map +1 -0
  28. package/dist/config/loader.js +295 -0
  29. package/dist/config/loader.js.map +1 -0
  30. package/dist/config/schema.d.ts +733 -0
  31. package/dist/config/schema.d.ts.map +1 -0
  32. package/dist/config/schema.js +174 -0
  33. package/dist/config/schema.js.map +1 -0
  34. package/dist/index.d.ts +24 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +33 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/middleware/error-handler.d.ts +30 -0
  39. package/dist/middleware/error-handler.d.ts.map +1 -0
  40. package/dist/middleware/error-handler.js +173 -0
  41. package/dist/middleware/error-handler.js.map +1 -0
  42. package/dist/middleware/index.d.ts +4 -0
  43. package/dist/middleware/index.d.ts.map +1 -0
  44. package/dist/middleware/index.js +4 -0
  45. package/dist/middleware/index.js.map +1 -0
  46. package/dist/middleware/rate-limit.d.ts +32 -0
  47. package/dist/middleware/rate-limit.d.ts.map +1 -0
  48. package/dist/middleware/rate-limit.js +92 -0
  49. package/dist/middleware/rate-limit.js.map +1 -0
  50. package/dist/middleware/request-logger.d.ts +31 -0
  51. package/dist/middleware/request-logger.d.ts.map +1 -0
  52. package/dist/middleware/request-logger.js +89 -0
  53. package/dist/middleware/request-logger.js.map +1 -0
  54. package/dist/routes/agents.d.ts +7 -0
  55. package/dist/routes/agents.d.ts.map +1 -0
  56. package/dist/routes/agents.js +78 -0
  57. package/dist/routes/agents.js.map +1 -0
  58. package/dist/routes/dispatch.d.ts +8 -0
  59. package/dist/routes/dispatch.d.ts.map +1 -0
  60. package/dist/routes/dispatch.js +46 -0
  61. package/dist/routes/dispatch.js.map +1 -0
  62. package/dist/routes/events.d.ts +14 -0
  63. package/dist/routes/events.d.ts.map +1 -0
  64. package/dist/routes/events.js +240 -0
  65. package/dist/routes/events.js.map +1 -0
  66. package/dist/routes/health.d.ts +14 -0
  67. package/dist/routes/health.d.ts.map +1 -0
  68. package/dist/routes/health.js +132 -0
  69. package/dist/routes/health.js.map +1 -0
  70. package/dist/routes/index.d.ts +36 -0
  71. package/dist/routes/index.d.ts.map +1 -0
  72. package/dist/routes/index.js +34 -0
  73. package/dist/routes/index.js.map +1 -0
  74. package/dist/routes/integrations.d.ts +34 -0
  75. package/dist/routes/integrations.d.ts.map +1 -0
  76. package/dist/routes/integrations.js +81 -0
  77. package/dist/routes/integrations.js.map +1 -0
  78. package/dist/routes/metrics.d.ts +31 -0
  79. package/dist/routes/metrics.d.ts.map +1 -0
  80. package/dist/routes/metrics.js +157 -0
  81. package/dist/routes/metrics.js.map +1 -0
  82. package/dist/routes/pr-webhooks.d.ts +15 -0
  83. package/dist/routes/pr-webhooks.d.ts.map +1 -0
  84. package/dist/routes/pr-webhooks.js +114 -0
  85. package/dist/routes/pr-webhooks.js.map +1 -0
  86. package/dist/routes/queue.d.ts +7 -0
  87. package/dist/routes/queue.d.ts.map +1 -0
  88. package/dist/routes/queue.js +94 -0
  89. package/dist/routes/queue.js.map +1 -0
  90. package/dist/routes/webhooks.d.ts +15 -0
  91. package/dist/routes/webhooks.d.ts.map +1 -0
  92. package/dist/routes/webhooks.js +117 -0
  93. package/dist/routes/webhooks.js.map +1 -0
  94. package/dist/routes/workflows.d.ts +7 -0
  95. package/dist/routes/workflows.d.ts.map +1 -0
  96. package/dist/routes/workflows.js +138 -0
  97. package/dist/routes/workflows.js.map +1 -0
  98. package/dist/server.d.ts +35 -0
  99. package/dist/server.d.ts.map +1 -0
  100. package/dist/server.js +264 -0
  101. package/dist/server.js.map +1 -0
  102. package/dist/services/agent-registry.d.ts +89 -0
  103. package/dist/services/agent-registry.d.ts.map +1 -0
  104. package/dist/services/agent-registry.js +173 -0
  105. package/dist/services/agent-registry.js.map +1 -0
  106. package/dist/services/epic-completion-monitor-service.d.ts +69 -0
  107. package/dist/services/epic-completion-monitor-service.d.ts.map +1 -0
  108. package/dist/services/epic-completion-monitor-service.js +200 -0
  109. package/dist/services/epic-completion-monitor-service.js.map +1 -0
  110. package/dist/services/identity.d.ts +41 -0
  111. package/dist/services/identity.d.ts.map +1 -0
  112. package/dist/services/identity.js +91 -0
  113. package/dist/services/identity.js.map +1 -0
  114. package/dist/services/index.d.ts +13 -0
  115. package/dist/services/index.d.ts.map +1 -0
  116. package/dist/services/index.js +13 -0
  117. package/dist/services/index.js.map +1 -0
  118. package/dist/services/label-monitor-service.d.ts +95 -0
  119. package/dist/services/label-monitor-service.d.ts.map +1 -0
  120. package/dist/services/label-monitor-service.js +414 -0
  121. package/dist/services/label-monitor-service.js.map +1 -0
  122. package/dist/services/label-sync-service.d.ts +76 -0
  123. package/dist/services/label-sync-service.d.ts.map +1 -0
  124. package/dist/services/label-sync-service.js +108 -0
  125. package/dist/services/label-sync-service.js.map +1 -0
  126. package/dist/services/phase-tracker-service.d.ts +32 -0
  127. package/dist/services/phase-tracker-service.d.ts.map +1 -0
  128. package/dist/services/phase-tracker-service.js +82 -0
  129. package/dist/services/phase-tracker-service.js.map +1 -0
  130. package/dist/services/pr-feedback-monitor-service.d.ts +86 -0
  131. package/dist/services/pr-feedback-monitor-service.d.ts.map +1 -0
  132. package/dist/services/pr-feedback-monitor-service.js +423 -0
  133. package/dist/services/pr-feedback-monitor-service.js.map +1 -0
  134. package/dist/services/queue-service.d.ts +62 -0
  135. package/dist/services/queue-service.d.ts.map +1 -0
  136. package/dist/services/queue-service.js +147 -0
  137. package/dist/services/queue-service.js.map +1 -0
  138. package/dist/services/redis-queue-adapter.d.ts +35 -0
  139. package/dist/services/redis-queue-adapter.d.ts.map +1 -0
  140. package/dist/services/redis-queue-adapter.js +218 -0
  141. package/dist/services/redis-queue-adapter.js.map +1 -0
  142. package/dist/services/smee-receiver.d.ts +87 -0
  143. package/dist/services/smee-receiver.d.ts.map +1 -0
  144. package/dist/services/smee-receiver.js +225 -0
  145. package/dist/services/smee-receiver.js.map +1 -0
  146. package/dist/services/webhook-setup-service.d.ts +253 -0
  147. package/dist/services/webhook-setup-service.d.ts.map +1 -0
  148. package/dist/services/webhook-setup-service.js +369 -0
  149. package/dist/services/webhook-setup-service.js.map +1 -0
  150. package/dist/services/worker-dispatcher.d.ts +57 -0
  151. package/dist/services/worker-dispatcher.d.ts.map +1 -0
  152. package/dist/services/worker-dispatcher.js +211 -0
  153. package/dist/services/worker-dispatcher.js.map +1 -0
  154. package/dist/services/workflow-service.d.ts +65 -0
  155. package/dist/services/workflow-service.d.ts.map +1 -0
  156. package/dist/services/workflow-service.js +164 -0
  157. package/dist/services/workflow-service.js.map +1 -0
  158. package/dist/sse/events.d.ts +50 -0
  159. package/dist/sse/events.d.ts.map +1 -0
  160. package/dist/sse/events.js +152 -0
  161. package/dist/sse/events.js.map +1 -0
  162. package/dist/sse/index.d.ts +4 -0
  163. package/dist/sse/index.d.ts.map +1 -0
  164. package/dist/sse/index.js +7 -0
  165. package/dist/sse/index.js.map +1 -0
  166. package/dist/sse/stream.d.ts +109 -0
  167. package/dist/sse/stream.d.ts.map +1 -0
  168. package/dist/sse/stream.js +239 -0
  169. package/dist/sse/stream.js.map +1 -0
  170. package/dist/sse/subscriptions.d.ts +91 -0
  171. package/dist/sse/subscriptions.d.ts.map +1 -0
  172. package/dist/sse/subscriptions.js +299 -0
  173. package/dist/sse/subscriptions.js.map +1 -0
  174. package/dist/types/api.d.ts +651 -0
  175. package/dist/types/api.d.ts.map +1 -0
  176. package/dist/types/api.js +169 -0
  177. package/dist/types/api.js.map +1 -0
  178. package/dist/types/index.d.ts +6 -0
  179. package/dist/types/index.d.ts.map +1 -0
  180. package/dist/types/index.js +27 -0
  181. package/dist/types/index.js.map +1 -0
  182. package/dist/types/monitor.d.ts +243 -0
  183. package/dist/types/monitor.d.ts.map +1 -0
  184. package/dist/types/monitor.js +2 -0
  185. package/dist/types/monitor.js.map +1 -0
  186. package/dist/types/problem-details.d.ts +63 -0
  187. package/dist/types/problem-details.d.ts.map +1 -0
  188. package/dist/types/problem-details.js +37 -0
  189. package/dist/types/problem-details.js.map +1 -0
  190. package/dist/types/sse.d.ts +224 -0
  191. package/dist/types/sse.d.ts.map +1 -0
  192. package/dist/types/sse.js +103 -0
  193. package/dist/types/sse.js.map +1 -0
  194. package/dist/types/webhook.d.ts +59 -0
  195. package/dist/types/webhook.d.ts.map +1 -0
  196. package/dist/types/webhook.js +2 -0
  197. package/dist/types/webhook.js.map +1 -0
  198. package/dist/utils/correlation.d.ts +30 -0
  199. package/dist/utils/correlation.d.ts.map +1 -0
  200. package/dist/utils/correlation.js +34 -0
  201. package/dist/utils/correlation.js.map +1 -0
  202. package/dist/utils/index.d.ts +3 -0
  203. package/dist/utils/index.d.ts.map +1 -0
  204. package/dist/utils/index.js +3 -0
  205. package/dist/utils/index.js.map +1 -0
  206. package/dist/utils/shutdown.d.ts +28 -0
  207. package/dist/utils/shutdown.d.ts.map +1 -0
  208. package/dist/utils/shutdown.js +86 -0
  209. package/dist/utils/shutdown.js.map +1 -0
  210. package/dist/worker/claude-cli-worker.d.ts +61 -0
  211. package/dist/worker/claude-cli-worker.d.ts.map +1 -0
  212. package/dist/worker/claude-cli-worker.js +330 -0
  213. package/dist/worker/claude-cli-worker.js.map +1 -0
  214. package/dist/worker/cli-spawner.d.ts +42 -0
  215. package/dist/worker/cli-spawner.d.ts.map +1 -0
  216. package/dist/worker/cli-spawner.js +183 -0
  217. package/dist/worker/cli-spawner.js.map +1 -0
  218. package/dist/worker/config.d.ts +76 -0
  219. package/dist/worker/config.d.ts.map +1 -0
  220. package/dist/worker/config.js +39 -0
  221. package/dist/worker/config.js.map +1 -0
  222. package/dist/worker/epic-post-tasks.d.ts +73 -0
  223. package/dist/worker/epic-post-tasks.d.ts.map +1 -0
  224. package/dist/worker/epic-post-tasks.js +266 -0
  225. package/dist/worker/epic-post-tasks.js.map +1 -0
  226. package/dist/worker/gate-checker.d.ts +22 -0
  227. package/dist/worker/gate-checker.d.ts.map +1 -0
  228. package/dist/worker/gate-checker.js +41 -0
  229. package/dist/worker/gate-checker.js.map +1 -0
  230. package/dist/worker/index.d.ts +13 -0
  231. package/dist/worker/index.d.ts.map +1 -0
  232. package/dist/worker/index.js +19 -0
  233. package/dist/worker/index.js.map +1 -0
  234. package/dist/worker/label-manager.d.ts +89 -0
  235. package/dist/worker/label-manager.d.ts.map +1 -0
  236. package/dist/worker/label-manager.js +200 -0
  237. package/dist/worker/label-manager.js.map +1 -0
  238. package/dist/worker/output-capture.d.ts +58 -0
  239. package/dist/worker/output-capture.d.ts.map +1 -0
  240. package/dist/worker/output-capture.js +153 -0
  241. package/dist/worker/output-capture.js.map +1 -0
  242. package/dist/worker/phase-loop.d.ts +64 -0
  243. package/dist/worker/phase-loop.d.ts.map +1 -0
  244. package/dist/worker/phase-loop.js +185 -0
  245. package/dist/worker/phase-loop.js.map +1 -0
  246. package/dist/worker/phase-resolver.d.ts +62 -0
  247. package/dist/worker/phase-resolver.d.ts.map +1 -0
  248. package/dist/worker/phase-resolver.js +144 -0
  249. package/dist/worker/phase-resolver.js.map +1 -0
  250. package/dist/worker/pr-feedback-handler.d.ts +105 -0
  251. package/dist/worker/pr-feedback-handler.d.ts.map +1 -0
  252. package/dist/worker/pr-feedback-handler.js +391 -0
  253. package/dist/worker/pr-feedback-handler.js.map +1 -0
  254. package/dist/worker/pr-linker.d.ts +69 -0
  255. package/dist/worker/pr-linker.d.ts.map +1 -0
  256. package/dist/worker/pr-linker.js +108 -0
  257. package/dist/worker/pr-linker.js.map +1 -0
  258. package/dist/worker/pr-manager.d.ts +61 -0
  259. package/dist/worker/pr-manager.d.ts.map +1 -0
  260. package/dist/worker/pr-manager.js +140 -0
  261. package/dist/worker/pr-manager.js.map +1 -0
  262. package/dist/worker/repo-checkout.d.ts +63 -0
  263. package/dist/worker/repo-checkout.d.ts.map +1 -0
  264. package/dist/worker/repo-checkout.js +160 -0
  265. package/dist/worker/repo-checkout.js.map +1 -0
  266. package/dist/worker/stage-comment-manager.d.ts +34 -0
  267. package/dist/worker/stage-comment-manager.d.ts.map +1 -0
  268. package/dist/worker/stage-comment-manager.js +114 -0
  269. package/dist/worker/stage-comment-manager.js.map +1 -0
  270. package/dist/worker/types.d.ts +192 -0
  271. package/dist/worker/types.d.ts.map +1 -0
  272. package/dist/worker/types.js +53 -0
  273. package/dist/worker/types.js.map +1 -0
  274. package/package.json +64 -0
@@ -0,0 +1,185 @@
1
+ import { PHASE_SEQUENCE, PHASE_TO_COMMAND, PHASE_TO_STAGE } from './types.js';
2
+ /**
3
+ * Iterates through workflow phases from the starting phase to completion.
4
+ *
5
+ * For each phase the loop:
6
+ * 1. Updates labels to reflect the current phase
7
+ * 2. Spawns the Claude CLI (or runs the validate command)
8
+ * 3. Marks the phase as completed
9
+ * 4. Checks for review gates
10
+ * 5. Updates the stage comment with progress
11
+ *
12
+ * The loop stops on:
13
+ * - Gate hit (workflow paused for human review)
14
+ * - Phase failure (error)
15
+ * - Abort signal
16
+ * - All phases completed
17
+ */
18
+ export class PhaseLoop {
19
+ logger;
20
+ constructor(logger) {
21
+ this.logger = logger;
22
+ }
23
+ /**
24
+ * Execute the phase loop from the starting phase through to completion.
25
+ *
26
+ * @param phaseSequence - Optional workflow-specific phase sequence.
27
+ * Defaults to the global PHASE_SEQUENCE for backward compatibility.
28
+ */
29
+ async executeLoop(context, config, deps, phaseSequence) {
30
+ const sequence = phaseSequence ?? PHASE_SEQUENCE;
31
+ const { labelManager, stageCommentManager, gateChecker, cliSpawner, outputCapture, prManager } = deps;
32
+ const results = [];
33
+ // Track session ID across phases for conversation resume.
34
+ // When a CLI phase completes, its session ID is passed to the next phase
35
+ // so Claude CLI can reuse the conversation (keeping MCP servers warm and
36
+ // carrying forward accumulated context).
37
+ let currentSessionId;
38
+ // Find the starting index in the phase sequence
39
+ const startIndex = sequence.indexOf(context.startPhase);
40
+ if (startIndex === -1) {
41
+ throw new Error(`Unknown starting phase: ${context.startPhase}`);
42
+ }
43
+ this.logger.info({ startPhase: context.startPhase, startIndex, totalPhases: sequence.length }, 'Starting phase loop');
44
+ for (let i = startIndex; i < sequence.length; i++) {
45
+ const phase = sequence[i];
46
+ // Check abort signal before starting each phase
47
+ if (context.signal.aborted) {
48
+ this.logger.warn({ phase }, 'Abort signal detected, stopping phase loop');
49
+ return { results, completed: false, lastPhase: phase, gateHit: false };
50
+ }
51
+ this.logger.info({ phase, index: i }, 'Starting phase');
52
+ // 1. Update labels: mark this phase as active
53
+ await labelManager.onPhaseStart(phase);
54
+ // 2. Update stage comment to show phase in progress
55
+ const stage = PHASE_TO_STAGE[phase];
56
+ await stageCommentManager.updateStageComment({
57
+ stage,
58
+ status: 'in_progress',
59
+ phases: this.buildPhaseProgress(sequence, startIndex, i),
60
+ startedAt: new Date().toISOString(),
61
+ });
62
+ // 3. Execute the phase
63
+ let result;
64
+ try {
65
+ if (PHASE_TO_COMMAND[phase] === null) {
66
+ // Validate phase — run test command
67
+ result = await cliSpawner.runValidatePhase(context.checkoutPath, config.validateCommand, context.signal);
68
+ }
69
+ else {
70
+ // CLI phase — spawn Claude CLI (resume previous session if available)
71
+ result = await cliSpawner.spawnPhase(phase, {
72
+ prompt: context.issueUrl,
73
+ cwd: context.checkoutPath,
74
+ env: {},
75
+ maxTurns: config.maxTurns,
76
+ timeoutMs: config.phaseTimeoutMs,
77
+ signal: context.signal,
78
+ resumeSessionId: currentSessionId,
79
+ }, outputCapture);
80
+ }
81
+ }
82
+ catch (error) {
83
+ // Unexpected error during spawning
84
+ this.logger.error({ phase, error: String(error) }, 'Unexpected error during phase execution');
85
+ await labelManager.onError(phase);
86
+ await stageCommentManager.updateStageComment({
87
+ stage,
88
+ status: 'error',
89
+ phases: this.buildPhaseProgress(sequence, startIndex, i, 'error'),
90
+ startedAt: new Date().toISOString(),
91
+ });
92
+ throw error;
93
+ }
94
+ results.push(result);
95
+ // 3b. Capture session ID for resume in subsequent phases
96
+ if (result.sessionId) {
97
+ if (!currentSessionId) {
98
+ this.logger.info({ sessionId: result.sessionId, phase }, 'Captured initial session ID for conversation reuse');
99
+ }
100
+ currentSessionId = result.sessionId;
101
+ }
102
+ // 4. Handle phase failure
103
+ if (!result.success) {
104
+ this.logger.error({ phase, exitCode: result.exitCode, error: result.error?.message }, 'Phase failed');
105
+ await labelManager.onError(phase);
106
+ await stageCommentManager.updateStageComment({
107
+ stage,
108
+ status: 'error',
109
+ phases: this.buildPhaseProgress(sequence, startIndex, i, 'error'),
110
+ startedAt: new Date().toISOString(),
111
+ });
112
+ return { results, completed: false, lastPhase: phase, gateHit: false };
113
+ }
114
+ // 5. Mark phase as completed in labels
115
+ await labelManager.onPhaseComplete(phase);
116
+ // 5b. Commit, push, and ensure draft PR exists
117
+ const prUrl = await prManager.commitPushAndEnsurePr(phase);
118
+ if (prUrl) {
119
+ context.prUrl = prUrl;
120
+ }
121
+ // 6. Check for review gates
122
+ const gate = gateChecker.checkGate(phase, context.item.workflowName, config);
123
+ if (gate && gate.condition === 'always') {
124
+ this.logger.info({ phase, gateLabel: gate.gateLabel }, 'Gate hit, pausing workflow');
125
+ await labelManager.onGateHit(phase, gate.gateLabel);
126
+ // Update the result with gate info
127
+ result.gateHit = {
128
+ gateLabel: gate.gateLabel,
129
+ reason: `Review gate "${gate.gateLabel}" activated after phase "${phase}"`,
130
+ };
131
+ // Update stage comment showing gate hit
132
+ await stageCommentManager.updateStageComment({
133
+ stage,
134
+ status: 'in_progress',
135
+ phases: this.buildPhaseProgress(sequence, startIndex, i, 'complete'),
136
+ startedAt: new Date().toISOString(),
137
+ prUrl: context.prUrl,
138
+ });
139
+ return { results, completed: false, lastPhase: phase, gateHit: true };
140
+ }
141
+ // 7. Update stage comment showing phase complete
142
+ const isLastPhaseInStage = i + 1 >= sequence.length || PHASE_TO_STAGE[sequence[i + 1]] !== stage;
143
+ await stageCommentManager.updateStageComment({
144
+ stage,
145
+ status: isLastPhaseInStage ? 'complete' : 'in_progress',
146
+ phases: this.buildPhaseProgress(sequence, startIndex, i, 'complete'),
147
+ startedAt: new Date().toISOString(),
148
+ ...(isLastPhaseInStage ? { completedAt: new Date().toISOString() } : {}),
149
+ prUrl: context.prUrl,
150
+ });
151
+ // Clear output buffer for next phase
152
+ outputCapture.clear();
153
+ }
154
+ this.logger.info('Phase loop completed successfully — all phases done');
155
+ return {
156
+ results,
157
+ completed: true,
158
+ lastPhase: sequence[sequence.length - 1],
159
+ gateHit: false,
160
+ };
161
+ }
162
+ /**
163
+ * Build a phase progress array for stage comment updates.
164
+ */
165
+ buildPhaseProgress(sequence, startIndex, currentIndex, currentStatus = 'in_progress') {
166
+ const now = new Date().toISOString();
167
+ return sequence.map((phase, idx) => {
168
+ if (idx < startIndex) {
169
+ // Before the start — already complete from a prior run
170
+ return { phase, status: 'complete', completedAt: now };
171
+ }
172
+ if (idx < currentIndex) {
173
+ // Earlier in this run — completed
174
+ return { phase, status: 'complete', startedAt: now, completedAt: now };
175
+ }
176
+ if (idx === currentIndex) {
177
+ // Current phase
178
+ return { phase, status: currentStatus, startedAt: now };
179
+ }
180
+ // Future phase
181
+ return { phase, status: 'pending' };
182
+ });
183
+ }
184
+ }
185
+ //# sourceMappingURL=phase-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase-loop.js","sourceRoot":"","sources":["../../src/worker/phase-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { type WorkflowPhase } from './types.js';
2
+ /**
3
+ * Unified mapping from gate names to their owning phase and the phase to resume from.
4
+ *
5
+ * - `phase`: the workflow phase this gate belongs to (used to normalize gate names in resolveFromProcess)
6
+ * - `resumeFrom`: the phase to start from when the gate is satisfied (used in resolveFromContinue)
7
+ */
8
+ export declare const GATE_MAPPING: Record<string, {
9
+ phase: WorkflowPhase;
10
+ resumeFrom: WorkflowPhase;
11
+ }>;
12
+ /**
13
+ * Workflow-specific gate mappings that override the global GATE_MAPPING.
14
+ *
15
+ * For epic workflows, certain gates have different resume behavior:
16
+ * - `tasks-review`: resumes to 'tasks' (triggers post-tasks/child creation, not implement)
17
+ * - `children-complete`: dedicated handling (routes to epic-complete command)
18
+ * - `epic-approval`: dedicated handling (routes to epic-close)
19
+ */
20
+ export declare const WORKFLOW_GATE_MAPPING: Record<string, Record<string, {
21
+ phase: WorkflowPhase;
22
+ resumeFrom: WorkflowPhase;
23
+ }>>;
24
+ /**
25
+ * Resolve the starting phase based on issue labels and command type.
26
+ */
27
+ export declare class PhaseResolver {
28
+ /**
29
+ * Determine the starting phase for a queue item.
30
+ *
31
+ * - 'process' command: inspects completed/phase labels to find the next uncompleted phase.
32
+ * - 'continue' command: matches completed gate labels via GATE_MAPPING to determine resume phase.
33
+ *
34
+ * @param workflowName - Optional workflow name for workflow-specific gate resolution.
35
+ * When provided, uses the workflow's phase sequence and gate mappings.
36
+ */
37
+ resolveStartPhase(labels: string[], command: 'process' | 'continue', workflowName?: string): WorkflowPhase;
38
+ /**
39
+ * For 'process' command: find the starting phase from labels.
40
+ *
41
+ * Priority:
42
+ * 1. If a `phase:*` label exists, resume from that phase
43
+ * 2. If `completed:*` labels exist, start from next uncompleted phase
44
+ * (gate names like 'clarification' are normalized to phase names via GATE_MAPPING)
45
+ * 3. If no phase labels, start from 'specify'
46
+ */
47
+ private resolveFromProcess;
48
+ /**
49
+ * For 'continue' command: find which gate was just satisfied and resume from the next phase.
50
+ *
51
+ * Does not depend on `waiting-for:*` labels (those are removed by the worker on resume).
52
+ * Matches `completed:*` labels against the effective gate mapping (workflow-specific first,
53
+ * then global GATE_MAPPING) and returns the most advanced gate's resumeFrom phase.
54
+ */
55
+ private resolveFromContinue;
56
+ /**
57
+ * Build the effective gate mapping for a workflow.
58
+ * Workflow-specific mappings in WORKFLOW_GATE_MAPPING override entries in the global GATE_MAPPING.
59
+ */
60
+ private getEffectiveGateMapping;
61
+ }
62
+ //# sourceMappingURL=phase-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase-resolver.d.ts","sourceRoot":"","sources":["../../src/worker/phase-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAElF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAAE,CAQ5F,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAAE,CAAC,CAMrH,CAAC;AAEF;;GAEG;AACH,qBAAa,aAAa;IACxB;;;;;;;;OAQG;IACH,iBAAiB,CACf,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,SAAS,GAAG,UAAU,EAC/B,YAAY,CAAC,EAAE,MAAM,GACpB,aAAa;IAOhB;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IA2C1B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IA8B3B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;CAYhC"}
@@ -0,0 +1,144 @@
1
+ import { PHASE_SEQUENCE, getPhaseSequence } from './types.js';
2
+ /**
3
+ * Unified mapping from gate names to their owning phase and the phase to resume from.
4
+ *
5
+ * - `phase`: the workflow phase this gate belongs to (used to normalize gate names in resolveFromProcess)
6
+ * - `resumeFrom`: the phase to start from when the gate is satisfied (used in resolveFromContinue)
7
+ */
8
+ export const GATE_MAPPING = {
9
+ 'clarification': { phase: 'clarify', resumeFrom: 'plan' },
10
+ 'spec-review': { phase: 'specify', resumeFrom: 'clarify' },
11
+ 'clarification-review': { phase: 'clarify', resumeFrom: 'plan' },
12
+ 'plan-review': { phase: 'plan', resumeFrom: 'tasks' },
13
+ 'tasks-review': { phase: 'tasks', resumeFrom: 'implement' },
14
+ 'implementation-review': { phase: 'implement', resumeFrom: 'validate' },
15
+ 'manual-validation': { phase: 'validate', resumeFrom: 'validate' },
16
+ };
17
+ /**
18
+ * Workflow-specific gate mappings that override the global GATE_MAPPING.
19
+ *
20
+ * For epic workflows, certain gates have different resume behavior:
21
+ * - `tasks-review`: resumes to 'tasks' (triggers post-tasks/child creation, not implement)
22
+ * - `children-complete`: dedicated handling (routes to epic-complete command)
23
+ * - `epic-approval`: dedicated handling (routes to epic-close)
24
+ */
25
+ export const WORKFLOW_GATE_MAPPING = {
26
+ 'speckit-epic': {
27
+ 'tasks-review': { phase: 'tasks', resumeFrom: 'tasks' },
28
+ 'children-complete': { phase: 'tasks', resumeFrom: 'tasks' },
29
+ 'epic-approval': { phase: 'tasks', resumeFrom: 'tasks' },
30
+ },
31
+ };
32
+ /**
33
+ * Resolve the starting phase based on issue labels and command type.
34
+ */
35
+ export class PhaseResolver {
36
+ /**
37
+ * Determine the starting phase for a queue item.
38
+ *
39
+ * - 'process' command: inspects completed/phase labels to find the next uncompleted phase.
40
+ * - 'continue' command: matches completed gate labels via GATE_MAPPING to determine resume phase.
41
+ *
42
+ * @param workflowName - Optional workflow name for workflow-specific gate resolution.
43
+ * When provided, uses the workflow's phase sequence and gate mappings.
44
+ */
45
+ resolveStartPhase(labels, command, workflowName) {
46
+ if (command === 'continue') {
47
+ return this.resolveFromContinue(labels, workflowName);
48
+ }
49
+ return this.resolveFromProcess(labels, workflowName);
50
+ }
51
+ /**
52
+ * For 'process' command: find the starting phase from labels.
53
+ *
54
+ * Priority:
55
+ * 1. If a `phase:*` label exists, resume from that phase
56
+ * 2. If `completed:*` labels exist, start from next uncompleted phase
57
+ * (gate names like 'clarification' are normalized to phase names via GATE_MAPPING)
58
+ * 3. If no phase labels, start from 'specify'
59
+ */
60
+ resolveFromProcess(labels, workflowName) {
61
+ const sequence = workflowName ? getPhaseSequence(workflowName) : PHASE_SEQUENCE;
62
+ const effectiveGateMapping = this.getEffectiveGateMapping(workflowName);
63
+ // Check for an active phase label
64
+ for (const label of labels) {
65
+ if (label.startsWith('phase:')) {
66
+ const phase = label.slice('phase:'.length);
67
+ if (sequence.includes(phase)) {
68
+ return phase;
69
+ }
70
+ }
71
+ }
72
+ // Find the last completed phase and return the next one.
73
+ // Normalize gate names (e.g., 'clarification') to phase names (e.g., 'clarify')
74
+ // so phase sequence iteration matches correctly.
75
+ const completedPhases = new Set();
76
+ for (const label of labels) {
77
+ if (label.startsWith('completed:')) {
78
+ const name = label.slice('completed:'.length);
79
+ completedPhases.add(name);
80
+ const gateEntry = effectiveGateMapping[name];
81
+ if (gateEntry) {
82
+ completedPhases.add(gateEntry.phase);
83
+ }
84
+ }
85
+ }
86
+ if (completedPhases.size > 0) {
87
+ for (const phase of sequence) {
88
+ if (!completedPhases.has(phase)) {
89
+ return phase;
90
+ }
91
+ }
92
+ // All phases completed — return the last phase in the sequence as the terminal phase
93
+ return sequence[sequence.length - 1];
94
+ }
95
+ // No phase labels at all — start from beginning
96
+ return 'specify';
97
+ }
98
+ /**
99
+ * For 'continue' command: find which gate was just satisfied and resume from the next phase.
100
+ *
101
+ * Does not depend on `waiting-for:*` labels (those are removed by the worker on resume).
102
+ * Matches `completed:*` labels against the effective gate mapping (workflow-specific first,
103
+ * then global GATE_MAPPING) and returns the most advanced gate's resumeFrom phase.
104
+ */
105
+ resolveFromContinue(labels, workflowName) {
106
+ const sequence = workflowName ? getPhaseSequence(workflowName) : PHASE_SEQUENCE;
107
+ const effectiveGateMapping = this.getEffectiveGateMapping(workflowName);
108
+ const completedGates = new Set();
109
+ for (const label of labels) {
110
+ if (label.startsWith('completed:')) {
111
+ const name = label.slice('completed:'.length);
112
+ if (effectiveGateMapping[name]) {
113
+ completedGates.add(name);
114
+ }
115
+ }
116
+ }
117
+ // Iterate phases latest-to-earliest — most advanced gate wins
118
+ for (let i = sequence.length - 1; i >= 0; i--) {
119
+ const phase = sequence[i];
120
+ for (const gateName of completedGates) {
121
+ const mapping = effectiveGateMapping[gateName];
122
+ if (mapping && mapping.phase === phase) {
123
+ return mapping.resumeFrom;
124
+ }
125
+ }
126
+ }
127
+ // Fallback: use the process resolver
128
+ return this.resolveFromProcess(labels, workflowName);
129
+ }
130
+ /**
131
+ * Build the effective gate mapping for a workflow.
132
+ * Workflow-specific mappings in WORKFLOW_GATE_MAPPING override entries in the global GATE_MAPPING.
133
+ */
134
+ getEffectiveGateMapping(workflowName) {
135
+ if (!workflowName || !WORKFLOW_GATE_MAPPING[workflowName]) {
136
+ return GATE_MAPPING;
137
+ }
138
+ return {
139
+ ...GATE_MAPPING,
140
+ ...WORKFLOW_GATE_MAPPING[workflowName],
141
+ };
142
+ }
143
+ }
144
+ //# sourceMappingURL=phase-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase-resolver.js","sourceRoot":"","sources":["../../src/worker/phase-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import type { QueueItem } from '../types/index.js';
2
+ import type { Logger, ProcessFactory } from './types.js';
3
+ import type { WorkerConfig } from './config.js';
4
+ import type { SSEEventEmitter } from './output-capture.js';
5
+ /**
6
+ * Handles the `address-pr-feedback` command.
7
+ *
8
+ * Processing flow:
9
+ * 1. Extract PR number from queue item metadata
10
+ * 2. Fetch the PR to get the branch name
11
+ * 3. Switch to the PR branch (not default branch)
12
+ * 4. Fetch fresh unresolved review threads
13
+ * 5. Build a structured prompt with all unresolved comments
14
+ * 6. Spawn Claude CLI to address the feedback
15
+ * 7. Stage, commit, and push changes to the PR branch
16
+ * 8. Reply to each review thread (never resolve)
17
+ * 9. Remove the `waiting-for:address-pr-feedback` label
18
+ *
19
+ * Error handling strategy (T019):
20
+ *
21
+ * **FR-013: Timeout handling**
22
+ * - If CLI times out: push any partial changes that were made
23
+ * - Keep `waiting-for:address-pr-feedback` label (don't remove)
24
+ * - Label retention ensures the task will be retried on next detection cycle
25
+ * - Log timeout warning with structured context
26
+ *
27
+ * **FR-007: Reply failure handling**
28
+ * - If posting replies fails for some threads: still remove label
29
+ * - Log warnings for each failed reply
30
+ * - Partial reply success is acceptable (code changes were pushed successfully)
31
+ * - Handler does not throw on reply failures
32
+ *
33
+ * **SC-006: Thread resolution prevention**
34
+ * - Only use `replyToPRComment()` API — never call any thread-resolve API
35
+ * - Human reviewer will resolve threads after verifying changes
36
+ * - Comments in code explicitly reference SC-006 for clarity
37
+ *
38
+ * **Structured logging**
39
+ * - All operations logged with structured context (prNumber, issueNumber, owner, repo)
40
+ * - Error logs include full error messages and relevant context
41
+ * - Success/failure states clearly logged for observability
42
+ * - All FR/SC references included in log messages for traceability
43
+ *
44
+ * **Critical operation failures**
45
+ * - PR fetch failure: throw (cannot proceed without PR details)
46
+ * - Branch switch failure: throw (wrong branch would cause issues)
47
+ * - Comment fetch failure: throw (cannot address unknown feedback)
48
+ * - Push failure: log error but don't throw (allows retry via label)
49
+ *
50
+ * **Non-critical operation failures**
51
+ * - No unresolved threads: remove label, early return (success case)
52
+ * - Reply posting: log warning, continue (FR-007)
53
+ * - Label removal: log warning, continue (non-fatal)
54
+ */
55
+ export declare class PrFeedbackHandler {
56
+ private readonly config;
57
+ private readonly logger;
58
+ private readonly processFactory;
59
+ private readonly sseEmitter?;
60
+ private readonly repoCheckout;
61
+ constructor(config: WorkerConfig, logger: Logger, processFactory: ProcessFactory, sseEmitter?: SSEEventEmitter | undefined);
62
+ /**
63
+ * Process a PR feedback addressing task.
64
+ *
65
+ * @param item - Queue item with `command: 'address-pr-feedback'`
66
+ * @param checkoutPath - Path to the already-checked-out repository
67
+ */
68
+ handle(item: QueueItem, checkoutPath: string): Promise<void>;
69
+ /**
70
+ * Build a structured prompt containing all unresolved review comments.
71
+ *
72
+ * The prompt instructs Claude to:
73
+ * - Read each review comment
74
+ * - Make the necessary code changes
75
+ * - Commit the changes
76
+ * - NOT resolve any threads (human reviewer will resolve)
77
+ */
78
+ private buildFeedbackPrompt;
79
+ /**
80
+ * Spawn Claude CLI to address PR feedback.
81
+ *
82
+ * Returns true if the CLI completed successfully, false on timeout or failure.
83
+ * FR-013: On timeout, partial changes are pushed and label is kept for retry.
84
+ */
85
+ private spawnClaudeForFeedback;
86
+ /**
87
+ * Stage all changes, commit, and push to the PR branch.
88
+ *
89
+ * Returns true if there were changes to commit, false otherwise.
90
+ */
91
+ private commitAndPushChanges;
92
+ /**
93
+ * Post a reply to each unresolved review thread.
94
+ *
95
+ * SC-006: Never resolves threads — that's left to the human reviewer.
96
+ * FR-007: Partial failure is acceptable: if some replies fail, log warnings but continue.
97
+ * The handler will still remove the label even if some replies fail.
98
+ */
99
+ private replyToThreads;
100
+ /**
101
+ * Remove the `waiting-for:address-pr-feedback` label from the linked issue.
102
+ */
103
+ private removeFeedbackLabel;
104
+ }
105
+ //# sourceMappingURL=pr-feedback-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-feedback-handler.d.ts","sourceRoot":"","sources":["../../src/worker/pr-feedback-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAsB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAN9B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAGzB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,cAAc,EAC9B,UAAU,CAAC,EAAE,eAAe,YAAA;IAK/C;;;;;OAKG;IACG,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmKlE;;;;;;;;OAQG;IACH,OAAO,CAAC,mBAAmB;IA6B3B;;;;;OAKG;YACW,sBAAsB;IA0HpC;;;;OAIG;YACW,oBAAoB;IA2ElC;;;;;;OAMG;YACW,cAAc;IAsD5B;;OAEG;YACW,mBAAmB;CAgBlC"}