@rely-ai/caliber 1.4.1 → 1.4.2

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 +631 -618
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -51,17 +51,17 @@ var init_constants = __esm({
51
51
 
52
52
  // src/cli.ts
53
53
  import { Command } from "commander";
54
- import fs27 from "fs";
54
+ import fs28 from "fs";
55
55
  import path22 from "path";
56
56
  import { fileURLToPath } from "url";
57
57
 
58
58
  // src/commands/onboard.ts
59
- import chalk5 from "chalk";
59
+ import chalk6 from "chalk";
60
60
  import ora2 from "ora";
61
61
  import readline4 from "readline";
62
- import select2 from "@inquirer/select";
62
+ import select3 from "@inquirer/select";
63
63
  import checkbox from "@inquirer/checkbox";
64
- import fs20 from "fs";
64
+ import fs21 from "fs";
65
65
 
66
66
  // src/fingerprint/index.ts
67
67
  import fs6 from "fs";
@@ -2163,6 +2163,12 @@ function cleanupStaging() {
2163
2163
  }
2164
2164
  }
2165
2165
 
2166
+ // src/utils/review.ts
2167
+ import chalk from "chalk";
2168
+ import fs14 from "fs";
2169
+ import select from "@inquirer/select";
2170
+ import { createTwoFilesPatch } from "diff";
2171
+
2166
2172
  // src/utils/editor.ts
2167
2173
  import { execSync as execSync4, spawn as spawn3 } from "child_process";
2168
2174
  function commandExists(cmd) {
@@ -2201,11 +2207,206 @@ function openDiffsInEditor(editor, files) {
2201
2207
  }
2202
2208
  }
2203
2209
 
2204
- // src/commands/onboard.ts
2205
- import { createTwoFilesPatch } from "diff";
2210
+ // src/utils/review.ts
2211
+ async function promptWantsReview() {
2212
+ return select({
2213
+ message: "Would you like to review the diffs before deciding?",
2214
+ choices: [
2215
+ { name: "Yes, show me the diffs", value: true },
2216
+ { name: "No, continue", value: false }
2217
+ ]
2218
+ });
2219
+ }
2220
+ async function promptReviewMethod() {
2221
+ const available = detectAvailableEditors();
2222
+ if (available.length === 1) return "terminal";
2223
+ const choices = available.map((method) => {
2224
+ switch (method) {
2225
+ case "cursor":
2226
+ return { name: "Cursor (diff view)", value: "cursor" };
2227
+ case "vscode":
2228
+ return { name: "VS Code (diff view)", value: "vscode" };
2229
+ case "terminal":
2230
+ return { name: "Terminal", value: "terminal" };
2231
+ }
2232
+ });
2233
+ return select({ message: "How would you like to review the changes?", choices });
2234
+ }
2235
+ async function openReview(method, stagedFiles) {
2236
+ if (method === "cursor" || method === "vscode") {
2237
+ openDiffsInEditor(method, stagedFiles.map((f) => ({
2238
+ originalPath: f.originalPath,
2239
+ proposedPath: f.proposedPath
2240
+ })));
2241
+ console.log(chalk.dim(" Diffs opened in your editor.\n"));
2242
+ return;
2243
+ }
2244
+ const fileInfos = stagedFiles.map((file) => {
2245
+ const proposed = fs14.readFileSync(file.proposedPath, "utf-8");
2246
+ const current = file.currentPath ? fs14.readFileSync(file.currentPath, "utf-8") : "";
2247
+ const patch = createTwoFilesPatch(
2248
+ file.isNew ? "/dev/null" : file.relativePath,
2249
+ file.relativePath,
2250
+ current,
2251
+ proposed
2252
+ );
2253
+ let added = 0, removed = 0;
2254
+ for (const line of patch.split("\n")) {
2255
+ if (line.startsWith("+") && !line.startsWith("+++")) added++;
2256
+ if (line.startsWith("-") && !line.startsWith("---")) removed++;
2257
+ }
2258
+ return {
2259
+ relativePath: file.relativePath,
2260
+ isNew: file.isNew,
2261
+ added,
2262
+ removed,
2263
+ lines: proposed.split("\n").length,
2264
+ patch
2265
+ };
2266
+ });
2267
+ await interactiveDiffExplorer(fileInfos);
2268
+ }
2269
+ async function interactiveDiffExplorer(files) {
2270
+ if (!process.stdin.isTTY) {
2271
+ for (const f of files) {
2272
+ const icon = f.isNew ? chalk.green("+") : chalk.yellow("~");
2273
+ const stats = f.isNew ? chalk.dim(`${f.lines} lines`) : `${chalk.green(`+${f.added}`)} ${chalk.red(`-${f.removed}`)}`;
2274
+ console.log(` ${icon} ${f.relativePath} ${stats}`);
2275
+ }
2276
+ console.log("");
2277
+ return;
2278
+ }
2279
+ const { stdin, stdout } = process;
2280
+ let cursor = 0;
2281
+ let viewing = null;
2282
+ let scrollOffset = 0;
2283
+ let lineCount = 0;
2284
+ function getTermHeight() {
2285
+ return (stdout.rows || 24) - 4;
2286
+ }
2287
+ function renderFileList() {
2288
+ const lines = [];
2289
+ lines.push(chalk.bold(" Review changes"));
2290
+ lines.push("");
2291
+ for (let i = 0; i < files.length; i++) {
2292
+ const f = files[i];
2293
+ const ptr = i === cursor ? chalk.cyan(">") : " ";
2294
+ const icon = f.isNew ? chalk.green("+") : chalk.yellow("~");
2295
+ const stats = f.isNew ? chalk.dim(`${f.lines} lines`) : `${chalk.green(`+${f.added}`)} ${chalk.red(`-${f.removed}`)}`;
2296
+ lines.push(` ${ptr} ${icon} ${f.relativePath} ${stats}`);
2297
+ }
2298
+ lines.push("");
2299
+ lines.push(chalk.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
2300
+ return lines.join("\n");
2301
+ }
2302
+ function renderDiff(index) {
2303
+ const f = files[index];
2304
+ const lines = [];
2305
+ const header = f.isNew ? ` ${chalk.green("+")} ${f.relativePath} ${chalk.dim("(new file)")}` : ` ${chalk.yellow("~")} ${f.relativePath} ${chalk.green(`+${f.added}`)} ${chalk.red(`-${f.removed}`)}`;
2306
+ lines.push(header);
2307
+ lines.push(chalk.dim(" " + "\u2500".repeat(60)));
2308
+ const patchLines = f.patch.split("\n");
2309
+ const bodyLines = patchLines.slice(4);
2310
+ const maxVisible = getTermHeight() - 4;
2311
+ const visibleLines = bodyLines.slice(scrollOffset, scrollOffset + maxVisible);
2312
+ for (const line of visibleLines) {
2313
+ if (line.startsWith("+")) {
2314
+ lines.push(chalk.green(" " + line));
2315
+ } else if (line.startsWith("-")) {
2316
+ lines.push(chalk.red(" " + line));
2317
+ } else if (line.startsWith("@@")) {
2318
+ lines.push(chalk.cyan(" " + line));
2319
+ } else {
2320
+ lines.push(chalk.dim(" " + line));
2321
+ }
2322
+ }
2323
+ const totalBody = bodyLines.length;
2324
+ if (totalBody > maxVisible) {
2325
+ const pct = Math.round((scrollOffset + maxVisible) / totalBody * 100);
2326
+ lines.push(chalk.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
2327
+ }
2328
+ lines.push("");
2329
+ lines.push(chalk.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
2330
+ return lines.join("\n");
2331
+ }
2332
+ function draw(initial) {
2333
+ if (!initial && lineCount > 0) {
2334
+ stdout.write(`\x1B[${lineCount}A`);
2335
+ }
2336
+ stdout.write("\x1B[0J");
2337
+ const output = viewing !== null ? renderDiff(viewing) : renderFileList();
2338
+ stdout.write(output + "\n");
2339
+ lineCount = output.split("\n").length;
2340
+ }
2341
+ return new Promise((resolve2) => {
2342
+ console.log("");
2343
+ draw(true);
2344
+ stdin.setRawMode(true);
2345
+ stdin.resume();
2346
+ stdin.setEncoding("utf8");
2347
+ function cleanup() {
2348
+ stdin.removeListener("data", onData);
2349
+ stdin.setRawMode(false);
2350
+ stdin.pause();
2351
+ }
2352
+ function onData(key) {
2353
+ if (viewing !== null) {
2354
+ const f = files[viewing];
2355
+ const totalBody = f.patch.split("\n").length - 4;
2356
+ const maxVisible = getTermHeight() - 4;
2357
+ switch (key) {
2358
+ case "\x1B[A":
2359
+ scrollOffset = Math.max(0, scrollOffset - 1);
2360
+ draw(false);
2361
+ break;
2362
+ case "\x1B[B":
2363
+ scrollOffset = Math.min(Math.max(0, totalBody - maxVisible), scrollOffset + 1);
2364
+ draw(false);
2365
+ break;
2366
+ case " ":
2367
+ case "\x1B":
2368
+ viewing = null;
2369
+ scrollOffset = 0;
2370
+ draw(false);
2371
+ break;
2372
+ case "q":
2373
+ case "":
2374
+ cleanup();
2375
+ console.log("");
2376
+ resolve2();
2377
+ break;
2378
+ }
2379
+ } else {
2380
+ switch (key) {
2381
+ case "\x1B[A":
2382
+ cursor = (cursor - 1 + files.length) % files.length;
2383
+ draw(false);
2384
+ break;
2385
+ case "\x1B[B":
2386
+ cursor = (cursor + 1) % files.length;
2387
+ draw(false);
2388
+ break;
2389
+ case "\r":
2390
+ case "\n":
2391
+ viewing = cursor;
2392
+ scrollOffset = 0;
2393
+ draw(false);
2394
+ break;
2395
+ case "q":
2396
+ case "":
2397
+ cleanup();
2398
+ console.log("");
2399
+ resolve2();
2400
+ break;
2401
+ }
2402
+ }
2403
+ }
2404
+ stdin.on("data", onData);
2405
+ });
2406
+ }
2206
2407
 
2207
2408
  // src/commands/setup-files.ts
2208
- import fs14 from "fs";
2409
+ import fs15 from "fs";
2209
2410
  function buildSkillContent(skill) {
2210
2411
  const frontmatter = `---
2211
2412
  name: ${skill.name}
@@ -2253,7 +2454,7 @@ function collectSetupFiles(setup) {
2253
2454
  }
2254
2455
  }
2255
2456
  }
2256
- if (!fs14.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
2457
+ if (!fs15.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
2257
2458
  const agentRefs = [];
2258
2459
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
2259
2460
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
@@ -2272,24 +2473,24 @@ ${agentRefs.join(" ")}
2272
2473
  }
2273
2474
 
2274
2475
  // src/lib/hooks.ts
2275
- import fs15 from "fs";
2476
+ import fs16 from "fs";
2276
2477
  import path12 from "path";
2277
2478
  import { execSync as execSync5 } from "child_process";
2278
2479
  var SETTINGS_PATH = path12.join(".claude", "settings.json");
2279
2480
  var HOOK_COMMAND = "caliber refresh --quiet";
2280
2481
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
2281
2482
  function readSettings() {
2282
- if (!fs15.existsSync(SETTINGS_PATH)) return {};
2483
+ if (!fs16.existsSync(SETTINGS_PATH)) return {};
2283
2484
  try {
2284
- return JSON.parse(fs15.readFileSync(SETTINGS_PATH, "utf-8"));
2485
+ return JSON.parse(fs16.readFileSync(SETTINGS_PATH, "utf-8"));
2285
2486
  } catch {
2286
2487
  return {};
2287
2488
  }
2288
2489
  }
2289
2490
  function writeSettings(settings) {
2290
2491
  const dir = path12.dirname(SETTINGS_PATH);
2291
- if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
2292
- fs15.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
2492
+ if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
2493
+ fs16.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
2293
2494
  }
2294
2495
  function findHookIndex(sessionEnd) {
2295
2496
  return sessionEnd.findIndex(
@@ -2358,8 +2559,8 @@ function getPreCommitPath() {
2358
2559
  }
2359
2560
  function isPreCommitHookInstalled() {
2360
2561
  const hookPath = getPreCommitPath();
2361
- if (!hookPath || !fs15.existsSync(hookPath)) return false;
2362
- const content = fs15.readFileSync(hookPath, "utf-8");
2562
+ if (!hookPath || !fs16.existsSync(hookPath)) return false;
2563
+ const content = fs16.readFileSync(hookPath, "utf-8");
2363
2564
  return content.includes(PRECOMMIT_START);
2364
2565
  }
2365
2566
  function installPreCommitHook() {
@@ -2369,40 +2570,40 @@ function installPreCommitHook() {
2369
2570
  const hookPath = getPreCommitPath();
2370
2571
  if (!hookPath) return { installed: false, alreadyInstalled: false };
2371
2572
  const hooksDir = path12.dirname(hookPath);
2372
- if (!fs15.existsSync(hooksDir)) fs15.mkdirSync(hooksDir, { recursive: true });
2573
+ if (!fs16.existsSync(hooksDir)) fs16.mkdirSync(hooksDir, { recursive: true });
2373
2574
  let content = "";
2374
- if (fs15.existsSync(hookPath)) {
2375
- content = fs15.readFileSync(hookPath, "utf-8");
2575
+ if (fs16.existsSync(hookPath)) {
2576
+ content = fs16.readFileSync(hookPath, "utf-8");
2376
2577
  if (!content.endsWith("\n")) content += "\n";
2377
2578
  content += "\n" + PRECOMMIT_BLOCK + "\n";
2378
2579
  } else {
2379
2580
  content = "#!/bin/sh\n\n" + PRECOMMIT_BLOCK + "\n";
2380
2581
  }
2381
- fs15.writeFileSync(hookPath, content);
2382
- fs15.chmodSync(hookPath, 493);
2582
+ fs16.writeFileSync(hookPath, content);
2583
+ fs16.chmodSync(hookPath, 493);
2383
2584
  return { installed: true, alreadyInstalled: false };
2384
2585
  }
2385
2586
  function removePreCommitHook() {
2386
2587
  const hookPath = getPreCommitPath();
2387
- if (!hookPath || !fs15.existsSync(hookPath)) {
2588
+ if (!hookPath || !fs16.existsSync(hookPath)) {
2388
2589
  return { removed: false, notFound: true };
2389
2590
  }
2390
- let content = fs15.readFileSync(hookPath, "utf-8");
2591
+ let content = fs16.readFileSync(hookPath, "utf-8");
2391
2592
  if (!content.includes(PRECOMMIT_START)) {
2392
2593
  return { removed: false, notFound: true };
2393
2594
  }
2394
2595
  const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
2395
2596
  content = content.replace(regex, "\n");
2396
2597
  if (content.trim() === "#!/bin/sh" || content.trim() === "") {
2397
- fs15.unlinkSync(hookPath);
2598
+ fs16.unlinkSync(hookPath);
2398
2599
  } else {
2399
- fs15.writeFileSync(hookPath, content);
2600
+ fs16.writeFileSync(hookPath, content);
2400
2601
  }
2401
2602
  return { removed: true, notFound: false };
2402
2603
  }
2403
2604
 
2404
2605
  // src/lib/learning-hooks.ts
2405
- import fs16 from "fs";
2606
+ import fs17 from "fs";
2406
2607
  import path13 from "path";
2407
2608
  var SETTINGS_PATH2 = path13.join(".claude", "settings.json");
2408
2609
  var HOOK_CONFIGS = [
@@ -2423,17 +2624,17 @@ var HOOK_CONFIGS = [
2423
2624
  }
2424
2625
  ];
2425
2626
  function readSettings2() {
2426
- if (!fs16.existsSync(SETTINGS_PATH2)) return {};
2627
+ if (!fs17.existsSync(SETTINGS_PATH2)) return {};
2427
2628
  try {
2428
- return JSON.parse(fs16.readFileSync(SETTINGS_PATH2, "utf-8"));
2629
+ return JSON.parse(fs17.readFileSync(SETTINGS_PATH2, "utf-8"));
2429
2630
  } catch {
2430
2631
  return {};
2431
2632
  }
2432
2633
  }
2433
2634
  function writeSettings2(settings) {
2434
2635
  const dir = path13.dirname(SETTINGS_PATH2);
2435
- if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
2436
- fs16.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
2636
+ if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
2637
+ fs17.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
2437
2638
  }
2438
2639
  function hasLearningHook(matchers, command) {
2439
2640
  return matchers.some((entry) => entry.hooks?.some((h) => h.command === command));
@@ -2490,7 +2691,7 @@ function removeLearningHooks() {
2490
2691
 
2491
2692
  // src/lib/state.ts
2492
2693
  init_constants();
2493
- import fs17 from "fs";
2694
+ import fs18 from "fs";
2494
2695
  import path14 from "path";
2495
2696
  import { execSync as execSync6 } from "child_process";
2496
2697
  var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
@@ -2504,8 +2705,8 @@ function normalizeTargetAgent(value) {
2504
2705
  }
2505
2706
  function readState() {
2506
2707
  try {
2507
- if (!fs17.existsSync(STATE_FILE)) return null;
2508
- const raw = JSON.parse(fs17.readFileSync(STATE_FILE, "utf-8"));
2708
+ if (!fs18.existsSync(STATE_FILE)) return null;
2709
+ const raw = JSON.parse(fs18.readFileSync(STATE_FILE, "utf-8"));
2509
2710
  if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
2510
2711
  return raw;
2511
2712
  } catch {
@@ -2513,10 +2714,10 @@ function readState() {
2513
2714
  }
2514
2715
  }
2515
2716
  function writeState(state) {
2516
- if (!fs17.existsSync(CALIBER_DIR)) {
2517
- fs17.mkdirSync(CALIBER_DIR, { recursive: true });
2717
+ if (!fs18.existsSync(CALIBER_DIR)) {
2718
+ fs18.mkdirSync(CALIBER_DIR, { recursive: true });
2518
2719
  }
2519
- fs17.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
2720
+ fs18.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
2520
2721
  }
2521
2722
  function getCurrentHeadSha() {
2522
2723
  try {
@@ -2530,7 +2731,7 @@ function getCurrentHeadSha() {
2530
2731
  }
2531
2732
 
2532
2733
  // src/utils/spinner-messages.ts
2533
- import chalk from "chalk";
2734
+ import chalk2 from "chalk";
2534
2735
  var GENERATION_MESSAGES = [
2535
2736
  "Analyzing your project structure and dependencies...",
2536
2737
  "Mapping out build commands and test workflows...",
@@ -2580,9 +2781,9 @@ var SpinnerMessages = class {
2580
2781
  this.currentBaseMessage = this.messages[0];
2581
2782
  this.updateSpinnerText();
2582
2783
  if (this.showElapsedTime) {
2583
- this.spinner.suffixText = chalk.dim(`(${this.formatElapsed()})`);
2784
+ this.spinner.suffixText = chalk2.dim(`(${this.formatElapsed()})`);
2584
2785
  this.elapsedTimer = setInterval(() => {
2585
- this.spinner.suffixText = chalk.dim(`(${this.formatElapsed()})`);
2786
+ this.spinner.suffixText = chalk2.dim(`(${this.formatElapsed()})`);
2586
2787
  }, 1e3);
2587
2788
  }
2588
2789
  this.timer = setInterval(() => {
@@ -2617,13 +2818,13 @@ var SpinnerMessages = class {
2617
2818
  };
2618
2819
 
2619
2820
  // src/commands/interactive-provider-setup.ts
2620
- import chalk2 from "chalk";
2821
+ import chalk3 from "chalk";
2621
2822
  import readline2 from "readline";
2622
- import select from "@inquirer/select";
2823
+ import select2 from "@inquirer/select";
2623
2824
  function promptInput(question) {
2624
2825
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
2625
2826
  return new Promise((resolve2) => {
2626
- rl.question(chalk2.cyan(`${question} `), (answer) => {
2827
+ rl.question(chalk3.cyan(`${question} `), (answer) => {
2627
2828
  rl.close();
2628
2829
  resolve2(answer.trim());
2629
2830
  });
@@ -2638,7 +2839,7 @@ var PROVIDER_CHOICES = [
2638
2839
  ];
2639
2840
  async function runInteractiveProviderSetup(options) {
2640
2841
  const message = options?.selectMessage ?? "Select LLM provider";
2641
- const provider = await select({
2842
+ const provider = await select2({
2642
2843
  message,
2643
2844
  choices: PROVIDER_CHOICES
2644
2845
  });
@@ -2646,19 +2847,19 @@ async function runInteractiveProviderSetup(options) {
2646
2847
  switch (provider) {
2647
2848
  case "claude-cli": {
2648
2849
  config.model = "default";
2649
- console.log(chalk2.dim(" Run `claude` once and log in with your Pro/Max/Team account if you haven't."));
2850
+ console.log(chalk3.dim(" Run `claude` once and log in with your Pro/Max/Team account if you haven't."));
2650
2851
  break;
2651
2852
  }
2652
2853
  case "cursor": {
2653
2854
  config.model = "default";
2654
- console.log(chalk2.dim(" Run `agent login` if you haven't, or set CURSOR_API_KEY."));
2855
+ console.log(chalk3.dim(" Run `agent login` if you haven't, or set CURSOR_API_KEY."));
2655
2856
  break;
2656
2857
  }
2657
2858
  case "anthropic": {
2658
- console.log(chalk2.dim(" Get a key at https://console.anthropic.com (same account as Claude Pro/Team/Max)."));
2859
+ console.log(chalk3.dim(" Get a key at https://console.anthropic.com (same account as Claude Pro/Team/Max)."));
2659
2860
  config.apiKey = await promptInput("Anthropic API key:");
2660
2861
  if (!config.apiKey) {
2661
- console.log(chalk2.red("API key is required."));
2862
+ console.log(chalk3.red("API key is required."));
2662
2863
  throw new Error("__exit__");
2663
2864
  }
2664
2865
  config.model = await promptInput(`Model (default: ${DEFAULT_MODELS.anthropic}):`) || DEFAULT_MODELS.anthropic;
@@ -2667,7 +2868,7 @@ async function runInteractiveProviderSetup(options) {
2667
2868
  case "vertex": {
2668
2869
  config.vertexProjectId = await promptInput("GCP Project ID:");
2669
2870
  if (!config.vertexProjectId) {
2670
- console.log(chalk2.red("Project ID is required."));
2871
+ console.log(chalk3.red("Project ID is required."));
2671
2872
  throw new Error("__exit__");
2672
2873
  }
2673
2874
  config.vertexRegion = await promptInput("Region (default: us-east5):") || "us-east5";
@@ -2678,7 +2879,7 @@ async function runInteractiveProviderSetup(options) {
2678
2879
  case "openai": {
2679
2880
  config.apiKey = await promptInput("API key:");
2680
2881
  if (!config.apiKey) {
2681
- console.log(chalk2.red("API key is required."));
2882
+ console.log(chalk3.red("API key is required."));
2682
2883
  throw new Error("__exit__");
2683
2884
  }
2684
2885
  config.baseUrl = await promptInput("Base URL (leave empty for OpenAI, or enter custom endpoint):") || void 0;
@@ -3737,22 +3938,22 @@ function checkBonus(dir) {
3737
3938
 
3738
3939
  // src/scoring/dismissed.ts
3739
3940
  init_constants();
3740
- import fs18 from "fs";
3941
+ import fs19 from "fs";
3741
3942
  import path15 from "path";
3742
3943
  var DISMISSED_FILE = path15.join(CALIBER_DIR, "dismissed-checks.json");
3743
3944
  function readDismissedChecks() {
3744
3945
  try {
3745
- if (!fs18.existsSync(DISMISSED_FILE)) return [];
3746
- return JSON.parse(fs18.readFileSync(DISMISSED_FILE, "utf-8"));
3946
+ if (!fs19.existsSync(DISMISSED_FILE)) return [];
3947
+ return JSON.parse(fs19.readFileSync(DISMISSED_FILE, "utf-8"));
3747
3948
  } catch {
3748
3949
  return [];
3749
3950
  }
3750
3951
  }
3751
3952
  function writeDismissedChecks(checks) {
3752
- if (!fs18.existsSync(CALIBER_DIR)) {
3753
- fs18.mkdirSync(CALIBER_DIR, { recursive: true });
3953
+ if (!fs19.existsSync(CALIBER_DIR)) {
3954
+ fs19.mkdirSync(CALIBER_DIR, { recursive: true });
3754
3955
  }
3755
- fs18.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
3956
+ fs19.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
3756
3957
  }
3757
3958
  function getDismissedIds() {
3758
3959
  return new Set(readDismissedChecks().map((c) => c.id));
@@ -3816,7 +4017,7 @@ function computeLocalScore(dir, targetAgent) {
3816
4017
  }
3817
4018
 
3818
4019
  // src/scoring/display.ts
3819
- import chalk3 from "chalk";
4020
+ import chalk4 from "chalk";
3820
4021
  var AGENT_DISPLAY_NAMES = {
3821
4022
  claude: "Claude Code",
3822
4023
  cursor: "Cursor",
@@ -3834,31 +4035,31 @@ var CATEGORY_ORDER = ["existence", "quality", "coverage", "accuracy", "freshness
3834
4035
  function gradeColor(grade) {
3835
4036
  switch (grade) {
3836
4037
  case "A":
3837
- return chalk3.green;
4038
+ return chalk4.green;
3838
4039
  case "B":
3839
- return chalk3.greenBright;
4040
+ return chalk4.greenBright;
3840
4041
  case "C":
3841
- return chalk3.yellow;
4042
+ return chalk4.yellow;
3842
4043
  case "D":
3843
- return chalk3.hex("#f97316");
4044
+ return chalk4.hex("#f97316");
3844
4045
  case "F":
3845
- return chalk3.red;
4046
+ return chalk4.red;
3846
4047
  default:
3847
- return chalk3.white;
4048
+ return chalk4.white;
3848
4049
  }
3849
4050
  }
3850
4051
  function progressBar(score, max, width = 40) {
3851
4052
  const filled = Math.round(score / max * width);
3852
4053
  const empty = width - filled;
3853
- const bar = chalk3.hex("#f97316")("\u2593".repeat(filled)) + chalk3.gray("\u2591".repeat(empty));
4054
+ const bar = chalk4.hex("#f97316")("\u2593".repeat(filled)) + chalk4.gray("\u2591".repeat(empty));
3854
4055
  return bar;
3855
4056
  }
3856
4057
  function formatCheck(check) {
3857
- const icon = check.passed ? chalk3.green("\u2713") : check.earnedPoints < 0 ? chalk3.red("\u2717") : chalk3.gray("\u2717");
3858
- const points = check.passed ? chalk3.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk3.red(`${check.earnedPoints}`.padStart(4)) : chalk3.gray(" \u2014");
3859
- const name = check.passed ? chalk3.white(check.name) : chalk3.gray(check.name);
3860
- const detail = check.detail ? chalk3.gray(` (${check.detail})`) : "";
3861
- const suggestion = !check.passed && check.suggestion ? chalk3.gray(`
4058
+ const icon = check.passed ? chalk4.green("\u2713") : check.earnedPoints < 0 ? chalk4.red("\u2717") : chalk4.gray("\u2717");
4059
+ const points = check.passed ? chalk4.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk4.red(`${check.earnedPoints}`.padStart(4)) : chalk4.gray(" \u2014");
4060
+ const name = check.passed ? chalk4.white(check.name) : chalk4.gray(check.name);
4061
+ const detail = check.detail ? chalk4.gray(` (${check.detail})`) : "";
4062
+ const suggestion = !check.passed && check.suggestion ? chalk4.gray(`
3862
4063
  \u2192 ${check.suggestion}`) : "";
3863
4064
  return ` ${icon} ${name.padEnd(38)}${points}${detail}${suggestion}`;
3864
4065
  }
@@ -3866,19 +4067,19 @@ function displayScore(result) {
3866
4067
  const gc = gradeColor(result.grade);
3867
4068
  const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
3868
4069
  console.log("");
3869
- console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4070
+ console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3870
4071
  console.log("");
3871
- console.log(` ${chalk3.bold("Agent Config Score")} ${gc(chalk3.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk3.bold(result.grade))}`);
4072
+ console.log(` ${chalk4.bold("Agent Config Score")} ${gc(chalk4.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk4.bold(result.grade))}`);
3872
4073
  console.log(` ${progressBar(result.score, result.maxScore)}`);
3873
- console.log(chalk3.dim(` Target: ${agentLabel}`));
4074
+ console.log(chalk4.dim(` Target: ${agentLabel}`));
3874
4075
  console.log("");
3875
- console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4076
+ console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3876
4077
  console.log("");
3877
4078
  for (const category of CATEGORY_ORDER) {
3878
4079
  const summary = result.categories[category];
3879
4080
  const categoryChecks = result.checks.filter((c) => c.category === category);
3880
4081
  console.log(
3881
- chalk3.gray(` ${CATEGORY_LABELS[category]}`) + chalk3.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk3.white(`${summary.earned}`) + chalk3.gray(` / ${summary.max}`)
4082
+ chalk4.gray(` ${CATEGORY_LABELS[category]}`) + chalk4.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk4.white(`${summary.earned}`) + chalk4.gray(` / ${summary.max}`)
3882
4083
  );
3883
4084
  for (const check of categoryChecks) {
3884
4085
  console.log(formatCheck(check));
@@ -3891,48 +4092,48 @@ function displayScoreSummary(result) {
3891
4092
  const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
3892
4093
  console.log("");
3893
4094
  console.log(
3894
- chalk3.gray(" ") + gc(`${result.score}/${result.maxScore}`) + chalk3.gray(` (Grade ${result.grade})`) + chalk3.gray(` \xB7 ${agentLabel}`) + chalk3.gray(` \xB7 ${progressBar(result.score, result.maxScore, 20)}`)
4095
+ chalk4.gray(" ") + gc(`${result.score}/${result.maxScore}`) + chalk4.gray(` (Grade ${result.grade})`) + chalk4.gray(` \xB7 ${agentLabel}`) + chalk4.gray(` \xB7 ${progressBar(result.score, result.maxScore, 20)}`)
3895
4096
  );
3896
4097
  const failing = result.checks.filter((c) => !c.passed);
3897
4098
  if (failing.length > 0) {
3898
4099
  const shown = failing.slice(0, 5);
3899
4100
  for (const check of shown) {
3900
- console.log(chalk3.gray(` \u2717 ${check.name}`));
4101
+ console.log(chalk4.gray(` \u2717 ${check.name}`));
3901
4102
  }
3902
4103
  const remaining = failing.length - shown.length;
3903
4104
  const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
3904
- console.log(chalk3.dim(`
3905
- Run ${chalk3.hex("#83D1EB")("caliber score")} for details.${moreText}`));
4105
+ console.log(chalk4.dim(`
4106
+ Run ${chalk4.hex("#83D1EB")("caliber score")} for details.${moreText}`));
3906
4107
  }
3907
4108
  console.log("");
3908
4109
  }
3909
4110
  function displayScoreDelta(before, after) {
3910
4111
  const delta = after.score - before.score;
3911
4112
  const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
3912
- const deltaColor = delta >= 0 ? chalk3.green : chalk3.red;
4113
+ const deltaColor = delta >= 0 ? chalk4.green : chalk4.red;
3913
4114
  const beforeGc = gradeColor(before.grade);
3914
4115
  const afterGc = gradeColor(after.grade);
3915
4116
  console.log("");
3916
- console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4117
+ console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3917
4118
  console.log("");
3918
4119
  console.log(
3919
- ` Score: ${beforeGc(`${before.score}`)} ${chalk3.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk3.gray("\u2192")} ${afterGc(after.grade)}`
4120
+ ` Score: ${beforeGc(`${before.score}`)} ${chalk4.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk4.gray("\u2192")} ${afterGc(after.grade)}`
3920
4121
  );
3921
- console.log(` ${progressBar(before.score, before.maxScore, 19)} ${chalk3.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`);
4122
+ console.log(` ${progressBar(before.score, before.maxScore, 19)} ${chalk4.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`);
3922
4123
  console.log("");
3923
- console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4124
+ console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3924
4125
  console.log("");
3925
4126
  const improved = after.checks.filter((ac) => {
3926
4127
  const bc = before.checks.find((b) => b.id === ac.id);
3927
4128
  return bc && ac.earnedPoints > bc.earnedPoints;
3928
4129
  });
3929
4130
  if (improved.length > 0) {
3930
- console.log(chalk3.gray(" What improved:"));
4131
+ console.log(chalk4.gray(" What improved:"));
3931
4132
  for (const check of improved) {
3932
4133
  const bc = before.checks.find((b) => b.id === check.id);
3933
4134
  const gain = check.earnedPoints - bc.earnedPoints;
3934
4135
  console.log(
3935
- chalk3.green(" +") + chalk3.white(` ${check.name.padEnd(50)}`) + chalk3.green(`+${gain}`)
4136
+ chalk4.green(" +") + chalk4.white(` ${check.name.padEnd(50)}`) + chalk4.green(`+${gain}`)
3936
4137
  );
3937
4138
  }
3938
4139
  console.log("");
@@ -3940,10 +4141,10 @@ function displayScoreDelta(before, after) {
3940
4141
  }
3941
4142
 
3942
4143
  // src/mcp/index.ts
3943
- import chalk4 from "chalk";
4144
+ import chalk5 from "chalk";
3944
4145
  import ora from "ora";
3945
4146
  import readline3 from "readline";
3946
- import fs19 from "fs";
4147
+ import fs20 from "fs";
3947
4148
  import path16 from "path";
3948
4149
 
3949
4150
  // src/mcp/search.ts
@@ -4218,38 +4419,38 @@ ${truncated}`,
4218
4419
 
4219
4420
  // src/mcp/index.ts
4220
4421
  async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4221
- console.log(chalk4.hex("#6366f1").bold("\n MCP Server Discovery\n"));
4422
+ console.log(chalk5.hex("#6366f1").bold("\n MCP Server Discovery\n"));
4222
4423
  const toolDeps = fingerprint.tools;
4223
4424
  if (toolDeps.length === 0) {
4224
- console.log(chalk4.dim(" No external tools or services detected \u2014 skipping MCP discovery"));
4425
+ console.log(chalk5.dim(" No external tools or services detected \u2014 skipping MCP discovery"));
4225
4426
  return { installed: 0, names: [] };
4226
4427
  }
4227
4428
  const spinner = ora(`Searching MCP servers for ${toolDeps.length} detected tool${toolDeps.length === 1 ? "" : "s"}...`).start();
4228
- console.log(chalk4.dim(` Detected: ${toolDeps.join(", ")}`));
4429
+ console.log(chalk5.dim(` Detected: ${toolDeps.join(", ")}`));
4229
4430
  const existingMcps = getExistingMcpNames(fingerprint, targetAgent);
4230
4431
  const filteredDeps = toolDeps.filter((d) => {
4231
4432
  const lower = d.toLowerCase();
4232
4433
  return !existingMcps.some((name) => name.includes(lower) || lower.includes(name));
4233
4434
  });
4234
4435
  if (filteredDeps.length === 0) {
4235
- spinner.succeed(chalk4.dim("All detected tools already have MCP servers configured"));
4436
+ spinner.succeed(chalk5.dim("All detected tools already have MCP servers configured"));
4236
4437
  return { installed: 0, names: [] };
4237
4438
  }
4238
4439
  const candidates = await searchAllMcpSources(filteredDeps);
4239
4440
  if (candidates.length === 0) {
4240
- spinner.succeed(chalk4.dim("No MCP servers found for detected tools"));
4441
+ spinner.succeed(chalk5.dim("No MCP servers found for detected tools"));
4241
4442
  return { installed: 0, names: [] };
4242
4443
  }
4243
4444
  spinner.succeed(`Found ${candidates.length} candidate${candidates.length === 1 ? "" : "s"} for ${filteredDeps.join(", ")}`);
4244
4445
  const scoreSpinner = ora("Scoring MCP candidates...").start();
4245
4446
  const scored = await validateAndScore(candidates, filteredDeps);
4246
4447
  if (scored.length === 0) {
4247
- scoreSpinner.succeed(chalk4.dim("No quality MCP servers passed validation"));
4248
- console.log(chalk4.dim(` Candidates checked: ${candidates.map((c) => c.name).join(", ")}`));
4448
+ scoreSpinner.succeed(chalk5.dim("No quality MCP servers passed validation"));
4449
+ console.log(chalk5.dim(` Candidates checked: ${candidates.map((c) => c.name).join(", ")}`));
4249
4450
  return { installed: 0, names: [] };
4250
4451
  }
4251
4452
  scoreSpinner.succeed(`${scored.length} quality MCP server${scored.length === 1 ? "" : "s"} found`);
4252
- console.log(chalk4.dim(` Scored: ${scored.map((c) => `${c.name} (${c.score})`).join(", ")}`));
4453
+ console.log(chalk5.dim(` Scored: ${scored.map((c) => `${c.name} (${c.score})`).join(", ")}`));
4253
4454
  const selected = await interactiveSelect(scored);
4254
4455
  if (!selected || selected.length === 0) {
4255
4456
  return { installed: 0, names: [] };
@@ -4257,18 +4458,18 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4257
4458
  const mcpServers = {};
4258
4459
  const installedNames = [];
4259
4460
  for (const mcp of selected) {
4260
- console.log(chalk4.bold(`
4461
+ console.log(chalk5.bold(`
4261
4462
  Configuring ${mcp.name}...`));
4262
4463
  const readme = await fetchReadme(mcp.repoFullName);
4263
4464
  if (!readme) {
4264
- console.log(chalk4.yellow(` Could not fetch README for ${mcp.repoFullName} \u2014 skipping`));
4265
- console.log(chalk4.dim(` Manual setup: ${mcp.url}`));
4465
+ console.log(chalk5.yellow(` Could not fetch README for ${mcp.repoFullName} \u2014 skipping`));
4466
+ console.log(chalk5.dim(` Manual setup: ${mcp.url}`));
4266
4467
  continue;
4267
4468
  }
4268
4469
  const config = await extractMcpConfig(readme, mcp.name);
4269
4470
  if (!config || !config.command) {
4270
- console.log(chalk4.yellow(` Could not extract config for ${mcp.name} \u2014 skipping`));
4271
- console.log(chalk4.dim(` Manual setup: ${mcp.url}`));
4471
+ console.log(chalk5.yellow(` Could not extract config for ${mcp.name} \u2014 skipping`));
4472
+ console.log(chalk5.dim(` Manual setup: ${mcp.url}`));
4272
4473
  continue;
4273
4474
  }
4274
4475
  const env = {};
@@ -4286,7 +4487,7 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4286
4487
  if (Object.keys(env).length > 0) serverConfig.env = env;
4287
4488
  mcpServers[mcp.name] = serverConfig;
4288
4489
  installedNames.push(mcp.name);
4289
- console.log(` ${chalk4.green("\u2713")} ${mcp.name} configured`);
4490
+ console.log(` ${chalk5.green("\u2713")} ${mcp.name} configured`);
4290
4491
  }
4291
4492
  if (installedNames.length === 0) {
4292
4493
  return { installed: 0, names: [] };
@@ -4296,7 +4497,7 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4296
4497
  }
4297
4498
  if (targetAgent.includes("cursor")) {
4298
4499
  const cursorDir = path16.join(dir, ".cursor");
4299
- if (!fs19.existsSync(cursorDir)) fs19.mkdirSync(cursorDir, { recursive: true });
4500
+ if (!fs20.existsSync(cursorDir)) fs20.mkdirSync(cursorDir, { recursive: true });
4300
4501
  writeMcpJson(path16.join(cursorDir, "mcp.json"), mcpServers);
4301
4502
  }
4302
4503
  return { installed: installedNames.length, names: installedNames };
@@ -4304,14 +4505,14 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4304
4505
  function writeMcpJson(filePath, mcpServers) {
4305
4506
  let existing = {};
4306
4507
  try {
4307
- if (fs19.existsSync(filePath)) {
4308
- const parsed = JSON.parse(fs19.readFileSync(filePath, "utf-8"));
4508
+ if (fs20.existsSync(filePath)) {
4509
+ const parsed = JSON.parse(fs20.readFileSync(filePath, "utf-8"));
4309
4510
  if (parsed.mcpServers) existing = parsed.mcpServers;
4310
4511
  }
4311
4512
  } catch {
4312
4513
  }
4313
4514
  const merged = { ...existing, ...mcpServers };
4314
- fs19.writeFileSync(filePath, JSON.stringify({ mcpServers: merged }, null, 2) + "\n");
4515
+ fs20.writeFileSync(filePath, JSON.stringify({ mcpServers: merged }, null, 2) + "\n");
4315
4516
  }
4316
4517
  function getExistingMcpNames(fingerprint, targetAgent) {
4317
4518
  const names = [];
@@ -4330,7 +4531,7 @@ function getExistingMcpNames(fingerprint, targetAgent) {
4330
4531
  function promptInput2(question) {
4331
4532
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
4332
4533
  return new Promise((resolve2) => {
4333
- rl.question(chalk4.cyan(`${question}: `), (answer) => {
4534
+ rl.question(chalk5.cyan(`${question}: `), (answer) => {
4334
4535
  rl.close();
4335
4536
  resolve2(answer.trim());
4336
4537
  });
@@ -4338,10 +4539,10 @@ function promptInput2(question) {
4338
4539
  }
4339
4540
  async function interactiveSelect(candidates) {
4340
4541
  if (!process.stdin.isTTY) {
4341
- console.log(chalk4.bold("\n Available MCP servers:\n"));
4542
+ console.log(chalk5.bold("\n Available MCP servers:\n"));
4342
4543
  for (const c of candidates) {
4343
- const vendorTag = c.vendor ? chalk4.blue(" (vendor)") : "";
4344
- console.log(` ${String(c.score).padStart(3)} ${c.name}${vendorTag} ${chalk4.dim(c.reason)}`);
4544
+ const vendorTag = c.vendor ? chalk5.blue(" (vendor)") : "";
4545
+ console.log(` ${String(c.score).padStart(3)} ${c.name}${vendorTag} ${chalk5.dim(c.reason)}`);
4345
4546
  }
4346
4547
  console.log("");
4347
4548
  return null;
@@ -4352,18 +4553,18 @@ async function interactiveSelect(candidates) {
4352
4553
  let lineCount = 0;
4353
4554
  function render() {
4354
4555
  const lines = [];
4355
- lines.push(chalk4.bold(" Select MCP servers to install:"));
4556
+ lines.push(chalk5.bold(" Select MCP servers to install:"));
4356
4557
  lines.push("");
4357
4558
  for (let i = 0; i < candidates.length; i++) {
4358
4559
  const c = candidates[i];
4359
- const check = selected.has(i) ? chalk4.green("[x]") : "[ ]";
4360
- const ptr = i === cursor ? chalk4.cyan(">") : " ";
4361
- const scoreColor = c.score >= 90 ? chalk4.green : c.score >= 70 ? chalk4.yellow : chalk4.dim;
4362
- const vendorTag = c.vendor ? chalk4.blue(" (vendor)") : "";
4363
- lines.push(` ${ptr} ${check} ${scoreColor(String(c.score).padStart(3))} ${c.name}${vendorTag} ${chalk4.dim(c.reason.slice(0, 40))}`);
4560
+ const check = selected.has(i) ? chalk5.green("[x]") : "[ ]";
4561
+ const ptr = i === cursor ? chalk5.cyan(">") : " ";
4562
+ const scoreColor = c.score >= 90 ? chalk5.green : c.score >= 70 ? chalk5.yellow : chalk5.dim;
4563
+ const vendorTag = c.vendor ? chalk5.blue(" (vendor)") : "";
4564
+ lines.push(` ${ptr} ${check} ${scoreColor(String(c.score).padStart(3))} ${c.name}${vendorTag} ${chalk5.dim(c.reason.slice(0, 40))}`);
4364
4565
  }
4365
4566
  lines.push("");
4366
- lines.push(chalk4.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q skip"));
4567
+ lines.push(chalk5.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q skip"));
4367
4568
  return lines.join("\n");
4368
4569
  }
4369
4570
  function draw(initial) {
@@ -4412,7 +4613,7 @@ async function interactiveSelect(candidates) {
4412
4613
  case "\n":
4413
4614
  cleanup();
4414
4615
  if (selected.size === 0) {
4415
- console.log(chalk4.dim("\n No MCP servers selected.\n"));
4616
+ console.log(chalk5.dim("\n No MCP servers selected.\n"));
4416
4617
  resolve2(null);
4417
4618
  } else {
4418
4619
  resolve2(Array.from(selected).sort().map((i) => candidates[i]));
@@ -4422,7 +4623,7 @@ async function interactiveSelect(candidates) {
4422
4623
  case "\x1B":
4423
4624
  case "":
4424
4625
  cleanup();
4425
- console.log(chalk4.dim("\n Skipped MCP server installation.\n"));
4626
+ console.log(chalk5.dim("\n Skipped MCP server installation.\n"));
4426
4627
  resolve2(null);
4427
4628
  break;
4428
4629
  }
@@ -4433,8 +4634,8 @@ async function interactiveSelect(candidates) {
4433
4634
 
4434
4635
  // src/commands/onboard.ts
4435
4636
  async function initCommand(options) {
4436
- const brand = chalk5.hex("#EB9D83");
4437
- const title = chalk5.hex("#83D1EB");
4637
+ const brand = chalk6.hex("#EB9D83");
4638
+ const title = chalk6.hex("#83D1EB");
4438
4639
  console.log(brand.bold(`
4439
4640
  \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
4440
4641
  \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
@@ -4443,20 +4644,20 @@ async function initCommand(options) {
4443
4644
  \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551
4444
4645
  \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
4445
4646
  `));
4446
- console.log(chalk5.dim(" Onboard your project for AI-assisted development\n"));
4647
+ console.log(chalk6.dim(" Onboard your project for AI-assisted development\n"));
4447
4648
  console.log(title.bold(" Welcome to Caliber\n"));
4448
- console.log(chalk5.dim(" Caliber analyzes your codebase and creates tailored config files"));
4449
- console.log(chalk5.dim(" so your AI coding agents understand your project from day one.\n"));
4649
+ console.log(chalk6.dim(" Caliber analyzes your codebase and creates tailored config files"));
4650
+ console.log(chalk6.dim(" so your AI coding agents understand your project from day one.\n"));
4450
4651
  console.log(title.bold(" How onboarding works:\n"));
4451
- console.log(chalk5.dim(" 1. Connect Set up your LLM provider"));
4452
- console.log(chalk5.dim(" 2. Discover Analyze your code, dependencies, and structure"));
4453
- console.log(chalk5.dim(" 3. Generate Create config files tailored to your project"));
4454
- console.log(chalk5.dim(" 4. Review Preview, refine, and apply the changes"));
4455
- console.log(chalk5.dim(" 5. Enhance Discover MCP servers for your tools\n"));
4652
+ console.log(chalk6.dim(" 1. Connect Set up your LLM provider"));
4653
+ console.log(chalk6.dim(" 2. Discover Analyze your code, dependencies, and structure"));
4654
+ console.log(chalk6.dim(" 3. Generate Create config files tailored to your project"));
4655
+ console.log(chalk6.dim(" 4. Review Preview, refine, and apply the changes"));
4656
+ console.log(chalk6.dim(" 5. Enhance Discover MCP servers for your tools\n"));
4456
4657
  console.log(title.bold(" Step 1/5 \u2014 Connect your LLM\n"));
4457
4658
  let config = loadConfig();
4458
4659
  if (!config) {
4459
- console.log(chalk5.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
4660
+ console.log(chalk6.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
4460
4661
  try {
4461
4662
  await runInteractiveProviderSetup({
4462
4663
  selectMessage: "How do you want to use Caliber? (choose LLM provider)"
@@ -4467,23 +4668,23 @@ async function initCommand(options) {
4467
4668
  }
4468
4669
  config = loadConfig();
4469
4670
  if (!config) {
4470
- console.log(chalk5.red(" Setup was cancelled or failed.\n"));
4671
+ console.log(chalk6.red(" Setup was cancelled or failed.\n"));
4471
4672
  throw new Error("__exit__");
4472
4673
  }
4473
- console.log(chalk5.green(" \u2713 Provider saved. Let's continue.\n"));
4674
+ console.log(chalk6.green(" \u2713 Provider saved. Let's continue.\n"));
4474
4675
  }
4475
4676
  const displayModel = config.model === "default" && config.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : config.model;
4476
4677
  const fastModel = getFastModel();
4477
4678
  const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
4478
- console.log(chalk5.dim(modelLine + "\n"));
4679
+ console.log(chalk6.dim(modelLine + "\n"));
4479
4680
  console.log(title.bold(" Step 2/5 \u2014 Discover your project\n"));
4480
- console.log(chalk5.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
4681
+ console.log(chalk6.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
4481
4682
  const spinner = ora2("Analyzing project...").start();
4482
4683
  const fingerprint = collectFingerprint(process.cwd());
4483
4684
  await enrichFingerprintWithLLM(fingerprint, process.cwd());
4484
4685
  spinner.succeed("Project analyzed");
4485
- console.log(chalk5.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
4486
- console.log(chalk5.dim(` Files: ${fingerprint.fileTree.length} found
4686
+ console.log(chalk6.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
4687
+ console.log(chalk6.dim(` Files: ${fingerprint.fileTree.length} found
4487
4688
  `));
4488
4689
  const targetAgent = options.agent || await promptAgent();
4489
4690
  const preScore = computeLocalScore(process.cwd(), targetAgent);
@@ -4502,23 +4703,23 @@ async function initCommand(options) {
4502
4703
  const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length || fingerprint.existingConfigs.agentsMd);
4503
4704
  const NON_LLM_CHECKS = /* @__PURE__ */ new Set(["hooks_configured", "agents_md_exists", "permissions_configured", "mcp_servers"]);
4504
4705
  if (hasExistingConfig && baselineScore.score === 100) {
4505
- console.log(chalk5.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
4506
- console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber onboard --force") + chalk5.dim(" to regenerate anyway.\n"));
4706
+ console.log(chalk6.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
4707
+ console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber onboard --force") + chalk6.dim(" to regenerate anyway.\n"));
4507
4708
  if (!options.force) return;
4508
4709
  }
4509
4710
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
4510
4711
  const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
4511
4712
  if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
4512
- console.log(chalk5.bold.green("\n Your config is fully optimized for LLM generation.\n"));
4513
- console.log(chalk5.dim(" Remaining items need CLI actions:\n"));
4713
+ console.log(chalk6.bold.green("\n Your config is fully optimized for LLM generation.\n"));
4714
+ console.log(chalk6.dim(" Remaining items need CLI actions:\n"));
4514
4715
  for (const check of allFailingChecks) {
4515
- console.log(chalk5.dim(` \u2022 ${check.name}`));
4716
+ console.log(chalk6.dim(` \u2022 ${check.name}`));
4516
4717
  if (check.suggestion) {
4517
- console.log(` ${chalk5.hex("#83D1EB")(check.suggestion)}`);
4718
+ console.log(` ${chalk6.hex("#83D1EB")(check.suggestion)}`);
4518
4719
  }
4519
4720
  }
4520
4721
  console.log("");
4521
- console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber onboard --force") + chalk5.dim(" to regenerate anyway.\n"));
4722
+ console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber onboard --force") + chalk6.dim(" to regenerate anyway.\n"));
4522
4723
  return;
4523
4724
  }
4524
4725
  const isEmpty = fingerprint.fileTree.length < 3;
@@ -4534,22 +4735,22 @@ async function initCommand(options) {
4534
4735
  currentScore = baselineScore.score;
4535
4736
  if (failingChecks.length > 0) {
4536
4737
  console.log(title.bold(" Step 3/5 \u2014 Fine-tuning\n"));
4537
- console.log(chalk5.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
4738
+ console.log(chalk6.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
4538
4739
  `));
4539
4740
  for (const check of failingChecks) {
4540
- console.log(chalk5.dim(` \u2022 ${check.name}`));
4741
+ console.log(chalk6.dim(` \u2022 ${check.name}`));
4541
4742
  }
4542
4743
  console.log("");
4543
4744
  }
4544
4745
  } else if (hasExistingConfig) {
4545
4746
  console.log(title.bold(" Step 3/5 \u2014 Improve your setup\n"));
4546
- console.log(chalk5.dim(" Reviewing your existing configs against your codebase"));
4547
- console.log(chalk5.dim(" and preparing improvements.\n"));
4747
+ console.log(chalk6.dim(" Reviewing your existing configs against your codebase"));
4748
+ console.log(chalk6.dim(" and preparing improvements.\n"));
4548
4749
  } else {
4549
4750
  console.log(title.bold(" Step 3/5 \u2014 Build your agent setup\n"));
4550
- console.log(chalk5.dim(" Creating config files tailored to your project.\n"));
4751
+ console.log(chalk6.dim(" Creating config files tailored to your project.\n"));
4551
4752
  }
4552
- console.log(chalk5.dim(" This can take a couple of minutes depending on your model and provider.\n"));
4753
+ console.log(chalk6.dim(" This can take a couple of minutes depending on your model and provider.\n"));
4553
4754
  const genStartTime = Date.now();
4554
4755
  const genSpinner = ora2("Generating setup...").start();
4555
4756
  const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
@@ -4591,8 +4792,8 @@ async function initCommand(options) {
4591
4792
  if (!generatedSetup) {
4592
4793
  genSpinner.fail("Failed to generate setup.");
4593
4794
  if (rawOutput) {
4594
- console.log(chalk5.dim("\nRaw LLM output (JSON parse failed):"));
4595
- console.log(chalk5.dim(rawOutput.slice(0, 500)));
4795
+ console.log(chalk6.dim("\nRaw LLM output (JSON parse failed):"));
4796
+ console.log(chalk6.dim(rawOutput.slice(0, 500)));
4596
4797
  }
4597
4798
  throw new Error("__exit__");
4598
4799
  }
@@ -4600,7 +4801,7 @@ async function initCommand(options) {
4600
4801
  const mins = Math.floor(elapsedMs / 6e4);
4601
4802
  const secs = Math.floor(elapsedMs % 6e4 / 1e3);
4602
4803
  const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
4603
- genSpinner.succeed(`Setup generated ${chalk5.dim(`in ${timeStr}`)}`);
4804
+ genSpinner.succeed(`Setup generated ${chalk6.dim(`in ${timeStr}`)}`);
4604
4805
  printSetupSummary(generatedSetup);
4605
4806
  const sessionHistory = [];
4606
4807
  sessionHistory.push({
@@ -4611,11 +4812,11 @@ async function initCommand(options) {
4611
4812
  const setupFiles = collectSetupFiles(generatedSetup);
4612
4813
  const staged = stageFiles(setupFiles, process.cwd());
4613
4814
  const totalChanges = staged.newFiles + staged.modifiedFiles;
4614
- console.log(chalk5.dim(` ${chalk5.green(`${staged.newFiles} new`)} / ${chalk5.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
4815
+ console.log(chalk6.dim(` ${chalk6.green(`${staged.newFiles} new`)} / ${chalk6.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
4615
4816
  `));
4616
4817
  let action;
4617
4818
  if (totalChanges === 0) {
4618
- console.log(chalk5.dim(" No changes needed \u2014 your configs are already up to date.\n"));
4819
+ console.log(chalk6.dim(" No changes needed \u2014 your configs are already up to date.\n"));
4619
4820
  cleanupStaging();
4620
4821
  action = "accept";
4621
4822
  } else {
@@ -4630,12 +4831,12 @@ async function initCommand(options) {
4630
4831
  generatedSetup = await refineLoop(generatedSetup, targetAgent, sessionHistory);
4631
4832
  if (!generatedSetup) {
4632
4833
  cleanupStaging();
4633
- console.log(chalk5.dim("Refinement cancelled. No files were modified."));
4834
+ console.log(chalk6.dim("Refinement cancelled. No files were modified."));
4634
4835
  return;
4635
4836
  }
4636
4837
  const updatedFiles = collectSetupFiles(generatedSetup);
4637
4838
  const restaged = stageFiles(updatedFiles, process.cwd());
4638
- console.log(chalk5.dim(` ${chalk5.green(`${restaged.newFiles} new`)} / ${chalk5.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
4839
+ console.log(chalk6.dim(` ${chalk6.green(`${restaged.newFiles} new`)} / ${chalk6.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
4639
4840
  `));
4640
4841
  printSetupSummary(generatedSetup);
4641
4842
  await openReview("terminal", restaged.stagedFiles);
@@ -4643,11 +4844,11 @@ async function initCommand(options) {
4643
4844
  }
4644
4845
  cleanupStaging();
4645
4846
  if (action === "decline") {
4646
- console.log(chalk5.dim("Setup declined. No files were modified."));
4847
+ console.log(chalk6.dim("Setup declined. No files were modified."));
4647
4848
  return;
4648
4849
  }
4649
4850
  if (options.dryRun) {
4650
- console.log(chalk5.yellow("\n[Dry run] Would write the following files:"));
4851
+ console.log(chalk6.yellow("\n[Dry run] Would write the following files:"));
4651
4852
  console.log(JSON.stringify(generatedSetup, null, 2));
4652
4853
  return;
4653
4854
  }
@@ -4655,43 +4856,43 @@ async function initCommand(options) {
4655
4856
  try {
4656
4857
  const result = writeSetup(generatedSetup);
4657
4858
  writeSpinner.succeed("Config files written");
4658
- console.log(chalk5.bold("\nFiles created/updated:"));
4859
+ console.log(chalk6.bold("\nFiles created/updated:"));
4659
4860
  for (const file of result.written) {
4660
- console.log(` ${chalk5.green("\u2713")} ${file}`);
4861
+ console.log(` ${chalk6.green("\u2713")} ${file}`);
4661
4862
  }
4662
4863
  if (result.deleted.length > 0) {
4663
- console.log(chalk5.bold("\nFiles removed:"));
4864
+ console.log(chalk6.bold("\nFiles removed:"));
4664
4865
  for (const file of result.deleted) {
4665
- console.log(` ${chalk5.red("\u2717")} ${file}`);
4866
+ console.log(` ${chalk6.red("\u2717")} ${file}`);
4666
4867
  }
4667
4868
  }
4668
4869
  if (result.backupDir) {
4669
- console.log(chalk5.dim(`
4870
+ console.log(chalk6.dim(`
4670
4871
  Backups saved to ${result.backupDir}`));
4671
4872
  }
4672
4873
  } catch (err) {
4673
4874
  writeSpinner.fail("Failed to write files");
4674
- console.error(chalk5.red(err instanceof Error ? err.message : "Unknown error"));
4875
+ console.error(chalk6.red(err instanceof Error ? err.message : "Unknown error"));
4675
4876
  throw new Error("__exit__");
4676
4877
  }
4677
4878
  console.log(title.bold("\n Step 5/5 \u2014 Enhance with MCP servers\n"));
4678
- console.log(chalk5.dim(" MCP servers connect your AI agents to external tools and services"));
4679
- console.log(chalk5.dim(" like databases, APIs, and platforms your project depends on.\n"));
4879
+ console.log(chalk6.dim(" MCP servers connect your AI agents to external tools and services"));
4880
+ console.log(chalk6.dim(" like databases, APIs, and platforms your project depends on.\n"));
4680
4881
  if (fingerprint.tools.length > 0) {
4681
4882
  try {
4682
4883
  const mcpResult = await discoverAndInstallMcps(targetAgent, fingerprint, process.cwd());
4683
4884
  if (mcpResult.installed > 0) {
4684
- console.log(chalk5.bold(`
4885
+ console.log(chalk6.bold(`
4685
4886
  ${mcpResult.installed} MCP server${mcpResult.installed > 1 ? "s" : ""} configured`));
4686
4887
  for (const name of mcpResult.names) {
4687
- console.log(` ${chalk5.green("\u2713")} ${name}`);
4888
+ console.log(` ${chalk6.green("\u2713")} ${name}`);
4688
4889
  }
4689
4890
  }
4690
4891
  } catch (err) {
4691
- console.log(chalk5.dim(" MCP discovery skipped: " + (err instanceof Error ? err.message : "unknown error")));
4892
+ console.log(chalk6.dim(" MCP discovery skipped: " + (err instanceof Error ? err.message : "unknown error")));
4692
4893
  }
4693
4894
  } else {
4694
- console.log(chalk5.dim(" No external tools or services detected \u2014 skipping MCP discovery.\n"));
4895
+ console.log(chalk6.dim(" No external tools or services detected \u2014 skipping MCP discovery.\n"));
4695
4896
  }
4696
4897
  ensurePermissions();
4697
4898
  const sha = getCurrentHeadSha();
@@ -4702,56 +4903,56 @@ async function initCommand(options) {
4702
4903
  });
4703
4904
  console.log("");
4704
4905
  console.log(title.bold(" Keep your configs fresh\n"));
4705
- console.log(chalk5.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
4906
+ console.log(chalk6.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
4706
4907
  const hookChoice = await promptHookType(targetAgent);
4707
4908
  if (hookChoice === "claude" || hookChoice === "both") {
4708
4909
  const hookResult = installHook();
4709
4910
  if (hookResult.installed) {
4710
- console.log(` ${chalk5.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
4711
- console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber hooks --remove") + chalk5.dim(" to disable"));
4911
+ console.log(` ${chalk6.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
4912
+ console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber hooks --remove") + chalk6.dim(" to disable"));
4712
4913
  } else if (hookResult.alreadyInstalled) {
4713
- console.log(chalk5.dim(" Claude Code hook already installed"));
4914
+ console.log(chalk6.dim(" Claude Code hook already installed"));
4714
4915
  }
4715
4916
  const learnResult = installLearningHooks();
4716
4917
  if (learnResult.installed) {
4717
- console.log(` ${chalk5.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
4718
- console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber learn remove") + chalk5.dim(" to disable"));
4918
+ console.log(` ${chalk6.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
4919
+ console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber learn remove") + chalk6.dim(" to disable"));
4719
4920
  } else if (learnResult.alreadyInstalled) {
4720
- console.log(chalk5.dim(" Learning hooks already installed"));
4921
+ console.log(chalk6.dim(" Learning hooks already installed"));
4721
4922
  }
4722
4923
  }
4723
4924
  if (hookChoice === "precommit" || hookChoice === "both") {
4724
4925
  const precommitResult = installPreCommitHook();
4725
4926
  if (precommitResult.installed) {
4726
- console.log(` ${chalk5.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
4727
- console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber hooks --remove") + chalk5.dim(" to disable"));
4927
+ console.log(` ${chalk6.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
4928
+ console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber hooks --remove") + chalk6.dim(" to disable"));
4728
4929
  } else if (precommitResult.alreadyInstalled) {
4729
- console.log(chalk5.dim(" Pre-commit hook already installed"));
4930
+ console.log(chalk6.dim(" Pre-commit hook already installed"));
4730
4931
  } else {
4731
- console.log(chalk5.yellow(" Could not install pre-commit hook (not a git repository?)"));
4932
+ console.log(chalk6.yellow(" Could not install pre-commit hook (not a git repository?)"));
4732
4933
  }
4733
4934
  }
4734
4935
  if (hookChoice === "skip") {
4735
- console.log(chalk5.dim(" Skipped auto-refresh hooks. Run ") + chalk5.hex("#83D1EB")("caliber hooks --install") + chalk5.dim(" later to enable."));
4936
+ console.log(chalk6.dim(" Skipped auto-refresh hooks. Run ") + chalk6.hex("#83D1EB")("caliber hooks --install") + chalk6.dim(" later to enable."));
4736
4937
  }
4737
4938
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
4738
4939
  if (afterScore.score < baselineScore.score) {
4739
4940
  console.log("");
4740
- console.log(chalk5.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
4941
+ console.log(chalk6.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
4741
4942
  try {
4742
4943
  const { restored, removed } = undoSetup();
4743
4944
  if (restored.length > 0 || removed.length > 0) {
4744
- console.log(chalk5.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
4945
+ console.log(chalk6.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
4745
4946
  }
4746
4947
  } catch {
4747
4948
  }
4748
- console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber onboard --force") + chalk5.dim(" to override.\n"));
4949
+ console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber onboard --force") + chalk6.dim(" to override.\n"));
4749
4950
  return;
4750
4951
  }
4751
4952
  displayScoreDelta(baselineScore, afterScore);
4752
- console.log(chalk5.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
4753
- console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber undo") + chalk5.dim(" to revert changes.\n"));
4754
- console.log(chalk5.bold(" Next steps:\n"));
4953
+ console.log(chalk6.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
4954
+ console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber undo") + chalk6.dim(" to revert changes.\n"));
4955
+ console.log(chalk6.bold(" Next steps:\n"));
4755
4956
  console.log(` ${title("caliber score")} See your full config breakdown`);
4756
4957
  console.log(` ${title("caliber recommend")} Discover community skills for your stack`);
4757
4958
  console.log(` ${title("caliber undo")} Revert all changes from this run`);
@@ -4768,9 +4969,9 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
4768
4969
  }
4769
4970
  const isValid = await classifyRefineIntent(message);
4770
4971
  if (!isValid) {
4771
- console.log(chalk5.dim(" This doesn't look like a config change request."));
4772
- console.log(chalk5.dim(" Describe what to add, remove, or modify in your configs."));
4773
- console.log(chalk5.dim(' Type "done" to accept the current setup.\n'));
4972
+ console.log(chalk6.dim(" This doesn't look like a config change request."));
4973
+ console.log(chalk6.dim(" Describe what to add, remove, or modify in your configs."));
4974
+ console.log(chalk6.dim(' Type "done" to accept the current setup.\n'));
4774
4975
  continue;
4775
4976
  }
4776
4977
  const refineSpinner = ora2("Refining setup...").start();
@@ -4791,10 +4992,10 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
4791
4992
  });
4792
4993
  refineSpinner.succeed("Setup updated");
4793
4994
  printSetupSummary(refined);
4794
- console.log(chalk5.dim('Type "done" to accept, or describe more changes.'));
4995
+ console.log(chalk6.dim('Type "done" to accept, or describe more changes.'));
4795
4996
  } else {
4796
4997
  refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
4797
- console.log(chalk5.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
4998
+ console.log(chalk6.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
4798
4999
  }
4799
5000
  }
4800
5001
  }
@@ -4854,7 +5055,7 @@ ${JSON.stringify(checkList, null, 2)}`,
4854
5055
  function promptInput3(question) {
4855
5056
  const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
4856
5057
  return new Promise((resolve2) => {
4857
- rl.question(chalk5.cyan(`${question} `), (answer) => {
5058
+ rl.question(chalk6.cyan(`${question} `), (answer) => {
4858
5059
  rl.close();
4859
5060
  resolve2(answer.trim());
4860
5061
  });
@@ -4886,210 +5087,13 @@ async function promptHookType(targetAgent) {
4886
5087
  choices.push({ name: "Both (Claude Code + pre-commit)", value: "both" });
4887
5088
  }
4888
5089
  choices.push({ name: "Skip for now", value: "skip" });
4889
- return select2({
5090
+ return select3({
4890
5091
  message: "How would you like to auto-refresh your docs?",
4891
5092
  choices
4892
5093
  });
4893
5094
  }
4894
- async function promptWantsReview() {
4895
- const answer = await select2({
4896
- message: "Would you like to review the diffs before deciding?",
4897
- choices: [
4898
- { name: "Yes, show me the diffs", value: true },
4899
- { name: "No, continue", value: false }
4900
- ]
4901
- });
4902
- return answer;
4903
- }
4904
- async function promptReviewMethod() {
4905
- const available = detectAvailableEditors();
4906
- if (available.length === 1) return "terminal";
4907
- const choices = available.map((method) => {
4908
- switch (method) {
4909
- case "cursor":
4910
- return { name: "Cursor (diff view)", value: "cursor" };
4911
- case "vscode":
4912
- return { name: "VS Code (diff view)", value: "vscode" };
4913
- case "terminal":
4914
- return { name: "Terminal", value: "terminal" };
4915
- }
4916
- });
4917
- return select2({ message: "How would you like to review the changes?", choices });
4918
- }
4919
- async function openReview(method, stagedFiles) {
4920
- if (method === "cursor" || method === "vscode") {
4921
- openDiffsInEditor(method, stagedFiles.map((f) => ({
4922
- originalPath: f.originalPath,
4923
- proposedPath: f.proposedPath
4924
- })));
4925
- console.log(chalk5.dim(" Diffs opened in your editor.\n"));
4926
- return;
4927
- }
4928
- const fileInfos = stagedFiles.map((file) => {
4929
- const proposed = fs20.readFileSync(file.proposedPath, "utf-8");
4930
- const current = file.currentPath ? fs20.readFileSync(file.currentPath, "utf-8") : "";
4931
- const patch = createTwoFilesPatch(
4932
- file.isNew ? "/dev/null" : file.relativePath,
4933
- file.relativePath,
4934
- current,
4935
- proposed
4936
- );
4937
- let added = 0, removed = 0;
4938
- for (const line of patch.split("\n")) {
4939
- if (line.startsWith("+") && !line.startsWith("+++")) added++;
4940
- if (line.startsWith("-") && !line.startsWith("---")) removed++;
4941
- }
4942
- return {
4943
- relativePath: file.relativePath,
4944
- isNew: file.isNew,
4945
- added,
4946
- removed,
4947
- lines: proposed.split("\n").length,
4948
- patch
4949
- };
4950
- });
4951
- await interactiveDiffExplorer(fileInfos);
4952
- }
4953
- async function interactiveDiffExplorer(files) {
4954
- if (!process.stdin.isTTY) {
4955
- for (const f of files) {
4956
- const icon = f.isNew ? chalk5.green("+") : chalk5.yellow("~");
4957
- const stats = f.isNew ? chalk5.dim(`${f.lines} lines`) : `${chalk5.green(`+${f.added}`)} ${chalk5.red(`-${f.removed}`)}`;
4958
- console.log(` ${icon} ${f.relativePath} ${stats}`);
4959
- }
4960
- console.log("");
4961
- return;
4962
- }
4963
- const { stdin, stdout } = process;
4964
- let cursor = 0;
4965
- let viewing = null;
4966
- let scrollOffset = 0;
4967
- let lineCount = 0;
4968
- function getTermHeight() {
4969
- return (stdout.rows || 24) - 4;
4970
- }
4971
- function renderFileList() {
4972
- const lines = [];
4973
- lines.push(chalk5.bold(" Review changes"));
4974
- lines.push("");
4975
- for (let i = 0; i < files.length; i++) {
4976
- const f = files[i];
4977
- const ptr = i === cursor ? chalk5.cyan(">") : " ";
4978
- const icon = f.isNew ? chalk5.green("+") : chalk5.yellow("~");
4979
- const stats = f.isNew ? chalk5.dim(`${f.lines} lines`) : `${chalk5.green(`+${f.added}`)} ${chalk5.red(`-${f.removed}`)}`;
4980
- lines.push(` ${ptr} ${icon} ${f.relativePath} ${stats}`);
4981
- }
4982
- lines.push("");
4983
- lines.push(chalk5.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
4984
- return lines.join("\n");
4985
- }
4986
- function renderDiff(index) {
4987
- const f = files[index];
4988
- const lines = [];
4989
- const header = f.isNew ? ` ${chalk5.green("+")} ${f.relativePath} ${chalk5.dim("(new file)")}` : ` ${chalk5.yellow("~")} ${f.relativePath} ${chalk5.green(`+${f.added}`)} ${chalk5.red(`-${f.removed}`)}`;
4990
- lines.push(header);
4991
- lines.push(chalk5.dim(" " + "\u2500".repeat(60)));
4992
- const patchLines = f.patch.split("\n");
4993
- const bodyLines = patchLines.slice(4);
4994
- const maxVisible = getTermHeight() - 4;
4995
- const visibleLines = bodyLines.slice(scrollOffset, scrollOffset + maxVisible);
4996
- for (const line of visibleLines) {
4997
- if (line.startsWith("+")) {
4998
- lines.push(chalk5.green(" " + line));
4999
- } else if (line.startsWith("-")) {
5000
- lines.push(chalk5.red(" " + line));
5001
- } else if (line.startsWith("@@")) {
5002
- lines.push(chalk5.cyan(" " + line));
5003
- } else {
5004
- lines.push(chalk5.dim(" " + line));
5005
- }
5006
- }
5007
- const totalBody = bodyLines.length;
5008
- if (totalBody > maxVisible) {
5009
- const pct = Math.round((scrollOffset + maxVisible) / totalBody * 100);
5010
- lines.push(chalk5.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
5011
- }
5012
- lines.push("");
5013
- lines.push(chalk5.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
5014
- return lines.join("\n");
5015
- }
5016
- function draw(initial) {
5017
- if (!initial && lineCount > 0) {
5018
- stdout.write(`\x1B[${lineCount}A`);
5019
- }
5020
- stdout.write("\x1B[0J");
5021
- const output = viewing !== null ? renderDiff(viewing) : renderFileList();
5022
- stdout.write(output + "\n");
5023
- lineCount = output.split("\n").length;
5024
- }
5025
- return new Promise((resolve2) => {
5026
- console.log("");
5027
- draw(true);
5028
- stdin.setRawMode(true);
5029
- stdin.resume();
5030
- stdin.setEncoding("utf8");
5031
- function cleanup() {
5032
- stdin.removeListener("data", onData);
5033
- stdin.setRawMode(false);
5034
- stdin.pause();
5035
- }
5036
- function onData(key) {
5037
- if (viewing !== null) {
5038
- const f = files[viewing];
5039
- const totalBody = f.patch.split("\n").length - 4;
5040
- const maxVisible = getTermHeight() - 4;
5041
- switch (key) {
5042
- case "\x1B[A":
5043
- scrollOffset = Math.max(0, scrollOffset - 1);
5044
- draw(false);
5045
- break;
5046
- case "\x1B[B":
5047
- scrollOffset = Math.min(Math.max(0, totalBody - maxVisible), scrollOffset + 1);
5048
- draw(false);
5049
- break;
5050
- case " ":
5051
- case "\x1B":
5052
- viewing = null;
5053
- scrollOffset = 0;
5054
- draw(false);
5055
- break;
5056
- case "q":
5057
- case "":
5058
- cleanup();
5059
- console.log("");
5060
- resolve2();
5061
- break;
5062
- }
5063
- } else {
5064
- switch (key) {
5065
- case "\x1B[A":
5066
- cursor = (cursor - 1 + files.length) % files.length;
5067
- draw(false);
5068
- break;
5069
- case "\x1B[B":
5070
- cursor = (cursor + 1) % files.length;
5071
- draw(false);
5072
- break;
5073
- case "\r":
5074
- case "\n":
5075
- viewing = cursor;
5076
- scrollOffset = 0;
5077
- draw(false);
5078
- break;
5079
- case "q":
5080
- case "":
5081
- cleanup();
5082
- console.log("");
5083
- resolve2();
5084
- break;
5085
- }
5086
- }
5087
- }
5088
- stdin.on("data", onData);
5089
- });
5090
- }
5091
5095
  async function promptReviewAction() {
5092
- return select2({
5096
+ return select3({
5093
5097
  message: "What would you like to do?",
5094
5098
  choices: [
5095
5099
  { name: "Accept and apply", value: "accept" },
@@ -5104,26 +5108,26 @@ function printSetupSummary(setup) {
5104
5108
  const fileDescriptions = setup.fileDescriptions;
5105
5109
  const deletions = setup.deletions;
5106
5110
  console.log("");
5107
- console.log(chalk5.bold(" Proposed changes:\n"));
5111
+ console.log(chalk6.bold(" Proposed changes:\n"));
5108
5112
  const getDescription = (filePath) => {
5109
5113
  return fileDescriptions?.[filePath];
5110
5114
  };
5111
5115
  if (claude) {
5112
5116
  if (claude.claudeMd) {
5113
- const icon = fs20.existsSync("CLAUDE.md") ? chalk5.yellow("~") : chalk5.green("+");
5117
+ const icon = fs21.existsSync("CLAUDE.md") ? chalk6.yellow("~") : chalk6.green("+");
5114
5118
  const desc = getDescription("CLAUDE.md");
5115
- console.log(` ${icon} ${chalk5.bold("CLAUDE.md")}`);
5116
- if (desc) console.log(chalk5.dim(` ${desc}`));
5119
+ console.log(` ${icon} ${chalk6.bold("CLAUDE.md")}`);
5120
+ if (desc) console.log(chalk6.dim(` ${desc}`));
5117
5121
  console.log("");
5118
5122
  }
5119
5123
  const skills = claude.skills;
5120
5124
  if (Array.isArray(skills) && skills.length > 0) {
5121
5125
  for (const skill of skills) {
5122
5126
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
5123
- const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5127
+ const icon = fs21.existsSync(skillPath) ? chalk6.yellow("~") : chalk6.green("+");
5124
5128
  const desc = getDescription(skillPath);
5125
- console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5126
- console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
5129
+ console.log(` ${icon} ${chalk6.bold(skillPath)}`);
5130
+ console.log(chalk6.dim(` ${desc || skill.description || skill.name}`));
5127
5131
  console.log("");
5128
5132
  }
5129
5133
  }
@@ -5131,40 +5135,40 @@ function printSetupSummary(setup) {
5131
5135
  const codex = setup.codex;
5132
5136
  if (codex) {
5133
5137
  if (codex.agentsMd) {
5134
- const icon = fs20.existsSync("AGENTS.md") ? chalk5.yellow("~") : chalk5.green("+");
5138
+ const icon = fs21.existsSync("AGENTS.md") ? chalk6.yellow("~") : chalk6.green("+");
5135
5139
  const desc = getDescription("AGENTS.md");
5136
- console.log(` ${icon} ${chalk5.bold("AGENTS.md")}`);
5137
- if (desc) console.log(chalk5.dim(` ${desc}`));
5140
+ console.log(` ${icon} ${chalk6.bold("AGENTS.md")}`);
5141
+ if (desc) console.log(chalk6.dim(` ${desc}`));
5138
5142
  console.log("");
5139
5143
  }
5140
5144
  const codexSkills = codex.skills;
5141
5145
  if (Array.isArray(codexSkills) && codexSkills.length > 0) {
5142
5146
  for (const skill of codexSkills) {
5143
5147
  const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
5144
- const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5148
+ const icon = fs21.existsSync(skillPath) ? chalk6.yellow("~") : chalk6.green("+");
5145
5149
  const desc = getDescription(skillPath);
5146
- console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5147
- console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
5150
+ console.log(` ${icon} ${chalk6.bold(skillPath)}`);
5151
+ console.log(chalk6.dim(` ${desc || skill.description || skill.name}`));
5148
5152
  console.log("");
5149
5153
  }
5150
5154
  }
5151
5155
  }
5152
5156
  if (cursor) {
5153
5157
  if (cursor.cursorrules) {
5154
- const icon = fs20.existsSync(".cursorrules") ? chalk5.yellow("~") : chalk5.green("+");
5158
+ const icon = fs21.existsSync(".cursorrules") ? chalk6.yellow("~") : chalk6.green("+");
5155
5159
  const desc = getDescription(".cursorrules");
5156
- console.log(` ${icon} ${chalk5.bold(".cursorrules")}`);
5157
- if (desc) console.log(chalk5.dim(` ${desc}`));
5160
+ console.log(` ${icon} ${chalk6.bold(".cursorrules")}`);
5161
+ if (desc) console.log(chalk6.dim(` ${desc}`));
5158
5162
  console.log("");
5159
5163
  }
5160
5164
  const cursorSkills = cursor.skills;
5161
5165
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
5162
5166
  for (const skill of cursorSkills) {
5163
5167
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
5164
- const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5168
+ const icon = fs21.existsSync(skillPath) ? chalk6.yellow("~") : chalk6.green("+");
5165
5169
  const desc = getDescription(skillPath);
5166
- console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5167
- console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
5170
+ console.log(` ${icon} ${chalk6.bold(skillPath)}`);
5171
+ console.log(chalk6.dim(` ${desc || skill.description || skill.name}`));
5168
5172
  console.log("");
5169
5173
  }
5170
5174
  }
@@ -5172,40 +5176,40 @@ function printSetupSummary(setup) {
5172
5176
  if (Array.isArray(rules) && rules.length > 0) {
5173
5177
  for (const rule of rules) {
5174
5178
  const rulePath = `.cursor/rules/${rule.filename}`;
5175
- const icon = fs20.existsSync(rulePath) ? chalk5.yellow("~") : chalk5.green("+");
5179
+ const icon = fs21.existsSync(rulePath) ? chalk6.yellow("~") : chalk6.green("+");
5176
5180
  const desc = getDescription(rulePath);
5177
- console.log(` ${icon} ${chalk5.bold(rulePath)}`);
5181
+ console.log(` ${icon} ${chalk6.bold(rulePath)}`);
5178
5182
  if (desc) {
5179
- console.log(chalk5.dim(` ${desc}`));
5183
+ console.log(chalk6.dim(` ${desc}`));
5180
5184
  } else {
5181
5185
  const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
5182
- if (firstLine) console.log(chalk5.dim(` ${firstLine.trim().slice(0, 80)}`));
5186
+ if (firstLine) console.log(chalk6.dim(` ${firstLine.trim().slice(0, 80)}`));
5183
5187
  }
5184
5188
  console.log("");
5185
5189
  }
5186
5190
  }
5187
5191
  }
5188
- if (!codex && !fs20.existsSync("AGENTS.md")) {
5189
- console.log(` ${chalk5.green("+")} ${chalk5.bold("AGENTS.md")}`);
5190
- console.log(chalk5.dim(" Cross-agent coordination file"));
5192
+ if (!codex && !fs21.existsSync("AGENTS.md")) {
5193
+ console.log(` ${chalk6.green("+")} ${chalk6.bold("AGENTS.md")}`);
5194
+ console.log(chalk6.dim(" Cross-agent coordination file"));
5191
5195
  console.log("");
5192
5196
  }
5193
5197
  if (Array.isArray(deletions) && deletions.length > 0) {
5194
5198
  for (const del of deletions) {
5195
- console.log(` ${chalk5.red("-")} ${chalk5.bold(del.filePath)}`);
5196
- console.log(chalk5.dim(` ${del.reason}`));
5199
+ console.log(` ${chalk6.red("-")} ${chalk6.bold(del.filePath)}`);
5200
+ console.log(chalk6.dim(` ${del.reason}`));
5197
5201
  console.log("");
5198
5202
  }
5199
5203
  }
5200
- console.log(` ${chalk5.green("+")} ${chalk5.dim("new")} ${chalk5.yellow("~")} ${chalk5.dim("modified")} ${chalk5.red("-")} ${chalk5.dim("removed")}`);
5204
+ console.log(` ${chalk6.green("+")} ${chalk6.dim("new")} ${chalk6.yellow("~")} ${chalk6.dim("modified")} ${chalk6.red("-")} ${chalk6.dim("removed")}`);
5201
5205
  console.log("");
5202
5206
  }
5203
5207
  function ensurePermissions() {
5204
5208
  const settingsPath = ".claude/settings.json";
5205
5209
  let settings = {};
5206
5210
  try {
5207
- if (fs20.existsSync(settingsPath)) {
5208
- settings = JSON.parse(fs20.readFileSync(settingsPath, "utf-8"));
5211
+ if (fs21.existsSync(settingsPath)) {
5212
+ settings = JSON.parse(fs21.readFileSync(settingsPath, "utf-8"));
5209
5213
  }
5210
5214
  } catch {
5211
5215
  }
@@ -5219,12 +5223,12 @@ function ensurePermissions() {
5219
5223
  "Bash(git *)"
5220
5224
  ];
5221
5225
  settings.permissions = permissions;
5222
- if (!fs20.existsSync(".claude")) fs20.mkdirSync(".claude", { recursive: true });
5223
- fs20.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5226
+ if (!fs21.existsSync(".claude")) fs21.mkdirSync(".claude", { recursive: true });
5227
+ fs21.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5224
5228
  }
5225
5229
 
5226
5230
  // src/commands/undo.ts
5227
- import chalk6 from "chalk";
5231
+ import chalk7 from "chalk";
5228
5232
  import ora3 from "ora";
5229
5233
  function undoCommand() {
5230
5234
  const spinner = ora3("Reverting setup...").start();
@@ -5236,27 +5240,27 @@ function undoCommand() {
5236
5240
  }
5237
5241
  spinner.succeed("Setup reverted successfully.\n");
5238
5242
  if (restored.length > 0) {
5239
- console.log(chalk6.cyan(" Restored from backup:"));
5243
+ console.log(chalk7.cyan(" Restored from backup:"));
5240
5244
  for (const file of restored) {
5241
- console.log(` ${chalk6.green("\u21A9")} ${file}`);
5245
+ console.log(` ${chalk7.green("\u21A9")} ${file}`);
5242
5246
  }
5243
5247
  }
5244
5248
  if (removed.length > 0) {
5245
- console.log(chalk6.cyan(" Removed:"));
5249
+ console.log(chalk7.cyan(" Removed:"));
5246
5250
  for (const file of removed) {
5247
- console.log(` ${chalk6.red("\u2717")} ${file}`);
5251
+ console.log(` ${chalk7.red("\u2717")} ${file}`);
5248
5252
  }
5249
5253
  }
5250
5254
  console.log("");
5251
5255
  } catch (err) {
5252
- spinner.fail(chalk6.red(err instanceof Error ? err.message : "Undo failed"));
5256
+ spinner.fail(chalk7.red(err instanceof Error ? err.message : "Undo failed"));
5253
5257
  throw new Error("__exit__");
5254
5258
  }
5255
5259
  }
5256
5260
 
5257
5261
  // src/commands/status.ts
5258
- import chalk7 from "chalk";
5259
- import fs21 from "fs";
5262
+ import chalk8 from "chalk";
5263
+ import fs22 from "fs";
5260
5264
  async function statusCommand(options) {
5261
5265
  const config = loadConfig();
5262
5266
  const manifest = readManifest();
@@ -5269,39 +5273,39 @@ async function statusCommand(options) {
5269
5273
  }, null, 2));
5270
5274
  return;
5271
5275
  }
5272
- console.log(chalk7.bold("\nCaliber Status\n"));
5276
+ console.log(chalk8.bold("\nCaliber Status\n"));
5273
5277
  if (config) {
5274
- console.log(` LLM: ${chalk7.green(config.provider)} (${config.model})`);
5278
+ console.log(` LLM: ${chalk8.green(config.provider)} (${config.model})`);
5275
5279
  } else {
5276
- console.log(` LLM: ${chalk7.yellow("Not configured")} \u2014 run ${chalk7.hex("#83D1EB")("caliber config")}`);
5280
+ console.log(` LLM: ${chalk8.yellow("Not configured")} \u2014 run ${chalk8.hex("#83D1EB")("caliber config")}`);
5277
5281
  }
5278
5282
  if (!manifest) {
5279
- console.log(` Setup: ${chalk7.dim("No setup applied")}`);
5280
- console.log(chalk7.dim("\n Run ") + chalk7.hex("#83D1EB")("caliber onboard") + chalk7.dim(" to get started.\n"));
5283
+ console.log(` Setup: ${chalk8.dim("No setup applied")}`);
5284
+ console.log(chalk8.dim("\n Run ") + chalk8.hex("#83D1EB")("caliber onboard") + chalk8.dim(" to get started.\n"));
5281
5285
  return;
5282
5286
  }
5283
- console.log(` Files managed: ${chalk7.cyan(manifest.entries.length.toString())}`);
5287
+ console.log(` Files managed: ${chalk8.cyan(manifest.entries.length.toString())}`);
5284
5288
  for (const entry of manifest.entries) {
5285
- const exists = fs21.existsSync(entry.path);
5286
- const icon = exists ? chalk7.green("\u2713") : chalk7.red("\u2717");
5289
+ const exists = fs22.existsSync(entry.path);
5290
+ const icon = exists ? chalk8.green("\u2713") : chalk8.red("\u2717");
5287
5291
  console.log(` ${icon} ${entry.path} (${entry.action})`);
5288
5292
  }
5289
5293
  console.log("");
5290
5294
  }
5291
5295
 
5292
5296
  // src/commands/regenerate.ts
5293
- import chalk8 from "chalk";
5297
+ import chalk9 from "chalk";
5294
5298
  import ora4 from "ora";
5295
- import select3 from "@inquirer/select";
5299
+ import select4 from "@inquirer/select";
5296
5300
  async function regenerateCommand(options) {
5297
5301
  const config = loadConfig();
5298
5302
  if (!config) {
5299
- console.log(chalk8.red("No LLM provider configured. Run ") + chalk8.hex("#83D1EB")("caliber config") + chalk8.red(" first."));
5303
+ console.log(chalk9.red("No LLM provider configured. Run ") + chalk9.hex("#83D1EB")("caliber config") + chalk9.red(" first."));
5300
5304
  throw new Error("__exit__");
5301
5305
  }
5302
5306
  const manifest = readManifest();
5303
5307
  if (!manifest) {
5304
- console.log(chalk8.yellow("No existing setup found. Run ") + chalk8.hex("#83D1EB")("caliber onboard") + chalk8.yellow(" first."));
5308
+ console.log(chalk9.yellow("No existing setup found. Run ") + chalk9.hex("#83D1EB")("caliber onboard") + chalk9.yellow(" first."));
5305
5309
  throw new Error("__exit__");
5306
5310
  }
5307
5311
  const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
@@ -5311,6 +5315,10 @@ async function regenerateCommand(options) {
5311
5315
  spinner.succeed("Project analyzed");
5312
5316
  const baselineScore = computeLocalScore(process.cwd(), targetAgent);
5313
5317
  displayScoreSummary(baselineScore);
5318
+ if (baselineScore.score === 100) {
5319
+ console.log(chalk9.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
5320
+ return;
5321
+ }
5314
5322
  const genSpinner = ora4("Regenerating setup...").start();
5315
5323
  const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
5316
5324
  genMessages.start();
@@ -5349,23 +5357,28 @@ async function regenerateCommand(options) {
5349
5357
  const setupFiles = collectSetupFiles(generatedSetup);
5350
5358
  const staged = stageFiles(setupFiles, process.cwd());
5351
5359
  const totalChanges = staged.newFiles + staged.modifiedFiles;
5352
- console.log(chalk8.dim(`
5353
- ${chalk8.green(`${staged.newFiles} new`)} / ${chalk8.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
5360
+ console.log(chalk9.dim(`
5361
+ ${chalk9.green(`${staged.newFiles} new`)} / ${chalk9.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
5354
5362
  `));
5355
5363
  if (totalChanges === 0) {
5356
- console.log(chalk8.dim(" No changes needed \u2014 your configs are already up to date.\n"));
5364
+ console.log(chalk9.dim(" No changes needed \u2014 your configs are already up to date.\n"));
5357
5365
  cleanupStaging();
5358
5366
  return;
5359
5367
  }
5360
5368
  if (options.dryRun) {
5361
- console.log(chalk8.yellow("[Dry run] Would write:"));
5369
+ console.log(chalk9.yellow("[Dry run] Would write:"));
5362
5370
  for (const f of staged.stagedFiles) {
5363
- console.log(` ${f.isNew ? chalk8.green("+") : chalk8.yellow("~")} ${f.relativePath}`);
5371
+ console.log(` ${f.isNew ? chalk9.green("+") : chalk9.yellow("~")} ${f.relativePath}`);
5364
5372
  }
5365
5373
  cleanupStaging();
5366
5374
  return;
5367
5375
  }
5368
- const action = await select3({
5376
+ const wantsReview = await promptWantsReview();
5377
+ if (wantsReview) {
5378
+ const reviewMethod = await promptReviewMethod();
5379
+ await openReview(reviewMethod, staged.stagedFiles);
5380
+ }
5381
+ const action = await select4({
5369
5382
  message: "Apply regenerated setup?",
5370
5383
  choices: [
5371
5384
  { name: "Accept and apply", value: "accept" },
@@ -5374,7 +5387,7 @@ async function regenerateCommand(options) {
5374
5387
  });
5375
5388
  cleanupStaging();
5376
5389
  if (action === "decline") {
5377
- console.log(chalk8.dim("Regeneration cancelled. No files were modified."));
5390
+ console.log(chalk9.dim("Regeneration cancelled. No files were modified."));
5378
5391
  return;
5379
5392
  }
5380
5393
  const writeSpinner = ora4("Writing config files...").start();
@@ -5382,20 +5395,20 @@ async function regenerateCommand(options) {
5382
5395
  const result = writeSetup(generatedSetup);
5383
5396
  writeSpinner.succeed("Config files written");
5384
5397
  for (const file of result.written) {
5385
- console.log(` ${chalk8.green("\u2713")} ${file}`);
5398
+ console.log(` ${chalk9.green("\u2713")} ${file}`);
5386
5399
  }
5387
5400
  if (result.deleted.length > 0) {
5388
5401
  for (const file of result.deleted) {
5389
- console.log(` ${chalk8.red("\u2717")} ${file}`);
5402
+ console.log(` ${chalk9.red("\u2717")} ${file}`);
5390
5403
  }
5391
5404
  }
5392
5405
  if (result.backupDir) {
5393
- console.log(chalk8.dim(`
5406
+ console.log(chalk9.dim(`
5394
5407
  Backups saved to ${result.backupDir}`));
5395
5408
  }
5396
5409
  } catch (err) {
5397
5410
  writeSpinner.fail("Failed to write files");
5398
- console.error(chalk8.red(err instanceof Error ? err.message : "Unknown error"));
5411
+ console.error(chalk9.red(err instanceof Error ? err.message : "Unknown error"));
5399
5412
  throw new Error("__exit__");
5400
5413
  }
5401
5414
  const sha = getCurrentHeadSha();
@@ -5407,36 +5420,36 @@ async function regenerateCommand(options) {
5407
5420
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
5408
5421
  if (afterScore.score < baselineScore.score) {
5409
5422
  console.log("");
5410
- console.log(chalk8.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
5423
+ console.log(chalk9.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
5411
5424
  try {
5412
5425
  const { restored, removed } = undoSetup();
5413
5426
  if (restored.length > 0 || removed.length > 0) {
5414
- console.log(chalk8.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
5427
+ console.log(chalk9.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
5415
5428
  }
5416
5429
  } catch {
5417
5430
  }
5418
- console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to override.\n"));
5431
+ console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber onboard --force") + chalk9.dim(" to override.\n"));
5419
5432
  return;
5420
5433
  }
5421
5434
  displayScoreDelta(baselineScore, afterScore);
5422
- console.log(chalk8.bold.green(" Regeneration complete!"));
5423
- console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber undo") + chalk8.dim(" to revert changes.\n"));
5435
+ console.log(chalk9.bold.green(" Regeneration complete!"));
5436
+ console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber undo") + chalk9.dim(" to revert changes.\n"));
5424
5437
  }
5425
5438
 
5426
5439
  // src/commands/recommend.ts
5427
- import chalk9 from "chalk";
5440
+ import chalk10 from "chalk";
5428
5441
  import ora5 from "ora";
5429
5442
  import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5, existsSync as existsSync9, writeFileSync } from "fs";
5430
5443
  import { join as join8, dirname as dirname2 } from "path";
5431
5444
 
5432
5445
  // src/scanner/index.ts
5433
- import fs22 from "fs";
5446
+ import fs23 from "fs";
5434
5447
  import path17 from "path";
5435
5448
  import crypto2 from "crypto";
5436
5449
  function scanLocalState(dir) {
5437
5450
  const items = [];
5438
5451
  const claudeMdPath = path17.join(dir, "CLAUDE.md");
5439
- if (fs22.existsSync(claudeMdPath)) {
5452
+ if (fs23.existsSync(claudeMdPath)) {
5440
5453
  items.push({
5441
5454
  type: "rule",
5442
5455
  platform: "claude",
@@ -5446,8 +5459,8 @@ function scanLocalState(dir) {
5446
5459
  });
5447
5460
  }
5448
5461
  const skillsDir = path17.join(dir, ".claude", "skills");
5449
- if (fs22.existsSync(skillsDir)) {
5450
- for (const file of fs22.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5462
+ if (fs23.existsSync(skillsDir)) {
5463
+ for (const file of fs23.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5451
5464
  const filePath = path17.join(skillsDir, file);
5452
5465
  items.push({
5453
5466
  type: "skill",
@@ -5459,9 +5472,9 @@ function scanLocalState(dir) {
5459
5472
  }
5460
5473
  }
5461
5474
  const mcpJsonPath = path17.join(dir, ".mcp.json");
5462
- if (fs22.existsSync(mcpJsonPath)) {
5475
+ if (fs23.existsSync(mcpJsonPath)) {
5463
5476
  try {
5464
- const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
5477
+ const mcpJson = JSON.parse(fs23.readFileSync(mcpJsonPath, "utf-8"));
5465
5478
  if (mcpJson.mcpServers) {
5466
5479
  for (const name of Object.keys(mcpJson.mcpServers)) {
5467
5480
  items.push({
@@ -5477,7 +5490,7 @@ function scanLocalState(dir) {
5477
5490
  }
5478
5491
  }
5479
5492
  const agentsMdPath = path17.join(dir, "AGENTS.md");
5480
- if (fs22.existsSync(agentsMdPath)) {
5493
+ if (fs23.existsSync(agentsMdPath)) {
5481
5494
  items.push({
5482
5495
  type: "rule",
5483
5496
  platform: "codex",
@@ -5487,11 +5500,11 @@ function scanLocalState(dir) {
5487
5500
  });
5488
5501
  }
5489
5502
  const codexSkillsDir = path17.join(dir, ".agents", "skills");
5490
- if (fs22.existsSync(codexSkillsDir)) {
5503
+ if (fs23.existsSync(codexSkillsDir)) {
5491
5504
  try {
5492
- for (const name of fs22.readdirSync(codexSkillsDir)) {
5505
+ for (const name of fs23.readdirSync(codexSkillsDir)) {
5493
5506
  const skillFile = path17.join(codexSkillsDir, name, "SKILL.md");
5494
- if (fs22.existsSync(skillFile)) {
5507
+ if (fs23.existsSync(skillFile)) {
5495
5508
  items.push({
5496
5509
  type: "skill",
5497
5510
  platform: "codex",
@@ -5505,7 +5518,7 @@ function scanLocalState(dir) {
5505
5518
  }
5506
5519
  }
5507
5520
  const cursorrulesPath = path17.join(dir, ".cursorrules");
5508
- if (fs22.existsSync(cursorrulesPath)) {
5521
+ if (fs23.existsSync(cursorrulesPath)) {
5509
5522
  items.push({
5510
5523
  type: "rule",
5511
5524
  platform: "cursor",
@@ -5515,8 +5528,8 @@ function scanLocalState(dir) {
5515
5528
  });
5516
5529
  }
5517
5530
  const cursorRulesDir = path17.join(dir, ".cursor", "rules");
5518
- if (fs22.existsSync(cursorRulesDir)) {
5519
- for (const file of fs22.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5531
+ if (fs23.existsSync(cursorRulesDir)) {
5532
+ for (const file of fs23.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5520
5533
  const filePath = path17.join(cursorRulesDir, file);
5521
5534
  items.push({
5522
5535
  type: "rule",
@@ -5528,11 +5541,11 @@ function scanLocalState(dir) {
5528
5541
  }
5529
5542
  }
5530
5543
  const cursorSkillsDir = path17.join(dir, ".cursor", "skills");
5531
- if (fs22.existsSync(cursorSkillsDir)) {
5544
+ if (fs23.existsSync(cursorSkillsDir)) {
5532
5545
  try {
5533
- for (const name of fs22.readdirSync(cursorSkillsDir)) {
5546
+ for (const name of fs23.readdirSync(cursorSkillsDir)) {
5534
5547
  const skillFile = path17.join(cursorSkillsDir, name, "SKILL.md");
5535
- if (fs22.existsSync(skillFile)) {
5548
+ if (fs23.existsSync(skillFile)) {
5536
5549
  items.push({
5537
5550
  type: "skill",
5538
5551
  platform: "cursor",
@@ -5546,9 +5559,9 @@ function scanLocalState(dir) {
5546
5559
  }
5547
5560
  }
5548
5561
  const cursorMcpPath = path17.join(dir, ".cursor", "mcp.json");
5549
- if (fs22.existsSync(cursorMcpPath)) {
5562
+ if (fs23.existsSync(cursorMcpPath)) {
5550
5563
  try {
5551
- const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
5564
+ const mcpJson = JSON.parse(fs23.readFileSync(cursorMcpPath, "utf-8"));
5552
5565
  if (mcpJson.mcpServers) {
5553
5566
  for (const name of Object.keys(mcpJson.mcpServers)) {
5554
5567
  items.push({
@@ -5566,7 +5579,7 @@ function scanLocalState(dir) {
5566
5579
  return items;
5567
5580
  }
5568
5581
  function hashFile(filePath) {
5569
- const text = fs22.readFileSync(filePath, "utf-8");
5582
+ const text = fs23.readFileSync(filePath, "utf-8");
5570
5583
  return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
5571
5584
  }
5572
5585
  function hashJson(obj) {
@@ -5881,7 +5894,7 @@ async function recommendCommand(options) {
5881
5894
  ...extractTopDeps()
5882
5895
  ].filter(Boolean))];
5883
5896
  if (technologies.length === 0) {
5884
- console.log(chalk9.yellow("Could not detect any languages or dependencies. Try running from a project root."));
5897
+ console.log(chalk10.yellow("Could not detect any languages or dependencies. Try running from a project root."));
5885
5898
  throw new Error("__exit__");
5886
5899
  }
5887
5900
  const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
@@ -5898,7 +5911,7 @@ async function recommendCommand(options) {
5898
5911
  return;
5899
5912
  }
5900
5913
  searchSpinner.succeed(
5901
- `Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk9.dim(` (${filteredCount} already installed)`) : "")
5914
+ `Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk10.dim(` (${filteredCount} already installed)`) : "")
5902
5915
  );
5903
5916
  let results;
5904
5917
  const config = loadConfig();
@@ -5932,7 +5945,7 @@ async function recommendCommand(options) {
5932
5945
  }
5933
5946
  const unavailableCount = results.length - available.length;
5934
5947
  fetchSpinner.succeed(
5935
- `${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk9.dim(` (${unavailableCount} unavailable)`) : "")
5948
+ `${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk10.dim(` (${unavailableCount} unavailable)`) : "")
5936
5949
  );
5937
5950
  const selected = await interactiveSelect2(available);
5938
5951
  if (selected?.length) {
@@ -5951,27 +5964,27 @@ async function interactiveSelect2(recs) {
5951
5964
  const hasScores = recs.some((r) => r.score > 0);
5952
5965
  function render() {
5953
5966
  const lines = [];
5954
- lines.push(chalk9.bold(" Recommendations"));
5967
+ lines.push(chalk10.bold(" Recommendations"));
5955
5968
  lines.push("");
5956
5969
  if (hasScores) {
5957
- lines.push(` ${chalk9.dim("Score".padEnd(7))} ${chalk9.dim("Name".padEnd(28))} ${chalk9.dim("Why")}`);
5970
+ lines.push(` ${chalk10.dim("Score".padEnd(7))} ${chalk10.dim("Name".padEnd(28))} ${chalk10.dim("Why")}`);
5958
5971
  } else {
5959
- lines.push(` ${chalk9.dim("Name".padEnd(30))} ${chalk9.dim("Technology".padEnd(18))} ${chalk9.dim("Source")}`);
5972
+ lines.push(` ${chalk10.dim("Name".padEnd(30))} ${chalk10.dim("Technology".padEnd(18))} ${chalk10.dim("Source")}`);
5960
5973
  }
5961
- lines.push(chalk9.dim(" " + "\u2500".repeat(70)));
5974
+ lines.push(chalk10.dim(" " + "\u2500".repeat(70)));
5962
5975
  for (let i = 0; i < recs.length; i++) {
5963
5976
  const rec = recs[i];
5964
- const check = selected.has(i) ? chalk9.green("[x]") : "[ ]";
5965
- const ptr = i === cursor ? chalk9.cyan(">") : " ";
5977
+ const check = selected.has(i) ? chalk10.green("[x]") : "[ ]";
5978
+ const ptr = i === cursor ? chalk10.cyan(">") : " ";
5966
5979
  if (hasScores) {
5967
- const scoreColor = rec.score >= 90 ? chalk9.green : rec.score >= 70 ? chalk9.yellow : chalk9.dim;
5968
- lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(26)} ${chalk9.dim(rec.reason.slice(0, 40))}`);
5980
+ const scoreColor = rec.score >= 90 ? chalk10.green : rec.score >= 70 ? chalk10.yellow : chalk10.dim;
5981
+ lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(26)} ${chalk10.dim(rec.reason.slice(0, 40))}`);
5969
5982
  } else {
5970
- lines.push(` ${ptr} ${check} ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk9.dim(rec.source_url || "")}`);
5983
+ lines.push(` ${ptr} ${check} ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk10.dim(rec.source_url || "")}`);
5971
5984
  }
5972
5985
  }
5973
5986
  lines.push("");
5974
- lines.push(chalk9.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
5987
+ lines.push(chalk10.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
5975
5988
  return lines.join("\n");
5976
5989
  }
5977
5990
  function draw(initial) {
@@ -6020,7 +6033,7 @@ async function interactiveSelect2(recs) {
6020
6033
  case "\n":
6021
6034
  cleanup();
6022
6035
  if (selected.size === 0) {
6023
- console.log(chalk9.dim("\n No skills selected.\n"));
6036
+ console.log(chalk10.dim("\n No skills selected.\n"));
6024
6037
  resolve2(null);
6025
6038
  } else {
6026
6039
  resolve2(Array.from(selected).sort().map((i) => recs[i]));
@@ -6030,7 +6043,7 @@ async function interactiveSelect2(recs) {
6030
6043
  case "\x1B":
6031
6044
  case "":
6032
6045
  cleanup();
6033
- console.log(chalk9.dim("\n Cancelled.\n"));
6046
+ console.log(chalk10.dim("\n Cancelled.\n"));
6034
6047
  resolve2(null);
6035
6048
  break;
6036
6049
  }
@@ -6093,7 +6106,7 @@ async function installSkills(recs, platforms, contentMap) {
6093
6106
  if (installed.length > 0) {
6094
6107
  spinner.succeed(`Installed ${installed.length} file${installed.length > 1 ? "s" : ""}`);
6095
6108
  for (const p of installed) {
6096
- console.log(chalk9.green(` \u2713 ${p}`));
6109
+ console.log(chalk10.green(` \u2713 ${p}`));
6097
6110
  }
6098
6111
  } else {
6099
6112
  spinner.fail("No skills were installed");
@@ -6102,25 +6115,25 @@ async function installSkills(recs, platforms, contentMap) {
6102
6115
  }
6103
6116
  function printRecommendations(recs) {
6104
6117
  const hasScores = recs.some((r) => r.score > 0);
6105
- console.log(chalk9.bold("\n Recommendations\n"));
6118
+ console.log(chalk10.bold("\n Recommendations\n"));
6106
6119
  if (hasScores) {
6107
- console.log(` ${chalk9.dim("Score".padEnd(7))} ${chalk9.dim("Name".padEnd(28))} ${chalk9.dim("Why")}`);
6120
+ console.log(` ${chalk10.dim("Score".padEnd(7))} ${chalk10.dim("Name".padEnd(28))} ${chalk10.dim("Why")}`);
6108
6121
  } else {
6109
- console.log(` ${chalk9.dim("Name".padEnd(30))} ${chalk9.dim("Technology".padEnd(18))} ${chalk9.dim("Source")}`);
6122
+ console.log(` ${chalk10.dim("Name".padEnd(30))} ${chalk10.dim("Technology".padEnd(18))} ${chalk10.dim("Source")}`);
6110
6123
  }
6111
- console.log(chalk9.dim(" " + "\u2500".repeat(70)));
6124
+ console.log(chalk10.dim(" " + "\u2500".repeat(70)));
6112
6125
  for (const rec of recs) {
6113
6126
  if (hasScores) {
6114
- console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(26)} ${chalk9.dim(rec.reason.slice(0, 50))}`);
6127
+ console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(26)} ${chalk10.dim(rec.reason.slice(0, 50))}`);
6115
6128
  } else {
6116
- console.log(` ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk9.dim(rec.source_url || "")}`);
6129
+ console.log(` ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk10.dim(rec.source_url || "")}`);
6117
6130
  }
6118
6131
  }
6119
6132
  console.log("");
6120
6133
  }
6121
6134
 
6122
6135
  // src/commands/score.ts
6123
- import chalk10 from "chalk";
6136
+ import chalk11 from "chalk";
6124
6137
  async function scoreCommand(options) {
6125
6138
  const dir = process.cwd();
6126
6139
  const target = options.agent ?? readState()?.targetAgent;
@@ -6134,22 +6147,22 @@ async function scoreCommand(options) {
6134
6147
  return;
6135
6148
  }
6136
6149
  displayScore(result);
6137
- const separator = chalk10.gray(" " + "\u2500".repeat(53));
6150
+ const separator = chalk11.gray(" " + "\u2500".repeat(53));
6138
6151
  console.log(separator);
6139
6152
  if (result.score < 40) {
6140
- console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to generate a complete, optimized setup."));
6153
+ console.log(chalk11.gray(" Run ") + chalk11.hex("#83D1EB")("caliber onboard") + chalk11.gray(" to generate a complete, optimized setup."));
6141
6154
  } else if (result.score < 70) {
6142
- console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to improve your setup."));
6155
+ console.log(chalk11.gray(" Run ") + chalk11.hex("#83D1EB")("caliber onboard") + chalk11.gray(" to improve your setup."));
6143
6156
  } else {
6144
- console.log(chalk10.green(" Looking good!") + chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber regenerate") + chalk10.gray(" to rebuild from scratch."));
6157
+ console.log(chalk11.green(" Looking good!") + chalk11.gray(" Run ") + chalk11.hex("#83D1EB")("caliber regenerate") + chalk11.gray(" to rebuild from scratch."));
6145
6158
  }
6146
6159
  console.log("");
6147
6160
  }
6148
6161
 
6149
6162
  // src/commands/refresh.ts
6150
- import fs24 from "fs";
6163
+ import fs25 from "fs";
6151
6164
  import path19 from "path";
6152
- import chalk11 from "chalk";
6165
+ import chalk12 from "chalk";
6153
6166
  import ora6 from "ora";
6154
6167
 
6155
6168
  // src/lib/git-diff.ts
@@ -6225,37 +6238,37 @@ function collectDiff(lastSha) {
6225
6238
  }
6226
6239
 
6227
6240
  // src/writers/refresh.ts
6228
- import fs23 from "fs";
6241
+ import fs24 from "fs";
6229
6242
  import path18 from "path";
6230
6243
  function writeRefreshDocs(docs) {
6231
6244
  const written = [];
6232
6245
  if (docs.claudeMd) {
6233
- fs23.writeFileSync("CLAUDE.md", docs.claudeMd);
6246
+ fs24.writeFileSync("CLAUDE.md", docs.claudeMd);
6234
6247
  written.push("CLAUDE.md");
6235
6248
  }
6236
6249
  if (docs.readmeMd) {
6237
- fs23.writeFileSync("README.md", docs.readmeMd);
6250
+ fs24.writeFileSync("README.md", docs.readmeMd);
6238
6251
  written.push("README.md");
6239
6252
  }
6240
6253
  if (docs.cursorrules) {
6241
- fs23.writeFileSync(".cursorrules", docs.cursorrules);
6254
+ fs24.writeFileSync(".cursorrules", docs.cursorrules);
6242
6255
  written.push(".cursorrules");
6243
6256
  }
6244
6257
  if (docs.cursorRules) {
6245
6258
  const rulesDir = path18.join(".cursor", "rules");
6246
- if (!fs23.existsSync(rulesDir)) fs23.mkdirSync(rulesDir, { recursive: true });
6259
+ if (!fs24.existsSync(rulesDir)) fs24.mkdirSync(rulesDir, { recursive: true });
6247
6260
  for (const rule of docs.cursorRules) {
6248
6261
  const filePath = path18.join(rulesDir, rule.filename);
6249
- fs23.writeFileSync(filePath, rule.content);
6262
+ fs24.writeFileSync(filePath, rule.content);
6250
6263
  written.push(filePath);
6251
6264
  }
6252
6265
  }
6253
6266
  if (docs.claudeSkills) {
6254
6267
  const skillsDir = path18.join(".claude", "skills");
6255
- if (!fs23.existsSync(skillsDir)) fs23.mkdirSync(skillsDir, { recursive: true });
6268
+ if (!fs24.existsSync(skillsDir)) fs24.mkdirSync(skillsDir, { recursive: true });
6256
6269
  for (const skill of docs.claudeSkills) {
6257
6270
  const filePath = path18.join(skillsDir, skill.filename);
6258
- fs23.writeFileSync(filePath, skill.content);
6271
+ fs24.writeFileSync(filePath, skill.content);
6259
6272
  written.push(filePath);
6260
6273
  }
6261
6274
  }
@@ -6332,11 +6345,11 @@ function log(quiet, ...args) {
6332
6345
  function discoverGitRepos(parentDir) {
6333
6346
  const repos = [];
6334
6347
  try {
6335
- const entries = fs24.readdirSync(parentDir, { withFileTypes: true });
6348
+ const entries = fs25.readdirSync(parentDir, { withFileTypes: true });
6336
6349
  for (const entry of entries) {
6337
6350
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
6338
6351
  const childPath = path19.join(parentDir, entry.name);
6339
- if (fs24.existsSync(path19.join(childPath, ".git"))) {
6352
+ if (fs25.existsSync(path19.join(childPath, ".git"))) {
6340
6353
  repos.push(childPath);
6341
6354
  }
6342
6355
  }
@@ -6346,7 +6359,7 @@ function discoverGitRepos(parentDir) {
6346
6359
  }
6347
6360
  async function refreshSingleRepo(repoDir, options) {
6348
6361
  const quiet = !!options.quiet;
6349
- const prefix = options.label ? `${chalk11.bold(options.label)} ` : "";
6362
+ const prefix = options.label ? `${chalk12.bold(options.label)} ` : "";
6350
6363
  const state = readState();
6351
6364
  const lastSha = state?.lastRefreshSha ?? null;
6352
6365
  const diff = collectDiff(lastSha);
@@ -6355,7 +6368,7 @@ async function refreshSingleRepo(repoDir, options) {
6355
6368
  if (currentSha) {
6356
6369
  writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
6357
6370
  }
6358
- log(quiet, chalk11.dim(`${prefix}No changes since last refresh.`));
6371
+ log(quiet, chalk12.dim(`${prefix}No changes since last refresh.`));
6359
6372
  return;
6360
6373
  }
6361
6374
  const spinner = quiet ? null : ora6(`${prefix}Analyzing changes...`).start();
@@ -6387,10 +6400,10 @@ async function refreshSingleRepo(repoDir, options) {
6387
6400
  if (options.dryRun) {
6388
6401
  spinner?.info(`${prefix}Dry run \u2014 would update:`);
6389
6402
  for (const doc of response.docsUpdated) {
6390
- console.log(` ${chalk11.yellow("~")} ${doc}`);
6403
+ console.log(` ${chalk12.yellow("~")} ${doc}`);
6391
6404
  }
6392
6405
  if (response.changesSummary) {
6393
- console.log(chalk11.dim(`
6406
+ console.log(chalk12.dim(`
6394
6407
  ${response.changesSummary}`));
6395
6408
  }
6396
6409
  return;
@@ -6398,10 +6411,10 @@ async function refreshSingleRepo(repoDir, options) {
6398
6411
  const written = writeRefreshDocs(response.updatedDocs);
6399
6412
  spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
6400
6413
  for (const file of written) {
6401
- log(quiet, ` ${chalk11.green("\u2713")} ${file}`);
6414
+ log(quiet, ` ${chalk12.green("\u2713")} ${file}`);
6402
6415
  }
6403
6416
  if (response.changesSummary) {
6404
- log(quiet, chalk11.dim(`
6417
+ log(quiet, chalk12.dim(`
6405
6418
  ${response.changesSummary}`));
6406
6419
  }
6407
6420
  if (currentSha) {
@@ -6414,7 +6427,7 @@ async function refreshCommand(options) {
6414
6427
  const config = loadConfig();
6415
6428
  if (!config) {
6416
6429
  if (quiet) return;
6417
- console.log(chalk11.red("No LLM provider configured. Run ") + chalk11.hex("#83D1EB")("caliber config") + chalk11.red(" (e.g. choose Cursor) or set an API key."));
6430
+ console.log(chalk12.red("No LLM provider configured. Run ") + chalk12.hex("#83D1EB")("caliber config") + chalk12.red(" (e.g. choose Cursor) or set an API key."));
6418
6431
  throw new Error("__exit__");
6419
6432
  }
6420
6433
  if (isGitRepo()) {
@@ -6424,10 +6437,10 @@ async function refreshCommand(options) {
6424
6437
  const repos = discoverGitRepos(process.cwd());
6425
6438
  if (repos.length === 0) {
6426
6439
  if (quiet) return;
6427
- console.log(chalk11.red("Not inside a git repository and no git repos found in child directories."));
6440
+ console.log(chalk12.red("Not inside a git repository and no git repos found in child directories."));
6428
6441
  throw new Error("__exit__");
6429
6442
  }
6430
- log(quiet, chalk11.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
6443
+ log(quiet, chalk12.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
6431
6444
  `));
6432
6445
  const originalDir = process.cwd();
6433
6446
  for (const repo of repos) {
@@ -6437,7 +6450,7 @@ async function refreshCommand(options) {
6437
6450
  await refreshSingleRepo(repo, { ...options, label: repoName });
6438
6451
  } catch (err) {
6439
6452
  if (err instanceof Error && err.message === "__exit__") continue;
6440
- log(quiet, chalk11.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
6453
+ log(quiet, chalk12.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
6441
6454
  }
6442
6455
  }
6443
6456
  process.chdir(originalDir);
@@ -6445,13 +6458,13 @@ async function refreshCommand(options) {
6445
6458
  if (err instanceof Error && err.message === "__exit__") throw err;
6446
6459
  if (quiet) return;
6447
6460
  const msg = err instanceof Error ? err.message : "Unknown error";
6448
- console.log(chalk11.red(`Refresh failed: ${msg}`));
6461
+ console.log(chalk12.red(`Refresh failed: ${msg}`));
6449
6462
  throw new Error("__exit__");
6450
6463
  }
6451
6464
  }
6452
6465
 
6453
6466
  // src/commands/hooks.ts
6454
- import chalk12 from "chalk";
6467
+ import chalk13 from "chalk";
6455
6468
  var HOOKS = [
6456
6469
  {
6457
6470
  id: "session-end",
@@ -6471,13 +6484,13 @@ var HOOKS = [
6471
6484
  }
6472
6485
  ];
6473
6486
  function printStatus() {
6474
- console.log(chalk12.bold("\n Hooks\n"));
6487
+ console.log(chalk13.bold("\n Hooks\n"));
6475
6488
  for (const hook of HOOKS) {
6476
6489
  const installed = hook.isInstalled();
6477
- const icon = installed ? chalk12.green("\u2713") : chalk12.dim("\u2717");
6478
- const state = installed ? chalk12.green("enabled") : chalk12.dim("disabled");
6490
+ const icon = installed ? chalk13.green("\u2713") : chalk13.dim("\u2717");
6491
+ const state = installed ? chalk13.green("enabled") : chalk13.dim("disabled");
6479
6492
  console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
6480
- console.log(chalk12.dim(` ${hook.description}`));
6493
+ console.log(chalk13.dim(` ${hook.description}`));
6481
6494
  }
6482
6495
  console.log("");
6483
6496
  }
@@ -6486,9 +6499,9 @@ async function hooksCommand(options) {
6486
6499
  for (const hook of HOOKS) {
6487
6500
  const result = hook.install();
6488
6501
  if (result.alreadyInstalled) {
6489
- console.log(chalk12.dim(` ${hook.label} already enabled.`));
6502
+ console.log(chalk13.dim(` ${hook.label} already enabled.`));
6490
6503
  } else {
6491
- console.log(chalk12.green(" \u2713") + ` ${hook.label} enabled`);
6504
+ console.log(chalk13.green(" \u2713") + ` ${hook.label} enabled`);
6492
6505
  }
6493
6506
  }
6494
6507
  return;
@@ -6497,9 +6510,9 @@ async function hooksCommand(options) {
6497
6510
  for (const hook of HOOKS) {
6498
6511
  const result = hook.remove();
6499
6512
  if (result.notFound) {
6500
- console.log(chalk12.dim(` ${hook.label} already disabled.`));
6513
+ console.log(chalk13.dim(` ${hook.label} already disabled.`));
6501
6514
  } else {
6502
- console.log(chalk12.green(" \u2713") + ` ${hook.label} removed`);
6515
+ console.log(chalk13.green(" \u2713") + ` ${hook.label} removed`);
6503
6516
  }
6504
6517
  }
6505
6518
  return;
@@ -6514,18 +6527,18 @@ async function hooksCommand(options) {
6514
6527
  const states = HOOKS.map((h) => h.isInstalled());
6515
6528
  function render() {
6516
6529
  const lines = [];
6517
- lines.push(chalk12.bold(" Hooks"));
6530
+ lines.push(chalk13.bold(" Hooks"));
6518
6531
  lines.push("");
6519
6532
  for (let i = 0; i < HOOKS.length; i++) {
6520
6533
  const hook = HOOKS[i];
6521
6534
  const enabled = states[i];
6522
- const toggle = enabled ? chalk12.green("[on] ") : chalk12.dim("[off]");
6523
- const ptr = i === cursor ? chalk12.cyan(">") : " ";
6535
+ const toggle = enabled ? chalk13.green("[on] ") : chalk13.dim("[off]");
6536
+ const ptr = i === cursor ? chalk13.cyan(">") : " ";
6524
6537
  lines.push(` ${ptr} ${toggle} ${hook.label}`);
6525
- lines.push(chalk12.dim(` ${hook.description}`));
6538
+ lines.push(chalk13.dim(` ${hook.description}`));
6526
6539
  }
6527
6540
  lines.push("");
6528
- lines.push(chalk12.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
6541
+ lines.push(chalk13.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
6529
6542
  return lines.join("\n");
6530
6543
  }
6531
6544
  function draw(initial) {
@@ -6556,16 +6569,16 @@ async function hooksCommand(options) {
6556
6569
  const wantEnabled = states[i];
6557
6570
  if (wantEnabled && !wasInstalled) {
6558
6571
  hook.install();
6559
- console.log(chalk12.green(" \u2713") + ` ${hook.label} enabled`);
6572
+ console.log(chalk13.green(" \u2713") + ` ${hook.label} enabled`);
6560
6573
  changed++;
6561
6574
  } else if (!wantEnabled && wasInstalled) {
6562
6575
  hook.remove();
6563
- console.log(chalk12.green(" \u2713") + ` ${hook.label} disabled`);
6576
+ console.log(chalk13.green(" \u2713") + ` ${hook.label} disabled`);
6564
6577
  changed++;
6565
6578
  }
6566
6579
  }
6567
6580
  if (changed === 0) {
6568
- console.log(chalk12.dim(" No changes."));
6581
+ console.log(chalk13.dim(" No changes."));
6569
6582
  }
6570
6583
  console.log("");
6571
6584
  }
@@ -6601,7 +6614,7 @@ async function hooksCommand(options) {
6601
6614
  case "\x1B":
6602
6615
  case "":
6603
6616
  cleanup();
6604
- console.log(chalk12.dim("\n Cancelled.\n"));
6617
+ console.log(chalk13.dim("\n Cancelled.\n"));
6605
6618
  resolve2();
6606
6619
  break;
6607
6620
  }
@@ -6611,48 +6624,48 @@ async function hooksCommand(options) {
6611
6624
  }
6612
6625
 
6613
6626
  // src/commands/config.ts
6614
- import chalk13 from "chalk";
6627
+ import chalk14 from "chalk";
6615
6628
  async function configCommand() {
6616
6629
  const existing = loadConfig();
6617
6630
  if (existing) {
6618
6631
  const displayModel = existing.model === "default" && existing.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : existing.model;
6619
6632
  const fastModel = getFastModel();
6620
- console.log(chalk13.bold("\nCurrent Configuration\n"));
6621
- console.log(` Provider: ${chalk13.cyan(existing.provider)}`);
6622
- console.log(` Model: ${chalk13.cyan(displayModel)}`);
6633
+ console.log(chalk14.bold("\nCurrent Configuration\n"));
6634
+ console.log(` Provider: ${chalk14.cyan(existing.provider)}`);
6635
+ console.log(` Model: ${chalk14.cyan(displayModel)}`);
6623
6636
  if (fastModel) {
6624
- console.log(` Scan: ${chalk13.cyan(fastModel)}`);
6637
+ console.log(` Scan: ${chalk14.cyan(fastModel)}`);
6625
6638
  }
6626
6639
  if (existing.apiKey) {
6627
6640
  const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
6628
- console.log(` API Key: ${chalk13.dim(masked)}`);
6641
+ console.log(` API Key: ${chalk14.dim(masked)}`);
6629
6642
  }
6630
6643
  if (existing.provider === "cursor") {
6631
- console.log(` Seat: ${chalk13.dim("Cursor (agent acp)")}`);
6644
+ console.log(` Seat: ${chalk14.dim("Cursor (agent acp)")}`);
6632
6645
  }
6633
6646
  if (existing.provider === "claude-cli") {
6634
- console.log(` Seat: ${chalk13.dim("Claude Code (claude -p)")}`);
6647
+ console.log(` Seat: ${chalk14.dim("Claude Code (claude -p)")}`);
6635
6648
  }
6636
6649
  if (existing.baseUrl) {
6637
- console.log(` Base URL: ${chalk13.dim(existing.baseUrl)}`);
6650
+ console.log(` Base URL: ${chalk14.dim(existing.baseUrl)}`);
6638
6651
  }
6639
6652
  if (existing.vertexProjectId) {
6640
- console.log(` Vertex Project: ${chalk13.dim(existing.vertexProjectId)}`);
6641
- console.log(` Vertex Region: ${chalk13.dim(existing.vertexRegion || "us-east5")}`);
6653
+ console.log(` Vertex Project: ${chalk14.dim(existing.vertexProjectId)}`);
6654
+ console.log(` Vertex Region: ${chalk14.dim(existing.vertexRegion || "us-east5")}`);
6642
6655
  }
6643
- console.log(` Source: ${chalk13.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID || process.env.CALIBER_USE_CURSOR_SEAT || process.env.CALIBER_USE_CLAUDE_CLI ? "environment variables" : getConfigFilePath())}`);
6656
+ console.log(` Source: ${chalk14.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID || process.env.CALIBER_USE_CURSOR_SEAT || process.env.CALIBER_USE_CLAUDE_CLI ? "environment variables" : getConfigFilePath())}`);
6644
6657
  console.log("");
6645
6658
  }
6646
6659
  await runInteractiveProviderSetup();
6647
- console.log(chalk13.green("\n\u2713 Configuration saved"));
6648
- console.log(chalk13.dim(` ${getConfigFilePath()}
6660
+ console.log(chalk14.green("\n\u2713 Configuration saved"));
6661
+ console.log(chalk14.dim(` ${getConfigFilePath()}
6649
6662
  `));
6650
- console.log(chalk13.dim(" You can also set environment variables instead:"));
6651
- console.log(chalk13.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
6663
+ console.log(chalk14.dim(" You can also set environment variables instead:"));
6664
+ console.log(chalk14.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
6652
6665
  }
6653
6666
 
6654
6667
  // src/commands/learn.ts
6655
- import chalk14 from "chalk";
6668
+ import chalk15 from "chalk";
6656
6669
 
6657
6670
  // src/learner/stdin.ts
6658
6671
  var STDIN_TIMEOUT_MS = 5e3;
@@ -6683,7 +6696,7 @@ function readStdin() {
6683
6696
 
6684
6697
  // src/learner/storage.ts
6685
6698
  init_constants();
6686
- import fs25 from "fs";
6699
+ import fs26 from "fs";
6687
6700
  import path20 from "path";
6688
6701
  var MAX_RESPONSE_LENGTH = 2e3;
6689
6702
  var DEFAULT_STATE = {
@@ -6692,8 +6705,8 @@ var DEFAULT_STATE = {
6692
6705
  lastAnalysisTimestamp: null
6693
6706
  };
6694
6707
  function ensureLearningDir() {
6695
- if (!fs25.existsSync(LEARNING_DIR)) {
6696
- fs25.mkdirSync(LEARNING_DIR, { recursive: true });
6708
+ if (!fs26.existsSync(LEARNING_DIR)) {
6709
+ fs26.mkdirSync(LEARNING_DIR, { recursive: true });
6697
6710
  }
6698
6711
  }
6699
6712
  function sessionFilePath() {
@@ -6711,49 +6724,49 @@ function appendEvent(event) {
6711
6724
  ensureLearningDir();
6712
6725
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
6713
6726
  const filePath = sessionFilePath();
6714
- fs25.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6727
+ fs26.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6715
6728
  const count = getEventCount();
6716
6729
  if (count > LEARNING_MAX_EVENTS) {
6717
- const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6730
+ const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6718
6731
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
6719
- fs25.writeFileSync(filePath, kept.join("\n") + "\n");
6732
+ fs26.writeFileSync(filePath, kept.join("\n") + "\n");
6720
6733
  }
6721
6734
  }
6722
6735
  function readAllEvents() {
6723
6736
  const filePath = sessionFilePath();
6724
- if (!fs25.existsSync(filePath)) return [];
6725
- const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6737
+ if (!fs26.existsSync(filePath)) return [];
6738
+ const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6726
6739
  return lines.map((line) => JSON.parse(line));
6727
6740
  }
6728
6741
  function getEventCount() {
6729
6742
  const filePath = sessionFilePath();
6730
- if (!fs25.existsSync(filePath)) return 0;
6731
- const content = fs25.readFileSync(filePath, "utf-8");
6743
+ if (!fs26.existsSync(filePath)) return 0;
6744
+ const content = fs26.readFileSync(filePath, "utf-8");
6732
6745
  return content.split("\n").filter(Boolean).length;
6733
6746
  }
6734
6747
  function clearSession() {
6735
6748
  const filePath = sessionFilePath();
6736
- if (fs25.existsSync(filePath)) fs25.unlinkSync(filePath);
6749
+ if (fs26.existsSync(filePath)) fs26.unlinkSync(filePath);
6737
6750
  }
6738
6751
  function readState2() {
6739
6752
  const filePath = stateFilePath();
6740
- if (!fs25.existsSync(filePath)) return { ...DEFAULT_STATE };
6753
+ if (!fs26.existsSync(filePath)) return { ...DEFAULT_STATE };
6741
6754
  try {
6742
- return JSON.parse(fs25.readFileSync(filePath, "utf-8"));
6755
+ return JSON.parse(fs26.readFileSync(filePath, "utf-8"));
6743
6756
  } catch {
6744
6757
  return { ...DEFAULT_STATE };
6745
6758
  }
6746
6759
  }
6747
6760
  function writeState2(state) {
6748
6761
  ensureLearningDir();
6749
- fs25.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6762
+ fs26.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6750
6763
  }
6751
6764
  function resetState() {
6752
6765
  writeState2({ ...DEFAULT_STATE });
6753
6766
  }
6754
6767
 
6755
6768
  // src/learner/writer.ts
6756
- import fs26 from "fs";
6769
+ import fs27 from "fs";
6757
6770
  import path21 from "path";
6758
6771
  var LEARNED_START = "<!-- caliber:learned -->";
6759
6772
  var LEARNED_END = "<!-- /caliber:learned -->";
@@ -6774,8 +6787,8 @@ function writeLearnedContent(update) {
6774
6787
  function writeLearnedSection(content) {
6775
6788
  const claudeMdPath = "CLAUDE.md";
6776
6789
  let existing = "";
6777
- if (fs26.existsSync(claudeMdPath)) {
6778
- existing = fs26.readFileSync(claudeMdPath, "utf-8");
6790
+ if (fs27.existsSync(claudeMdPath)) {
6791
+ existing = fs27.readFileSync(claudeMdPath, "utf-8");
6779
6792
  }
6780
6793
  const section = `${LEARNED_START}
6781
6794
  ${content}
@@ -6789,15 +6802,15 @@ ${LEARNED_END}`;
6789
6802
  const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
6790
6803
  updated = existing + separator + "\n" + section + "\n";
6791
6804
  }
6792
- fs26.writeFileSync(claudeMdPath, updated);
6805
+ fs27.writeFileSync(claudeMdPath, updated);
6793
6806
  }
6794
6807
  function writeLearnedSkill(skill) {
6795
6808
  const skillDir = path21.join(".claude", "skills", skill.name);
6796
- if (!fs26.existsSync(skillDir)) fs26.mkdirSync(skillDir, { recursive: true });
6809
+ if (!fs27.existsSync(skillDir)) fs27.mkdirSync(skillDir, { recursive: true });
6797
6810
  const skillPath = path21.join(skillDir, "SKILL.md");
6798
- if (!skill.isNew && fs26.existsSync(skillPath)) {
6799
- const existing = fs26.readFileSync(skillPath, "utf-8");
6800
- fs26.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6811
+ if (!skill.isNew && fs27.existsSync(skillPath)) {
6812
+ const existing = fs27.readFileSync(skillPath, "utf-8");
6813
+ fs27.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6801
6814
  } else {
6802
6815
  const frontmatter = [
6803
6816
  "---",
@@ -6806,14 +6819,14 @@ function writeLearnedSkill(skill) {
6806
6819
  "---",
6807
6820
  ""
6808
6821
  ].join("\n");
6809
- fs26.writeFileSync(skillPath, frontmatter + skill.content);
6822
+ fs27.writeFileSync(skillPath, frontmatter + skill.content);
6810
6823
  }
6811
6824
  return skillPath;
6812
6825
  }
6813
6826
  function readLearnedSection() {
6814
6827
  const claudeMdPath = "CLAUDE.md";
6815
- if (!fs26.existsSync(claudeMdPath)) return null;
6816
- const content = fs26.readFileSync(claudeMdPath, "utf-8");
6828
+ if (!fs27.existsSync(claudeMdPath)) return null;
6829
+ const content = fs27.readFileSync(claudeMdPath, "utf-8");
6817
6830
  const startIdx = content.indexOf(LEARNED_START);
6818
6831
  const endIdx = content.indexOf(LEARNED_END);
6819
6832
  if (startIdx === -1 || endIdx === -1) return null;
@@ -6953,53 +6966,53 @@ async function learnFinalizeCommand() {
6953
6966
  async function learnInstallCommand() {
6954
6967
  const result = installLearningHooks();
6955
6968
  if (result.alreadyInstalled) {
6956
- console.log(chalk14.dim("Learning hooks already installed."));
6969
+ console.log(chalk15.dim("Learning hooks already installed."));
6957
6970
  return;
6958
6971
  }
6959
- console.log(chalk14.green("\u2713") + " Learning hooks installed in .claude/settings.json");
6960
- console.log(chalk14.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
6961
- console.log(chalk14.dim(" Session learnings will be written to CLAUDE.md and skills."));
6972
+ console.log(chalk15.green("\u2713") + " Learning hooks installed in .claude/settings.json");
6973
+ console.log(chalk15.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
6974
+ console.log(chalk15.dim(" Session learnings will be written to CLAUDE.md and skills."));
6962
6975
  }
6963
6976
  async function learnRemoveCommand() {
6964
6977
  const result = removeLearningHooks();
6965
6978
  if (result.notFound) {
6966
- console.log(chalk14.dim("Learning hooks not found."));
6979
+ console.log(chalk15.dim("Learning hooks not found."));
6967
6980
  return;
6968
6981
  }
6969
- console.log(chalk14.green("\u2713") + " Learning hooks removed from .claude/settings.json");
6982
+ console.log(chalk15.green("\u2713") + " Learning hooks removed from .claude/settings.json");
6970
6983
  }
6971
6984
  async function learnStatusCommand() {
6972
6985
  const installed = areLearningHooksInstalled();
6973
6986
  const state = readState2();
6974
6987
  const eventCount = getEventCount();
6975
- console.log(chalk14.bold("Session Learning Status"));
6988
+ console.log(chalk15.bold("Session Learning Status"));
6976
6989
  console.log();
6977
6990
  if (installed) {
6978
- console.log(chalk14.green("\u2713") + " Learning hooks are " + chalk14.green("installed"));
6991
+ console.log(chalk15.green("\u2713") + " Learning hooks are " + chalk15.green("installed"));
6979
6992
  } else {
6980
- console.log(chalk14.dim("\u2717") + " Learning hooks are " + chalk14.yellow("not installed"));
6981
- console.log(chalk14.dim(" Run `caliber learn install` to enable session learning."));
6993
+ console.log(chalk15.dim("\u2717") + " Learning hooks are " + chalk15.yellow("not installed"));
6994
+ console.log(chalk15.dim(" Run `caliber learn install` to enable session learning."));
6982
6995
  }
6983
6996
  console.log();
6984
- console.log(`Events recorded: ${chalk14.cyan(String(eventCount))}`);
6985
- console.log(`Total this session: ${chalk14.cyan(String(state.eventCount))}`);
6997
+ console.log(`Events recorded: ${chalk15.cyan(String(eventCount))}`);
6998
+ console.log(`Total this session: ${chalk15.cyan(String(state.eventCount))}`);
6986
6999
  if (state.lastAnalysisTimestamp) {
6987
- console.log(`Last analysis: ${chalk14.cyan(state.lastAnalysisTimestamp)}`);
7000
+ console.log(`Last analysis: ${chalk15.cyan(state.lastAnalysisTimestamp)}`);
6988
7001
  } else {
6989
- console.log(`Last analysis: ${chalk14.dim("none")}`);
7002
+ console.log(`Last analysis: ${chalk15.dim("none")}`);
6990
7003
  }
6991
7004
  const learnedSection = readLearnedSection();
6992
7005
  if (learnedSection) {
6993
7006
  const lineCount = learnedSection.split("\n").filter(Boolean).length;
6994
7007
  console.log(`
6995
- Learned items in CLAUDE.md: ${chalk14.cyan(String(lineCount))}`);
7008
+ Learned items in CLAUDE.md: ${chalk15.cyan(String(lineCount))}`);
6996
7009
  }
6997
7010
  }
6998
7011
 
6999
7012
  // src/cli.ts
7000
7013
  var __dirname = path22.dirname(fileURLToPath(import.meta.url));
7001
7014
  var pkg = JSON.parse(
7002
- fs27.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
7015
+ fs28.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
7003
7016
  );
7004
7017
  var program = new Command();
7005
7018
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -7032,22 +7045,22 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
7032
7045
  learn.command("status").description("Show learning system status").action(learnStatusCommand);
7033
7046
 
7034
7047
  // src/utils/version-check.ts
7035
- import fs28 from "fs";
7048
+ import fs29 from "fs";
7036
7049
  import path23 from "path";
7037
7050
  import { fileURLToPath as fileURLToPath2 } from "url";
7038
7051
  import { execSync as execSync9 } from "child_process";
7039
- import chalk15 from "chalk";
7052
+ import chalk16 from "chalk";
7040
7053
  import ora7 from "ora";
7041
7054
  import confirm from "@inquirer/confirm";
7042
7055
  var __dirname_vc = path23.dirname(fileURLToPath2(import.meta.url));
7043
7056
  var pkg2 = JSON.parse(
7044
- fs28.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
7057
+ fs29.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
7045
7058
  );
7046
7059
  function getInstalledVersion() {
7047
7060
  try {
7048
7061
  const globalRoot = execSync9("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
7049
7062
  const pkgPath = path23.join(globalRoot, "@rely-ai", "caliber", "package.json");
7050
- return JSON.parse(fs28.readFileSync(pkgPath, "utf-8")).version;
7063
+ return JSON.parse(fs29.readFileSync(pkgPath, "utf-8")).version;
7051
7064
  } catch {
7052
7065
  return null;
7053
7066
  }
@@ -7070,17 +7083,17 @@ async function checkForUpdates() {
7070
7083
  const isInteractive = process.stdin.isTTY === true;
7071
7084
  if (!isInteractive) {
7072
7085
  console.log(
7073
- chalk15.yellow(
7086
+ chalk16.yellow(
7074
7087
  `
7075
7088
  Update available: ${current} -> ${latest}
7076
- Run ${chalk15.bold("npm install -g @rely-ai/caliber")} to upgrade.
7089
+ Run ${chalk16.bold("npm install -g @rely-ai/caliber")} to upgrade.
7077
7090
  `
7078
7091
  )
7079
7092
  );
7080
7093
  return;
7081
7094
  }
7082
7095
  console.log(
7083
- chalk15.yellow(`
7096
+ chalk16.yellow(`
7084
7097
  Update available: ${current} -> ${latest}`)
7085
7098
  );
7086
7099
  const shouldUpdate = await confirm({ message: "Would you like to update now? (Y/n)", default: true });
@@ -7098,13 +7111,13 @@ Update available: ${current} -> ${latest}`)
7098
7111
  const installed = getInstalledVersion();
7099
7112
  if (installed !== latest) {
7100
7113
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
7101
- console.log(chalk15.yellow(`Run ${chalk15.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
7114
+ console.log(chalk16.yellow(`Run ${chalk16.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
7102
7115
  `));
7103
7116
  return;
7104
7117
  }
7105
- spinner.succeed(chalk15.green(`Updated to ${latest}`));
7118
+ spinner.succeed(chalk16.green(`Updated to ${latest}`));
7106
7119
  const args = process.argv.slice(2);
7107
- console.log(chalk15.dim(`
7120
+ console.log(chalk16.dim(`
7108
7121
  Restarting: caliber ${args.join(" ")}
7109
7122
  `));
7110
7123
  execSync9(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
@@ -7117,11 +7130,11 @@ Restarting: caliber ${args.join(" ")}
7117
7130
  if (err instanceof Error) {
7118
7131
  const stderr = err.stderr;
7119
7132
  const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
7120
- if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk15.dim(` ${errMsg}`));
7133
+ if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk16.dim(` ${errMsg}`));
7121
7134
  }
7122
7135
  console.log(
7123
- chalk15.yellow(
7124
- `Run ${chalk15.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
7136
+ chalk16.yellow(
7137
+ `Run ${chalk16.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
7125
7138
  `
7126
7139
  )
7127
7140
  );