@ulpi/cli 0.1.5 → 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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{auth-PN7TMQHV-2W4ICG64.js → auth-FWM7MM4Q-VZC3U2XZ.js} +1 -1
  3. package/dist/{auth-BFFBUJUC.js → auth-HDK7ECJL.js} +2 -1
  4. package/dist/{chunk-RJIRWQJD.js → chunk-3BCW6ABU.js} +402 -142
  5. package/dist/{chunk-L3PWNHSA.js → chunk-3WB5CXH4.js} +180 -5
  6. package/dist/{chunk-K4OVPFY2.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-AV5RB3N2.js → chunk-76D3BYJD.js} +48 -0
  12. package/dist/{chunk-DOIKS6C5.js → chunk-AWOSRA5F.js} +1 -1
  13. package/dist/{chunk-UCMT5OKP.js → chunk-BFEKZZHM.js} +274 -57
  14. package/dist/chunk-C7CLUQI6.js +1286 -0
  15. package/dist/{chunk-ELTGWMDE.js → chunk-E3B5NROU.js} +7 -7
  16. package/dist/chunk-EJ7TW77N.js +1418 -0
  17. package/dist/{chunk-6OURRFP7.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-P2RESJRN.js → chunk-KYYI23AQ.js} +2 -2
  21. package/dist/chunk-S6ANCSYO.js +1271 -0
  22. package/dist/chunk-SEU7WWNQ.js +1251 -0
  23. package/dist/chunk-SNQ7NAIS.js +453 -0
  24. package/dist/{ulpi-RMMCUAGP-EWYUE7RU.js → chunk-TSLDGT5O.js} +73 -35
  25. package/dist/{chunk-EIWYSP3A.js → chunk-UXHCHOWQ.js} +83 -62
  26. package/dist/chunk-V2H5D6Y3.js +146 -0
  27. package/dist/{chunk-5SCG7UYM.js → chunk-VVEDXI7E.js} +1 -1
  28. package/dist/chunk-VXH5Y4FO.js +6761 -0
  29. package/dist/chunk-WED4LM5N.js +322 -0
  30. package/dist/{chunk-74WVVWJ4.js → chunk-YOKL7RB5.js} +184 -15
  31. package/dist/chunk-Z53CAR7G.js +298 -0
  32. package/dist/{ci-JQ56YIKC.js → ci-X3U2W4HC.js} +124 -26
  33. package/dist/cloud-2F3NLVHN.js +274 -0
  34. package/dist/{codemap-HMYBXJL2.js → codemap-XNGMAF3F.js} +37 -37
  35. package/dist/codex-MB5YTMRT.js +132 -0
  36. package/dist/{config-YYWEN7U2.js → config-OOELBYTH.js} +1 -1
  37. package/dist/dist-2BJYR5EI.js +59 -0
  38. package/dist/dist-3EIQTZHT.js +1380 -0
  39. package/dist/{dist-WAMAQVPK.js → dist-4U5L2X2C.js} +2 -2
  40. package/dist/{dist-4XTJ6HLM.js → dist-54KAMNLO.js} +16 -15
  41. package/dist/dist-6M4MZWZW.js +58 -0
  42. package/dist/dist-6X576SU2.js +27 -0
  43. package/dist/dist-7QOEYLFX.js +103 -0
  44. package/dist/dist-AYBGHEDY.js +2541 -0
  45. package/dist/dist-EK45QNEM.js +45 -0
  46. package/dist/{dist-U7ZIJMZD.js → dist-FKFEJRPX.js} +16 -15
  47. package/dist/dist-GTEJUBBT.js +66 -0
  48. package/dist/dist-HA74OKJZ.js +40 -0
  49. package/dist/{dist-XG2GG5SD.js → dist-HU5RZAON.js} +14 -2
  50. package/dist/dist-IYE3OBRB.js +374 -0
  51. package/dist/{dist-7WLLPWWB.js → dist-JLU26AB6.js} +12 -9
  52. package/dist/{dist-6G7JC2RA.js → dist-KUCI6JFE.js} +49 -9
  53. package/dist/dist-NUEMFZFL.js +33 -0
  54. package/dist/{dist-GWGTAHNM.js → dist-NUXMDXZ3.js} +31 -3
  55. package/dist/{dist-5R4RYNQO.js → dist-YCNWHSLN.js} +15 -5
  56. package/dist/{dist-6MFVWIFF.js → dist-YFFG2ZD6.js} +9 -16
  57. package/dist/dist-ZG4OKCSR.js +15 -0
  58. package/dist/doctor-SI4LLLDZ.js +345 -0
  59. package/dist/{export-import-4A5MWLIA.js → export-import-JFQH4KSJ.js} +1 -1
  60. package/dist/{history-RNUWO4JZ.js → history-5NE46ZAH.js} +7 -7
  61. package/dist/{hooks-installer-K2JXEBNN.js → hooks-installer-UN5JZLDQ.js} +2 -2
  62. package/dist/index.js +394 -618
  63. package/dist/{init-NQWFZPKO.js → init-5FK3VKRT.js} +76 -10
  64. package/dist/job-HIDMAFW2.js +376 -0
  65. package/dist/jobs.memory-PLMMSFHB-VBECCTHN.js +33 -0
  66. package/dist/kiro-VMUHDFGK.js +153 -0
  67. package/dist/{launchd-OYXUAVW6.js → launchd-6AWT54HR.js} +9 -17
  68. package/dist/mcp-PDUD7SGP.js +249 -0
  69. package/dist/mcp-installer-PQU3XOGO.js +259 -0
  70. package/dist/mcp-setup-OA7IB3H3.js +263 -0
  71. package/dist/{memory-D6ZFFCI2.js → memory-ZNAEAK3B.js} +17 -17
  72. package/dist/{ollama-3XCUZMZT-FYKHW4TZ.js → ollama-3XCUZMZT-4JMH6B7P.js} +1 -1
  73. package/dist/{openai-E7G2YAHU-IG33BFYF.js → openai-E7G2YAHU-T3HMBPH7.js} +2 -2
  74. package/dist/portal-JYWVHXDU.js +210 -0
  75. package/dist/prd-Q4J5NVAR.js +408 -0
  76. package/dist/repos-WWZXNN3P.js +271 -0
  77. package/dist/review-integration-5WHEJU2A.js +14 -0
  78. package/dist/{rules-3OFGWHP4.js → rules-Y4VSOY5Y.js} +3 -3
  79. package/dist/run-VPNXEIBY.js +687 -0
  80. package/dist/server-COL4AXKU-P7S7NNF6.js +11 -0
  81. package/dist/server-KKSETHDV-XSSLEENT.js +20 -0
  82. package/dist/{skills-GY2CTPWN.js → skills-QEYU2N27.js} +4 -2
  83. package/dist/start-JYOEL7AJ.js +303 -0
  84. package/dist/{status-SE43TIFJ.js → status-BHQYYGAL.js} +2 -2
  85. package/dist/{templates-O2XDKB5R.js → templates-CBRUJ66V.js} +6 -5
  86. package/dist/tui-DP7736EX.js +61 -0
  87. package/dist/ulpi-5EN6JCAS-LFE3WSL4.js +10 -0
  88. package/dist/{uninstall-KWGSGZTI.js → uninstall-ICUV6DDV.js} +3 -3
  89. package/dist/{update-QYZA4D23.js → update-7ZMAYRBH.js} +3 -3
  90. package/dist/{version-checker-MVB74DEX.js → version-checker-4ZFMZA7Y.js} +2 -2
  91. package/package.json +39 -31
  92. package/dist/chunk-26LLDX2T.js +0 -553
  93. package/dist/chunk-DDRLI6JU.js +0 -331
  94. package/dist/chunk-IFATANHR.js +0 -453
  95. package/dist/chunk-JWUUVXIV.js +0 -13694
  96. package/dist/chunk-LD52XG3X.js +0 -4273
  97. package/dist/chunk-MIAQVCFW.js +0 -39
  98. package/dist/chunk-YYZOFYS6.js +0 -415
  99. package/dist/dist-XD4YI27T.js +0 -26
  100. package/dist/mcp-installer-TOYDP77X.js +0 -124
  101. package/dist/projects-COUJP4ZC.js +0 -271
  102. package/dist/review-KMGP2S25.js +0 -152
  103. package/dist/server-USLHY6GH-F4JSXCWA.js +0 -18
  104. package/dist/server-X5P6WH2M-ULZF5WHZ.js +0 -11
  105. package/dist/skills/ulpi-generate-guardian/SKILL.md +0 -750
  106. package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +0 -849
  107. package/dist/skills/ulpi-generate-guardian/references/language-rules.md +0 -591
  108. package/dist/ui-4SM2SUI6.js +0 -167
  109. package/dist/ui.html +0 -698
