@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
@@ -2,24 +2,26 @@ import {
2
2
  installGlobalSkill,
3
3
  installHooks,
4
4
  installLocalSkill
5
- } from "./chunk-QJ5GSMEC.js";
5
+ } from "./chunk-VVEDXI7E.js";
6
6
  import {
7
- detectStack
8
- } from "./chunk-2CLNOKPA.js";
9
- import {
10
- registerProject
11
- } from "./chunk-SPOI23SB.js";
7
+ registerRepo
8
+ } from "./chunk-UXHCHOWQ.js";
12
9
  import {
13
10
  composeTemplates,
14
11
  loadBundledTemplates,
15
12
  resolveTemplate
16
- } from "./chunk-6OCEY7JY.js";
13
+ } from "./chunk-4ZPOZULQ.js";
14
+ import {
15
+ detectStack
16
+ } from "./chunk-RSFJ6QSR.js";
17
17
  import {
18
18
  DEFAULT_AI_MODEL,
19
19
  GUARDS_FILENAME,
20
20
  getApiPort,
21
21
  projectConfigDir
22
- } from "./chunk-7LXY5UVC.js";
22
+ } from "./chunk-C7CLUQI6.js";
23
+ import "./chunk-YOKL7RB5.js";
24
+ import "./chunk-KIKPIH6N.js";
23
25
  import "./chunk-4VNS5WPM.js";
24
26
 
25
27
  // src/commands/init.ts
@@ -95,7 +97,7 @@ async function runInit(args) {
95
97
  console.log(chalk.yellow(`\u26A0 ${globalResult.message}`));
96
98
  }
