@rely-ai/caliber 1.20.0-dev.1773685589 → 1.20.0-dev.1773686430

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 +857 -601
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -177,13 +177,13 @@ __export(lock_exports, {
177
177
  isCaliberRunning: () => isCaliberRunning,
178
178
  releaseLock: () => releaseLock
179
179
  });
180
- import fs28 from "fs";
181
- import path22 from "path";
182
- import os4 from "os";
180
+ import fs29 from "fs";
181
+ import path23 from "path";
182
+ import os5 from "os";
183
183
  function isCaliberRunning() {
184
184
  try {
185
- if (!fs28.existsSync(LOCK_FILE)) return false;
186
- const raw = fs28.readFileSync(LOCK_FILE, "utf-8").trim();
185
+ if (!fs29.existsSync(LOCK_FILE)) return false;
186
+ const raw = fs29.readFileSync(LOCK_FILE, "utf-8").trim();
187
187
  const { pid, ts } = JSON.parse(raw);
188
188
  if (Date.now() - ts > STALE_MS) return false;
189
189
  try {
@@ -198,13 +198,13 @@ function isCaliberRunning() {
198
198
  }
199
199
  function acquireLock() {
200
200
  try {
201
- fs28.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
201
+ fs29.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
202
202
  } catch {
203
203
  }
204
204
  }
205
205
  function releaseLock() {
206
206
  try {
207
- if (fs28.existsSync(LOCK_FILE)) fs28.unlinkSync(LOCK_FILE);
207
+ if (fs29.existsSync(LOCK_FILE)) fs29.unlinkSync(LOCK_FILE);
208
208
  } catch {
209
209
  }
210
210
  }
@@ -212,24 +212,24 @@ var LOCK_FILE, STALE_MS;
212
212
  var init_lock = __esm({
213
213
  "src/lib/lock.ts"() {
214
214
  "use strict";
215
- LOCK_FILE = path22.join(os4.tmpdir(), ".caliber.lock");
215
+ LOCK_FILE = path23.join(os5.tmpdir(), ".caliber.lock");
216
216
  STALE_MS = 10 * 60 * 1e3;
217
217
  }
218
218
  });
219
219
 
220
220
  // src/cli.ts
221
221
  import { Command } from "commander";
222
- import fs32 from "fs";
223
- import path25 from "path";
222
+ import fs33 from "fs";
223
+ import path26 from "path";
224
224
  import { fileURLToPath } from "url";
225
225
 
226
226
  // src/commands/init.ts
227
- import path19 from "path";
228
- import chalk9 from "chalk";
227
+ import path20 from "path";
228
+ import chalk10 from "chalk";
229
229
  import ora2 from "ora";
230
230
  import select5 from "@inquirer/select";
231
231
  import checkbox from "@inquirer/checkbox";
232
- import fs24 from "fs";
232
+ import fs25 from "fs";
233
233
 
234
234
  // src/fingerprint/index.ts
235
235
  import fs6 from "fs";
@@ -2262,15 +2262,15 @@ init_config();
2262
2262
  // src/utils/dependencies.ts
2263
2263
  import { readFileSync } from "fs";
2264
2264
  import { join } from "path";
2265
- function readFileOrNull(path27) {
2265
+ function readFileOrNull(path28) {
2266
2266
  try {
2267
- return readFileSync(path27, "utf-8");
2267
+ return readFileSync(path28, "utf-8");
2268
2268
  } catch {
2269
2269
  return null;
2270
2270
  }
2271
2271
  }
2272
- function readJsonOrNull(path27) {
2273
- const content = readFileOrNull(path27);
2272
+ function readJsonOrNull(path28) {
2273
+ const content = readFileOrNull(path28);
2274
2274
  if (!content) return null;
2275
2275
  try {
2276
2276
  return JSON.parse(content);
@@ -2686,6 +2686,37 @@ async function generateMonolithic(fingerprint, targetAgent, prompt, callbacks, f
2686
2686
  };
2687
2687
  return attemptGeneration();
2688
2688
  }
2689
+ async function generateSkillsForSetup(setup, fingerprint, targetAgent, onStatus) {
2690
+ const skillTopics = collectSkillTopics(setup, targetAgent, fingerprint);
2691
+ if (skillTopics.length === 0) return 0;
2692
+ onStatus?.(`Generating ${skillTopics.length} skills...`);
2693
+ const allDeps = extractAllDeps(process.cwd());
2694
+ const skillContext = buildSkillContext(fingerprint, setup, allDeps);
2695
+ const fastModel = getFastModel();
2696
+ const skillResults = await Promise.allSettled(
2697
+ skillTopics.map(
2698
+ ({ platform, topic }) => generateSkill(skillContext, topic, fastModel).then((skill) => ({ platform, skill }))
2699
+ )
2700
+ );
2701
+ for (const result of skillResults) {
2702
+ if (result.status === "fulfilled") {
2703
+ const { platform, skill } = result.value;
2704
+ const platformObj = setup[platform] ?? {};
2705
+ const skills = platformObj.skills ?? [];
2706
+ skills.push(skill);
2707
+ platformObj.skills = skills;
2708
+ setup[platform] = platformObj;
2709
+ const skillPath = platform === "codex" ? `.agents/skills/${skill.name}/SKILL.md` : `.${platform}/skills/${skill.name}/SKILL.md`;
2710
+ const descriptions = setup.fileDescriptions ?? {};
2711
+ descriptions[skillPath] = skill.description.slice(0, 80);
2712
+ setup.fileDescriptions = descriptions;
2713
+ }
2714
+ }
2715
+ const succeeded = skillResults.filter((r) => r.status === "fulfilled").length;
2716
+ const failed = skillResults.filter((r) => r.status === "rejected").length;
2717
+ if (failed > 0) onStatus?.(`${succeeded} generated, ${failed} failed`);
2718
+ return succeeded;
2719
+ }
2689
2720
  var LIMITS = {
2690
2721
  FILE_TREE_ENTRIES: 500,
2691
2722
  EXISTING_CONFIG_CHARS: 8e3,
@@ -3205,13 +3236,23 @@ function cleanupStaging() {
3205
3236
 
3206
3237
  // src/utils/review.ts
3207
3238
  import chalk2 from "chalk";
3208
- import fs14 from "fs";
3239
+ import fs15 from "fs";
3209
3240
  import select2 from "@inquirer/select";
3210
3241
  import { createTwoFilesPatch } from "diff";
3211
3242
 
3212
3243
  // src/utils/editor.ts
3213
3244
  import { execSync as execSync5, spawn as spawn3 } from "child_process";
3245
+ import fs14 from "fs";
3246
+ import path12 from "path";
3247
+ import os3 from "os";
3214
3248
  var IS_WINDOWS3 = process.platform === "win32";
3249
+ var DIFF_TEMP_DIR = path12.join(os3.tmpdir(), "caliber-diff");
3250
+ function getEmptyFilePath(proposedPath) {
3251
+ fs14.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
3252
+ const tempPath = path12.join(DIFF_TEMP_DIR, path12.basename(proposedPath));
3253
+ fs14.writeFileSync(tempPath, "");
3254
+ return tempPath;
3255
+ }
3215
3256
  function commandExists(cmd) {
3216
3257
  try {
3217
3258
  const check = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
@@ -3232,13 +3273,12 @@ function openDiffsInEditor(editor, files) {
3232
3273
  const cmd = editor === "cursor" ? "cursor" : "code";
3233
3274
  for (const file of files) {
3234
3275
  try {
3276
+ const leftPath = file.originalPath ?? getEmptyFilePath(file.proposedPath);
3235
3277
  if (IS_WINDOWS3) {
3236
3278
  const quote = (s) => `"${s}"`;
3237
- const parts = file.originalPath ? [cmd, "--diff", quote(file.originalPath), quote(file.proposedPath)] : [cmd, quote(file.proposedPath)];
3238
- spawn3(parts.join(" "), { shell: true, stdio: "ignore", detached: true }).unref();
3279
+ spawn3([cmd, "--diff", quote(leftPath), quote(file.proposedPath)].join(" "), { shell: true, stdio: "ignore", detached: true }).unref();
3239
3280
  } else {
3240
- const args = file.originalPath ? ["--diff", file.originalPath, file.proposedPath] : [file.proposedPath];
3241
- spawn3(cmd, args, { stdio: "ignore", detached: true }).unref();
3281
+ spawn3(cmd, ["--diff", leftPath, file.proposedPath], { stdio: "ignore", detached: true }).unref();
3242
3282
  }
3243
3283
  } catch {
3244
3284
  continue;
@@ -3281,8 +3321,8 @@ async function openReview(method, stagedFiles) {
3281
3321
  return;
3282
3322
  }
3283
3323
  const fileInfos = stagedFiles.map((file) => {
3284
- const proposed = fs14.readFileSync(file.proposedPath, "utf-8");
3285
- const current = file.currentPath ? fs14.readFileSync(file.currentPath, "utf-8") : "";
3324
+ const proposed = fs15.readFileSync(file.proposedPath, "utf-8");
3325
+ const current = file.currentPath ? fs15.readFileSync(file.currentPath, "utf-8") : "";
3286
3326
  const patch = createTwoFilesPatch(
3287
3327
  file.isNew ? "/dev/null" : file.relativePath,
3288
3328
  file.relativePath,
@@ -3445,7 +3485,7 @@ async function interactiveDiffExplorer(files) {
3445
3485
  }
3446
3486
 
3447
3487
  // src/commands/setup-files.ts
3448
- import fs15 from "fs";
3488
+ import fs16 from "fs";
3449
3489
  function buildSkillContent(skill) {
3450
3490
  const frontmatter = `---
3451
3491
  name: ${skill.name}
@@ -3494,7 +3534,7 @@ function collectSetupFiles(setup, targetAgent) {
3494
3534
  }
3495
3535
  }
3496
3536
  const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
3497
- if (codexTargeted && !fs15.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
3537
+ if (codexTargeted && !fs16.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
3498
3538
  const agentRefs = [];
3499
3539
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
3500
3540
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
@@ -3511,12 +3551,12 @@ ${agentRefs.join(" ")}
3511
3551
  }
3512
3552
 
3513
3553
  // src/lib/hooks.ts
3514
- import fs17 from "fs";
3515
- import path12 from "path";
3554
+ import fs18 from "fs";
3555
+ import path13 from "path";
3516
3556
  import { execSync as execSync7 } from "child_process";
3517
3557
 
3518
3558
  // src/lib/resolve-caliber.ts
3519
- import fs16 from "fs";
3559
+ import fs17 from "fs";
3520
3560
  import { execSync as execSync6 } from "child_process";
3521
3561
  var _resolved = null;
3522
3562
  function resolveCaliber() {
@@ -3539,7 +3579,7 @@ function resolveCaliber() {
3539
3579
  } catch {
3540
3580
  }
3541
3581
  const binPath = process.argv[1];
3542
- if (binPath && fs16.existsSync(binPath)) {
3582
+ if (binPath && fs17.existsSync(binPath)) {
3543
3583
  _resolved = binPath;
3544
3584
  return _resolved;
3545
3585
  }
@@ -3555,24 +3595,24 @@ function isCaliberCommand(command, subcommandTail) {
3555
3595
  }
3556
3596
 
3557
3597
  // src/lib/hooks.ts
3558
- var SETTINGS_PATH = path12.join(".claude", "settings.json");
3598
+ var SETTINGS_PATH = path13.join(".claude", "settings.json");
3559
3599
  var REFRESH_TAIL = "refresh --quiet";
3560
3600
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
3561
3601
  function getHookCommand() {
3562
3602
  return `${resolveCaliber()} ${REFRESH_TAIL}`;
3563
3603
  }
3564
3604
  function readSettings() {
3565
- if (!fs17.existsSync(SETTINGS_PATH)) return {};
3605
+ if (!fs18.existsSync(SETTINGS_PATH)) return {};
3566
3606
  try {
3567
- return JSON.parse(fs17.readFileSync(SETTINGS_PATH, "utf-8"));
3607
+ return JSON.parse(fs18.readFileSync(SETTINGS_PATH, "utf-8"));
3568
3608
  } catch {
3569
3609
  return {};
3570
3610
  }
3571
3611
  }
3572
3612
  function writeSettings(settings) {
3573
- const dir = path12.dirname(SETTINGS_PATH);
3574
- if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
3575
- fs17.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
3613
+ const dir = path13.dirname(SETTINGS_PATH);
3614
+ if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
3615
+ fs18.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
3576
3616
  }
3577
3617
  function findHookIndex(sessionEnd) {
3578
3618
  return sessionEnd.findIndex(
@@ -3635,19 +3675,19 @@ ${PRECOMMIT_END}`;
3635
3675
  function getGitHooksDir() {
3636
3676
  try {
3637
3677
  const gitDir = execSync7("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3638
- return path12.join(gitDir, "hooks");
3678
+ return path13.join(gitDir, "hooks");
3639
3679
  } catch {
3640
3680
  return null;
3641
3681
  }
3642
3682
  }
3643
3683
  function getPreCommitPath() {
3644
3684
  const hooksDir = getGitHooksDir();
3645
- return hooksDir ? path12.join(hooksDir, "pre-commit") : null;
3685
+ return hooksDir ? path13.join(hooksDir, "pre-commit") : null;
3646
3686
  }
3647
3687
  function isPreCommitHookInstalled() {
3648
3688
  const hookPath = getPreCommitPath();
3649
- if (!hookPath || !fs17.existsSync(hookPath)) return false;
3650
- const content = fs17.readFileSync(hookPath, "utf-8");
3689
+ if (!hookPath || !fs18.existsSync(hookPath)) return false;
3690
+ const content = fs18.readFileSync(hookPath, "utf-8");
3651
3691
  return content.includes(PRECOMMIT_START);
3652
3692
  }
3653
3693
  function installPreCommitHook() {
@@ -3656,43 +3696,43 @@ function installPreCommitHook() {
3656
3696
  }
3657
3697
  const hookPath = getPreCommitPath();
3658
3698
  if (!hookPath) return { installed: false, alreadyInstalled: false };
3659
- const hooksDir = path12.dirname(hookPath);
3660
- if (!fs17.existsSync(hooksDir)) fs17.mkdirSync(hooksDir, { recursive: true });
3699
+ const hooksDir = path13.dirname(hookPath);
3700
+ if (!fs18.existsSync(hooksDir)) fs18.mkdirSync(hooksDir, { recursive: true });
3661
3701
  let content = "";
3662
- if (fs17.existsSync(hookPath)) {
3663
- content = fs17.readFileSync(hookPath, "utf-8");
3702
+ if (fs18.existsSync(hookPath)) {
3703
+ content = fs18.readFileSync(hookPath, "utf-8");
3664
3704
  if (!content.endsWith("\n")) content += "\n";
3665
3705
  content += "\n" + getPrecommitBlock() + "\n";
3666
3706
  } else {
3667
3707
  content = "#!/bin/sh\n\n" + getPrecommitBlock() + "\n";
3668
3708
  }
3669
- fs17.writeFileSync(hookPath, content);
3670
- fs17.chmodSync(hookPath, 493);
3709
+ fs18.writeFileSync(hookPath, content);
3710
+ fs18.chmodSync(hookPath, 493);
3671
3711
  return { installed: true, alreadyInstalled: false };
3672
3712
  }
3673
3713
  function removePreCommitHook() {
3674
3714
  const hookPath = getPreCommitPath();
3675
- if (!hookPath || !fs17.existsSync(hookPath)) {
3715
+ if (!hookPath || !fs18.existsSync(hookPath)) {
3676
3716
  return { removed: false, notFound: true };
3677
3717
  }
3678
- let content = fs17.readFileSync(hookPath, "utf-8");
3718
+ let content = fs18.readFileSync(hookPath, "utf-8");
3679
3719
  if (!content.includes(PRECOMMIT_START)) {
3680
3720
  return { removed: false, notFound: true };
3681
3721
  }
3682
- const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
3683
- content = content.replace(regex, "\n");
3722
+ const regex2 = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
3723
+ content = content.replace(regex2, "\n");
3684
3724
  if (content.trim() === "#!/bin/sh" || content.trim() === "") {
3685
- fs17.unlinkSync(hookPath);
3725
+ fs18.unlinkSync(hookPath);
3686
3726
  } else {
3687
- fs17.writeFileSync(hookPath, content);
3727
+ fs18.writeFileSync(hookPath, content);
3688
3728
  }
3689
3729
  return { removed: true, notFound: false };
3690
3730
  }
3691
3731
 
3692
3732
  // src/lib/learning-hooks.ts
3693
- import fs18 from "fs";
3694
- import path13 from "path";
3695
- var SETTINGS_PATH2 = path13.join(".claude", "settings.json");
3733
+ import fs19 from "fs";
3734
+ import path14 from "path";
3735
+ var SETTINGS_PATH2 = path14.join(".claude", "settings.json");
3696
3736
  var HOOK_TAILS = [
3697
3737
  { event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
3698
3738
  { event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
@@ -3709,17 +3749,17 @@ function getHookConfigs() {
3709
3749
  }));
3710
3750
  }
3711
3751
  function readSettings2() {
3712
- if (!fs18.existsSync(SETTINGS_PATH2)) return {};
3752
+ if (!fs19.existsSync(SETTINGS_PATH2)) return {};
3713
3753
  try {
3714
- return JSON.parse(fs18.readFileSync(SETTINGS_PATH2, "utf-8"));
3754
+ return JSON.parse(fs19.readFileSync(SETTINGS_PATH2, "utf-8"));
3715
3755
  } catch {
3716
3756
  return {};
3717
3757
  }
3718
3758
  }
3719
3759
  function writeSettings2(settings) {
3720
- const dir = path13.dirname(SETTINGS_PATH2);
3721
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
3722
- fs18.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
3760
+ const dir = path14.dirname(SETTINGS_PATH2);
3761
+ if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
3762
+ fs19.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
3723
3763
  }
3724
3764
  function hasLearningHook(matchers, tail) {
3725
3765
  return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
@@ -3753,7 +3793,7 @@ function installLearningHooks() {
3753
3793
  writeSettings2(settings);
3754
3794
  return { installed: true, alreadyInstalled: false };
3755
3795
  }
3756
- var CURSOR_HOOKS_PATH = path13.join(".cursor", "hooks.json");
3796
+ var CURSOR_HOOKS_PATH = path14.join(".cursor", "hooks.json");
3757
3797
  var CURSOR_HOOK_EVENTS = [
3758
3798
  { event: "postToolUse", tail: "learn observe" },
3759
3799
  { event: "postToolUseFailure", tail: "learn observe --failure" },
@@ -3761,17 +3801,17 @@ var CURSOR_HOOK_EVENTS = [
3761
3801
  { event: "sessionEnd", tail: "learn finalize" }
3762
3802
  ];
3763
3803
  function readCursorHooks() {
3764
- if (!fs18.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
3804
+ if (!fs19.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
3765
3805
  try {
3766
- return JSON.parse(fs18.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
3806
+ return JSON.parse(fs19.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
3767
3807
  } catch {
3768
3808
  return { version: 1, hooks: {} };
3769
3809
  }
3770
3810
  }
3771
3811
  function writeCursorHooks(config) {
3772
- const dir = path13.dirname(CURSOR_HOOKS_PATH);
3773
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
3774
- fs18.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
3812
+ const dir = path14.dirname(CURSOR_HOOKS_PATH);
3813
+ if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
3814
+ fs19.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
3775
3815
  }
3776
3816
  function hasCursorHook(entries, tail) {
3777
3817
  return entries.some((e) => isCaliberCommand(e.command, tail));
@@ -3841,10 +3881,10 @@ function removeLearningHooks() {
3841
3881
 
3842
3882
  // src/lib/state.ts
3843
3883
  init_constants();
3844
- import fs19 from "fs";
3845
- import path14 from "path";
3884
+ import fs20 from "fs";
3885
+ import path15 from "path";
3846
3886
  import { execSync as execSync8 } from "child_process";
3847
- var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
3887
+ var STATE_FILE = path15.join(CALIBER_DIR, ".caliber-state.json");
3848
3888
  function normalizeTargetAgent(value) {
3849
3889
  if (Array.isArray(value)) return value;
3850
3890
  if (typeof value === "string") {
@@ -3855,8 +3895,8 @@ function normalizeTargetAgent(value) {
3855
3895
  }
3856
3896
  function readState() {
3857
3897
  try {
3858
- if (!fs19.existsSync(STATE_FILE)) return null;
3859
- const raw = JSON.parse(fs19.readFileSync(STATE_FILE, "utf-8"));
3898
+ if (!fs20.existsSync(STATE_FILE)) return null;
3899
+ const raw = JSON.parse(fs20.readFileSync(STATE_FILE, "utf-8"));
3860
3900
  if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
3861
3901
  return raw;
3862
3902
  } catch {
@@ -3864,10 +3904,10 @@ function readState() {
3864
3904
  }
3865
3905
  }
3866
3906
  function writeState(state) {
3867
- if (!fs19.existsSync(CALIBER_DIR)) {
3868
- fs19.mkdirSync(CALIBER_DIR, { recursive: true });
3907
+ if (!fs20.existsSync(CALIBER_DIR)) {
3908
+ fs20.mkdirSync(CALIBER_DIR, { recursive: true });
3869
3909
  }
3870
- fs19.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
3910
+ fs20.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
3871
3911
  }
3872
3912
  function getCurrentHeadSha() {
3873
3913
  try {
@@ -5224,22 +5264,22 @@ function checkBonus(dir) {
5224
5264
 
5225
5265
  // src/scoring/dismissed.ts
5226
5266
  init_constants();
5227
- import fs20 from "fs";
5228
- import path15 from "path";
5229
- var DISMISSED_FILE = path15.join(CALIBER_DIR, "dismissed-checks.json");
5267
+ import fs21 from "fs";
5268
+ import path16 from "path";
5269
+ var DISMISSED_FILE = path16.join(CALIBER_DIR, "dismissed-checks.json");
5230
5270
  function readDismissedChecks() {
5231
5271
  try {
5232
- if (!fs20.existsSync(DISMISSED_FILE)) return [];
5233
- return JSON.parse(fs20.readFileSync(DISMISSED_FILE, "utf-8"));
5272
+ if (!fs21.existsSync(DISMISSED_FILE)) return [];
5273
+ return JSON.parse(fs21.readFileSync(DISMISSED_FILE, "utf-8"));
5234
5274
  } catch {
5235
5275
  return [];
5236
5276
  }
5237
5277
  }
5238
5278
  function writeDismissedChecks(checks) {
5239
- if (!fs20.existsSync(CALIBER_DIR)) {
5240
- fs20.mkdirSync(CALIBER_DIR, { recursive: true });
5279
+ if (!fs21.existsSync(CALIBER_DIR)) {
5280
+ fs21.mkdirSync(CALIBER_DIR, { recursive: true });
5241
5281
  }
5242
- fs20.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
5282
+ fs21.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
5243
5283
  }
5244
5284
  function getDismissedIds() {
5245
5285
  return new Set(readDismissedChecks().map((c) => c.id));
@@ -5435,13 +5475,13 @@ import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4,
5435
5475
  import { join as join9, dirname as dirname2 } from "path";
5436
5476
 
5437
5477
  // src/scanner/index.ts
5438
- import fs21 from "fs";
5439
- import path16 from "path";
5478
+ import fs22 from "fs";
5479
+ import path17 from "path";
5440
5480
  import crypto2 from "crypto";
5441
5481
  function scanLocalState(dir) {
5442
5482
  const items = [];
5443
- const claudeMdPath = path16.join(dir, "CLAUDE.md");
5444
- if (fs21.existsSync(claudeMdPath)) {
5483
+ const claudeMdPath = path17.join(dir, "CLAUDE.md");
5484
+ if (fs22.existsSync(claudeMdPath)) {
5445
5485
  items.push({
5446
5486
  type: "rule",
5447
5487
  platform: "claude",
@@ -5450,10 +5490,10 @@ function scanLocalState(dir) {
5450
5490
  path: claudeMdPath
5451
5491
  });
5452
5492
  }
5453
- const skillsDir = path16.join(dir, ".claude", "skills");
5454
- if (fs21.existsSync(skillsDir)) {
5455
- for (const file of fs21.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5456
- const filePath = path16.join(skillsDir, file);
5493
+ const skillsDir = path17.join(dir, ".claude", "skills");
5494
+ if (fs22.existsSync(skillsDir)) {
5495
+ for (const file of fs22.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5496
+ const filePath = path17.join(skillsDir, file);
5457
5497
  items.push({
5458
5498
  type: "skill",
5459
5499
  platform: "claude",
@@ -5463,10 +5503,10 @@ function scanLocalState(dir) {
5463
5503
  });
5464
5504
  }
5465
5505
  }
5466
- const mcpJsonPath = path16.join(dir, ".mcp.json");
5467
- if (fs21.existsSync(mcpJsonPath)) {
5506
+ const mcpJsonPath = path17.join(dir, ".mcp.json");
5507
+ if (fs22.existsSync(mcpJsonPath)) {
5468
5508
  try {
5469
- const mcpJson = JSON.parse(fs21.readFileSync(mcpJsonPath, "utf-8"));
5509
+ const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
5470
5510
  if (mcpJson.mcpServers) {
5471
5511
  for (const name of Object.keys(mcpJson.mcpServers)) {
5472
5512
  items.push({
@@ -5481,8 +5521,8 @@ function scanLocalState(dir) {
5481
5521
  } catch {
5482
5522
  }
5483
5523
  }
5484
- const agentsMdPath = path16.join(dir, "AGENTS.md");
5485
- if (fs21.existsSync(agentsMdPath)) {
5524
+ const agentsMdPath = path17.join(dir, "AGENTS.md");
5525
+ if (fs22.existsSync(agentsMdPath)) {
5486
5526
  items.push({
5487
5527
  type: "rule",
5488
5528
  platform: "codex",
@@ -5491,12 +5531,12 @@ function scanLocalState(dir) {
5491
5531
  path: agentsMdPath
5492
5532
  });
5493
5533
  }
5494
- const codexSkillsDir = path16.join(dir, ".agents", "skills");
5495
- if (fs21.existsSync(codexSkillsDir)) {
5534
+ const codexSkillsDir = path17.join(dir, ".agents", "skills");
5535
+ if (fs22.existsSync(codexSkillsDir)) {
5496
5536
  try {
5497
- for (const name of fs21.readdirSync(codexSkillsDir)) {
5498
- const skillFile = path16.join(codexSkillsDir, name, "SKILL.md");
5499
- if (fs21.existsSync(skillFile)) {
5537
+ for (const name of fs22.readdirSync(codexSkillsDir)) {
5538
+ const skillFile = path17.join(codexSkillsDir, name, "SKILL.md");
5539
+ if (fs22.existsSync(skillFile)) {
5500
5540
  items.push({
5501
5541
  type: "skill",
5502
5542
  platform: "codex",
@@ -5509,8 +5549,8 @@ function scanLocalState(dir) {
5509
5549
  } catch {
5510
5550
  }
5511
5551
  }
5512
- const cursorrulesPath = path16.join(dir, ".cursorrules");
5513
- if (fs21.existsSync(cursorrulesPath)) {
5552
+ const cursorrulesPath = path17.join(dir, ".cursorrules");
5553
+ if (fs22.existsSync(cursorrulesPath)) {
5514
5554
  items.push({
5515
5555
  type: "rule",
5516
5556
  platform: "cursor",
@@ -5519,10 +5559,10 @@ function scanLocalState(dir) {
5519
5559
  path: cursorrulesPath
5520
5560
  });
5521
5561
  }
5522
- const cursorRulesDir = path16.join(dir, ".cursor", "rules");
5523
- if (fs21.existsSync(cursorRulesDir)) {
5524
- for (const file of fs21.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5525
- const filePath = path16.join(cursorRulesDir, file);
5562
+ const cursorRulesDir = path17.join(dir, ".cursor", "rules");
5563
+ if (fs22.existsSync(cursorRulesDir)) {
5564
+ for (const file of fs22.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5565
+ const filePath = path17.join(cursorRulesDir, file);
5526
5566
  items.push({
5527
5567
  type: "rule",
5528
5568
  platform: "cursor",
@@ -5532,12 +5572,12 @@ function scanLocalState(dir) {
5532
5572
  });
5533
5573
  }
5534
5574
  }
5535
- const cursorSkillsDir = path16.join(dir, ".cursor", "skills");
5536
- if (fs21.existsSync(cursorSkillsDir)) {
5575
+ const cursorSkillsDir = path17.join(dir, ".cursor", "skills");
5576
+ if (fs22.existsSync(cursorSkillsDir)) {
5537
5577
  try {
5538
- for (const name of fs21.readdirSync(cursorSkillsDir)) {
5539
- const skillFile = path16.join(cursorSkillsDir, name, "SKILL.md");
5540
- if (fs21.existsSync(skillFile)) {
5578
+ for (const name of fs22.readdirSync(cursorSkillsDir)) {
5579
+ const skillFile = path17.join(cursorSkillsDir, name, "SKILL.md");
5580
+ if (fs22.existsSync(skillFile)) {
5541
5581
  items.push({
5542
5582
  type: "skill",
5543
5583
  platform: "cursor",
@@ -5550,10 +5590,10 @@ function scanLocalState(dir) {
5550
5590
  } catch {
5551
5591
  }
5552
5592
  }
5553
- const cursorMcpPath = path16.join(dir, ".cursor", "mcp.json");
5554
- if (fs21.existsSync(cursorMcpPath)) {
5593
+ const cursorMcpPath = path17.join(dir, ".cursor", "mcp.json");
5594
+ if (fs22.existsSync(cursorMcpPath)) {
5555
5595
  try {
5556
- const mcpJson = JSON.parse(fs21.readFileSync(cursorMcpPath, "utf-8"));
5596
+ const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
5557
5597
  if (mcpJson.mcpServers) {
5558
5598
  for (const name of Object.keys(mcpJson.mcpServers)) {
5559
5599
  items.push({
@@ -5571,7 +5611,7 @@ function scanLocalState(dir) {
5571
5611
  return items;
5572
5612
  }
5573
5613
  function hashFile(filePath) {
5574
- const text = fs21.readFileSync(filePath, "utf-8");
5614
+ const text = fs22.readFileSync(filePath, "utf-8");
5575
5615
  return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
5576
5616
  }
5577
5617
  function hashJson(obj) {
@@ -5586,27 +5626,27 @@ import { PostHog } from "posthog-node";
5586
5626
  import chalk7 from "chalk";
5587
5627
 
5588
5628
  // src/telemetry/config.ts
5589
- import fs22 from "fs";
5590
- import path17 from "path";
5591
- import os3 from "os";
5629
+ import fs23 from "fs";
5630
+ import path18 from "path";
5631
+ import os4 from "os";
5592
5632
  import crypto3 from "crypto";
5593
5633
  import { execSync as execSync12 } from "child_process";
5594
- var CONFIG_DIR2 = path17.join(os3.homedir(), ".caliber");
5595
- var CONFIG_FILE2 = path17.join(CONFIG_DIR2, "config.json");
5634
+ var CONFIG_DIR2 = path18.join(os4.homedir(), ".caliber");
5635
+ var CONFIG_FILE2 = path18.join(CONFIG_DIR2, "config.json");
5596
5636
  var runtimeDisabled = false;
5597
5637
  function readConfig() {
5598
5638
  try {
5599
- if (!fs22.existsSync(CONFIG_FILE2)) return {};
5600
- return JSON.parse(fs22.readFileSync(CONFIG_FILE2, "utf-8"));
5639
+ if (!fs23.existsSync(CONFIG_FILE2)) return {};
5640
+ return JSON.parse(fs23.readFileSync(CONFIG_FILE2, "utf-8"));
5601
5641
  } catch {
5602
5642
  return {};
5603
5643
  }
5604
5644
  }
5605
5645
  function writeConfig(config) {
5606
- if (!fs22.existsSync(CONFIG_DIR2)) {
5607
- fs22.mkdirSync(CONFIG_DIR2, { recursive: true });
5646
+ if (!fs23.existsSync(CONFIG_DIR2)) {
5647
+ fs23.mkdirSync(CONFIG_DIR2, { recursive: true });
5608
5648
  }
5609
- fs22.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
5649
+ fs23.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
5610
5650
  }
5611
5651
  function getMachineId() {
5612
5652
  const config = readConfig();
@@ -6007,6 +6047,51 @@ function extractTopDeps() {
6007
6047
  return [];
6008
6048
  }
6009
6049
  }
6050
+ async function searchSkills(fingerprint, targetPlatforms, onStatus) {
6051
+ const installedSkills = getInstalledSkills(targetPlatforms);
6052
+ const technologies = [...new Set([
6053
+ ...fingerprint.languages,
6054
+ ...fingerprint.frameworks,
6055
+ ...extractTopDeps()
6056
+ ].filter(Boolean))];
6057
+ if (technologies.length === 0) {
6058
+ return { results: [], contentMap: /* @__PURE__ */ new Map() };
6059
+ }
6060
+ const primaryPlatform = targetPlatforms.includes("claude") ? "claude" : targetPlatforms[0];
6061
+ onStatus?.("Searching skill registries...");
6062
+ const allCandidates = await searchAllProviders(technologies, primaryPlatform);
6063
+ if (!allCandidates.length) {
6064
+ return { results: [], contentMap: /* @__PURE__ */ new Map() };
6065
+ }
6066
+ const newCandidates = allCandidates.filter((c) => !installedSkills.has(c.slug.toLowerCase()));
6067
+ if (!newCandidates.length) {
6068
+ return { results: [], contentMap: /* @__PURE__ */ new Map() };
6069
+ }
6070
+ onStatus?.(`Scoring ${newCandidates.length} candidates...`);
6071
+ let results;
6072
+ const config = loadConfig();
6073
+ if (config) {
6074
+ try {
6075
+ const projectContext = buildProjectContext(fingerprint, targetPlatforms);
6076
+ results = await scoreWithLLM(newCandidates, projectContext, technologies);
6077
+ } catch {
6078
+ results = newCandidates.slice(0, 20);
6079
+ }
6080
+ } else {
6081
+ results = newCandidates.slice(0, 20);
6082
+ }
6083
+ if (results.length === 0) {
6084
+ return { results: [], contentMap: /* @__PURE__ */ new Map() };
6085
+ }
6086
+ onStatus?.("Fetching skill content...");
6087
+ const contentMap = /* @__PURE__ */ new Map();
6088
+ await Promise.all(results.map(async (rec) => {
6089
+ const content = await fetchSkillContent(rec);
6090
+ if (content) contentMap.set(rec.slug, content);
6091
+ }));
6092
+ const available = results.filter((r) => contentMap.has(r.slug));
6093
+ return { results: available, contentMap };
6094
+ }
6010
6095
  async function recommendCommand() {
6011
6096
  const proceed = await select4({
6012
6097
  message: "Search public repos for relevant skills to add to this project?",
@@ -6285,8 +6370,8 @@ function printSkills(recs) {
6285
6370
  }
6286
6371
 
6287
6372
  // src/lib/debug-report.ts
6288
- import fs23 from "fs";
6289
- import path18 from "path";
6373
+ import fs24 from "fs";
6374
+ import path19 from "path";
6290
6375
  var DebugReport = class {
6291
6376
  sections = [];
6292
6377
  startTime;
@@ -6355,11 +6440,11 @@ var DebugReport = class {
6355
6440
  lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
6356
6441
  lines.push("");
6357
6442
  }
6358
- const dir = path18.dirname(outputPath);
6359
- if (!fs23.existsSync(dir)) {
6360
- fs23.mkdirSync(dir, { recursive: true });
6443
+ const dir = path19.dirname(outputPath);
6444
+ if (!fs24.existsSync(dir)) {
6445
+ fs24.mkdirSync(dir, { recursive: true });
6361
6446
  }
6362
- fs23.writeFileSync(outputPath, lines.join("\n"));
6447
+ fs24.writeFileSync(outputPath, lines.join("\n"));
6363
6448
  }
6364
6449
  };
6365
6450
  function formatMs(ms) {
@@ -6371,13 +6456,144 @@ function formatMs(ms) {
6371
6456
  return `${secs}s`;
6372
6457
  }
6373
6458
 
6459
+ // src/utils/parallel-tasks.ts
6460
+ import chalk9 from "chalk";
6461
+
6462
+ // node_modules/ansi-regex/index.js
6463
+ function ansiRegex({ onlyFirst = false } = {}) {
6464
+ const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
6465
+ const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`;
6466
+ const csi = "[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]";
6467
+ const pattern = `${osc}|${csi}`;
6468
+ return new RegExp(pattern, onlyFirst ? void 0 : "g");
6469
+ }
6470
+
6471
+ // node_modules/strip-ansi/index.js
6472
+ var regex = ansiRegex();
6473
+ function stripAnsi(string) {
6474
+ if (typeof string !== "string") {
6475
+ throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
6476
+ }
6477
+ if (!string.includes("\x1B") && !string.includes("\x9B")) {
6478
+ return string;
6479
+ }
6480
+ return string.replace(regex, "");
6481
+ }
6482
+
6483
+ // src/utils/parallel-tasks.ts
6484
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
6485
+ var SPINNER_INTERVAL_MS = 80;
6486
+ var ParallelTaskDisplay = class {
6487
+ tasks = [];
6488
+ lineCount = 0;
6489
+ spinnerFrame = 0;
6490
+ timer = null;
6491
+ startTime = 0;
6492
+ rendered = false;
6493
+ add(name) {
6494
+ const index = this.tasks.length;
6495
+ this.tasks.push({ name, status: "pending", message: "" });
6496
+ return index;
6497
+ }
6498
+ start() {
6499
+ this.startTime = Date.now();
6500
+ this.draw(true);
6501
+ this.timer = setInterval(() => {
6502
+ this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
6503
+ this.draw(false);
6504
+ }, SPINNER_INTERVAL_MS);
6505
+ }
6506
+ update(index, status, message) {
6507
+ const task = this.tasks[index];
6508
+ if (!task) return;
6509
+ if (status === "running" && task.status === "pending") {
6510
+ task.startTime = Date.now();
6511
+ }
6512
+ if ((status === "done" || status === "failed") && !task.endTime) {
6513
+ task.endTime = Date.now();
6514
+ }
6515
+ task.status = status;
6516
+ if (message !== void 0) task.message = message;
6517
+ }
6518
+ stop() {
6519
+ if (this.timer) {
6520
+ clearInterval(this.timer);
6521
+ this.timer = null;
6522
+ }
6523
+ this.draw(false);
6524
+ }
6525
+ formatTime(ms) {
6526
+ const secs = Math.floor(ms / 1e3);
6527
+ if (secs < 60) return `${secs}s`;
6528
+ return `${Math.floor(secs / 60)}m ${secs % 60}s`;
6529
+ }
6530
+ truncate(text, maxVisible) {
6531
+ const plain = stripAnsi(text);
6532
+ if (plain.length <= maxVisible) return text;
6533
+ let visible = 0;
6534
+ let i = 0;
6535
+ while (i < text.length && visible < maxVisible - 3) {
6536
+ if (text[i] === "\x1B") {
6537
+ const end = text.indexOf("m", i);
6538
+ if (end !== -1) {
6539
+ i = end + 1;
6540
+ continue;
6541
+ }
6542
+ }
6543
+ visible++;
6544
+ i++;
6545
+ }
6546
+ return text.slice(0, i) + "...";
6547
+ }
6548
+ renderLine(task) {
6549
+ const maxWidth = process.stdout.columns || 80;
6550
+ const elapsed = task.startTime ? this.formatTime((task.endTime ?? Date.now()) - task.startTime) : "";
6551
+ let line;
6552
+ switch (task.status) {
6553
+ case "pending":
6554
+ line = ` ${chalk9.dim("\u25CB")} ${chalk9.dim(task.name)}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}`;
6555
+ break;
6556
+ case "running": {
6557
+ const spinner = chalk9.cyan(SPINNER_FRAMES[this.spinnerFrame]);
6558
+ const time = elapsed ? chalk9.dim(` (${elapsed})`) : "";
6559
+ line = ` ${spinner} ${task.name}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}${time}`;
6560
+ break;
6561
+ }
6562
+ case "done": {
6563
+ const time = elapsed ? chalk9.dim(` (${elapsed})`) : "";
6564
+ line = ` ${chalk9.green("\u2713")} ${task.name}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}${time}`;
6565
+ break;
6566
+ }
6567
+ case "failed":
6568
+ line = ` ${chalk9.red("\u2717")} ${task.name}${task.message ? chalk9.red(` \u2014 ${task.message}`) : ""}`;
6569
+ break;
6570
+ }
6571
+ return this.truncate(line, maxWidth - 1);
6572
+ }
6573
+ draw(initial) {
6574
+ const { stdout } = process;
6575
+ if (!initial && this.rendered && this.lineCount > 0) {
6576
+ stdout.write(`\x1B[${this.lineCount}A`);
6577
+ }
6578
+ stdout.write("\x1B[0J");
6579
+ const lines = this.tasks.map((t) => this.renderLine(t));
6580
+ const totalElapsed = this.formatTime(Date.now() - this.startTime);
6581
+ lines.push(chalk9.dim(`
6582
+ Total: ${totalElapsed}`));
6583
+ const output = lines.join("\n");
6584
+ stdout.write(output + "\n");
6585
+ this.lineCount = output.split("\n").length;
6586
+ this.rendered = true;
6587
+ }
6588
+ };
6589
+
6374
6590
  // src/commands/init.ts
6375
6591
  function log(verbose, ...args) {
6376
- if (verbose) console.log(chalk9.dim(` [verbose] ${args.map(String).join(" ")}`));
6592
+ if (verbose) console.log(chalk10.dim(` [verbose] ${args.map(String).join(" ")}`));
6377
6593
  }
6378
6594
  async function initCommand(options) {
6379
- const brand = chalk9.hex("#EB9D83");
6380
- const title = chalk9.hex("#83D1EB");
6595
+ const brand = chalk10.hex("#EB9D83");
6596
+ const title = chalk10.hex("#83D1EB");
6381
6597
  console.log(brand.bold(`
6382
6598
  \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
6383
6599
  \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
@@ -6386,34 +6602,33 @@ async function initCommand(options) {
6386
6602
  \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
6387
6603
  \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
6388
6604
  `));
6389
- console.log(chalk9.dim(" Scan your project and generate tailored config files for"));
6390
- console.log(chalk9.dim(" Claude Code, Cursor, and Codex.\n"));
6605
+ console.log(chalk10.dim(" Scan your project and generate tailored config files for"));
6606
+ console.log(chalk10.dim(" Claude Code, Cursor, and Codex.\n"));
6391
6607
  const report = options.debugReport ? new DebugReport() : null;
6392
6608
  console.log(title.bold(" How it works:\n"));
6393
- console.log(chalk9.dim(" 1. Connect Choose your LLM provider"));
6394
- console.log(chalk9.dim(" 2. Discover Scan code, dependencies, and existing configs"));
6395
- console.log(chalk9.dim(" 3. Generate Build CLAUDE.md, rules, and skills for your codebase"));
6396
- console.log(chalk9.dim(" 4. Review See a diff \u2014 accept, refine via chat, or decline"));
6397
- console.log(chalk9.dim(" 5. Skills Search community registries and install skills\n"));
6398
- console.log(title.bold(" Step 1/5 \u2014 Connect\n"));
6609
+ console.log(chalk10.dim(" 1. Setup Connect your LLM provider and select your agents"));
6610
+ console.log(chalk10.dim(" 2. Engine Detect stack, generate configs & skills in parallel"));
6611
+ console.log(chalk10.dim(" 3. Review See all changes \u2014 accept, refine, or decline"));
6612
+ console.log(chalk10.dim(" 4. Finalize Score check and auto-sync hooks\n"));
6613
+ console.log(title.bold(" Step 1/4 \u2014 Setup\n"));
6399
6614
  let config = loadConfig();
6400
6615
  if (!config) {
6401
- console.log(chalk9.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
6616
+ console.log(chalk10.dim(" No LLM provider configured yet.\n"));
6402
6617
  await runInteractiveProviderSetup({
6403
6618
  selectMessage: "How do you want to use Caliber? (choose LLM provider)"
6404
6619
  });
6405
6620
  config = loadConfig();
6406
6621
  if (!config) {
6407
- console.log(chalk9.red(" Setup was cancelled or failed.\n"));
6622
+ console.log(chalk10.red(" Setup was cancelled or failed.\n"));
6408
6623
  throw new Error("__exit__");
6409
6624
  }
6410
- console.log(chalk9.green(" \u2713 Provider saved. Let's continue.\n"));
6625
+ console.log(chalk10.green(" \u2713 Provider saved\n"));
6411
6626
  }
6412
6627
  trackInitProviderSelected(config.provider, config.model);
6413
6628
  const displayModel = getDisplayModel(config);
6414
6629
  const fastModel = getFastModel();
6415
6630
  const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
6416
- console.log(chalk9.dim(modelLine + "\n"));
6631
+ console.log(chalk10.dim(modelLine + "\n"));
6417
6632
  if (report) {
6418
6633
  report.markStep("Provider setup");
6419
6634
  report.addSection("LLM Provider", `- **Provider**: ${config.provider}
@@ -6421,30 +6636,6 @@ async function initCommand(options) {
6421
6636
  - **Fast model**: ${fastModel || "none"}`);
6422
6637
  }
6423
6638
  await validateModel({ fast: true });
6424
- console.log(title.bold(" Step 2/5 \u2014 Discover\n"));
6425
- const spinner = ora2("Scanning code, dependencies, and existing configs...").start();
6426
- const fingerprint = await collectFingerprint(process.cwd());
6427
- spinner.succeed("Project scanned");
6428
- log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
6429
- if (options.verbose && fingerprint.codeAnalysis) {
6430
- log(options.verbose, `Code analysis: ${fingerprint.codeAnalysis.filesIncluded}/${fingerprint.codeAnalysis.filesAnalyzed} files, ~${fingerprint.codeAnalysis.includedTokens.toLocaleString()} tokens, ${fingerprint.codeAnalysis.duplicateGroups} dedup groups`);
6431
- }
6432
- trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
6433
- const langDisplay = fingerprint.languages.join(", ") || "none detected";
6434
- const frameworkDisplay = fingerprint.frameworks.length > 0 ? ` (${fingerprint.frameworks.join(", ")})` : "";
6435
- console.log(chalk9.dim(` Languages: ${langDisplay}${frameworkDisplay}`));
6436
- console.log(chalk9.dim(` Files: ${fingerprint.fileTree.length} found
6437
- `));
6438
- if (report) {
6439
- report.markStep("Fingerprint");
6440
- report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
6441
- report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
6442
- report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
6443
- report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
6444
- if (fingerprint.codeAnalysis) {
6445
- report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
6446
- }
6447
- }
6448
6639
  let targetAgent;
6449
6640
  if (options.agent) {
6450
6641
  targetAgent = options.agent;
@@ -6454,30 +6645,27 @@ async function initCommand(options) {
6454
6645
  } else {
6455
6646
  targetAgent = await promptAgent();
6456
6647
  }
6457
- console.log(chalk9.dim(` Target: ${targetAgent.join(", ")}
6648
+ console.log(chalk10.dim(` Target: ${targetAgent.join(", ")}
6458
6649
  `));
6459
6650
  trackInitAgentSelected(targetAgent);
6460
- const preScore = computeLocalScore(process.cwd(), targetAgent);
6461
- const failingForDismissal = preScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
6462
- if (failingForDismissal.length > 0) {
6463
- const newDismissals = await evaluateDismissals(failingForDismissal, fingerprint);
6464
- if (newDismissals.length > 0) {
6465
- const existing = readDismissedChecks();
6466
- const existingIds = new Set(existing.map((d) => d.id));
6467
- const merged = [...existing, ...newDismissals.filter((d) => !existingIds.has(d.id))];
6468
- writeDismissedChecks(merged);
6469
- }
6651
+ let wantsSkills = false;
6652
+ if (!options.autoApprove) {
6653
+ wantsSkills = await select5({
6654
+ message: "Discover community-maintained skills that match your stack?",
6655
+ choices: [
6656
+ { name: "Yes, find skills for my project", value: true },
6657
+ { name: "Skip for now", value: false }
6658
+ ]
6659
+ });
6470
6660
  }
6471
- const baselineScore = computeLocalScore(process.cwd(), targetAgent);
6472
- console.log(chalk9.dim(" Current setup score:"));
6661
+ let baselineScore = computeLocalScore(process.cwd(), targetAgent);
6662
+ console.log(chalk10.dim("\n Current setup score:"));
6473
6663
  displayScoreSummary(baselineScore);
6474
6664
  if (options.verbose) {
6475
6665
  for (const c of baselineScore.checks) {
6476
6666
  log(options.verbose, ` ${c.passed ? "\u2713" : "\u2717"} ${c.name}: ${c.earnedPoints}/${c.maxPoints}${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
6477
6667
  }
6478
6668
  }
6479
- const passingCount = baselineScore.checks.filter((c) => c.passed).length;
6480
- const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
6481
6669
  if (report) {
6482
6670
  report.markStep("Baseline scoring");
6483
6671
  report.addSection("Scoring: Baseline", `**Score**: ${baselineScore.score}/100
@@ -6487,7 +6675,7 @@ async function initCommand(options) {
6487
6675
  ` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
6488
6676
  report.addSection("Generation: Target Agents", targetAgent.join(", "));
6489
6677
  }
6490
- const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length || fingerprint.existingConfigs.agentsMd);
6678
+ const hasExistingConfig = !!(baselineScore.checks.some((c) => c.id === "claude_md_exists" && c.passed) || baselineScore.checks.some((c) => c.id === "cursorrules_exists" && c.passed));
6491
6679
  const NON_LLM_CHECKS = /* @__PURE__ */ new Set([
6492
6680
  "hooks_configured",
6493
6681
  "agents_md_exists",
@@ -6496,111 +6684,175 @@ async function initCommand(options) {
6496
6684
  "service_coverage",
6497
6685
  "mcp_completeness"
6498
6686
  ]);
6687
+ const passingCount = baselineScore.checks.filter((c) => c.passed).length;
6688
+ const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
6499
6689
  if (hasExistingConfig && baselineScore.score === 100) {
6500
6690
  trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
6501
- console.log(chalk9.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
6502
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber init --force") + chalk9.dim(" to regenerate anyway.\n"));
6691
+ console.log(chalk10.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
6692
+ console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber init --force") + chalk10.dim(" to regenerate anyway.\n"));
6503
6693
  if (!options.force) return;
6504
6694
  }
6505
6695
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
6506
6696
  const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
6507
6697
  trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
6508
6698
  if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
6509
- console.log(chalk9.bold.green("\n Your config is fully optimized for LLM generation.\n"));
6510
- console.log(chalk9.dim(" Remaining items need CLI actions:\n"));
6699
+ console.log(chalk10.bold.green("\n Your config is fully optimized for LLM generation.\n"));
6700
+ console.log(chalk10.dim(" Remaining items need CLI actions:\n"));
6511
6701
  for (const check of allFailingChecks) {
6512
- console.log(chalk9.dim(` \u2022 ${check.name}`));
6702
+ console.log(chalk10.dim(` \u2022 ${check.name}`));
6513
6703
  if (check.suggestion) {
6514
- console.log(` ${chalk9.hex("#83D1EB")(check.suggestion)}`);
6704
+ console.log(` ${chalk10.hex("#83D1EB")(check.suggestion)}`);
6515
6705
  }
6516
6706
  }
6517
6707
  console.log("");
6518
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber init --force") + chalk9.dim(" to regenerate anyway.\n"));
6708
+ console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber init --force") + chalk10.dim(" to regenerate anyway.\n"));
6519
6709
  return;
6520
6710
  }
6711
+ console.log(title.bold(" Step 2/4 \u2014 Engine\n"));
6712
+ const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
6713
+ console.log(chalk10.dim(genModelInfo + "\n"));
6714
+ if (report) report.markStep("Generation");
6715
+ trackInitGenerationStarted(false);
6716
+ const genStartTime = Date.now();
6717
+ let generatedSetup = null;
6718
+ let rawOutput;
6719
+ let genStopReason;
6720
+ let skillSearchResult = { results: [], contentMap: /* @__PURE__ */ new Map() };
6721
+ let fingerprint;
6722
+ const fpSpinner = ora2("Scanning project...").start();
6723
+ try {
6724
+ fingerprint = await collectFingerprint(process.cwd());
6725
+ fpSpinner.succeed(`Stack detected \u2014 ${fingerprint.languages.join(", ") || "no languages"}${fingerprint.frameworks.length > 0 ? `, ${fingerprint.frameworks.join(", ")}` : ""}`);
6726
+ } catch (err) {
6727
+ fpSpinner.fail("Failed to scan project");
6728
+ throw new Error("__exit__");
6729
+ }
6730
+ trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
6731
+ log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
6732
+ if (report) {
6733
+ report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
6734
+ report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
6735
+ report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
6736
+ report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
6737
+ if (fingerprint.codeAnalysis) report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
6738
+ }
6521
6739
  const isEmpty = fingerprint.fileTree.length < 3;
6522
6740
  if (isEmpty) {
6523
6741
  fingerprint.description = await promptInput("What will you build in this project?");
6524
6742
  }
6743
+ const failingForDismissal = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
6744
+ if (failingForDismissal.length > 0) {
6745
+ const newDismissals = await evaluateDismissals(failingForDismissal, fingerprint);
6746
+ if (newDismissals.length > 0) {
6747
+ const existing = readDismissedChecks();
6748
+ const existingIds = new Set(existing.map((d) => d.id));
6749
+ const merged = [...existing, ...newDismissals.filter((d) => !existingIds.has(d.id))];
6750
+ writeDismissedChecks(merged);
6751
+ baselineScore = computeLocalScore(process.cwd(), targetAgent);
6752
+ }
6753
+ }
6525
6754
  let failingChecks;
6526
6755
  let passingChecks;
6527
6756
  let currentScore;
6528
6757
  if (hasExistingConfig && baselineScore.score >= 95 && !options.force) {
6529
- failingChecks = llmFixableChecks.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
6758
+ const currentLlmFixable = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
6759
+ failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
6530
6760
  passingChecks = baselineScore.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
6531
6761
  currentScore = baselineScore.score;
6532
- if (failingChecks.length > 0) {
6533
- console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
6534
- console.log(chalk9.dim(` Score is ${baselineScore.score}/100 \u2014 fine-tuning ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
6535
- `));
6536
- for (const check of failingChecks) {
6537
- console.log(chalk9.dim(` \u2022 ${check.name}`));
6538
- }
6539
- console.log("");
6540
- }
6541
- } else if (hasExistingConfig) {
6542
- console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
6543
- console.log(chalk9.dim(" Auditing your existing configs against your codebase and improving them.\n"));
6544
- } else {
6545
- console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
6546
- console.log(chalk9.dim(" Building CLAUDE.md, rules, and skills tailored to your project.\n"));
6547
6762
  }
6548
- const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
6549
- console.log(chalk9.dim(genModelInfo));
6550
- console.log(chalk9.dim(" This can take a couple of minutes depending on your model and provider.\n"));
6551
6763
  if (report) {
6552
- report.markStep("Generation");
6553
6764
  const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
6554
6765
  report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
6555
6766
  }
6556
- trackInitGenerationStarted(!!failingChecks);
6557
- const genStartTime = Date.now();
6558
- const genSpinner = ora2("Generating setup...").start();
6559
- const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
6560
- genMessages.start();
6561
- let generatedSetup = null;
6562
- let rawOutput;
6563
- let genStopReason;
6767
+ const display = new ParallelTaskDisplay();
6768
+ const TASK_CONFIG = display.add("Generating configs");
6769
+ const TASK_SKILLS_GEN = display.add("Generating skills");
6770
+ const TASK_SKILLS_SEARCH = wantsSkills ? display.add("Searching community skills") : -1;
6771
+ display.start();
6564
6772
  try {
6565
- const result = await generateSetup(
6566
- fingerprint,
6567
- targetAgent,
6568
- fingerprint.description,
6569
- {
6570
- onStatus: (status) => {
6571
- genMessages.handleServerStatus(status);
6572
- },
6573
- onComplete: (setup) => {
6574
- generatedSetup = setup;
6773
+ display.update(TASK_CONFIG, "running");
6774
+ const generatePromise = (async () => {
6775
+ const result = await generateSetup(
6776
+ fingerprint,
6777
+ targetAgent,
6778
+ fingerprint.description,
6779
+ {
6780
+ onStatus: (status) => display.update(TASK_CONFIG, "running", status),
6781
+ onComplete: (setup) => {
6782
+ generatedSetup = setup;
6783
+ },
6784
+ onError: (error) => display.update(TASK_CONFIG, "failed", error)
6575
6785
  },
6576
- onError: (error) => {
6577
- genMessages.stop();
6578
- genSpinner.fail(`Generation error: ${error}`);
6579
- }
6580
- },
6581
- failingChecks,
6582
- currentScore,
6583
- passingChecks
6584
- );
6585
- if (!generatedSetup) {
6586
- generatedSetup = result.setup;
6786
+ failingChecks,
6787
+ currentScore,
6788
+ passingChecks,
6789
+ { skipSkills: true }
6790
+ );
6791
+ if (!generatedSetup) generatedSetup = result.setup;
6587
6792
  rawOutput = result.raw;
6588
- }
6589
- genStopReason = result.stopReason;
6793
+ genStopReason = result.stopReason;
6794
+ if (!generatedSetup) {
6795
+ display.update(TASK_CONFIG, "failed", "Could not parse LLM response");
6796
+ display.update(TASK_SKILLS_GEN, "failed", "Skipped");
6797
+ return;
6798
+ }
6799
+ display.update(TASK_CONFIG, "done");
6800
+ display.update(TASK_SKILLS_GEN, "running");
6801
+ const skillCount = await generateSkillsForSetup(
6802
+ generatedSetup,
6803
+ fingerprint,
6804
+ targetAgent,
6805
+ (status) => display.update(TASK_SKILLS_GEN, "running", status)
6806
+ );
6807
+ display.update(TASK_SKILLS_GEN, "done", `${skillCount} skills`);
6808
+ })();
6809
+ const SEARCH_TIMEOUT_MS = 6e4;
6810
+ const searchPromise = wantsSkills ? (async () => {
6811
+ display.update(TASK_SKILLS_SEARCH, "running");
6812
+ try {
6813
+ const searchWithTimeout = Promise.race([
6814
+ searchSkills(
6815
+ fingerprint,
6816
+ targetAgent,
6817
+ (status) => display.update(TASK_SKILLS_SEARCH, "running", status)
6818
+ ),
6819
+ new Promise(
6820
+ (_, reject) => setTimeout(() => reject(new Error("timeout")), SEARCH_TIMEOUT_MS)
6821
+ )
6822
+ ]);
6823
+ skillSearchResult = await searchWithTimeout;
6824
+ const count = skillSearchResult.results.length;
6825
+ display.update(TASK_SKILLS_SEARCH, "done", count > 0 ? `${count} skills found` : "No matches");
6826
+ } catch (err) {
6827
+ const reason = err instanceof Error && err.message === "timeout" ? "Timed out" : "Search failed";
6828
+ display.update(TASK_SKILLS_SEARCH, "failed", reason);
6829
+ }
6830
+ })() : Promise.resolve();
6831
+ await Promise.all([generatePromise, searchPromise]);
6590
6832
  } catch (err) {
6591
- genMessages.stop();
6833
+ display.stop();
6592
6834
  const msg = err instanceof Error ? err.message : "Unknown error";
6593
- genSpinner.fail(`Generation failed: ${msg}`);
6835
+ console.log(chalk10.red(`
6836
+ Engine failed: ${msg}
6837
+ `));
6594
6838
  writeErrorLog(config, void 0, msg, "exception");
6595
6839
  throw new Error("__exit__");
6596
6840
  }
6597
- genMessages.stop();
6841
+ display.stop();
6842
+ const elapsedMs = Date.now() - genStartTime;
6843
+ trackInitGenerationCompleted(elapsedMs, 0);
6844
+ const mins = Math.floor(elapsedMs / 6e4);
6845
+ const secs = Math.floor(elapsedMs % 6e4 / 1e3);
6846
+ const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
6847
+ console.log(chalk10.dim(`
6848
+ Completed in ${timeStr}
6849
+ `));
6598
6850
  if (!generatedSetup) {
6599
- genSpinner.fail("Failed to generate setup.");
6851
+ console.log(chalk10.red(" Failed to generate setup."));
6600
6852
  writeErrorLog(config, rawOutput, void 0, genStopReason);
6601
6853
  if (rawOutput) {
6602
- console.log(chalk9.dim("\nRaw LLM output (JSON parse failed):"));
6603
- console.log(chalk9.dim(rawOutput.slice(0, 500)));
6854
+ console.log(chalk10.dim("\nRaw LLM output (JSON parse failed):"));
6855
+ console.log(chalk10.dim(rawOutput.slice(0, 500)));
6604
6856
  }
6605
6857
  throw new Error("__exit__");
6606
6858
  }
@@ -6608,12 +6860,6 @@ async function initCommand(options) {
6608
6860
  if (rawOutput) report.addCodeBlock("Generation: Raw LLM Response", rawOutput);
6609
6861
  report.addJson("Generation: Parsed Setup", generatedSetup);
6610
6862
  }
6611
- const elapsedMs = Date.now() - genStartTime;
6612
- trackInitGenerationCompleted(elapsedMs, 0);
6613
- const mins = Math.floor(elapsedMs / 6e4);
6614
- const secs = Math.floor(elapsedMs % 6e4 / 1e3);
6615
- const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
6616
- genSpinner.succeed(`Setup generated ${chalk9.dim(`in ${timeStr}`)}`);
6617
6863
  log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
6618
6864
  printSetupSummary(generatedSetup);
6619
6865
  const sessionHistory = [];
@@ -6621,15 +6867,20 @@ async function initCommand(options) {
6621
6867
  role: "assistant",
6622
6868
  content: summarizeSetup("Initial generation", generatedSetup)
6623
6869
  });
6624
- console.log(title.bold(" Step 4/5 \u2014 Review\n"));
6870
+ console.log(title.bold(" Step 3/4 \u2014 Review\n"));
6625
6871
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
6626
6872
  const staged = stageFiles(setupFiles, process.cwd());
6627
6873
  const totalChanges = staged.newFiles + staged.modifiedFiles;
6628
- console.log(chalk9.dim(` ${chalk9.green(`${staged.newFiles} new`)} / ${chalk9.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
6874
+ console.log(chalk10.dim(` ${chalk10.green(`${staged.newFiles} new`)} / ${chalk10.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`));
6875
+ if (skillSearchResult.results.length > 0) {
6876
+ console.log(chalk10.dim(` ${chalk10.cyan(`${skillSearchResult.results.length}`)} community skills available to install
6629
6877
  `));
6878
+ } else {
6879
+ console.log("");
6880
+ }
6630
6881
  let action;
6631
- if (totalChanges === 0) {
6632
- console.log(chalk9.dim(" No changes needed \u2014 your configs are already up to date.\n"));
6882
+ if (totalChanges === 0 && skillSearchResult.results.length === 0) {
6883
+ console.log(chalk10.dim(" No changes needed \u2014 your configs are already up to date.\n"));
6633
6884
  cleanupStaging();
6634
6885
  action = "accept";
6635
6886
  } else if (options.autoApprove) {
@@ -6637,13 +6888,15 @@ async function initCommand(options) {
6637
6888
  action = "accept";
6638
6889
  trackInitReviewAction(action, "auto-approved");
6639
6890
  } else {
6640
- const wantsReview = await promptWantsReview();
6641
- if (wantsReview) {
6642
- const reviewMethod = await promptReviewMethod();
6643
- await openReview(reviewMethod, staged.stagedFiles);
6891
+ if (totalChanges > 0) {
6892
+ const wantsReview = await promptWantsReview();
6893
+ if (wantsReview) {
6894
+ const reviewMethod = await promptReviewMethod();
6895
+ await openReview(reviewMethod, staged.stagedFiles);
6896
+ }
6644
6897
  }
6645
6898
  action = await promptReviewAction();
6646
- trackInitReviewAction(action, wantsReview ? "reviewed" : "skipped");
6899
+ trackInitReviewAction(action, totalChanges > 0 ? "reviewed" : "skipped");
6647
6900
  }
6648
6901
  let refinementRound = 0;
6649
6902
  while (action === "refine") {
@@ -6652,12 +6905,12 @@ async function initCommand(options) {
6652
6905
  trackInitRefinementRound(refinementRound, !!generatedSetup);
6653
6906
  if (!generatedSetup) {
6654
6907
  cleanupStaging();
6655
- console.log(chalk9.dim("Refinement cancelled. No files were modified."));
6908
+ console.log(chalk10.dim("Refinement cancelled. No files were modified."));
6656
6909
  return;
6657
6910
  }
6658
6911
  const updatedFiles = collectSetupFiles(generatedSetup, targetAgent);
6659
6912
  const restaged = stageFiles(updatedFiles, process.cwd());
6660
- console.log(chalk9.dim(` ${chalk9.green(`${restaged.newFiles} new`)} / ${chalk9.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
6913
+ console.log(chalk10.dim(` ${chalk10.green(`${restaged.newFiles} new`)} / ${chalk10.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
6661
6914
  `));
6662
6915
  printSetupSummary(generatedSetup);
6663
6916
  await openReview("terminal", restaged.stagedFiles);
@@ -6666,17 +6919,18 @@ async function initCommand(options) {
6666
6919
  }
6667
6920
  cleanupStaging();
6668
6921
  if (action === "decline") {
6669
- console.log(chalk9.dim("Setup declined. No files were modified."));
6922
+ console.log(chalk10.dim("Setup declined. No files were modified."));
6670
6923
  return;
6671
6924
  }
6925
+ console.log(title.bold("\n Step 4/4 \u2014 Finalize\n"));
6672
6926
  if (options.dryRun) {
6673
- console.log(chalk9.yellow("\n[Dry run] Would write the following files:"));
6927
+ console.log(chalk10.yellow("\n[Dry run] Would write the following files:"));
6674
6928
  console.log(JSON.stringify(generatedSetup, null, 2));
6675
6929
  return;
6676
6930
  }
6677
6931
  const writeSpinner = ora2("Writing config files...").start();
6678
6932
  try {
6679
- if (targetAgent.includes("codex") && !fs24.existsSync("AGENTS.md") && !generatedSetup.codex) {
6933
+ if (targetAgent.includes("codex") && !fs25.existsSync("AGENTS.md") && !generatedSetup.codex) {
6680
6934
  const claude = generatedSetup.claude;
6681
6935
  const cursor = generatedSetup.cursor;
6682
6936
  const agentRefs = [];
@@ -6699,85 +6953,45 @@ ${agentRefs.join(" ")}
6699
6953
  0,
6700
6954
  result.deleted.length
6701
6955
  );
6702
- console.log(chalk9.bold("\nFiles created/updated:"));
6956
+ console.log(chalk10.bold("\nFiles created/updated:"));
6703
6957
  for (const file of result.written) {
6704
- console.log(` ${chalk9.green("\u2713")} ${file}`);
6958
+ console.log(` ${chalk10.green("\u2713")} ${file}`);
6705
6959
  }
6706
6960
  if (result.deleted.length > 0) {
6707
- console.log(chalk9.bold("\nFiles removed:"));
6961
+ console.log(chalk10.bold("\nFiles removed:"));
6708
6962
  for (const file of result.deleted) {
6709
- console.log(` ${chalk9.red("\u2717")} ${file}`);
6963
+ console.log(` ${chalk10.red("\u2717")} ${file}`);
6710
6964
  }
6711
6965
  }
6712
6966
  if (result.backupDir) {
6713
- console.log(chalk9.dim(`
6967
+ console.log(chalk10.dim(`
6714
6968
  Backups saved to ${result.backupDir}`));
6715
6969
  }
6716
6970
  } catch (err) {
6717
6971
  writeSpinner.fail("Failed to write files");
6718
- console.error(chalk9.red(err instanceof Error ? err.message : "Unknown error"));
6972
+ console.error(chalk10.red(err instanceof Error ? err.message : "Unknown error"));
6719
6973
  throw new Error("__exit__");
6720
6974
  }
6721
- ensurePermissions(fingerprint);
6975
+ if (fingerprint) ensurePermissions(fingerprint);
6722
6976
  const sha = getCurrentHeadSha();
6723
6977
  writeState({
6724
6978
  lastRefreshSha: sha ?? "",
6725
6979
  lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
6726
6980
  targetAgent
6727
6981
  });
6728
- console.log("");
6729
- console.log(chalk9.dim(" Auto-refresh: keep your configs in sync as your code changes.\n"));
6730
- let hookChoice;
6731
- if (options.autoApprove) {
6732
- hookChoice = "skip";
6733
- log(options.verbose, "Auto-approve: skipping hook installation");
6734
- } else {
6735
- hookChoice = await promptHookType(targetAgent);
6736
- }
6737
- trackInitHookSelected(hookChoice);
6738
- if (hookChoice === "claude" || hookChoice === "both") {
6739
- const hookResult = installHook();
6740
- if (hookResult.installed) {
6741
- console.log(` ${chalk9.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
6742
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber hooks --remove") + chalk9.dim(" to disable"));
6743
- } else if (hookResult.alreadyInstalled) {
6744
- console.log(chalk9.dim(" Claude Code hook already installed"));
6745
- }
6746
- const learnResult = installLearningHooks();
6747
- if (learnResult.installed) {
6748
- console.log(` ${chalk9.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
6749
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber learn remove") + chalk9.dim(" to disable"));
6750
- } else if (learnResult.alreadyInstalled) {
6751
- console.log(chalk9.dim(" Learning hooks already installed"));
6752
- }
6753
- }
6754
- if (hookChoice === "precommit" || hookChoice === "both") {
6755
- const precommitResult = installPreCommitHook();
6756
- if (precommitResult.installed) {
6757
- console.log(` ${chalk9.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
6758
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber hooks --remove") + chalk9.dim(" to disable"));
6759
- } else if (precommitResult.alreadyInstalled) {
6760
- console.log(chalk9.dim(" Pre-commit hook already installed"));
6761
- } else {
6762
- console.log(chalk9.yellow(" Could not install pre-commit hook (not a git repository?)"));
6763
- }
6764
- }
6765
- if (hookChoice === "skip") {
6766
- console.log(chalk9.dim(" Skipped auto-refresh hooks. Run ") + chalk9.hex("#83D1EB")("caliber hooks --install") + chalk9.dim(" later to enable."));
6767
- }
6768
6982
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
6769
6983
  if (afterScore.score < baselineScore.score) {
6770
6984
  trackInitScoreRegression(baselineScore.score, afterScore.score);
6771
6985
  console.log("");
6772
- console.log(chalk9.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
6986
+ console.log(chalk10.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
6773
6987
  try {
6774
6988
  const { restored, removed } = undoSetup();
6775
6989
  if (restored.length > 0 || removed.length > 0) {
6776
- console.log(chalk9.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
6990
+ console.log(chalk10.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
6777
6991
  }
6778
6992
  } catch {
6779
6993
  }
6780
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber init --force") + chalk9.dim(" to override.\n"));
6994
+ console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber init --force") + chalk10.dim(" to override.\n"));
6781
6995
  return;
6782
6996
  }
6783
6997
  if (report) {
@@ -6795,39 +7009,57 @@ ${agentRefs.join(" ")}
6795
7009
  log(options.verbose, ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
6796
7010
  }
6797
7011
  }
6798
- console.log(title.bold("\n Step 5/5 \u2014 Skills\n"));
6799
- console.log(chalk9.dim(" Search community registries for skills that match your tech stack.\n"));
6800
- let wantsSkills;
7012
+ if (skillSearchResult.results.length > 0 && !options.autoApprove) {
7013
+ console.log(chalk10.dim(" Community skills matched to your project:\n"));
7014
+ const selected = await interactiveSelect(skillSearchResult.results);
7015
+ if (selected?.length) {
7016
+ await installSkills(selected, targetAgent, skillSearchResult.contentMap);
7017
+ trackInitSkillsSearch(true, selected.length);
7018
+ }
7019
+ }
7020
+ console.log("");
7021
+ let hookChoice;
6801
7022
  if (options.autoApprove) {
6802
- wantsSkills = false;
6803
- log(options.verbose, "Auto-approve: skipping skills search");
7023
+ hookChoice = "skip";
7024
+ log(options.verbose, "Auto-approve: skipping hook installation");
6804
7025
  } else {
6805
- wantsSkills = await select5({
6806
- message: "Search public repos for relevant skills to add to this project?",
6807
- choices: [
6808
- { name: "Yes, find skills for my project", value: true },
6809
- { name: "Skip for now", value: false }
6810
- ]
6811
- });
7026
+ hookChoice = await promptHookType(targetAgent);
6812
7027
  }
6813
- if (wantsSkills) {
6814
- trackInitSkillsSearch(true, 0);
6815
- try {
6816
- await searchAndInstallSkills(targetAgent);
6817
- } catch (err) {
6818
- if (err.message !== "__exit__") {
6819
- console.log(chalk9.dim(" Skills search failed: " + (err.message || "unknown error")));
6820
- }
6821
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber skills") + chalk9.dim(" later to try again.\n"));
7028
+ trackInitHookSelected(hookChoice);
7029
+ if (hookChoice === "claude" || hookChoice === "both") {
7030
+ const hookResult = installHook();
7031
+ if (hookResult.installed) {
7032
+ console.log(` ${chalk10.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
7033
+ console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber hooks --remove") + chalk10.dim(" to disable"));
7034
+ } else if (hookResult.alreadyInstalled) {
7035
+ console.log(chalk10.dim(" Claude Code hook already installed"));
7036
+ }
7037
+ const learnResult = installLearningHooks();
7038
+ if (learnResult.installed) {
7039
+ console.log(` ${chalk10.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
7040
+ console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber learn remove") + chalk10.dim(" to disable"));
7041
+ } else if (learnResult.alreadyInstalled) {
7042
+ console.log(chalk10.dim(" Learning hooks already installed"));
7043
+ }
7044
+ }
7045
+ if (hookChoice === "precommit" || hookChoice === "both") {
7046
+ const precommitResult = installPreCommitHook();
7047
+ if (precommitResult.installed) {
7048
+ console.log(` ${chalk10.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
7049
+ console.log(chalk10.dim(" Run ") + chalk10.hex("#83D1EB")("caliber hooks --remove") + chalk10.dim(" to disable"));
7050
+ } else if (precommitResult.alreadyInstalled) {
7051
+ console.log(chalk10.dim(" Pre-commit hook already installed"));
7052
+ } else {
7053
+ console.log(chalk10.yellow(" Could not install pre-commit hook (not a git repository?)"));
6822
7054
  }
6823
- } else {
6824
- trackInitSkillsSearch(false, 0);
6825
- console.log(chalk9.dim(" Skipped. Run ") + chalk9.hex("#83D1EB")("caliber skills") + chalk9.dim(" later to browse.\n"));
6826
7055
  }
6827
- console.log(chalk9.bold.green(" Setup complete!"));
6828
- console.log(chalk9.dim(" Your AI agents now understand your project's architecture, build commands,"));
6829
- console.log(chalk9.dim(" testing patterns, and conventions. All changes are backed up automatically.\n"));
6830
- console.log(chalk9.bold(" Next steps:\n"));
7056
+ if (hookChoice === "skip") {
7057
+ console.log(chalk10.dim(" Skipped auto-sync hooks. Run ") + chalk10.hex("#83D1EB")("caliber hooks --install") + chalk10.dim(" later to enable."));
7058
+ }
7059
+ console.log(chalk10.bold.green("\n Setup complete!"));
7060
+ console.log(chalk10.dim(" Your AI agents now understand your project's architecture, build commands,"));
7061
+ console.log(chalk10.dim(" testing patterns, and conventions. All changes are backed up automatically.\n"));
7062
+ console.log(chalk10.bold(" Next steps:\n"));
6831
7063
  console.log(` ${title("caliber score")} See your full config breakdown`);
6832
7064
  console.log(` ${title("caliber refresh")} Update docs after code changes`);
6833
7065
  console.log(` ${title("caliber hooks")} Toggle auto-refresh hooks`);
@@ -6839,9 +7071,9 @@ ${agentRefs.join(" ")}
6839
7071
  }
6840
7072
  if (report) {
6841
7073
  report.markStep("Finished");
6842
- const reportPath = path19.join(process.cwd(), ".caliber", "debug-report.md");
7074
+ const reportPath = path20.join(process.cwd(), ".caliber", "debug-report.md");
6843
7075
  report.write(reportPath);
6844
- console.log(chalk9.dim(` Debug report written to ${path19.relative(process.cwd(), reportPath)}
7076
+ console.log(chalk10.dim(` Debug report written to ${path20.relative(process.cwd(), reportPath)}
6845
7077
  `));
6846
7078
  }
6847
7079
  }
@@ -6856,9 +7088,9 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
6856
7088
  }
6857
7089
  const isValid = await classifyRefineIntent(message);
6858
7090
  if (!isValid) {
6859
- console.log(chalk9.dim(" This doesn't look like a config change request."));
6860
- console.log(chalk9.dim(" Describe what to add, remove, or modify in your configs."));
6861
- console.log(chalk9.dim(' Type "done" to accept the current setup.\n'));
7091
+ console.log(chalk10.dim(" This doesn't look like a config change request."));
7092
+ console.log(chalk10.dim(" Describe what to add, remove, or modify in your configs."));
7093
+ console.log(chalk10.dim(' Type "done" to accept the current setup.\n'));
6862
7094
  continue;
6863
7095
  }
6864
7096
  const refineSpinner = ora2("Refining setup...").start();
@@ -6879,16 +7111,16 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
6879
7111
  });
6880
7112
  refineSpinner.succeed("Setup updated");
6881
7113
  printSetupSummary(refined);
6882
- console.log(chalk9.dim('Type "done" to accept, or describe more changes.'));
7114
+ console.log(chalk10.dim('Type "done" to accept, or describe more changes.'));
6883
7115
  } else {
6884
7116
  refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
6885
- console.log(chalk9.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
7117
+ console.log(chalk10.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
6886
7118
  }
6887
7119
  }
6888
7120
  }
6889
7121
  function summarizeSetup(action, setup) {
6890
7122
  const descriptions = setup.fileDescriptions;
6891
- const files = descriptions ? Object.entries(descriptions).map(([path27, desc]) => ` ${path27}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
7123
+ const files = descriptions ? Object.entries(descriptions).map(([path28, desc]) => ` ${path28}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
6892
7124
  return `${action}. Files:
6893
7125
  ${files}`;
6894
7126
  }
@@ -6910,6 +7142,7 @@ Return {"valid": true} or {"valid": false}. Nothing else.`,
6910
7142
  }
6911
7143
  }
6912
7144
  async function evaluateDismissals(failingChecks, fingerprint) {
7145
+ if (failingChecks.length === 0) return [];
6913
7146
  const fastModel = getFastModel();
6914
7147
  const checkList = failingChecks.map((c) => ({
6915
7148
  id: c.id,
@@ -6977,7 +7210,7 @@ async function promptHookType(targetAgent) {
6977
7210
  }
6978
7211
  choices.push({ name: "Skip for now", value: "skip" });
6979
7212
  return select5({
6980
- message: "How would you like to auto-refresh your setup?",
7213
+ message: "Keep your AI docs & skills in sync as your code evolves?",
6981
7214
  choices
6982
7215
  });
6983
7216
  }
@@ -6997,26 +7230,26 @@ function printSetupSummary(setup) {
6997
7230
  const fileDescriptions = setup.fileDescriptions;
6998
7231
  const deletions = setup.deletions;
6999
7232
  console.log("");
7000
- console.log(chalk9.bold(" Proposed changes:\n"));
7233
+ console.log(chalk10.bold(" Proposed changes:\n"));
7001
7234
  const getDescription = (filePath) => {
7002
7235
  return fileDescriptions?.[filePath];
7003
7236
  };
7004
7237
  if (claude) {
7005
7238
  if (claude.claudeMd) {
7006
- const icon = fs24.existsSync("CLAUDE.md") ? chalk9.yellow("~") : chalk9.green("+");
7239
+ const icon = fs25.existsSync("CLAUDE.md") ? chalk10.yellow("~") : chalk10.green("+");
7007
7240
  const desc = getDescription("CLAUDE.md");
7008
- console.log(` ${icon} ${chalk9.bold("CLAUDE.md")}`);
7009
- if (desc) console.log(chalk9.dim(` ${desc}`));
7241
+ console.log(` ${icon} ${chalk10.bold("CLAUDE.md")}`);
7242
+ if (desc) console.log(chalk10.dim(` ${desc}`));
7010
7243
  console.log("");
7011
7244
  }
7012
7245
  const skills = claude.skills;
7013
7246
  if (Array.isArray(skills) && skills.length > 0) {
7014
7247
  for (const skill of skills) {
7015
7248
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
7016
- const icon = fs24.existsSync(skillPath) ? chalk9.yellow("~") : chalk9.green("+");
7249
+ const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7017
7250
  const desc = getDescription(skillPath);
7018
- console.log(` ${icon} ${chalk9.bold(skillPath)}`);
7019
- console.log(chalk9.dim(` ${desc || skill.description || skill.name}`));
7251
+ console.log(` ${icon} ${chalk10.bold(skillPath)}`);
7252
+ console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
7020
7253
  console.log("");
7021
7254
  }
7022
7255
  }
@@ -7024,40 +7257,40 @@ function printSetupSummary(setup) {
7024
7257
  const codex = setup.codex;
7025
7258
  if (codex) {
7026
7259
  if (codex.agentsMd) {
7027
- const icon = fs24.existsSync("AGENTS.md") ? chalk9.yellow("~") : chalk9.green("+");
7260
+ const icon = fs25.existsSync("AGENTS.md") ? chalk10.yellow("~") : chalk10.green("+");
7028
7261
  const desc = getDescription("AGENTS.md");
7029
- console.log(` ${icon} ${chalk9.bold("AGENTS.md")}`);
7030
- if (desc) console.log(chalk9.dim(` ${desc}`));
7262
+ console.log(` ${icon} ${chalk10.bold("AGENTS.md")}`);
7263
+ if (desc) console.log(chalk10.dim(` ${desc}`));
7031
7264
  console.log("");
7032
7265
  }
7033
7266
  const codexSkills = codex.skills;
7034
7267
  if (Array.isArray(codexSkills) && codexSkills.length > 0) {
7035
7268
  for (const skill of codexSkills) {
7036
7269
  const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
7037
- const icon = fs24.existsSync(skillPath) ? chalk9.yellow("~") : chalk9.green("+");
7270
+ const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7038
7271
  const desc = getDescription(skillPath);
7039
- console.log(` ${icon} ${chalk9.bold(skillPath)}`);
7040
- console.log(chalk9.dim(` ${desc || skill.description || skill.name}`));
7272
+ console.log(` ${icon} ${chalk10.bold(skillPath)}`);
7273
+ console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
7041
7274
  console.log("");
7042
7275
  }
7043
7276
  }
7044
7277
  }
7045
7278
  if (cursor) {
7046
7279
  if (cursor.cursorrules) {
7047
- const icon = fs24.existsSync(".cursorrules") ? chalk9.yellow("~") : chalk9.green("+");
7280
+ const icon = fs25.existsSync(".cursorrules") ? chalk10.yellow("~") : chalk10.green("+");
7048
7281
  const desc = getDescription(".cursorrules");
7049
- console.log(` ${icon} ${chalk9.bold(".cursorrules")}`);
7050
- if (desc) console.log(chalk9.dim(` ${desc}`));
7282
+ console.log(` ${icon} ${chalk10.bold(".cursorrules")}`);
7283
+ if (desc) console.log(chalk10.dim(` ${desc}`));
7051
7284
  console.log("");
7052
7285
  }
7053
7286
  const cursorSkills = cursor.skills;
7054
7287
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
7055
7288
  for (const skill of cursorSkills) {
7056
7289
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
7057
- const icon = fs24.existsSync(skillPath) ? chalk9.yellow("~") : chalk9.green("+");
7290
+ const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7058
7291
  const desc = getDescription(skillPath);
7059
- console.log(` ${icon} ${chalk9.bold(skillPath)}`);
7060
- console.log(chalk9.dim(` ${desc || skill.description || skill.name}`));
7292
+ console.log(` ${icon} ${chalk10.bold(skillPath)}`);
7293
+ console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
7061
7294
  console.log("");
7062
7295
  }
7063
7296
  }
@@ -7065,14 +7298,14 @@ function printSetupSummary(setup) {
7065
7298
  if (Array.isArray(rules) && rules.length > 0) {
7066
7299
  for (const rule of rules) {
7067
7300
  const rulePath = `.cursor/rules/${rule.filename}`;
7068
- const icon = fs24.existsSync(rulePath) ? chalk9.yellow("~") : chalk9.green("+");
7301
+ const icon = fs25.existsSync(rulePath) ? chalk10.yellow("~") : chalk10.green("+");
7069
7302
  const desc = getDescription(rulePath);
7070
- console.log(` ${icon} ${chalk9.bold(rulePath)}`);
7303
+ console.log(` ${icon} ${chalk10.bold(rulePath)}`);
7071
7304
  if (desc) {
7072
- console.log(chalk9.dim(` ${desc}`));
7305
+ console.log(chalk10.dim(` ${desc}`));
7073
7306
  } else {
7074
7307
  const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
7075
- if (firstLine) console.log(chalk9.dim(` ${firstLine.trim().slice(0, 80)}`));
7308
+ if (firstLine) console.log(chalk10.dim(` ${firstLine.trim().slice(0, 80)}`));
7076
7309
  }
7077
7310
  console.log("");
7078
7311
  }
@@ -7080,12 +7313,12 @@ function printSetupSummary(setup) {
7080
7313
  }
7081
7314
  if (Array.isArray(deletions) && deletions.length > 0) {
7082
7315
  for (const del of deletions) {
7083
- console.log(` ${chalk9.red("-")} ${chalk9.bold(del.filePath)}`);
7084
- console.log(chalk9.dim(` ${del.reason}`));
7316
+ console.log(` ${chalk10.red("-")} ${chalk10.bold(del.filePath)}`);
7317
+ console.log(chalk10.dim(` ${del.reason}`));
7085
7318
  console.log("");
7086
7319
  }
7087
7320
  }
7088
- console.log(` ${chalk9.green("+")} ${chalk9.dim("new")} ${chalk9.yellow("~")} ${chalk9.dim("modified")} ${chalk9.red("-")} ${chalk9.dim("removed")}`);
7321
+ console.log(` ${chalk10.green("+")} ${chalk10.dim("new")} ${chalk10.yellow("~")} ${chalk10.dim("modified")} ${chalk10.red("-")} ${chalk10.dim("removed")}`);
7089
7322
  console.log("");
7090
7323
  }
7091
7324
  function derivePermissions(fingerprint) {
@@ -7129,8 +7362,8 @@ function ensurePermissions(fingerprint) {
7129
7362
  const settingsPath = ".claude/settings.json";
7130
7363
  let settings = {};
7131
7364
  try {
7132
- if (fs24.existsSync(settingsPath)) {
7133
- settings = JSON.parse(fs24.readFileSync(settingsPath, "utf-8"));
7365
+ if (fs25.existsSync(settingsPath)) {
7366
+ settings = JSON.parse(fs25.readFileSync(settingsPath, "utf-8"));
7134
7367
  }
7135
7368
  } catch {
7136
7369
  }
@@ -7139,32 +7372,32 @@ function ensurePermissions(fingerprint) {
7139
7372
  if (Array.isArray(allow) && allow.length > 0) return;
7140
7373
  permissions.allow = derivePermissions(fingerprint);
7141
7374
  settings.permissions = permissions;
7142
- if (!fs24.existsSync(".claude")) fs24.mkdirSync(".claude", { recursive: true });
7143
- fs24.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
7375
+ if (!fs25.existsSync(".claude")) fs25.mkdirSync(".claude", { recursive: true });
7376
+ fs25.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
7144
7377
  }
7145
7378
  function displayTokenUsage() {
7146
7379
  const summary = getUsageSummary();
7147
7380
  if (summary.length === 0) {
7148
- console.log(chalk9.dim(" Token tracking not available for this provider.\n"));
7381
+ console.log(chalk10.dim(" Token tracking not available for this provider.\n"));
7149
7382
  return;
7150
7383
  }
7151
- console.log(chalk9.bold(" Token usage:\n"));
7384
+ console.log(chalk10.bold(" Token usage:\n"));
7152
7385
  let totalIn = 0;
7153
7386
  let totalOut = 0;
7154
7387
  for (const m of summary) {
7155
7388
  totalIn += m.inputTokens;
7156
7389
  totalOut += m.outputTokens;
7157
- const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ? chalk9.dim(` (cache: ${m.cacheReadTokens.toLocaleString()} read, ${m.cacheWriteTokens.toLocaleString()} write)`) : "";
7158
- console.log(` ${chalk9.dim(m.model)}: ${m.inputTokens.toLocaleString()} in / ${m.outputTokens.toLocaleString()} out (${m.calls} call${m.calls === 1 ? "" : "s"})${cacheInfo}`);
7390
+ const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ? chalk10.dim(` (cache: ${m.cacheReadTokens.toLocaleString()} read, ${m.cacheWriteTokens.toLocaleString()} write)`) : "";
7391
+ console.log(` ${chalk10.dim(m.model)}: ${m.inputTokens.toLocaleString()} in / ${m.outputTokens.toLocaleString()} out (${m.calls} call${m.calls === 1 ? "" : "s"})${cacheInfo}`);
7159
7392
  }
7160
7393
  if (summary.length > 1) {
7161
- console.log(` ${chalk9.dim("Total")}: ${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out`);
7394
+ console.log(` ${chalk10.dim("Total")}: ${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out`);
7162
7395
  }
7163
7396
  console.log("");
7164
7397
  }
7165
7398
  function writeErrorLog(config, rawOutput, error, stopReason) {
7166
7399
  try {
7167
- const logPath = path19.join(process.cwd(), ".caliber", "error-log.md");
7400
+ const logPath = path20.join(process.cwd(), ".caliber", "error-log.md");
7168
7401
  const lines = [
7169
7402
  `# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
7170
7403
  "",
@@ -7177,16 +7410,16 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
7177
7410
  lines.push("## Error", "```", error, "```", "");
7178
7411
  }
7179
7412
  lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
7180
- fs24.mkdirSync(path19.join(process.cwd(), ".caliber"), { recursive: true });
7181
- fs24.writeFileSync(logPath, lines.join("\n"));
7182
- console.log(chalk9.dim(`
7413
+ fs25.mkdirSync(path20.join(process.cwd(), ".caliber"), { recursive: true });
7414
+ fs25.writeFileSync(logPath, lines.join("\n"));
7415
+ console.log(chalk10.dim(`
7183
7416
  Error log written to .caliber/error-log.md`));
7184
7417
  } catch {
7185
7418
  }
7186
7419
  }
7187
7420
 
7188
7421
  // src/commands/undo.ts
7189
- import chalk10 from "chalk";
7422
+ import chalk11 from "chalk";
7190
7423
  import ora3 from "ora";
7191
7424
  function undoCommand() {
7192
7425
  const spinner = ora3("Reverting setup...").start();
@@ -7199,27 +7432,27 @@ function undoCommand() {
7199
7432
  trackUndoExecuted();
7200
7433
  spinner.succeed("Setup reverted successfully.\n");
7201
7434
  if (restored.length > 0) {
7202
- console.log(chalk10.cyan(" Restored from backup:"));
7435
+ console.log(chalk11.cyan(" Restored from backup:"));
7203
7436
  for (const file of restored) {
7204
- console.log(` ${chalk10.green("\u21A9")} ${file}`);
7437
+ console.log(` ${chalk11.green("\u21A9")} ${file}`);
7205
7438
  }
7206
7439
  }
7207
7440
  if (removed.length > 0) {
7208
- console.log(chalk10.cyan(" Removed:"));
7441
+ console.log(chalk11.cyan(" Removed:"));
7209
7442
  for (const file of removed) {
7210
- console.log(` ${chalk10.red("\u2717")} ${file}`);
7443
+ console.log(` ${chalk11.red("\u2717")} ${file}`);
7211
7444
  }
7212
7445
  }
7213
7446
  console.log("");
7214
7447
  } catch (err) {
7215
- spinner.fail(chalk10.red(err instanceof Error ? err.message : "Undo failed"));
7448
+ spinner.fail(chalk11.red(err instanceof Error ? err.message : "Undo failed"));
7216
7449
  throw new Error("__exit__");
7217
7450
  }
7218
7451
  }
7219
7452
 
7220
7453
  // src/commands/status.ts
7221
- import chalk11 from "chalk";
7222
- import fs25 from "fs";
7454
+ import chalk12 from "chalk";
7455
+ import fs26 from "fs";
7223
7456
  init_config();
7224
7457
  async function statusCommand(options) {
7225
7458
  const config = loadConfig();
@@ -7233,40 +7466,40 @@ async function statusCommand(options) {
7233
7466
  }, null, 2));
7234
7467
  return;
7235
7468
  }
7236
- console.log(chalk11.bold("\nCaliber Status\n"));
7469
+ console.log(chalk12.bold("\nCaliber Status\n"));
7237
7470
  if (config) {
7238
- console.log(` LLM: ${chalk11.green(config.provider)} (${config.model})`);
7471
+ console.log(` LLM: ${chalk12.green(config.provider)} (${config.model})`);
7239
7472
  } else {
7240
- console.log(` LLM: ${chalk11.yellow("Not configured")} \u2014 run ${chalk11.hex("#83D1EB")("caliber config")}`);
7473
+ console.log(` LLM: ${chalk12.yellow("Not configured")} \u2014 run ${chalk12.hex("#83D1EB")("caliber config")}`);
7241
7474
  }
7242
7475
  if (!manifest) {
7243
- console.log(` Setup: ${chalk11.dim("No setup applied")}`);
7244
- console.log(chalk11.dim("\n Run ") + chalk11.hex("#83D1EB")("caliber init") + chalk11.dim(" to get started.\n"));
7476
+ console.log(` Setup: ${chalk12.dim("No setup applied")}`);
7477
+ console.log(chalk12.dim("\n Run ") + chalk12.hex("#83D1EB")("caliber init") + chalk12.dim(" to get started.\n"));
7245
7478
  return;
7246
7479
  }
7247
- console.log(` Files managed: ${chalk11.cyan(manifest.entries.length.toString())}`);
7480
+ console.log(` Files managed: ${chalk12.cyan(manifest.entries.length.toString())}`);
7248
7481
  for (const entry of manifest.entries) {
7249
- const exists = fs25.existsSync(entry.path);
7250
- const icon = exists ? chalk11.green("\u2713") : chalk11.red("\u2717");
7482
+ const exists = fs26.existsSync(entry.path);
7483
+ const icon = exists ? chalk12.green("\u2713") : chalk12.red("\u2717");
7251
7484
  console.log(` ${icon} ${entry.path} (${entry.action})`);
7252
7485
  }
7253
7486
  console.log("");
7254
7487
  }
7255
7488
 
7256
7489
  // src/commands/regenerate.ts
7257
- import chalk12 from "chalk";
7490
+ import chalk13 from "chalk";
7258
7491
  import ora4 from "ora";
7259
7492
  import select6 from "@inquirer/select";
7260
7493
  init_config();
7261
7494
  async function regenerateCommand(options) {
7262
7495
  const config = loadConfig();
7263
7496
  if (!config) {
7264
- console.log(chalk12.red("No LLM provider configured. Run ") + chalk12.hex("#83D1EB")("caliber config") + chalk12.red(" first."));
7497
+ console.log(chalk13.red("No LLM provider configured. Run ") + chalk13.hex("#83D1EB")("caliber config") + chalk13.red(" first."));
7265
7498
  throw new Error("__exit__");
7266
7499
  }
7267
7500
  const manifest = readManifest();
7268
7501
  if (!manifest) {
7269
- console.log(chalk12.yellow("No existing setup found. Run ") + chalk12.hex("#83D1EB")("caliber init") + chalk12.yellow(" first."));
7502
+ console.log(chalk13.yellow("No existing setup found. Run ") + chalk13.hex("#83D1EB")("caliber init") + chalk13.yellow(" first."));
7270
7503
  throw new Error("__exit__");
7271
7504
  }
7272
7505
  const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
@@ -7277,7 +7510,7 @@ async function regenerateCommand(options) {
7277
7510
  const baselineScore = computeLocalScore(process.cwd(), targetAgent);
7278
7511
  displayScoreSummary(baselineScore);
7279
7512
  if (baselineScore.score === 100) {
7280
- console.log(chalk12.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
7513
+ console.log(chalk13.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
7281
7514
  return;
7282
7515
  }
7283
7516
  const genSpinner = ora4("Regenerating setup...").start();
@@ -7318,18 +7551,18 @@ async function regenerateCommand(options) {
7318
7551
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
7319
7552
  const staged = stageFiles(setupFiles, process.cwd());
7320
7553
  const totalChanges = staged.newFiles + staged.modifiedFiles;
7321
- console.log(chalk12.dim(`
7322
- ${chalk12.green(`${staged.newFiles} new`)} / ${chalk12.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
7554
+ console.log(chalk13.dim(`
7555
+ ${chalk13.green(`${staged.newFiles} new`)} / ${chalk13.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
7323
7556
  `));
7324
7557
  if (totalChanges === 0) {
7325
- console.log(chalk12.dim(" No changes needed \u2014 your configs are already up to date.\n"));
7558
+ console.log(chalk13.dim(" No changes needed \u2014 your configs are already up to date.\n"));
7326
7559
  cleanupStaging();
7327
7560
  return;
7328
7561
  }
7329
7562
  if (options.dryRun) {
7330
- console.log(chalk12.yellow("[Dry run] Would write:"));
7563
+ console.log(chalk13.yellow("[Dry run] Would write:"));
7331
7564
  for (const f of staged.stagedFiles) {
7332
- console.log(` ${f.isNew ? chalk12.green("+") : chalk12.yellow("~")} ${f.relativePath}`);
7565
+ console.log(` ${f.isNew ? chalk13.green("+") : chalk13.yellow("~")} ${f.relativePath}`);
7333
7566
  }
7334
7567
  cleanupStaging();
7335
7568
  return;
@@ -7348,7 +7581,7 @@ async function regenerateCommand(options) {
7348
7581
  });
7349
7582
  cleanupStaging();
7350
7583
  if (action === "decline") {
7351
- console.log(chalk12.dim("Regeneration cancelled. No files were modified."));
7584
+ console.log(chalk13.dim("Regeneration cancelled. No files were modified."));
7352
7585
  return;
7353
7586
  }
7354
7587
  const writeSpinner = ora4("Writing config files...").start();
@@ -7356,20 +7589,20 @@ async function regenerateCommand(options) {
7356
7589
  const result = writeSetup(generatedSetup);
7357
7590
  writeSpinner.succeed("Config files written");
7358
7591
  for (const file of result.written) {
7359
- console.log(` ${chalk12.green("\u2713")} ${file}`);
7592
+ console.log(` ${chalk13.green("\u2713")} ${file}`);
7360
7593
  }
7361
7594
  if (result.deleted.length > 0) {
7362
7595
  for (const file of result.deleted) {
7363
- console.log(` ${chalk12.red("\u2717")} ${file}`);
7596
+ console.log(` ${chalk13.red("\u2717")} ${file}`);
7364
7597
  }
7365
7598
  }
7366
7599
  if (result.backupDir) {
7367
- console.log(chalk12.dim(`
7600
+ console.log(chalk13.dim(`
7368
7601
  Backups saved to ${result.backupDir}`));
7369
7602
  }
7370
7603
  } catch (err) {
7371
7604
  writeSpinner.fail("Failed to write files");
7372
- console.error(chalk12.red(err instanceof Error ? err.message : "Unknown error"));
7605
+ console.error(chalk13.red(err instanceof Error ? err.message : "Unknown error"));
7373
7606
  throw new Error("__exit__");
7374
7607
  }
7375
7608
  const sha = getCurrentHeadSha();
@@ -7381,25 +7614,25 @@ async function regenerateCommand(options) {
7381
7614
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
7382
7615
  if (afterScore.score < baselineScore.score) {
7383
7616
  console.log("");
7384
- console.log(chalk12.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
7617
+ console.log(chalk13.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
7385
7618
  try {
7386
7619
  const { restored, removed } = undoSetup();
7387
7620
  if (restored.length > 0 || removed.length > 0) {
7388
- console.log(chalk12.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
7621
+ console.log(chalk13.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
7389
7622
  }
7390
7623
  } catch {
7391
7624
  }
7392
- console.log(chalk12.dim(" Run ") + chalk12.hex("#83D1EB")("caliber init --force") + chalk12.dim(" to override.\n"));
7625
+ console.log(chalk13.dim(" Run ") + chalk13.hex("#83D1EB")("caliber init --force") + chalk13.dim(" to override.\n"));
7393
7626
  return;
7394
7627
  }
7395
7628
  displayScoreDelta(baselineScore, afterScore);
7396
7629
  trackRegenerateCompleted(action, Date.now());
7397
- console.log(chalk12.bold.green(" Regeneration complete!"));
7398
- console.log(chalk12.dim(" Run ") + chalk12.hex("#83D1EB")("caliber undo") + chalk12.dim(" to revert changes.\n"));
7630
+ console.log(chalk13.bold.green(" Regeneration complete!"));
7631
+ console.log(chalk13.dim(" Run ") + chalk13.hex("#83D1EB")("caliber undo") + chalk13.dim(" to revert changes.\n"));
7399
7632
  }
7400
7633
 
7401
7634
  // src/commands/score.ts
7402
- import chalk13 from "chalk";
7635
+ import chalk14 from "chalk";
7403
7636
  async function scoreCommand(options) {
7404
7637
  const dir = process.cwd();
7405
7638
  const target = options.agent ?? readState()?.targetAgent;
@@ -7414,22 +7647,22 @@ async function scoreCommand(options) {
7414
7647
  return;
7415
7648
  }
7416
7649
  displayScore(result);
7417
- const separator = chalk13.gray(" " + "\u2500".repeat(53));
7650
+ const separator = chalk14.gray(" " + "\u2500".repeat(53));
7418
7651
  console.log(separator);
7419
7652
  if (result.score < 40) {
7420
- console.log(chalk13.gray(" Run ") + chalk13.hex("#83D1EB")("caliber init") + chalk13.gray(" to generate a complete, optimized setup."));
7653
+ console.log(chalk14.gray(" Run ") + chalk14.hex("#83D1EB")("caliber init") + chalk14.gray(" to generate a complete, optimized setup."));
7421
7654
  } else if (result.score < 70) {
7422
- console.log(chalk13.gray(" Run ") + chalk13.hex("#83D1EB")("caliber init") + chalk13.gray(" to improve your setup."));
7655
+ console.log(chalk14.gray(" Run ") + chalk14.hex("#83D1EB")("caliber init") + chalk14.gray(" to improve your setup."));
7423
7656
  } else {
7424
- console.log(chalk13.green(" Looking good!") + chalk13.gray(" Run ") + chalk13.hex("#83D1EB")("caliber regenerate") + chalk13.gray(" to rebuild from scratch."));
7657
+ console.log(chalk14.green(" Looking good!") + chalk14.gray(" Run ") + chalk14.hex("#83D1EB")("caliber regenerate") + chalk14.gray(" to rebuild from scratch."));
7425
7658
  }
7426
7659
  console.log("");
7427
7660
  }
7428
7661
 
7429
7662
  // src/commands/refresh.ts
7430
- import fs29 from "fs";
7431
- import path23 from "path";
7432
- import chalk14 from "chalk";
7663
+ import fs30 from "fs";
7664
+ import path24 from "path";
7665
+ import chalk15 from "chalk";
7433
7666
  import ora5 from "ora";
7434
7667
 
7435
7668
  // src/lib/git-diff.ts
@@ -7506,37 +7739,37 @@ function collectDiff(lastSha) {
7506
7739
  }
7507
7740
 
7508
7741
  // src/writers/refresh.ts
7509
- import fs26 from "fs";
7510
- import path20 from "path";
7742
+ import fs27 from "fs";
7743
+ import path21 from "path";
7511
7744
  function writeRefreshDocs(docs) {
7512
7745
  const written = [];
7513
7746
  if (docs.claudeMd) {
7514
- fs26.writeFileSync("CLAUDE.md", docs.claudeMd);
7747
+ fs27.writeFileSync("CLAUDE.md", docs.claudeMd);
7515
7748
  written.push("CLAUDE.md");
7516
7749
  }
7517
7750
  if (docs.readmeMd) {
7518
- fs26.writeFileSync("README.md", docs.readmeMd);
7751
+ fs27.writeFileSync("README.md", docs.readmeMd);
7519
7752
  written.push("README.md");
7520
7753
  }
7521
7754
  if (docs.cursorrules) {
7522
- fs26.writeFileSync(".cursorrules", docs.cursorrules);
7755
+ fs27.writeFileSync(".cursorrules", docs.cursorrules);
7523
7756
  written.push(".cursorrules");
7524
7757
  }
7525
7758
  if (docs.cursorRules) {
7526
- const rulesDir = path20.join(".cursor", "rules");
7527
- if (!fs26.existsSync(rulesDir)) fs26.mkdirSync(rulesDir, { recursive: true });
7759
+ const rulesDir = path21.join(".cursor", "rules");
7760
+ if (!fs27.existsSync(rulesDir)) fs27.mkdirSync(rulesDir, { recursive: true });
7528
7761
  for (const rule of docs.cursorRules) {
7529
- const filePath = path20.join(rulesDir, rule.filename);
7530
- fs26.writeFileSync(filePath, rule.content);
7762
+ const filePath = path21.join(rulesDir, rule.filename);
7763
+ fs27.writeFileSync(filePath, rule.content);
7531
7764
  written.push(filePath);
7532
7765
  }
7533
7766
  }
7534
7767
  if (docs.claudeSkills) {
7535
- const skillsDir = path20.join(".claude", "skills");
7536
- if (!fs26.existsSync(skillsDir)) fs26.mkdirSync(skillsDir, { recursive: true });
7768
+ const skillsDir = path21.join(".claude", "skills");
7769
+ if (!fs27.existsSync(skillsDir)) fs27.mkdirSync(skillsDir, { recursive: true });
7537
7770
  for (const skill of docs.claudeSkills) {
7538
- const filePath = path20.join(skillsDir, skill.filename);
7539
- fs26.writeFileSync(filePath, skill.content);
7771
+ const filePath = path21.join(skillsDir, skill.filename);
7772
+ fs27.writeFileSync(filePath, skill.content);
7540
7773
  written.push(filePath);
7541
7774
  }
7542
7775
  }
@@ -7613,8 +7846,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
7613
7846
  }
7614
7847
 
7615
7848
  // src/learner/writer.ts
7616
- import fs27 from "fs";
7617
- import path21 from "path";
7849
+ import fs28 from "fs";
7850
+ import path22 from "path";
7618
7851
  var LEARNINGS_FILE = "CALIBER_LEARNINGS.md";
7619
7852
  var LEARNINGS_HEADER = `# Caliber Learnings
7620
7853
 
@@ -7698,16 +7931,16 @@ function deduplicateLearnedItems(existing, incoming) {
7698
7931
  function writeLearnedSection(content) {
7699
7932
  const existingSection = readLearnedSection();
7700
7933
  const { merged, newCount, newItems } = deduplicateLearnedItems(existingSection, content);
7701
- fs27.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
7934
+ fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
7702
7935
  return { newCount, newItems };
7703
7936
  }
7704
7937
  function writeLearnedSkill(skill) {
7705
- const skillDir = path21.join(".claude", "skills", skill.name);
7706
- if (!fs27.existsSync(skillDir)) fs27.mkdirSync(skillDir, { recursive: true });
7707
- const skillPath = path21.join(skillDir, "SKILL.md");
7708
- if (!skill.isNew && fs27.existsSync(skillPath)) {
7709
- const existing = fs27.readFileSync(skillPath, "utf-8");
7710
- fs27.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
7938
+ const skillDir = path22.join(".claude", "skills", skill.name);
7939
+ if (!fs28.existsSync(skillDir)) fs28.mkdirSync(skillDir, { recursive: true });
7940
+ const skillPath = path22.join(skillDir, "SKILL.md");
7941
+ if (!skill.isNew && fs28.existsSync(skillPath)) {
7942
+ const existing = fs28.readFileSync(skillPath, "utf-8");
7943
+ fs28.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
7711
7944
  } else {
7712
7945
  const frontmatter = [
7713
7946
  "---",
@@ -7716,37 +7949,37 @@ function writeLearnedSkill(skill) {
7716
7949
  "---",
7717
7950
  ""
7718
7951
  ].join("\n");
7719
- fs27.writeFileSync(skillPath, frontmatter + skill.content);
7952
+ fs28.writeFileSync(skillPath, frontmatter + skill.content);
7720
7953
  }
7721
7954
  return skillPath;
7722
7955
  }
7723
7956
  function readLearnedSection() {
7724
- if (fs27.existsSync(LEARNINGS_FILE)) {
7725
- const content2 = fs27.readFileSync(LEARNINGS_FILE, "utf-8");
7957
+ if (fs28.existsSync(LEARNINGS_FILE)) {
7958
+ const content2 = fs28.readFileSync(LEARNINGS_FILE, "utf-8");
7726
7959
  const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
7727
7960
  return bullets || null;
7728
7961
  }
7729
7962
  const claudeMdPath = "CLAUDE.md";
7730
- if (!fs27.existsSync(claudeMdPath)) return null;
7731
- const content = fs27.readFileSync(claudeMdPath, "utf-8");
7963
+ if (!fs28.existsSync(claudeMdPath)) return null;
7964
+ const content = fs28.readFileSync(claudeMdPath, "utf-8");
7732
7965
  const startIdx = content.indexOf(LEARNED_START);
7733
7966
  const endIdx = content.indexOf(LEARNED_END);
7734
7967
  if (startIdx === -1 || endIdx === -1) return null;
7735
7968
  return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
7736
7969
  }
7737
7970
  function migrateInlineLearnings() {
7738
- if (fs27.existsSync(LEARNINGS_FILE)) return false;
7971
+ if (fs28.existsSync(LEARNINGS_FILE)) return false;
7739
7972
  const claudeMdPath = "CLAUDE.md";
7740
- if (!fs27.existsSync(claudeMdPath)) return false;
7741
- const content = fs27.readFileSync(claudeMdPath, "utf-8");
7973
+ if (!fs28.existsSync(claudeMdPath)) return false;
7974
+ const content = fs28.readFileSync(claudeMdPath, "utf-8");
7742
7975
  const startIdx = content.indexOf(LEARNED_START);
7743
7976
  const endIdx = content.indexOf(LEARNED_END);
7744
7977
  if (startIdx === -1 || endIdx === -1) return false;
7745
7978
  const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
7746
7979
  if (!section) return false;
7747
- fs27.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
7980
+ fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
7748
7981
  const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
7749
- fs27.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
7982
+ fs28.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
7750
7983
  return true;
7751
7984
  }
7752
7985
 
@@ -7758,11 +7991,11 @@ function log2(quiet, ...args) {
7758
7991
  function discoverGitRepos(parentDir) {
7759
7992
  const repos = [];
7760
7993
  try {
7761
- const entries = fs29.readdirSync(parentDir, { withFileTypes: true });
7994
+ const entries = fs30.readdirSync(parentDir, { withFileTypes: true });
7762
7995
  for (const entry of entries) {
7763
7996
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
7764
- const childPath = path23.join(parentDir, entry.name);
7765
- if (fs29.existsSync(path23.join(childPath, ".git"))) {
7997
+ const childPath = path24.join(parentDir, entry.name);
7998
+ if (fs30.existsSync(path24.join(childPath, ".git"))) {
7766
7999
  repos.push(childPath);
7767
8000
  }
7768
8001
  }
@@ -7772,7 +8005,7 @@ function discoverGitRepos(parentDir) {
7772
8005
  }
7773
8006
  async function refreshSingleRepo(repoDir, options) {
7774
8007
  const quiet = !!options.quiet;
7775
- const prefix = options.label ? `${chalk14.bold(options.label)} ` : "";
8008
+ const prefix = options.label ? `${chalk15.bold(options.label)} ` : "";
7776
8009
  const state = readState();
7777
8010
  const lastSha = state?.lastRefreshSha ?? null;
7778
8011
  const diff = collectDiff(lastSha);
@@ -7781,7 +8014,7 @@ async function refreshSingleRepo(repoDir, options) {
7781
8014
  if (currentSha) {
7782
8015
  writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
7783
8016
  }
7784
- log2(quiet, chalk14.dim(`${prefix}No changes since last refresh.`));
8017
+ log2(quiet, chalk15.dim(`${prefix}No changes since last refresh.`));
7785
8018
  return;
7786
8019
  }
7787
8020
  const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
@@ -7815,10 +8048,10 @@ async function refreshSingleRepo(repoDir, options) {
7815
8048
  if (options.dryRun) {
7816
8049
  spinner?.info(`${prefix}Dry run \u2014 would update:`);
7817
8050
  for (const doc of response.docsUpdated) {
7818
- console.log(` ${chalk14.yellow("~")} ${doc}`);
8051
+ console.log(` ${chalk15.yellow("~")} ${doc}`);
7819
8052
  }
7820
8053
  if (response.changesSummary) {
7821
- console.log(chalk14.dim(`
8054
+ console.log(chalk15.dim(`
7822
8055
  ${response.changesSummary}`));
7823
8056
  }
7824
8057
  return;
@@ -7827,10 +8060,10 @@ async function refreshSingleRepo(repoDir, options) {
7827
8060
  trackRefreshCompleted(written.length, Date.now());
7828
8061
  spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
7829
8062
  for (const file of written) {
7830
- log2(quiet, ` ${chalk14.green("\u2713")} ${file}`);
8063
+ log2(quiet, ` ${chalk15.green("\u2713")} ${file}`);
7831
8064
  }
7832
8065
  if (response.changesSummary) {
7833
- log2(quiet, chalk14.dim(`
8066
+ log2(quiet, chalk15.dim(`
7834
8067
  ${response.changesSummary}`));
7835
8068
  }
7836
8069
  if (currentSha) {
@@ -7847,7 +8080,7 @@ async function refreshCommand(options) {
7847
8080
  const config = loadConfig();
7848
8081
  if (!config) {
7849
8082
  if (quiet) return;
7850
- console.log(chalk14.red("No LLM provider configured. Run ") + chalk14.hex("#83D1EB")("caliber config") + chalk14.red(" (e.g. choose Cursor) or set an API key."));
8083
+ console.log(chalk15.red("No LLM provider configured. Run ") + chalk15.hex("#83D1EB")("caliber config") + chalk15.red(" (e.g. choose Cursor) or set an API key."));
7851
8084
  throw new Error("__exit__");
7852
8085
  }
7853
8086
  await validateModel({ fast: true });
@@ -7858,20 +8091,20 @@ async function refreshCommand(options) {
7858
8091
  const repos = discoverGitRepos(process.cwd());
7859
8092
  if (repos.length === 0) {
7860
8093
  if (quiet) return;
7861
- console.log(chalk14.red("Not inside a git repository and no git repos found in child directories."));
8094
+ console.log(chalk15.red("Not inside a git repository and no git repos found in child directories."));
7862
8095
  throw new Error("__exit__");
7863
8096
  }
7864
- log2(quiet, chalk14.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
8097
+ log2(quiet, chalk15.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
7865
8098
  `));
7866
8099
  const originalDir = process.cwd();
7867
8100
  for (const repo of repos) {
7868
- const repoName = path23.basename(repo);
8101
+ const repoName = path24.basename(repo);
7869
8102
  try {
7870
8103
  process.chdir(repo);
7871
8104
  await refreshSingleRepo(repo, { ...options, label: repoName });
7872
8105
  } catch (err) {
7873
8106
  if (err instanceof Error && err.message === "__exit__") continue;
7874
- log2(quiet, chalk14.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
8107
+ log2(quiet, chalk15.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
7875
8108
  }
7876
8109
  }
7877
8110
  process.chdir(originalDir);
@@ -7879,13 +8112,13 @@ async function refreshCommand(options) {
7879
8112
  if (err instanceof Error && err.message === "__exit__") throw err;
7880
8113
  if (quiet) return;
7881
8114
  const msg = err instanceof Error ? err.message : "Unknown error";
7882
- console.log(chalk14.red(`Refresh failed: ${msg}`));
8115
+ console.log(chalk15.red(`Refresh failed: ${msg}`));
7883
8116
  throw new Error("__exit__");
7884
8117
  }
7885
8118
  }
7886
8119
 
7887
8120
  // src/commands/hooks.ts
7888
- import chalk15 from "chalk";
8121
+ import chalk16 from "chalk";
7889
8122
  var HOOKS = [
7890
8123
  {
7891
8124
  id: "session-end",
@@ -7905,13 +8138,13 @@ var HOOKS = [
7905
8138
  }
7906
8139
  ];
7907
8140
  function printStatus() {
7908
- console.log(chalk15.bold("\n Hooks\n"));
8141
+ console.log(chalk16.bold("\n Hooks\n"));
7909
8142
  for (const hook of HOOKS) {
7910
8143
  const installed = hook.isInstalled();
7911
- const icon = installed ? chalk15.green("\u2713") : chalk15.dim("\u2717");
7912
- const state = installed ? chalk15.green("enabled") : chalk15.dim("disabled");
8144
+ const icon = installed ? chalk16.green("\u2713") : chalk16.dim("\u2717");
8145
+ const state = installed ? chalk16.green("enabled") : chalk16.dim("disabled");
7913
8146
  console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
7914
- console.log(chalk15.dim(` ${hook.description}`));
8147
+ console.log(chalk16.dim(` ${hook.description}`));
7915
8148
  }
7916
8149
  console.log("");
7917
8150
  }
@@ -7920,9 +8153,9 @@ async function hooksCommand(options) {
7920
8153
  for (const hook of HOOKS) {
7921
8154
  const result = hook.install();
7922
8155
  if (result.alreadyInstalled) {
7923
- console.log(chalk15.dim(` ${hook.label} already enabled.`));
8156
+ console.log(chalk16.dim(` ${hook.label} already enabled.`));
7924
8157
  } else {
7925
- console.log(chalk15.green(" \u2713") + ` ${hook.label} enabled`);
8158
+ console.log(chalk16.green(" \u2713") + ` ${hook.label} enabled`);
7926
8159
  }
7927
8160
  }
7928
8161
  return;
@@ -7931,9 +8164,9 @@ async function hooksCommand(options) {
7931
8164
  for (const hook of HOOKS) {
7932
8165
  const result = hook.remove();
7933
8166
  if (result.notFound) {
7934
- console.log(chalk15.dim(` ${hook.label} already disabled.`));
8167
+ console.log(chalk16.dim(` ${hook.label} already disabled.`));
7935
8168
  } else {
7936
- console.log(chalk15.green(" \u2713") + ` ${hook.label} removed`);
8169
+ console.log(chalk16.green(" \u2713") + ` ${hook.label} removed`);
7937
8170
  }
7938
8171
  }
7939
8172
  return;
@@ -7948,18 +8181,18 @@ async function hooksCommand(options) {
7948
8181
  const states = HOOKS.map((h) => h.isInstalled());
7949
8182
  function render() {
7950
8183
  const lines = [];
7951
- lines.push(chalk15.bold(" Hooks"));
8184
+ lines.push(chalk16.bold(" Hooks"));
7952
8185
  lines.push("");
7953
8186
  for (let i = 0; i < HOOKS.length; i++) {
7954
8187
  const hook = HOOKS[i];
7955
8188
  const enabled = states[i];
7956
- const toggle = enabled ? chalk15.green("[on] ") : chalk15.dim("[off]");
7957
- const ptr = i === cursor ? chalk15.cyan(">") : " ";
8189
+ const toggle = enabled ? chalk16.green("[on] ") : chalk16.dim("[off]");
8190
+ const ptr = i === cursor ? chalk16.cyan(">") : " ";
7958
8191
  lines.push(` ${ptr} ${toggle} ${hook.label}`);
7959
- lines.push(chalk15.dim(` ${hook.description}`));
8192
+ lines.push(chalk16.dim(` ${hook.description}`));
7960
8193
  }
7961
8194
  lines.push("");
7962
- lines.push(chalk15.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
8195
+ lines.push(chalk16.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
7963
8196
  return lines.join("\n");
7964
8197
  }
7965
8198
  function draw(initial) {
@@ -7990,16 +8223,16 @@ async function hooksCommand(options) {
7990
8223
  const wantEnabled = states[i];
7991
8224
  if (wantEnabled && !wasInstalled) {
7992
8225
  hook.install();
7993
- console.log(chalk15.green(" \u2713") + ` ${hook.label} enabled`);
8226
+ console.log(chalk16.green(" \u2713") + ` ${hook.label} enabled`);
7994
8227
  changed++;
7995
8228
  } else if (!wantEnabled && wasInstalled) {
7996
8229
  hook.remove();
7997
- console.log(chalk15.green(" \u2713") + ` ${hook.label} disabled`);
8230
+ console.log(chalk16.green(" \u2713") + ` ${hook.label} disabled`);
7998
8231
  changed++;
7999
8232
  }
8000
8233
  }
8001
8234
  if (changed === 0) {
8002
- console.log(chalk15.dim(" No changes."));
8235
+ console.log(chalk16.dim(" No changes."));
8003
8236
  }
8004
8237
  console.log("");
8005
8238
  }
@@ -8035,7 +8268,7 @@ async function hooksCommand(options) {
8035
8268
  case "\x1B":
8036
8269
  case "":
8037
8270
  cleanup();
8038
- console.log(chalk15.dim("\n Cancelled.\n"));
8271
+ console.log(chalk16.dim("\n Cancelled.\n"));
8039
8272
  resolve2();
8040
8273
  break;
8041
8274
  }
@@ -8046,51 +8279,51 @@ async function hooksCommand(options) {
8046
8279
 
8047
8280
  // src/commands/config.ts
8048
8281
  init_config();
8049
- import chalk16 from "chalk";
8282
+ import chalk17 from "chalk";
8050
8283
  async function configCommand() {
8051
8284
  const existing = loadConfig();
8052
8285
  if (existing) {
8053
8286
  const displayModel = getDisplayModel(existing);
8054
8287
  const fastModel = getFastModel();
8055
- console.log(chalk16.bold("\nCurrent Configuration\n"));
8056
- console.log(` Provider: ${chalk16.cyan(existing.provider)}`);
8057
- console.log(` Model: ${chalk16.cyan(displayModel)}`);
8288
+ console.log(chalk17.bold("\nCurrent Configuration\n"));
8289
+ console.log(` Provider: ${chalk17.cyan(existing.provider)}`);
8290
+ console.log(` Model: ${chalk17.cyan(displayModel)}`);
8058
8291
  if (fastModel) {
8059
- console.log(` Scan: ${chalk16.cyan(fastModel)}`);
8292
+ console.log(` Scan: ${chalk17.cyan(fastModel)}`);
8060
8293
  }
8061
8294
  if (existing.apiKey) {
8062
8295
  const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
8063
- console.log(` API Key: ${chalk16.dim(masked)}`);
8296
+ console.log(` API Key: ${chalk17.dim(masked)}`);
8064
8297
  }
8065
8298
  if (existing.provider === "cursor") {
8066
- console.log(` Seat: ${chalk16.dim("Cursor (agent acp)")}`);
8299
+ console.log(` Seat: ${chalk17.dim("Cursor (agent acp)")}`);
8067
8300
  }
8068
8301
  if (existing.provider === "claude-cli") {
8069
- console.log(` Seat: ${chalk16.dim("Claude Code (claude -p)")}`);
8302
+ console.log(` Seat: ${chalk17.dim("Claude Code (claude -p)")}`);
8070
8303
  }
8071
8304
  if (existing.baseUrl) {
8072
- console.log(` Base URL: ${chalk16.dim(existing.baseUrl)}`);
8305
+ console.log(` Base URL: ${chalk17.dim(existing.baseUrl)}`);
8073
8306
  }
8074
8307
  if (existing.vertexProjectId) {
8075
- console.log(` Vertex Project: ${chalk16.dim(existing.vertexProjectId)}`);
8076
- console.log(` Vertex Region: ${chalk16.dim(existing.vertexRegion || "us-east5")}`);
8308
+ console.log(` Vertex Project: ${chalk17.dim(existing.vertexProjectId)}`);
8309
+ console.log(` Vertex Region: ${chalk17.dim(existing.vertexRegion || "us-east5")}`);
8077
8310
  }
8078
- console.log(` Source: ${chalk16.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())}`);
8311
+ console.log(` Source: ${chalk17.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())}`);
8079
8312
  console.log("");
8080
8313
  }
8081
8314
  await runInteractiveProviderSetup();
8082
8315
  const updated = loadConfig();
8083
8316
  if (updated) trackConfigProviderSet(updated.provider);
8084
- console.log(chalk16.green("\n\u2713 Configuration saved"));
8085
- console.log(chalk16.dim(` ${getConfigFilePath()}
8317
+ console.log(chalk17.green("\n\u2713 Configuration saved"));
8318
+ console.log(chalk17.dim(` ${getConfigFilePath()}
8086
8319
  `));
8087
- console.log(chalk16.dim(" You can also set environment variables instead:"));
8088
- console.log(chalk16.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
8320
+ console.log(chalk17.dim(" You can also set environment variables instead:"));
8321
+ console.log(chalk17.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
8089
8322
  }
8090
8323
 
8091
8324
  // src/commands/learn.ts
8092
- import fs31 from "fs";
8093
- import chalk17 from "chalk";
8325
+ import fs32 from "fs";
8326
+ import chalk18 from "chalk";
8094
8327
 
8095
8328
  // src/learner/stdin.ts
8096
8329
  var STDIN_TIMEOUT_MS = 5e3;
@@ -8121,8 +8354,8 @@ function readStdin() {
8121
8354
 
8122
8355
  // src/learner/storage.ts
8123
8356
  init_constants();
8124
- import fs30 from "fs";
8125
- import path24 from "path";
8357
+ import fs31 from "fs";
8358
+ import path25 from "path";
8126
8359
  var MAX_RESPONSE_LENGTH = 2e3;
8127
8360
  var DEFAULT_STATE = {
8128
8361
  sessionId: null,
@@ -8130,15 +8363,15 @@ var DEFAULT_STATE = {
8130
8363
  lastAnalysisTimestamp: null
8131
8364
  };
8132
8365
  function ensureLearningDir() {
8133
- if (!fs30.existsSync(LEARNING_DIR)) {
8134
- fs30.mkdirSync(LEARNING_DIR, { recursive: true });
8366
+ if (!fs31.existsSync(LEARNING_DIR)) {
8367
+ fs31.mkdirSync(LEARNING_DIR, { recursive: true });
8135
8368
  }
8136
8369
  }
8137
8370
  function sessionFilePath() {
8138
- return path24.join(LEARNING_DIR, LEARNING_SESSION_FILE);
8371
+ return path25.join(LEARNING_DIR, LEARNING_SESSION_FILE);
8139
8372
  }
8140
8373
  function stateFilePath() {
8141
- return path24.join(LEARNING_DIR, LEARNING_STATE_FILE);
8374
+ return path25.join(LEARNING_DIR, LEARNING_STATE_FILE);
8142
8375
  }
8143
8376
  function truncateResponse(response) {
8144
8377
  const str = JSON.stringify(response);
@@ -8149,29 +8382,29 @@ function appendEvent(event) {
8149
8382
  ensureLearningDir();
8150
8383
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
8151
8384
  const filePath = sessionFilePath();
8152
- fs30.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
8385
+ fs31.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
8153
8386
  const count = getEventCount();
8154
8387
  if (count > LEARNING_MAX_EVENTS) {
8155
- const lines = fs30.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8388
+ const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8156
8389
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
8157
- fs30.writeFileSync(filePath, kept.join("\n") + "\n");
8390
+ fs31.writeFileSync(filePath, kept.join("\n") + "\n");
8158
8391
  }
8159
8392
  }
8160
8393
  function appendPromptEvent(event) {
8161
8394
  ensureLearningDir();
8162
8395
  const filePath = sessionFilePath();
8163
- fs30.appendFileSync(filePath, JSON.stringify(event) + "\n");
8396
+ fs31.appendFileSync(filePath, JSON.stringify(event) + "\n");
8164
8397
  const count = getEventCount();
8165
8398
  if (count > LEARNING_MAX_EVENTS) {
8166
- const lines = fs30.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8399
+ const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8167
8400
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
8168
- fs30.writeFileSync(filePath, kept.join("\n") + "\n");
8401
+ fs31.writeFileSync(filePath, kept.join("\n") + "\n");
8169
8402
  }
8170
8403
  }
8171
8404
  function readAllEvents() {
8172
8405
  const filePath = sessionFilePath();
8173
- if (!fs30.existsSync(filePath)) return [];
8174
- const lines = fs30.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8406
+ if (!fs31.existsSync(filePath)) return [];
8407
+ const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8175
8408
  const events = [];
8176
8409
  for (const line of lines) {
8177
8410
  try {
@@ -8183,26 +8416,26 @@ function readAllEvents() {
8183
8416
  }
8184
8417
  function getEventCount() {
8185
8418
  const filePath = sessionFilePath();
8186
- if (!fs30.existsSync(filePath)) return 0;
8187
- const content = fs30.readFileSync(filePath, "utf-8");
8419
+ if (!fs31.existsSync(filePath)) return 0;
8420
+ const content = fs31.readFileSync(filePath, "utf-8");
8188
8421
  return content.split("\n").filter(Boolean).length;
8189
8422
  }
8190
8423
  function clearSession() {
8191
8424
  const filePath = sessionFilePath();
8192
- if (fs30.existsSync(filePath)) fs30.unlinkSync(filePath);
8425
+ if (fs31.existsSync(filePath)) fs31.unlinkSync(filePath);
8193
8426
  }
8194
8427
  function readState2() {
8195
8428
  const filePath = stateFilePath();
8196
- if (!fs30.existsSync(filePath)) return { ...DEFAULT_STATE };
8429
+ if (!fs31.existsSync(filePath)) return { ...DEFAULT_STATE };
8197
8430
  try {
8198
- return JSON.parse(fs30.readFileSync(filePath, "utf-8"));
8431
+ return JSON.parse(fs31.readFileSync(filePath, "utf-8"));
8199
8432
  } catch {
8200
8433
  return { ...DEFAULT_STATE };
8201
8434
  }
8202
8435
  }
8203
8436
  function writeState2(state) {
8204
8437
  ensureLearningDir();
8205
- fs30.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
8438
+ fs31.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
8206
8439
  }
8207
8440
  function resetState() {
8208
8441
  writeState2({ ...DEFAULT_STATE });
@@ -8210,14 +8443,14 @@ function resetState() {
8210
8443
  var LOCK_FILE2 = "finalize.lock";
8211
8444
  var LOCK_STALE_MS = 5 * 60 * 1e3;
8212
8445
  function lockFilePath() {
8213
- return path24.join(LEARNING_DIR, LOCK_FILE2);
8446
+ return path25.join(LEARNING_DIR, LOCK_FILE2);
8214
8447
  }
8215
8448
  function acquireFinalizeLock() {
8216
8449
  ensureLearningDir();
8217
8450
  const lockPath = lockFilePath();
8218
- if (fs30.existsSync(lockPath)) {
8451
+ if (fs31.existsSync(lockPath)) {
8219
8452
  try {
8220
- const stat = fs30.statSync(lockPath);
8453
+ const stat = fs31.statSync(lockPath);
8221
8454
  if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
8222
8455
  return false;
8223
8456
  }
@@ -8225,7 +8458,7 @@ function acquireFinalizeLock() {
8225
8458
  }
8226
8459
  }
8227
8460
  try {
8228
- fs30.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
8461
+ fs31.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
8229
8462
  return true;
8230
8463
  } catch {
8231
8464
  return false;
@@ -8234,7 +8467,7 @@ function acquireFinalizeLock() {
8234
8467
  function releaseFinalizeLock() {
8235
8468
  const lockPath = lockFilePath();
8236
8469
  try {
8237
- if (fs30.existsSync(lockPath)) fs30.unlinkSync(lockPath);
8470
+ if (fs31.existsSync(lockPath)) fs31.unlinkSync(lockPath);
8238
8471
  } catch {
8239
8472
  }
8240
8473
  }
@@ -8406,26 +8639,26 @@ async function learnFinalizeCommand(options) {
8406
8639
  if (!options?.force) {
8407
8640
  const { isCaliberRunning: isCaliberRunning2 } = await Promise.resolve().then(() => (init_lock(), lock_exports));
8408
8641
  if (isCaliberRunning2()) {
8409
- console.log(chalk17.dim("caliber: skipping finalize \u2014 another caliber process is running"));
8642
+ console.log(chalk18.dim("caliber: skipping finalize \u2014 another caliber process is running"));
8410
8643
  return;
8411
8644
  }
8412
8645
  }
8413
8646
  if (!acquireFinalizeLock()) {
8414
- console.log(chalk17.dim("caliber: skipping finalize \u2014 another finalize is in progress"));
8647
+ console.log(chalk18.dim("caliber: skipping finalize \u2014 another finalize is in progress"));
8415
8648
  return;
8416
8649
  }
8417
8650
  let analyzed = false;
8418
8651
  try {
8419
8652
  const config = loadConfig();
8420
8653
  if (!config) {
8421
- console.log(chalk17.yellow("caliber: no LLM provider configured \u2014 run `caliber config` first"));
8654
+ console.log(chalk18.yellow("caliber: no LLM provider configured \u2014 run `caliber config` first"));
8422
8655
  clearSession();
8423
8656
  resetState();
8424
8657
  return;
8425
8658
  }
8426
8659
  const events = readAllEvents();
8427
8660
  if (events.length < MIN_EVENTS_FOR_ANALYSIS) {
8428
- console.log(chalk17.dim(`caliber: ${events.length}/${MIN_EVENTS_FOR_ANALYSIS} events recorded \u2014 need more before analysis`));
8661
+ console.log(chalk18.dim(`caliber: ${events.length}/${MIN_EVENTS_FOR_ANALYSIS} events recorded \u2014 need more before analysis`));
8429
8662
  return;
8430
8663
  }
8431
8664
  await validateModel({ fast: true });
@@ -8446,15 +8679,15 @@ async function learnFinalizeCommand(options) {
8446
8679
  skills: response.skills
8447
8680
  });
8448
8681
  if (result.newItemCount > 0) {
8449
- console.log(chalk17.dim(`caliber: learned ${result.newItemCount} new pattern${result.newItemCount === 1 ? "" : "s"}`));
8682
+ console.log(chalk18.dim(`caliber: learned ${result.newItemCount} new pattern${result.newItemCount === 1 ? "" : "s"}`));
8450
8683
  for (const item of result.newItems) {
8451
- console.log(chalk17.dim(` + ${item.replace(/^- /, "").slice(0, 80)}`));
8684
+ console.log(chalk18.dim(` + ${item.replace(/^- /, "").slice(0, 80)}`));
8452
8685
  }
8453
8686
  }
8454
8687
  }
8455
8688
  } catch (err) {
8456
8689
  if (options?.force) {
8457
- console.error(chalk17.red("caliber: finalize failed \u2014"), err instanceof Error ? err.message : err);
8690
+ console.error(chalk18.red("caliber: finalize failed \u2014"), err instanceof Error ? err.message : err);
8458
8691
  }
8459
8692
  } finally {
8460
8693
  if (analyzed) {
@@ -8466,48 +8699,48 @@ async function learnFinalizeCommand(options) {
8466
8699
  }
8467
8700
  async function learnInstallCommand() {
8468
8701
  let anyInstalled = false;
8469
- if (fs31.existsSync(".claude")) {
8702
+ if (fs32.existsSync(".claude")) {
8470
8703
  const r = installLearningHooks();
8471
8704
  if (r.installed) {
8472
- console.log(chalk17.green("\u2713") + " Claude Code learning hooks installed");
8705
+ console.log(chalk18.green("\u2713") + " Claude Code learning hooks installed");
8473
8706
  anyInstalled = true;
8474
8707
  } else if (r.alreadyInstalled) {
8475
- console.log(chalk17.dim(" Claude Code hooks already installed"));
8708
+ console.log(chalk18.dim(" Claude Code hooks already installed"));
8476
8709
  }
8477
8710
  }
8478
- if (fs31.existsSync(".cursor")) {
8711
+ if (fs32.existsSync(".cursor")) {
8479
8712
  const r = installCursorLearningHooks();
8480
8713
  if (r.installed) {
8481
- console.log(chalk17.green("\u2713") + " Cursor learning hooks installed");
8714
+ console.log(chalk18.green("\u2713") + " Cursor learning hooks installed");
8482
8715
  anyInstalled = true;
8483
8716
  } else if (r.alreadyInstalled) {
8484
- console.log(chalk17.dim(" Cursor hooks already installed"));
8717
+ console.log(chalk18.dim(" Cursor hooks already installed"));
8485
8718
  }
8486
8719
  }
8487
- if (!fs31.existsSync(".claude") && !fs31.existsSync(".cursor")) {
8488
- console.log(chalk17.yellow("No .claude/ or .cursor/ directory found."));
8489
- console.log(chalk17.dim(" Run `caliber init` first, or create the directory manually."));
8720
+ if (!fs32.existsSync(".claude") && !fs32.existsSync(".cursor")) {
8721
+ console.log(chalk18.yellow("No .claude/ or .cursor/ directory found."));
8722
+ console.log(chalk18.dim(" Run `caliber init` first, or create the directory manually."));
8490
8723
  return;
8491
8724
  }
8492
8725
  if (anyInstalled) {
8493
- console.log(chalk17.dim(` Tool usage will be recorded and learnings extracted after \u2265${MIN_EVENTS_FOR_ANALYSIS} events.`));
8494
- console.log(chalk17.dim(" Learnings written to CALIBER_LEARNINGS.md."));
8726
+ console.log(chalk18.dim(` Tool usage will be recorded and learnings extracted after \u2265${MIN_EVENTS_FOR_ANALYSIS} events.`));
8727
+ console.log(chalk18.dim(" Learnings written to CALIBER_LEARNINGS.md."));
8495
8728
  }
8496
8729
  }
8497
8730
  async function learnRemoveCommand() {
8498
8731
  let anyRemoved = false;
8499
8732
  const r1 = removeLearningHooks();
8500
8733
  if (r1.removed) {
8501
- console.log(chalk17.green("\u2713") + " Claude Code learning hooks removed");
8734
+ console.log(chalk18.green("\u2713") + " Claude Code learning hooks removed");
8502
8735
  anyRemoved = true;
8503
8736
  }
8504
8737
  const r2 = removeCursorLearningHooks();
8505
8738
  if (r2.removed) {
8506
- console.log(chalk17.green("\u2713") + " Cursor learning hooks removed");
8739
+ console.log(chalk18.green("\u2713") + " Cursor learning hooks removed");
8507
8740
  anyRemoved = true;
8508
8741
  }
8509
8742
  if (!anyRemoved) {
8510
- console.log(chalk17.dim("No learning hooks found."));
8743
+ console.log(chalk18.dim("No learning hooks found."));
8511
8744
  }
8512
8745
  }
8513
8746
  async function learnStatusCommand() {
@@ -8515,41 +8748,41 @@ async function learnStatusCommand() {
8515
8748
  const cursorInstalled = areCursorLearningHooksInstalled();
8516
8749
  const state = readState2();
8517
8750
  const eventCount = getEventCount();
8518
- console.log(chalk17.bold("Session Learning Status"));
8751
+ console.log(chalk18.bold("Session Learning Status"));
8519
8752
  console.log();
8520
8753
  if (claudeInstalled) {
8521
- console.log(chalk17.green("\u2713") + " Claude Code hooks " + chalk17.green("installed"));
8754
+ console.log(chalk18.green("\u2713") + " Claude Code hooks " + chalk18.green("installed"));
8522
8755
  } else {
8523
- console.log(chalk17.dim("\u2717") + " Claude Code hooks " + chalk17.dim("not installed"));
8756
+ console.log(chalk18.dim("\u2717") + " Claude Code hooks " + chalk18.dim("not installed"));
8524
8757
  }
8525
8758
  if (cursorInstalled) {
8526
- console.log(chalk17.green("\u2713") + " Cursor hooks " + chalk17.green("installed"));
8759
+ console.log(chalk18.green("\u2713") + " Cursor hooks " + chalk18.green("installed"));
8527
8760
  } else {
8528
- console.log(chalk17.dim("\u2717") + " Cursor hooks " + chalk17.dim("not installed"));
8761
+ console.log(chalk18.dim("\u2717") + " Cursor hooks " + chalk18.dim("not installed"));
8529
8762
  }
8530
8763
  if (!claudeInstalled && !cursorInstalled) {
8531
- console.log(chalk17.dim(" Run `caliber learn install` to enable session learning."));
8764
+ console.log(chalk18.dim(" Run `caliber learn install` to enable session learning."));
8532
8765
  }
8533
8766
  console.log();
8534
- console.log(`Events recorded: ${chalk17.cyan(String(eventCount))}`);
8535
- console.log(`Threshold for analysis: ${chalk17.cyan(String(MIN_EVENTS_FOR_ANALYSIS))}`);
8767
+ console.log(`Events recorded: ${chalk18.cyan(String(eventCount))}`);
8768
+ console.log(`Threshold for analysis: ${chalk18.cyan(String(MIN_EVENTS_FOR_ANALYSIS))}`);
8536
8769
  if (state.lastAnalysisTimestamp) {
8537
- console.log(`Last analysis: ${chalk17.cyan(state.lastAnalysisTimestamp)}`);
8770
+ console.log(`Last analysis: ${chalk18.cyan(state.lastAnalysisTimestamp)}`);
8538
8771
  } else {
8539
- console.log(`Last analysis: ${chalk17.dim("none")}`);
8772
+ console.log(`Last analysis: ${chalk18.dim("none")}`);
8540
8773
  }
8541
8774
  const learnedSection = readLearnedSection();
8542
8775
  if (learnedSection) {
8543
8776
  const lineCount = learnedSection.split("\n").filter(Boolean).length;
8544
8777
  console.log(`
8545
- Learned items in CALIBER_LEARNINGS.md: ${chalk17.cyan(String(lineCount))}`);
8778
+ Learned items in CALIBER_LEARNINGS.md: ${chalk18.cyan(String(lineCount))}`);
8546
8779
  }
8547
8780
  }
8548
8781
 
8549
8782
  // src/cli.ts
8550
- var __dirname = path25.dirname(fileURLToPath(import.meta.url));
8783
+ var __dirname = path26.dirname(fileURLToPath(import.meta.url));
8551
8784
  var pkg = JSON.parse(
8552
- fs32.readFileSync(path25.resolve(__dirname, "..", "package.json"), "utf-8")
8785
+ fs33.readFileSync(path26.resolve(__dirname, "..", "package.json"), "utf-8")
8553
8786
  );
8554
8787
  var program = new Command();
8555
8788
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -8623,22 +8856,42 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
8623
8856
  learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
8624
8857
 
8625
8858
  // src/utils/version-check.ts
8626
- import fs33 from "fs";
8627
- import path26 from "path";
8859
+ import fs34 from "fs";
8860
+ import path27 from "path";
8628
8861
  import { fileURLToPath as fileURLToPath2 } from "url";
8629
8862
  import { execSync as execSync14 } from "child_process";
8630
- import chalk18 from "chalk";
8863
+ import chalk19 from "chalk";
8631
8864
  import ora6 from "ora";
8632
8865
  import confirm2 from "@inquirer/confirm";
8633
- var __dirname_vc = path26.dirname(fileURLToPath2(import.meta.url));
8866
+ var __dirname_vc = path27.dirname(fileURLToPath2(import.meta.url));
8634
8867
  var pkg2 = JSON.parse(
8635
- fs33.readFileSync(path26.resolve(__dirname_vc, "..", "package.json"), "utf-8")
8868
+ fs34.readFileSync(path27.resolve(__dirname_vc, "..", "package.json"), "utf-8")
8636
8869
  );
8870
+ function getChannel(version) {
8871
+ const match = version.match(/-(dev|next)\./);
8872
+ return match ? match[1] : "latest";
8873
+ }
8874
+ function isNewer(registry, current) {
8875
+ const parse = (v) => {
8876
+ const [core, pre] = v.split("-");
8877
+ const parts = core.split(".").map(Number);
8878
+ return { major: parts[0], minor: parts[1], patch: parts[2], pre };
8879
+ };
8880
+ const r = parse(registry);
8881
+ const c = parse(current);
8882
+ if (r.major !== c.major) return r.major > c.major;
8883
+ if (r.minor !== c.minor) return r.minor > c.minor;
8884
+ if (r.patch !== c.patch) return r.patch > c.patch;
8885
+ if (!r.pre && c.pre) return true;
8886
+ if (r.pre && !c.pre) return false;
8887
+ if (r.pre && c.pre) return r.pre > c.pre;
8888
+ return false;
8889
+ }
8637
8890
  function getInstalledVersion() {
8638
8891
  try {
8639
8892
  const globalRoot = execSync14("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
8640
- const pkgPath = path26.join(globalRoot, "@rely-ai", "caliber", "package.json");
8641
- return JSON.parse(fs33.readFileSync(pkgPath, "utf-8")).version;
8893
+ const pkgPath = path27.join(globalRoot, "@rely-ai", "caliber", "package.json");
8894
+ return JSON.parse(fs34.readFileSync(pkgPath, "utf-8")).version;
8642
8895
  } catch {
8643
8896
  return null;
8644
8897
  }
@@ -8646,9 +8899,11 @@ function getInstalledVersion() {
8646
8899
  async function checkForUpdates() {
8647
8900
  if (process.env.CALIBER_SKIP_UPDATE_CHECK) return;
8648
8901
  try {
8902
+ const current = pkg2.version;
8903
+ const channel = getChannel(current);
8649
8904
  const controller = new AbortController();
8650
8905
  const timeout = setTimeout(() => controller.abort(), 2e3);
8651
- const res = await fetch("https://registry.npmjs.org/@rely-ai/caliber/latest", {
8906
+ const res = await fetch(`https://registry.npmjs.org/@rely-ai/caliber/${channel}`, {
8652
8907
  signal: controller.signal
8653
8908
  });
8654
8909
  clearTimeout(timeout);
@@ -8656,22 +8911,22 @@ async function checkForUpdates() {
8656
8911
  const data = await res.json();
8657
8912
  const latest = data.version;
8658
8913
  if (!latest) return;
8659
- const current = pkg2.version;
8660
- if (current === latest) return;
8914
+ if (!isNewer(latest, current)) return;
8661
8915
  const isInteractive = process.stdin.isTTY === true;
8662
8916
  if (!isInteractive) {
8917
+ const installTag = channel === "latest" ? "" : `@${channel}`;
8663
8918
  console.log(
8664
- chalk18.yellow(
8919
+ chalk19.yellow(
8665
8920
  `
8666
8921
  Update available: ${current} -> ${latest}
8667
- Run ${chalk18.bold("npm install -g @rely-ai/caliber")} to upgrade.
8922
+ Run ${chalk19.bold(`npm install -g @rely-ai/caliber${installTag}`)} to upgrade.
8668
8923
  `
8669
8924
  )
8670
8925
  );
8671
8926
  return;
8672
8927
  }
8673
8928
  console.log(
8674
- chalk18.yellow(`
8929
+ chalk19.yellow(`
8675
8930
  Update available: ${current} -> ${latest}`)
8676
8931
  );
8677
8932
  const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
@@ -8679,9 +8934,10 @@ Update available: ${current} -> ${latest}`)
8679
8934
  console.log();
8680
8935
  return;
8681
8936
  }
8937
+ const tag = channel === "latest" ? latest : channel;
8682
8938
  const spinner = ora6("Updating caliber...").start();
8683
8939
  try {
8684
- execSync14(`npm install -g @rely-ai/caliber@${latest}`, {
8940
+ execSync14(`npm install -g @rely-ai/caliber@${tag}`, {
8685
8941
  stdio: "pipe",
8686
8942
  timeout: 12e4,
8687
8943
  env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
@@ -8689,13 +8945,13 @@ Update available: ${current} -> ${latest}`)
8689
8945
  const installed = getInstalledVersion();
8690
8946
  if (installed !== latest) {
8691
8947
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
8692
- console.log(chalk18.yellow(`Run ${chalk18.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
8948
+ console.log(chalk19.yellow(`Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
8693
8949
  `));
8694
8950
  return;
8695
8951
  }
8696
- spinner.succeed(chalk18.green(`Updated to ${latest}`));
8952
+ spinner.succeed(chalk19.green(`Updated to ${latest}`));
8697
8953
  const args = process.argv.slice(2);
8698
- console.log(chalk18.dim(`
8954
+ console.log(chalk19.dim(`
8699
8955
  Restarting: caliber ${args.join(" ")}
8700
8956
  `));
8701
8957
  execSync14(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
@@ -8708,11 +8964,11 @@ Restarting: caliber ${args.join(" ")}
8708
8964
  if (err instanceof Error) {
8709
8965
  const stderr = err.stderr;
8710
8966
  const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
8711
- if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk18.dim(` ${errMsg}`));
8967
+ if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk19.dim(` ${errMsg}`));
8712
8968
  }
8713
8969
  console.log(
8714
- chalk18.yellow(
8715
- `Run ${chalk18.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
8970
+ chalk19.yellow(
8971
+ `Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually to upgrade.
8716
8972
  `
8717
8973
  )
8718
8974
  );