@@ -0,0 +1,298 @@
1
+ // ../../packages/http/dist/middleware/auth.js
2
+ import { randomBytes } from "crypto";
3
+ var apiSecret;
4
+ function generateApiSecret() {
5
+ return randomBytes(32).toString("hex");
6
+ }
7
+ function setApiSecret(secret) {
8
+ apiSecret = secret;
9
+ }
10
+ function getApiSecret() {
11
+ return apiSecret;
12
+ }
13
+ var LOOPBACK_ADDRESSES = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "::ffff:127.0.0.1"]);
14
+ function validateLoopback(req) {
15
+ const remoteAddr = req.socket.remoteAddress ?? "";
16
+ return LOOPBACK_ADDRESSES.has(remoteAddr);
17
+ }
18
+ function validateAuth(req) {
19
+ if (!validateLoopback(req))
20
+ return false;
21
+ if (apiSecret) {
22
+ const headerSecret = req.headers["x-ulpi-secret"];
23
+ if (headerSecret === apiSecret)
24
+ return true;
25
+ try {
26
+ const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
27
+ const paramSecret = url.searchParams.get("secret");
28
+ if (paramSecret === apiSecret)
29
+ return true;
30
+ } catch {
31
+ }
32
+ return false;
33
+ }
34
+ return true;
35
+ }
36
+
37
+ // ../../packages/http/dist/router.js
38
+ function createRouter() {
39
+ const routes = [];
40
+ function add(method, pattern, handler) {
41
+ routes.push({ method, pattern, handler });
42
+ }
43
+ return {
44
+ get(pattern, handler) {
45
+ add("GET", pattern, handler);
46
+ },
47
+ post(pattern, handler) {
48
+ add("POST", pattern, handler);
49
+ },
50
+ put(pattern, handler) {
51
+ add("PUT", pattern, handler);
52
+ },
53
+ patch(pattern, handler) {
54
+ add("PATCH", pattern, handler);
55
+ },
56
+ delete(pattern, handler) {
57
+ add("DELETE", pattern, handler);
58
+ },
59
+ /**
60
+ * Try each registered route in order. For string patterns, performs an
61
+ * exact match against `ctx.pathname`. For RegExp patterns, tests the
62
+ * pathname and extracts named groups (or positional captures indexed by
63
+ * their number) into `params`.
64
+ *
65
+ * Returns `true` if a matching route was found (and its handler was
66
+ * invoked), `false` otherwise.
67
+ */
68
+ async handle(ctx) {
69
+ for (const route of routes) {
70
+ if (route.method !== ctx.method)
71
+ continue;
72
+ let params = {};
73
+ if (typeof route.pattern === "string") {
74
+ if (ctx.pathname !== route.pattern)
75
+ continue;
76
+ } else {
77
+ const match = route.pattern.exec(ctx.pathname);
78
+ if (!match)
79
+ continue;
80
+ if (match.groups) {
81
+ params = { ...match.groups };
82
+ }
83
+ for (let i = 1; i < match.length; i++) {
84
+ if (match[i] !== void 0) {
85
+ params[String(i)] = decodeURIComponent(match[i]);
86
+ }
87
+ }
88
+ }
89
+ await route.handler({ ...ctx, params });
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ };
95
+ }
96
+
97
+ // ../../packages/http/dist/request.js
98
+ function readBody(req, maxSize = 1048576) {
99
+ return new Promise((resolve, reject) => {
100
+ const chunks = [];
101
+ let size = 0;
102
+ req.on("data", (chunk) => {
103
+ size += chunk.length;
104
+ if (size > maxSize) {
105
+ req.destroy();
106
+ reject(new Error("Request body too large"));
107
+ return;
108
+ }
109
+ chunks.push(chunk);
110
+ });
111
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
112
+ req.on("error", reject);
113
+ });
114
+ }
115
+ function readBodyRaw(req, maxSize = 5 * 1024 * 1024) {
116
+ return new Promise((resolve, reject) => {
117
+ const chunks = [];
118
+ let size = 0;
119
+ req.on("data", (chunk) => {
120
+ size += chunk.length;
121
+ if (size > maxSize) {
122
+ req.destroy();
123
+ reject(new Error("Request body too large"));
124
+ return;
125
+ }
126
+ chunks.push(chunk);
127
+ });
128
+ req.on("end", () => resolve(Buffer.concat(chunks)));
129
+ req.on("error", reject);
130
+ });
131
+ }
132
+ async function parseJsonBody(req) {
133
+ try {
134
+ const raw = await readBody(req);
135
+ const parsed = JSON.parse(raw);
136
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
137
+ return { data: null, error: "Expected a JSON object" };
138
+ }
139
+ return { data: parsed, error: null };
140
+ } catch (err) {
141
+ const message = err instanceof Error ? err.message : "Invalid JSON body";
142
+ return { data: null, error: message };
143
+ }
144
+ }
145
+ function parseMultipartImage(body, boundary) {
146
+ const boundaryBuffer = Buffer.from(`--${boundary}`);
147
+ const start = body.indexOf(boundaryBuffer);
148
+ if (start === -1)
149
+ return null;
150
+ const headerEnd = body.indexOf(Buffer.from("\r\n\r\n"), start);
151
+ if (headerEnd === -1)
152
+ return null;
153
+ const headers = body.subarray(start + boundaryBuffer.length + 2, headerEnd).toString();
154
+ const ctMatch = headers.match(/Content-Type:\s*(.+)/i);
155
+ const contentType = ctMatch ? ctMatch[1].trim() : "image/png";
156
+ const dataStart = headerEnd + 4;
157
+ const nextBoundary = body.indexOf(boundaryBuffer, dataStart);
158
+ const dataEnd = nextBoundary !== -1 ? nextBoundary - 2 : body.length;
159
+ return { data: body.subarray(dataStart, dataEnd), contentType };
160
+ }
161
+
162
+ // ../../packages/http/dist/response.js
163
+ function resolveOrigin(options, req) {
164
+ if (!options)
165
+ return "*";
166
+ if (typeof options.origin === "function")
167
+ return options.origin(req);
168
+ return options.origin;
169
+ }
170
+ function corsHeaders(options, req) {
171
+ const headers = {
172
+ "Access-Control-Allow-Origin": resolveOrigin(options, req),
173
+ "Access-Control-Allow-Methods": options?.methods ?? "GET, POST, PUT, PATCH, DELETE, OPTIONS",
174
+ "Access-Control-Allow-Headers": options?.headers ?? "Content-Type, Authorization"
175
+ };
176
+ if (options?.credentials) {
177
+ headers["Access-Control-Allow-Credentials"] = "true";
178
+ }
179
+ if (options?.maxAge) {
180
+ headers["Access-Control-Max-Age"] = String(options.maxAge);
181
+ }
182
+ return headers;
183
+ }
184
+ function jsonResponse(res, data, status = 200, req, cors) {
185
+ const body = JSON.stringify(data);
186
+ res.writeHead(status, {
187
+ "Content-Type": "application/json",
188
+ ...corsHeaders(cors, req)
189
+ });
190
+ res.end(body);
191
+ }
192
+ function notFound(res, message = "Not found", req, cors) {
193
+ jsonResponse(res, { error: message }, 404, req, cors);
194
+ }
195
+ function sseHeaders(res, req, cors) {
196
+ res.writeHead(200, {
197
+ "Content-Type": "text/event-stream",
198
+ "Cache-Control": "no-cache",
199
+ Connection: "keep-alive",
200
+ ...corsHeaders(cors, req)
201
+ });
202
+ }
203
+ function sseEvent(res, eventName, data) {
204
+ res.write(`event: ${eventName}
205
+ data: ${JSON.stringify(data)}
206
+
207
+ `);
208
+ }
209
+
210
+ // ../../packages/http/dist/middleware/rate-limit.js
211
+ var store = /* @__PURE__ */ new Map();
212
+ var CLEANUP_INTERVAL = 6e4;
213
+ setInterval(() => {
214
+ const now = Date.now();
215
+ for (const [key, entry] of store) {
216
+ if (now >= entry.resetAt) {
217
+ store.delete(key);
218
+ }
219
+ }
220
+ }, CLEANUP_INTERVAL).unref();
221
+ function checkRateLimit(key, limit = 200, windowMs = 6e4) {
222
+ const now = Date.now();
223
+ const entry = store.get(key);
224
+ if (!entry || now >= entry.resetAt) {
225
+ store.set(key, { count: 1, resetAt: now + windowMs });
226
+ return true;
227
+ }
228
+ entry.count++;
229
+ return entry.count <= limit;
230
+ }
231
+
232
+ // ../../packages/http/dist/middleware/cors.js
233
+ function handleCorsPreFlight(req, res, options) {
234
+ if ((req.method ?? "GET") !== "OPTIONS")
235
+ return false;
236
+ res.writeHead(204, corsHeaders(options, req));
237
+ res.end();
238
+ return true;
239
+ }
240
+
241
+ // ../../packages/http/dist/websocket.js
242
+ import { WebSocketServer } from "ws";
243
+
244
+ // ../../packages/http/dist/sse.js
245
+ var SSEBroadcaster = class _SSEBroadcaster {
246
+ static MAX_CLIENTS = 100;
247
+ clients = /* @__PURE__ */ new Set();
248
+ /** Check if the broadcaster can accept another client. */
249
+ canAccept() {
250
+ return this.clients.size < _SSEBroadcaster.MAX_CLIENTS;
251
+ }
252
+ /** Register a new SSE client. */
253
+ add(res) {
254
+ this.clients.add(res);
255
+ }
256
+ /** Remove a disconnected SSE client. */
257
+ remove(res) {
258
+ this.clients.delete(res);
259
+ }
260
+ /** Broadcast a named SSE event to every connected client. */
261
+ broadcast(eventName, data) {
262
+ const message = `event: ${eventName}
263
+ data: ${JSON.stringify(data)}
264
+
265
+ `;
266
+ for (const client of this.clients) {
267
+ try {
268
+ client.write(message);
269
+ } catch {
270
+ this.clients.delete(client);
271
+ }
272
+ }
273
+ }
274
+ /** Number of currently connected clients. */
275
+ get size() {
276
+ return this.clients.size;
277
+ }
278
+ };
279
+
280
+ export {
281
+ createRouter,
282
+ readBody,
283
+ readBodyRaw,
284
+ parseJsonBody,
285
+ parseMultipartImage,
286
+ jsonResponse,
287
+ notFound,
288
+ sseHeaders,
289
+ sseEvent,
290
+ generateApiSecret,
291
+ setApiSecret,
292
+ getApiSecret,
293
+ validateLoopback,
294
+ validateAuth,
295
+ checkRateLimit,
296
+ handleCorsPreFlight,
297
+ SSEBroadcaster
298
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildPrompt
3
- } from "./chunk-AV5RB3N2.js";
3
+ } from "./chunk-76D3BYJD.js";
4
4
  import {
5
5
  external_exports
6
6
  } from "./chunk-KIKPIH6N.js";
