hub-launch 1.0.3

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 (331) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/README.md +195 -0
  3. package/bin/hublaunch +20 -0
  4. package/dist/commands/checkout.d.ts +7 -0
  5. package/dist/commands/checkout.d.ts.map +1 -0
  6. package/dist/commands/checkout.js +164 -0
  7. package/dist/commands/checkout.js.map +1 -0
  8. package/dist/commands/clean.d.ts +7 -0
  9. package/dist/commands/clean.d.ts.map +1 -0
  10. package/dist/commands/clean.js +206 -0
  11. package/dist/commands/clean.js.map +1 -0
  12. package/dist/commands/close.d.ts +7 -0
  13. package/dist/commands/close.d.ts.map +1 -0
  14. package/dist/commands/close.js +109 -0
  15. package/dist/commands/close.js.map +1 -0
  16. package/dist/commands/create.d.ts +7 -0
  17. package/dist/commands/create.d.ts.map +1 -0
  18. package/dist/commands/create.js +367 -0
  19. package/dist/commands/create.js.map +1 -0
  20. package/dist/commands/diff.d.ts +7 -0
  21. package/dist/commands/diff.d.ts.map +1 -0
  22. package/dist/commands/diff.js +98 -0
  23. package/dist/commands/diff.js.map +1 -0
  24. package/dist/commands/execute.d.ts +7 -0
  25. package/dist/commands/execute.d.ts.map +1 -0
  26. package/dist/commands/execute.js +376 -0
  27. package/dist/commands/execute.js.map +1 -0
  28. package/dist/commands/init.d.ts +8 -0
  29. package/dist/commands/init.d.ts.map +1 -0
  30. package/dist/commands/init.js +1243 -0
  31. package/dist/commands/init.js.map +1 -0
  32. package/dist/commands/interactive.d.ts +12 -0
  33. package/dist/commands/interactive.d.ts.map +1 -0
  34. package/dist/commands/interactive.js +1071 -0
  35. package/dist/commands/interactive.js.map +1 -0
  36. package/dist/commands/launch.d.ts +16 -0
  37. package/dist/commands/launch.d.ts.map +1 -0
  38. package/dist/commands/launch.js +684 -0
  39. package/dist/commands/launch.js.map +1 -0
  40. package/dist/commands/login.d.ts +40 -0
  41. package/dist/commands/login.d.ts.map +1 -0
  42. package/dist/commands/login.js +469 -0
  43. package/dist/commands/login.js.map +1 -0
  44. package/dist/commands/logs.d.ts +22 -0
  45. package/dist/commands/logs.d.ts.map +1 -0
  46. package/dist/commands/logs.js +105 -0
  47. package/dist/commands/logs.js.map +1 -0
  48. package/dist/commands/merge.d.ts +7 -0
  49. package/dist/commands/merge.d.ts.map +1 -0
  50. package/dist/commands/merge.js +240 -0
  51. package/dist/commands/merge.js.map +1 -0
  52. package/dist/commands/preview.d.ts +7 -0
  53. package/dist/commands/preview.d.ts.map +1 -0
  54. package/dist/commands/preview.js +160 -0
  55. package/dist/commands/preview.js.map +1 -0
  56. package/dist/commands/project.d.ts +18 -0
  57. package/dist/commands/project.d.ts.map +1 -0
  58. package/dist/commands/project.js +352 -0
  59. package/dist/commands/project.js.map +1 -0
  60. package/dist/commands/respond.d.ts +7 -0
  61. package/dist/commands/respond.d.ts.map +1 -0
  62. package/dist/commands/respond.js +112 -0
  63. package/dist/commands/respond.js.map +1 -0
  64. package/dist/commands/setPriority.d.ts +7 -0
  65. package/dist/commands/setPriority.d.ts.map +1 -0
  66. package/dist/commands/setPriority.js +112 -0
  67. package/dist/commands/setPriority.js.map +1 -0
  68. package/dist/commands/track.d.ts +7 -0
  69. package/dist/commands/track.d.ts.map +1 -0
  70. package/dist/commands/track.js +140 -0
  71. package/dist/commands/track.js.map +1 -0
  72. package/dist/commands/upload.d.ts +21 -0
  73. package/dist/commands/upload.d.ts.map +1 -0
  74. package/dist/commands/upload.js +145 -0
  75. package/dist/commands/upload.js.map +1 -0
  76. package/dist/commands/view.d.ts +7 -0
  77. package/dist/commands/view.d.ts.map +1 -0
  78. package/dist/commands/view.js +168 -0
  79. package/dist/commands/view.js.map +1 -0
  80. package/dist/commands/watch.d.ts +7 -0
  81. package/dist/commands/watch.d.ts.map +1 -0
  82. package/dist/commands/watch.js +438 -0
  83. package/dist/commands/watch.js.map +1 -0
  84. package/dist/commands/worktree.d.ts +7 -0
  85. package/dist/commands/worktree.d.ts.map +1 -0
  86. package/dist/commands/worktree.js +122 -0
  87. package/dist/commands/worktree.js.map +1 -0
  88. package/dist/config/command-names.d.ts +16 -0
  89. package/dist/config/command-names.d.ts.map +1 -0
  90. package/dist/config/command-names.js +17 -0
  91. package/dist/config/command-names.js.map +1 -0
  92. package/dist/config/constants.d.ts +12 -0
  93. package/dist/config/constants.d.ts.map +1 -0
  94. package/dist/config/constants.js +12 -0
  95. package/dist/config/constants.js.map +1 -0
  96. package/dist/config/index.d.ts +47 -0
  97. package/dist/config/index.d.ts.map +1 -0
  98. package/dist/config/index.js +175 -0
  99. package/dist/config/index.js.map +1 -0
  100. package/dist/index.d.ts +3 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +148 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/services/api/HulaApiClient.d.ts +170 -0
  105. package/dist/services/api/HulaApiClient.d.ts.map +1 -0
  106. package/dist/services/api/HulaApiClient.js +233 -0
  107. package/dist/services/api/HulaApiClient.js.map +1 -0
  108. package/dist/services/diff/DiffService.d.ts +44 -0
  109. package/dist/services/diff/DiffService.d.ts.map +1 -0
  110. package/dist/services/diff/DiffService.js +126 -0
  111. package/dist/services/diff/DiffService.js.map +1 -0
  112. package/dist/services/editor/EditorService.d.ts +53 -0
  113. package/dist/services/editor/EditorService.d.ts.map +1 -0
  114. package/dist/services/editor/EditorService.js +161 -0
  115. package/dist/services/editor/EditorService.js.map +1 -0
  116. package/dist/services/git/GitService.d.ts +124 -0
  117. package/dist/services/git/GitService.d.ts.map +1 -0
  118. package/dist/services/git/GitService.js +423 -0
  119. package/dist/services/git/GitService.js.map +1 -0
  120. package/dist/services/git/WorktreeService.d.ts +144 -0
  121. package/dist/services/git/WorktreeService.d.ts.map +1 -0
  122. package/dist/services/git/WorktreeService.js +505 -0
  123. package/dist/services/git/WorktreeService.js.map +1 -0
  124. package/dist/services/github/ActionsService.d.ts +66 -0
  125. package/dist/services/github/ActionsService.d.ts.map +1 -0
  126. package/dist/services/github/ActionsService.js +114 -0
  127. package/dist/services/github/ActionsService.js.map +1 -0
  128. package/dist/services/github/AssetUploadService.d.ts +103 -0
  129. package/dist/services/github/AssetUploadService.d.ts.map +1 -0
  130. package/dist/services/github/AssetUploadService.js +299 -0
  131. package/dist/services/github/AssetUploadService.js.map +1 -0
  132. package/dist/services/github/BatchCopilotDetectionService.d.ts +58 -0
  133. package/dist/services/github/BatchCopilotDetectionService.d.ts.map +1 -0
  134. package/dist/services/github/BatchCopilotDetectionService.js +321 -0
  135. package/dist/services/github/BatchCopilotDetectionService.js.map +1 -0
  136. package/dist/services/github/CopilotDetectionService.d.ts +40 -0
  137. package/dist/services/github/CopilotDetectionService.d.ts.map +1 -0
  138. package/dist/services/github/CopilotDetectionService.js +280 -0
  139. package/dist/services/github/CopilotDetectionService.js.map +1 -0
  140. package/dist/services/github/CopilotService.d.ts +27 -0
  141. package/dist/services/github/CopilotService.d.ts.map +1 -0
  142. package/dist/services/github/CopilotService.js +249 -0
  143. package/dist/services/github/CopilotService.js.map +1 -0
  144. package/dist/services/github/DeploymentDetectionService.d.ts +38 -0
  145. package/dist/services/github/DeploymentDetectionService.d.ts.map +1 -0
  146. package/dist/services/github/DeploymentDetectionService.js +104 -0
  147. package/dist/services/github/DeploymentDetectionService.js.map +1 -0
  148. package/dist/services/github/GithubAppService.d.ts +40 -0
  149. package/dist/services/github/GithubAppService.d.ts.map +1 -0
  150. package/dist/services/github/GithubAppService.js +187 -0
  151. package/dist/services/github/GithubAppService.js.map +1 -0
  152. package/dist/services/github/IssueService.d.ts +65 -0
  153. package/dist/services/github/IssueService.d.ts.map +1 -0
  154. package/dist/services/github/IssueService.js +231 -0
  155. package/dist/services/github/IssueService.js.map +1 -0
  156. package/dist/services/github/LabelService.d.ts +36 -0
  157. package/dist/services/github/LabelService.d.ts.map +1 -0
  158. package/dist/services/github/LabelService.js +122 -0
  159. package/dist/services/github/LabelService.js.map +1 -0
  160. package/dist/services/github/PRService.d.ts +77 -0
  161. package/dist/services/github/PRService.d.ts.map +1 -0
  162. package/dist/services/github/PRService.js +287 -0
  163. package/dist/services/github/PRService.js.map +1 -0
  164. package/dist/services/github/ProjectService.d.ts +144 -0
  165. package/dist/services/github/ProjectService.d.ts.map +1 -0
  166. package/dist/services/github/ProjectService.js +804 -0
  167. package/dist/services/github/ProjectService.js.map +1 -0
  168. package/dist/services/hooks/HookExecutor.d.ts +66 -0
  169. package/dist/services/hooks/HookExecutor.d.ts.map +1 -0
  170. package/dist/services/hooks/HookExecutor.js +227 -0
  171. package/dist/services/hooks/HookExecutor.js.map +1 -0
  172. package/dist/services/hooks/index.d.ts +2 -0
  173. package/dist/services/hooks/index.d.ts.map +1 -0
  174. package/dist/services/hooks/index.js +2 -0
  175. package/dist/services/hooks/index.js.map +1 -0
  176. package/dist/services/logs/LogFormatterService.d.ts +17 -0
  177. package/dist/services/logs/LogFormatterService.d.ts.map +1 -0
  178. package/dist/services/logs/LogFormatterService.js +35 -0
  179. package/dist/services/logs/LogFormatterService.js.map +1 -0
  180. package/dist/services/logs/TempFileService.d.ts +27 -0
  181. package/dist/services/logs/TempFileService.d.ts.map +1 -0
  182. package/dist/services/logs/TempFileService.js +90 -0
  183. package/dist/services/logs/TempFileService.js.map +1 -0
  184. package/dist/services/logs/index.d.ts +3 -0
  185. package/dist/services/logs/index.d.ts.map +1 -0
  186. package/dist/services/logs/index.js +4 -0
  187. package/dist/services/logs/index.js.map +1 -0
  188. package/dist/services/plan/PlanService.d.ts +70 -0
  189. package/dist/services/plan/PlanService.d.ts.map +1 -0
  190. package/dist/services/plan/PlanService.js +211 -0
  191. package/dist/services/plan/PlanService.js.map +1 -0
  192. package/dist/services/polling/GitHubDirectPollingAdapter.d.ts +16 -0
  193. package/dist/services/polling/GitHubDirectPollingAdapter.d.ts.map +1 -0
  194. package/dist/services/polling/GitHubDirectPollingAdapter.js +87 -0
  195. package/dist/services/polling/GitHubDirectPollingAdapter.js.map +1 -0
  196. package/dist/services/polling/HulaServerPollingAdapter.d.ts +23 -0
  197. package/dist/services/polling/HulaServerPollingAdapter.d.ts.map +1 -0
  198. package/dist/services/polling/HulaServerPollingAdapter.js +78 -0
  199. package/dist/services/polling/HulaServerPollingAdapter.js.map +1 -0
  200. package/dist/services/polling/IStatusPollingAdapter.d.ts +29 -0
  201. package/dist/services/polling/IStatusPollingAdapter.d.ts.map +1 -0
  202. package/dist/services/polling/IStatusPollingAdapter.js +2 -0
  203. package/dist/services/polling/IStatusPollingAdapter.js.map +1 -0
  204. package/dist/services/polling/StatusPollingAdapterFactory.d.ts +14 -0
  205. package/dist/services/polling/StatusPollingAdapterFactory.d.ts.map +1 -0
  206. package/dist/services/polling/StatusPollingAdapterFactory.js +41 -0
  207. package/dist/services/polling/StatusPollingAdapterFactory.js.map +1 -0
  208. package/dist/services/polling/index.d.ts +5 -0
  209. package/dist/services/polling/index.d.ts.map +1 -0
  210. package/dist/services/polling/index.js +5 -0
  211. package/dist/services/polling/index.js.map +1 -0
  212. package/dist/services/preview/PreviewService.d.ts +86 -0
  213. package/dist/services/preview/PreviewService.d.ts.map +1 -0
  214. package/dist/services/preview/PreviewService.js +439 -0
  215. package/dist/services/preview/PreviewService.js.map +1 -0
  216. package/dist/services/tracking/ProjectTrackingAdapter.d.ts +41 -0
  217. package/dist/services/tracking/ProjectTrackingAdapter.d.ts.map +1 -0
  218. package/dist/services/tracking/ProjectTrackingAdapter.js +230 -0
  219. package/dist/services/tracking/ProjectTrackingAdapter.js.map +1 -0
  220. package/dist/services/tracking/RemoteTrackingAdapter.d.ts +62 -0
  221. package/dist/services/tracking/RemoteTrackingAdapter.d.ts.map +1 -0
  222. package/dist/services/tracking/RemoteTrackingAdapter.js +242 -0
  223. package/dist/services/tracking/RemoteTrackingAdapter.js.map +1 -0
  224. package/dist/services/tracking/TrackingAdapterFactory.d.ts +25 -0
  225. package/dist/services/tracking/TrackingAdapterFactory.d.ts.map +1 -0
  226. package/dist/services/tracking/TrackingAdapterFactory.js +55 -0
  227. package/dist/services/tracking/TrackingAdapterFactory.js.map +1 -0
  228. package/dist/services/tracking/TrackingService.d.ts +104 -0
  229. package/dist/services/tracking/TrackingService.d.ts.map +1 -0
  230. package/dist/services/tracking/TrackingService.js +256 -0
  231. package/dist/services/tracking/TrackingService.js.map +1 -0
  232. package/dist/services/tracking/UntrackedIssuesService.d.ts +20 -0
  233. package/dist/services/tracking/UntrackedIssuesService.d.ts.map +1 -0
  234. package/dist/services/tracking/UntrackedIssuesService.js +148 -0
  235. package/dist/services/tracking/UntrackedIssuesService.js.map +1 -0
  236. package/dist/services/tracking/local-file-migration.d.ts +16 -0
  237. package/dist/services/tracking/local-file-migration.d.ts.map +1 -0
  238. package/dist/services/tracking/local-file-migration.js +86 -0
  239. package/dist/services/tracking/local-file-migration.js.map +1 -0
  240. package/dist/templates/planning-instructions.md +752 -0
  241. package/dist/templates/proceed-instructions.md +453 -0
  242. package/dist/templates/scripts/hula-fix-commit.sh +110 -0
  243. package/dist/templates/scripts/hula-fix-setup.sh +145 -0
  244. package/dist/templates/scripts/hula-launch-run.sh +89 -0
  245. package/dist/templates/scripts/hula-merge-local.sh +138 -0
  246. package/dist/templates/scripts/hula-merge-remote.sh +74 -0
  247. package/dist/templates/scripts/hula-read-config.sh +38 -0
  248. package/dist/templates/scripts/hula-verify-gather.sh +135 -0
  249. package/dist/templates/scripts/hula-verify-post.sh +84 -0
  250. package/dist/templates/skills/hula-confirm/SKILL.md +361 -0
  251. package/dist/templates/skills/hula-create/SKILL.md +211 -0
  252. package/dist/templates/skills/hula-fix/SKILL.md +224 -0
  253. package/dist/templates/skills/hula-launch/SKILL.md +159 -0
  254. package/dist/templates/skills/hula-log/SKILL.md +105 -0
  255. package/dist/templates/skills/hula-merge/SKILL.md +387 -0
  256. package/dist/templates/skills/hula-plan/SKILL.md +148 -0
  257. package/dist/templates/skills/hula-upload/SKILL.md +115 -0
  258. package/dist/templates/skills/hula-verify/SKILL.md +754 -0
  259. package/dist/types/common.schema.d.ts +46 -0
  260. package/dist/types/common.schema.d.ts.map +1 -0
  261. package/dist/types/common.schema.js +60 -0
  262. package/dist/types/common.schema.js.map +1 -0
  263. package/dist/types/config.schema.d.ts +443 -0
  264. package/dist/types/config.schema.d.ts.map +1 -0
  265. package/dist/types/config.schema.js +126 -0
  266. package/dist/types/config.schema.js.map +1 -0
  267. package/dist/types/index.d.ts +6 -0
  268. package/dist/types/index.d.ts.map +1 -0
  269. package/dist/types/index.js +7 -0
  270. package/dist/types/index.js.map +1 -0
  271. package/dist/types/issue.schema.d.ts +136 -0
  272. package/dist/types/issue.schema.d.ts.map +1 -0
  273. package/dist/types/issue.schema.js +49 -0
  274. package/dist/types/issue.schema.js.map +1 -0
  275. package/dist/types/pr.schema.d.ts +118 -0
  276. package/dist/types/pr.schema.d.ts.map +1 -0
  277. package/dist/types/pr.schema.js +40 -0
  278. package/dist/types/pr.schema.js.map +1 -0
  279. package/dist/types/tracking.schema.d.ts +340 -0
  280. package/dist/types/tracking.schema.d.ts.map +1 -0
  281. package/dist/types/tracking.schema.js +56 -0
  282. package/dist/types/tracking.schema.js.map +1 -0
  283. package/dist/utils/browser-launcher.d.ts +60 -0
  284. package/dist/utils/browser-launcher.d.ts.map +1 -0
  285. package/dist/utils/browser-launcher.js +263 -0
  286. package/dist/utils/browser-launcher.js.map +1 -0
  287. package/dist/utils/cache.d.ts +44 -0
  288. package/dist/utils/cache.d.ts.map +1 -0
  289. package/dist/utils/cache.js +94 -0
  290. package/dist/utils/cache.js.map +1 -0
  291. package/dist/utils/config-parser.d.ts +16 -0
  292. package/dist/utils/config-parser.d.ts.map +1 -0
  293. package/dist/utils/config-parser.js +210 -0
  294. package/dist/utils/config-parser.js.map +1 -0
  295. package/dist/utils/editor.d.ts +21 -0
  296. package/dist/utils/editor.d.ts.map +1 -0
  297. package/dist/utils/editor.js +213 -0
  298. package/dist/utils/editor.js.map +1 -0
  299. package/dist/utils/git-utils.d.ts +5 -0
  300. package/dist/utils/git-utils.d.ts.map +1 -0
  301. package/dist/utils/git-utils.js +18 -0
  302. package/dist/utils/git-utils.js.map +1 -0
  303. package/dist/utils/github-cli.d.ts +62 -0
  304. package/dist/utils/github-cli.d.ts.map +1 -0
  305. package/dist/utils/github-cli.js +492 -0
  306. package/dist/utils/github-cli.js.map +1 -0
  307. package/dist/utils/logger.d.ts +45 -0
  308. package/dist/utils/logger.d.ts.map +1 -0
  309. package/dist/utils/logger.js +118 -0
  310. package/dist/utils/logger.js.map +1 -0
  311. package/dist/utils/open-url.d.ts +19 -0
  312. package/dist/utils/open-url.d.ts.map +1 -0
  313. package/dist/utils/open-url.js +37 -0
  314. package/dist/utils/open-url.js.map +1 -0
  315. package/dist/utils/project-resolver.d.ts +13 -0
  316. package/dist/utils/project-resolver.d.ts.map +1 -0
  317. package/dist/utils/project-resolver.js +35 -0
  318. package/dist/utils/project-resolver.js.map +1 -0
  319. package/dist/utils/prompts.d.ts +80 -0
  320. package/dist/utils/prompts.d.ts.map +1 -0
  321. package/dist/utils/prompts.js +326 -0
  322. package/dist/utils/prompts.js.map +1 -0
  323. package/dist/utils/shell.d.ts +54 -0
  324. package/dist/utils/shell.d.ts.map +1 -0
  325. package/dist/utils/shell.js +152 -0
  326. package/dist/utils/shell.js.map +1 -0
  327. package/dist/utils/validators.d.ts +32 -0
  328. package/dist/utils/validators.d.ts.map +1 -0
  329. package/dist/utils/validators.js +64 -0
  330. package/dist/utils/validators.js.map +1 -0
  331. package/package.json +73 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * GitHub Actions workflow run status
