@ulpi/cli 0.1.4 → 0.1.6

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 (112) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{auth-PN7TMQHV-2W4ICG64.js → auth-FWM7MM4Q-VZC3U2XZ.js} +1 -1
  3. package/dist/{auth-ECQ3IB4E.js → auth-HDK7ECJL.js} +2 -1
  4. package/dist/{chunk-3SBPZRB5.js → chunk-3BCW6ABU.js} +402 -142
  5. package/dist/{chunk-JGBXM5NC.js → chunk-3WB5CXH4.js} +180 -5
  6. package/dist/{chunk-2HEE5OKX.js → chunk-4UCJIAOU.js} +2 -2
  7. package/dist/chunk-4XTHZVDS.js +109 -0
  8. package/dist/chunk-4ZPOZULQ.js +6522 -0
  9. package/dist/{chunk-SIAQVRKG.js → chunk-5MI5GIXM.js} +48 -2
  10. package/dist/{chunk-KLEASXUR.js → chunk-6ZL6NXMV.js} +1 -1
  11. package/dist/chunk-76D3BYJD.js +221 -0
  12. package/dist/{chunk-ZLYRPD7I.js → chunk-AWOSRA5F.js} +1 -1
  13. package/dist/{chunk-PDR55ZNW.js → chunk-BFEKZZHM.js} +274 -57
  14. package/dist/chunk-C7CLUQI6.js +1286 -0
  15. package/dist/{chunk-7AL4DOEJ.js → chunk-E3B5NROU.js} +7 -7
  16. package/dist/chunk-EJ7TW77N.js +1418 -0
  17. package/dist/{chunk-5J6NLQUN.js → chunk-IV6MWETF.js} +383 -168
  18. package/dist/chunk-IZPJHSPX.js +1478 -0
  19. package/dist/chunk-JLHNLM3C.js +228 -0
  20. package/dist/{chunk-BZL5H4YQ.js → chunk-KYYI23AQ.js} +2 -2
  21. package/dist/{chunk-2CLNOKPA.js → chunk-RSFJ6QSR.js} +18 -0
  22. package/dist/chunk-S6ANCSYO.js +1271 -0
  23. package/dist/chunk-SEU7WWNQ.js +1251 -0
  24. package/dist/chunk-SNQ7NAIS.js +453 -0
  25. package/dist/{ulpi-RMMCUAGP-JCJ273T6.js → chunk-TSLDGT5O.js} +73 -35
  26. package/dist/{chunk-SPOI23SB.js → chunk-UXHCHOWQ.js} +83 -62
  27. package/dist/chunk-V2H5D6Y3.js +146 -0
  28. package/dist/{chunk-QJ5GSMEC.js → chunk-VVEDXI7E.js} +2 -1
  29. package/dist/chunk-VXH5Y4FO.js +6761 -0
  30. package/dist/chunk-WED4LM5N.js +322 -0
  31. package/dist/{chunk-74WVVWJ4.js → chunk-YOKL7RB5.js} +184 -15
  32. package/dist/chunk-Z53CAR7G.js +298 -0
  33. package/dist/ci-X3U2W4HC.js +854 -0
  34. package/dist/cloud-2F3NLVHN.js +274 -0
  35. package/dist/{codemap-RKSD4MIE.js → codemap-XNGMAF3F.js} +37 -37
  36. package/dist/codex-MB5YTMRT.js +132 -0
  37. package/dist/{config-EGAXXCGL.js → config-OOELBYTH.js} +1 -1
  38. package/dist/dist-2BJYR5EI.js +59 -0
  39. package/dist/dist-2K7IEVTA.js +43 -0
  40. package/dist/dist-3EIQTZHT.js +1380 -0
  41. package/dist/{dist-YA2BWZB2.js → dist-4U5L2X2C.js} +2 -2
  42. package/dist/{dist-UKMCJBB2.js → dist-54KAMNLO.js} +16 -15
  43. package/dist/dist-6M4MZWZW.js +58 -0
  44. package/dist/dist-6X576SU2.js +27 -0
  45. package/dist/dist-7QOEYLFX.js +103 -0
  46. package/dist/dist-AYBGHEDY.js +2541 -0
  47. package/dist/dist-EK45QNEM.js +45 -0
  48. package/dist/{dist-CS2VKNYS.js → dist-FKFEJRPX.js} +16 -15
  49. package/dist/dist-GTEJUBBT.js +66 -0
  50. package/dist/dist-HA74OKJZ.js +40 -0
  51. package/dist/dist-HU5RZAON.js +48 -0
  52. package/dist/dist-IYE3OBRB.js +374 -0
  53. package/dist/{dist-GJYT2OQV.js → dist-JLU26AB6.js} +12 -9
  54. package/dist/{dist-6G7JC2RA.js → dist-KUCI6JFE.js} +49 -9
  55. package/dist/dist-NUEMFZFL.js +33 -0
  56. package/dist/{dist-RKOGLK7R.js → dist-NUXMDXZ3.js} +31 -3
  57. package/dist/{dist-QAU3LGJN.js → dist-YCNWHSLN.js} +15 -5
  58. package/dist/{dist-CB5D5LMO.js → dist-YFFG2ZD6.js} +9 -16
  59. package/dist/dist-ZG4OKCSR.js +15 -0
  60. package/dist/doctor-SI4LLLDZ.js +345 -0
  61. package/dist/{export-import-4A5MWLIA.js → export-import-JFQH4KSJ.js} +1 -1
  62. package/dist/{history-3MOBX4MA.js → history-5NE46ZAH.js} +7 -7
  63. package/dist/hooks-installer-UN5JZLDQ.js +19 -0
  64. package/dist/index.js +395 -619
  65. package/dist/{init-6CH4HV5T.js → init-5FK3VKRT.js} +79 -13
  66. package/dist/job-HIDMAFW2.js +376 -0
  67. package/dist/jobs.memory-PLMMSFHB-VBECCTHN.js +33 -0
  68. package/dist/kiro-VMUHDFGK.js +153 -0
  69. package/dist/{launchd-LF2QMSKZ.js → launchd-6AWT54HR.js} +9 -17
  70. package/dist/mcp-PDUD7SGP.js +249 -0
  71. package/dist/mcp-installer-PQU3XOGO.js +259 -0
  72. package/dist/mcp-setup-OA7IB3H3.js +263 -0
  73. package/dist/{memory-Y6OZTXJ2.js → memory-ZNAEAK3B.js} +17 -17
  74. package/dist/{ollama-3XCUZMZT-FYKHW4TZ.js → ollama-3XCUZMZT-4JMH6B7P.js} +1 -1
  75. package/dist/{openai-E7G2YAHU-UYY4ZWON.js → openai-E7G2YAHU-T3HMBPH7.js} +2 -2
  76. package/dist/portal-JYWVHXDU.js +210 -0
  77. package/dist/prd-Q4J5NVAR.js +408 -0
  78. package/dist/repos-WWZXNN3P.js +271 -0
  79. package/dist/review-integration-5WHEJU2A.js +14 -0
  80. package/dist/{rules-E427DKYJ.js → rules-Y4VSOY5Y.js} +3 -3
  81. package/dist/run-VPNXEIBY.js +687 -0
  82. package/dist/server-COL4AXKU-P7S7NNF6.js +11 -0
  83. package/dist/server-KKSETHDV-XSSLEENT.js +20 -0
  84. package/dist/{skills-CX73O3IV.js → skills-QEYU2N27.js} +4 -2
  85. package/dist/start-JYOEL7AJ.js +303 -0
  86. package/dist/{status-4DFHDJMN.js → status-BHQYYGAL.js} +2 -2
  87. package/dist/{templates-U7T6MARD.js → templates-CBRUJ66V.js} +4 -3
  88. package/dist/tui-DP7736EX.js +61 -0
  89. package/dist/ulpi-5EN6JCAS-LFE3WSL4.js +10 -0
  90. package/dist/{uninstall-6SW35IK4.js → uninstall-ICUV6DDV.js} +3 -3
  91. package/dist/{update-M6IBJNYP.js → update-7ZMAYRBH.js} +3 -3
  92. package/dist/{version-checker-Q6YTYAGP.js → version-checker-4ZFMZA7Y.js} +2 -2
  93. package/package.json +39 -31
  94. package/dist/chunk-2MZER6ND.js +0 -415
  95. package/dist/chunk-2VYFVYJL.js +0 -4273
  96. package/dist/chunk-6OCEY7JY.js +0 -422
  97. package/dist/chunk-7LXY5UVC.js +0 -330
  98. package/dist/chunk-B55DDP24.js +0 -136
  99. package/dist/chunk-JWUUVXIV.js +0 -13694
  100. package/dist/chunk-MIAQVCFW.js +0 -39
  101. package/dist/chunk-YM2HV4IA.js +0 -505
  102. package/dist/ci-STSL2LSP.js +0 -370
  103. package/dist/mcp-installer-NQCGKQ23.js +0 -124
  104. package/dist/projects-ATHDD3D6.js +0 -271
  105. package/dist/review-ADUPV3PN.js +0 -152
  106. package/dist/server-USLHY6GH-AEOJC5ST.js +0 -18
  107. package/dist/server-X5P6WH2M-7K2RY34N.js +0 -11
  108. package/dist/skills/ulpi-generate-guardian/SKILL.md +0 -750
  109. package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +0 -849
  110. package/dist/skills/ulpi-generate-guardian/references/language-rules.md +0 -591
  111. package/dist/ui-OWXZ3YSR.js +0 -167
  112. package/dist/ui.html +0 -698
