@ipul-labs/forge 1.16.7 → 1.17.0

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 (280) hide show
  1. package/README.md +58 -21
  2. package/lib/bin/cli/analyze.d.ts +9 -0
  3. package/lib/bin/cli/analyze.d.ts.map +1 -0
  4. package/lib/bin/cli/analyze.js +491 -0
  5. package/lib/bin/cli/analyze.js.map +1 -0
  6. package/lib/bin/cli/apply.d.ts +2 -0
  7. package/lib/bin/cli/apply.d.ts.map +1 -0
  8. package/lib/bin/cli/apply.js +262 -0
  9. package/lib/bin/cli/apply.js.map +1 -0
  10. package/lib/bin/cli/cifix.d.ts +2 -0
  11. package/lib/bin/cli/cifix.d.ts.map +1 -0
  12. package/lib/bin/cli/cifix.js +310 -0
  13. package/lib/bin/cli/cifix.js.map +1 -0
  14. package/lib/bin/cli/close.d.ts +2 -0
  15. package/lib/bin/cli/close.d.ts.map +1 -0
  16. package/lib/bin/cli/close.js +113 -0
  17. package/lib/bin/cli/close.js.map +1 -0
  18. package/lib/bin/cli/createIssue.d.ts +2 -0
  19. package/lib/bin/cli/createIssue.d.ts.map +1 -0
  20. package/lib/bin/cli/createIssue.js +108 -0
  21. package/lib/bin/cli/createIssue.js.map +1 -0
  22. package/lib/bin/cli/doctor.d.ts +2 -0
  23. package/lib/bin/cli/doctor.d.ts.map +1 -0
  24. package/lib/bin/cli/doctor.js +145 -0
  25. package/lib/bin/cli/doctor.js.map +1 -0
  26. package/lib/bin/cli/init.d.ts +4 -0
  27. package/lib/bin/cli/init.d.ts.map +1 -0
  28. package/lib/bin/cli/init.js +288 -0
  29. package/lib/bin/cli/init.js.map +1 -0
  30. package/lib/bin/cli/ink.d.ts +23 -0
  31. package/lib/bin/cli/ink.d.ts.map +1 -0
  32. package/{bin → lib/bin}/cli/ink.js +18 -19
  33. package/lib/bin/cli/ink.js.map +1 -0
  34. package/lib/bin/cli/issue.d.ts +2 -0
  35. package/lib/bin/cli/issue.d.ts.map +1 -0
  36. package/lib/bin/cli/issue.js +114 -0
  37. package/lib/bin/cli/issue.js.map +1 -0
  38. package/lib/bin/cli/issues.d.ts +2 -0
  39. package/lib/bin/cli/issues.d.ts.map +1 -0
  40. package/lib/bin/cli/issues.js +149 -0
  41. package/lib/bin/cli/issues.js.map +1 -0
  42. package/lib/bin/cli/merge.d.ts +2 -0
  43. package/lib/bin/cli/merge.d.ts.map +1 -0
  44. package/lib/bin/cli/merge.js +162 -0
  45. package/lib/bin/cli/merge.js.map +1 -0
  46. package/lib/bin/cli/refine.d.ts +2 -0
  47. package/lib/bin/cli/refine.d.ts.map +1 -0
  48. package/lib/bin/cli/refine.js +249 -0
  49. package/lib/bin/cli/refine.js.map +1 -0
  50. package/lib/bin/cli/repl.d.ts +2 -0
  51. package/lib/bin/cli/repl.d.ts.map +1 -0
  52. package/lib/bin/cli/repl.js +309 -0
  53. package/lib/bin/cli/repl.js.map +1 -0
  54. package/lib/bin/cli/repos.d.ts +2 -0
  55. package/lib/bin/cli/repos.d.ts.map +1 -0
  56. package/lib/bin/cli/repos.js +86 -0
  57. package/lib/bin/cli/repos.js.map +1 -0
  58. package/lib/bin/cli/resolution.d.ts +2 -0
  59. package/lib/bin/cli/resolution.d.ts.map +1 -0
  60. package/lib/bin/cli/resolution.js +139 -0
  61. package/lib/bin/cli/resolution.js.map +1 -0
  62. package/lib/bin/cli/serverClient.d.ts +26 -0
  63. package/lib/bin/cli/serverClient.d.ts.map +1 -0
  64. package/lib/bin/cli/serverClient.js +111 -0
  65. package/lib/bin/cli/serverClient.js.map +1 -0
  66. package/lib/bin/cli/session.d.ts +8 -0
  67. package/lib/bin/cli/session.d.ts.map +1 -0
  68. package/lib/bin/cli/session.js +212 -0
  69. package/lib/bin/cli/session.js.map +1 -0
  70. package/lib/bin/cli/sessionStore.d.ts +69 -0
  71. package/lib/bin/cli/sessionStore.d.ts.map +1 -0
  72. package/lib/bin/cli/sessionStore.js +196 -0
  73. package/lib/bin/cli/sessionStore.js.map +1 -0
  74. package/lib/bin/cli/ship.d.ts +33 -0
  75. package/lib/bin/cli/ship.d.ts.map +1 -0
  76. package/lib/bin/cli/ship.js +737 -0
  77. package/lib/bin/cli/ship.js.map +1 -0
  78. package/lib/bin/cli/types.d.ts +59 -0
  79. package/lib/bin/cli/types.d.ts.map +1 -0
  80. package/lib/bin/cli/types.js +2 -0
  81. package/lib/bin/cli/types.js.map +1 -0
  82. package/lib/bin/cli/update.d.ts +2 -0
  83. package/lib/bin/cli/update.d.ts.map +1 -0
  84. package/lib/bin/cli/update.js +87 -0
  85. package/lib/bin/cli/update.js.map +1 -0
  86. package/lib/bin/cli/utils.d.ts +43 -0
  87. package/lib/bin/cli/utils.d.ts.map +1 -0
  88. package/lib/bin/cli/utils.js +171 -0
  89. package/lib/bin/cli/utils.js.map +1 -0
  90. package/lib/bin/cli/validate.d.ts +2 -0
  91. package/lib/bin/cli/validate.d.ts.map +1 -0
  92. package/lib/bin/cli/validate.js +283 -0
  93. package/lib/bin/cli/validate.js.map +1 -0
  94. package/lib/bin/cli/watch.d.ts +5 -0
  95. package/lib/bin/cli/watch.d.ts.map +1 -0
  96. package/lib/bin/cli/watch.js +263 -0
  97. package/lib/bin/cli/watch.js.map +1 -0
  98. package/lib/bin/forge-agent.d.ts +3 -0
  99. package/lib/bin/forge-agent.d.ts.map +1 -0
  100. package/{bin → lib/bin}/forge-agent.js +104 -105
  101. package/lib/bin/forge-agent.js.map +1 -0
  102. package/lib/server/forge/core/ForgeAgent.d.ts +260 -0
  103. package/lib/server/forge/core/ForgeAgent.d.ts.map +1 -0
  104. package/lib/server/forge/core/ForgeAgent.js +995 -0
  105. package/lib/server/forge/core/ForgeAgent.js.map +1 -0
  106. package/lib/server/forge/core/agentClient.d.ts +39 -0
  107. package/lib/server/forge/core/agentClient.d.ts.map +1 -0
  108. package/{server → lib/server}/forge/core/agentClient.js +7 -12
  109. package/lib/server/forge/core/agentClient.js.map +1 -0
  110. package/lib/server/forge/core/branchName.d.ts +20 -0
  111. package/lib/server/forge/core/branchName.d.ts.map +1 -0
  112. package/lib/server/forge/core/branchName.js +39 -0
  113. package/lib/server/forge/core/branchName.js.map +1 -0
  114. package/lib/server/forge/core/claudeClient.d.ts +60 -0
  115. package/lib/server/forge/core/claudeClient.d.ts.map +1 -0
  116. package/lib/server/forge/core/claudeClient.js +347 -0
  117. package/lib/server/forge/core/claudeClient.js.map +1 -0
  118. package/lib/server/forge/core/configStore.d.ts +76 -0
  119. package/lib/server/forge/core/configStore.d.ts.map +1 -0
  120. package/lib/server/forge/core/configStore.js +213 -0
  121. package/lib/server/forge/core/configStore.js.map +1 -0
  122. package/lib/server/forge/core/gitlabClient.d.ts +144 -0
  123. package/lib/server/forge/core/gitlabClient.d.ts.map +1 -0
  124. package/{server → lib/server}/forge/core/gitlabClient.js +98 -180
  125. package/lib/server/forge/core/gitlabClient.js.map +1 -0
  126. package/lib/server/forge/core/jobs.d.ts +67 -0
  127. package/lib/server/forge/core/jobs.d.ts.map +1 -0
  128. package/lib/server/forge/core/jobs.js +185 -0
  129. package/lib/server/forge/core/jobs.js.map +1 -0
  130. package/lib/server/forge/core/k8s.d.ts +18 -0
  131. package/lib/server/forge/core/k8s.d.ts.map +1 -0
  132. package/lib/server/forge/core/k8s.js +49 -0
  133. package/lib/server/forge/core/k8s.js.map +1 -0
  134. package/lib/server/forge/core/localRepo.d.ts +36 -0
  135. package/lib/server/forge/core/localRepo.d.ts.map +1 -0
  136. package/lib/server/forge/core/localRepo.js +165 -0
  137. package/lib/server/forge/core/localRepo.js.map +1 -0
  138. package/lib/server/forge/core/openclawClient.d.ts +61 -0
  139. package/lib/server/forge/core/openclawClient.d.ts.map +1 -0
  140. package/lib/server/forge/core/openclawClient.js +111 -0
  141. package/lib/server/forge/core/openclawClient.js.map +1 -0
  142. package/lib/server/forge/core/prompts.d.ts +96 -0
  143. package/lib/server/forge/core/prompts.d.ts.map +1 -0
  144. package/lib/server/forge/core/prompts.js +450 -0
  145. package/lib/server/forge/core/prompts.js.map +1 -0
  146. package/lib/server/forge/core/providers/azuredevops.d.ts +134 -0
  147. package/lib/server/forge/core/providers/azuredevops.d.ts.map +1 -0
  148. package/lib/server/forge/core/providers/azuredevops.js +360 -0
  149. package/lib/server/forge/core/providers/azuredevops.js.map +1 -0
  150. package/lib/server/forge/core/providers/base.d.ts +114 -0
  151. package/lib/server/forge/core/providers/base.d.ts.map +1 -0
  152. package/lib/server/forge/core/providers/base.js +98 -0
  153. package/lib/server/forge/core/providers/base.js.map +1 -0
  154. package/lib/server/forge/core/providers/github.d.ts +133 -0
  155. package/lib/server/forge/core/providers/github.d.ts.map +1 -0
  156. package/lib/server/forge/core/providers/github.js +307 -0
  157. package/lib/server/forge/core/providers/github.js.map +1 -0
  158. package/lib/server/forge/core/providers/gitlab.d.ts +144 -0
  159. package/lib/server/forge/core/providers/gitlab.d.ts.map +1 -0
  160. package/lib/server/forge/core/providers/gitlab.js +407 -0
  161. package/lib/server/forge/core/providers/gitlab.js.map +1 -0
  162. package/lib/server/forge/core/providers/index.d.ts +21 -0
  163. package/lib/server/forge/core/providers/index.d.ts.map +1 -0
  164. package/lib/server/forge/core/providers/index.js +43 -0
  165. package/lib/server/forge/core/providers/index.js.map +1 -0
  166. package/lib/server/forge/core/providers/types.d.ts +80 -0
  167. package/lib/server/forge/core/providers/types.d.ts.map +1 -0
  168. package/lib/server/forge/core/providers/types.js +2 -0
  169. package/lib/server/forge/core/providers/types.js.map +1 -0
  170. package/lib/server/forge/core/quotaClient.d.ts +48 -0
  171. package/lib/server/forge/core/quotaClient.d.ts.map +1 -0
  172. package/lib/server/forge/core/quotaClient.js +88 -0
  173. package/lib/server/forge/core/quotaClient.js.map +1 -0
  174. package/lib/server/forge/core/types.d.ts +160 -0
  175. package/lib/server/forge/core/types.d.ts.map +1 -0
  176. package/lib/server/forge/core/types.js +2 -0
  177. package/lib/server/forge/core/types.js.map +1 -0
  178. package/lib/server/forge/core/validator/attribute.d.ts +31 -0
  179. package/lib/server/forge/core/validator/attribute.d.ts.map +1 -0
  180. package/lib/server/forge/core/validator/attribute.js +82 -0
  181. package/lib/server/forge/core/validator/attribute.js.map +1 -0
  182. package/lib/server/forge/core/validator/clone.d.ts +14 -0
  183. package/lib/server/forge/core/validator/clone.d.ts.map +1 -0
  184. package/lib/server/forge/core/validator/clone.js +99 -0
  185. package/lib/server/forge/core/validator/clone.js.map +1 -0
  186. package/lib/server/forge/core/validator/cmd.d.ts +23 -0
  187. package/lib/server/forge/core/validator/cmd.d.ts.map +1 -0
  188. package/lib/server/forge/core/validator/cmd.js +87 -0
  189. package/lib/server/forge/core/validator/cmd.js.map +1 -0
  190. package/lib/server/forge/core/validator/fs.d.ts +5 -0
  191. package/lib/server/forge/core/validator/fs.d.ts.map +1 -0
  192. package/{server → lib/server}/forge/core/validator/fs.js +8 -3
  193. package/lib/server/forge/core/validator/fs.js.map +1 -0
  194. package/lib/server/forge/core/validator/overlay.d.ts +13 -0
  195. package/lib/server/forge/core/validator/overlay.d.ts.map +1 -0
  196. package/lib/server/forge/core/validator/overlay.js +53 -0
  197. package/lib/server/forge/core/validator/overlay.js.map +1 -0
  198. package/lib/server/forge/core/validator/projectType.d.ts +20 -0
  199. package/lib/server/forge/core/validator/projectType.d.ts.map +1 -0
  200. package/lib/server/forge/core/validator/projectType.js +94 -0
  201. package/lib/server/forge/core/validator/projectType.js.map +1 -0
  202. package/lib/server/forge/core/validator/runners/go.d.ts +21 -0
  203. package/lib/server/forge/core/validator/runners/go.d.ts.map +1 -0
  204. package/lib/server/forge/core/validator/runners/go.js +99 -0
  205. package/lib/server/forge/core/validator/runners/go.js.map +1 -0
  206. package/lib/server/forge/core/validator/runners/node.d.ts +12 -0
  207. package/lib/server/forge/core/validator/runners/node.d.ts.map +1 -0
  208. package/lib/server/forge/core/validator/runners/node.js +75 -0
  209. package/lib/server/forge/core/validator/runners/node.js.map +1 -0
  210. package/lib/server/forge/core/validator/tdd.d.ts +30 -0
  211. package/lib/server/forge/core/validator/tdd.d.ts.map +1 -0
  212. package/lib/server/forge/core/validator/tdd.js +96 -0
  213. package/lib/server/forge/core/validator/tdd.js.map +1 -0
  214. package/lib/server/forge/core/validator.d.ts +58 -0
  215. package/lib/server/forge/core/validator.d.ts.map +1 -0
  216. package/lib/server/forge/core/validator.js +150 -0
  217. package/lib/server/forge/core/validator.js.map +1 -0
  218. package/lib/server/forge/routes.d.ts +22 -0
  219. package/lib/server/forge/routes.d.ts.map +1 -0
  220. package/lib/server/forge/routes.js +984 -0
  221. package/lib/server/forge/routes.js.map +1 -0
  222. package/lib/server.d.ts +2 -0
  223. package/lib/server.d.ts.map +1 -0
  224. package/lib/server.js +52 -0
  225. package/lib/server.js.map +1 -0
  226. package/lib/shared/events.d.ts +12 -0
  227. package/lib/shared/events.d.ts.map +1 -0
  228. package/lib/shared/events.js +12 -0
  229. package/lib/shared/events.js.map +1 -0
  230. package/package.json +17 -13
  231. package/scripts/fix-shebang.cjs +10 -0
  232. package/bin/cli/analyze.js +0 -516
  233. package/bin/cli/apply.js +0 -264
  234. package/bin/cli/cifix.js +0 -300
  235. package/bin/cli/close.js +0 -125
  236. package/bin/cli/createIssue.js +0 -112
  237. package/bin/cli/doctor.js +0 -161
  238. package/bin/cli/init.js +0 -306
  239. package/bin/cli/issue.js +0 -116
  240. package/bin/cli/issues.js +0 -155
  241. package/bin/cli/merge.js +0 -175
  242. package/bin/cli/refine.js +0 -253
  243. package/bin/cli/repl.js +0 -301
  244. package/bin/cli/repos.js +0 -91
  245. package/bin/cli/resolution.js +0 -126
  246. package/bin/cli/session.js +0 -230
  247. package/bin/cli/sessionStore.js +0 -211
  248. package/bin/cli/ship.js +0 -762
  249. package/bin/cli/update.js +0 -95
  250. package/bin/cli/utils.js +0 -145
  251. package/bin/cli/validate.js +0 -280
  252. package/bin/cli/watch.js +0 -274
  253. package/server/forge/core/ForgeAgent.js +0 -1179
  254. package/server/forge/core/ForgeAgent.test.js +0 -179
  255. package/server/forge/core/branchName.js +0 -41
  256. package/server/forge/core/claudeClient.js +0 -378
  257. package/server/forge/core/configStore.js +0 -229
  258. package/server/forge/core/configStore.test.js +0 -89
  259. package/server/forge/core/jobs.js +0 -180
  260. package/server/forge/core/k8s.js +0 -54
  261. package/server/forge/core/localRepo.js +0 -153
  262. package/server/forge/core/openclawClient.js +0 -125
  263. package/server/forge/core/prompts.js +0 -483
  264. package/server/forge/core/prompts.test.js +0 -219
  265. package/server/forge/core/providers/azuredevops.js +0 -409
  266. package/server/forge/core/providers/base.js +0 -208
  267. package/server/forge/core/providers/github.js +0 -348
  268. package/server/forge/core/providers/gitlab.js +0 -529
  269. package/server/forge/core/providers/index.js +0 -47
  270. package/server/forge/core/quotaClient.js +0 -101
  271. package/server/forge/core/validator/attribute.js +0 -84
  272. package/server/forge/core/validator/clone.js +0 -105
  273. package/server/forge/core/validator/cmd.js +0 -98
  274. package/server/forge/core/validator/overlay.js +0 -52
  275. package/server/forge/core/validator/projectType.js +0 -87
  276. package/server/forge/core/validator/runners/go.js +0 -107
  277. package/server/forge/core/validator/runners/node.js +0 -84
  278. package/server/forge/core/validator/tdd.js +0 -105
  279. package/server/forge/core/validator.js +0 -167
  280. package/server/forge/routes.js +0 -1026
