@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,140 @@
1
+ /**
2
+ * Manages draft PR creation and git commit/push operations between workflow phases.
3
+ *
4
+ * After each phase completes:
5
+ * 1. Commits any changed files with a phase-specific message
6
+ * 2. Pushes the branch to the remote
7
+ * 3. Creates a draft PR (if one doesn't already exist)
8
+ *
9
+ * This ensures the PR is created early (after specify) and updated incrementally.
10
+ */
11
+ export class PrManager {
12
+ github;
13
+ owner;
14
+ repo;
15
+ issueNumber;
16
+ logger;
17
+ prUrl;
18
+ prNumber;
19
+ constructor(github, owner, repo, issueNumber, logger) {
20
+ this.github = github;
21
+ this.owner = owner;
22
+ this.repo = repo;
23
+ this.issueNumber = issueNumber;
24
+ this.logger = logger;
25
+ }
26
+ /**
27
+ * Get the current PR URL (if a PR has been created).
28
+ */
29
+ getPrUrl() {
30
+ return this.prUrl;
31
+ }
32
+ /**
33
+ * Commit any changes, push to remote, and ensure a draft PR exists.
34
+ *
35
+ * Safe to call after every phase — handles "nothing to commit" and
36
+ * "PR already exists" gracefully.
37
+ *
38
+ * @returns The PR URL if one exists/was created, undefined otherwise.
39
+ */
40
+ async commitPushAndEnsurePr(phase) {
41
+ await this.commitAndPush(phase);
42
+ return this.ensureDraftPr();
43
+ }
44
+ /**
45
+ * Commit all changed files and push to the remote.
46
+ *
47
+ * Handles "nothing to commit" gracefully by checking git status first.
48
+ */
49
+ async commitAndPush(phase) {
50
+ try {
51
+ // Check if there are any changes to commit
52
+ const status = await this.github.getStatus();
53
+ if (!status.has_changes) {
54
+ this.logger.debug({ phase }, 'No changes to commit after phase');
55
+ return;
56
+ }
57
+ // Stage all changes
58
+ await this.github.stageAll();
59
+ // Commit with a phase-specific message
60
+ const message = `chore(speckit): complete ${phase} phase for #${this.issueNumber}`;
61
+ const commitResult = await this.github.commit(message);
62
+ this.logger.info({ phase, sha: commitResult.sha, files: commitResult.files_committed.length }, 'Committed phase changes');
63
+ // Push to remote (set upstream on first push)
64
+ const branch = await this.github.getCurrentBranch();
65
+ const pushResult = await this.github.push('origin', branch, true);
66
+ this.logger.info({ phase, ref: pushResult.ref, remote: pushResult.remote }, 'Pushed phase changes to remote');
67
+ }
68
+ catch (error) {
69
+ // Log but don't fail the workflow — commit/push is best-effort between phases
70
+ this.logger.warn({ phase, error: String(error) }, 'Failed to commit/push after phase (non-fatal)');
71
+ }
72
+ }
73
+ /**
74
+ * Ensure a draft PR exists for the current branch.
75
+ *
76
+ * On first call: creates a new draft PR linked to the issue.
77
+ * On subsequent calls: returns the existing PR URL (no-op).
78
+ *
79
+ * @returns The PR URL, or undefined if creation failed.
80
+ */
81
+ async ensureDraftPr() {
82
+ // If we already know the PR URL, return it
83
+ if (this.prUrl) {
84
+ return this.prUrl;
85
+ }
86
+ try {
87
+ const branch = await this.github.getCurrentBranch();
88
+ // Check if a PR already exists for this branch
89
+ const existingPr = await this.github.findPRForBranch(this.owner, this.repo, branch);
90
+ if (existingPr) {
91
+ this.prNumber = existingPr.number;
92
+ this.prUrl = `https://github.com/${this.owner}/${this.repo}/pull/${existingPr.number}`;
93
+ this.logger.info({ prNumber: existingPr.number, prUrl: this.prUrl }, 'Found existing PR for branch');
94
+ return this.prUrl;
95
+ }
96
+ // Create a new draft PR
97
+ const defaultBranch = await this.github.getDefaultBranch();
98
+ const pr = await this.github.createPullRequest(this.owner, this.repo, {
99
+ title: `feat: #${this.issueNumber} ${branch}`,
100
+ body: `## Summary\n\nCloses #${this.issueNumber}\n\n---\n*Draft PR created by Generacy orchestrator. Updated after each workflow phase.*\n`,
101
+ head: branch,
102
+ base: defaultBranch,
103
+ draft: true,
104
+ });
105
+ this.prNumber = pr.number;
106
+ this.prUrl = `https://github.com/${this.owner}/${this.repo}/pull/${pr.number}`;
107
+ this.logger.info({ prNumber: pr.number, prUrl: this.prUrl }, 'Created draft PR');
108
+ return this.prUrl;
109
+ }
110
+ catch (error) {
111
+ // Log but don't fail the workflow — PR creation is best-effort
112
+ this.logger.warn({ error: String(error) }, 'Failed to ensure draft PR (non-fatal)');
113
+ return undefined;
114
+ }
115
+ }
116
+ /**
117
+ * Mark the draft PR as ready for review.
118
+ *
119
+ * Should be called after the workflow completes successfully (all phases done).
120
+ * If no PR exists or the PR number is unknown, this is a no-op.
121
+ *
122
+ * The underlying GitHub API call is idempotent — calling it on a non-draft PR
123
+ * has no effect.
124
+ */
125
+ async markReadyForReview() {
126
+ if (!this.prNumber) {
127
+ this.logger.debug('No PR number available — skipping markReadyForReview');
128
+ return;
129
+ }
130
+ try {
131
+ await this.github.markPRReady(this.owner, this.repo, this.prNumber);
132
+ this.logger.info({ prNumber: this.prNumber, prUrl: this.prUrl }, 'Marked PR as ready for review');
133
+ }
134
+ catch (error) {
135
+ // Log but don't fail the workflow — marking ready is best-effort
136
+ this.logger.warn({ prNumber: this.prNumber, error: String(error) }, 'Failed to mark PR as ready for review (non-fatal)');
137
+ }
138
+ }
139
+ }
140
+ //# sourceMappingURL=pr-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-manager.js","sourceRoot":"","sources":["../../src/worker/pr-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { Logger } from './types.js';
2
+ /**
3
+ * Manages per-worker isolated git repository checkouts.
4
+ *
5
+ * Each worker gets its own checkout at `{workspaceDir}/{workerId}/{owner}/{repo}`
6
+ * to avoid race conditions between concurrent workers.
7
+ */
8
+ export declare class RepoCheckout {
9
+ private readonly workspaceDir;
10
+ private readonly logger;
11
+ constructor(workspaceDir: string, logger: Logger);
12
+ /**
13
+ * Compute the checkout path for a given worker and repository.
14
+ * Does not perform any filesystem or git operations.
15
+ *
16
+ * @param workerId - Unique worker identifier
17
+ * @param owner - Repository owner (GitHub user or org)
18
+ * @param repo - Repository name
19
+ * @returns The absolute path where the checkout would reside
20
+ */
21
+ getCheckoutPath(workerId: string, owner: string, repo: string): string;
22
+ /**
23
+ * Ensure a repository checkout exists and is up-to-date on the given branch.
24
+ *
25
+ * If the checkout directory does not exist, the repository is cloned.
26
+ * If it already exists, it is fetched and reset to the remote branch head.
27
+ *
28
+ * @param workerId - Unique worker identifier
29
+ * @param owner - Repository owner (GitHub user or org)
30
+ * @param repo - Repository name
31
+ * @param branch - Branch to check out
32
+ * @returns The absolute path to the checkout directory
33
+ */
34
+ ensureCheckout(workerId: string, owner: string, repo: string, branch: string): Promise<string>;
35
+ /**
36
+ * Get the default branch for a repository using the GitHub API.
37
+ */
38
+ getDefaultBranch(owner: string, repo: string): Promise<string>;
39
+ /**
40
+ * Switch an existing checkout to a different branch.
41
+ * Fetches from origin first, then checks out the branch and resets to remote HEAD.
42
+ */
43
+ switchBranch(checkoutPath: string, branch: string): Promise<void>;
44
+ /**
45
+ * Remove a checkout directory recursively.
46
+ *
47
+ * @param checkoutPath - Absolute path to the checkout directory to remove
48
+ */
49
+ cleanup(checkoutPath: string): Promise<void>;
50
+ /**
51
+ * Check whether a directory exists on disk.
52
+ */
53
+ private directoryExists;
54
+ /**
55
+ * Clone a repository into the checkout path.
56
+ */
57
+ private cloneRepo;
58
+ /**
59
+ * Update an existing checkout to the latest state of a branch.
60
+ */
61
+ private updateRepo;
62
+ }
63
+ //# sourceMappingURL=repo-checkout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-checkout.d.ts","sourceRoot":"","sources":["../../src/worker/repo-checkout.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAIzC;;;;;GAKG;AACH,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM;IAGjC;;;;;;;;OAQG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAItE;;;;;;;;;;;OAWG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IAclB;;OAEG;IACG,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmBpE;;;OAGG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBvE;;;;OAIG;IACG,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlD;;OAEG;YACW,eAAe;IAY7B;;OAEG;YACW,SAAS;IA8BvB;;OAEG;YACW,UAAU;CAmCzB"}
@@ -0,0 +1,160 @@
1
+ import { mkdir, rm, stat } from 'node:fs/promises';
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import { join, dirname } from 'node:path';
5
+ const execFileAsync = promisify(execFile);
6
+ /**
7
+ * Manages per-worker isolated git repository checkouts.
8
+ *
9
+ * Each worker gets its own checkout at `{workspaceDir}/{workerId}/{owner}/{repo}`
10
+ * to avoid race conditions between concurrent workers.
11
+ */
12
+ export class RepoCheckout {
13
+ workspaceDir;
14
+ logger;
15
+ constructor(workspaceDir, logger) {
16
+ this.workspaceDir = workspaceDir;
17
+ this.logger = logger;
18
+ }
19
+ /**
20
+ * Compute the checkout path for a given worker and repository.
21
+ * Does not perform any filesystem or git operations.
22
+ *
23
+ * @param workerId - Unique worker identifier
24
+ * @param owner - Repository owner (GitHub user or org)
25
+ * @param repo - Repository name
26
+ * @returns The absolute path where the checkout would reside
27
+ */
28
+ getCheckoutPath(workerId, owner, repo) {
29
+ return join(this.workspaceDir, workerId, owner, repo);
30
+ }
31
+ /**
32
+ * Ensure a repository checkout exists and is up-to-date on the given branch.
33
+ *
34
+ * If the checkout directory does not exist, the repository is cloned.
35
+ * If it already exists, it is fetched and reset to the remote branch head.
36
+ *
37
+ * @param workerId - Unique worker identifier
38
+ * @param owner - Repository owner (GitHub user or org)
39
+ * @param repo - Repository name
40
+ * @param branch - Branch to check out
41
+ * @returns The absolute path to the checkout directory
42
+ */
43
+ async ensureCheckout(workerId, owner, repo, branch) {
44
+ const checkoutPath = this.getCheckoutPath(workerId, owner, repo);
45
+ const exists = await this.directoryExists(checkoutPath);
46
+ if (!exists) {
47
+ await this.cloneRepo(checkoutPath, owner, repo, branch);
48
+ }
49
+ else {
50
+ await this.updateRepo(checkoutPath, branch);
51
+ }
52
+ return checkoutPath;
53
+ }
54
+ /**
55
+ * Get the default branch for a repository using the GitHub API.
56
+ */
57
+ async getDefaultBranch(owner, repo) {
58
+ try {
59
+ const { stdout } = await execFileAsync('gh', [
60
+ 'repo', 'view', `${owner}/${repo}`, '--json', 'defaultBranchRef', '-q', '.defaultBranchRef.name',
61
+ ]);
62
+ const branch = stdout.trim();
63
+ if (branch) {
64
+ this.logger.info({ owner, repo, branch }, 'Resolved default branch');
65
+ return branch;
66
+ }
67
+ }
68
+ catch (error) {
69
+ this.logger.warn({ err: error, owner, repo }, 'Failed to resolve default branch, falling back to develop');
70
+ }
71
+ return 'develop';
72
+ }
73
+ /**
74
+ * Switch an existing checkout to a different branch.
75
+ * Fetches from origin first, then checks out the branch and resets to remote HEAD.
76
+ */
77
+ async switchBranch(checkoutPath, branch) {
78
+ this.logger.info({ checkoutPath, branch }, 'Switching to branch');
79
+ await execFileAsync('git', ['fetch', 'origin'], { cwd: checkoutPath });
80
+ try {
81
+ await execFileAsync('git', ['checkout', branch], { cwd: checkoutPath });
82
+ }
83
+ catch {
84
+ this.logger.debug({ checkoutPath, branch }, 'Local branch not found, creating tracking branch');
85
+ await execFileAsync('git', ['checkout', '-b', branch, `origin/${branch}`], {
86
+ cwd: checkoutPath,
87
+ });
88
+ }
89
+ await execFileAsync('git', ['reset', '--hard', `origin/${branch}`], {
90
+ cwd: checkoutPath,
91
+ });
92
+ this.logger.info({ checkoutPath, branch }, 'Switched to branch successfully');
93
+ }
94
+ /**
95
+ * Remove a checkout directory recursively.
96
+ *
97
+ * @param checkoutPath - Absolute path to the checkout directory to remove
98
+ */
99
+ async cleanup(checkoutPath) {
100
+ this.logger.info({ checkoutPath }, 'Cleaning up checkout directory');
101
+ await rm(checkoutPath, { recursive: true, force: true });
102
+ this.logger.debug({ checkoutPath }, 'Checkout directory removed');
103
+ }
104
+ /**
105
+ * Check whether a directory exists on disk.
106
+ */
107
+ async directoryExists(dirPath) {
108
+ try {
109
+ await stat(dirPath);
110
+ return true;
111
+ }
112
+ catch (err) {
113
+ if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
114
+ return false;
115
+ }
116
+ throw err;
117
+ }
118
+ }
119
+ /**
120
+ * Clone a repository into the checkout path.
121
+ */
122
+ async cloneRepo(checkoutPath, owner, repo, branch) {
123
+ const parentDir = dirname(checkoutPath);
124
+ const repoUrl = `https://github.com/${owner}/${repo}.git`;
125
+ this.logger.info({ checkoutPath, repoUrl, branch }, 'Cloning repository');
126
+ await mkdir(parentDir, { recursive: true });
127
+ this.logger.debug({ parentDir }, 'Created parent directories');
128
+ await execFileAsync('git', [
129
+ 'clone',
130
+ '--branch', branch,
131
+ repoUrl,
132
+ checkoutPath,
133
+ ]);
134
+ this.logger.info({ checkoutPath, branch }, 'Repository cloned successfully');
135
+ }
136
+ /**
137
+ * Update an existing checkout to the latest state of a branch.
138
+ */
139
+ async updateRepo(checkoutPath, branch) {
140
+ this.logger.info({ checkoutPath, branch }, 'Updating existing checkout');
141
+ this.logger.debug({ checkoutPath }, 'Fetching from origin');
142
+ await execFileAsync('git', ['fetch', 'origin'], { cwd: checkoutPath });
143
+ this.logger.debug({ checkoutPath, branch }, 'Checking out branch');
144
+ try {
145
+ await execFileAsync('git', ['checkout', branch], { cwd: checkoutPath });
146
+ }
147
+ catch {
148
+ this.logger.debug({ checkoutPath, branch }, 'Local branch not found, creating tracking branch');
149
+ await execFileAsync('git', ['checkout', '-b', branch, `origin/${branch}`], {
150
+ cwd: checkoutPath,
151
+ });
152
+ }
153
+ this.logger.debug({ checkoutPath, branch }, 'Resetting to origin branch head');
154
+ await execFileAsync('git', ['reset', '--hard', `origin/${branch}`], {
155
+ cwd: checkoutPath,
156
+ });
157
+ this.logger.info({ checkoutPath, branch }, 'Checkout updated successfully');
158
+ }
159
+ }
160
+ //# sourceMappingURL=repo-checkout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-checkout.js","sourceRoot":"","sources":["../../src/worker/repo-checkout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { GitHubClient } from '@generacy-ai/workflow-engine';
2
+ import type { StageType, StageCommentData, Logger } from './types.js';
3
+ /**
4
+ * Manages stage comments on GitHub issues using HTML markers
5
+ * to find, create, and update stage progress comments.
6
+ */
7
+ export declare class StageCommentManager {
8
+ private readonly github;
9
+ private readonly owner;
10
+ private readonly repo;
11
+ private readonly issueNumber;
12
+ private readonly logger;
13
+ constructor(github: GitHubClient, owner: string, repo: string, issueNumber: number, logger: Logger);
14
+ /**
15
+ * Find an existing stage comment or create a new one.
16
+ *
17
+ * Searches issue comments for the HTML marker corresponding to the stage.
18
+ * If found, returns its comment ID. Otherwise, creates a new comment
19
+ * with the marker and initial content, then returns the new ID.
20
+ */
21
+ findOrCreateStageComment(stage: StageType): Promise<number>;
22
+ /**
23
+ * Update an existing stage comment with new progress data.
24
+ *
25
+ * Finds or creates the comment, renders the updated body,
26
+ * and updates it via the GitHub API.
27
+ */
28
+ updateStageComment(data: StageCommentData): Promise<void>;
29
+ /**
30
+ * Render a stage comment body with a progress table and summary.
31
+ */
32
+ private renderStageComment;
33
+ }
34
+ //# sourceMappingURL=stage-comment-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage-comment-manager.d.ts","sourceRoot":"","sources":["../../src/worker/stage-comment-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA+BtE;;;GAGG;AACH,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAJN,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM;IAGjC;;;;;;OAMG;IACG,wBAAwB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAsCjE;;;;;OAKG;IACG,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB/D;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAuC3B"}
@@ -0,0 +1,114 @@
1
+ import { STAGE_MARKERS } from './types.js';
2
+ /**
3
+ * Stage display titles with emoji prefixes
4
+ */
5
+ const STAGE_TITLES = {
6
+ specification: '\u{1F4CB} Specification',
7
+ planning: '\u{1F4D0} Planning',
8
+ implementation: '\u{1F528} Implementation',
9
+ };
10
+ /**
11
+ * Status icons for phase and stage statuses
12
+ */
13
+ const STATUS_ICONS = {
14
+ pending: '\u{23F3}',
15
+ in_progress: '\u{1F504}',
16
+ complete: '\u{2705}',
17
+ error: '\u{274C}',
18
+ };
19
+ /**
20
+ * Human-readable status labels
21
+ */
22
+ const STATUS_LABELS = {
23
+ in_progress: 'In Progress',
24
+ complete: 'Complete',
25
+ error: 'Error',
26
+ };
27
+ /**
28
+ * Manages stage comments on GitHub issues using HTML markers
29
+ * to find, create, and update stage progress comments.
30
+ */
31
+ export class StageCommentManager {
32
+ github;
33
+ owner;
34
+ repo;
35
+ issueNumber;
36
+ logger;
37
+ constructor(github, owner, repo, issueNumber, logger) {
38
+ this.github = github;
39
+ this.owner = owner;
40
+ this.repo = repo;
41
+ this.issueNumber = issueNumber;
42
+ this.logger = logger;
43
+ }
44
+ /**
45
+ * Find an existing stage comment or create a new one.
46
+ *
47
+ * Searches issue comments for the HTML marker corresponding to the stage.
48
+ * If found, returns its comment ID. Otherwise, creates a new comment
49
+ * with the marker and initial content, then returns the new ID.
50
+ */
51
+ async findOrCreateStageComment(stage) {
52
+ const marker = STAGE_MARKERS[stage];
53
+ const comments = await this.github.getIssueComments(this.owner, this.repo, this.issueNumber);
54
+ // Look for an existing comment with the stage marker
55
+ for (const comment of comments) {
56
+ if (comment.body.includes(marker)) {
57
+ this.logger.debug({ stage, commentId: comment.id }, 'Found existing stage comment');
58
+ return comment.id;
59
+ }
60
+ }
61
+ // No existing comment found — create a new one
62
+ const title = STAGE_TITLES[stage];
63
+ const initialBody = `${marker}\n## ${title} Stage\n\n**Status**: ${STATUS_ICONS['pending']} Pending\n`;
64
+ const created = await this.github.addIssueComment(this.owner, this.repo, this.issueNumber, initialBody);
65
+ this.logger.info({ stage, commentId: created.id }, 'Created new stage comment');
66
+ return created.id;
67
+ }
68
+ /**
69
+ * Update an existing stage comment with new progress data.
70
+ *
71
+ * Finds or creates the comment, renders the updated body,
72
+ * and updates it via the GitHub API.
73
+ */
74
+ async updateStageComment(data) {
75
+ const commentId = await this.findOrCreateStageComment(data.stage);
76
+ const body = this.renderStageComment(data);
77
+ await this.github.updateComment(this.owner, this.repo, commentId, body);
78
+ this.logger.debug({ stage: data.stage, commentId }, 'Updated stage comment');
79
+ }
80
+ /**
81
+ * Render a stage comment body with a progress table and summary.
82
+ */
83
+ renderStageComment(data) {
84
+ const marker = STAGE_MARKERS[data.stage];
85
+ const title = STAGE_TITLES[data.stage];
86
+ const statusIcon = STATUS_ICONS[data.status] ?? STATUS_ICONS['in_progress'];
87
+ const statusLabel = STATUS_LABELS[data.status] ?? data.status;
88
+ const lines = [
89
+ marker,
90
+ `## ${title} Stage`,
91
+ '',
92
+ '| Phase | Status | Started | Completed |',
93
+ '|-------|--------|---------|-----------|',
94
+ ];
95
+ for (const phase of data.phases) {
96
+ const phaseIcon = STATUS_ICONS[phase.status] ?? STATUS_ICONS['pending'];
97
+ const started = phase.startedAt ?? '\u{2014}';
98
+ const completed = phase.completedAt ?? '\u{2014}';
99
+ lines.push(`| ${phase.phase} | ${phaseIcon} ${phase.status} | ${started} | ${completed} |`);
100
+ }
101
+ lines.push('');
102
+ lines.push(`**Status**: ${statusIcon} ${statusLabel}`);
103
+ lines.push(`**Started**: ${data.startedAt}`);
104
+ if (data.completedAt) {
105
+ lines.push(`**Completed**: ${data.completedAt}`);
106
+ }
107
+ if (data.prUrl) {
108
+ lines.push(`**PR**: ${data.prUrl}`);
109
+ }
110
+ lines.push('');
111
+ return lines.join('\n');
112
+ }
113
+ }
114
+ //# sourceMappingURL=stage-comment-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage-comment-manager.js","sourceRoot":"","sources":["../../src/worker/stage-comment-manager.ts"],"names":[],"mappings":"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"}