3
+ */
4
+ export type WorkflowRunStatus = "queued" | "in_progress" | "completed" | "waiting";
5
+ /**
6
+ * GitHub Actions workflow run conclusion
7
+ */
8
+ export type WorkflowRunConclusion = "success" | "failure" | "cancelled" | "skipped" | "timed_out" | "action_required" | null;
9
+ /**
10
+ * Workflow run result
11
+ */
12
+ export interface WorkflowRun {
13
+ id: number;
14
+ name: string;
15
+ status: WorkflowRunStatus;
16
+ conclusion: WorkflowRunConclusion;
17
+ html_url: string;
18
+ created_at: string;
19
+ updated_at: string;
20
+ run_started_at?: string;
21
+ }
22
+ /**
23
+ * Test result summary
24
+ */
25
+ export interface TestResult {
26
+ passed: boolean;
27
+ duration: number;
28
+ workflowUrl: string;
29
+ workflowRunId: number;
30
+ logs?: string;
31
+ }
32
+ /**
33
+ * Service for GitHub Actions operations
34
+ * Single Responsibility: Monitor and interact with GitHub Actions workflows
35
+ */
36
+ export declare class ActionsService {
37
+ /**
38
+ * Get workflow runs for a specific PR
39
+ * Note: Fetches recent workflow runs and filters by time in getLatestWorkflowRunAfter().
40
+ * Supports workflows triggered by both pull_request and issue_comment events.
41
+ */
42
+ getWorkflowRunsForPR(_prNumber: number): Promise<WorkflowRun[]>;
43
+ /**
44
+ * Get a specific workflow run by ID
45
+ */
46
+ getWorkflowRun(runId: number): Promise<WorkflowRun>;
47
+ /**
48
+ * Get the latest workflow run for a PR after a specific time
49
+ * Filters for "Run Test" workflow to avoid picking up other workflows
50
+ */
51
+ getLatestWorkflowRunAfter(prNumber: number, afterTime: Date): Promise<WorkflowRun | null>;
52
+ /**
53
+ * Poll for workflow completion
54
+ * Returns the completed workflow run or null if timeout
55
+ */
56
+ pollForCompletion(runId: number, timeoutSeconds?: number, pollIntervalSeconds?: number): Promise<WorkflowRun | null>;
57
+ /**
58
+ * Get workflow run logs (simplified - actual implementation would need job ID)
59
+ */
60
+ getWorkflowLogs(runId: number): Promise<string>;
61
+ /**
62
+ * Convert workflow run to test result
63
+ */
64
+ convertToTestResult(run: WorkflowRun): Promise<TestResult>;
65
+ }
66
+ //# sourceMappingURL=ActionsService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionsService.d.ts","sourceRoot":"","sources":["../../../src/services/github/ActionsService.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,aAAa,GACb,WAAW,GACX,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAC7B,SAAS,GACT,SAAS,GACT,WAAW,GACX,SAAS,GACT,WAAW,GACX,iBAAiB,GACjB,IAAI,CAAC;AAET;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,qBAAqB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB;;;;OAIG;IACG,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAYrE;;OAEG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAUzD;;;OAGG;IACG,yBAAyB,CAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,IAAI,GACd,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAuB9B;;;OAGG;IACG,iBAAiB,CACrB,KAAK,EAAE,MAAM,EACb,cAAc,GAAE,MAAY,EAC5B,mBAAmB,GAAE,MAAW,GAC/B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAsC9B;;OAEG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcrD;;OAEG;IACG,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;CAqBjE"}
@@ -0,0 +1,114 @@
1
+ /* eslint-disable @typescript-eslint/no-inferrable-types */
2
+ import { ghApi, getRepoInfo } from "../../utils/github-cli.js";
3
+ import { logger } from "../../utils/logger.js";
4
+ /**
5
+ * Service for GitHub Actions operations
6
+ * Single Responsibility: Monitor and interact with GitHub Actions workflows
7
+ */
8
+ export class ActionsService {
9
+ /**
10
+ * Get workflow runs for a specific PR
11
+ * Note: Fetches recent workflow runs and filters by time in getLatestWorkflowRunAfter().
12
+ * Supports workflows triggered by both pull_request and issue_comment events.
13
+ */
14
+ async getWorkflowRunsForPR(_prNumber) {
15
+ const repo = await getRepoInfo();
16
+ // Get recent workflow runs with pagination limit to avoid buffer overflow
17
+ // No event filter to support both pull_request and issue_comment triggers
18
+ const response = await ghApi(`/repos/${repo.owner}/${repo.name}/actions/runs?per_page=30`);
19
+ return response.workflow_runs || [];
20
+ }
21
+ /**
22
+ * Get a specific workflow run by ID
23
+ */
24
+ async getWorkflowRun(runId) {
25
+ const repo = await getRepoInfo();
26
+ const response = await ghApi(`/repos/${repo.owner}/${repo.name}/actions/runs/${runId}`);
27
+ return response;
28
+ }
29
+ /**
30
+ * Get the latest workflow run for a PR after a specific time
31
+ * Filters for "Run Test" workflow to avoid picking up other workflows
32
+ */
33
+ async getLatestWorkflowRunAfter(prNumber, afterTime) {
34
+ const runs = await this.getWorkflowRunsForPR(prNumber);
35
+ // Find the most recent "Run Test" workflow run after the specified time
36
+ const recentRuns = runs.filter((run) => {
37
+ const createdAt = new Date(run.created_at);
38
+ const isRunTestWorkflow = run.name === "Run Test";
39
+ return createdAt > afterTime && isRunTestWorkflow;
40
+ });
41
+ if (recentRuns.length === 0) {
42
+ return null;
43
+ }
44
+ // Sort by created_at descending and return the first one
45
+ recentRuns.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
46
+ return recentRuns[0] ?? null;
47
+ }
48
+ /**
49
+ * Poll for workflow completion
50
+ * Returns the completed workflow run or null if timeout
51
+ */
52
+ async pollForCompletion(runId, timeoutSeconds = 120, pollIntervalSeconds = 10) {
53
+ const startTime = Date.now();
54
+ const pollIntervalMs = pollIntervalSeconds * 1000;
55
+ process.stdout.write(`⏳ Waiting for workflow run #${runId} to complete...\n`);
56
+ while (Date.now() - startTime < timeoutSeconds * 1000) {
57
+ const run = await this.getWorkflowRun(runId);
58
+ if (run.status === "completed") {
59
+ // Clear the status line and show completion message
60
+ process.stdout.write("\r" + " ".repeat(80) + "\r");
61
+ logger.success(`✓ Workflow completed with conclusion: ${run.conclusion}`);
62
+ return run;
63
+ }
64
+ const elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
65
+ // Update the same line with current status
66
+ process.stdout.write(`\r⏳ Workflow status: ${run.status} (${elapsedSeconds}s elapsed)` +
67
+ " ".repeat(20));
68
+ // Wait before next poll
69
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
70
+ }
71
+ // Clear the status line before showing timeout message
72
+ process.stdout.write("\r" + " ".repeat(80) + "\r");
73
+ logger.warning(`⏱️ Timeout waiting for workflow completion`);
74
+ return null;
75
+ }
76
+ /**
77
+ * Get workflow run logs (simplified - actual implementation would need job ID)
78
+ */
79
+ async getWorkflowLogs(runId) {
80
+ const repo = await getRepoInfo();
81
+ try {
82
+ // This would download logs as a zip file in real implementation
83
+ // For now, we'll return a placeholder
84
+ logger.debug(`Fetching logs for workflow run #${runId}`);
85
+ return `Logs for workflow run #${runId}\nView full logs at: https://github.com/${repo.owner}/${repo.name}/actions/runs/${runId}`;
86
+ }
87
+ catch (error) {
88
+ logger.debug(`Could not fetch logs: ${String(error)}`);
89
+ return "";
90
+ }
91
+ }
92
+ /**
93
+ * Convert workflow run to test result
94
+ */
95
+ async convertToTestResult(run) {
96
+ const passed = run.conclusion === "success";
97
+ // Calculate duration
98
+ const startTime = run.run_started_at
99
+ ? new Date(run.run_started_at)
100
+ : new Date(run.created_at);
101
+ const endTime = new Date(run.updated_at);
102
+ const durationMs = endTime.getTime() - startTime.getTime();
103
+ const durationSeconds = Math.floor(durationMs / 1000);
104
+ const logs = await this.getWorkflowLogs(run.id);
105
+ return {
106
+ passed,
107
+ duration: durationSeconds,
108
+ workflowUrl: run.html_url,
109
+ workflowRunId: run.id,
110
+ logs,
111
+ };
112
+ }
113
+ }
114
+ //# sourceMappingURL=ActionsService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionsService.js","sourceRoot":"","sources":["../../../src/services/github/ActionsService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Result of uploading a single image asset.
3
+ */
4
+ export interface UploadedAsset {
5
+ /** Original local file path */
6
+ localPath: string;
7
+ /** The filename (e.g., "screenshot.png") */
8
+ filename: string;
9
+ /** The GitHub URL for the uploaded image */
10
+ url: string;
11
+ /** Markdown image reference: ![filename](url) */
12
+ markdown: string;
13
+ }
14
+ /**
15
+ * Service for uploading image assets to GitHub via the REST API.
16
+ *
17
+ * Uploads images to a dedicated `hublaunch-assets` branch in the
18
+ * repository using the Git database API (blobs, trees, commits).
19
+ * This works with the standard OAuth token from `gh auth` / `hula login`
20
+ * and supports files up to 100 MB.
21
+ *
22
+ * The resulting raw.githubusercontent.com URLs inherit the repository's
23
+ * visibility — images on private repos require authentication to view.
24
+ */
25
+ export declare class AssetUploadService {
26
+ private token;
27
+ private repoInfo;
28
+ private assetsBranchReady;
29
+ /**
30
+ * Get the GitHub auth token from the gh CLI.
31
+ */
32
+ private getToken;
33
+ /**
34
+ * Get repo info (cached).
35
+ */
36
+ private getRepo;
37
+ /**
38
+ * Make an authenticated GitHub API request.
39
+ */
40
+ private githubApi;
41
+ /**
42
+ * Ensure the assets branch exists in the remote. Creates it from the
43
+ * default branch if it doesn't exist yet.
44
+ */
45
+ private ensureAssetsBranch;
46
+ /**
47
+ * Validate that a file path points to a supported image file.
48
+ * Returns the resolved absolute path, or throws with a descriptive error.
49
+ */
50
+ validateImageFile(filePath: string): string;
51
+ /**
52
+ * Upload a single image file via the GitHub Git database API.
53
+ *
54
+ * Uses the blob → tree → commit → ref update flow to support
55
+ * files up to 100 MB without command-line length limits.
56
+ *
57
+ * @param filePath - Absolute or relative path to the image file
58
+ * @returns UploadedAsset with the GitHub URL and markdown reference
59
+ */
60
+ uploadImage(filePath: string): Promise<UploadedAsset>;
61
+ /**
62
+ * Upload multiple image files.
63
+ *
64
+ * @param filePaths - Array of file paths to upload
65
+ * @returns Array of UploadedAsset results (one per file)
66
+ */
67
+ uploadImages(filePaths: string[]): Promise<UploadedAsset[]>;
68
+ /**
69
+ * Scan a markdown body for local image references and return the
70
+ * file paths that need uploading.
71
+ *
72
+ * Detects patterns like:
73
+ * - ![alt](./screenshot.png)
74
+ * - ![alt](screenshot.png)
75
+ * - ![alt](../assets/image.jpg)
76
+ * - ![alt](/absolute/path/to/image.png)
77
+ *
78
+ * Only matches paths that:
79
+ * 1. Have a supported image extension
80
+ * 2. Do NOT start with http:// or https:// (those are already URLs)
81
+ * 3. Point to files that exist on disk
82
+ *
83
+ * @param body - The markdown content to scan
84
+ * @param basePath - The directory to resolve relative paths against
85
+ * (typically the directory containing the plan file)
86
+ * @returns Array of { match, localPath, altText } for each local image found
87
+ */
88
+ scanForLocalImages(body: string, basePath: string): Array<{
89
+ match: string;
90
+ localPath: string;
91
+ altText: string;
92
+ }>;
93
+ /**
94
+ * Process a plan body: find local image references, upload them,
95
+ * and replace the local paths with GitHub URLs.
96
+ *
97
+ * @param body - The plan markdown body
98
+ * @param basePath - Directory to resolve relative image paths against
99
+ * @returns The updated body with local image paths replaced by GitHub URLs
100
+ */
101
+ resolveLocalImages(body: string, basePath: string): Promise<string>;
102
+ }
103
+ //# sourceMappingURL=AssetUploadService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetUploadService.d.ts","sourceRoot":"","sources":["../../../src/services/github/AssetUploadService.ts"],"names":[],"mappings":"AAwBA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAgD;IAChE,OAAO,CAAC,iBAAiB,CAAS;IAElC;;OAEG;YACW,QAAQ;IAYtB;;OAEG;YACW,OAAO;IAMrB;;OAEG;YACW,SAAS;IAqBvB;;;OAGG;YACW,kBAAkB;IAqChC;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAgC3C;;;;;;;;OAQG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA8E3D;;;;;OAKG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAuBjE;;;;;;;;;;;;;;;;;;;OAmBG;IACH,kBAAkB,CAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAiD/D;;;;;;;OAOG;IACG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAkC1E"}
@@ -0,0 +1,299 @@
1
+ import { existsSync, statSync, readFileSync } from 'fs';
2
+ import { basename, extname, resolve, isAbsolute } from 'path';
3
+ import { logger } from '../../utils/logger.js';
4
+ import { runCommand } from '../../utils/shell.js';
5
+ import { getRepoInfo } from '../../utils/github-cli.js';
6
+ import axios from 'axios';
7
+ /**
8
+ * Supported image extensions for attachment uploads.
9
+ * Only image formats are allowed (screenshots use case).
10
+ */
11
+ const SUPPORTED_IMAGE_EXTENSIONS = new Set([
12
+ '.png',
13
+ '.jpg',
14
+ '.jpeg',
15
+ '.gif',
16
+ '.webp',
17
+ ]);
18
+ /**
19
+ * Branch used to store uploaded image assets.
20
+ */
21
+ const ASSETS_BRANCH = 'hublaunch-assets';
22
+ /**
23
+ * Service for uploading image assets to GitHub via the REST API.
24
+ *
25
+ * Uploads images to a dedicated `hublaunch-assets` branch in the
26
+ * repository using the Git database API (blobs, trees, commits).
27
+ * This works with the standard OAuth token from `gh auth` / `hula login`
28
+ * and supports files up to 100 MB.
29
+ *
30
+ * The resulting raw.githubusercontent.com URLs inherit the repository's
31
+ * visibility — images on private repos require authentication to view.
32
+ */
33
+ export class AssetUploadService {
34
+ token = null;
35
+ repoInfo = null;
36
+ assetsBranchReady = false;
37
+ /**
38
+ * Get the GitHub auth token from the gh CLI.
39
+ */
40
+ async getToken() {
41
+ if (this.token)
42
+ return this.token;
43
+ try {
44
+ this.token = await runCommand('gh auth token', { silent: true });
45
+ return this.token;
46
+ }
47
+ catch {
48
+ throw new Error('GitHub authentication required for image uploads. Run `hula login` first.');
49
+ }
50
+ }
51
+ /**
52
+ * Get repo info (cached).
53
+ */
54
+ async getRepo() {
55
+ if (this.repoInfo)
56
+ return this.repoInfo;
57
+ this.repoInfo = await getRepoInfo();
58
+ return this.repoInfo;
59
+ }
60
+ /**
61
+ * Make an authenticated GitHub API request.
62
+ */
63
+ async githubApi(method, path, data) {
64
+ const token = await this.getToken();
65
+ const url = path.startsWith('https://')
66
+ ? path
67
+ : `https://api.github.com${path}`;
68
+ const response = await axios({
69
+ method,
70
+ url,
71
+ data,
72
+ headers: {
73
+ Authorization: `token ${token}`,
74
+ Accept: 'application/vnd.github.v3+json',
75
+ },
76
+ });
77
+ return response.data;
78
+ }
79
+ /**
80
+ * Ensure the assets branch exists in the remote. Creates it from the
81
+ * default branch if it doesn't exist yet.
82
+ */
83
+ async ensureAssetsBranch() {
84
+ if (this.assetsBranchReady)
85
+ return;
86
+ const repo = await this.getRepo();
87
+ try {
88
+ await this.githubApi('get', `/repos/${repo.owner}/${repo.name}/git/refs/heads/${ASSETS_BRANCH}`);
89
+ }
90
+ catch (error) {
91
+ if (error.response?.status === 404) {
92
+ logger.debug(`Creating ${ASSETS_BRANCH} branch...`);
93
+ const repoData = await this.githubApi('get', `/repos/${repo.owner}/${repo.name}`);
94
+ const refData = await this.githubApi('get', `/repos/${repo.owner}/${repo.name}/git/refs/heads/${repoData.default_branch}`);
95
+ await this.githubApi('post', `/repos/${repo.owner}/${repo.name}/git/refs`, {
96
+ ref: `refs/heads/${ASSETS_BRANCH}`,
97
+ sha: refData.object.sha,
98
+ });
99
+ logger.debug(`Created ${ASSETS_BRANCH} branch`);
100
+ }
101
+ else {
102
+ throw error;
103
+ }
104
+ }
105
+ this.assetsBranchReady = true;
106
+ }
107
+ /**
108
+ * Validate that a file path points to a supported image file.
109
+ * Returns the resolved absolute path, or throws with a descriptive error.
110
+ */
111
+ validateImageFile(filePath) {
112
+ const resolved = isAbsolute(filePath) ? filePath : resolve(filePath);
113
+ if (!existsSync(resolved)) {
114
+ throw new Error(`Attachment file not found: ${filePath}`);
115
+ }
116
+ const ext = extname(resolved).toLowerCase();
117
+ if (!SUPPORTED_IMAGE_EXTENSIONS.has(ext)) {
118
+ throw new Error(`Unsupported file type: ${ext} (${basename(resolved)}). ` +
119
+ `Supported: ${[...SUPPORTED_IMAGE_EXTENSIONS].join(', ')}`);
120
+ }
121
+ // Basic size check — GitHub rejects uploads > 10 MB
122
+ const stats = statSync(resolved);
123
+ const maxSizeBytes = 10 * 1024 * 1024; // 10 MB
124
+ if (stats.size > maxSizeBytes) {
125
+ throw new Error(`File too large: ${basename(resolved)} (${(stats.size / 1024 / 1024).toFixed(1)} MB). ` +
126
+ `Maximum size is 10 MB.`);
127
+ }
128
+ if (stats.size === 0) {
129
+ throw new Error(`File is empty: ${basename(resolved)}`);
130
+ }
131
+ return resolved;
132
+ }
133
+ /**
134
+ * Upload a single image file via the GitHub Git database API.
135
+ *
136
+ * Uses the blob → tree → commit → ref update flow to support
137
+ * files up to 100 MB without command-line length limits.
138
+ *
139
+ * @param filePath - Absolute or relative path to the image file
140
+ * @returns UploadedAsset with the GitHub URL and markdown reference
141
+ */
142
+ async uploadImage(filePath) {
143
+ const resolvedPath = this.validateImageFile(filePath);
144
+ const filename = basename(resolvedPath);
145
+ const repo = await this.getRepo();
146
+ await this.ensureAssetsBranch();
147
+ logger.debug(`Uploading: ${filename}`);
148
+ // Read and base64-encode the file
149
+ const content = readFileSync(resolvedPath).toString('base64');
150
+ const uniqueFilename = `${Date.now()}-${filename}`;
151
+ const targetPath = `attachments/${uniqueFilename}`;
152
+ // 1. Create a blob with the file content
153
+ const blobData = await this.githubApi('post', `/repos/${repo.owner}/${repo.name}/git/blobs`, { content, encoding: 'base64' });
154
+ // 2. Get the current branch tip
155
+ const refData = await this.githubApi('get', `/repos/${repo.owner}/${repo.name}/git/refs/heads/${ASSETS_BRANCH}`);
156
+ const currentCommitSha = refData.object.sha;
157
+ const commitData = await this.githubApi('get', `/repos/${repo.owner}/${repo.name}/git/commits/${currentCommitSha}`);
158
+ // 3. Create a new tree that includes the uploaded file
159
+ const treeData = await this.githubApi('post', `/repos/${repo.owner}/${repo.name}/git/trees`, {
160
+ base_tree: commitData.tree.sha,
161
+ tree: [
162
+ {
163
+ path: targetPath,
164
+ mode: '100644',
165
+ type: 'blob',
166
+ sha: blobData.sha,
167
+ },
168
+ ],
169
+ });
170
+ // 4. Create a commit pointing to the new tree
171
+ const newCommitData = await this.githubApi('post', `/repos/${repo.owner}/${repo.name}/git/commits`, {
172
+ message: `chore: upload attachment ${filename}`,
173
+ tree: treeData.sha,
174
+ parents: [currentCommitSha],
175
+ });
176
+ // 5. Update the branch ref to the new commit
177
+ await this.githubApi('patch', `/repos/${repo.owner}/${repo.name}/git/refs/heads/${ASSETS_BRANCH}`, { sha: newCommitData.sha });
178
+ const url = `https://github.com/${repo.owner}/${repo.name}/raw/${ASSETS_BRANCH}/${targetPath}`;
179
+ return {
180
+ localPath: resolvedPath,
181
+ filename,
182
+ url,
183
+ markdown: `![${filename}](${url})`,
184
+ };
185
+ }
186
+ /**
187
+ * Upload multiple image files.
188
+ *
189
+ * @param filePaths - Array of file paths to upload
190
+ * @returns Array of UploadedAsset results (one per file)
191
+ */
192
+ async uploadImages(filePaths) {
193
+ if (filePaths.length === 0)
194
+ return [];
195
+ await this.ensureAssetsBranch();
196
+ const results = [];
197
+ for (const filePath of filePaths) {
198
+ try {
199
+ const result = await this.uploadImage(filePath);
200
+ results.push(result);
201
+ logger.success(`Uploaded: ${result.filename}`);
202
+ }
203
+ catch (error) {
204
+ logger.error(`Failed to upload ${basename(filePath)}: ${error instanceof Error ? error.message : String(error)}`);
205
+ throw error;
206
+ }
207
+ }
208
+ return results;
209
+ }
210
+ /**
211
+ * Scan a markdown body for local image references and return the
212
+ * file paths that need uploading.
213
+ *
214
+ * Detects patterns like:
215
+ * - ![alt](./screenshot.png)
216
+ * - ![alt](screenshot.png)
217
+ * - ![alt](../assets/image.jpg)
218
+ * - ![alt](/absolute/path/to/image.png)
219
+ *
220
+ * Only matches paths that:
221
+ * 1. Have a supported image extension
222
+ * 2. Do NOT start with http:// or https:// (those are already URLs)
223
+ * 3. Point to files that exist on disk
224
+ *
225
+ * @param body - The markdown content to scan
226
+ * @param basePath - The directory to resolve relative paths against
227
+ * (typically the directory containing the plan file)
228
+ * @returns Array of { match, localPath, altText } for each local image found
229
+ */
230
+ scanForLocalImages(body, basePath) {
231
+ const results = [];
232
+ // Match markdown image syntax: ![alt](path)
233
+ const imageRegex = /!\[([^\]]*)\]\(([^)]+)\)/g;
234
+ let regexMatch;
235
+ while ((regexMatch = imageRegex.exec(body)) !== null) {
236
+ const altText = regexMatch[1];
237
+ const imagePath = regexMatch[2];
238
+ // Skip URLs — those are already hosted
239
+ if (imagePath.startsWith('http://') ||
240
+ imagePath.startsWith('https://')) {
241
+ continue;
242
+ }
243
+ // Check extension
244
+ const ext = extname(imagePath).toLowerCase();
245
+ if (!SUPPORTED_IMAGE_EXTENSIONS.has(ext)) {
246
+ continue;
247
+ }
248
+ // Resolve the path relative to the plan file's directory
249
+ const resolvedPath = isAbsolute(imagePath)
250
+ ? imagePath
251
+ : resolve(basePath, imagePath);
252
+ // Only include if the file actually exists
253
+ if (existsSync(resolvedPath)) {
254
+ results.push({
255
+ match: regexMatch[0],
256
+ localPath: resolvedPath,
257
+ altText,
258
+ });
259
+ }
260
+ else {
261
+ logger.debug(`Local image not found (skipping): ${imagePath}`);
262
+ }
263
+ }
264
+ return results;
265
+ }
266
+ /**
267
+ * Process a plan body: find local image references, upload them,
268
+ * and replace the local paths with GitHub URLs.
269
+ *
270
+ * @param body - The plan markdown body
271
+ * @param basePath - Directory to resolve relative image paths against
272
+ * @returns The updated body with local image paths replaced by GitHub URLs
273
+ */
274
+ async resolveLocalImages(body, basePath) {
275
+ const localImages = this.scanForLocalImages(body, basePath);
276
+ if (localImages.length === 0) {
277
+ return body;
278
+ }
279
+ logger.info(`Found ${localImages.length} local image(s) in plan, uploading...`);
280
+ await this.ensureAssetsBranch();
281
+ let updatedBody = body;
282
+ for (const img of localImages) {
283
+ try {
284
+ const uploaded = await this.uploadImage(img.localPath);
285
+ // Replace the local reference with the uploaded URL
286
+ // Use the original alt text from the plan
287
+ const newMarkdown = `![${img.altText}](${uploaded.url})`;
288
+ updatedBody = updatedBody.replaceAll(img.match, newMarkdown);
289
+ logger.success(`Resolved: ${basename(img.localPath)} → ${ASSETS_BRANCH}`);
290
+ }
291
+ catch (error) {
292
+ logger.warning(`Could not upload ${basename(img.localPath)}: ${error instanceof Error ? error.message : String(error)}`);
293
+ // Leave the original reference in place — non-fatal
294
+ }
295
+ }
296
+ return updatedBody;
297
+ }
298
+ }
299
+ //# sourceMappingURL=AssetUploadService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetUploadService.js","sourceRoot":"","sources":["../../../src/services/github/AssetUploadService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;GAGG;AACH,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;CACR,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,aAAa,GAAG,kBAAkB,CAAC;AAgBzC;;;;;;;;;;GAUG;AACH,MAAM,OAAO,kBAAkB;IACrB,KAAK,GAAkB,IAAI,CAAC;IAC5B,QAAQ,GAA2C,IAAI,CAAC;IACxD,iBAAiB,GAAG,KAAK,CAAC;IAElC;;OAEG;IACK,KAAK,CAAC,QAAQ;QACpB,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QAClC,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,MAAM,UAAU,CAAC,eAAe,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,OAAO;QACnB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;QACxC,IAAI,CAAC,QAAQ,GAAG,MAAM,WAAW,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,SAAS,CACrB,MAAwC,EACxC,IAAY,EACZ,IAAU;QAEV,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YACrC,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,yBAAyB,IAAI,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC;YAC3B,MAAM;YACN,GAAG;YACH,IAAI;YACJ,OAAO,EAAE;gBACP,aAAa,EAAE,SAAS,KAAK,EAAE;gBAC/B,MAAM,EAAE,gCAAgC;aACzC;SACF,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,kBAAkB;QAC9B,IAAI,IAAI,CAAC,iBAAiB;YAAE,OAAO;QAEnC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,SAAS,CAClB,KAAK,EACL,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,mBAAmB,aAAa,EAAE,CACpE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnC,MAAM,CAAC,KAAK,CAAC,YAAY,aAAa,YAAY,CAAC,CAAC;gBACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CACnC,KAAK,EACL,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CACpC,CAAC;gBACF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAClC,KAAK,EACL,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,mBAAmB,QAAQ,CAAC,cAAc,EAAE,CAC9E,CAAC;gBACF,MAAM,IAAI,CAAC,SAAS,CAClB,MAAM,EACN,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,WAAW,EAC5C;oBACE,GAAG,EAAE,cAAc,aAAa,EAAE;oBAClC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG;iBACxB,CACF,CAAC;gBACF,MAAM,CAAC,KAAK,CAAC,WAAW,aAAa,SAAS,CAAC,CAAC;YAClD,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAChC,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,QAAgB;QAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAErE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5C,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CACb,0BAA0B,GAAG,KAAK,QAAQ,CAAC,QAAQ,CAAC,KAAK;gBACvD,cAAc,CAAC,GAAG,0BAA0B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7D,CAAC;QACJ,CAAC;QAED,oDAAoD;QACpD,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,YAAY,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;QAC/C,IAAI,KAAK,CAAC,IAAI,GAAG,YAAY,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,mBAAmB,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;gBACrF,wBAAwB,CAC3B,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,WAAW,CAAC,QAAgB;QAChC,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAElC,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEhC,MAAM,CAAC,KAAK,CAAC,cAAc,QAAQ,EAAE,CAAC,CAAC;QAEvC,kCAAkC;QAClC,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,cAAc,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;QACnD,MAAM,UAAU,GAAG,eAAe,cAAc,EAAE,CAAC;QAEnD,yCAAyC;QACzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CACnC,MAAM,EACN,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,YAAY,EAC7C,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAChC,CAAC;QAEF,gCAAgC;QAChC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAClC,KAAK,EACL,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,mBAAmB,aAAa,EAAE,CACpE,CAAC;QACF,MAAM,gBAAgB,GAAW,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;QAEpD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CACrC,KAAK,EACL,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,gBAAgB,gBAAgB,EAAE,CACpE,CAAC;QAEF,uDAAuD;QACvD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CACnC,MAAM,EACN,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,YAAY,EAC7C;YACE,SAAS,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG;YAC9B,IAAI,EAAE;gBACJ;oBACE,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,MAAM;oBACZ,GAAG,EAAE,QAAQ,CAAC,GAAG;iBAClB;aACF;SACF,CACF,CAAC;QAEF,8CAA8C;QAC9C,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,SAAS,CACxC,MAAM,EACN,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,cAAc,EAC/C;YACE,OAAO,EAAE,4BAA4B,QAAQ,EAAE;YAC/C,IAAI,EAAE,QAAQ,CAAC,GAAG;YAClB,OAAO,EAAE,CAAC,gBAAgB,CAAC;SAC5B,CACF,CAAC;QAEF,6CAA6C;QAC7C,MAAM,IAAI,CAAC,SAAS,CAClB,OAAO,EACP,UAAU,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,mBAAmB,aAAa,EAAE,EACnE,EAAE,GAAG,EAAE,aAAa,CAAC,GAAG,EAAE,CAC3B,CAAC;QAEF,MAAM,GAAG,GAAG,sBAAsB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,QAAQ,aAAa,IAAI,UAAU,EAAE,CAAC;QAE/F,OAAO;YACL,SAAS,EAAE,YAAY;YACvB,QAAQ;YACR,GAAG;YACH,QAAQ,EAAE,KAAK,QAAQ,KAAK,GAAG,GAAG;SACnC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,SAAmB;QACpC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEtC,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEhC,MAAM,OAAO,GAAoB,EAAE,CAAC;QAEpC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACrB,MAAM,CAAC,OAAO,CAAC,aAAa,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CACV,oBAAoB,QAAQ,CAAC,QAAQ,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACpG,CAAC;gBACF,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,kBAAkB,CAChB,IAAY,EACZ,QAAgB;QAEhB,MAAM,OAAO,GAIR,EAAE,CAAC;QAER,4CAA4C;QAC5C,MAAM,UAAU,GAAG,2BAA2B,CAAC;QAC/C,IAAI,UAAkC,CAAC;QAEvC,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACrD,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;YAEjC,uCAAuC;YACvC,IACE,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC;gBAC/B,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,EAChC,CAAC;gBACD,SAAS;YACX,CAAC;YAED,kBAAkB;YAClB,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;YAC7C,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,SAAS;YACX,CAAC;YAED,yDAAyD;YACzD,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC;gBACxC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAEjC,2CAA2C;YAC3C,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC;oBACX,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;oBACpB,SAAS,EAAE,YAAY;oBACvB,OAAO;iBACR,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,qCAAqC,SAAS,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,kBAAkB,CAAC,IAAY,EAAE,QAAgB;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE5D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,CAAC,IAAI,CACT,SAAS,WAAW,CAAC,MAAM,uCAAuC,CACnE,CAAC;QACF,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEhC,IAAI,WAAW,GAAG,IAAI,CAAC;QAEvB,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACvD,oDAAoD;gBACpD,0CAA0C;gBAC1C,MAAM,WAAW,GAAG,KAAK,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,GAAG,GAAG,CAAC;gBACzD,WAAW,GAAG,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;gBAC7D,MAAM,CAAC,OAAO,CACZ,aAAa,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,aAAa,EAAE,CAC1D,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,OAAO,CACZ,oBAAoB,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACzG,CAAC;gBACF,oDAAoD;YACtD,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF"}