package/bin/cli/watch.js DELETED
@@ -1,274 +0,0 @@
1
- import path from "node:path";
2
- import React, { useEffect, useState } from "react";
3
- import Spinner from "ink-spinner";
4
- import { h, Box, Text, useApp, runApp } from "./ink.js";
5
- import { getFlag, projectRoot } from "./utils.js";
6
- import {
7
- PHASES,
8
- appendEvent,
9
- readState,
10
- resolveSessionTarget,
11
- updateState,
12
- } from "./sessionStore.js";
13
-
14
- const POLL_MS = 5000;
15
- const TERMINAL_PIPELINE = new Set([
16
- "success",
17
- "failed",
18
- "canceled",
19
- "skipped",
20
- "manual",
21
- ]);
22
- const TERMINAL_JOB = new Set([
23
- "success",
24
- "failed",
25
- "canceled",
26
- "skipped",
27
- "manual",
28
- ]);
29
-
30
- function jobStatusIcon(status) {
31
- if (status === "success") return { glyph: "✓", color: "green" };
32
- if (status === "failed") return { glyph: "✘", color: "red" };
33
- if (status === "canceled" || status === "skipped") return { glyph: "○", color: "gray" };
34
- if (status === "manual") return { glyph: "▶", color: "yellow" };
35
- if (status === "running") return { glyph: "●", color: "cyan" };
36
- if (status === "pending" || status === "created" || status === "scheduled")
37
- return { glyph: "·", color: "yellow" };
38
- return { glyph: "?", color: undefined };
39
- }
40
-
41
- function pipelineStatusColor(status) {
42
- if (status === "success") return "green";
43
- if (status === "failed") return "red";
44
- if (status === "running" || status === "pending") return "cyan";
45
- if (status === "canceled" || status === "skipped") return "gray";
46
- return undefined;
47
- }
48
-
49
- function fmtDuration(s) {
50
- if (s == null) return "";
51
- if (s < 60) return `${Math.round(s)}s`;
52
- const m = Math.floor(s / 60);
53
- const r = Math.round(s - m * 60);
54
- return `${m}m${r > 0 ? `${r}s` : ""}`;
55
- }
56
-
57
- function PipelineRow({ pipeline }) {
58
- if (!pipeline) {
59
- return h`<${Box}>
60
- <${Text} color="cyan"><${Spinner} type="dots"/></>
61
- <${Text}> Waiting for pipeline to start…</>
62
- </>`;
63
- }
64
- const color = pipelineStatusColor(pipeline.status);
65
- return h`<${Box}>
66
- <${Text}>Pipeline </>
67
- <${Text} dimColor>#${pipeline.id} </>
68
- <${Text} color=${color} bold>${pipeline.status.padEnd(8)}</>
69
- ${pipeline.web_url ? h`<${Text} dimColor> ${pipeline.web_url}</>` : null}
70
- </>`;
71
- }
72
-
73
- function JobsTable({ jobs }) {
74
- if (!jobs?.length) return null;
75
- const stages = [...new Set(jobs.map((j) => j.stage ?? "(no-stage)"))];
76
- return h`<${Box} flexDirection="column" marginTop=${1}>
77
- ${stages.map((stage, si) =>
78
- h`<${Box} flexDirection="column" key=${si}>
79
- <${Text} dimColor>${stage}</>
80
- ${jobs
81
- .filter((j) => (j.stage ?? "(no-stage)") === stage)
82
- .map((j, ji) => {
83
- const { glyph, color } = jobStatusIcon(j.status);
84
- return h`<${Box} key=${ji} marginLeft=${2}>
85
- <${Text} color=${color}>${glyph}</>
86
- <${Text}> ${j.name.padEnd(28)}</>
87
- <${Text} color=${color}>${j.status.padEnd(10)}</>
88
- <${Text} dimColor>${fmtDuration(j.duration)}</>
89
- </>`;
90
- })}
91
- </>`,
92
- )}
93
- </>`;
94
- }
95
-
96
- function WatchView({ repo, mrIid, onDone }) {
97
- const { exit } = useApp();
98
- const [pipeline, setPipeline] = useState(null);
99
- const [jobs, setJobs] = useState([]);
100
- const [error, setError] = useState(null);
101
- const [tick, setTick] = useState(0);
102
- const [done, setDone] = useState(null);
103
-
104
- useEffect(() => {
105
- if (!done) return;
106
- onDone(done);
107
- exit();
108
- }, [done]);
109
-
110
- useEffect(() => {
111
- let cancelled = false;
112
- let timer;
113
-
114
- (async () => {
115
- try {
116
- const { createProvider } = await import(
117
- path.join(projectRoot, "server/forge/core/providers/index.js")
118
- );
119
- const provider = createProvider(repo);
120
-
121
- const poll = async () => {
122
- if (cancelled) return;
123
- try {
124
- const pipelines = await provider.getMRPipelines(mrIid);
125
- if (!pipelines?.length) {
126
- setPipeline(null);
127
- setJobs([]);
128
- } else {
129
- const latest = pipelines[0];
130
- const [pipe, list] = await Promise.all([
131
- provider.getPipeline(latest.id),
132
- provider.getPipelineJobs(latest.id),
133
- ]);
134
- if (cancelled) return;
135
- setPipeline(pipe);
136
- setJobs(list);
137
- if (TERMINAL_PIPELINE.has(pipe.status)) {
138
- setDone({ ok: true, pipeline: pipe, jobs: list });
139
- return;
140
- }
141
- }
142
- } catch (err) {
143
- if (cancelled) return;
144
- setError(err.message ?? String(err));
145
- }
146
- setTick((t) => t + 1);
147
- timer = setTimeout(poll, POLL_MS);
148
- };
149
-
150
- await poll();
151
- } catch (err) {
152
- if (cancelled) return;
153
- setDone({ ok: false, error: err });
154
- }
155
- })();
156
-
157
- return () => {
158
- cancelled = true;
159
- if (timer) clearTimeout(timer);
160
- };
161
- }, []);
162
-
163
- return h`<${Box} flexDirection="column">
164
- <${Box}>
165
- <${Text} color="yellow">Watching </>
166
- <${Text}>${repo} !${mrIid}</>
167
- <${Text} dimColor>${` (poll #${tick + 1}, every ${POLL_MS / 1000}s)`}</>
168
- </>
169
- <${Box} marginTop=${1}><${PipelineRow} pipeline=${pipeline} /></>
170
- <${JobsTable} jobs=${jobs} />
171
- ${error ? h`<${Box} marginTop=${1}><${Text} color="red">${error}</></>` : null}
172
- ${done?.ok
173
- ? h`<${Box} marginTop=${1}>
174
- <${Text} color=${pipelineStatusColor(done.pipeline.status)}>
175
- ${`Pipeline finished: ${done.pipeline.status}`}
176
- </>
177
- </>`
178
- : null}
179
- </>`;
180
- }
181
-
182
- export async function cmdWatch(argv) {
183
- const json = argv.includes("--json");
184
- const explicitIid = Number(argv[1]);
185
- const explicitRepo = getFlag(argv, "--repo");
186
- const explicitMr = Number(getFlag(argv, "--mr"));
187
-
188
- let repo;
189
- let mrIid;
190
-
191
- if (Number.isInteger(explicitMr) && explicitMr > 0) {
192
- repo = explicitRepo;
193
- mrIid = explicitMr;
194
- } else {
195
- const target = await resolveSessionTarget({
196
- explicitIid:
197
- Number.isInteger(explicitIid) && explicitIid > 0 ? explicitIid : null,
198
- explicitRepo,
199
- });
200
- if (!target?.repo || !target?.iid) {
201
- console.error(
202
- "No session target. Pass --mr <iid> --repo <repo>, or run analyze + apply first.",
203
- );
204
- process.exit(1);
205
- }
206
- const state = await readState(target.repo, target.iid);
207
- if (!state?.mrIid) {
208
- console.error(
209
- `Session ${target.repo}#${target.iid} has no MR yet. Run: forge apply ${target.iid}`,
210
- );
211
- process.exit(1);
212
- }
213
- repo = state.primary ?? target.repo;
214
- mrIid = state.mrIid;
215
- }
216
-
217
- if (!repo) {
218
- console.error("Repo is required: pass --repo <id>");
219
- process.exit(1);
220
- }
221
-
222
- if (json) {
223
- const { createProvider } = await import(
224
- path.join(projectRoot, "server/forge/core/providers/index.js")
225
- );
226
- const provider = createProvider(repo);
227
- while (true) {
228
- const pipelines = await provider.getMRPipelines(mrIid).catch((err) => {
229
- process.stdout.write(JSON.stringify({ type: "error", message: err.message }) + "\n");
230
- return null;
231
- });
232
- if (!pipelines?.length) {
233
- process.stdout.write(JSON.stringify({ type: "tick", pipeline: null }) + "\n");
234
- } else {
235
- const latest = pipelines[0];
236
- const [pipe, list] = await Promise.all([
237
- provider.getPipeline(latest.id),
238
- provider.getPipelineJobs(latest.id),
239
- ]);
240
- process.stdout.write(
241
- JSON.stringify({ type: "tick", pipeline: pipe, jobs: list }) + "\n",
242
- );
243
- if (TERMINAL_PIPELINE.has(pipe.status)) {
244
- process.exit(pipe.status === "success" ? 0 : 2);
245
- }
246
- }
247
- await new Promise((r) => setTimeout(r, POLL_MS));
248
- }
249
- }
250
-
251
- let outcome = { ok: false };
252
- await runApp(
253
- h`<${WatchView}
254
- repo=${repo}
255
- mrIid=${mrIid}
256
- onDone=${(o) => (outcome = o)} />`,
257
- );
258
-
259
- // Persist last pipeline state if we have a session
260
- if (Number.isInteger(explicitIid) && explicitIid > 0 && explicitRepo) {
261
- await updateState(explicitRepo, explicitIid, {
262
- lastPipelineStatus: outcome.pipeline?.status ?? null,
263
- lastPipelineUrl: outcome.pipeline?.web_url ?? null,
264
- }).catch(() => {});
265
- await appendEvent(explicitRepo, explicitIid, {
266
- type: "session:watch-end",
267
- status: outcome.pipeline?.status,
268
- }).catch(() => {});
269
- }
270
-
271
- if (!outcome.ok || outcome.pipeline?.status !== "success") process.exit(2);
272
- }
273
-
274
- export { TERMINAL_PIPELINE, TERMINAL_JOB };