@@ -0,0 +1,687 @@
1
+ import {
2
+ ExecutionEngine
3
+ } from "./chunk-EJ7TW77N.js";
4
+ import "./chunk-S6ANCSYO.js";
5
+ import "./chunk-76D3BYJD.js";
6
+ import "./chunk-IZPJHSPX.js";
7
+ import "./chunk-5MI5GIXM.js";
8
+ import "./chunk-SEU7WWNQ.js";
9
+ import {
10
+ API_LOCK_FILE
11
+ } from "./chunk-C7CLUQI6.js";
12
+ import "./chunk-KIKPIH6N.js";
13
+ import "./chunk-4VNS5WPM.js";
14
+
15
+ // src/commands/run.ts
16
+ import * as fs from "fs";
17
+ import * as http from "http";
18
+ import * as os from "os";
19
+ import * as path from "path";
20
+ import { execFileSync } from "child_process";
21
+ import chalk from "chalk";
22
+ function getFlag(args, flag) {
23
+ const idx = args.indexOf(flag);
24
+ if (idx !== -1 && idx + 1 < args.length) {
25
+ return args[idx + 1];
26
+ }
27
+ return void 0;
28
+ }
29
+ function hasFlag(args, flag) {
30
+ return args.includes(flag);
31
+ }
32
+ async function runRunCommand(args, projectDir) {
33
+ const prdFile = getFlag(args, "--prd");
34
+ const branchName = getFlag(args, "--branch");
35
+ let trackerName = getFlag(args, "--tracker") ?? "json";
36
+ const agentName = getFlag(args, "--agent") ?? "claude";
37
+ const model = getFlag(args, "--model") ?? "";
38
+ let tasksFile = getFlag(args, "--tasks");
39
+ const autoCommit = hasFlag(args, "--auto-commit");
40
+ const maxRetries = parseInt(getFlag(args, "--max-retries") ?? "3", 10);
41
+ const maxIterations = parseInt(
42
+ getFlag(args, "--max-iterations") ?? "0",
43
+ 10
44
+ );
45
+ const timeout = parseInt(getFlag(args, "--timeout") ?? "0", 10);
46
+ const maxWorkers = parseInt(getFlag(args, "--max-workers") ?? "3", 10);
47
+ if (prdFile) {
48
+ const resolvedPrd = path.resolve(prdFile);
49
+ if (!fs.existsSync(resolvedPrd)) {
50
+ console.error(chalk.red(`PRD file not found: ${resolvedPrd}`));
51
+ process.exit(1);
52
+ }
53
+ try {
54
+ const { parsePrdMarkdown } = await import("./dist-3EIQTZHT.js");
55
+ const { convertPrdToJson } = await import("./dist-3EIQTZHT.js");
56
+ const prdContent = fs.readFileSync(resolvedPrd, "utf-8");
57
+ const parsed = parsePrdMarkdown(prdContent);
58
+ if (parsed.document.tasks.length === 0) {
59
+ console.error(chalk.red("No tasks found in PRD file."));
60
+ process.exit(1);
61
+ }
62
+ console.log(
63
+ chalk.green(
64
+ `Parsed PRD: ${parsed.document.tasks.length} task(s) from "${parsed.document.title}"`
65
+ )
66
+ );
67
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ulpi-prd-"));
68
+ const tmpTasksFile = path.join(tmpDir, "tasks.json");
69
+ const tasksJson = convertPrdToJson(parsed.document);
70
+ fs.writeFileSync(tmpTasksFile, JSON.stringify(tasksJson, null, 2));
71
+ tasksFile = tmpTasksFile;
72
+ trackerName = "json";
73
+ } catch (err) {
74
+ console.error(
75
+ chalk.red(
76
+ `Failed to parse PRD: ${err instanceof Error ? err.message : String(err)}`
77
+ )
78
+ );
79
+ process.exit(1);
80
+ }
81
+ }
82
+ if (branchName) {
83
+ try {
84
+ execFileSync("git", ["checkout", "-b", branchName], {
85
+ cwd: projectDir,
86
+ encoding: "utf-8"
87
+ });
88
+ console.log(chalk.green(`Created and checked out branch: ${branchName}`));
89
+ } catch (err) {
90
+ try {
91
+ execFileSync("git", ["checkout", branchName], {
92
+ cwd: projectDir,
93
+ encoding: "utf-8"
94
+ });
95
+ console.log(chalk.yellow(`Checked out existing branch: ${branchName}`));
96
+ } catch (err2) {
97
+ console.error(
98
+ chalk.red(
99
+ `Failed to create/checkout branch: ${err2 instanceof Error ? err2.message : String(err2)}`
100
+ )
101
+ );
102
+ process.exit(1);
103
+ }
104
+ }
105
+ }
106
+ const trackerConfig = {};
107
+ if (trackerName === "json") {
108
+ const defaultTasksPath = path.join(projectDir, "tasks.json");
109
+ const resolvedTasksFile = tasksFile ? path.resolve(tasksFile) : defaultTasksPath;
110
+ if (!fs.existsSync(resolvedTasksFile)) {
111
+ console.error(
112
+ chalk.red(
113
+ `Tasks file not found: ${resolvedTasksFile}
114
+ Create a tasks.json file or specify one with --tasks <file>`
115
+ )
116
+ );
117
+ process.exit(1);
118
+ }
119
+ trackerConfig.path = resolvedTasksFile;
120
+ } else if (tasksFile) {
121
+ trackerConfig.path = path.resolve(tasksFile);
122
+ }
123
+ if (hasFlag(args, "--parallel")) {
124
+ let prdMarkdown;
125
+ if (prdFile) {
126
+ try {
127
+ prdMarkdown = fs.readFileSync(path.resolve(prdFile), "utf-8");
128
+ } catch {
129
+ }
130
+ }
131
+ await runParallelMode(args, projectDir, {
132
+ agentName,
133
+ model,
134
+ trackerName,
135
+ trackerConfig,
136
+ maxWorkers,
137
+ autoCommit,
138
+ maxRetries,
139
+ prdMarkdown
140
+ });
141
+ return;
142
+ }
143
+ const config = {
144
+ agentName,
145
+ trackerName,
146
+ trackerConfig,
147
+ workingDir: projectDir,
148
+ maxRetries,
149
+ retryDelayMs: 5e3,
150
+ autoCommit,
151
+ timeout,
152
+ maxIterations,
153
+ iterationDelayMs: 0,
154
+ errorStrategy: "retry",
155
+ rateLimit: {
156
+ enabled: true,
157
+ maxRetries: 3,
158
+ baseBackoffMs: 5e3,
159
+ recoverPrimaryBetweenIterations: true
160
+ },
161
+ agentConfig: model ? { model } : {}
162
+ };
163
+ console.log(chalk.bold("\nULPI Execution Engine"));
164
+ console.log(chalk.dim("\u2500".repeat(40)));
165
+ console.log(` Agent: ${chalk.cyan(agentName)}${model ? ` (${chalk.cyan(model)})` : ""}`);
166
+ console.log(` Tracker: ${chalk.cyan(trackerName)}`);
167
+ console.log(` Dir: ${chalk.dim(projectDir)}`);
168
+ if (autoCommit) {
169
+ console.log(` Auto-commit: ${chalk.green("enabled")}`);
170
+ }
171
+ if (maxIterations > 0) {
172
+ console.log(` Max iterations: ${maxIterations}`);
173
+ }
174
+ console.log(chalk.dim("\u2500".repeat(40)));
175
+ console.log();
176
+ const engine = new ExecutionEngine(config);
177
+ try {
178
+ await engine.initialize();
179
+ } catch (err) {
180
+ console.error(
181
+ chalk.red(
182
+ `Failed to initialize engine: ${err instanceof Error ? err.message : String(err)}`
183
+ )
184
+ );
185
+ process.exit(1);
186
+ }
187
+ const startedAt = Date.now();
188
+ const collectedEvents = [];
189
+ engine.on((event) => {
190
+ handleEvent(event);
191
+ relayLoopEvent(event);
192
+ if (event.type !== "agent:output") {
193
+ collectedEvents.push({ ...event, ts: event.timestamp });
194
+ }
195
+ });
196
+ let stopping = false;
197
+ process.on("SIGINT", async () => {
198
+ if (stopping) {
199
+ console.log(chalk.red("\nForce exiting..."));
200
+ process.exit(1);
201
+ }
202
+ stopping = true;
203
+ console.log(chalk.yellow("\nInterrupted. Stopping engine..."));
204
+ await engine.stop();
205
+ });
206
+ try {
207
+ await engine.start();
208
+ } catch (err) {
209
+ console.error(
210
+ chalk.red(
211
+ `Engine error: ${err instanceof Error ? err.message : String(err)}`
212
+ )
213
+ );
214
+ process.exit(1);
215
+ }
216
+ const state = engine.getState();
217
+ try {
218
+ const { captureJobForClassification, isMemoryEnabled } = await import("./dist-JLU26AB6.js");
219
+ if (isMemoryEnabled(projectDir) && collectedEvents.length > 0) {
220
+ const cliJobId = `cli-${Date.now()}`;
221
+ captureJobForClassification(projectDir, cliJobId, collectedEvents, {
222
+ jobId: cliJobId,
223
+ mode: "sequential",
224
+ agentName,
225
+ startedAt: new Date(startedAt).toISOString(),
226
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
227
+ tasksCompleted: state.completedTasks.length,
228
+ tasksFailed: state.failedTasks.length,
229
+ totalIterations: state.currentIteration
230
+ });
231
+ const { spawn } = await import("child_process");
232
+ const child = spawn(
233
+ process.execPath,
234
+ [process.argv[1], "memory", "classify", "-p", projectDir, "--session", cliJobId],
235
+ { detached: true, stdio: "ignore", env: { ...process.env, ULPI_BG_CLASSIFY: "1" } }
236
+ );
237
+ child.unref();
238
+ }
239
+ } catch {
240
+ }
241
+ console.log();
242
+ console.log(chalk.bold("Run Summary"));
243
+ console.log(chalk.dim("\u2500".repeat(40)));
244
+ console.log(
245
+ ` Completed: ${chalk.green(String(state.completedTasks.length))}`
246
+ );
247
+ console.log(
248
+ ` Failed: ${chalk.red(String(state.failedTasks.length))}`
249
+ );
250
+ console.log(
251
+ ` Skipped: ${chalk.yellow(String(state.skippedTasks.length))}`
252
+ );
253
+ console.log(` Iterations: ${state.currentIteration}`);
254
+ console.log(chalk.dim("\u2500".repeat(40)));
255
+ }
256
+ function handleEvent(event) {
257
+ switch (event.type) {
258
+ case "engine:started":
259
+ console.log(
260
+ chalk.green(`Engine started with ${event.totalTasks} task(s)`)
261
+ );
262
+ break;
263
+ case "engine:stopped":
264
+ console.log(
265
+ chalk.dim(
266
+ `Engine stopped: ${event.reason} (${event.totalIterations} iterations, ${event.tasksCompleted} completed)`
267
+ )
268
+ );
269
+ break;
270
+ case "engine:paused":
271
+ console.log(chalk.yellow("Engine paused"));
272
+ break;
273
+ case "engine:resumed":
274
+ console.log(chalk.green("Engine resumed"));
275
+ break;
276
+ case "iteration:started":
277
+ console.log(
278
+ chalk.blue(
279
+ `
280
+ [Iteration ${event.iteration}] Task: ${event.task.id} - ${event.task.title}`
281
+ )
282
+ );
283
+ break;
284
+ case "iteration:completed":
285
+ if (event.result.taskCompleted) {
286
+ console.log(
287
+ chalk.green(
288
+ ` Task completed in ${formatDuration(event.result.durationMs)}`
289
+ )
290
+ );
291
+ } else {
292
+ console.log(
293
+ chalk.dim(
294
+ ` Iteration completed (task not done) in ${formatDuration(event.result.durationMs)}`
295
+ )
296
+ );
297
+ }
298
+ break;
299
+ case "iteration:failed":
300
+ console.log(
301
+ chalk.red(` Iteration failed: ${event.error} [${event.action}]`)
302
+ );
303
+ break;
304
+ case "iteration:retrying":
305
+ console.log(
306
+ chalk.yellow(
307
+ ` Retrying (${event.retryAttempt}/${event.maxRetries}) in ${formatDuration(event.delayMs)}...`
308
+ )
309
+ );
310
+ break;
311
+ case "iteration:rate-limited":
312
+ console.log(
313
+ chalk.yellow(
314
+ ` Rate limited (${event.retryAttempt}/${event.maxRetries}). Waiting ${formatDuration(event.delayMs)}...`
315
+ )
316
+ );
317
+ break;
318
+ case "task:auto-committed":
319
+ console.log(
320
+ chalk.green(
321
+ ` Auto-committed: ${event.commitSha ?? "unknown"} - ${event.commitMessage}`
322
+ )
323
+ );
324
+ break;
325
+ case "task:auto-commit-failed":
326
+ console.log(
327
+ chalk.red(` Auto-commit failed: ${event.error}`)
328
+ );
329
+ break;
330
+ case "task:auto-commit-skipped":
331
+ console.log(
332
+ chalk.dim(` Auto-commit skipped: ${event.reason}`)
333
+ );
334
+ break;
335
+ case "agent:switched":
336
+ console.log(
337
+ chalk.cyan(
338
+ ` Agent switched: ${event.previousAgent} -> ${event.newAgent} (${event.reason})`
339
+ )
340
+ );
341
+ break;
342
+ case "agent:all-limited":
343
+ console.log(
344
+ chalk.red(
345
+ ` All agents rate-limited: ${event.triedAgents.join(", ")}. Pausing.`
346
+ )
347
+ );
348
+ break;
349
+ case "agent:recovery-attempted":
350
+ if (event.success) {
351
+ console.log(
352
+ chalk.green(
353
+ ` Primary agent '${event.primaryAgent}' recovered (${event.testDurationMs}ms)`
354
+ )
355
+ );
356
+ }
357
+ break;
358
+ case "all:complete":
359
+ console.log(
360
+ chalk.green(
361
+ `
362
+ All tasks complete! ${event.totalCompleted} tasks in ${event.totalIterations} iterations.`
363
+ )
364
+ );
365
+ break;
366
+ // agent:output events are intentionally not printed to avoid flooding terminal
367
+ default:
368
+ break;
369
+ }
370
+ }
371
+ function formatDuration(ms) {
372
+ if (ms < 1e3) return `${ms}ms`;
373
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
374
+ const mins = Math.floor(ms / 6e4);
375
+ const secs = Math.round(ms % 6e4 / 1e3);
376
+ return `${mins}m ${secs}s`;
377
+ }
378
+ function emitToApi(event) {
379
+ try {
380
+ const lockData = JSON.parse(fs.readFileSync(API_LOCK_FILE, "utf-8"));
381
+ const port = lockData.port;
382
+ if (!port) return;
383
+ const body = JSON.stringify(event);
384
+ const headers = {
385
+ "Content-Type": "application/json",
386
+ "Content-Length": String(Buffer.byteLength(body))
387
+ };
388
+ if (lockData.secret) {
389
+ headers["X-Ulpi-Secret"] = lockData.secret;
390
+ }
391
+ const req = http.request({
392
+ hostname: "127.0.0.1",
393
+ port,
394
+ path: "/api/events/emit",
395
+ method: "POST",
396
+ headers,
397
+ timeout: 2e3
398
+ });
399
+ req.on("error", () => {
400
+ });
401
+ req.on("timeout", () => req.destroy());
402
+ req.write(body);
403
+ req.end();
404
+ } catch {
405
+ }
406
+ }
407
+ function relayLoopEvent(event) {
408
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
409
+ const base = { ts, sessionId: "" };
410
+ let mapped = null;
411
+ switch (event.type) {
412
+ case "engine:started":
413
+ mapped = { ...base, type: "engine:started", totalTasks: event.totalTasks, tasks: [] };
414
+ break;
415
+ case "engine:stopped":
416
+ mapped = { ...base, type: "engine:stopped", reason: event.reason, totalIterations: event.totalIterations, tasksCompleted: event.tasksCompleted };
417
+ break;
418
+ case "iteration:started":
419
+ mapped = { ...base, type: "iteration:started", iteration: event.iteration, taskId: event.task.id };
420
+ break;
421
+ case "iteration:completed":
422
+ mapped = {
423
+ ...base,
424
+ type: "iteration:completed",
425
+ iteration: event.result.iteration,
426
+ taskId: event.result.task.id,
427
+ durationMs: event.result.durationMs,
428
+ completionSignalDetected: event.result.completionSignalDetected
429
+ };
430
+ break;
431
+ case "iteration:failed":
432
+ mapped = { ...base, type: "iteration:failed", iteration: event.iteration, taskId: "", error: event.error, action: event.action };
433
+ break;
434
+ case "task:auto-committed":
435
+ mapped = {
436
+ ...base,
437
+ type: "task:auto-committed",
438
+ taskId: event.task.id,
439
+ iteration: event.iteration,
440
+ commitMessage: event.commitMessage,
441
+ commitSha: event.commitSha
442
+ };
443
+ break;
444
+ case "all:complete":
445
+ mapped = { ...base, type: "all:complete", totalCompleted: event.totalCompleted, totalIterations: event.totalIterations };
446
+ break;
447
+ default:
448
+ break;
449
+ }
450
+ if (mapped) {
451
+ emitToApi(mapped);
452
+ }
453
+ }
454
+ async function runParallelMode(args, projectDir, opts) {
455
+ const { ParallelExecutor } = await import("./dist-AYBGHEDY.js");
456
+ const { getTrackerRegistry } = await import("./dist-NUEMFZFL.js");
457
+ console.log(chalk.bold("\nULPI Parallel Execution"));
458
+ console.log(chalk.dim("\u2500".repeat(40)));
459
+ console.log(` Agent: ${chalk.cyan(opts.agentName)}${opts.model ? ` (${chalk.cyan(opts.model)})` : ""}`);
460
+ console.log(` Tracker: ${chalk.cyan(opts.trackerName)}`);
461
+ console.log(` Workers: ${chalk.cyan(String(opts.maxWorkers))}`);
462
+ console.log(` Dir: ${chalk.dim(projectDir)}`);
463
+ console.log(` Auto-commit: ${chalk.green("enabled")} (required for worktree merge)`);
464
+ console.log(chalk.dim("\u2500".repeat(40)));
465
+ console.log();
466
+ const registry = getTrackerRegistry();
467
+ await registry.initialize();
468
+ await registry.disposeInstance(opts.trackerName);
469
+ const tracker = await registry.getInstance({
470
+ name: opts.trackerName,
471
+ plugin: opts.trackerName,
472
+ options: opts.trackerConfig
473
+ });
474
+ await tracker.sync();
475
+ const tasks = await tracker.getTasks();
476
+ if (tasks.length === 0) {
477
+ console.error(chalk.red("No open tasks found. Nothing to execute."));
478
+ process.exit(1);
479
+ }
480
+ console.log(chalk.green(`Found ${tasks.length} task(s)`));
481
+ const baseEngineConfig = {
482
+ agentName: opts.agentName,
483
+ trackerName: opts.trackerName,
484
+ trackerConfig: opts.trackerConfig,
485
+ workingDir: projectDir,
486
+ maxRetries: opts.maxRetries,
487
+ retryDelayMs: 5e3,
488
+ autoCommit: true,
489
+ // Required for worktree merge
490
+ timeout: 0,
491
+ maxIterations: 0,
492
+ iterationDelayMs: 0,
493
+ errorStrategy: "retry",
494
+ rateLimit: {
495
+ enabled: true,
496
+ maxRetries: 3,
497
+ baseBackoffMs: 5e3,
498
+ recoverPrimaryBetweenIterations: true
499
+ },
500
+ agentConfig: opts.model ? { model: opts.model } : {}
501
+ };
502
+ const aiConflictResolution = !hasFlag(args, "--no-ai-conflicts");
503
+ const enableValidation = !hasFlag(args, "--no-validation");
504
+ const executor = new ParallelExecutor(
505
+ {
506
+ cwd: projectDir,
507
+ maxWorkers: opts.maxWorkers,
508
+ aiConflictResolution,
509
+ enableValidation,
510
+ prdMarkdown: opts.prdMarkdown
511
+ },
512
+ baseEngineConfig
513
+ );
514
+ const startedAt = Date.now();
515
+ const collectedParallelEvents = [];
516
+ executor.on((event) => {
517
+ handleParallelEvent(event);
518
+ if (event.type !== "worker-progress") {
519
+ collectedParallelEvents.push({ ...event, ts: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString() });
520
+ }
521
+ });
522
+ let stopping = false;
523
+ const sigHandler = async () => {
524
+ if (stopping) {
525
+ console.log(chalk.red("\nForce exiting..."));
526
+ process.exit(1);
527
+ }
528
+ stopping = true;
529
+ console.log(chalk.yellow("\nInterrupted. Stopping parallel execution..."));
530
+ await executor.stop();
531
+ };
532
+ process.on("SIGINT", sigHandler);
533
+ try {
534
+ await executor.initialize(tasks);
535
+ const state = executor.getState();
536
+ if (state.dagAnalysis) {
537
+ console.log(
538
+ chalk.dim(
539
+ ` DAG: ${state.dagAnalysis.groups.length} group(s), max parallelism: ${state.dagAnalysis.maxParallelism}`
540
+ )
541
+ );
542
+ if (state.dagAnalysis.warnings.length > 0) {
543
+ for (const w of state.dagAnalysis.warnings) {
544
+ console.log(chalk.yellow(` Warning: ${w}`));
545
+ }
546
+ }
547
+ }
548
+ console.log();
549
+ await executor.execute();
550
+ } catch (err) {
551
+ console.error(
552
+ chalk.red(
553
+ `
554
+ Parallel execution error: ${err instanceof Error ? err.message : String(err)}`
555
+ )
556
+ );
557
+ process.exit(1);
558
+ } finally {
559
+ process.removeListener("SIGINT", sigHandler);
560
+ try {
561
+ await registry.disposeInstance(opts.trackerName);
562
+ } catch {
563
+ }
564
+ }
565
+ const finalState = executor.getState();
566
+ console.log();
567
+ console.log(chalk.bold("Parallel Run Summary"));
568
+ console.log(chalk.dim("\u2500".repeat(40)));
569
+ console.log(` Total tasks: ${finalState.totalTasks}`);
570
+ console.log(` Completed: ${chalk.green(String(finalState.totalTasksCompleted))}`);
571
+ console.log(` Groups: ${finalState.totalGroups}`);
572
+ const durationMs = finalState.elapsedMs;
573
+ console.log(` Duration: ${formatDuration(durationMs)}`);
574
+ console.log(chalk.dim("\u2500".repeat(40)));
575
+ try {
576
+ const { captureJobForClassification, isMemoryEnabled } = await import("./dist-JLU26AB6.js");
577
+ if (isMemoryEnabled(projectDir) && collectedParallelEvents.length > 0) {
578
+ const cliJobId = `cli-par-${Date.now()}`;
579
+ const totalFailed = finalState.totalTasks - finalState.totalTasksCompleted;
580
+ captureJobForClassification(projectDir, cliJobId, collectedParallelEvents, {
581
+ jobId: cliJobId,
582
+ mode: "parallel",
583
+ agentName: opts.agentName,
584
+ startedAt: new Date(startedAt).toISOString(),
585
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
586
+ tasksCompleted: finalState.totalTasksCompleted,
587
+ tasksFailed: totalFailed > 0 ? totalFailed : 0,
588
+ totalIterations: collectedParallelEvents.filter((e) => e.type === "worker-started").length
589
+ });
590
+ const { spawn } = await import("child_process");
591
+ const child = spawn(
592
+ process.execPath,
593
+ [process.argv[1], "memory", "classify", "-p", projectDir, "--session", cliJobId],
594
+ { detached: true, stdio: "ignore", env: { ...process.env, ULPI_BG_CLASSIFY: "1" } }
595
+ );
596
+ child.unref();
597
+ }
598
+ } catch {
599
+ }
600
+ }
601
+ function handleParallelEvent(event) {
602
+ switch (event.type) {
603
+ case "worker-started":
604
+ console.log(
605
+ chalk.blue(` [Worker ${event.workerId}] Started: task ${event.taskId}`)
606
+ );
607
+ break;
608
+ case "worker-completed":
609
+ console.log(
610
+ event.success ? chalk.green(
611
+ ` [Worker ${event.workerId}] Completed: task ${event.taskId}`
612
+ ) : chalk.red(
613
+ ` [Worker ${event.workerId}] Failed: task ${event.taskId}`
614
+ )
615
+ );
616
+ break;
617
+ case "worker-failed":
618
+ console.log(
619
+ chalk.red(` [Worker ${event.workerId}] Failed: ${event.error}`)
620
+ );
621
+ break;
622
+ case "merge-started":
623
+ console.log(
624
+ chalk.dim(` [Merge] Starting merge for task ${event.taskId}`)
625
+ );
626
+ break;
627
+ case "merge-completed":
628
+ console.log(
629
+ chalk.green(
630
+ ` [Merge] Task ${event.taskId} merged${event.commitSha ? ` (${event.commitSha})` : ""}`
631
+ )
632
+ );
633
+ break;
634
+ case "merge-failed":
635
+ console.log(
636
+ chalk.red(
637
+ ` [Merge] Task ${event.taskId} merge failed: ${event.error}`
638
+ )
639
+ );
640
+ break;
641
+ case "group-completed":
642
+ console.log(
643
+ chalk.bold(
644
+ `
645
+ Group ${event.groupIndex}: ${event.tasksCompleted} completed, ${event.tasksFailed} failed`
646
+ )
647
+ );
648
+ break;
649
+ case "all-completed":
650
+ console.log(
651
+ chalk.green(
652
+ `
653
+ All tasks complete! ${event.totalCompleted} completed, ${event.totalFailed} failed (${formatDuration(event.durationMs)})`
654
+ )
655
+ );
656
+ break;
657
+ case "worker-progress":
658
+ if (event.engineEventType === "task:auto-committed" || event.engineEventType === "iteration:failed") {
659
+ console.log(
660
+ chalk.dim(
661
+ ` [Worker ${event.workerId}] ${event.engineEventType}`
662
+ )
663
+ );
664
+ }
665
+ break;
666
+ case "validation-started":
667
+ console.log(
668
+ chalk.bold(
669
+ `
670
+ Validation: Starting post-parallel validation (${event.totalMerged} merged, ${event.totalFailed} failed)`
671
+ )
672
+ );
673
+ break;
674
+ case "validation-completed":
675
+ console.log(
676
+ event.success ? chalk.green(
677
+ ` Validation: Completed (${event.commitCount} commits, ${formatDuration(event.durationMs)})`
678
+ ) : chalk.yellow(
679
+ ` Validation: Finished with issues (${event.commitCount} commits, ${formatDuration(event.durationMs)})`
680
+ )
681
+ );
682
+ break;
683
+ }
684
+ }
685
+ export {
686
+ runRunCommand
687
+ };
@@ -0,0 +1,11 @@
1
+ import {
2
+ attachWebSocket
3
+ } from "./chunk-E3B5NROU.js";
4
+ import "./chunk-Z53CAR7G.js";
5
+ import "./chunk-UXHCHOWQ.js";
6
+ import "./chunk-SEU7WWNQ.js";
7
+ import "./chunk-C7CLUQI6.js";
8
+ import "./chunk-4VNS5WPM.js";
9
+ export {
10
+ attachWebSocket
11
+ };