@ipul-labs/forge 1.16.8 → 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 +39 -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 +15 -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 -163
  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 -116
  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 -1027
package/bin/cli/repl.js DELETED
@@ -1,301 +0,0 @@
1
- import readline from "node:readline";
2
- import { execSync } from "node:child_process";
3
- import path from "node:path";
4
- import { projectRoot, readPkg, resolvePrimaryRepo, relativeAge } from "./utils.js";
5
- import { getHead, readState, listSessions } from "./sessionStore.js";
6
-
7
- const COMMANDS = [
8
- "ship", "init", "start", "repos", "issues", "issue", "create-issue",
9
- "analyze", "show", "refine", "validate", "apply", "watch",
10
- "ci-fix", "merge", "resolution-check", "close",
11
- "session", "doctor", "update", "use", "status", "open", "log",
12
- "version", "help", "exit", "quit", "clear",
13
- ];
14
-
15
- class ExitInterrupt extends Error {
16
- constructor(code) {
17
- super();
18
- this.code = code;
19
- }
20
- }
21
-
22
- const DIM = "\x1b[2m";
23
- const RESET = "\x1b[0m";
24
- const BOLD = "\x1b[1m";
25
- const YELLOW = "\x1b[33m";
26
- const GREEN = "\x1b[32m";
27
- const CYAN = "\x1b[36m";
28
-
29
- function cols() {
30
- return process.stdout.columns || 80;
31
- }
32
-
33
- function bar() {
34
- return DIM + "─".repeat(cols()) + RESET;
35
- }
36
-
37
- async function resolveContext() {
38
- let repo = null;
39
- let agent = "claude";
40
- try {
41
- repo = await resolvePrimaryRepo([]);
42
- } catch {}
43
- try {
44
- const { get } = await import(
45
- path.join(projectRoot, "server/forge/core/configStore.js")
46
- );
47
- const cfg = get();
48
- agent = cfg?.defaults?.agent || "claude";
49
- } catch {}
50
- return { repo, agent };
51
- }
52
-
53
- async function getConfiguredRepos() {
54
- try {
55
- const { get } = await import(
56
- path.join(projectRoot, "server/forge/core/configStore.js")
57
- );
58
- return (get().repos ?? []).map((r) => r.id);
59
- } catch {
60
- return [];
61
- }
62
- }
63
-
64
- async function switchRepo(repoId) {
65
- const { get, patch } = await import(
66
- path.join(projectRoot, "server/forge/core/configStore.js")
67
- );
68
- const repos = get().repos ?? [];
69
- const target = repos.find((r) => r.id === repoId);
70
- if (!target) {
71
- console.error(`Not configured: ${repoId}`);
72
- console.error(`Add it first: repos add ${repoId}`);
73
- return null;
74
- }
75
- const rest = repos.filter((r) => r.id !== repoId);
76
- await patch({ repos: [target, ...rest] });
77
- return repoId;
78
- }
79
-
80
- export async function startRepl(dispatch) {
81
- const pkg = await readPkg();
82
- const tty = process.stdout.isTTY;
83
- const ctx = await resolveContext();
84
-
85
- if (tty) {
86
- process.stdout.write(
87
- `\n ${BOLD}forge${RESET} ${DIM}v${pkg.version}${RESET}\n\n`,
88
- );
89
- }
90
-
91
- function footerText() {
92
- const parts = [];
93
- if (ctx.repo) parts.push(`${YELLOW}${ctx.repo}${RESET}`);
94
- parts.push(`${DIM}agent:${RESET}${ctx.agent}`);
95
- parts.push(`${DIM}v${pkg.version}${RESET}`);
96
- return ` ${parts.join(` ${DIM}|${RESET} `)}`;
97
- }
98
-
99
- // Draw top bar, then let readline show its simple prompt,
100
- // then draw bottom bar + footer below and move cursor back up.
101
- // This keeps readline's prompt short so cursor positioning works.
102
- function showPrompt() {
103
- if (tty) {
104
- process.stdout.write(bar() + "\n");
105
- }
106
- rl.prompt();
107
- if (tty) {
108
- process.stdout.write(
109
- "\n" + bar() + "\n" + footerText() +
110
- "\x1b[2A\x1b[4G",
111
- );
112
- }
113
- }
114
-
115
- function clearFrame() {
116
- if (!tty) return;
117
- process.stdout.write("\x1b[0J");
118
- }
119
-
120
- const prompt = tty ? ` ${DIM}❯${RESET} ` : "forge> ";
121
-
122
- const rl = readline.createInterface({
123
- input: process.stdin,
124
- output: process.stdout,
125
- prompt,
126
- completer: (line) => {
127
- const hits = COMMANDS.filter((c) => c.startsWith(line.trim()));
128
- return [hits.length ? hits : COMMANDS, line];
129
- },
130
- terminal: tty,
131
- });
132
-
133
- showPrompt();
134
-
135
- for await (const line of rl) {
136
- const trimmed = line.trim();
137
-
138
- if (!trimmed) {
139
- showPrompt();
140
- continue;
141
- }
142
-
143
- clearFrame();
144
-
145
- if (trimmed === "exit" || trimmed === "quit") {
146
- if (tty) process.stdout.write(`\n ${DIM}Session ended.${RESET}\n\n`);
147
- rl.close();
148
- return;
149
- }
150
-
151
- if (trimmed === "clear") {
152
- if (tty) process.stdout.write("\x1b[2J\x1b[H");
153
- showPrompt();
154
- continue;
155
- }
156
-
157
- const argv = parseInput(trimmed);
158
-
159
- if (argv[0] === "status") {
160
- process.stdout.write("\n");
161
- const head = await getHead();
162
- if (!head) {
163
- process.stdout.write(`${DIM}No active session. Run: analyze <iid>${RESET}\n`);
164
- } else {
165
- const state = await readState(head.repo, head.iid);
166
- if (!state) {
167
- process.stdout.write(`${DIM}Session ${head.repo}#${head.iid} — no state${RESET}\n`);
168
- } else {
169
- process.stdout.write(`${YELLOW}${state.repo || head.repo}${RESET} ${BOLD}#${state.iid || head.iid}${RESET}\n`);
170
- process.stdout.write(`${DIM}phase${RESET} ${state.phase || "unknown"}\n`);
171
- if (state.branch) process.stdout.write(`${DIM}branch${RESET} ${state.branch}\n`);
172
- if (state.mrUrl) process.stdout.write(`${DIM}mr${RESET} ${state.mrUrl}\n`);
173
- if (state.lastPipelineStatus) process.stdout.write(`${DIM}ci${RESET} ${state.lastPipelineStatus}\n`);
174
- if (state.updatedAt) process.stdout.write(`${DIM}updated${RESET} ${relativeAge(state.updatedAt)} ago\n`);
175
- }
176
- }
177
- process.stdout.write("\n");
178
- showPrompt();
179
- continue;
180
- }
181
-
182
- if (argv[0] === "open") {
183
- const head = await getHead();
184
- if (!head) {
185
- process.stdout.write(`${DIM}No active session.${RESET}\n`);
186
- } else {
187
- const state = await readState(head.repo, head.iid);
188
- const url = argv[1] === "mr" && state?.mrUrl
189
- ? state.mrUrl
190
- : state?.issueUrl || state?.mrUrl;
191
- if (url) {
192
- try { execSync(`open "${url}"`); } catch {}
193
- process.stdout.write(`${DIM}Opened ${url}${RESET}\n`);
194
- } else {
195
- process.stdout.write(`${DIM}No URL found. Run: analyze <iid>${RESET}\n`);
196
- }
197
- }
198
- showPrompt();
199
- continue;
200
- }
201
-
202
- if (argv[0] === "log") {
203
- const sessions = await listSessions();
204
- if (sessions.length === 0) {
205
- process.stdout.write(`\n${DIM}No sessions.${RESET}\n\n`);
206
- } else {
207
- const head = await getHead();
208
- const limit = Math.min(sessions.length, 10);
209
- process.stdout.write("\n");
210
- for (let i = 0; i < limit; i++) {
211
- const s = sessions[i];
212
- const isHead = head && s.repo === head.repo && s.iid === head.iid;
213
- const marker = isHead ? `${GREEN}*${RESET} ` : " ";
214
- const age = relativeAge(s.updatedAt);
215
- process.stdout.write(`${marker}${YELLOW}#${s.iid}${RESET} ${s.phase || "?"} ${DIM}${s.repo} ${age}${RESET}\n`);
216
- }
217
- if (sessions.length > limit) {
218
- process.stdout.write(`${DIM} ...${sessions.length - limit} more${RESET}\n`);
219
- }
220
- process.stdout.write("\n");
221
- }
222
- showPrompt();
223
- continue;
224
- }
225
-
226
- if (argv[0] === "use") {
227
- process.stdout.write("\n");
228
- if (!argv[1]) {
229
- const repos = await getConfiguredRepos();
230
- if (repos.length === 0) {
231
- console.error("No repos configured. Run: repos add <group/repo>");
232
- } else {
233
- for (const id of repos) {
234
- const marker = id === ctx.repo ? `${GREEN}*${RESET} ` : " ";
235
- process.stdout.write(`${marker}${id}\n`);
236
- }
237
- }
238
- } else {
239
- const result = await switchRepo(argv[1]);
240
- if (result) {
241
- ctx.repo = result;
242
- process.stdout.write(`${GREEN}*${RESET} ${YELLOW}${result}${RESET}\n`);
243
- }
244
- }
245
- process.stdout.write("\n");
246
- showPrompt();
247
- continue;
248
- }
249
-
250
- process.stdout.write("\n");
251
-
252
- const originalExit = process.exit;
253
- try {
254
- process.exit = (code) => {
255
- throw new ExitInterrupt(code ?? 0);
256
- };
257
- await dispatch(argv);
258
- } catch (err) {
259
- if (err instanceof ExitInterrupt) {
260
- // swallow
261
- } else {
262
- console.error(err.message || String(err));
263
- }
264
- } finally {
265
- process.exit = originalExit;
266
- }
267
-
268
- process.stdout.write("\n");
269
- showPrompt();
270
- }
271
-
272
- if (tty) process.stdout.write(`\n ${DIM}Session ended.${RESET}\n\n`);
273
- }
274
-
275
- function parseInput(line) {
276
- const tokens = [];
277
- let current = "";
278
- let inQuote = null;
279
-
280
- for (let i = 0; i < line.length; i++) {
281
- const ch = line[i];
282
- if (inQuote) {
283
- if (ch === inQuote) {
284
- inQuote = null;
285
- } else {
286
- current += ch;
287
- }
288
- } else if (ch === '"' || ch === "'") {
289
- inQuote = ch;
290
- } else if (ch === " " || ch === "\t") {
291
- if (current) {
292
- tokens.push(current);
293
- current = "";
294
- }
295
- } else {
296
- current += ch;
297
- }
298
- }
299
- if (current) tokens.push(current);
300
- return tokens;
301
- }
package/bin/cli/repos.js DELETED
@@ -1,91 +0,0 @@
1
- import path from "node:path";
2
- import React from "react";
3
- import { h, Box, Text, runApp } from "./ink.js";
4
- import { projectRoot } from "./utils.js";
5
-
6
- function ReposList({ repos }) {
7
- if (repos.length === 0) {
8
- return h`<${Box} flexDirection="column">
9
- <${Text} dimColor>No repos configured.</>
10
- <${Text}>${"Add one: forge repos add <group/repo>"}</>
11
- </>`;
12
- }
13
- return h`<${Box} flexDirection="column" marginTop=${1}>
14
- ${repos.map((r, i) =>
15
- h`<${Box} key=${i}>
16
- ${i === 0
17
- ? h`<${Text} color="green"> *</>`
18
- : h`<${Text}> </>`}
19
- <${Text}> ${r.id}</>
20
- </>`,
21
- )}
22
- <${Box} marginTop=${1}>
23
- <${Text} dimColor>${"* default — override per-call with --repo <group/repo>"}</>
24
- </>
25
- </>`;
26
- }
27
-
28
- export async function cmdRepos(argv) {
29
- const { get, patch } = await import(
30
- path.join(projectRoot, "server/forge/core/configStore.js")
31
- );
32
- const sub = argv[1] ?? "list";
33
-
34
- if (sub === "list") {
35
- const json = argv.includes("--json");
36
- const repos = get().repos ?? [];
37
- if (json) {
38
- process.stdout.write(`${JSON.stringify(repos, null, 2)}\n`);
39
- return;
40
- }
41
- await runApp(h`<${ReposList} repos=${repos} />`);
42
- return;
43
- }
44
-
45
- const repoArg = argv[2];
46
- if (!repoArg) {
47
- console.error(`Usage: forge repos ${sub} <group/repo>`);
48
- process.exit(1);
49
- }
50
-
51
- const repos = get().repos ?? [];
52
-
53
- if (sub === "add") {
54
- if (repos.some((r) => r.id === repoArg)) {
55
- console.error(`Already configured: ${repoArg}`);
56
- process.exit(1);
57
- }
58
- await patch({ repos: [...repos, { id: repoArg, label: repoArg }] });
59
- process.stderr.write(`✓ Added ${repoArg}\n`);
60
- if (repos.length === 0) {
61
- process.stderr.write(` (set as default)\n`);
62
- }
63
- return;
64
- }
65
-
66
- if (sub === "remove" || sub === "rm") {
67
- if (!repos.some((r) => r.id === repoArg)) {
68
- console.error(`Not configured: ${repoArg}`);
69
- process.exit(1);
70
- }
71
- await patch({ repos: repos.filter((r) => r.id !== repoArg) });
72
- process.stderr.write(`✓ Removed ${repoArg}\n`);
73
- return;
74
- }
75
-
76
- if (sub === "set-default" || sub === "default") {
77
- const target = repos.find((r) => r.id === repoArg);
78
- if (!target) {
79
- console.error(`Not configured. Add it first: forge repos add ${repoArg}`);
80
- process.exit(1);
81
- }
82
- const rest = repos.filter((r) => r.id !== repoArg);
83
- await patch({ repos: [target, ...rest] });
84
- process.stderr.write(`✓ Default: ${repoArg}\n`);
85
- return;
86
- }
87
-
88
- console.error(`Unknown subcommand: ${sub}`);
89
- console.error("Subcommands: list, add, set-default, remove");
90
- process.exit(1);
91
- }
@@ -1,126 +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
- function ResolutionView({ repo, secondaries, iid, mrIid, onDone }) {
15
- const { exit } = useApp();
16
- const [phase, setPhase] = useState("checking"); // checking → done | error
17
- const [verdict, setVerdict] = useState(null);
18
- const [error, setError] = useState(null);
19
-
20
- useEffect(() => {
21
- if (phase === "done" || phase === "error") {
22
- onDone({ phase, verdict, error });
23
- exit();
24
- }
25
- }, [phase]);
26
-
27
- useEffect(() => {
28
- let cancelled = false;
29
- (async () => {
30
- try {
31
- const { ForgeAgent } = await import(
32
- path.join(projectRoot, "server/forge/core/ForgeAgent.js")
33
- );
34
- const agent = new ForgeAgent({
35
- project: repo,
36
- secondaryProjects: secondaries,
37
- });
38
- const result = await agent.checkResolution(iid, mrIid, repo);
39
- if (cancelled) return;
40
- setVerdict(result);
41
- setPhase("done");
42
- } catch (err) {
43
- if (cancelled) return;
44
- setError(err);
45
- setPhase("error");
46
- }
47
- })();
48
- return () => {
49
- cancelled = true;
50
- };
51
- }, []);
52
-
53
- if (phase === "checking") {
54
- return h`<${Box}>
55
- <${Text} color="cyan"><${Spinner} type="dots"/></>
56
- <${Text}>${` Checking whether MR !${mrIid} resolves issue #${iid}…`}</>
57
- </>`;
58
- }
59
-
60
- if (phase === "error") {
61
- return h`<${Box}>
62
- <${Text} color="red">${`✘ ${error?.message ?? String(error)}`}</>
63
- </>`;
64
- }
65
-
66
- const ok = verdict?.resolved === true || verdict?.ok === true;
67
- const reasoning = verdict?.reasoning ?? verdict?.explanation ?? "";
68
- return h`<${Box} flexDirection="column">
69
- <${Text} color=${ok ? "green" : "red"}>${ok ? "✓ Resolved" : "✘ Not resolved"}</>
70
- ${reasoning
71
- ? h`<${Box} marginTop=${1}>
72
- <${Text} dimColor>Model reasoning: </>
73
- <${Text}>${reasoning}</>
74
- </>`
75
- : null}
76
- </>`;
77
- }
78
-
79
- export async function cmdResolutionCheck(argv) {
80
- const explicitIid = Number(argv[1]);
81
- const explicitRepo = getFlag(argv, "--repo");
82
- const target = await resolveSessionTarget({
83
- explicitIid: Number.isInteger(explicitIid) && explicitIid > 0 ? explicitIid : null,
84
- explicitRepo,
85
- });
86
- if (!target?.repo || !target?.iid) {
87
- console.error(
88
- "No session target. Pass an <iid>, set --repo, or run analyze + apply first.",
89
- );
90
- process.exit(1);
91
- }
92
- const state = await readState(target.repo, target.iid);
93
- if (!state?.mrIid) {
94
- console.error(
95
- `Session ${target.repo}#${target.iid} has no MR. Run: forge apply ${target.iid}`,
96
- );
97
- process.exit(1);
98
- }
99
- const repo = state.primary ?? target.repo;
100
- const secondaries = state.secondaries ?? [];
101
-
102
- let outcome = { phase: null };
103
- await runApp(
104
- h`<${ResolutionView}
105
- repo=${repo}
106
- secondaries=${secondaries}
107
- iid=${target.iid}
108
- mrIid=${state.mrIid}
109
- onDone=${(o) => (outcome = o)} />`,
110
- );
111
-
112
- if (outcome.phase === "done") {
113
- const ok = outcome.verdict?.resolved === true || outcome.verdict?.ok === true;
114
- await updateState(target.repo, target.iid, {
115
- phase: ok ? PHASES.RESOLVED : "resolution-rejected",
116
- resolution: outcome.verdict ?? null,
117
- }).catch(() => {});
118
- await appendEvent(target.repo, target.iid, {
119
- type: "session:resolution-check",
120
- resolved: ok,
121
- }).catch(() => {});
122
- if (!ok) process.exit(2);
123
- return;
124
- }
125
- process.exit(2);
126
- }