@rely-ai/caliber 1.23.0-dev.1773792440 → 1.23.0-dev.1773793983

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 (2) hide show
  1. package/dist/bin.js +560 -491
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -25,9 +25,11 @@ var config_exports = {};
25
25
  __export(config_exports, {
26
26
  DEFAULT_FAST_MODELS: () => DEFAULT_FAST_MODELS,
27
27
  DEFAULT_MODELS: () => DEFAULT_MODELS,
28
+ MODEL_CONTEXT_WINDOWS: () => MODEL_CONTEXT_WINDOWS,
28
29
  getConfigFilePath: () => getConfigFilePath,
29
30
  getDisplayModel: () => getDisplayModel,
30
31
  getFastModel: () => getFastModel,
32
+ getMaxPromptTokens: () => getMaxPromptTokens,
31
33
  loadConfig: () => loadConfig,
32
34
  readConfigFile: () => readConfigFile,
33
35
  resolveFromEnv: () => resolveFromEnv,
@@ -36,6 +38,13 @@ __export(config_exports, {
36
38
  import fs4 from "fs";
37
39
  import path4 from "path";
38
40
  import os from "os";
41
+ function getMaxPromptTokens() {
42
+ const config = loadConfig();
43
+ const model = process.env.CALIBER_MODEL || config?.model;
44
+ const contextWindow = model ? MODEL_CONTEXT_WINDOWS[model] ?? DEFAULT_CONTEXT_WINDOW : DEFAULT_CONTEXT_WINDOW;
45
+ const budget = Math.floor(contextWindow * INPUT_BUDGET_FRACTION);
46
+ return Math.max(MIN_PROMPT_TOKENS, Math.min(budget, MAX_PROMPT_TOKENS_CAP));
47
+ }
39
48
  function loadConfig() {
40
49
  const envConfig = resolveFromEnv();
41
50
  if (envConfig) return envConfig;
@@ -123,7 +132,7 @@ function getFastModel() {
123
132
  if (provider) return DEFAULT_FAST_MODELS[provider];
124
133
  return void 0;
125
134
  }
126
- var CONFIG_DIR, CONFIG_FILE, DEFAULT_MODELS, DEFAULT_FAST_MODELS;
135
+ var CONFIG_DIR, CONFIG_FILE, DEFAULT_MODELS, MODEL_CONTEXT_WINDOWS, DEFAULT_CONTEXT_WINDOW, INPUT_BUDGET_FRACTION, MAX_PROMPT_TOKENS_CAP, MIN_PROMPT_TOKENS, DEFAULT_FAST_MODELS;
127
136
  var init_config = __esm({
128
137
  "src/llm/config.ts"() {
129
138
  "use strict";
@@ -136,6 +145,21 @@ var init_config = __esm({
136
145
  cursor: "sonnet-4.6",
137
146
  "claude-cli": "default"
138
147
  };
148
+ MODEL_CONTEXT_WINDOWS = {
149
+ "claude-sonnet-4-6": 2e5,
150
+ "claude-opus-4-6": 2e5,
151
+ "claude-haiku-4-5-20251001": 2e5,
152
+ "claude-sonnet-4-5-20250514": 2e5,
153
+ "gpt-4.1": 1e6,
154
+ "gpt-4.1-mini": 1e6,
155
+ "gpt-4o": 128e3,
156
+ "gpt-4o-mini": 128e3,
157
+ "sonnet-4.6": 2e5
158
+ };
159
+ DEFAULT_CONTEXT_WINDOW = 2e5;
160
+ INPUT_BUDGET_FRACTION = 0.6;
161
+ MAX_PROMPT_TOKENS_CAP = 3e5;
162
+ MIN_PROMPT_TOKENS = 3e4;
139
163
  DEFAULT_FAST_MODELS = {
140
164
  anthropic: "claude-haiku-4-5-20251001",
141
165
  vertex: "claude-haiku-4-5-20251001",
@@ -158,17 +182,17 @@ __export(constants_exports, {
158
182
  LEARNING_STATE_FILE: () => LEARNING_STATE_FILE,
159
183
  MANIFEST_FILE: () => MANIFEST_FILE
160
184
  });
161
- import path9 from "path";
185
+ import path10 from "path";
162
186
  import os3 from "os";
163
187
  var AUTH_DIR, CALIBER_DIR, MANIFEST_FILE, BACKUPS_DIR, LEARNING_DIR, LEARNING_SESSION_FILE, LEARNING_STATE_FILE, LEARNING_MAX_EVENTS, LEARNING_ROI_FILE;
164
188
  var init_constants = __esm({
165
189
  "src/constants.ts"() {
166
190
  "use strict";
167
- AUTH_DIR = path9.join(os3.homedir(), ".caliber");
191
+ AUTH_DIR = path10.join(os3.homedir(), ".caliber");
168
192
  CALIBER_DIR = ".caliber";
169
- MANIFEST_FILE = path9.join(CALIBER_DIR, "manifest.json");
170
- BACKUPS_DIR = path9.join(CALIBER_DIR, "backups");
171
- LEARNING_DIR = path9.join(CALIBER_DIR, "learning");
193
+ MANIFEST_FILE = path10.join(CALIBER_DIR, "manifest.json");
194
+ BACKUPS_DIR = path10.join(CALIBER_DIR, "backups");
195
+ LEARNING_DIR = path10.join(CALIBER_DIR, "learning");
172
196
  LEARNING_SESSION_FILE = "current-session.jsonl";
173
197
  LEARNING_STATE_FILE = "state.json";
174
198
  LEARNING_MAX_EVENTS = 500;
@@ -183,13 +207,13 @@ __export(lock_exports, {
183
207
  isCaliberRunning: () => isCaliberRunning,
184
208
  releaseLock: () => releaseLock
185
209
  });
186
- import fs29 from "fs";
187
- import path23 from "path";
210
+ import fs30 from "fs";
211
+ import path24 from "path";
188
212
  import os6 from "os";
189
213
  function isCaliberRunning() {
190
214
  try {
191
- if (!fs29.existsSync(LOCK_FILE)) return false;
192
- const raw = fs29.readFileSync(LOCK_FILE, "utf-8").trim();
215
+ if (!fs30.existsSync(LOCK_FILE)) return false;
216
+ const raw = fs30.readFileSync(LOCK_FILE, "utf-8").trim();
193
217
  const { pid, ts } = JSON.parse(raw);
194
218
  if (Date.now() - ts > STALE_MS) return false;
195
219
  try {
@@ -204,13 +228,13 @@ function isCaliberRunning() {
204
228
  }
205
229
  function acquireLock() {
206
230
  try {
207
- fs29.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
231
+ fs30.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
208
232
  } catch {
209
233
  }
210
234
  }
211
235
  function releaseLock() {
212
236
  try {
213
- if (fs29.existsSync(LOCK_FILE)) fs29.unlinkSync(LOCK_FILE);
237
+ if (fs30.existsSync(LOCK_FILE)) fs30.unlinkSync(LOCK_FILE);
214
238
  } catch {
215
239
  }
216
240
  }
@@ -218,28 +242,28 @@ var LOCK_FILE, STALE_MS;
218
242
  var init_lock = __esm({
219
243
  "src/lib/lock.ts"() {
220
244
  "use strict";
221
- LOCK_FILE = path23.join(os6.tmpdir(), ".caliber.lock");
245
+ LOCK_FILE = path24.join(os6.tmpdir(), ".caliber.lock");
222
246
  STALE_MS = 10 * 60 * 1e3;
223
247
  }
224
248
  });
225
249
 
226
250
  // src/cli.ts
227
251
  import { Command } from "commander";
228
- import fs34 from "fs";
229
- import path27 from "path";
252
+ import fs35 from "fs";
253
+ import path28 from "path";
230
254
  import { fileURLToPath } from "url";
231
255
 
232
256
  // src/commands/init.ts
233
- import path20 from "path";
257
+ import path21 from "path";
234
258
  import chalk11 from "chalk";
235
259
  import ora3 from "ora";
236
260
  import select5 from "@inquirer/select";
237
261
  import checkbox from "@inquirer/checkbox";
238
- import fs25 from "fs";
262
+ import fs26 from "fs";
239
263
 
240
264
  // src/fingerprint/index.ts
241
- import fs6 from "fs";
242
- import path5 from "path";
265
+ import fs7 from "fs";
266
+ import path6 from "path";
243
267
 
244
268
  // src/fingerprint/git.ts
245
269
  import { execSync } from "child_process";
@@ -292,15 +316,23 @@ function getFileTree(dir, maxDepth = 3) {
292
316
  for (const e of entries) {
293
317
  (e.isDir ? dirs : files).push(e);
294
318
  }
295
- for (const d of dirs) {
296
- const prefix = d.relPath;
297
- let maxChildMtime = d.mtime;
298
- for (const f of files) {
299
- if (f.relPath.startsWith(prefix) && f.mtime > maxChildMtime) {
300
- maxChildMtime = f.mtime;
319
+ const dirMaxMtime = /* @__PURE__ */ new Map();
320
+ for (const d of dirs) dirMaxMtime.set(d.relPath, d.mtime);
321
+ for (const f of files) {
322
+ let remaining = f.relPath;
323
+ while (true) {
324
+ const lastSlash = remaining.lastIndexOf("/");
325
+ if (lastSlash === -1) break;
326
+ const dirPrefix = remaining.slice(0, lastSlash + 1);
327
+ const current = dirMaxMtime.get(dirPrefix);
328
+ if (current !== void 0 && f.mtime > current) {
329
+ dirMaxMtime.set(dirPrefix, f.mtime);
301
330
  }
331
+ remaining = remaining.slice(0, lastSlash);
302
332
  }
303
- d.mtime = maxChildMtime;
333
+ }
334
+ for (const d of dirs) {
335
+ d.mtime = dirMaxMtime.get(d.relPath) ?? d.mtime;
304
336
  }
305
337
  dirs.sort((a, b) => b.mtime - a.mtime);
306
338
  files.sort((a, b) => b.mtime - a.mtime);
@@ -2212,12 +2244,112 @@ async function detectProjectStack(fileTree, suffixCounts) {
2212
2244
 
2213
2245
  // src/fingerprint/index.ts
2214
2246
  init_config();
2247
+
2248
+ // src/fingerprint/cache.ts
2249
+ import fs6 from "fs";
2250
+ import path5 from "path";
2251
+ import crypto from "crypto";
2252
+ import { execSync as execSync5 } from "child_process";
2253
+ var CACHE_VERSION = 1;
2254
+ var CACHE_DIR = ".caliber/cache";
2255
+ var CACHE_FILE = "fingerprint.json";
2256
+ function getCachePath(dir) {
2257
+ return path5.join(dir, CACHE_DIR, CACHE_FILE);
2258
+ }
2259
+ function getGitHead(dir) {
2260
+ try {
2261
+ return execSync5("git rev-parse HEAD", {
2262
+ cwd: dir,
2263
+ encoding: "utf-8",
2264
+ stdio: ["pipe", "pipe", "pipe"],
2265
+ timeout: 3e3
2266
+ }).trim();
2267
+ } catch {
2268
+ return "";
2269
+ }
2270
+ }
2271
+ function getDirtySignature(dir) {
2272
+ try {
2273
+ const output = execSync5("git diff --name-only HEAD", {
2274
+ cwd: dir,
2275
+ encoding: "utf-8",
2276
+ stdio: ["pipe", "pipe", "pipe"],
2277
+ timeout: 3e3
2278
+ }).trim();
2279
+ return output.split("\n").slice(0, 100).join("\n");
2280
+ } catch {
2281
+ return "";
2282
+ }
2283
+ }
2284
+ function computeTreeSignature(fileTree, dir) {
2285
+ const hash = crypto.createHash("sha256");
2286
+ hash.update(fileTree.join("\0"));
2287
+ hash.update("\n");
2288
+ hash.update(getDirtySignature(dir));
2289
+ return hash.digest("hex").slice(0, 16);
2290
+ }
2291
+ function loadFingerprintCache(dir, fileTree) {
2292
+ const cachePath = getCachePath(dir);
2293
+ try {
2294
+ if (!fs6.existsSync(cachePath)) return null;
2295
+ const raw = fs6.readFileSync(cachePath, "utf-8");
2296
+ const cache = JSON.parse(raw);
2297
+ if (cache.version !== CACHE_VERSION) return null;
2298
+ const currentHead = getGitHead(dir);
2299
+ if (currentHead && cache.gitHead !== currentHead) return null;
2300
+ const currentSig = computeTreeSignature(fileTree, dir);
2301
+ if (cache.treeSignature !== currentSig) return null;
2302
+ return {
2303
+ codeAnalysis: cache.codeAnalysis,
2304
+ languages: cache.languages,
2305
+ frameworks: cache.frameworks,
2306
+ tools: cache.tools
2307
+ };
2308
+ } catch {
2309
+ return null;
2310
+ }
2311
+ }
2312
+ function saveFingerprintCache(dir, fileTree, codeAnalysis, languages, frameworks, tools) {
2313
+ const cachePath = getCachePath(dir);
2314
+ try {
2315
+ const cacheDir = path5.dirname(cachePath);
2316
+ if (!fs6.existsSync(cacheDir)) {
2317
+ fs6.mkdirSync(cacheDir, { recursive: true });
2318
+ }
2319
+ const cache = {
2320
+ version: CACHE_VERSION,
2321
+ gitHead: getGitHead(dir),
2322
+ treeSignature: computeTreeSignature(fileTree, dir),
2323
+ codeAnalysis,
2324
+ languages,
2325
+ frameworks,
2326
+ tools
2327
+ };
2328
+ fs6.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
2329
+ } catch {
2330
+ }
2331
+ }
2332
+
2333
+ // src/fingerprint/index.ts
2215
2334
  async function collectFingerprint(dir) {
2216
2335
  const gitRemoteUrl = getGitRemoteUrl();
2217
2336
  const fileTree = getFileTree(dir);
2218
2337
  const existingConfigs = readExistingConfigs(dir);
2219
- const codeAnalysis = analyzeCode(dir);
2220
2338
  const packageName = readPackageName(dir);
2339
+ const cached = loadFingerprintCache(dir, fileTree);
2340
+ if (cached) {
2341
+ return {
2342
+ gitRemoteUrl,
2343
+ packageName,
2344
+ languages: cached.languages,
2345
+ frameworks: cached.frameworks,
2346
+ tools: cached.tools,
2347
+ fileTree,
2348
+ existingConfigs,
2349
+ codeAnalysis: cached.codeAnalysis
2350
+ };
2351
+ }
2352
+ const codeAnalysis = analyzeCode(dir);
2221
2353
  const fingerprint = {
2222
2354
  gitRemoteUrl,
2223
2355
  packageName,
@@ -2229,13 +2361,21 @@ async function collectFingerprint(dir) {
2229
2361
  codeAnalysis
2230
2362
  };
2231
2363
  await enrichWithLLM(fingerprint);
2364
+ saveFingerprintCache(
2365
+ dir,
2366
+ fileTree,
2367
+ codeAnalysis,
2368
+ fingerprint.languages,
2369
+ fingerprint.frameworks,
2370
+ fingerprint.tools
2371
+ );
2232
2372
  return fingerprint;
2233
2373
  }
2234
2374
  function readPackageName(dir) {
2235
2375
  try {
2236
- const pkgPath = path5.join(dir, "package.json");
2237
- if (!fs6.existsSync(pkgPath)) return void 0;
2238
- const pkg3 = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
2376
+ const pkgPath = path6.join(dir, "package.json");
2377
+ if (!fs7.existsSync(pkgPath)) return void 0;
2378
+ const pkg3 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2239
2379
  return pkg3.name;
2240
2380
  } catch {
2241
2381
  return void 0;
@@ -2249,7 +2389,7 @@ async function enrichWithLLM(fingerprint) {
2249
2389
  const suffixCounts = {};
2250
2390
  for (const entry of fingerprint.fileTree) {
2251
2391
  if (entry.endsWith("/")) continue;
2252
- const ext = path5.extname(entry).toLowerCase();
2392
+ const ext = path6.extname(entry).toLowerCase();
2253
2393
  if (ext) {
2254
2394
  suffixCounts[ext] = (suffixCounts[ext] || 0) + 1;
2255
2395
  }
@@ -2268,15 +2408,15 @@ init_config();
2268
2408
  // src/utils/dependencies.ts
2269
2409
  import { readFileSync } from "fs";
2270
2410
  import { join } from "path";
2271
- function readFileOrNull(path29) {
2411
+ function readFileOrNull(path30) {
2272
2412
  try {
2273
- return readFileSync(path29, "utf-8");
2413
+ return readFileSync(path30, "utf-8");
2274
2414
  } catch {
2275
2415
  return null;
2276
2416
  }
2277
2417
  }
2278
- function readJsonOrNull(path29) {
2279
- const content = readFileOrNull(path29);
2418
+ function readJsonOrNull(path30) {
2419
+ const content = readFileOrNull(path30);
2280
2420
  if (!content) return null;
2281
2421
  try {
2282
2422
  return JSON.parse(content);
@@ -2500,15 +2640,14 @@ Generate the skill content following the instructions in the system prompt.`;
2500
2640
  content
2501
2641
  };
2502
2642
  }
2503
- async function generateCore(fingerprint, targetAgent, prompt, callbacks, failingChecks, currentScore, passingChecks) {
2643
+ async function streamGeneration(config) {
2504
2644
  const provider = getProvider();
2505
- const userMessage = buildGeneratePrompt(fingerprint, targetAgent, prompt, failingChecks, currentScore, passingChecks);
2506
2645
  let attempt = 0;
2507
2646
  const attemptGeneration = async () => {
2508
2647
  attempt++;
2509
2648
  const maxTokensForAttempt = Math.min(
2510
- CORE_MAX_TOKENS + attempt * 8e3,
2511
- GENERATION_MAX_TOKENS
2649
+ config.baseMaxTokens + attempt * config.tokenIncrement,
2650
+ config.maxTokensCap
2512
2651
  );
2513
2652
  return new Promise((resolve2) => {
2514
2653
  let preJsonBuffer = "";
@@ -2518,8 +2657,8 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
2518
2657
  let stopReason = null;
2519
2658
  provider.stream(
2520
2659
  {
2521
- system: CORE_GENERATION_PROMPT,
2522
- prompt: userMessage,
2660
+ system: config.systemPrompt,
2661
+ prompt: config.userMessage,
2523
2662
  maxTokens: maxTokensForAttempt
2524
2663
  },
2525
2664
  {
@@ -2532,7 +2671,7 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
2532
2671
  const trimmed = completedLines[i].trim();
2533
2672
  if (trimmed.startsWith("STATUS:")) {
2534
2673
  const status = trimmed.slice(7).trim();
2535
- if (status && callbacks) callbacks.onStatus(status);
2674
+ if (status && config.callbacks) config.callbacks.onStatus(status);
2536
2675
  }
2537
2676
  }
2538
2677
  sentStatuses = completedLines.length;
@@ -2562,7 +2701,7 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
2562
2701
  } catch {
2563
2702
  }
2564
2703
  if (!setup && stopReason === "max_tokens" && attempt < MAX_RETRIES2) {
2565
- if (callbacks) callbacks.onStatus("Output was truncated, retrying with higher token limit...");
2704
+ if (config.callbacks) config.callbacks.onStatus("Output was truncated, retrying with higher token limit...");
2566
2705
  setTimeout(() => attemptGeneration().then(resolve2), 1e3);
2567
2706
  return;
2568
2707
  }
@@ -2572,7 +2711,7 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
2572
2711
  explanation = explainMatch[1].trim();
2573
2712
  }
2574
2713
  if (setup) {
2575
- if (callbacks) callbacks.onComplete(setup, explanation);
2714
+ if (config.callbacks) config.callbacks.onComplete(setup, explanation);
2576
2715
  resolve2({ setup, explanation, stopReason: stopReason ?? void 0 });
2577
2716
  } else {
2578
2717
  resolve2({ setup: null, explanation, raw: preJsonBuffer, stopReason: stopReason ?? void 0 });
@@ -2580,117 +2719,43 @@ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failing
2580
2719
  },
2581
2720
  onError: (error) => {
2582
2721
  if (isTransientError2(error) && attempt < MAX_RETRIES2) {
2583
- if (callbacks) callbacks.onStatus("Connection interrupted, retrying...");
2722
+ if (config.callbacks) config.callbacks.onStatus("Connection interrupted, retrying...");
2584
2723
  setTimeout(() => attemptGeneration().then(resolve2), 2e3);
2585
2724
  return;
2586
2725
  }
2587
- if (callbacks) callbacks.onError(error.message);
2726
+ if (config.callbacks) config.callbacks.onError(error.message);
2588
2727
  resolve2({ setup: null, raw: error.message, stopReason: "error" });
2589
2728
  }
2590
2729
  }
2591
2730
  ).catch((error) => {
2592
- if (callbacks) callbacks.onError(error.message);
2731
+ if (config.callbacks) config.callbacks.onError(error.message);
2593
2732
  resolve2({ setup: null, raw: error.message, stopReason: "error" });
2594
2733
  });
2595
2734
  });
2596
2735
  };
2597
2736
  return attemptGeneration();
2598
2737
  }
2738
+ async function generateCore(fingerprint, targetAgent, prompt, callbacks, failingChecks, currentScore, passingChecks) {
2739
+ const userMessage = buildGeneratePrompt(fingerprint, targetAgent, prompt, failingChecks, currentScore, passingChecks);
2740
+ return streamGeneration({
2741
+ systemPrompt: CORE_GENERATION_PROMPT,
2742
+ userMessage,
2743
+ baseMaxTokens: CORE_MAX_TOKENS,
2744
+ tokenIncrement: 8e3,
2745
+ maxTokensCap: GENERATION_MAX_TOKENS,
2746
+ callbacks
2747
+ });
2748
+ }
2599
2749
  async function generateMonolithic(fingerprint, targetAgent, prompt, callbacks, failingChecks, currentScore, passingChecks) {
2600
- const provider = getProvider();
2601
2750
  const userMessage = buildGeneratePrompt(fingerprint, targetAgent, prompt, failingChecks, currentScore, passingChecks);
2602
- let attempt = 0;
2603
- const attemptGeneration = async () => {
2604
- attempt++;
2605
- const maxTokensForAttempt = Math.min(
2606
- GENERATION_MAX_TOKENS + attempt * 16e3,
2607
- MODEL_MAX_OUTPUT_TOKENS
2608
- );
2609
- return new Promise((resolve2) => {
2610
- let preJsonBuffer = "";
2611
- let jsonContent = "";
2612
- let inJson = false;
2613
- let sentStatuses = 0;
2614
- let stopReason = null;
2615
- provider.stream(
2616
- {
2617
- system: GENERATION_SYSTEM_PROMPT,
2618
- prompt: userMessage,
2619
- maxTokens: maxTokensForAttempt
2620
- },
2621
- {
2622
- onText: (text) => {
2623
- if (!inJson) {
2624
- preJsonBuffer += text;
2625
- const lines = preJsonBuffer.split("\n");
2626
- const completedLines = lines.slice(0, -1);
2627
- for (let i = sentStatuses; i < completedLines.length; i++) {
2628
- const trimmed = completedLines[i].trim();
2629
- if (trimmed.startsWith("STATUS:")) {
2630
- const status = trimmed.slice(7).trim();
2631
- if (status && callbacks) callbacks.onStatus(status);
2632
- }
2633
- }
2634
- sentStatuses = completedLines.length;
2635
- const jsonStartMatch = preJsonBuffer.match(/(?:^|\n)\s*(?:```json\s*\n\s*)?\{(?=\s*")/);
2636
- if (jsonStartMatch) {
2637
- const matchIndex = preJsonBuffer.indexOf("{", jsonStartMatch.index);
2638
- inJson = true;
2639
- jsonContent = preJsonBuffer.slice(matchIndex);
2640
- }
2641
- } else {
2642
- jsonContent += text;
2643
- }
2644
- },
2645
- onEnd: (meta) => {
2646
- stopReason = meta?.stopReason ?? null;
2647
- let setup = null;
2648
- let jsonToParse = (jsonContent || preJsonBuffer).replace(/```\s*$/g, "").trim();
2649
- if (!jsonContent && preJsonBuffer) {
2650
- const fallbackMatch = preJsonBuffer.match(/(?:^|\n)\s*(?:```json\s*\n\s*)?\{(?=\s*")/);
2651
- if (fallbackMatch) {
2652
- const matchIndex = preJsonBuffer.indexOf("{", fallbackMatch.index);
2653
- jsonToParse = preJsonBuffer.slice(matchIndex).replace(/```\s*$/g, "").trim();
2654
- }
2655
- }
2656
- try {
2657
- setup = JSON.parse(jsonToParse);
2658
- } catch {
2659
- }
2660
- if (!setup && stopReason === "max_tokens" && attempt < MAX_RETRIES2) {
2661
- if (callbacks) callbacks.onStatus("Output was truncated, retrying with higher token limit...");
2662
- setTimeout(() => attemptGeneration().then(resolve2), 1e3);
2663
- return;
2664
- }
2665
- let explanation;
2666
- const explainMatch = preJsonBuffer.match(/EXPLAIN:\s*\n([\s\S]*?)(?=\n\s*(`{3}|\{))/);
2667
- if (explainMatch) {
2668
- explanation = explainMatch[1].trim();
2669
- }
2670
- if (setup) {
2671
- if (callbacks) callbacks.onComplete(setup, explanation);
2672
- resolve2({ setup, explanation, stopReason: stopReason ?? void 0 });
2673
- } else {
2674
- resolve2({ setup: null, explanation, raw: preJsonBuffer, stopReason: stopReason ?? void 0 });
2675
- }
2676
- },
2677
- onError: (error) => {
2678
- if (isTransientError2(error) && attempt < MAX_RETRIES2) {
2679
- if (callbacks) callbacks.onStatus("Connection interrupted, retrying...");
2680
- setTimeout(() => attemptGeneration().then(resolve2), 2e3);
2681
- return;
2682
- }
2683
- if (callbacks) callbacks.onError(error.message);
2684
- resolve2({ setup: null, raw: error.message, stopReason: "error" });
2685
- }
2686
- }
2687
- ).catch((error) => {
2688
- if (callbacks) callbacks.onError(error.message);
2689
- resolve2({ setup: null, raw: error.message, stopReason: "error" });
2690
- });
2691
- });
2692
- };
2693
- return attemptGeneration();
2751
+ return streamGeneration({
2752
+ systemPrompt: GENERATION_SYSTEM_PROMPT,
2753
+ userMessage,
2754
+ baseMaxTokens: GENERATION_MAX_TOKENS,
2755
+ tokenIncrement: 16e3,
2756
+ maxTokensCap: MODEL_MAX_OUTPUT_TOKENS,
2757
+ callbacks
2758
+ });
2694
2759
  }
2695
2760
  async function generateSkillsForSetup(setup, fingerprint, targetAgent, onStatus) {
2696
2761
  const skillTopics = collectSkillTopics(setup, targetAgent, fingerprint);
@@ -2723,7 +2788,6 @@ async function generateSkillsForSetup(setup, fingerprint, targetAgent, onStatus)
2723
2788
  if (failed > 0) onStatus?.(`${succeeded} generated, ${failed} failed`);
2724
2789
  return succeeded;
2725
2790
  }
2726
- var MAX_PROMPT_TOKENS = 12e4;
2727
2791
  var LIMITS = {
2728
2792
  FILE_TREE_ENTRIES: 500,
2729
2793
  EXISTING_CONFIG_CHARS: 8e3,
@@ -2738,6 +2802,7 @@ function truncate(text, maxChars) {
2738
2802
  }
2739
2803
  function sampleFileTree(fileTree, codeAnalysisPaths, limit) {
2740
2804
  if (fileTree.length <= limit) return fileTree;
2805
+ const fileTreeSet = new Set(fileTree);
2741
2806
  const dirs = [];
2742
2807
  const rootFiles = [];
2743
2808
  const nestedFiles = [];
@@ -2763,7 +2828,7 @@ function sampleFileTree(fileTree, codeAnalysisPaths, limit) {
2763
2828
  for (const f of rootFiles.slice(0, 50)) add(f);
2764
2829
  for (const p of codeAnalysisPaths) {
2765
2830
  if (result.length >= limit) break;
2766
- if (fileTree.includes(p)) add(p);
2831
+ if (fileTreeSet.has(p)) add(p);
2767
2832
  }
2768
2833
  for (const f of nestedFiles) {
2769
2834
  if (result.length >= limit) break;
@@ -2887,20 +2952,25 @@ User instructions: ${prompt}`);
2887
2952
  if (fingerprint.codeAnalysis) {
2888
2953
  const ca = fingerprint.codeAnalysis;
2889
2954
  const basePrompt = parts.join("\n");
2955
+ const maxPromptTokens = getMaxPromptTokens();
2890
2956
  const baseTokens = estimateTokens(basePrompt);
2891
- const tokenBudgetForCode = Math.max(0, MAX_PROMPT_TOKENS - baseTokens);
2957
+ const tokenBudgetForCode = Math.max(0, maxPromptTokens - baseTokens);
2892
2958
  const codeLines = [];
2893
2959
  let codeChars = 0;
2894
- codeLines.push("Study these files to extract patterns for skills. Use the exact code patterns you see here.\n");
2960
+ const introLine = "Study these files to extract patterns for skills. Use the exact code patterns you see here.\n";
2961
+ codeLines.push(introLine);
2962
+ let runningCodeLen = introLine.length;
2895
2963
  const sortedFiles = [...ca.files].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
2896
2964
  let includedFiles = 0;
2897
2965
  for (const f of sortedFiles) {
2898
2966
  const entry = `[${f.path}]
2899
2967
  ${f.content}
2900
2968
  `;
2901
- if (estimateTokens(codeLines.join("\n") + entry) > tokenBudgetForCode && includedFiles > 0) break;
2969
+ const projectedLen = runningCodeLen + 1 + entry.length;
2970
+ if (Math.ceil(projectedLen / 4) > tokenBudgetForCode && includedFiles > 0) break;
2902
2971
  codeLines.push(entry);
2903
2972
  codeChars += f.content.length;
2973
+ runningCodeLen = projectedLen;
2904
2974
  includedFiles++;
2905
2975
  }
2906
2976
  const includedTokens = Math.ceil(codeChars / 4);
@@ -2971,20 +3041,20 @@ Return the complete updated AgentSetup JSON incorporating the user's changes. Re
2971
3041
  }
2972
3042
 
2973
3043
  // src/writers/index.ts
2974
- import fs12 from "fs";
3044
+ import fs13 from "fs";
2975
3045
 
2976
3046
  // src/writers/claude/index.ts
2977
- import fs7 from "fs";
2978
- import path6 from "path";
3047
+ import fs8 from "fs";
3048
+ import path7 from "path";
2979
3049
  function writeClaudeConfig(config) {
2980
3050
  const written = [];
2981
- fs7.writeFileSync("CLAUDE.md", config.claudeMd);
3051
+ fs8.writeFileSync("CLAUDE.md", config.claudeMd);
2982
3052
  written.push("CLAUDE.md");
2983
3053
  if (config.skills?.length) {
2984
3054
  for (const skill of config.skills) {
2985
- const skillDir = path6.join(".claude", "skills", skill.name);
2986
- if (!fs7.existsSync(skillDir)) fs7.mkdirSync(skillDir, { recursive: true });
2987
- const skillPath = path6.join(skillDir, "SKILL.md");
3055
+ const skillDir = path7.join(".claude", "skills", skill.name);
3056
+ if (!fs8.existsSync(skillDir)) fs8.mkdirSync(skillDir, { recursive: true });
3057
+ const skillPath = path7.join(skillDir, "SKILL.md");
2988
3058
  const frontmatter = [
2989
3059
  "---",
2990
3060
  `name: ${skill.name}`,
@@ -2992,49 +3062,49 @@ function writeClaudeConfig(config) {
2992
3062
  "---",
2993
3063
  ""
2994
3064
  ].join("\n");
2995
- fs7.writeFileSync(skillPath, frontmatter + skill.content);
3065
+ fs8.writeFileSync(skillPath, frontmatter + skill.content);
2996
3066
  written.push(skillPath);
2997
3067
  }
2998
3068
  }
2999
3069
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
3000
3070
  let existingServers = {};
3001
3071
  try {
3002
- if (fs7.existsSync(".mcp.json")) {
3003
- const existing = JSON.parse(fs7.readFileSync(".mcp.json", "utf-8"));
3072
+ if (fs8.existsSync(".mcp.json")) {
3073
+ const existing = JSON.parse(fs8.readFileSync(".mcp.json", "utf-8"));
3004
3074
  if (existing.mcpServers) existingServers = existing.mcpServers;
3005
3075
  }
3006
3076
  } catch {
3007
3077
  }
3008
3078
  const mergedServers = { ...existingServers, ...config.mcpServers };
3009
- fs7.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
3079
+ fs8.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
3010
3080
  written.push(".mcp.json");
3011
3081
  }
3012
3082
  return written;
3013
3083
  }
3014
3084
 
3015
3085
  // src/writers/cursor/index.ts
3016
- import fs8 from "fs";
3017
- import path7 from "path";
3086
+ import fs9 from "fs";
3087
+ import path8 from "path";
3018
3088
  function writeCursorConfig(config) {
3019
3089
  const written = [];
3020
3090
  if (config.cursorrules) {
3021
- fs8.writeFileSync(".cursorrules", config.cursorrules);
3091
+ fs9.writeFileSync(".cursorrules", config.cursorrules);
3022
3092
  written.push(".cursorrules");
3023
3093
  }
3024
3094
  if (config.rules?.length) {
3025
- const rulesDir = path7.join(".cursor", "rules");
3026
- if (!fs8.existsSync(rulesDir)) fs8.mkdirSync(rulesDir, { recursive: true });
3095
+ const rulesDir = path8.join(".cursor", "rules");
3096
+ if (!fs9.existsSync(rulesDir)) fs9.mkdirSync(rulesDir, { recursive: true });
3027
3097
  for (const rule of config.rules) {
3028
- const rulePath = path7.join(rulesDir, rule.filename);
3029
- fs8.writeFileSync(rulePath, rule.content);
3098
+ const rulePath = path8.join(rulesDir, rule.filename);
3099
+ fs9.writeFileSync(rulePath, rule.content);
3030
3100
  written.push(rulePath);
3031
3101
  }
3032
3102
  }
3033
3103
  if (config.skills?.length) {
3034
3104
  for (const skill of config.skills) {
3035
- const skillDir = path7.join(".cursor", "skills", skill.name);
3036
- if (!fs8.existsSync(skillDir)) fs8.mkdirSync(skillDir, { recursive: true });
3037
- const skillPath = path7.join(skillDir, "SKILL.md");
3105
+ const skillDir = path8.join(".cursor", "skills", skill.name);
3106
+ if (!fs9.existsSync(skillDir)) fs9.mkdirSync(skillDir, { recursive: true });
3107
+ const skillPath = path8.join(skillDir, "SKILL.md");
3038
3108
  const frontmatter = [
3039
3109
  "---",
3040
3110
  `name: ${skill.name}`,
@@ -3042,41 +3112,41 @@ function writeCursorConfig(config) {
3042
3112
  "---",
3043
3113
  ""
3044
3114
  ].join("\n");
3045
- fs8.writeFileSync(skillPath, frontmatter + skill.content);
3115
+ fs9.writeFileSync(skillPath, frontmatter + skill.content);
3046
3116
  written.push(skillPath);
3047
3117
  }
3048
3118
  }
3049
3119
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
3050
3120
  const cursorDir = ".cursor";
3051
- if (!fs8.existsSync(cursorDir)) fs8.mkdirSync(cursorDir, { recursive: true });
3052
- const mcpPath = path7.join(cursorDir, "mcp.json");
3121
+ if (!fs9.existsSync(cursorDir)) fs9.mkdirSync(cursorDir, { recursive: true });
3122
+ const mcpPath = path8.join(cursorDir, "mcp.json");
3053
3123
  let existingServers = {};
3054
3124
  try {
3055
- if (fs8.existsSync(mcpPath)) {
3056
- const existing = JSON.parse(fs8.readFileSync(mcpPath, "utf-8"));
3125
+ if (fs9.existsSync(mcpPath)) {
3126
+ const existing = JSON.parse(fs9.readFileSync(mcpPath, "utf-8"));
3057
3127
  if (existing.mcpServers) existingServers = existing.mcpServers;
3058
3128
  }
3059
3129
  } catch {
3060
3130
  }
3061
3131
  const mergedServers = { ...existingServers, ...config.mcpServers };
3062
- fs8.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
3132
+ fs9.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
3063
3133
  written.push(mcpPath);
3064
3134
  }
3065
3135
  return written;
3066
3136
  }
3067
3137
 
3068
3138
  // src/writers/codex/index.ts
3069
- import fs9 from "fs";
3070
- import path8 from "path";
3139
+ import fs10 from "fs";
3140
+ import path9 from "path";
3071
3141
  function writeCodexConfig(config) {
3072
3142
  const written = [];
3073
- fs9.writeFileSync("AGENTS.md", config.agentsMd);
3143
+ fs10.writeFileSync("AGENTS.md", config.agentsMd);
3074
3144
  written.push("AGENTS.md");
3075
3145
  if (config.skills?.length) {
3076
3146
  for (const skill of config.skills) {
3077
- const skillDir = path8.join(".agents", "skills", skill.name);
3078
- if (!fs9.existsSync(skillDir)) fs9.mkdirSync(skillDir, { recursive: true });
3079
- const skillPath = path8.join(skillDir, "SKILL.md");
3147
+ const skillDir = path9.join(".agents", "skills", skill.name);
3148
+ if (!fs10.existsSync(skillDir)) fs10.mkdirSync(skillDir, { recursive: true });
3149
+ const skillPath = path9.join(skillDir, "SKILL.md");
3080
3150
  const frontmatter = [
3081
3151
  "---",
3082
3152
  `name: ${skill.name}`,
@@ -3084,7 +3154,7 @@ function writeCodexConfig(config) {
3084
3154
  "---",
3085
3155
  ""
3086
3156
  ].join("\n");
3087
- fs9.writeFileSync(skillPath, frontmatter + skill.content);
3157
+ fs10.writeFileSync(skillPath, frontmatter + skill.content);
3088
3158
  written.push(skillPath);
3089
3159
  }
3090
3160
  }
@@ -3093,62 +3163,62 @@ function writeCodexConfig(config) {
3093
3163
 
3094
3164
  // src/writers/backup.ts
3095
3165
  init_constants();
3096
- import fs10 from "fs";
3097
- import path10 from "path";
3166
+ import fs11 from "fs";
3167
+ import path11 from "path";
3098
3168
  function createBackup(files) {
3099
3169
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3100
- const backupDir = path10.join(BACKUPS_DIR, timestamp);
3170
+ const backupDir = path11.join(BACKUPS_DIR, timestamp);
3101
3171
  for (const file of files) {
3102
- if (!fs10.existsSync(file)) continue;
3103
- const dest = path10.join(backupDir, file);
3104
- const destDir = path10.dirname(dest);
3105
- if (!fs10.existsSync(destDir)) {
3106
- fs10.mkdirSync(destDir, { recursive: true });
3172
+ if (!fs11.existsSync(file)) continue;
3173
+ const dest = path11.join(backupDir, file);
3174
+ const destDir = path11.dirname(dest);
3175
+ if (!fs11.existsSync(destDir)) {
3176
+ fs11.mkdirSync(destDir, { recursive: true });
3107
3177
  }
3108
- fs10.copyFileSync(file, dest);
3178
+ fs11.copyFileSync(file, dest);
3109
3179
  }
3110
3180
  return backupDir;
3111
3181
  }
3112
3182
  function restoreBackup(backupDir, file) {
3113
- const backupFile = path10.join(backupDir, file);
3114
- if (!fs10.existsSync(backupFile)) return false;
3115
- const destDir = path10.dirname(file);
3116
- if (!fs10.existsSync(destDir)) {
3117
- fs10.mkdirSync(destDir, { recursive: true });
3183
+ const backupFile = path11.join(backupDir, file);
3184
+ if (!fs11.existsSync(backupFile)) return false;
3185
+ const destDir = path11.dirname(file);
3186
+ if (!fs11.existsSync(destDir)) {
3187
+ fs11.mkdirSync(destDir, { recursive: true });
3118
3188
  }
3119
- fs10.copyFileSync(backupFile, file);
3189
+ fs11.copyFileSync(backupFile, file);
3120
3190
  return true;
3121
3191
  }
3122
3192
 
3123
3193
  // src/writers/manifest.ts
3124
3194
  init_constants();
3125
- import fs11 from "fs";
3126
- import crypto from "crypto";
3195
+ import fs12 from "fs";
3196
+ import crypto2 from "crypto";
3127
3197
  function readManifest() {
3128
3198
  try {
3129
- if (!fs11.existsSync(MANIFEST_FILE)) return null;
3130
- return JSON.parse(fs11.readFileSync(MANIFEST_FILE, "utf-8"));
3199
+ if (!fs12.existsSync(MANIFEST_FILE)) return null;
3200
+ return JSON.parse(fs12.readFileSync(MANIFEST_FILE, "utf-8"));
3131
3201
  } catch {
3132
3202
  return null;
3133
3203
  }
3134
3204
  }
3135
3205
  function writeManifest(manifest) {
3136
- if (!fs11.existsSync(CALIBER_DIR)) {
3137
- fs11.mkdirSync(CALIBER_DIR, { recursive: true });
3206
+ if (!fs12.existsSync(CALIBER_DIR)) {
3207
+ fs12.mkdirSync(CALIBER_DIR, { recursive: true });
3138
3208
  }
3139
- fs11.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
3209
+ fs12.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
3140
3210
  }
3141
3211
  function fileChecksum(filePath) {
3142
- const content = fs11.readFileSync(filePath);
3143
- return crypto.createHash("sha256").update(content).digest("hex");
3212
+ const content = fs12.readFileSync(filePath);
3213
+ return crypto2.createHash("sha256").update(content).digest("hex");
3144
3214
  }
3145
3215
 
3146
3216
  // src/writers/index.ts
3147
3217
  function writeSetup(setup) {
3148
3218
  const filesToWrite = getFilesToWrite(setup);
3149
- const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs12.existsSync(f));
3219
+ const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs13.existsSync(f));
3150
3220
  const existingFiles = [
3151
- ...filesToWrite.filter((f) => fs12.existsSync(f)),
3221
+ ...filesToWrite.filter((f) => fs13.existsSync(f)),
3152
3222
  ...filesToDelete
3153
3223
  ];
3154
3224
  const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
@@ -3164,7 +3234,7 @@ function writeSetup(setup) {
3164
3234
  }
3165
3235
  const deleted = [];
3166
3236
  for (const filePath of filesToDelete) {
3167
- fs12.unlinkSync(filePath);
3237
+ fs13.unlinkSync(filePath);
3168
3238
  deleted.push(filePath);
3169
3239
  }
3170
3240
  ensureGitignore();
@@ -3194,8 +3264,8 @@ function undoSetup() {
3194
3264
  const removed = [];
3195
3265
  for (const entry of manifest.entries) {
3196
3266
  if (entry.action === "created") {
3197
- if (fs12.existsSync(entry.path)) {
3198
- fs12.unlinkSync(entry.path);
3267
+ if (fs13.existsSync(entry.path)) {
3268
+ fs13.unlinkSync(entry.path);
3199
3269
  removed.push(entry.path);
3200
3270
  }
3201
3271
  } else if ((entry.action === "modified" || entry.action === "deleted") && manifest.backupDir) {
@@ -3205,8 +3275,8 @@ function undoSetup() {
3205
3275
  }
3206
3276
  }
3207
3277
  const { MANIFEST_FILE: MANIFEST_FILE2 } = (init_constants(), __toCommonJS(constants_exports));
3208
- if (fs12.existsSync(MANIFEST_FILE2)) {
3209
- fs12.unlinkSync(MANIFEST_FILE2);
3278
+ if (fs13.existsSync(MANIFEST_FILE2)) {
3279
+ fs13.unlinkSync(MANIFEST_FILE2);
3210
3280
  }
3211
3281
  return { restored, removed };
3212
3282
  }
@@ -3241,23 +3311,23 @@ function getFilesToWrite(setup) {
3241
3311
  }
3242
3312
  function ensureGitignore() {
3243
3313
  const gitignorePath = ".gitignore";
3244
- if (fs12.existsSync(gitignorePath)) {
3245
- const content = fs12.readFileSync(gitignorePath, "utf-8");
3314
+ if (fs13.existsSync(gitignorePath)) {
3315
+ const content = fs13.readFileSync(gitignorePath, "utf-8");
3246
3316
  if (!content.includes(".caliber/")) {
3247
- fs12.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
3317
+ fs13.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
3248
3318
  }
3249
3319
  } else {
3250
- fs12.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
3320
+ fs13.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
3251
3321
  }
3252
3322
  }
3253
3323
 
3254
3324
  // src/writers/staging.ts
3255
3325
  init_constants();
3256
- import fs13 from "fs";
3257
- import path11 from "path";
3258
- var STAGED_DIR = path11.join(CALIBER_DIR, "staged");
3259
- var PROPOSED_DIR = path11.join(STAGED_DIR, "proposed");
3260
- var CURRENT_DIR = path11.join(STAGED_DIR, "current");
3326
+ import fs14 from "fs";
3327
+ import path12 from "path";
3328
+ var STAGED_DIR = path12.join(CALIBER_DIR, "staged");
3329
+ var PROPOSED_DIR = path12.join(STAGED_DIR, "proposed");
3330
+ var CURRENT_DIR = path12.join(STAGED_DIR, "current");
3261
3331
  function normalizeContent(content) {
3262
3332
  return content.split("\n").map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
3263
3333
  }
@@ -3267,20 +3337,20 @@ function stageFiles(files, projectDir) {
3267
3337
  let modifiedFiles = 0;
3268
3338
  const stagedFiles = [];
3269
3339
  for (const file of files) {
3270
- const originalPath = path11.join(projectDir, file.path);
3271
- if (fs13.existsSync(originalPath)) {
3272
- const existing = fs13.readFileSync(originalPath, "utf-8");
3340
+ const originalPath = path12.join(projectDir, file.path);
3341
+ if (fs14.existsSync(originalPath)) {
3342
+ const existing = fs14.readFileSync(originalPath, "utf-8");
3273
3343
  if (normalizeContent(existing) === normalizeContent(file.content)) {
3274
3344
  continue;
3275
3345
  }
3276
3346
  }
3277
- const proposedPath = path11.join(PROPOSED_DIR, file.path);
3278
- fs13.mkdirSync(path11.dirname(proposedPath), { recursive: true });
3279
- fs13.writeFileSync(proposedPath, file.content);
3280
- if (fs13.existsSync(originalPath)) {
3281
- const currentPath = path11.join(CURRENT_DIR, file.path);
3282
- fs13.mkdirSync(path11.dirname(currentPath), { recursive: true });
3283
- fs13.copyFileSync(originalPath, currentPath);
3347
+ const proposedPath = path12.join(PROPOSED_DIR, file.path);
3348
+ fs14.mkdirSync(path12.dirname(proposedPath), { recursive: true });
3349
+ fs14.writeFileSync(proposedPath, file.content);
3350
+ if (fs14.existsSync(originalPath)) {
3351
+ const currentPath = path12.join(CURRENT_DIR, file.path);
3352
+ fs14.mkdirSync(path12.dirname(currentPath), { recursive: true });
3353
+ fs14.copyFileSync(originalPath, currentPath);
3284
3354
  modifiedFiles++;
3285
3355
  stagedFiles.push({ relativePath: file.path, proposedPath, currentPath, originalPath, isNew: false });
3286
3356
  } else {
@@ -3291,34 +3361,34 @@ function stageFiles(files, projectDir) {
3291
3361
  return { newFiles, modifiedFiles, stagedFiles };
3292
3362
  }
3293
3363
  function cleanupStaging() {
3294
- if (fs13.existsSync(STAGED_DIR)) {
3295
- fs13.rmSync(STAGED_DIR, { recursive: true, force: true });
3364
+ if (fs14.existsSync(STAGED_DIR)) {
3365
+ fs14.rmSync(STAGED_DIR, { recursive: true, force: true });
3296
3366
  }
3297
3367
  }
3298
3368
 
3299
3369
  // src/utils/review.ts
3300
3370
  import chalk2 from "chalk";
3301
- import fs15 from "fs";
3371
+ import fs16 from "fs";
3302
3372
  import select2 from "@inquirer/select";
3303
3373
  import { createTwoFilesPatch } from "diff";
3304
3374
 
3305
3375
  // src/utils/editor.ts
3306
- import { execSync as execSync5, spawn as spawn3 } from "child_process";
3307
- import fs14 from "fs";
3308
- import path12 from "path";
3376
+ import { execSync as execSync6, spawn as spawn3 } from "child_process";
3377
+ import fs15 from "fs";
3378
+ import path13 from "path";
3309
3379
  import os4 from "os";
3310
3380
  var IS_WINDOWS3 = process.platform === "win32";
3311
- var DIFF_TEMP_DIR = path12.join(os4.tmpdir(), "caliber-diff");
3381
+ var DIFF_TEMP_DIR = path13.join(os4.tmpdir(), "caliber-diff");
3312
3382
  function getEmptyFilePath(proposedPath) {
3313
- fs14.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
3314
- const tempPath = path12.join(DIFF_TEMP_DIR, path12.basename(proposedPath));
3315
- fs14.writeFileSync(tempPath, "");
3383
+ fs15.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
3384
+ const tempPath = path13.join(DIFF_TEMP_DIR, path13.basename(proposedPath));
3385
+ fs15.writeFileSync(tempPath, "");
3316
3386
  return tempPath;
3317
3387
  }
3318
3388
  function commandExists(cmd) {
3319
3389
  try {
3320
3390
  const check = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
3321
- execSync5(check, { stdio: "ignore" });
3391
+ execSync6(check, { stdio: "ignore" });
3322
3392
  return true;
3323
3393
  } catch {
3324
3394
  return false;
@@ -3383,8 +3453,8 @@ async function openReview(method, stagedFiles) {
3383
3453
  return;
3384
3454
  }
3385
3455
  const fileInfos = stagedFiles.map((file) => {
3386
- const proposed = fs15.readFileSync(file.proposedPath, "utf-8");
3387
- const current = file.currentPath ? fs15.readFileSync(file.currentPath, "utf-8") : "";
3456
+ const proposed = fs16.readFileSync(file.proposedPath, "utf-8");
3457
+ const current = file.currentPath ? fs16.readFileSync(file.currentPath, "utf-8") : "";
3388
3458
  const patch = createTwoFilesPatch(
3389
3459
  file.isNew ? "/dev/null" : file.relativePath,
3390
3460
  file.relativePath,
@@ -3547,7 +3617,7 @@ async function interactiveDiffExplorer(files) {
3547
3617
  }
3548
3618
 
3549
3619
  // src/commands/setup-files.ts
3550
- import fs16 from "fs";
3620
+ import fs17 from "fs";
3551
3621
  function buildSkillContent(skill) {
3552
3622
  const frontmatter = `---
3553
3623
  name: ${skill.name}
@@ -3596,7 +3666,7 @@ function collectSetupFiles(setup, targetAgent) {
3596
3666
  }
3597
3667
  }
3598
3668
  const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
3599
- if (codexTargeted && !fs16.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
3669
+ if (codexTargeted && !fs17.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
3600
3670
  const agentRefs = [];
3601
3671
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
3602
3672
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
@@ -3613,13 +3683,13 @@ ${agentRefs.join(" ")}
3613
3683
  }
3614
3684
 
3615
3685
  // src/lib/hooks.ts
3616
- import fs18 from "fs";
3617
- import path13 from "path";
3618
- import { execSync as execSync7 } from "child_process";
3686
+ import fs19 from "fs";
3687
+ import path14 from "path";
3688
+ import { execSync as execSync8 } from "child_process";
3619
3689
 
3620
3690
  // src/lib/resolve-caliber.ts
3621
- import fs17 from "fs";
3622
- import { execSync as execSync6 } from "child_process";
3691
+ import fs18 from "fs";
3692
+ import { execSync as execSync7 } from "child_process";
3623
3693
  var _resolved = null;
3624
3694
  function resolveCaliber() {
3625
3695
  if (_resolved) return _resolved;
@@ -3630,7 +3700,7 @@ function resolveCaliber() {
3630
3700
  }
3631
3701
  try {
3632
3702
  const whichCmd = process.platform === "win32" ? "where caliber" : "which caliber";
3633
- const found = execSync6(whichCmd, {
3703
+ const found = execSync7(whichCmd, {
3634
3704
  encoding: "utf-8",
3635
3705
  stdio: ["pipe", "pipe", "pipe"]
3636
3706
  }).trim();
@@ -3641,7 +3711,7 @@ function resolveCaliber() {
3641
3711
  } catch {
3642
3712
  }
3643
3713
  const binPath = process.argv[1];
3644
- if (binPath && fs17.existsSync(binPath)) {
3714
+ if (binPath && fs18.existsSync(binPath)) {
3645
3715
  _resolved = binPath;
3646
3716
  return _resolved;
3647
3717
  }
@@ -3657,24 +3727,24 @@ function isCaliberCommand(command, subcommandTail) {
3657
3727
  }
3658
3728
 
3659
3729
  // src/lib/hooks.ts
3660
- var SETTINGS_PATH = path13.join(".claude", "settings.json");
3730
+ var SETTINGS_PATH = path14.join(".claude", "settings.json");
3661
3731
  var REFRESH_TAIL = "refresh --quiet";
3662
3732
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
3663
3733
  function getHookCommand() {
3664
3734
  return `${resolveCaliber()} ${REFRESH_TAIL}`;
3665
3735
  }
3666
3736
  function readSettings() {
3667
- if (!fs18.existsSync(SETTINGS_PATH)) return {};
3737
+ if (!fs19.existsSync(SETTINGS_PATH)) return {};
3668
3738
  try {
3669
- return JSON.parse(fs18.readFileSync(SETTINGS_PATH, "utf-8"));
3739
+ return JSON.parse(fs19.readFileSync(SETTINGS_PATH, "utf-8"));
3670
3740
  } catch {
3671
3741
  return {};
3672
3742
  }
3673
3743
  }
3674
3744
  function writeSettings(settings) {
3675
- const dir = path13.dirname(SETTINGS_PATH);
3676
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
3677
- fs18.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
3745
+ const dir = path14.dirname(SETTINGS_PATH);
3746
+ if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
3747
+ fs19.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
3678
3748
  }
3679
3749
  function findHookIndex(sessionEnd) {
3680
3750
  return sessionEnd.findIndex(
@@ -3736,20 +3806,20 @@ ${PRECOMMIT_END}`;
3736
3806
  }
3737
3807
  function getGitHooksDir() {
3738
3808
  try {
3739
- const gitDir = execSync7("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3740
- return path13.join(gitDir, "hooks");
3809
+ const gitDir = execSync8("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3810
+ return path14.join(gitDir, "hooks");
3741
3811
  } catch {
3742
3812
  return null;
3743
3813
  }
3744
3814
  }
3745
3815
  function getPreCommitPath() {
3746
3816
  const hooksDir = getGitHooksDir();
3747
- return hooksDir ? path13.join(hooksDir, "pre-commit") : null;
3817
+ return hooksDir ? path14.join(hooksDir, "pre-commit") : null;
3748
3818
  }
3749
3819
  function isPreCommitHookInstalled() {
3750
3820
  const hookPath = getPreCommitPath();
3751
- if (!hookPath || !fs18.existsSync(hookPath)) return false;
3752
- const content = fs18.readFileSync(hookPath, "utf-8");
3821
+ if (!hookPath || !fs19.existsSync(hookPath)) return false;
3822
+ const content = fs19.readFileSync(hookPath, "utf-8");
3753
3823
  return content.includes(PRECOMMIT_START);
3754
3824
  }
3755
3825
  function installPreCommitHook() {
@@ -3758,43 +3828,43 @@ function installPreCommitHook() {
3758
3828
  }
3759
3829
  const hookPath = getPreCommitPath();
3760
3830
  if (!hookPath) return { installed: false, alreadyInstalled: false };
3761
- const hooksDir = path13.dirname(hookPath);
3762
- if (!fs18.existsSync(hooksDir)) fs18.mkdirSync(hooksDir, { recursive: true });
3831
+ const hooksDir = path14.dirname(hookPath);
3832
+ if (!fs19.existsSync(hooksDir)) fs19.mkdirSync(hooksDir, { recursive: true });
3763
3833
  let content = "";
3764
- if (fs18.existsSync(hookPath)) {
3765
- content = fs18.readFileSync(hookPath, "utf-8");
3834
+ if (fs19.existsSync(hookPath)) {
3835
+ content = fs19.readFileSync(hookPath, "utf-8");
3766
3836
  if (!content.endsWith("\n")) content += "\n";
3767
3837
  content += "\n" + getPrecommitBlock() + "\n";
3768
3838
  } else {
3769
3839
  content = "#!/bin/sh\n\n" + getPrecommitBlock() + "\n";
3770
3840
  }
3771
- fs18.writeFileSync(hookPath, content);
3772
- fs18.chmodSync(hookPath, 493);
3841
+ fs19.writeFileSync(hookPath, content);
3842
+ fs19.chmodSync(hookPath, 493);
3773
3843
  return { installed: true, alreadyInstalled: false };
3774
3844
  }
3775
3845
  function removePreCommitHook() {
3776
3846
  const hookPath = getPreCommitPath();
3777
- if (!hookPath || !fs18.existsSync(hookPath)) {
3847
+ if (!hookPath || !fs19.existsSync(hookPath)) {
3778
3848
  return { removed: false, notFound: true };
3779
3849
  }
3780
- let content = fs18.readFileSync(hookPath, "utf-8");
3850
+ let content = fs19.readFileSync(hookPath, "utf-8");
3781
3851
  if (!content.includes(PRECOMMIT_START)) {
3782
3852
  return { removed: false, notFound: true };
3783
3853
  }
3784
3854
  const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
3785
3855
  content = content.replace(regex, "\n");
3786
3856
  if (content.trim() === "#!/bin/sh" || content.trim() === "") {
3787
- fs18.unlinkSync(hookPath);
3857
+ fs19.unlinkSync(hookPath);
3788
3858
  } else {
3789
- fs18.writeFileSync(hookPath, content);
3859
+ fs19.writeFileSync(hookPath, content);
3790
3860
  }
3791
3861
  return { removed: true, notFound: false };
3792
3862
  }
3793
3863
 
3794
3864
  // src/lib/learning-hooks.ts
3795
- import fs19 from "fs";
3796
- import path14 from "path";
3797
- var SETTINGS_PATH2 = path14.join(".claude", "settings.json");
3865
+ import fs20 from "fs";
3866
+ import path15 from "path";
3867
+ var SETTINGS_PATH2 = path15.join(".claude", "settings.json");
3798
3868
  var HOOK_TAILS = [
3799
3869
  { event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
3800
3870
  { event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
@@ -3811,17 +3881,17 @@ function getHookConfigs() {
3811
3881
  }));
3812
3882
  }
3813
3883
  function readSettings2() {
3814
- if (!fs19.existsSync(SETTINGS_PATH2)) return {};
3884
+ if (!fs20.existsSync(SETTINGS_PATH2)) return {};
3815
3885
  try {
3816
- return JSON.parse(fs19.readFileSync(SETTINGS_PATH2, "utf-8"));
3886
+ return JSON.parse(fs20.readFileSync(SETTINGS_PATH2, "utf-8"));
3817
3887
  } catch {
3818
3888
  return {};
3819
3889
  }
3820
3890
  }
3821
3891
  function writeSettings2(settings) {
3822
- const dir = path14.dirname(SETTINGS_PATH2);
3823
- if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
3824
- fs19.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
3892
+ const dir = path15.dirname(SETTINGS_PATH2);
3893
+ if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
3894
+ fs20.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
3825
3895
  }
3826
3896
  function hasLearningHook(matchers, tail) {
3827
3897
  return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
@@ -3855,7 +3925,7 @@ function installLearningHooks() {
3855
3925
  writeSettings2(settings);
3856
3926
  return { installed: true, alreadyInstalled: false };
3857
3927
  }
3858
- var CURSOR_HOOKS_PATH = path14.join(".cursor", "hooks.json");
3928
+ var CURSOR_HOOKS_PATH = path15.join(".cursor", "hooks.json");
3859
3929
  var CURSOR_HOOK_EVENTS = [
3860
3930
  { event: "postToolUse", tail: "learn observe" },
3861
3931
  { event: "postToolUseFailure", tail: "learn observe --failure" },
@@ -3863,17 +3933,17 @@ var CURSOR_HOOK_EVENTS = [
3863
3933
  { event: "sessionEnd", tail: "learn finalize" }
3864
3934
  ];
3865
3935
  function readCursorHooks() {
3866
- if (!fs19.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
3936
+ if (!fs20.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
3867
3937
  try {
3868
- return JSON.parse(fs19.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
3938
+ return JSON.parse(fs20.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
3869
3939
  } catch {
3870
3940
  return { version: 1, hooks: {} };
3871
3941
  }
3872
3942
  }
3873
3943
  function writeCursorHooks(config) {
3874
- const dir = path14.dirname(CURSOR_HOOKS_PATH);
3875
- if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
3876
- fs19.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
3944
+ const dir = path15.dirname(CURSOR_HOOKS_PATH);
3945
+ if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
3946
+ fs20.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
3877
3947
  }
3878
3948
  function hasCursorHook(entries, tail) {
3879
3949
  return entries.some((e) => isCaliberCommand(e.command, tail));
@@ -3943,10 +4013,10 @@ function removeLearningHooks() {
3943
4013
 
3944
4014
  // src/lib/state.ts
3945
4015
  init_constants();
3946
- import fs20 from "fs";
3947
- import path15 from "path";
3948
- import { execSync as execSync8 } from "child_process";
3949
- var STATE_FILE = path15.join(CALIBER_DIR, ".caliber-state.json");
4016
+ import fs21 from "fs";
4017
+ import path16 from "path";
4018
+ import { execSync as execSync9 } from "child_process";
4019
+ var STATE_FILE = path16.join(CALIBER_DIR, ".caliber-state.json");
3950
4020
  function normalizeTargetAgent(value) {
3951
4021
  if (Array.isArray(value)) return value;
3952
4022
  if (typeof value === "string") {
@@ -3957,8 +4027,8 @@ function normalizeTargetAgent(value) {
3957
4027
  }
3958
4028
  function readState() {
3959
4029
  try {
3960
- if (!fs20.existsSync(STATE_FILE)) return null;
3961
- const raw = JSON.parse(fs20.readFileSync(STATE_FILE, "utf-8"));
4030
+ if (!fs21.existsSync(STATE_FILE)) return null;
4031
+ const raw = JSON.parse(fs21.readFileSync(STATE_FILE, "utf-8"));
3962
4032
  if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
3963
4033
  return raw;
3964
4034
  } catch {
@@ -3966,14 +4036,14 @@ function readState() {
3966
4036
  }
3967
4037
  }
3968
4038
  function writeState(state) {
3969
- if (!fs20.existsSync(CALIBER_DIR)) {
3970
- fs20.mkdirSync(CALIBER_DIR, { recursive: true });
4039
+ if (!fs21.existsSync(CALIBER_DIR)) {
4040
+ fs21.mkdirSync(CALIBER_DIR, { recursive: true });
3971
4041
  }
3972
- fs20.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
4042
+ fs21.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
3973
4043
  }
3974
4044
  function getCurrentHeadSha() {
3975
4045
  try {
3976
- return execSync8("git rev-parse HEAD", {
4046
+ return execSync9("git rev-parse HEAD", {
3977
4047
  encoding: "utf-8",
3978
4048
  stdio: ["pipe", "pipe", "pipe"]
3979
4049
  }).trim();
@@ -4918,7 +4988,7 @@ function checkGrounding(dir) {
4918
4988
 
4919
4989
  // src/scoring/checks/accuracy.ts
4920
4990
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
4921
- import { execSync as execSync9 } from "child_process";
4991
+ import { execSync as execSync10 } from "child_process";
4922
4992
  import { join as join5 } from "path";
4923
4993
  function validateReferences(dir) {
4924
4994
  const configContent = collectPrimaryConfigContent(dir);
@@ -4927,13 +4997,13 @@ function validateReferences(dir) {
4927
4997
  }
4928
4998
  function detectGitDrift(dir) {
4929
4999
  try {
4930
- execSync9("git rev-parse --git-dir", { cwd: dir, stdio: ["pipe", "pipe", "pipe"] });
5000
+ execSync10("git rev-parse --git-dir", { cwd: dir, stdio: ["pipe", "pipe", "pipe"] });
4931
5001
  } catch {
4932
5002
  return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: false };
4933
5003
  }
4934
5004
  const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules", ".cursor/rules"];
4935
5005
  try {
4936
- const headTimestamp = execSync9(
5006
+ const headTimestamp = execSync10(
4937
5007
  "git log -1 --format=%ct HEAD",
4938
5008
  { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4939
5009
  ).trim();
@@ -4954,7 +5024,7 @@ function detectGitDrift(dir) {
4954
5024
  let latestConfigCommitHash = null;
4955
5025
  for (const file of configFiles) {
4956
5026
  try {
4957
- const hash = execSync9(
5027
+ const hash = execSync10(
4958
5028
  `git log -1 --format=%H -- "${file}"`,
4959
5029
  { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4960
5030
  ).trim();
@@ -4963,7 +5033,7 @@ function detectGitDrift(dir) {
4963
5033
  latestConfigCommitHash = hash;
4964
5034
  } else {
4965
5035
  try {
4966
- execSync9(
5036
+ execSync10(
4967
5037
  `git merge-base --is-ancestor ${latestConfigCommitHash} ${hash}`,
4968
5038
  { cwd: dir, stdio: ["pipe", "pipe", "pipe"] }
4969
5039
  );
@@ -4978,12 +5048,12 @@ function detectGitDrift(dir) {
4978
5048
  return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: true };
4979
5049
  }
4980
5050
  try {
4981
- const countStr = execSync9(
5051
+ const countStr = execSync10(
4982
5052
  `git rev-list --count ${latestConfigCommitHash}..HEAD`,
4983
5053
  { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4984
5054
  ).trim();
4985
5055
  const commitsSince = parseInt(countStr, 10) || 0;
4986
- const lastDate = execSync9(
5056
+ const lastDate = execSync10(
4987
5057
  `git log -1 --format=%ci ${latestConfigCommitHash}`,
4988
5058
  { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4989
5059
  ).trim();
@@ -5055,12 +5125,12 @@ function checkAccuracy(dir) {
5055
5125
 
5056
5126
  // src/scoring/checks/freshness.ts
5057
5127
  import { existsSync as existsSync5, statSync as statSync3 } from "fs";
5058
- import { execSync as execSync10 } from "child_process";
5128
+ import { execSync as execSync11 } from "child_process";
5059
5129
  import { join as join6 } from "path";
5060
5130
  function getCommitsSinceConfigUpdate(dir) {
5061
5131
  const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules"];
5062
5132
  try {
5063
- const headTimestamp = execSync10(
5133
+ const headTimestamp = execSync11(
5064
5134
  "git log -1 --format=%ct HEAD",
5065
5135
  { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
5066
5136
  ).trim();
@@ -5080,12 +5150,12 @@ function getCommitsSinceConfigUpdate(dir) {
5080
5150
  }
5081
5151
  for (const file of configFiles) {
5082
5152
  try {
5083
- const hash = execSync10(
5153
+ const hash = execSync11(
5084
5154
  `git log -1 --format=%H -- "${file}"`,
5085
5155
  { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
5086
5156
  ).trim();
5087
5157
  if (hash) {
5088
- const countStr = execSync10(
5158
+ const countStr = execSync11(
5089
5159
  `git rev-list --count ${hash}..HEAD`,
5090
5160
  { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
5091
5161
  ).trim();
@@ -5203,11 +5273,11 @@ function checkFreshness(dir) {
5203
5273
 
5204
5274
  // src/scoring/checks/bonus.ts
5205
5275
  import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
5206
- import { execSync as execSync11 } from "child_process";
5276
+ import { execSync as execSync12 } from "child_process";
5207
5277
  import { join as join7 } from "path";
5208
5278
  function hasPreCommitHook(dir) {
5209
5279
  try {
5210
- const gitDir = execSync11("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
5280
+ const gitDir = execSync12("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
5211
5281
  const hookPath = join7(gitDir, "hooks", "pre-commit");
5212
5282
  const content = readFileOrNull2(hookPath);
5213
5283
  return content ? content.includes("caliber") : false;
@@ -5321,22 +5391,22 @@ function checkBonus(dir) {
5321
5391
 
5322
5392
  // src/scoring/dismissed.ts
5323
5393
  init_constants();
5324
- import fs21 from "fs";
5325
- import path16 from "path";
5326
- var DISMISSED_FILE = path16.join(CALIBER_DIR, "dismissed-checks.json");
5394
+ import fs22 from "fs";
5395
+ import path17 from "path";
5396
+ var DISMISSED_FILE = path17.join(CALIBER_DIR, "dismissed-checks.json");
5327
5397
  function readDismissedChecks() {
5328
5398
  try {
5329
- if (!fs21.existsSync(DISMISSED_FILE)) return [];
5330
- return JSON.parse(fs21.readFileSync(DISMISSED_FILE, "utf-8"));
5399
+ if (!fs22.existsSync(DISMISSED_FILE)) return [];
5400
+ return JSON.parse(fs22.readFileSync(DISMISSED_FILE, "utf-8"));
5331
5401
  } catch {
5332
5402
  return [];
5333
5403
  }
5334
5404
  }
5335
5405
  function writeDismissedChecks(checks) {
5336
- if (!fs21.existsSync(CALIBER_DIR)) {
5337
- fs21.mkdirSync(CALIBER_DIR, { recursive: true });
5406
+ if (!fs22.existsSync(CALIBER_DIR)) {
5407
+ fs22.mkdirSync(CALIBER_DIR, { recursive: true });
5338
5408
  }
5339
- fs21.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
5409
+ fs22.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
5340
5410
  }
5341
5411
  function getDismissedIds() {
5342
5412
  return new Set(readDismissedChecks().map((c) => c.id));
@@ -5581,13 +5651,13 @@ import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4,
5581
5651
  import { join as join9, dirname as dirname2 } from "path";
5582
5652
 
5583
5653
  // src/scanner/index.ts
5584
- import fs22 from "fs";
5585
- import path17 from "path";
5586
- import crypto2 from "crypto";
5654
+ import fs23 from "fs";
5655
+ import path18 from "path";
5656
+ import crypto3 from "crypto";
5587
5657
  function scanLocalState(dir) {
5588
5658
  const items = [];
5589
- const claudeMdPath = path17.join(dir, "CLAUDE.md");
5590
- if (fs22.existsSync(claudeMdPath)) {
5659
+ const claudeMdPath = path18.join(dir, "CLAUDE.md");
5660
+ if (fs23.existsSync(claudeMdPath)) {
5591
5661
  items.push({
5592
5662
  type: "rule",
5593
5663
  platform: "claude",
@@ -5596,10 +5666,10 @@ function scanLocalState(dir) {
5596
5666
  path: claudeMdPath
5597
5667
  });
5598
5668
  }
5599
- const skillsDir = path17.join(dir, ".claude", "skills");
5600
- if (fs22.existsSync(skillsDir)) {
5601
- for (const file of fs22.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5602
- const filePath = path17.join(skillsDir, file);
5669
+ const skillsDir = path18.join(dir, ".claude", "skills");
5670
+ if (fs23.existsSync(skillsDir)) {
5671
+ for (const file of fs23.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5672
+ const filePath = path18.join(skillsDir, file);
5603
5673
  items.push({
5604
5674
  type: "skill",
5605
5675
  platform: "claude",
@@ -5609,10 +5679,10 @@ function scanLocalState(dir) {
5609
5679
  });
5610
5680
  }
5611
5681
  }
5612
- const mcpJsonPath = path17.join(dir, ".mcp.json");
5613
- if (fs22.existsSync(mcpJsonPath)) {
5682
+ const mcpJsonPath = path18.join(dir, ".mcp.json");
5683
+ if (fs23.existsSync(mcpJsonPath)) {
5614
5684
  try {
5615
- const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
5685
+ const mcpJson = JSON.parse(fs23.readFileSync(mcpJsonPath, "utf-8"));
5616
5686
  if (mcpJson.mcpServers) {
5617
5687
  for (const name of Object.keys(mcpJson.mcpServers)) {
5618
5688
  items.push({
@@ -5627,8 +5697,8 @@ function scanLocalState(dir) {
5627
5697
  } catch {
5628
5698
  }
5629
5699
  }
5630
- const agentsMdPath = path17.join(dir, "AGENTS.md");
5631
- if (fs22.existsSync(agentsMdPath)) {
5700
+ const agentsMdPath = path18.join(dir, "AGENTS.md");
5701
+ if (fs23.existsSync(agentsMdPath)) {
5632
5702
  items.push({
5633
5703
  type: "rule",
5634
5704
  platform: "codex",
@@ -5637,12 +5707,12 @@ function scanLocalState(dir) {
5637
5707
  path: agentsMdPath
5638
5708
  });
5639
5709
  }
5640
- const codexSkillsDir = path17.join(dir, ".agents", "skills");
5641
- if (fs22.existsSync(codexSkillsDir)) {
5710
+ const codexSkillsDir = path18.join(dir, ".agents", "skills");
5711
+ if (fs23.existsSync(codexSkillsDir)) {
5642
5712
  try {
5643
- for (const name of fs22.readdirSync(codexSkillsDir)) {
5644
- const skillFile = path17.join(codexSkillsDir, name, "SKILL.md");
5645
- if (fs22.existsSync(skillFile)) {
5713
+ for (const name of fs23.readdirSync(codexSkillsDir)) {
5714
+ const skillFile = path18.join(codexSkillsDir, name, "SKILL.md");
5715
+ if (fs23.existsSync(skillFile)) {
5646
5716
  items.push({
5647
5717
  type: "skill",
5648
5718
  platform: "codex",
@@ -5655,8 +5725,8 @@ function scanLocalState(dir) {
5655
5725
  } catch {
5656
5726
  }
5657
5727
  }
5658
- const cursorrulesPath = path17.join(dir, ".cursorrules");
5659
- if (fs22.existsSync(cursorrulesPath)) {
5728
+ const cursorrulesPath = path18.join(dir, ".cursorrules");
5729
+ if (fs23.existsSync(cursorrulesPath)) {
5660
5730
  items.push({
5661
5731
  type: "rule",
5662
5732
  platform: "cursor",
@@ -5665,10 +5735,10 @@ function scanLocalState(dir) {
5665
5735
  path: cursorrulesPath
5666
5736
  });
5667
5737
  }
5668
- const cursorRulesDir = path17.join(dir, ".cursor", "rules");
5669
- if (fs22.existsSync(cursorRulesDir)) {
5670
- for (const file of fs22.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5671
- const filePath = path17.join(cursorRulesDir, file);
5738
+ const cursorRulesDir = path18.join(dir, ".cursor", "rules");
5739
+ if (fs23.existsSync(cursorRulesDir)) {
5740
+ for (const file of fs23.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5741
+ const filePath = path18.join(cursorRulesDir, file);
5672
5742
  items.push({
5673
5743
  type: "rule",
5674
5744
  platform: "cursor",
@@ -5678,12 +5748,12 @@ function scanLocalState(dir) {
5678
5748
  });
5679
5749
  }
5680
5750
  }
5681
- const cursorSkillsDir = path17.join(dir, ".cursor", "skills");
5682
- if (fs22.existsSync(cursorSkillsDir)) {
5751
+ const cursorSkillsDir = path18.join(dir, ".cursor", "skills");
5752
+ if (fs23.existsSync(cursorSkillsDir)) {
5683
5753
  try {
5684
- for (const name of fs22.readdirSync(cursorSkillsDir)) {
5685
- const skillFile = path17.join(cursorSkillsDir, name, "SKILL.md");
5686
- if (fs22.existsSync(skillFile)) {
5754
+ for (const name of fs23.readdirSync(cursorSkillsDir)) {
5755
+ const skillFile = path18.join(cursorSkillsDir, name, "SKILL.md");
5756
+ if (fs23.existsSync(skillFile)) {
5687
5757
  items.push({
5688
5758
  type: "skill",
5689
5759
  platform: "cursor",
@@ -5696,10 +5766,10 @@ function scanLocalState(dir) {
5696
5766
  } catch {
5697
5767
  }
5698
5768
  }
5699
- const cursorMcpPath = path17.join(dir, ".cursor", "mcp.json");
5700
- if (fs22.existsSync(cursorMcpPath)) {
5769
+ const cursorMcpPath = path18.join(dir, ".cursor", "mcp.json");
5770
+ if (fs23.existsSync(cursorMcpPath)) {
5701
5771
  try {
5702
- const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
5772
+ const mcpJson = JSON.parse(fs23.readFileSync(cursorMcpPath, "utf-8"));
5703
5773
  if (mcpJson.mcpServers) {
5704
5774
  for (const name of Object.keys(mcpJson.mcpServers)) {
5705
5775
  items.push({
@@ -5717,11 +5787,11 @@ function scanLocalState(dir) {
5717
5787
  return items;
5718
5788
  }
5719
5789
  function hashFile(filePath) {
5720
- const text = fs22.readFileSync(filePath, "utf-8");
5721
- return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
5790
+ const text = fs23.readFileSync(filePath, "utf-8");
5791
+ return crypto3.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
5722
5792
  }
5723
5793
  function hashJson(obj) {
5724
- return crypto2.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
5794
+ return crypto3.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
5725
5795
  }
5726
5796
 
5727
5797
  // src/commands/recommend.ts
@@ -5732,40 +5802,40 @@ import { PostHog } from "posthog-node";
5732
5802
  import chalk7 from "chalk";
5733
5803
 
5734
5804
  // src/telemetry/config.ts
5735
- import fs23 from "fs";
5736
- import path18 from "path";
5805
+ import fs24 from "fs";
5806
+ import path19 from "path";
5737
5807
  import os5 from "os";
5738
- import crypto3 from "crypto";
5739
- import { execSync as execSync12 } from "child_process";
5740
- var CONFIG_DIR2 = path18.join(os5.homedir(), ".caliber");
5741
- var CONFIG_FILE2 = path18.join(CONFIG_DIR2, "config.json");
5808
+ import crypto4 from "crypto";
5809
+ import { execSync as execSync13 } from "child_process";
5810
+ var CONFIG_DIR2 = path19.join(os5.homedir(), ".caliber");
5811
+ var CONFIG_FILE2 = path19.join(CONFIG_DIR2, "config.json");
5742
5812
  var runtimeDisabled = false;
5743
5813
  function readConfig() {
5744
5814
  try {
5745
- if (!fs23.existsSync(CONFIG_FILE2)) return {};
5746
- return JSON.parse(fs23.readFileSync(CONFIG_FILE2, "utf-8"));
5815
+ if (!fs24.existsSync(CONFIG_FILE2)) return {};
5816
+ return JSON.parse(fs24.readFileSync(CONFIG_FILE2, "utf-8"));
5747
5817
  } catch {
5748
5818
  return {};
5749
5819
  }
5750
5820
  }
5751
5821
  function writeConfig(config) {
5752
- if (!fs23.existsSync(CONFIG_DIR2)) {
5753
- fs23.mkdirSync(CONFIG_DIR2, { recursive: true });
5822
+ if (!fs24.existsSync(CONFIG_DIR2)) {
5823
+ fs24.mkdirSync(CONFIG_DIR2, { recursive: true });
5754
5824
  }
5755
- fs23.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
5825
+ fs24.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
5756
5826
  }
5757
5827
  function getMachineId() {
5758
5828
  const config = readConfig();
5759
5829
  if (config.machineId) return config.machineId;
5760
- const machineId = crypto3.randomUUID();
5830
+ const machineId = crypto4.randomUUID();
5761
5831
  writeConfig({ ...config, machineId });
5762
5832
  return machineId;
5763
5833
  }
5764
5834
  function getGitEmailHash() {
5765
5835
  try {
5766
- const email = execSync12("git config user.email", { encoding: "utf-8" }).trim();
5836
+ const email = execSync13("git config user.email", { encoding: "utf-8" }).trim();
5767
5837
  if (!email) return void 0;
5768
- return crypto3.createHash("sha256").update(email).digest("hex");
5838
+ return crypto4.createHash("sha256").update(email).digest("hex");
5769
5839
  } catch {
5770
5840
  return void 0;
5771
5841
  }
@@ -6708,11 +6778,11 @@ function countIssuePoints(issues) {
6708
6778
  }
6709
6779
  async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
6710
6780
  const existsCache = /* @__PURE__ */ new Map();
6711
- const cachedExists = (path29) => {
6712
- const cached = existsCache.get(path29);
6781
+ const cachedExists = (path30) => {
6782
+ const cached = existsCache.get(path30);
6713
6783
  if (cached !== void 0) return cached;
6714
- const result = existsSync9(path29);
6715
- existsCache.set(path29, result);
6784
+ const result = existsSync9(path30);
6785
+ existsCache.set(path30, result);
6716
6786
  return result;
6717
6787
  };
6718
6788
  const projectStructure = collectProjectStructure(dir);
@@ -6851,8 +6921,8 @@ async function runScoreRefineWithSpinner(setup, dir, sessionHistory) {
6851
6921
  }
6852
6922
 
6853
6923
  // src/lib/debug-report.ts
6854
- import fs24 from "fs";
6855
- import path19 from "path";
6924
+ import fs25 from "fs";
6925
+ import path20 from "path";
6856
6926
  var DebugReport = class {
6857
6927
  sections = [];
6858
6928
  startTime;
@@ -6921,11 +6991,11 @@ var DebugReport = class {
6921
6991
  lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
6922
6992
  lines.push("");
6923
6993
  }
6924
- const dir = path19.dirname(outputPath);
6925
- if (!fs24.existsSync(dir)) {
6926
- fs24.mkdirSync(dir, { recursive: true });
6994
+ const dir = path20.dirname(outputPath);
6995
+ if (!fs25.existsSync(dir)) {
6996
+ fs25.mkdirSync(dir, { recursive: true });
6927
6997
  }
6928
- fs24.writeFileSync(outputPath, lines.join("\n"));
6998
+ fs25.writeFileSync(outputPath, lines.join("\n"));
6929
6999
  }
6930
7000
  };
6931
7001
  function formatMs(ms) {
@@ -7421,11 +7491,10 @@ async function initCommand(options) {
7421
7491
  try {
7422
7492
  display.update(TASK_STACK, "running");
7423
7493
  fingerprint = await collectFingerprint(process.cwd());
7424
- const stackSummary = [
7425
- ...fingerprint.languages,
7426
- ...fingerprint.frameworks
7427
- ].join(", ") || "no languages";
7428
- display.update(TASK_STACK, "done", stackSummary);
7494
+ const stackParts = [...fingerprint.languages, ...fingerprint.frameworks];
7495
+ const stackSummary = stackParts.join(", ") || "no languages";
7496
+ const largeRepoNote = fingerprint.fileTree.length > 5e3 ? ` (${fingerprint.fileTree.length.toLocaleString()} files, smart sampling active)` : "";
7497
+ display.update(TASK_STACK, "done", stackSummary + largeRepoNote);
7429
7498
  trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
7430
7499
  log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
7431
7500
  if (report) {
@@ -7661,7 +7730,7 @@ async function initCommand(options) {
7661
7730
  }
7662
7731
  const writeSpinner = ora3("Writing config files...").start();
7663
7732
  try {
7664
- if (targetAgent.includes("codex") && !fs25.existsSync("AGENTS.md") && !generatedSetup.codex) {
7733
+ if (targetAgent.includes("codex") && !fs26.existsSync("AGENTS.md") && !generatedSetup.codex) {
7665
7734
  const claude = generatedSetup.claude;
7666
7735
  const cursor = generatedSetup.cursor;
7667
7736
  const agentRefs = [];
@@ -7845,9 +7914,9 @@ ${agentRefs.join(" ")}
7845
7914
  }
7846
7915
  if (report) {
7847
7916
  report.markStep("Finished");
7848
- const reportPath = path20.join(process.cwd(), ".caliber", "debug-report.md");
7917
+ const reportPath = path21.join(process.cwd(), ".caliber", "debug-report.md");
7849
7918
  report.write(reportPath);
7850
- console.log(chalk11.dim(` Debug report written to ${path20.relative(process.cwd(), reportPath)}
7919
+ console.log(chalk11.dim(` Debug report written to ${path21.relative(process.cwd(), reportPath)}
7851
7920
  `));
7852
7921
  }
7853
7922
  }
@@ -7894,7 +7963,7 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
7894
7963
  }
7895
7964
  function summarizeSetup(action, setup) {
7896
7965
  const descriptions = setup.fileDescriptions;
7897
- const files = descriptions ? Object.entries(descriptions).map(([path29, desc]) => ` ${path29}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
7966
+ const files = descriptions ? Object.entries(descriptions).map(([path30, desc]) => ` ${path30}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
7898
7967
  return `${action}. Files:
7899
7968
  ${files}`;
7900
7969
  }
@@ -8028,7 +8097,7 @@ function printSetupSummary(setup) {
8028
8097
  };
8029
8098
  if (claude) {
8030
8099
  if (claude.claudeMd) {
8031
- const icon = fs25.existsSync("CLAUDE.md") ? chalk11.yellow("~") : chalk11.green("+");
8100
+ const icon = fs26.existsSync("CLAUDE.md") ? chalk11.yellow("~") : chalk11.green("+");
8032
8101
  const desc = getDescription("CLAUDE.md");
8033
8102
  console.log(` ${icon} ${chalk11.bold("CLAUDE.md")}`);
8034
8103
  if (desc) console.log(chalk11.dim(` ${desc}`));
@@ -8038,7 +8107,7 @@ function printSetupSummary(setup) {
8038
8107
  if (Array.isArray(skills) && skills.length > 0) {
8039
8108
  for (const skill of skills) {
8040
8109
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
8041
- const icon = fs25.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
8110
+ const icon = fs26.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
8042
8111
  const desc = getDescription(skillPath);
8043
8112
  console.log(` ${icon} ${chalk11.bold(skillPath)}`);
8044
8113
  console.log(chalk11.dim(` ${desc || skill.description || skill.name}`));
@@ -8049,7 +8118,7 @@ function printSetupSummary(setup) {
8049
8118
  const codex = setup.codex;
8050
8119
  if (codex) {
8051
8120
  if (codex.agentsMd) {
8052
- const icon = fs25.existsSync("AGENTS.md") ? chalk11.yellow("~") : chalk11.green("+");
8121
+ const icon = fs26.existsSync("AGENTS.md") ? chalk11.yellow("~") : chalk11.green("+");
8053
8122
  const desc = getDescription("AGENTS.md");
8054
8123
  console.log(` ${icon} ${chalk11.bold("AGENTS.md")}`);
8055
8124
  if (desc) console.log(chalk11.dim(` ${desc}`));
@@ -8059,7 +8128,7 @@ function printSetupSummary(setup) {
8059
8128
  if (Array.isArray(codexSkills) && codexSkills.length > 0) {
8060
8129
  for (const skill of codexSkills) {
8061
8130
  const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
8062
- const icon = fs25.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
8131
+ const icon = fs26.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
8063
8132
  const desc = getDescription(skillPath);
8064
8133
  console.log(` ${icon} ${chalk11.bold(skillPath)}`);
8065
8134
  console.log(chalk11.dim(` ${desc || skill.description || skill.name}`));
@@ -8069,7 +8138,7 @@ function printSetupSummary(setup) {
8069
8138
  }
8070
8139
  if (cursor) {
8071
8140
  if (cursor.cursorrules) {
8072
- const icon = fs25.existsSync(".cursorrules") ? chalk11.yellow("~") : chalk11.green("+");
8141
+ const icon = fs26.existsSync(".cursorrules") ? chalk11.yellow("~") : chalk11.green("+");
8073
8142
  const desc = getDescription(".cursorrules");
8074
8143
  console.log(` ${icon} ${chalk11.bold(".cursorrules")}`);
8075
8144
  if (desc) console.log(chalk11.dim(` ${desc}`));
@@ -8079,7 +8148,7 @@ function printSetupSummary(setup) {
8079
8148
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
8080
8149
  for (const skill of cursorSkills) {
8081
8150
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
8082
- const icon = fs25.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
8151
+ const icon = fs26.existsSync(skillPath) ? chalk11.yellow("~") : chalk11.green("+");
8083
8152
  const desc = getDescription(skillPath);
8084
8153
  console.log(` ${icon} ${chalk11.bold(skillPath)}`);
8085
8154
  console.log(chalk11.dim(` ${desc || skill.description || skill.name}`));
@@ -8090,7 +8159,7 @@ function printSetupSummary(setup) {
8090
8159
  if (Array.isArray(rules) && rules.length > 0) {
8091
8160
  for (const rule of rules) {
8092
8161
  const rulePath = `.cursor/rules/${rule.filename}`;
8093
- const icon = fs25.existsSync(rulePath) ? chalk11.yellow("~") : chalk11.green("+");
8162
+ const icon = fs26.existsSync(rulePath) ? chalk11.yellow("~") : chalk11.green("+");
8094
8163
  const desc = getDescription(rulePath);
8095
8164
  console.log(` ${icon} ${chalk11.bold(rulePath)}`);
8096
8165
  if (desc) {
@@ -8154,8 +8223,8 @@ function ensurePermissions(fingerprint) {
8154
8223
  const settingsPath = ".claude/settings.json";
8155
8224
  let settings = {};
8156
8225
  try {
8157
- if (fs25.existsSync(settingsPath)) {
8158
- settings = JSON.parse(fs25.readFileSync(settingsPath, "utf-8"));
8226
+ if (fs26.existsSync(settingsPath)) {
8227
+ settings = JSON.parse(fs26.readFileSync(settingsPath, "utf-8"));
8159
8228
  }
8160
8229
  } catch {
8161
8230
  }
@@ -8164,8 +8233,8 @@ function ensurePermissions(fingerprint) {
8164
8233
  if (Array.isArray(allow) && allow.length > 0) return;
8165
8234
  permissions.allow = derivePermissions(fingerprint);
8166
8235
  settings.permissions = permissions;
8167
- if (!fs25.existsSync(".claude")) fs25.mkdirSync(".claude", { recursive: true });
8168
- fs25.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
8236
+ if (!fs26.existsSync(".claude")) fs26.mkdirSync(".claude", { recursive: true });
8237
+ fs26.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
8169
8238
  }
8170
8239
  function displayTokenUsage() {
8171
8240
  const summary = getUsageSummary();
@@ -8189,7 +8258,7 @@ function displayTokenUsage() {
8189
8258
  }
8190
8259
  function writeErrorLog(config, rawOutput, error, stopReason) {
8191
8260
  try {
8192
- const logPath = path20.join(process.cwd(), ".caliber", "error-log.md");
8261
+ const logPath = path21.join(process.cwd(), ".caliber", "error-log.md");
8193
8262
  const lines = [
8194
8263
  `# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
8195
8264
  "",
@@ -8202,8 +8271,8 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
8202
8271
  lines.push("## Error", "```", error, "```", "");
8203
8272
  }
8204
8273
  lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
8205
- fs25.mkdirSync(path20.join(process.cwd(), ".caliber"), { recursive: true });
8206
- fs25.writeFileSync(logPath, lines.join("\n"));
8274
+ fs26.mkdirSync(path21.join(process.cwd(), ".caliber"), { recursive: true });
8275
+ fs26.writeFileSync(logPath, lines.join("\n"));
8207
8276
  console.log(chalk11.dim(`
8208
8277
  Error log written to .caliber/error-log.md`));
8209
8278
  } catch {
@@ -8244,7 +8313,7 @@ function undoCommand() {
8244
8313
 
8245
8314
  // src/commands/status.ts
8246
8315
  import chalk13 from "chalk";
8247
- import fs26 from "fs";
8316
+ import fs27 from "fs";
8248
8317
  init_config();
8249
8318
  async function statusCommand(options) {
8250
8319
  const config = loadConfig();
@@ -8271,7 +8340,7 @@ async function statusCommand(options) {
8271
8340
  }
8272
8341
  console.log(` Files managed: ${chalk13.cyan(manifest.entries.length.toString())}`);
8273
8342
  for (const entry of manifest.entries) {
8274
- const exists = fs26.existsSync(entry.path);
8343
+ const exists = fs27.existsSync(entry.path);
8275
8344
  const icon = exists ? chalk13.green("\u2713") : chalk13.red("\u2717");
8276
8345
  console.log(` ${icon} ${entry.path} (${entry.action})`);
8277
8346
  }
@@ -8453,13 +8522,13 @@ async function scoreCommand(options) {
8453
8522
  }
8454
8523
 
8455
8524
  // src/commands/refresh.ts
8456
- import fs30 from "fs";
8457
- import path24 from "path";
8525
+ import fs31 from "fs";
8526
+ import path25 from "path";
8458
8527
  import chalk16 from "chalk";
8459
8528
  import ora6 from "ora";
8460
8529
 
8461
8530
  // src/lib/git-diff.ts
8462
- import { execSync as execSync13 } from "child_process";
8531
+ import { execSync as execSync14 } from "child_process";
8463
8532
  var MAX_DIFF_BYTES = 1e5;
8464
8533
  var DOC_PATTERNS = [
8465
8534
  "CLAUDE.md",
@@ -8474,7 +8543,7 @@ function excludeArgs() {
8474
8543
  }
8475
8544
  function safeExec(cmd) {
8476
8545
  try {
8477
- return execSync13(cmd, {
8546
+ return execSync14(cmd, {
8478
8547
  encoding: "utf-8",
8479
8548
  stdio: ["pipe", "pipe", "pipe"],
8480
8549
  maxBuffer: 10 * 1024 * 1024
@@ -8532,37 +8601,37 @@ function collectDiff(lastSha) {
8532
8601
  }
8533
8602
 
8534
8603
  // src/writers/refresh.ts
8535
- import fs27 from "fs";
8536
- import path21 from "path";
8604
+ import fs28 from "fs";
8605
+ import path22 from "path";
8537
8606
  function writeRefreshDocs(docs) {
8538
8607
  const written = [];
8539
8608
  if (docs.claudeMd) {
8540
- fs27.writeFileSync("CLAUDE.md", docs.claudeMd);
8609
+ fs28.writeFileSync("CLAUDE.md", docs.claudeMd);
8541
8610
  written.push("CLAUDE.md");
8542
8611
  }
8543
8612
  if (docs.readmeMd) {
8544
- fs27.writeFileSync("README.md", docs.readmeMd);
8613
+ fs28.writeFileSync("README.md", docs.readmeMd);
8545
8614
  written.push("README.md");
8546
8615
  }
8547
8616
  if (docs.cursorrules) {
8548
- fs27.writeFileSync(".cursorrules", docs.cursorrules);
8617
+ fs28.writeFileSync(".cursorrules", docs.cursorrules);
8549
8618
  written.push(".cursorrules");
8550
8619
  }
8551
8620
  if (docs.cursorRules) {
8552
- const rulesDir = path21.join(".cursor", "rules");
8553
- if (!fs27.existsSync(rulesDir)) fs27.mkdirSync(rulesDir, { recursive: true });
8621
+ const rulesDir = path22.join(".cursor", "rules");
8622
+ if (!fs28.existsSync(rulesDir)) fs28.mkdirSync(rulesDir, { recursive: true });
8554
8623
  for (const rule of docs.cursorRules) {
8555
- const filePath = path21.join(rulesDir, rule.filename);
8556
- fs27.writeFileSync(filePath, rule.content);
8624
+ const filePath = path22.join(rulesDir, rule.filename);
8625
+ fs28.writeFileSync(filePath, rule.content);
8557
8626
  written.push(filePath);
8558
8627
  }
8559
8628
  }
8560
8629
  if (docs.claudeSkills) {
8561
- const skillsDir = path21.join(".claude", "skills");
8562
- if (!fs27.existsSync(skillsDir)) fs27.mkdirSync(skillsDir, { recursive: true });
8630
+ const skillsDir = path22.join(".claude", "skills");
8631
+ if (!fs28.existsSync(skillsDir)) fs28.mkdirSync(skillsDir, { recursive: true });
8563
8632
  for (const skill of docs.claudeSkills) {
8564
- const filePath = path21.join(skillsDir, skill.filename);
8565
- fs27.writeFileSync(filePath, skill.content);
8633
+ const filePath = path22.join(skillsDir, skill.filename);
8634
+ fs28.writeFileSync(filePath, skill.content);
8566
8635
  written.push(filePath);
8567
8636
  }
8568
8637
  }
@@ -8639,8 +8708,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
8639
8708
  }
8640
8709
 
8641
8710
  // src/learner/writer.ts
8642
- import fs28 from "fs";
8643
- import path22 from "path";
8711
+ import fs29 from "fs";
8712
+ import path23 from "path";
8644
8713
  var LEARNINGS_FILE = "CALIBER_LEARNINGS.md";
8645
8714
  var LEARNINGS_HEADER = `# Caliber Learnings
8646
8715
 
@@ -8724,16 +8793,16 @@ function deduplicateLearnedItems(existing, incoming) {
8724
8793
  function writeLearnedSection(content) {
8725
8794
  const existingSection = readLearnedSection();
8726
8795
  const { merged, newCount, newItems } = deduplicateLearnedItems(existingSection, content);
8727
- fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
8796
+ fs29.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
8728
8797
  return { newCount, newItems };
8729
8798
  }
8730
8799
  function writeLearnedSkill(skill) {
8731
- const skillDir = path22.join(".claude", "skills", skill.name);
8732
- if (!fs28.existsSync(skillDir)) fs28.mkdirSync(skillDir, { recursive: true });
8733
- const skillPath = path22.join(skillDir, "SKILL.md");
8734
- if (!skill.isNew && fs28.existsSync(skillPath)) {
8735
- const existing = fs28.readFileSync(skillPath, "utf-8");
8736
- fs28.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
8800
+ const skillDir = path23.join(".claude", "skills", skill.name);
8801
+ if (!fs29.existsSync(skillDir)) fs29.mkdirSync(skillDir, { recursive: true });
8802
+ const skillPath = path23.join(skillDir, "SKILL.md");
8803
+ if (!skill.isNew && fs29.existsSync(skillPath)) {
8804
+ const existing = fs29.readFileSync(skillPath, "utf-8");
8805
+ fs29.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
8737
8806
  } else {
8738
8807
  const frontmatter = [
8739
8808
  "---",
@@ -8742,37 +8811,37 @@ function writeLearnedSkill(skill) {
8742
8811
  "---",
8743
8812
  ""
8744
8813
  ].join("\n");
8745
- fs28.writeFileSync(skillPath, frontmatter + skill.content);
8814
+ fs29.writeFileSync(skillPath, frontmatter + skill.content);
8746
8815
  }
8747
8816
  return skillPath;
8748
8817
  }
8749
8818
  function readLearnedSection() {
8750
- if (fs28.existsSync(LEARNINGS_FILE)) {
8751
- const content2 = fs28.readFileSync(LEARNINGS_FILE, "utf-8");
8819
+ if (fs29.existsSync(LEARNINGS_FILE)) {
8820
+ const content2 = fs29.readFileSync(LEARNINGS_FILE, "utf-8");
8752
8821
  const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
8753
8822
  return bullets || null;
8754
8823
  }
8755
8824
  const claudeMdPath = "CLAUDE.md";
8756
- if (!fs28.existsSync(claudeMdPath)) return null;
8757
- const content = fs28.readFileSync(claudeMdPath, "utf-8");
8825
+ if (!fs29.existsSync(claudeMdPath)) return null;
8826
+ const content = fs29.readFileSync(claudeMdPath, "utf-8");
8758
8827
  const startIdx = content.indexOf(LEARNED_START);
8759
8828
  const endIdx = content.indexOf(LEARNED_END);
8760
8829
  if (startIdx === -1 || endIdx === -1) return null;
8761
8830
  return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
8762
8831
  }
8763
8832
  function migrateInlineLearnings() {
8764
- if (fs28.existsSync(LEARNINGS_FILE)) return false;
8833
+ if (fs29.existsSync(LEARNINGS_FILE)) return false;
8765
8834
  const claudeMdPath = "CLAUDE.md";
8766
- if (!fs28.existsSync(claudeMdPath)) return false;
8767
- const content = fs28.readFileSync(claudeMdPath, "utf-8");
8835
+ if (!fs29.existsSync(claudeMdPath)) return false;
8836
+ const content = fs29.readFileSync(claudeMdPath, "utf-8");
8768
8837
  const startIdx = content.indexOf(LEARNED_START);
8769
8838
  const endIdx = content.indexOf(LEARNED_END);
8770
8839
  if (startIdx === -1 || endIdx === -1) return false;
8771
8840
  const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
8772
8841
  if (!section) return false;
8773
- fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
8842
+ fs29.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
8774
8843
  const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
8775
- fs28.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
8844
+ fs29.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
8776
8845
  return true;
8777
8846
  }
8778
8847
 
@@ -8784,11 +8853,11 @@ function log2(quiet, ...args) {
8784
8853
  function discoverGitRepos(parentDir) {
8785
8854
  const repos = [];
8786
8855
  try {
8787
- const entries = fs30.readdirSync(parentDir, { withFileTypes: true });
8856
+ const entries = fs31.readdirSync(parentDir, { withFileTypes: true });
8788
8857
  for (const entry of entries) {
8789
8858
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
8790
- const childPath = path24.join(parentDir, entry.name);
8791
- if (fs30.existsSync(path24.join(childPath, ".git"))) {
8859
+ const childPath = path25.join(parentDir, entry.name);
8860
+ if (fs31.existsSync(path25.join(childPath, ".git"))) {
8792
8861
  repos.push(childPath);
8793
8862
  }
8794
8863
  }
@@ -8891,7 +8960,7 @@ async function refreshCommand(options) {
8891
8960
  `));
8892
8961
  const originalDir = process.cwd();
8893
8962
  for (const repo of repos) {
8894
- const repoName = path24.basename(repo);
8963
+ const repoName = path25.basename(repo);
8895
8964
  try {
8896
8965
  process.chdir(repo);
8897
8966
  await refreshSingleRepo(repo, { ...options, label: repoName });
@@ -9115,7 +9184,7 @@ async function configCommand() {
9115
9184
  }
9116
9185
 
9117
9186
  // src/commands/learn.ts
9118
- import fs33 from "fs";
9187
+ import fs34 from "fs";
9119
9188
  import chalk19 from "chalk";
9120
9189
 
9121
9190
  // src/learner/stdin.ts
@@ -9147,8 +9216,8 @@ function readStdin() {
9147
9216
 
9148
9217
  // src/learner/storage.ts
9149
9218
  init_constants();
9150
- import fs31 from "fs";
9151
- import path25 from "path";
9219
+ import fs32 from "fs";
9220
+ import path26 from "path";
9152
9221
  var MAX_RESPONSE_LENGTH = 2e3;
9153
9222
  var DEFAULT_STATE = {
9154
9223
  sessionId: null,
@@ -9156,15 +9225,15 @@ var DEFAULT_STATE = {
9156
9225
  lastAnalysisTimestamp: null
9157
9226
  };
9158
9227
  function ensureLearningDir() {
9159
- if (!fs31.existsSync(LEARNING_DIR)) {
9160
- fs31.mkdirSync(LEARNING_DIR, { recursive: true });
9228
+ if (!fs32.existsSync(LEARNING_DIR)) {
9229
+ fs32.mkdirSync(LEARNING_DIR, { recursive: true });
9161
9230
  }
9162
9231
  }
9163
9232
  function sessionFilePath() {
9164
- return path25.join(LEARNING_DIR, LEARNING_SESSION_FILE);
9233
+ return path26.join(LEARNING_DIR, LEARNING_SESSION_FILE);
9165
9234
  }
9166
9235
  function stateFilePath() {
9167
- return path25.join(LEARNING_DIR, LEARNING_STATE_FILE);
9236
+ return path26.join(LEARNING_DIR, LEARNING_STATE_FILE);
9168
9237
  }
9169
9238
  function truncateResponse(response) {
9170
9239
  const str = JSON.stringify(response);
@@ -9175,29 +9244,29 @@ function appendEvent(event) {
9175
9244
  ensureLearningDir();
9176
9245
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
9177
9246
  const filePath = sessionFilePath();
9178
- fs31.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
9247
+ fs32.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
9179
9248
  const count = getEventCount();
9180
9249
  if (count > LEARNING_MAX_EVENTS) {
9181
- const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
9250
+ const lines = fs32.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
9182
9251
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
9183
- fs31.writeFileSync(filePath, kept.join("\n") + "\n");
9252
+ fs32.writeFileSync(filePath, kept.join("\n") + "\n");
9184
9253
  }
9185
9254
  }
9186
9255
  function appendPromptEvent(event) {
9187
9256
  ensureLearningDir();
9188
9257
  const filePath = sessionFilePath();
9189
- fs31.appendFileSync(filePath, JSON.stringify(event) + "\n");
9258
+ fs32.appendFileSync(filePath, JSON.stringify(event) + "\n");
9190
9259
  const count = getEventCount();
9191
9260
  if (count > LEARNING_MAX_EVENTS) {
9192
- const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
9261
+ const lines = fs32.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
9193
9262
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
9194
- fs31.writeFileSync(filePath, kept.join("\n") + "\n");
9263
+ fs32.writeFileSync(filePath, kept.join("\n") + "\n");
9195
9264
  }
9196
9265
  }
9197
9266
  function readAllEvents() {
9198
9267
  const filePath = sessionFilePath();
9199
- if (!fs31.existsSync(filePath)) return [];
9200
- const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
9268
+ if (!fs32.existsSync(filePath)) return [];
9269
+ const lines = fs32.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
9201
9270
  const events = [];
9202
9271
  for (const line of lines) {
9203
9272
  try {
@@ -9209,26 +9278,26 @@ function readAllEvents() {
9209
9278
  }
9210
9279
  function getEventCount() {
9211
9280
  const filePath = sessionFilePath();
9212
- if (!fs31.existsSync(filePath)) return 0;
9213
- const content = fs31.readFileSync(filePath, "utf-8");
9281
+ if (!fs32.existsSync(filePath)) return 0;
9282
+ const content = fs32.readFileSync(filePath, "utf-8");
9214
9283
  return content.split("\n").filter(Boolean).length;
9215
9284
  }
9216
9285
  function clearSession() {
9217
9286
  const filePath = sessionFilePath();
9218
- if (fs31.existsSync(filePath)) fs31.unlinkSync(filePath);
9287
+ if (fs32.existsSync(filePath)) fs32.unlinkSync(filePath);
9219
9288
  }
9220
9289
  function readState2() {
9221
9290
  const filePath = stateFilePath();
9222
- if (!fs31.existsSync(filePath)) return { ...DEFAULT_STATE };
9291
+ if (!fs32.existsSync(filePath)) return { ...DEFAULT_STATE };
9223
9292
  try {
9224
- return JSON.parse(fs31.readFileSync(filePath, "utf-8"));
9293
+ return JSON.parse(fs32.readFileSync(filePath, "utf-8"));
9225
9294
  } catch {
9226
9295
  return { ...DEFAULT_STATE };
9227
9296
  }
9228
9297
  }
9229
9298
  function writeState2(state) {
9230
9299
  ensureLearningDir();
9231
- fs31.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
9300
+ fs32.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
9232
9301
  }
9233
9302
  function resetState() {
9234
9303
  writeState2({ ...DEFAULT_STATE });
@@ -9236,14 +9305,14 @@ function resetState() {
9236
9305
  var LOCK_FILE2 = "finalize.lock";
9237
9306
  var LOCK_STALE_MS = 5 * 60 * 1e3;
9238
9307
  function lockFilePath() {
9239
- return path25.join(LEARNING_DIR, LOCK_FILE2);
9308
+ return path26.join(LEARNING_DIR, LOCK_FILE2);
9240
9309
  }
9241
9310
  function acquireFinalizeLock() {
9242
9311
  ensureLearningDir();
9243
9312
  const lockPath = lockFilePath();
9244
- if (fs31.existsSync(lockPath)) {
9313
+ if (fs32.existsSync(lockPath)) {
9245
9314
  try {
9246
- const stat = fs31.statSync(lockPath);
9315
+ const stat = fs32.statSync(lockPath);
9247
9316
  if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
9248
9317
  return false;
9249
9318
  }
@@ -9251,7 +9320,7 @@ function acquireFinalizeLock() {
9251
9320
  }
9252
9321
  }
9253
9322
  try {
9254
- fs31.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
9323
+ fs32.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
9255
9324
  return true;
9256
9325
  } catch {
9257
9326
  return false;
@@ -9260,7 +9329,7 @@ function acquireFinalizeLock() {
9260
9329
  function releaseFinalizeLock() {
9261
9330
  const lockPath = lockFilePath();
9262
9331
  try {
9263
- if (fs31.existsSync(lockPath)) fs31.unlinkSync(lockPath);
9332
+ if (fs32.existsSync(lockPath)) fs32.unlinkSync(lockPath);
9264
9333
  } catch {
9265
9334
  }
9266
9335
  }
@@ -9306,7 +9375,7 @@ function sanitizeSecrets(text) {
9306
9375
 
9307
9376
  // src/ai/learn.ts
9308
9377
  init_config();
9309
- var MAX_PROMPT_TOKENS2 = 1e5;
9378
+ var MAX_PROMPT_TOKENS = 1e5;
9310
9379
  function formatEventsForPrompt(events) {
9311
9380
  return events.map((e, i) => {
9312
9381
  if (e.hook_event_name === "UserPromptSubmit") {
@@ -9354,7 +9423,7 @@ function parseAnalysisResponse(raw) {
9354
9423
  }
9355
9424
  }
9356
9425
  async function analyzeEvents(events, existingClaudeMd, existingLearnedSection, existingSkills) {
9357
- const fittedEvents = trimEventsToFit(events, MAX_PROMPT_TOKENS2 - 1e4);
9426
+ const fittedEvents = trimEventsToFit(events, MAX_PROMPT_TOKENS - 1e4);
9358
9427
  const eventsText = formatEventsForPrompt(fittedEvents);
9359
9428
  const contextParts = [];
9360
9429
  if (existingClaudeMd) {
@@ -9416,8 +9485,8 @@ init_config();
9416
9485
 
9417
9486
  // src/learner/roi.ts
9418
9487
  init_constants();
9419
- import fs32 from "fs";
9420
- import path26 from "path";
9488
+ import fs33 from "fs";
9489
+ import path27 from "path";
9421
9490
  var DEFAULT_TOTALS = {
9422
9491
  totalWasteTokens: 0,
9423
9492
  totalWasteSeconds: 0,
@@ -9431,22 +9500,22 @@ var DEFAULT_TOTALS = {
9431
9500
  lastSessionTimestamp: ""
9432
9501
  };
9433
9502
  function roiFilePath() {
9434
- return path26.join(LEARNING_DIR, LEARNING_ROI_FILE);
9503
+ return path27.join(LEARNING_DIR, LEARNING_ROI_FILE);
9435
9504
  }
9436
9505
  function readROIStats() {
9437
9506
  const filePath = roiFilePath();
9438
- if (!fs32.existsSync(filePath)) {
9507
+ if (!fs33.existsSync(filePath)) {
9439
9508
  return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
9440
9509
  }
9441
9510
  try {
9442
- return JSON.parse(fs32.readFileSync(filePath, "utf-8"));
9511
+ return JSON.parse(fs33.readFileSync(filePath, "utf-8"));
9443
9512
  } catch {
9444
9513
  return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
9445
9514
  }
9446
9515
  }
9447
9516
  function writeROIStats(stats) {
9448
9517
  ensureLearningDir();
9449
- fs32.writeFileSync(roiFilePath(), JSON.stringify(stats, null, 2));
9518
+ fs33.writeFileSync(roiFilePath(), JSON.stringify(stats, null, 2));
9450
9519
  }
9451
9520
  function recalculateTotals(stats) {
9452
9521
  const totals = stats.totals;
@@ -9699,7 +9768,7 @@ async function learnFinalizeCommand(options) {
9699
9768
  }
9700
9769
  async function learnInstallCommand() {
9701
9770
  let anyInstalled = false;
9702
- if (fs33.existsSync(".claude")) {
9771
+ if (fs34.existsSync(".claude")) {
9703
9772
  const r = installLearningHooks();
9704
9773
  if (r.installed) {
9705
9774
  console.log(chalk19.green("\u2713") + " Claude Code learning hooks installed");
@@ -9708,7 +9777,7 @@ async function learnInstallCommand() {
9708
9777
  console.log(chalk19.dim(" Claude Code hooks already installed"));
9709
9778
  }
9710
9779
  }
9711
- if (fs33.existsSync(".cursor")) {
9780
+ if (fs34.existsSync(".cursor")) {
9712
9781
  const r = installCursorLearningHooks();
9713
9782
  if (r.installed) {
9714
9783
  console.log(chalk19.green("\u2713") + " Cursor learning hooks installed");
@@ -9717,7 +9786,7 @@ async function learnInstallCommand() {
9717
9786
  console.log(chalk19.dim(" Cursor hooks already installed"));
9718
9787
  }
9719
9788
  }
9720
- if (!fs33.existsSync(".claude") && !fs33.existsSync(".cursor")) {
9789
+ if (!fs34.existsSync(".claude") && !fs34.existsSync(".cursor")) {
9721
9790
  console.log(chalk19.yellow("No .claude/ or .cursor/ directory found."));
9722
9791
  console.log(chalk19.dim(" Run `caliber init` first, or create the directory manually."));
9723
9792
  return;
@@ -9789,9 +9858,9 @@ Learned items in CALIBER_LEARNINGS.md: ${chalk19.cyan(String(lineCount))}`);
9789
9858
  }
9790
9859
 
9791
9860
  // src/cli.ts
9792
- var __dirname = path27.dirname(fileURLToPath(import.meta.url));
9861
+ var __dirname = path28.dirname(fileURLToPath(import.meta.url));
9793
9862
  var pkg = JSON.parse(
9794
- fs34.readFileSync(path27.resolve(__dirname, "..", "package.json"), "utf-8")
9863
+ fs35.readFileSync(path28.resolve(__dirname, "..", "package.json"), "utf-8")
9795
9864
  );
9796
9865
  var program = new Command();
9797
9866
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -9865,16 +9934,16 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
9865
9934
  learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
9866
9935
 
9867
9936
  // src/utils/version-check.ts
9868
- import fs35 from "fs";
9869
- import path28 from "path";
9937
+ import fs36 from "fs";
9938
+ import path29 from "path";
9870
9939
  import { fileURLToPath as fileURLToPath2 } from "url";
9871
- import { execSync as execSync14 } from "child_process";
9940
+ import { execSync as execSync15 } from "child_process";
9872
9941
  import chalk20 from "chalk";
9873
9942
  import ora7 from "ora";
9874
9943
  import confirm2 from "@inquirer/confirm";
9875
- var __dirname_vc = path28.dirname(fileURLToPath2(import.meta.url));
9944
+ var __dirname_vc = path29.dirname(fileURLToPath2(import.meta.url));
9876
9945
  var pkg2 = JSON.parse(
9877
- fs35.readFileSync(path28.resolve(__dirname_vc, "..", "package.json"), "utf-8")
9946
+ fs36.readFileSync(path29.resolve(__dirname_vc, "..", "package.json"), "utf-8")
9878
9947
  );
9879
9948
  function getChannel(version) {
9880
9949
  const match = version.match(/-(dev|next)\./);
@@ -9898,9 +9967,9 @@ function isNewer(registry, current) {
9898
9967
  }
9899
9968
  function getInstalledVersion() {
9900
9969
  try {
9901
- const globalRoot = execSync14("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
9902
- const pkgPath = path28.join(globalRoot, "@rely-ai", "caliber", "package.json");
9903
- return JSON.parse(fs35.readFileSync(pkgPath, "utf-8")).version;
9970
+ const globalRoot = execSync15("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
9971
+ const pkgPath = path29.join(globalRoot, "@rely-ai", "caliber", "package.json");
9972
+ return JSON.parse(fs36.readFileSync(pkgPath, "utf-8")).version;
9904
9973
  } catch {
9905
9974
  return null;
9906
9975
  }
@@ -9946,7 +10015,7 @@ Update available: ${current} -> ${latest}`)
9946
10015
  const tag = channel === "latest" ? latest : channel;
9947
10016
  const spinner = ora7("Updating caliber...").start();
9948
10017
  try {
9949
- execSync14(`npm install -g @rely-ai/caliber@${tag}`, {
10018
+ execSync15(`npm install -g @rely-ai/caliber@${tag}`, {
9950
10019
  stdio: "pipe",
9951
10020
  timeout: 12e4,
9952
10021
  env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
@@ -9963,7 +10032,7 @@ Update available: ${current} -> ${latest}`)
9963
10032
  console.log(chalk20.dim(`
9964
10033
  Restarting: caliber ${args.join(" ")}
9965
10034
  `));
9966
- execSync14(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
10035
+ execSync15(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
9967
10036
  stdio: "inherit",
9968
10037
  env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
9969
10038
  });