@@ -38,12 +38,13 @@ var JobConfigSchema = external_exports.object({
38
38
  repoUrl: external_exports.string().url(),
39
39
  ref: external_exports.string(),
40
40
  baseBranch: external_exports.string(),
41
- prNumber: external_exports.number().int().positive(),
41
+ prNumber: external_exports.number().int().positive().optional(),
42
42
  repoFullName: external_exports.string(),
43
43
  instruction: external_exports.string(),
44
44
  jiraContext: external_exports.string().optional(),
45
45
  timeoutMinutes: external_exports.number().int().positive().default(1440),
46
- envVars: external_exports.record(external_exports.string()).optional()
46
+ envVars: external_exports.record(external_exports.string()).optional(),
47
+ autoCommitIgnore: external_exports.array(external_exports.string()).default([".pnpm-store/", "node_modules/", ".claude/"])
47
48
  });
48
49
  var JobResultSchema = external_exports.object({
49
50
  jobId: external_exports.string(),
@@ -69,8 +70,8 @@ var JobSchema = external_exports.object({
69
70
  startedAt: external_exports.string().datetime().optional(),
70
71
  completedAt: external_exports.string().datetime().optional(),
71
72
  cancelledBy: external_exports.string().optional(),
72
- commentId: external_exports.number().int().positive(),
73
- commentAuthor: external_exports.string()
73
+ commentId: external_exports.number().int().positive().optional(),
74
+ commentAuthor: external_exports.string().optional()
74
75
  });
75
76
  var GitHubAppAuthSchema = external_exports.object({
76
77
  appId: external_exports.string(),
@@ -157,6 +158,26 @@ var JiraReferenceSchema = external_exports.object({
157
158
  key: external_exports.string(),
158
159
  url: external_exports.string().url()
159
160
  });
161
+ var JiraSprintSchema = external_exports.object({
162
+ id: external_exports.number().int(),
163
+ name: external_exports.string(),
164
+ state: external_exports.string(),
165
+ // "active", "closed", "future"
166
+ startDate: external_exports.string().optional(),
167
+ endDate: external_exports.string().optional()
168
+ });
169
+ var SprintImportConfigSchema = external_exports.object({
170
+ jiraBaseUrl: external_exports.string().url(),
171
+ email: external_exports.string().email(),
172
+ apiToken: external_exports.string(),
173
+ sprintId: external_exports.number().int().positive()
174
+ });
175
+ var JiraSprintImportSchema = external_exports.object({
176
+ sprintId: external_exports.number().int(),
177
+ tasks: external_exports.array(external_exports.unknown()),
178
+ // TrackerTask[] — imported at runtime
179
+ warnings: external_exports.array(external_exports.string())
180
+ });
160
181
 
161
182
  // src/commands/ci.ts
162
183
  async function runCi(args, projectDir) {
@@ -185,7 +206,7 @@ async function runCiJob(args) {
185
206
  let jobId = "";
186
207
  let configJson = "";
187
208
  let outputPath = "";
188
- let model = "claude-sonnet-4-20250514";
209
+ let model = process.env.ULPI_CLAUDE_MODEL ?? "claude-opus-4-6";
189
210
  for (let i = 0; i < args.length; i++) {
190
211
  switch (args[i]) {
191
212
  case "--job-id":
@@ -250,6 +271,7 @@ async function runCiJob(args) {
250
271
  process.exit(1);
251
272
  }
252
273
  console.log(chalk.blue(`[ulpi-ci] Using claude at: ${claudePath}`));
274
+ logClaudeMdFiles(projectDir);
253
275
  const claudeArgs = [
254
276
  "--print",
255
277
  "--verbose",
@@ -261,8 +283,9 @@ async function runCiJob(args) {
261
283
  ];
262
284
  console.log(chalk.blue("[ulpi-ci] Spawning Claude Code..."));
263
285
  const result = await spawnClaude(claudePath, claudeArgs, prompt, config.timeoutMinutes * 60 * 1e3);
264
- commitUnstagedWork(process.cwd());
286
+ commitUnstagedWork(process.cwd(), config.autoCommitIgnore);
265
287
  await postSessionFinalize(process.cwd());
288
+ await exportShadowBranches(process.cwd());
266
289
  const baseBranch = config.baseBranch;
267
290
  let diff = "";
268
291
  let filesChanged = [];
@@ -327,7 +350,7 @@ async function initUlpiSubsystems(projectDir) {
327
350
  if (fs.existsSync(guardsPath)) {
328
351
  console.log(chalk.blue("[ulpi-ci] guards.yml found \u2014 rules will be enforced"));
329
352
  } else {
330
- const { loadBundledTemplates, composeTemplates, resolveTemplate } = await import("./dist-XG2GG5SD.js");
353
+ const { loadBundledTemplates, composeTemplates, resolveTemplate } = await import("./dist-HU5RZAON.js");
331
354
  const stackConfig = {
332
355
  name: path.basename(projectDir),
333
356
  runtime: stack.runtime?.id ?? "unknown",
@@ -369,14 +392,14 @@ async function initUlpiSubsystems(projectDir) {
369
392
  console.log(chalk.yellow(`[ulpi-ci] Warning: Could not detect stack/generate guards.yml: ${err instanceof Error ? err.message : String(err)}`));
370
393
  }
371
394
  try {
372
- const { installHooks } = await import("./hooks-installer-K2JXEBNN.js");
395
+ const { installHooks } = await import("./hooks-installer-UN5JZLDQ.js");
373
396
  installHooks(projectDir);
374
397
  console.log(chalk.blue("[ulpi-ci] Hooks installed"));
375
398
  } catch (err) {
376
399
  console.log(chalk.yellow(`[ulpi-ci] Warning: Could not install hooks: ${err instanceof Error ? err.message : String(err)}`));
377
400
  }
378
401
  try {
379
- const { installMcpServer, installMemoryMcpServer } = await import("./mcp-installer-TOYDP77X.js");
402
+ const { installMcpServer, installMemoryMcpServer } = await import("./mcp-installer-PQU3XOGO.js");
380
403
  installMcpServer(projectDir);
381
404
  installMemoryMcpServer(projectDir);
382
405
  console.log(chalk.blue("[ulpi-ci] MCP servers registered"));
@@ -389,10 +412,10 @@ async function initUlpiSubsystems(projectDir) {
389
412
  } catch {
390
413
  }
391
414
  try {
392
- const { historyBranchExists, initHistoryBranch } = await import("./dist-5R4RYNQO.js");
415
+ const { historyBranchExists, initHistoryBranch } = await import("./dist-YCNWHSLN.js");
393
416
  if (!historyBranchExists(projectDir)) {
394
417
  const projectName = path.basename(projectDir);
395
- const version = true ? "0.1.5" : "0.0.0";
418
+ const version = true ? "0.1.6" : "0.0.0";
396
419
  initHistoryBranch(projectDir, projectName, version);
397
420
  console.log(chalk.blue("[ulpi-ci] History branch initialized"));
398
421
  } else {
@@ -402,8 +425,8 @@ async function initUlpiSubsystems(projectDir) {
402
425
  console.log(chalk.yellow(`[ulpi-ci] Warning: Could not init history: ${err instanceof Error ? err.message : String(err)}`));
403
426
  }
404
427
  try {
405
- const { isMemoryInitialized, saveMemoryConfig, DEFAULT_MEMORY_CONFIG, initMemoryBranch } = await import("./dist-7WLLPWWB.js");
406
- const { projectMemoryDir } = await import("./dist-GWGTAHNM.js");
428
+ const { isMemoryInitialized, saveMemoryConfig, DEFAULT_MEMORY_CONFIG, initMemoryBranch } = await import("./dist-JLU26AB6.js");
429
+ const { projectMemoryDir } = await import("./dist-NUXMDXZ3.js");
407
430
  if (!isMemoryInitialized(projectDir)) {
408
431
  const memDir = projectMemoryDir(projectDir);
409
432
  fs.mkdirSync(memDir, { recursive: true });
@@ -418,11 +441,11 @@ async function initUlpiSubsystems(projectDir) {
418
441
  console.log(chalk.yellow(`[ulpi-ci] Warning: Could not init memory: ${err instanceof Error ? err.message : String(err)}`));
419
442
  }
420
443
  try {
421
- const { resolveApiKey } = await import("./dist-GWGTAHNM.js");
444
+ const { resolveApiKey } = await import("./dist-NUXMDXZ3.js");
422
445
  const hasOpenAiKey = !!resolveApiKey("openai");
423
446
  const hasUlpiKey = !!resolveApiKey("ulpi");
424
447
  if (hasOpenAiKey || hasUlpiKey) {
425
- const { runInitPipeline } = await import("./dist-6MFVWIFF.js");
448
+ const { runInitPipeline } = await import("./dist-YFFG2ZD6.js");
426
449
  console.log(chalk.blue("[ulpi-ci] Indexing codebase..."));
427
450
  await runInitPipeline(projectDir, (progress) => {
428
451
  if (progress.message) {
@@ -490,8 +513,22 @@ function writeYamlFields(obj, lines, indent) {
490
513
  }
491
514
  }
492
515
  }
493
- function commitUnstagedWork(cwd) {
516
+ function commitUnstagedWork(cwd, ignorePatterns = []) {
494
517
  try {
518
+ if (ignorePatterns.length > 0) {
519
+ const gitignorePath = path.join(cwd, ".gitignore");
520
+ try {
521
+ const existing = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, "utf-8") : "";
522
+ const missing = ignorePatterns.filter((p) => !existing.includes(p));
523
+ if (missing.length > 0) {
524
+ const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
525
+ fs.appendFileSync(gitignorePath, `${separator}# Added by ULPI CI worker
526
+ ${missing.join("\n")}
527
+ `);
528
+ }
529
+ } catch {
530
+ }
531
+ }
495
532
  const status = execFileSync("git", ["status", "--porcelain"], {
496
533
  cwd,
497
534
  encoding: "utf-8",
@@ -500,10 +537,11 @@ function commitUnstagedWork(cwd) {
500
537
  if (!status) return;
501
538
  const fileCount = status.split("\n").filter(Boolean).length;
502
539
  console.log(chalk.blue(`[ulpi-ci] Committing ${fileCount} uncommitted files...`));
503
- execFileSync("git", ["add", "-A"], { cwd, timeout: 3e4 });
504
- execFileSync("git", ["commit", "-m", "wip: auto-commit from ULPI CI worker"], {
540
+ execFileSync("git", ["add", "-A"], { cwd, timeout: 6e5, maxBuffer: 50 * 1024 * 1024 });
541
+ execFileSync("git", ["commit", "--no-verify", "-m", "wip: auto-commit from ULPI CI worker"], {
505
542
  cwd,
506
- timeout: 3e4
543
+ timeout: 6e5,
544
+ maxBuffer: 50 * 1024 * 1024
507
545
  });
508
546
  console.log(chalk.blue("[ulpi-ci] WIP commit created"));
509
547
  } catch (err) {
@@ -522,8 +560,8 @@ async function postSessionFinalize(projectDir) {
522
560
  writeHistoryEntry,
523
561
  readBranchMeta,
524
562
  DEFAULT_HISTORY_CONFIG
525
- } = await import("./dist-5R4RYNQO.js");
526
- const { loadActiveGuards } = await import("./dist-5R4RYNQO.js");
563
+ } = await import("./dist-YCNWHSLN.js");
564
+ const { loadActiveGuards } = await import("./dist-YCNWHSLN.js");
527
565
  if (historyBranchExists(projectDir)) {
528
566
  const commits = listBranchOnlyCommits(projectDir, 50);
529
567
  const meta = readBranchMeta(projectDir);
@@ -563,9 +601,9 @@ async function postSessionFinalize(projectDir) {
563
601
  console.log(chalk.yellow(`[ulpi-ci] Warning: History backfill failed: ${err instanceof Error ? err.message : String(err)}`));
564
602
  }
565
603
  try {
566
- const { isMemoryInitialized, classifySession } = await import("./dist-7WLLPWWB.js");
567
- const { ULPI_GLOBAL_DIR } = await import("./dist-GWGTAHNM.js");
568
- const { JsonSessionStore } = await import("./dist-XD4YI27T.js");
604
+ const { isMemoryInitialized, classifySession } = await import("./dist-JLU26AB6.js");
605
+ const { ULPI_GLOBAL_DIR } = await import("./dist-NUXMDXZ3.js");
606
+ const { JsonSessionStore } = await import("./dist-6M4MZWZW.js");
569
607
  if (isMemoryInitialized(projectDir)) {
570
608
  const store = new JsonSessionStore(ULPI_GLOBAL_DIR, projectDir);
571
609
  const latest = store.getLatestForProject(projectDir);
@@ -586,6 +624,66 @@ async function postSessionFinalize(projectDir) {
586
624
  console.log(chalk.yellow(`[ulpi-ci] Warning: Memory classify failed: ${err instanceof Error ? err.message : String(err)}`));
587
625
  }
588
626
  }
627
+ async function exportShadowBranches(projectDir) {
628
+ try {
629
+ const { getCodemapStatus, exportIndex } = await import("./dist-YFFG2ZD6.js");
630
+ const { getCurrentBranch } = await import("./dist-NUXMDXZ3.js");
631
+ const branch = getCurrentBranch(projectDir);
632
+ const status = getCodemapStatus(projectDir, branch);
633
+ if (status.initialized) {
634
+ const result = await exportIndex(projectDir, branch);
635
+ console.log(chalk.blue(`[ulpi-ci] Codemap exported to ${result.branchName} (${result.filesExported} files)`));
636
+ }
637
+ } catch (err) {
638
+ console.log(chalk.yellow(`[ulpi-ci] Warning: Codemap export failed: ${err instanceof Error ? err.message : String(err)}`));
639
+ }
640
+ try {
641
+ const { isMemoryInitialized, exportMemories } = await import("./dist-JLU26AB6.js");
642
+ if (isMemoryInitialized(projectDir)) {
643
+ const result = await exportMemories(projectDir);
644
+ console.log(chalk.blue(`[ulpi-ci] Memory exported to ${result.branchName} (${result.memoriesExported} memories, ${result.filesExported} files)`));
645
+ }
646
+ } catch (err) {
647
+ console.log(chalk.yellow(`[ulpi-ci] Warning: Memory export failed: ${err instanceof Error ? err.message : String(err)}`));
648
+ }
649
+ }
650
+ function logClaudeMdFiles(projectDir) {
651
+ const rootMd = path.join(projectDir, "CLAUDE.md");
652
+ if (fs.existsSync(rootMd)) {
653
+ const stat = fs.statSync(rootMd);
654
+ console.log(chalk.blue(`[ulpi-ci] Found CLAUDE.md (${stat.size} bytes)`));
655
+ } else {
656
+ console.log(chalk.yellow("[ulpi-ci] No CLAUDE.md in workspace root"));
657
+ }
658
+ const claudeDir = path.join(projectDir, ".claude");
659
+ if (fs.existsSync(claudeDir)) {
660
+ const items = [];
661
+ try {
662
+ for (const entry of fs.readdirSync(claudeDir, { recursive: true })) {
663
+ if (entry.endsWith(".md") || entry === "settings.local.json") {
664
+ items.push(entry);
665
+ }
666
+ }
667
+ } catch {
668
+ }
669
+ console.log(chalk.blue(`[ulpi-ci] .claude/ contents: ${items.length > 0 ? items.join(", ") : "(empty)"}`));
670
+ } else {
671
+ console.log(chalk.yellow("[ulpi-ci] No .claude/ directory in workspace"));
672
+ }
673
+ try {
674
+ const nested = [];
675
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
676
+ if (entry.isDirectory() && !entry.name.startsWith(".")) {
677
+ const nestedMd = path.join(projectDir, entry.name, "CLAUDE.md");
678
+ if (fs.existsSync(nestedMd)) nested.push(entry.name);
679
+ }
680
+ }
681
+ if (nested.length > 0) {
682
+ console.log(chalk.blue(`[ulpi-ci] Nested CLAUDE.md: ${nested.join(", ")}`));
683
+ }
684
+ } catch {
685
+ }
686
+ }
589
687
  function findClaudeBinary() {
590
688
  try {
591
689
  const result = execFileSync("which", ["claude"], { encoding: "utf-8", timeout: 5e3 });
@@ -662,7 +760,7 @@ function spawnClaude(claudePath, args, prompt, timeoutMs) {
662
760
  return new Promise((resolve) => {
663
761
  const proc = spawn(claudePath, args, {
664
762
  cwd: process.cwd(),
665
- env: process.env,
763
+ env: { ...process.env, ULPI_RUN_MODE: "ci" },
666
764
  stdio: ["pipe", "pipe", "pipe"]
667
765
  });
668
766
  let stdout = "";