@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.
- package/dist/{auth-ECQ3IB4E.js → auth-BFFBUJUC.js} +1 -1
- package/dist/{chunk-YM2HV4IA.js → chunk-26LLDX2T.js} +50 -2
- package/dist/{chunk-QJ5GSMEC.js → chunk-5SCG7UYM.js} +2 -1
- package/dist/{chunk-5J6NLQUN.js → chunk-6OURRFP7.js} +8 -8
- package/dist/chunk-AV5RB3N2.js +173 -0
- package/dist/{chunk-7LXY5UVC.js → chunk-DDRLI6JU.js} +2 -1
- package/dist/{chunk-ZLYRPD7I.js → chunk-DOIKS6C5.js} +1 -1
- package/dist/{chunk-SPOI23SB.js → chunk-EIWYSP3A.js} +1 -1
- package/dist/{chunk-7AL4DOEJ.js → chunk-ELTGWMDE.js} +3 -3
- package/dist/{chunk-6OCEY7JY.js → chunk-IFATANHR.js} +34 -3
- package/dist/{chunk-2HEE5OKX.js → chunk-K4OVPFY2.js} +1 -1
- package/dist/{chunk-JGBXM5NC.js → chunk-L3PWNHSA.js} +2 -2
- package/dist/{chunk-2VYFVYJL.js → chunk-LD52XG3X.js} +24 -24
- package/dist/{chunk-BZL5H4YQ.js → chunk-P2RESJRN.js} +2 -2
- package/dist/{chunk-3SBPZRB5.js → chunk-RJIRWQJD.js} +1 -1
- package/dist/{chunk-2CLNOKPA.js → chunk-RSFJ6QSR.js} +18 -0
- package/dist/{chunk-PDR55ZNW.js → chunk-UCMT5OKP.js} +4 -4
- package/dist/{chunk-2MZER6ND.js → chunk-YYZOFYS6.js} +2 -2
- package/dist/ci-JQ56YIKC.js +756 -0
- package/dist/{codemap-RKSD4MIE.js → codemap-HMYBXJL2.js} +36 -36
- package/dist/{config-EGAXXCGL.js → config-YYWEN7U2.js} +1 -1
- package/dist/dist-2K7IEVTA.js +43 -0
- package/dist/{dist-UKMCJBB2.js → dist-4XTJ6HLM.js} +7 -7
- package/dist/{dist-QAU3LGJN.js → dist-5R4RYNQO.js} +3 -3
- package/dist/{dist-CB5D5LMO.js → dist-6MFVWIFF.js} +8 -8
- package/dist/{dist-GJYT2OQV.js → dist-7WLLPWWB.js} +8 -8
- package/dist/{dist-RKOGLK7R.js → dist-GWGTAHNM.js} +1 -1
- package/dist/{dist-CS2VKNYS.js → dist-U7ZIJMZD.js} +8 -8
- package/dist/{dist-YA2BWZB2.js → dist-WAMAQVPK.js} +2 -2
- package/dist/dist-XD4YI27T.js +26 -0
- package/dist/dist-XG2GG5SD.js +36 -0
- package/dist/{history-3MOBX4MA.js → history-RNUWO4JZ.js} +7 -7
- package/dist/hooks-installer-K2JXEBNN.js +19 -0
- package/dist/index.js +42 -42
- package/dist/{init-6CH4HV5T.js → init-NQWFZPKO.js} +11 -11
- package/dist/{launchd-LF2QMSKZ.js → launchd-OYXUAVW6.js} +2 -2
- package/dist/{mcp-installer-NQCGKQ23.js → mcp-installer-TOYDP77X.js} +1 -1
- package/dist/{memory-Y6OZTXJ2.js → memory-D6ZFFCI2.js} +17 -17
- package/dist/{openai-E7G2YAHU-UYY4ZWON.js → openai-E7G2YAHU-IG33BFYF.js} +2 -2
- package/dist/{projects-ATHDD3D6.js → projects-COUJP4ZC.js} +3 -3
- package/dist/{review-ADUPV3PN.js → review-KMGP2S25.js} +2 -2
- package/dist/{rules-E427DKYJ.js → rules-3OFGWHP4.js} +1 -1
- package/dist/server-USLHY6GH-F4JSXCWA.js +18 -0
- package/dist/server-X5P6WH2M-ULZF5WHZ.js +11 -0
- package/dist/{skills-CX73O3IV.js → skills-GY2CTPWN.js} +2 -2
- package/dist/{status-4DFHDJMN.js → status-SE43TIFJ.js} +2 -2
- package/dist/{templates-U7T6MARD.js → templates-O2XDKB5R.js} +5 -5
- package/dist/{ui-OWXZ3YSR.js → ui-4SM2SUI6.js} +13 -13
- package/dist/{ulpi-RMMCUAGP-JCJ273T6.js → ulpi-RMMCUAGP-EWYUE7RU.js} +1 -1
- package/dist/{uninstall-6SW35IK4.js → uninstall-KWGSGZTI.js} +3 -3
- package/dist/{update-M6IBJNYP.js → update-QYZA4D23.js} +3 -3
- package/dist/{version-checker-Q6YTYAGP.js → version-checker-MVB74DEX.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-B55DDP24.js +0 -136
- package/dist/ci-STSL2LSP.js +0 -370
- package/dist/server-USLHY6GH-AEOJC5ST.js +0 -18
- package/dist/server-X5P6WH2M-7K2RY34N.js +0 -11
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
checkForUpdates
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P2RESJRN.js";
|
|
4
4
|
import {
|
|
5
5
|
CLI_BIN_NAME,
|
|
6
6
|
CLI_NPM_PACKAGE
|
|
7
|
-
} from "./chunk-
|
|
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-
|
|
39
|
+
const { isSupported, isLaunchAgentInstalled, needsLegacyMigration, installLaunchAgent, restartLaunchAgent } = await import("./launchd-OYXUAVW6.js");
|
|
40
40
|
if (isSupported()) {
|
|
41
41
|
if (needsLegacyMigration()) {
|
|
42
42
|
installLaunchAgent();
|
package/package.json
CHANGED
package/dist/chunk-B55DDP24.js
DELETED
|
@@ -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
|
-
};
|
package/dist/ci-STSL2LSP.js
DELETED
|
@@ -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
|
-
};
|