97
99
  try {
98
- const { isSupported, isLaunchAgentInstalled, needsLegacyMigration, installLaunchAgent } = await import("./launchd-LF2QMSKZ.js");
100
+ const { isSupported, isLaunchAgentInstalled, needsLegacyMigration, installLaunchAgent } = await import("./launchd-6AWT54HR.js");
99
101
  if (isSupported() && (!isLaunchAgentInstalled() || needsLegacyMigration())) {
100
102
  const migrating = needsLegacyMigration();
101
103
  installLaunchAgent();
@@ -109,7 +111,7 @@ async function runInit(args) {
109
111
  } catch {
110
112
  }
111
113
  try {
112
- const { installMcpServer, installMemoryMcpServer } = await import("./mcp-installer-NQCGKQ23.js");
114
+ const { installMcpServer, installMemoryMcpServer, installGatewayMcpServer, installMcpForAllClis } = await import("./mcp-installer-PQU3XOGO.js");
113
115
  const codemapMcp = installMcpServer(projectDir);
114
116
  if (codemapMcp.installed) {
115
117
  console.log(chalk.green("\u2713 CodeMap MCP server registered"));
@@ -118,11 +120,40 @@ async function runInit(args) {
118
120
  if (memoryMcp.installed) {
119
121
  console.log(chalk.green("\u2713 Memory MCP server registered"));
120
122
  }
123
+ const gatewayMcp = installGatewayMcpServer(projectDir);
124
+ if (gatewayMcp.installed) {
125
+ console.log(chalk.green("\u2713 MCP Gateway registered"));
126
+ }
127
+ const cliResults = installMcpForAllClis(projectDir);
128
+ for (const result of cliResults) {
129
+ console.log(chalk.green(`\u2713 ${result.cli} MCP configured (${result.file})`));
130
+ }
131
+ } catch {
132
+ }
133
+ try {
134
+ const { execFileSync: execFileSync2 } = await import("child_process");
135
+ try {
136
+ execFileSync2("which", ["kiro"], { encoding: "utf-8", timeout: 5e3 });
137
+ const { installKiroHooks, installKiroSkills } = await import("./dist-6X576SU2.js");
138
+ const { convertClaudeSkillsToKiro } = await import("./dist-HA74OKJZ.js");
139
+ const { agent } = installKiroHooks("agent");
140
+ console.log(chalk.green(`\u2713 Kiro governance agent installed: ${agent}`));
141
+ const skillCount = installKiroSkills(projectDir);
142
+ if (skillCount > 0) {
143
+ console.log(chalk.green(`\u2713 ${skillCount} Kiro bundled skill(s) installed`));
144
+ }
145
+ const converted = convertClaudeSkillsToKiro(projectDir);
146
+ if (converted > 0) {
147
+ console.log(chalk.green(`\u2713 ${converted} Claude Code skill(s) converted to Kiro format`));
148
+ }
149
+ console.log(chalk.dim(" Start Kiro with: kiro --agent ulpi-governance"));
150
+ } catch {
151
+ }
121
152
  } catch {
122
153
  }
123
154
  try {
124
- const { runInitPipeline } = await import("./dist-CB5D5LMO.js");
125
- const { initMemoryBranch } = await import("./dist-GJYT2OQV.js");
155
+ const { runInitPipeline } = await import("./dist-YFFG2ZD6.js");
156
+ const { initMemoryBranch } = await import("./dist-JLU26AB6.js");
126
157
  console.log(chalk.cyan("\nInitializing code index..."));
127
158
  try {
128
159
  await runInitPipeline(projectDir, (progress) => {
@@ -143,6 +174,41 @@ async function runInit(args) {
143
174
  }
144
175
  } catch {
145
176
  }
177
+ try {
178
+ const { collectProjectSignals } = await import("./dist-EK45QNEM.js");
179
+ const { suggestMcps, getCatalogEntry, addToLibrary, enableMcp } = await import("./dist-EK45QNEM.js");
180
+ const signals = collectProjectSignals(projectDir);
181
+ const suggestions = suggestMcps(signals);
182
+ const actionable = suggestions.filter((s) => !s.alreadyAdded && (s.confidence === "high" || s.confidence === "medium"));
183
+ if (actionable.length > 0) {
184
+ console.log(chalk.cyan("\nDetecting MCP tools for your project..."));
185
+ let added = 0;
186
+ for (const suggestion of actionable) {
187
+ const entry = getCatalogEntry(suggestion.name);
188
+ if (!entry) continue;
189
+ addToLibrary(entry.name, {
190
+ name: entry.name,
191
+ display_name: entry.display_name,
192
+ description: entry.description,
193
+ command: entry.command ?? "npx",
194
+ args: entry.args ?? [],
195
+ transport: entry.transport ?? "stdio",
196
+ category: entry.category ?? "custom",
197
+ config_schema: entry.config_schema,
198
+ tags: entry.tags ?? [],
199
+ source: "catalog"
200
+ });
201
+ enableMcp(projectDir, entry.name);
202
+ console.log(` ${chalk.green("\u2713")} ${suggestion.displayName} (${suggestion.confidence}) \u2014 ${suggestion.evidence.join(", ")}`);
203
+ added++;
204
+ }
205
+ if (added > 0) {
206
+ console.log(chalk.dim(`Added ${added} MCP tool(s) to library and enabled for this repo.`));
207
+ console.log(chalk.dim(`Run 'ulpi mcp status' to see enabled MCPs.`));
208
+ }
209
+ }
210
+ } catch {
211
+ }
146
212
  const config = buildStackConfig(stack, projectDir);
147
213
  let generated = false;
148
214
  if (!noAi) {
@@ -155,7 +221,7 @@ async function runInit(args) {
155
221
  generateFromTemplates(projectDir, rulesPath, stack, config);
156
222
  }
157
223
  try {
158
- registerProject(projectDir, {
224
+ registerRepo(projectDir, {
159
225
  name: config.name,
160
226
  hooksInstalled: true,
161
227
  configStatus: "configured",
@@ -0,0 +1,376 @@
1
+ import {
2
+ JOBS_DIR,
3
+ jobFile
4
+ } from "./chunk-C7CLUQI6.js";
5
+ import "./chunk-4VNS5WPM.js";
6
+
7
+ // src/commands/job.ts
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+ import chalk from "chalk";
11
+ function getFlag(args, flag) {
12
+ const idx = args.indexOf(flag);
13
+ if (idx !== -1 && idx + 1 < args.length) {
14
+ return args[idx + 1];
15
+ }
16
+ return void 0;
17
+ }
18
+ function hasFlag(args, flag) {
19
+ return args.includes(flag);
20
+ }
21
+ function generateJobId() {
22
+ const ts = Date.now().toString(36);
23
+ const rand = Math.random().toString(36).slice(2, 6);
24
+ return `job-${ts}-${rand}`;
25
+ }
26
+ function loadJob(jobId) {
27
+ const filePath = jobFile(jobId);
28
+ if (!fs.existsSync(filePath)) return null;
29
+ try {
30
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+ function saveJob(job) {
36
+ fs.mkdirSync(JOBS_DIR, { recursive: true });
37
+ fs.writeFileSync(jobFile(job.id), JSON.stringify(job, null, 2), "utf-8");
38
+ }
39
+ function listAllJobs() {
40
+ if (!fs.existsSync(JOBS_DIR)) return [];
41
+ const files = fs.readdirSync(JOBS_DIR).filter((f) => f.endsWith(".json"));
42
+ const jobs = [];
43
+ for (const file of files) {
44
+ try {
45
+ const raw = fs.readFileSync(path.join(JOBS_DIR, file), "utf-8");
46
+ jobs.push(JSON.parse(raw));
47
+ } catch {
48
+ }
49
+ }
50
+ jobs.sort(
51
+ (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
52
+ );
53
+ return jobs;
54
+ }
55
+ async function runJobCommand(args, projectDir) {
56
+ const subcommand = args[0];
57
+ switch (subcommand) {
58
+ case "create":
59
+ return await createSubcommand(args.slice(1), projectDir);
60
+ case "list":
61
+ return listSubcommand();
62
+ case "status":
63
+ return statusSubcommand(args.slice(1));
64
+ case "cancel":
65
+ return cancelSubcommand(args.slice(1));
66
+ case "logs":
67
+ return logsSubcommand(args.slice(1));
68
+ default:
69
+ printHelp();
70
+ }
71
+ }
72
+ function printHelp() {
73
+ console.log(`
74
+ Usage: ulpi job <subcommand> [options]
75
+
76
+ Subcommands:
77
+ create [options] Create and start a new job
78
+ list List all jobs
79
+ status <job-id> Show status of a specific job
80
+ cancel <job-id> Cancel a running job
81
+ logs <job-id> Show job logs
82
+
83
+ Create options:
84
+ --tasks <file> Task file (JSON)
85
+ --branch <name> Source branch
86
+ --agent <name> Agent override (default: claude)
87
+ --tracker <name> Tracker plugin (default: json)
88
+ --auto-commit Auto-commit after task completion
89
+ --jira-sprint <id> Import from Jira sprint (Phase 2)
90
+ `.trim());
91
+ }
92
+ async function createSubcommand(args, projectDir) {
93
+ const tasksFile = getFlag(args, "--tasks");
94
+ const branch = getFlag(args, "--branch");
95
+ const agentName = getFlag(args, "--agent") ?? "claude";
96
+ const trackerName = getFlag(args, "--tracker") ?? "json";
97
+ const autoCommit = hasFlag(args, "--auto-commit");
98
+ const jiraSprint = getFlag(args, "--jira-sprint");
99
+ if (jiraSprint) {
100
+ console.log(
101
+ chalk.yellow("Jira sprint import is not yet available (Phase 2).")
102
+ );
103
+ return;
104
+ }
105
+ if (trackerName === "json") {
106
+ const resolvedTasks = tasksFile ? path.resolve(tasksFile) : path.join(projectDir, "tasks.json");
107
+ if (!fs.existsSync(resolvedTasks)) {
108
+ console.error(
109
+ chalk.red(
110
+ `Tasks file not found: ${resolvedTasks}
111
+ Create a tasks.json or specify one with --tasks <file>`
112
+ )
113
+ );
114
+ process.exit(1);
115
+ }
116
+ }
117
+ if (branch) {
118
+ try {
119
+ const { execFileSync } = await import("child_process");
120
+ execFileSync("git", ["rev-parse", "--verify", branch], {
121
+ cwd: projectDir,
122
+ encoding: "utf-8",
123
+ timeout: 5e3
124
+ });
125
+ } catch {
126
+ console.error(chalk.red(`Branch '${branch}' does not exist.`));
127
+ process.exit(1);
128
+ }
129
+ }
130
+ const jobId = generateJobId();
131
+ const job = {
132
+ id: jobId,
133
+ status: "pending",
134
+ agentName,
135
+ trackerName,
136
+ workingDir: projectDir,
137
+ tasksFile: tasksFile ? path.resolve(tasksFile) : void 0,
138
+ sourceBranch: branch,
139
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
140
+ completedTasks: 0,
141
+ failedTasks: 0,
142
+ skippedTasks: 0,
143
+ totalTasks: 0
144
+ };
145
+ saveJob(job);
146
+ console.log(chalk.green(`Job created: ${chalk.bold(jobId)}`));
147
+ console.log(chalk.dim(` Agent: ${agentName}`));
148
+ console.log(chalk.dim(` Tracker: ${trackerName}`));
149
+ console.log(chalk.dim(` Dir: ${projectDir}`));
150
+ if (branch) {
151
+ console.log(chalk.dim(` Branch: ${branch}`));
152
+ }
153
+ if (autoCommit) {
154
+ console.log(chalk.dim(` Auto-commit: enabled`));
155
+ }
156
+ console.log();
157
+ const { ExecutionEngine } = await import("./dist-2BJYR5EI.js");
158
+ const trackerConfig = {};
159
+ if (trackerName === "json") {
160
+ trackerConfig.path = tasksFile ? path.resolve(tasksFile) : path.join(projectDir, "tasks.json");
161
+ }
162
+ const engineConfig = {
163
+ agentName,
164
+ trackerName,
165
+ trackerConfig,
166
+ workingDir: projectDir,
167
+ sourceBranch: branch,
168
+ maxRetries: 3,
169
+ retryDelayMs: 5e3,
170
+ autoCommit,
171
+ timeout: 0,
172
+ maxIterations: 0,
173
+ iterationDelayMs: 0,
174
+ errorStrategy: "retry",
175
+ rateLimit: {
176
+ enabled: true,
177
+ maxRetries: 3,
178
+ baseBackoffMs: 5e3,
179
+ recoverPrimaryBetweenIterations: true
180
+ },
181
+ agentConfig: {}
182
+ };
183
+ const engine = new ExecutionEngine(engineConfig);
184
+ job.status = "running";
185
+ job.startedAt = (/* @__PURE__ */ new Date()).toISOString();
186
+ saveJob(job);
187
+ let stopping = false;
188
+ const sigHandler = async () => {
189
+ if (stopping) {
190
+ process.exit(1);
191
+ }
192
+ stopping = true;
193
+ console.log(chalk.yellow("\nInterrupted. Stopping job..."));
194
+ await engine.stop();
195
+ job.status = "cancelled";
196
+ job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
197
+ const state = engine.getState();
198
+ job.completedTasks = state.completedTasks.length;
199
+ job.failedTasks = state.failedTasks.length;
200
+ job.skippedTasks = state.skippedTasks.length;
201
+ saveJob(job);
202
+ };
203
+ process.on("SIGINT", sigHandler);
204
+ engine.on((event) => {
205
+ if (event.type === "task:completed") {
206
+ job.completedTasks++;
207
+ saveJob(job);
208
+ } else if (event.type === "task:failed") {
209
+ job.failedTasks++;
210
+ saveJob(job);
211
+ } else if (event.type === "task:skipped") {
212
+ job.skippedTasks++;
213
+ saveJob(job);
214
+ } else if (event.type === "engine:started") {
215
+ job.totalTasks = event.totalTasks;
216
+ saveJob(job);
217
+ }
218
+ });
219
+ try {
220
+ await engine.initialize();
221
+ await engine.start();
222
+ job.status = "completed";
223
+ job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
224
+ const state = engine.getState();
225
+ job.completedTasks = state.completedTasks.length;
226
+ job.failedTasks = state.failedTasks.length;
227
+ job.skippedTasks = state.skippedTasks.length;
228
+ saveJob(job);
229
+ console.log(chalk.green(`
230
+ Job ${jobId} completed.`));
231
+ } catch (err) {
232
+ job.status = "failed";
233
+ job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
234
+ job.error = err instanceof Error ? err.message : String(err);
235
+ saveJob(job);
236
+ console.error(
237
+ chalk.red(
238
+ `
239
+ Job ${jobId} failed: ${err instanceof Error ? err.message : String(err)}`
240
+ )
241
+ );
242
+ process.exit(1);
243
+ } finally {
244
+ process.removeListener("SIGINT", sigHandler);
245
+ }
246
+ }
247
+ function listSubcommand() {
248
+ const jobs = listAllJobs();
249
+ if (jobs.length === 0) {
250
+ console.log(chalk.dim("No jobs found."));
251
+ return;
252
+ }
253
+ console.log(chalk.bold("Jobs"));
254
+ console.log(chalk.dim("\u2500".repeat(80)));
255
+ for (const job of jobs) {
256
+ const statusColor = job.status === "completed" ? chalk.green : job.status === "running" ? chalk.blue : job.status === "failed" ? chalk.red : job.status === "cancelled" ? chalk.yellow : chalk.dim;
257
+ const age = formatAge(job.createdAt);
258
+ console.log(
259
+ ` ${chalk.bold(job.id)} ${statusColor(job.status.padEnd(10))} ${chalk.cyan(job.agentName)} ${job.completedTasks}/${job.totalTasks} tasks ${chalk.dim(age)}`
260
+ );
261
+ }
262
+ console.log(chalk.dim("\u2500".repeat(80)));
263
+ }
264
+ function statusSubcommand(args) {
265
+ const jobId = args[0];
266
+ if (!jobId) {
267
+ console.error(chalk.red("Usage: ulpi job status <job-id>"));
268
+ process.exit(1);
269
+ }
270
+ const job = loadJob(jobId);
271
+ if (!job) {
272
+ console.error(chalk.red(`Job not found: ${jobId}`));
273
+ process.exit(1);
274
+ }
275
+ console.log(chalk.bold(`Job: ${job.id}`));
276
+ console.log(chalk.dim("\u2500".repeat(40)));
277
+ console.log(` Status: ${formatStatus(job.status)}`);
278
+ console.log(` Agent: ${chalk.cyan(job.agentName)}`);
279
+ console.log(` Tracker: ${chalk.cyan(job.trackerName)}`);
280
+ console.log(` Directory: ${chalk.dim(job.workingDir)}`);
281
+ if (job.sourceBranch) {
282
+ console.log(` Branch: ${job.sourceBranch}`);
283
+ }
284
+ console.log(` Created: ${job.createdAt}`);
285
+ if (job.startedAt) {
286
+ console.log(` Started: ${job.startedAt}`);
287
+ }
288
+ if (job.completedAt) {
289
+ console.log(` Finished: ${job.completedAt}`);
290
+ }
291
+ console.log();
292
+ console.log(` Tasks: ${job.completedTasks}/${job.totalTasks} completed`);
293
+ if (job.failedTasks > 0) {
294
+ console.log(` Failed: ${chalk.red(String(job.failedTasks))}`);
295
+ }
296
+ if (job.skippedTasks > 0) {
297
+ console.log(` Skipped: ${chalk.yellow(String(job.skippedTasks))}`);
298
+ }
299
+ if (job.error) {
300
+ console.log(` Error: ${chalk.red(job.error)}`);
301
+ }
302
+ console.log(chalk.dim("\u2500".repeat(40)));
303
+ }
304
+ function cancelSubcommand(args) {
305
+ const jobId = args[0];
306
+ if (!jobId) {
307
+ console.error(chalk.red("Usage: ulpi job cancel <job-id>"));
308
+ process.exit(1);
309
+ }
310
+ const job = loadJob(jobId);
311
+ if (!job) {
312
+ console.error(chalk.red(`Job not found: ${jobId}`));
313
+ process.exit(1);
314
+ }
315
+ if (job.status !== "running" && job.status !== "pending") {
316
+ console.log(
317
+ chalk.yellow(`Job ${jobId} is not running (status: ${job.status})`)
318
+ );
319
+ return;
320
+ }
321
+ job.status = "cancelled";
322
+ job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
323
+ saveJob(job);
324
+ console.log(chalk.yellow(`Job ${jobId} cancelled.`));
325
+ }
326
+ function logsSubcommand(args) {
327
+ const jobId = args[0];
328
+ if (!jobId) {
329
+ console.error(chalk.red("Usage: ulpi job logs <job-id>"));
330
+ process.exit(1);
331
+ }
332
+ const job = loadJob(jobId);
333
+ if (!job) {
334
+ console.error(chalk.red(`Job not found: ${jobId}`));
335
+ process.exit(1);
336
+ }
337
+ console.log(chalk.bold(`Logs for job: ${job.id}`));
338
+ console.log(chalk.dim("\u2500".repeat(40)));
339
+ console.log(chalk.dim("Job log streaming is not yet implemented."));
340
+ console.log(chalk.dim(`Job status: ${job.status}`));
341
+ console.log(chalk.dim(`Tasks: ${job.completedTasks}/${job.totalTasks}`));
342
+ if (job.error) {
343
+ console.log(chalk.red(`Error: ${job.error}`));
344
+ }
345
+ console.log(chalk.dim("\u2500".repeat(40)));
346
+ }
347
+ function formatStatus(status) {
348
+ switch (status) {
349
+ case "completed":
350
+ return chalk.green(status);
351
+ case "running":
352
+ return chalk.blue(status);
353
+ case "failed":
354
+ return chalk.red(status);
355
+ case "cancelled":
356
+ return chalk.yellow(status);
357
+ case "pending":
358
+ return chalk.dim(status);
359
+ default:
360
+ return status;
361
+ }
362
+ }
363
+ function formatAge(isoDate) {
364
+ const ms = Date.now() - new Date(isoDate).getTime();
365
+ const seconds = Math.floor(ms / 1e3);
366
+ if (seconds < 60) return `${seconds}s ago`;
367
+ const minutes = Math.floor(seconds / 60);
368
+ if (minutes < 60) return `${minutes}m ago`;
369
+ const hours = Math.floor(minutes / 60);
370
+ if (hours < 24) return `${hours}h ago`;
371
+ const days = Math.floor(hours / 24);
372
+ return `${days}d ago`;
373
+ }
374
+ export {
375
+ runJobCommand
376
+ };
@@ -0,0 +1,33 @@
1
+ import {
2
+ readEventLogs
3
+ } from "./chunk-4XTHZVDS.js";
4
+ import "./chunk-C7CLUQI6.js";
5
+ import "./chunk-4VNS5WPM.js";
6
+
7
+ // ../api/dist/jobs.memory-PLMMSFHB.js
8
+ async function captureAndClassifyJob(projectDir, jobId, mode, agentName, job) {
9
+ const { captureJobForClassification, isMemoryEnabled } = await import("./dist-JLU26AB6.js");
10
+ if (!isMemoryEnabled(projectDir)) return;
11
+ const events = readEventLogs(jobId);
12
+ if (events.length === 0) return;
13
+ captureJobForClassification(projectDir, jobId, events, {
14
+ jobId,
15
+ mode,
16
+ agentName,
17
+ startedAt: job.startedAt ?? job.createdAt,
18
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
19
+ tasksCompleted: job.completedTasks?.length ?? 0,
20
+ tasksFailed: job.failedTasks?.length ?? 0,
21
+ totalIterations: events.filter((e) => e.type === "iteration:started").length
22
+ });
23
+ const { spawn } = await import("child_process");
24
+ const child = spawn(
25
+ process.execPath,
26
+ [process.argv[1], "memory", "classify", "-p", projectDir, "--session", jobId],
27
+ { detached: true, stdio: "ignore", env: { ...process.env, ULPI_BG_CLASSIFY: "1" } }
28
+ );
29
+ child.unref();
30
+ }
31
+ export {
32
+ captureAndClassifyJob
33
+ };