@ulpi/cli 0.1.4 → 0.1.5

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 (57) hide show
  1. package/dist/{auth-ECQ3IB4E.js → auth-BFFBUJUC.js} +1 -1
  2. package/dist/{chunk-YM2HV4IA.js → chunk-26LLDX2T.js} +50 -2
  3. package/dist/{chunk-QJ5GSMEC.js → chunk-5SCG7UYM.js} +2 -1
  4. package/dist/{chunk-5J6NLQUN.js → chunk-6OURRFP7.js} +8 -8
  5. package/dist/chunk-AV5RB3N2.js +173 -0
  6. package/dist/{chunk-7LXY5UVC.js → chunk-DDRLI6JU.js} +2 -1
  7. package/dist/{chunk-ZLYRPD7I.js → chunk-DOIKS6C5.js} +1 -1
  8. package/dist/{chunk-SPOI23SB.js → chunk-EIWYSP3A.js} +1 -1
  9. package/dist/{chunk-7AL4DOEJ.js → chunk-ELTGWMDE.js} +3 -3
  10. package/dist/{chunk-6OCEY7JY.js → chunk-IFATANHR.js} +34 -3
  11. package/dist/{chunk-2HEE5OKX.js → chunk-K4OVPFY2.js} +1 -1
  12. package/dist/{chunk-JGBXM5NC.js → chunk-L3PWNHSA.js} +2 -2
  13. package/dist/{chunk-2VYFVYJL.js → chunk-LD52XG3X.js} +24 -24
  14. package/dist/{chunk-BZL5H4YQ.js → chunk-P2RESJRN.js} +2 -2
  15. package/dist/{chunk-3SBPZRB5.js → chunk-RJIRWQJD.js} +1 -1
  16. package/dist/{chunk-2CLNOKPA.js → chunk-RSFJ6QSR.js} +18 -0
  17. package/dist/{chunk-PDR55ZNW.js → chunk-UCMT5OKP.js} +4 -4
  18. package/dist/{chunk-2MZER6ND.js → chunk-YYZOFYS6.js} +2 -2
  19. package/dist/ci-JQ56YIKC.js +756 -0
  20. package/dist/{codemap-RKSD4MIE.js → codemap-HMYBXJL2.js} +36 -36
  21. package/dist/{config-EGAXXCGL.js → config-YYWEN7U2.js} +1 -1
  22. package/dist/dist-2K7IEVTA.js +43 -0
  23. package/dist/{dist-UKMCJBB2.js → dist-4XTJ6HLM.js} +7 -7
  24. package/dist/{dist-QAU3LGJN.js → dist-5R4RYNQO.js} +3 -3
  25. package/dist/{dist-CB5D5LMO.js → dist-6MFVWIFF.js} +8 -8
  26. package/dist/{dist-GJYT2OQV.js → dist-7WLLPWWB.js} +8 -8
  27. package/dist/{dist-RKOGLK7R.js → dist-GWGTAHNM.js} +1 -1
  28. package/dist/{dist-CS2VKNYS.js → dist-U7ZIJMZD.js} +8 -8
  29. package/dist/{dist-YA2BWZB2.js → dist-WAMAQVPK.js} +2 -2
  30. package/dist/dist-XD4YI27T.js +26 -0
  31. package/dist/dist-XG2GG5SD.js +36 -0
  32. package/dist/{history-3MOBX4MA.js → history-RNUWO4JZ.js} +7 -7
  33. package/dist/hooks-installer-K2JXEBNN.js +19 -0
  34. package/dist/index.js +42 -42
  35. package/dist/{init-6CH4HV5T.js → init-NQWFZPKO.js} +11 -11
  36. package/dist/{launchd-LF2QMSKZ.js → launchd-OYXUAVW6.js} +2 -2
  37. package/dist/{mcp-installer-NQCGKQ23.js → mcp-installer-TOYDP77X.js} +1 -1
  38. package/dist/{memory-Y6OZTXJ2.js → memory-D6ZFFCI2.js} +17 -17
  39. package/dist/{openai-E7G2YAHU-UYY4ZWON.js → openai-E7G2YAHU-IG33BFYF.js} +2 -2
  40. package/dist/{projects-ATHDD3D6.js → projects-COUJP4ZC.js} +3 -3
  41. package/dist/{review-ADUPV3PN.js → review-KMGP2S25.js} +2 -2
  42. package/dist/{rules-E427DKYJ.js → rules-3OFGWHP4.js} +1 -1
  43. package/dist/server-USLHY6GH-F4JSXCWA.js +18 -0
  44. package/dist/server-X5P6WH2M-ULZF5WHZ.js +11 -0
  45. package/dist/{skills-CX73O3IV.js → skills-GY2CTPWN.js} +2 -2
  46. package/dist/{status-4DFHDJMN.js → status-SE43TIFJ.js} +2 -2
  47. package/dist/{templates-U7T6MARD.js → templates-O2XDKB5R.js} +5 -5
  48. package/dist/{ui-OWXZ3YSR.js → ui-4SM2SUI6.js} +13 -13
  49. package/dist/{ulpi-RMMCUAGP-JCJ273T6.js → ulpi-RMMCUAGP-EWYUE7RU.js} +1 -1
  50. package/dist/{uninstall-6SW35IK4.js → uninstall-KWGSGZTI.js} +3 -3
  51. package/dist/{update-M6IBJNYP.js → update-QYZA4D23.js} +3 -3
  52. package/dist/{version-checker-Q6YTYAGP.js → version-checker-MVB74DEX.js} +2 -2
  53. package/package.json +1 -1
  54. package/dist/chunk-B55DDP24.js +0 -136
  55. package/dist/ci-STSL2LSP.js +0 -370
  56. package/dist/server-USLHY6GH-AEOJC5ST.js +0 -18
  57. package/dist/server-X5P6WH2M-7K2RY34N.js +0 -11
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  checkForUpdates
3
- } from "./chunk-BZL5H4YQ.js";
3
+ } from "./chunk-P2RESJRN.js";
4
4
  import {
5
5
  CLI_BIN_NAME,
6
6
  CLI_NPM_PACKAGE
7
- } from "./chunk-7LXY5UVC.js";
7
+ } from "./chunk-DDRLI6JU.js";
8
8
  import "./chunk-4VNS5WPM.js";
