@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.
- package/LICENSE +21 -0
- package/dist/{auth-PN7TMQHV-2W4ICG64.js → auth-FWM7MM4Q-VZC3U2XZ.js} +1 -1
- package/dist/{auth-ECQ3IB4E.js → auth-HDK7ECJL.js} +2 -1
- package/dist/{chunk-3SBPZRB5.js → chunk-3BCW6ABU.js} +402 -142
- package/dist/{chunk-JGBXM5NC.js → chunk-3WB5CXH4.js} +180 -5
- package/dist/{chunk-2HEE5OKX.js → chunk-4UCJIAOU.js} +2 -2
- package/dist/chunk-4XTHZVDS.js +109 -0
- package/dist/chunk-4ZPOZULQ.js +6522 -0
- package/dist/{chunk-SIAQVRKG.js → chunk-5MI5GIXM.js} +48 -2
- package/dist/{chunk-KLEASXUR.js → chunk-6ZL6NXMV.js} +1 -1
- package/dist/chunk-76D3BYJD.js +221 -0
- package/dist/{chunk-ZLYRPD7I.js → chunk-AWOSRA5F.js} +1 -1
- package/dist/{chunk-PDR55ZNW.js → chunk-BFEKZZHM.js} +274 -57
- package/dist/chunk-C7CLUQI6.js +1286 -0
- package/dist/{chunk-7AL4DOEJ.js → chunk-E3B5NROU.js} +7 -7
- package/dist/chunk-EJ7TW77N.js +1418 -0
- package/dist/{chunk-5J6NLQUN.js → chunk-IV6MWETF.js} +383 -168
- package/dist/chunk-IZPJHSPX.js +1478 -0
- package/dist/chunk-JLHNLM3C.js +228 -0
- package/dist/{chunk-BZL5H4YQ.js → chunk-KYYI23AQ.js} +2 -2
- package/dist/{chunk-2CLNOKPA.js → chunk-RSFJ6QSR.js} +18 -0
- package/dist/chunk-S6ANCSYO.js +1271 -0
- package/dist/chunk-SEU7WWNQ.js +1251 -0
- package/dist/chunk-SNQ7NAIS.js +453 -0
- package/dist/{ulpi-RMMCUAGP-JCJ273T6.js → chunk-TSLDGT5O.js} +73 -35
- package/dist/{chunk-SPOI23SB.js → chunk-UXHCHOWQ.js} +83 -62
- package/dist/chunk-V2H5D6Y3.js +146 -0
- package/dist/{chunk-QJ5GSMEC.js → chunk-VVEDXI7E.js} +2 -1
- package/dist/chunk-VXH5Y4FO.js +6761 -0
- package/dist/chunk-WED4LM5N.js +322 -0
- package/dist/{chunk-74WVVWJ4.js → chunk-YOKL7RB5.js} +184 -15
- package/dist/chunk-Z53CAR7G.js +298 -0
- package/dist/ci-X3U2W4HC.js +854 -0
- package/dist/cloud-2F3NLVHN.js +274 -0
- package/dist/{codemap-RKSD4MIE.js → codemap-XNGMAF3F.js} +37 -37
- package/dist/codex-MB5YTMRT.js +132 -0
- package/dist/{config-EGAXXCGL.js → config-OOELBYTH.js} +1 -1
- package/dist/dist-2BJYR5EI.js +59 -0
- package/dist/dist-2K7IEVTA.js +43 -0
- package/dist/dist-3EIQTZHT.js +1380 -0
- package/dist/{dist-YA2BWZB2.js → dist-4U5L2X2C.js} +2 -2
- package/dist/{dist-UKMCJBB2.js → dist-54KAMNLO.js} +16 -15
- package/dist/dist-6M4MZWZW.js +58 -0
- package/dist/dist-6X576SU2.js +27 -0
- package/dist/dist-7QOEYLFX.js +103 -0
- package/dist/dist-AYBGHEDY.js +2541 -0
- package/dist/dist-EK45QNEM.js +45 -0
- package/dist/{dist-CS2VKNYS.js → dist-FKFEJRPX.js} +16 -15
- package/dist/dist-GTEJUBBT.js +66 -0
- package/dist/dist-HA74OKJZ.js +40 -0
- package/dist/dist-HU5RZAON.js +48 -0
- package/dist/dist-IYE3OBRB.js +374 -0
- package/dist/{dist-GJYT2OQV.js → dist-JLU26AB6.js} +12 -9
- package/dist/{dist-6G7JC2RA.js → dist-KUCI6JFE.js} +49 -9
- package/dist/dist-NUEMFZFL.js +33 -0
- package/dist/{dist-RKOGLK7R.js → dist-NUXMDXZ3.js} +31 -3
- package/dist/{dist-QAU3LGJN.js → dist-YCNWHSLN.js} +15 -5
- package/dist/{dist-CB5D5LMO.js → dist-YFFG2ZD6.js} +9 -16
- package/dist/dist-ZG4OKCSR.js +15 -0
- package/dist/doctor-SI4LLLDZ.js +345 -0
- package/dist/{export-import-4A5MWLIA.js → export-import-JFQH4KSJ.js} +1 -1
- package/dist/{history-3MOBX4MA.js → history-5NE46ZAH.js} +7 -7
- package/dist/hooks-installer-UN5JZLDQ.js +19 -0
- package/dist/index.js +395 -619
- package/dist/{init-6CH4HV5T.js → init-5FK3VKRT.js} +79 -13
- package/dist/job-HIDMAFW2.js +376 -0
- package/dist/jobs.memory-PLMMSFHB-VBECCTHN.js +33 -0
- package/dist/kiro-VMUHDFGK.js +153 -0
- package/dist/{launchd-LF2QMSKZ.js → launchd-6AWT54HR.js} +9 -17
- package/dist/mcp-PDUD7SGP.js +249 -0
- package/dist/mcp-installer-PQU3XOGO.js +259 -0
- package/dist/mcp-setup-OA7IB3H3.js +263 -0
- package/dist/{memory-Y6OZTXJ2.js → memory-ZNAEAK3B.js} +17 -17
- package/dist/{ollama-3XCUZMZT-FYKHW4TZ.js → ollama-3XCUZMZT-4JMH6B7P.js} +1 -1
- package/dist/{openai-E7G2YAHU-UYY4ZWON.js → openai-E7G2YAHU-T3HMBPH7.js} +2 -2
- package/dist/portal-JYWVHXDU.js +210 -0
- package/dist/prd-Q4J5NVAR.js +408 -0
- package/dist/repos-WWZXNN3P.js +271 -0
- package/dist/review-integration-5WHEJU2A.js +14 -0
- package/dist/{rules-E427DKYJ.js → rules-Y4VSOY5Y.js} +3 -3
- package/dist/run-VPNXEIBY.js +687 -0
- package/dist/server-COL4AXKU-P7S7NNF6.js +11 -0
- package/dist/server-KKSETHDV-XSSLEENT.js +20 -0
- package/dist/{skills-CX73O3IV.js → skills-QEYU2N27.js} +4 -2
- package/dist/start-JYOEL7AJ.js +303 -0
- package/dist/{status-4DFHDJMN.js → status-BHQYYGAL.js} +2 -2
- package/dist/{templates-U7T6MARD.js → templates-CBRUJ66V.js} +4 -3
- package/dist/tui-DP7736EX.js +61 -0
- package/dist/ulpi-5EN6JCAS-LFE3WSL4.js +10 -0
- package/dist/{uninstall-6SW35IK4.js → uninstall-ICUV6DDV.js} +3 -3
- package/dist/{update-M6IBJNYP.js → update-7ZMAYRBH.js} +3 -3
- package/dist/{version-checker-Q6YTYAGP.js → version-checker-4ZFMZA7Y.js} +2 -2
- package/package.json +39 -31
- package/dist/chunk-2MZER6ND.js +0 -415
- package/dist/chunk-2VYFVYJL.js +0 -4273
- package/dist/chunk-6OCEY7JY.js +0 -422
- package/dist/chunk-7LXY5UVC.js +0 -330
- package/dist/chunk-B55DDP24.js +0 -136
- package/dist/chunk-JWUUVXIV.js +0 -13694
- package/dist/chunk-MIAQVCFW.js +0 -39
- package/dist/chunk-YM2HV4IA.js +0 -505
- package/dist/ci-STSL2LSP.js +0 -370
- package/dist/mcp-installer-NQCGKQ23.js +0 -124
- package/dist/projects-ATHDD3D6.js +0 -271
- package/dist/review-ADUPV3PN.js +0 -152
- package/dist/server-USLHY6GH-AEOJC5ST.js +0 -18
- package/dist/server-X5P6WH2M-7K2RY34N.js +0 -11
- package/dist/skills/ulpi-generate-guardian/SKILL.md +0 -750
- package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +0 -849
- package/dist/skills/ulpi-generate-guardian/references/language-rules.md +0 -591
- package/dist/ui-OWXZ3YSR.js +0 -167
- package/dist/ui.html +0 -698
|
@@ -2,24 +2,26 @@ import {
|
|
|
2
2
|
installGlobalSkill,
|
|
3
3
|
installHooks,
|
|
4
4
|
installLocalSkill
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VVEDXI7E.js";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
125
|
-
const { initMemoryBranch } = await import("./dist-
|
|
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
|
-
|
|
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
|
+
};
|