9
9
 
10
10
  // src/commands/update.ts
@@ -36,7 +36,7 @@ Run '${CLI_BIN_NAME} update' to install the update.`));
36
36
  console.log(chalk.green(`
37
37
  \u2713 Updated to v${info.latest}`));
38
38
  try {
39
- const { isSupported, isLaunchAgentInstalled, needsLegacyMigration, installLaunchAgent, restartLaunchAgent } = await import("./launchd-LF2QMSKZ.js");
39
+ const { isSupported, isLaunchAgentInstalled, needsLegacyMigration, installLaunchAgent, restartLaunchAgent } = await import("./launchd-OYXUAVW6.js");
40
40
  if (isSupported()) {
41
41
  if (needsLegacyMigration()) {
42
42
  installLaunchAgent();
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  checkForUpdates,
3
3
  getCurrentVersion
4
- } from "./chunk-BZL5H4YQ.js";
5
- import "./chunk-7LXY5UVC.js";
4
+ } from "./chunk-P2RESJRN.js";
5
+ import "./chunk-DDRLI6JU.js";
6
6
  import "./chunk-4VNS5WPM.js";
7
7
  export {
8
8
  checkForUpdates,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulpi/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "ulpi": "./dist/index.js"
@@ -1,136 +0,0 @@
1
- // ../../packages/ci-engine/dist/index.js
2
- import * as fs4 from "fs";
3
- import * as path3 from "path";
4
- import { execFileSync as execFileSync2 } from "child_process";
5
- function buildPrompt(config, context) {
6
- const sections = [];
7
- sections.push("# Task");
8
- sections.push("");
9
- sections.push(config.instruction);
10
- sections.push("");
11
- if (context.prTitle || context.prBody) {
12
- sections.push("# Pull Request Context");
13
- sections.push("");
14
- if (context.prTitle) sections.push(`**Title:** ${context.prTitle}`);
15
- if (context.prBody) {
16
- sections.push("");
17
- sections.push(context.prBody);
18
- }
19
- sections.push("");
20
- }
21
- sections.push("# Branch Info");
22
- sections.push("");
23
- sections.push(`- **Working branch:** ${config.ref}`);
24
- sections.push(`- **Base branch:** ${config.baseBranch}`);
25
- sections.push(`- **Repository:** ${config.repoFullName}`);
26
- sections.push("");
27
- if (config.jiraContext || context.jiraContext) {
28
- sections.push("# Jira Context");
29
- sections.push("");
30
- sections.push(config.jiraContext ?? context.jiraContext ?? "");
31
- sections.push("");
32
- }
33
- sections.push("# Important Instructions");
34
- sections.push("");
35
- sections.push(
36
- "- You are running in CI mode inside a worker container."
37
- );
38
- sections.push(
39
- "- Work on the existing branch \u2014 do NOT create new branches."
40
- );
41
- sections.push(
42
- "- Commit your changes with clear, descriptive commit messages."
43
- );
44
- sections.push("- Run tests if a test runner is configured.");
45
- sections.push(
46
- "- Do NOT push to the remote \u2014 the orchestrator will handle pushing."
47
- );
48
- sections.push("");
49
- return sections.join("\n");
50
- }
51
- var CREDENTIAL_FILES = [
52
- "oauth_token",
53
- ".credentials.json",
54
- "credentials.json",
55
- "auth.json"
56
- ];
57
- function extractCredentials(claudeConfigDir) {
58
- const configDir = claudeConfigDir ?? path3.join(process.env.HOME ?? "", ".claude");
59
- if (!fs4.existsSync(configDir)) {
60
- throw new Error(
61
- `Claude config directory not found: ${configDir}`
62
- );
63
- }
64
- const existingFiles = CREDENTIAL_FILES.filter(
65
- (f) => fs4.existsSync(path3.join(configDir, f))
66
- );
67
- if (existingFiles.length === 0) {
68
- throw new Error(
69
- `No credential files found in ${configDir}. Run 'claude login' first.`
70
- );
71
- }
72
- const tarOutput = execFileSync2(
73
- "tar",
74
- ["-czf", "-", "-C", configDir, ...existingFiles],
75
- {
76
- encoding: "buffer",
77
- timeout: 3e4,
78
- maxBuffer: 10 * 1024 * 1024
79
- // 10MB limit (credentials are tiny)
80
- }
81
- );
82
- return tarOutput.toString("base64");
83
- }
84
- function writeCredentials(blob, targetDir) {
85
- fs4.mkdirSync(targetDir, { recursive: true });
86
- const tarBuffer = Buffer.from(blob, "base64");
87
- execFileSync2("tar", ["-xzf", "-", "-C", targetDir], {
88
- input: tarBuffer,
89
- timeout: 3e4
90
- });
91
- }
92
- function validateCredentials(blob) {
93
- const tmpDir = fs4.mkdtempSync("/tmp/ulpi-claude-check-");
94
- try {
95
- writeCredentials(blob, tmpDir);
96
- const files = fs4.readdirSync(tmpDir);
97
- return files.length > 0;
98
- } catch {
99
- return false;
100
- } finally {
101
- try {
102
- fs4.rmSync(tmpDir, { recursive: true, force: true });
103
- } catch {
104
- }
105
- }
106
- }
107
- function getCredentialExpiry(blob) {
108
- const tmpDir = fs4.mkdtempSync("/tmp/ulpi-claude-expiry-");
109
- try {
110
- writeCredentials(blob, tmpDir);
111
- const authFile = path3.join(tmpDir, ".credentials.json");
112
- if (fs4.existsSync(authFile)) {
113
- try {
114
- const data = JSON.parse(
115
- fs4.readFileSync(authFile, "utf-8")
116
- );
117
- if (data.expiresAt) return data.expiresAt;
118
- if (data.expires_at) return data.expires_at;
119
- } catch {
120
- }
121
- }
122
- return void 0;
123
- } finally {
124
- try {
125
- fs4.rmSync(tmpDir, { recursive: true, force: true });
126
- } catch {
127
- }
128
- }
129
- }
130
-
131
- export {
132
- buildPrompt,
133
- extractCredentials,
134
- validateCredentials,
135
- getCredentialExpiry
136
- };
@@ -1,370 +0,0 @@
1
- import {
2
- buildPrompt
3
- } from "./chunk-B55DDP24.js";
4
- import {
5
- external_exports
6
- } from "./chunk-KIKPIH6N.js";
7
- import "./chunk-4VNS5WPM.js";
8
-
9
- // src/commands/ci.ts
10
- import * as fs from "fs";
11
- import * as path from "path";
12
- import { spawn, execFileSync } from "child_process";
13
- import chalk from "chalk";
14
-
15
- // ../../packages/contracts-ci/dist/index.js
16
- var CiCommandTypeSchema = external_exports.enum(["run", "cancel", "fork", "status"]);
17
- var CiCommandSchema = external_exports.object({
18
- type: CiCommandTypeSchema,
19
- instruction: external_exports.string().optional(),
20
- prNumber: external_exports.number().int().positive(),
21
- repoFullName: external_exports.string(),
22
- // "org/repo"
23
- commentId: external_exports.number().int().positive(),
24
- commentAuthor: external_exports.string(),
25
- forkName: external_exports.string().optional()
26
- });
27
- var JobStatusSchema = external_exports.enum([
28
- "queued",
29
- "provisioning",
30
- "running",
31
- "completing",
32
- "completed",
33
- "failed",
34
- "cancelled",
35
- "timed_out"
36
- ]);
37
- var JobConfigSchema = external_exports.object({
38
- repoUrl: external_exports.string().url(),
39
- ref: external_exports.string(),
40
- baseBranch: external_exports.string(),
41
- prNumber: external_exports.number().int().positive(),
42
- repoFullName: external_exports.string(),
43
- instruction: external_exports.string(),
44
- jiraContext: external_exports.string().optional(),
45
- timeoutMinutes: external_exports.number().int().positive().default(30),
46
- envVars: external_exports.record(external_exports.string()).optional()
47
- });
48
- var JobResultSchema = external_exports.object({
49
- jobId: external_exports.string(),
50
- status: JobStatusSchema,
51
- exitCode: external_exports.number().int().optional(),
52
- diff: external_exports.string().optional(),
53
- testOutput: external_exports.string().optional(),
54
- summary: external_exports.string().optional(),
55
- filesChanged: external_exports.array(external_exports.string()),
56
- sessionEvents: external_exports.number().int().default(0),
57
- durationMs: external_exports.number().int(),
58
- error: external_exports.string().optional()
59
- });
60
- var JobSchema = external_exports.object({
61
- id: external_exports.string(),
62
- config: JobConfigSchema,
63
- status: JobStatusSchema,
64
- result: JobResultSchema.optional(),
65
- containerId: external_exports.string().optional(),
66
- workspaceDir: external_exports.string().optional(),
67
- parentJobId: external_exports.string().optional(),
68
- createdAt: external_exports.string().datetime(),
69
- startedAt: external_exports.string().datetime().optional(),
70
- completedAt: external_exports.string().datetime().optional(),
71
- cancelledBy: external_exports.string().optional(),
72
- commentId: external_exports.number().int().positive(),
73
- commentAuthor: external_exports.string()
74
- });
75
- var GitHubAppAuthSchema = external_exports.object({
76
- appId: external_exports.string(),
77
- privateKeyPath: external_exports.string(),
78
- webhookSecret: external_exports.string(),
79
- installationId: external_exports.number().int().positive().optional()
80
- });
81
- var GitHubAuthConfigSchema = external_exports.discriminatedUnion("mode", [
82
- external_exports.object({ mode: external_exports.literal("app"), config: GitHubAppAuthSchema }),
83
- external_exports.object({ mode: external_exports.literal("pat"), token: external_exports.string() })
84
- ]);
85
- var JiraConfigSchema = external_exports.object({
86
- baseUrl: external_exports.string().url(),
87
- email: external_exports.string().email(),
88
- apiToken: external_exports.string(),
89
- defaultProject: external_exports.string().optional()
90
- });
91
- var DockerConfigSchema = external_exports.object({
92
- image: external_exports.string(),
93
- network: external_exports.string().optional(),
94
- memoryLimit: external_exports.string().optional(),
95
- // e.g. "4g"
96
- cpuLimit: external_exports.number().positive().optional(),
97
- // e.g. 2.0
98
- volumeBaseDir: external_exports.string(),
99
- // Host path — used for Docker bind mounts
100
- localVolumeBaseDir: external_exports.string().optional()
101
- // Container-local path — used for fs ops (defaults to volumeBaseDir)
102
- });
103
- var SecurityConfigSchema = external_exports.object({
104
- requireWriteAccess: external_exports.boolean().default(true),
105
- allowedRepos: external_exports.array(external_exports.string()).optional(),
106
- allowedAuthors: external_exports.array(external_exports.string()).optional(),
107
- allowedOrgs: external_exports.array(external_exports.string()).optional(),
108
- apiToken: external_exports.string(),
109
- rateLimitWebhook: external_exports.number().int().positive().default(60),
110
- rateLimitApi: external_exports.number().int().positive().default(200)
111
- });
112
- var OrchestratorConfigSchema = external_exports.object({
113
- github: GitHubAuthConfigSchema,
114
- jira: JiraConfigSchema.optional(),
115
- docker: DockerConfigSchema,
116
- jobs: external_exports.object({
117
- maxConcurrent: external_exports.number().int().positive().default(3),
118
- timeoutMinutes: external_exports.number().int().positive().default(30),
119
- retainCompletedHours: external_exports.number().int().positive().default(72)
120
- }),
121
- security: SecurityConfigSchema,
122
- port: external_exports.number().int().positive().default(3e3),
123
- host: external_exports.string().default("0.0.0.0")
124
- });
125
- var ClaudeCredentialsSchema = external_exports.object({
126
- blob: external_exports.string(),
127
- // base64-encoded credentials directory contents
128
- createdAt: external_exports.string().datetime(),
129
- expiresAt: external_exports.string().datetime().optional()
130
- });
131
- var WorkerInputSchema = external_exports.object({
132
- jobId: external_exports.string(),
133
- config: JobConfigSchema,
134
- claudeModel: external_exports.string().optional()
135
- });
136
- var WorkerOutputSchema = external_exports.object({
137
- jobId: external_exports.string(),
138
- result: JobResultSchema
139
- });
140
- var WorkerProgressSchema = external_exports.object({
141
- phase: external_exports.string(),
142
- message: external_exports.string(),
143
- timestamp: external_exports.string().datetime()
144
- });
145
- var JiraTicketSchema = external_exports.object({
146
- key: external_exports.string(),
147
- // e.g. "ABC-123"
148
- summary: external_exports.string(),
149
- description: external_exports.string().optional(),
150
- status: external_exports.string(),
151
- assignee: external_exports.string().optional(),
152
- priority: external_exports.string().optional(),
153
- labels: external_exports.array(external_exports.string()),
154
- acceptanceCriteria: external_exports.string().optional()
155
- });
156
- var JiraReferenceSchema = external_exports.object({
157
- key: external_exports.string(),
158
- url: external_exports.string().url()
159
- });
160
-
161
- // src/commands/ci.ts
162
- async function runCi(args, projectDir) {
163
- const subcommand = args[0];
164
- switch (subcommand) {
165
- case "run":
166
- return runCiJob(args.slice(1));
167
- default:
168
- console.log(`
169
- ${chalk.bold("ulpi ci")} \u2014 CI/PR worker mode
170
-
171
- Usage: ulpi ci <command>
172
-
173
- Commands:
174
- run Execute a CI job (used inside worker containers)
175
-
176
- Options:
177
- --job-id <id> Job identifier
178
- --config <json> Job config (JSON string or from ULPI_JOB_CONFIG env)
179
- --output <path> Output file path for results
180
- --model <model> Claude model to use (default: claude-sonnet-4-20250514)
181
- `.trim());
182
- }
183
- }
184
- async function runCiJob(args) {
185
- let jobId = "";
186
- let configJson = "";
187
- let outputPath = "";
188
- let model = "claude-sonnet-4-20250514";
189
- for (let i = 0; i < args.length; i++) {
190
- switch (args[i]) {
191
- case "--job-id":
192
- jobId = args[++i] ?? "";
193
- break;
194
- case "--config":
195
- configJson = args[++i] ?? "";
196
- break;
197
- case "--output":
198
- outputPath = args[++i] ?? "";
199
- break;
200
- case "--model":
201
- model = args[++i] ?? model;
202
- break;
203
- }
204
- }
205
- jobId = jobId || process.env.ULPI_JOB_ID || "";
206
- configJson = configJson || process.env.ULPI_JOB_CONFIG || "";
207
- outputPath = outputPath || "/workspace/.ulpi-ci/output.json";
208
- if (!jobId) {
209
- console.error(chalk.red("Error: --job-id is required"));
210
- process.exit(1);
211
- }
212
- if (!configJson) {
213
- console.error(chalk.red("Error: --config is required (or set ULPI_JOB_CONFIG env)"));
214
- process.exit(1);
215
- }
216
- let rawConfig;
217
- try {
218
- rawConfig = JSON.parse(configJson);
219
- } catch {
220
- console.error(chalk.red("Error: Invalid JSON in --config"));
221
- process.exit(1);
222
- }
223
- const parseResult = JobConfigSchema.safeParse(rawConfig);
224
- if (!parseResult.success) {
225
- console.error(chalk.red("Error: Invalid job config:"));
226
- console.error(parseResult.error.format());
227
- process.exit(1);
228
- }
229
- const config = parseResult.data;
230
- const startTime = Date.now();
231
- console.log(chalk.blue(`[ulpi-ci] Job ${jobId} starting`));
232
- console.log(chalk.blue(`[ulpi-ci] Instruction: ${config.instruction}`));
233
- console.log(chalk.blue(`[ulpi-ci] Repo: ${config.repoFullName} PR#${config.prNumber}`));
234
- const guardsPath = path.join(process.cwd(), ".ulpi", "guards.yml");
235
- const hasGuards = fs.existsSync(guardsPath);
236
- if (hasGuards) {
237
- console.log(chalk.blue("[ulpi-ci] guards.yml found \u2014 rules will be enforced"));
238
- }
239
- const prompt = buildPrompt(config, {});
240
- const claudePath = findClaudeBinary();
241
- if (!claudePath) {
242
- console.error(chalk.red("Error: claude binary not found in PATH"));
243
- writeOutput(outputPath, {
244
- jobId,
245
- status: "failed",
246
- filesChanged: [],
247
- sessionEvents: 0,
248
- durationMs: Date.now() - startTime,
249
- error: "claude binary not found"
250
- });
251
- process.exit(1);
252
- }
253
- console.log(chalk.blue(`[ulpi-ci] Using claude at: ${claudePath}`));
254
- const claudeArgs = [
255
- "--print",
256
- "--model",
257
- model
258
- ];
259
- console.log(chalk.blue("[ulpi-ci] Spawning Claude Code..."));
260
- const result = await spawnClaude(claudePath, claudeArgs, prompt, config.timeoutMinutes * 60 * 1e3);
261
- const baseBranch = config.baseBranch;
262
- let diff = "";
263
- let filesChanged = [];
264
- try {
265
- diff = execFileSync("git", ["diff", `origin/${baseBranch}...HEAD`], {
266
- cwd: process.cwd(),
267
- encoding: "utf-8",
268
- timeout: 3e4,
269
- maxBuffer: 10 * 1024 * 1024
270
- });
271
- } catch {
272
- }
273
- try {
274
- const output = execFileSync("git", ["diff", "--name-only", `origin/${baseBranch}...HEAD`], {
275
- cwd: process.cwd(),
276
- encoding: "utf-8",
277
- timeout: 3e4
278
- });
279
- filesChanged = output.trim().split("\n").filter(Boolean);
280
- } catch {
281
- }
282
- const jobResult = {
283
- jobId,
284
- status: result.exitCode === 0 ? "completed" : "failed",
285
- exitCode: result.exitCode,
286
- diff: diff || void 0,
287
- summary: result.output.slice(0, 5e3) || void 0,
288
- filesChanged,
289
- sessionEvents: 0,
290
- durationMs: Date.now() - startTime,
291
- error: result.exitCode !== 0 ? `Claude exited with code ${result.exitCode}` : void 0
292
- };
293
- writeOutput(outputPath, jobResult);
294
- console.log(chalk.blue(`[ulpi-ci] Job ${jobId} ${jobResult.status} in ${formatDuration(jobResult.durationMs)}`));
295
- console.log(chalk.blue(`[ulpi-ci] Files changed: ${filesChanged.length}`));
296
- process.exit(result.exitCode === 0 ? 0 : 1);
297
- }
298
- function findClaudeBinary() {
299
- try {
300
- const result = execFileSync("which", ["claude"], { encoding: "utf-8", timeout: 5e3 });
301
- return result.trim();
302
- } catch {
303
- }
304
- const commonPaths = ["/usr/local/bin/claude", "/usr/bin/claude"];
305
- for (const p of commonPaths) {
306
- if (fs.existsSync(p)) return p;
307
- }
308
- return null;
309
- }
310
- function spawnClaude(claudePath, args, prompt, timeoutMs) {
311
- return new Promise((resolve) => {
312
- const proc = spawn(claudePath, args, {
313
- cwd: process.cwd(),
314
- env: process.env,
315
- stdio: ["pipe", "pipe", "pipe"]
316
- });
317
- let stdout = "";
318
- let stderr = "";
319
- proc.stdout.on("data", (data) => {
320
- const text = data.toString();
321
- stdout += text;
322
- process.stdout.write(text);
323
- });
324
- proc.stderr.on("data", (data) => {
325
- const text = data.toString();
326
- stderr += text;
327
- process.stderr.write(text);
328
- });
329
- proc.stdin.write(prompt);
330
- proc.stdin.end();
331
- const timer = setTimeout(() => {
332
- console.log(chalk.yellow("[ulpi-ci] Timeout reached, killing Claude process..."));
333
- proc.kill("SIGTERM");
334
- setTimeout(() => {
335
- if (!proc.killed) proc.kill("SIGKILL");
336
- }, 1e4);
337
- }, timeoutMs);
338
- proc.on("close", (code) => {
339
- clearTimeout(timer);
340
- resolve({ exitCode: code ?? 1, output: stdout });
341
- });
342
- const onSigterm = () => {
343
- console.log(chalk.yellow("[ulpi-ci] Received SIGTERM, stopping Claude..."));
344
- proc.kill("SIGTERM");
345
- };
346
- process.on("SIGTERM", onSigterm);
347
- proc.on("close", () => {
348
- process.removeListener("SIGTERM", onSigterm);
349
- });
350
- });
351
- }
352
- function writeOutput(outputPath, result) {
353
- try {
354
- const dir = path.dirname(outputPath);
355
- fs.mkdirSync(dir, { recursive: true });
356
- fs.writeFileSync(outputPath, JSON.stringify({ jobId: result.jobId, result }, null, 2), "utf-8");
357
- } catch (err) {
358
- console.error(chalk.red(`Error writing output: ${err instanceof Error ? err.message : String(err)}`));
359
- }
360
- }
361
- function formatDuration(ms) {
362
- const seconds = Math.floor(ms / 1e3);
363
- if (seconds < 60) return `${seconds}s`;
364
- const minutes = Math.floor(seconds / 60);
365
- const remainingSeconds = seconds % 60;
366
- return `${minutes}m ${remainingSeconds}s`;
367
- }
368
- export {
369
- runCi
370
- };
@@ -1,18 +0,0 @@
1
- import {
2
- createApiServer
3
- } from "./chunk-2VYFVYJL.js";
4
- import "./chunk-MIAQVCFW.js";
5
- import "./chunk-2MZER6ND.js";
6
- import "./chunk-3SBPZRB5.js";
7
- import "./chunk-2CLNOKPA.js";
8
- import "./chunk-SPOI23SB.js";
9
- import "./chunk-6OCEY7JY.js";
10
- import "./chunk-SIAQVRKG.js";
11
- import "./chunk-JGBXM5NC.js";
12
- import "./chunk-YM2HV4IA.js";
13
- import "./chunk-KIKPIH6N.js";
14
- import "./chunk-7LXY5UVC.js";
15
- import "./chunk-4VNS5WPM.js";
16
- export {
17
- createApiServer
18
- };
@@ -1,11 +0,0 @@
1
- import {
2
- attachWebSocket
3
- } from "./chunk-7AL4DOEJ.js";
4
- import "./chunk-MIAQVCFW.js";
5
- import "./chunk-SPOI23SB.js";
6
- import "./chunk-YM2HV4IA.js";
7
- import "./chunk-7LXY5UVC.js";
8
- import "./chunk-4VNS5WPM.js";
9
- export {
10
- attachWebSocket
11
- };