@rely-ai/caliber 1.20.0-dev.1773685636 → 1.20.0-dev.1773686772

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 +364 -345
  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";
227
+ import path20 from "path";
228
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);
@@ -3236,13 +3236,23 @@ function cleanupStaging() {
3236
3236
 
3237
3237
  // src/utils/review.ts
3238
3238
  import chalk2 from "chalk";
3239
- import fs14 from "fs";
3239
+ import fs15 from "fs";
3240
3240
  import select2 from "@inquirer/select";
3241
3241
  import { createTwoFilesPatch } from "diff";
3242
3242
 
3243
3243
  // src/utils/editor.ts
3244
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";
3245
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
+ }
3246
3256
  function commandExists(cmd) {
3247
3257
  try {
3248
3258
  const check = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
@@ -3263,13 +3273,12 @@ function openDiffsInEditor(editor, files) {
3263
3273
  const cmd = editor === "cursor" ? "cursor" : "code";
3264
3274
  for (const file of files) {
3265
3275
  try {
3276
+ const leftPath = file.originalPath ?? getEmptyFilePath(file.proposedPath);
3266
3277
  if (IS_WINDOWS3) {
3267
3278
  const quote = (s) => `"${s}"`;
3268
- const parts = file.originalPath ? [cmd, "--diff", quote(file.originalPath), quote(file.proposedPath)] : [cmd, quote(file.proposedPath)];
3269
- 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();
3270
3280
  } else {
3271
- const args = file.originalPath ? ["--diff", file.originalPath, file.proposedPath] : [file.proposedPath];
3272
- spawn3(cmd, args, { stdio: "ignore", detached: true }).unref();
3281
+ spawn3(cmd, ["--diff", leftPath, file.proposedPath], { stdio: "ignore", detached: true }).unref();
3273
3282
  }
3274
3283
  } catch {
3275
3284
  continue;
@@ -3312,8 +3321,8 @@ async function openReview(method, stagedFiles) {
3312
3321
  return;
3313
3322
  }
3314
3323
  const fileInfos = stagedFiles.map((file) => {
3315
- const proposed = fs14.readFileSync(file.proposedPath, "utf-8");
3316
- 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") : "";
3317
3326
  const patch = createTwoFilesPatch(
3318
3327
  file.isNew ? "/dev/null" : file.relativePath,
3319
3328
  file.relativePath,
@@ -3476,7 +3485,7 @@ async function interactiveDiffExplorer(files) {
3476
3485
  }
3477
3486
 
3478
3487
  // src/commands/setup-files.ts
3479
- import fs15 from "fs";
3488
+ import fs16 from "fs";
3480
3489
  function buildSkillContent(skill) {
3481
3490
  const frontmatter = `---
3482
3491
  name: ${skill.name}
@@ -3525,7 +3534,7 @@ function collectSetupFiles(setup, targetAgent) {
3525
3534
  }
3526
3535
  }
3527
3536
  const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
3528
- if (codexTargeted && !fs15.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
3537
+ if (codexTargeted && !fs16.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
3529
3538
  const agentRefs = [];
3530
3539
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
3531
3540
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
@@ -3542,12 +3551,12 @@ ${agentRefs.join(" ")}
3542
3551
  }
3543
3552
 
3544
3553
  // src/lib/hooks.ts
3545
- import fs17 from "fs";
3546
- import path12 from "path";
3554
+ import fs18 from "fs";
3555
+ import path13 from "path";
3547
3556
  import { execSync as execSync7 } from "child_process";
3548
3557
 
3549
3558
  // src/lib/resolve-caliber.ts
3550
- import fs16 from "fs";
3559
+ import fs17 from "fs";
3551
3560
  import { execSync as execSync6 } from "child_process";
3552
3561
  var _resolved = null;
3553
3562
  function resolveCaliber() {
@@ -3570,7 +3579,7 @@ function resolveCaliber() {
3570
3579
  } catch {
3571
3580
  }
3572
3581
  const binPath = process.argv[1];
3573
- if (binPath && fs16.existsSync(binPath)) {
3582
+ if (binPath && fs17.existsSync(binPath)) {
3574
3583
  _resolved = binPath;
3575
3584
  return _resolved;
3576
3585
  }
@@ -3586,24 +3595,24 @@ function isCaliberCommand(command, subcommandTail) {
3586
3595
  }
3587
3596
 
3588
3597
  // src/lib/hooks.ts
3589
- var SETTINGS_PATH = path12.join(".claude", "settings.json");
3598
+ var SETTINGS_PATH = path13.join(".claude", "settings.json");
3590
3599
  var REFRESH_TAIL = "refresh --quiet";
3591
3600
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
3592
3601
  function getHookCommand() {
3593
3602
  return `${resolveCaliber()} ${REFRESH_TAIL}`;
3594
3603
  }
3595
3604
  function readSettings() {
3596
- if (!fs17.existsSync(SETTINGS_PATH)) return {};
3605
+ if (!fs18.existsSync(SETTINGS_PATH)) return {};
3597
3606
  try {
3598
- return JSON.parse(fs17.readFileSync(SETTINGS_PATH, "utf-8"));
3607
+ return JSON.parse(fs18.readFileSync(SETTINGS_PATH, "utf-8"));
3599
3608
  } catch {
3600
3609
  return {};
3601
3610
  }
3602
3611
  }
3603
3612
  function writeSettings(settings) {
3604
- const dir = path12.dirname(SETTINGS_PATH);
3605
- if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
3606
- 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));
3607
3616
  }
3608
3617
  function findHookIndex(sessionEnd) {
3609
3618
  return sessionEnd.findIndex(
@@ -3666,19 +3675,19 @@ ${PRECOMMIT_END}`;
3666
3675
  function getGitHooksDir() {
3667
3676
  try {
3668
3677
  const gitDir = execSync7("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3669
- return path12.join(gitDir, "hooks");
3678
+ return path13.join(gitDir, "hooks");
3670
3679
  } catch {
3671
3680
  return null;
3672
3681
  }
3673
3682
  }
3674
3683
  function getPreCommitPath() {
3675
3684
  const hooksDir = getGitHooksDir();
3676
- return hooksDir ? path12.join(hooksDir, "pre-commit") : null;
3685
+ return hooksDir ? path13.join(hooksDir, "pre-commit") : null;
3677
3686
  }
3678
3687
  function isPreCommitHookInstalled() {
3679
3688
  const hookPath = getPreCommitPath();
3680
- if (!hookPath || !fs17.existsSync(hookPath)) return false;
3681
- const content = fs17.readFileSync(hookPath, "utf-8");
3689
+ if (!hookPath || !fs18.existsSync(hookPath)) return false;
3690
+ const content = fs18.readFileSync(hookPath, "utf-8");
3682
3691
  return content.includes(PRECOMMIT_START);
3683
3692
  }
3684
3693
  function installPreCommitHook() {
@@ -3687,43 +3696,43 @@ function installPreCommitHook() {
3687
3696
  }
3688
3697
  const hookPath = getPreCommitPath();
3689
3698
  if (!hookPath) return { installed: false, alreadyInstalled: false };
3690
- const hooksDir = path12.dirname(hookPath);
3691
- 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 });
3692
3701
  let content = "";
3693
- if (fs17.existsSync(hookPath)) {
3694
- content = fs17.readFileSync(hookPath, "utf-8");
3702
+ if (fs18.existsSync(hookPath)) {
3703
+ content = fs18.readFileSync(hookPath, "utf-8");
3695
3704
  if (!content.endsWith("\n")) content += "\n";
3696
3705
  content += "\n" + getPrecommitBlock() + "\n";
3697
3706
  } else {
3698
3707
  content = "#!/bin/sh\n\n" + getPrecommitBlock() + "\n";
3699
3708
  }
3700
- fs17.writeFileSync(hookPath, content);
3701
- fs17.chmodSync(hookPath, 493);
3709
+ fs18.writeFileSync(hookPath, content);
3710
+ fs18.chmodSync(hookPath, 493);
3702
3711
  return { installed: true, alreadyInstalled: false };
3703
3712
  }
3704
3713
  function removePreCommitHook() {
3705
3714
  const hookPath = getPreCommitPath();
3706
- if (!hookPath || !fs17.existsSync(hookPath)) {
3715
+ if (!hookPath || !fs18.existsSync(hookPath)) {
3707
3716
  return { removed: false, notFound: true };
3708
3717
  }
3709
- let content = fs17.readFileSync(hookPath, "utf-8");
3718
+ let content = fs18.readFileSync(hookPath, "utf-8");
3710
3719
  if (!content.includes(PRECOMMIT_START)) {
3711
3720
  return { removed: false, notFound: true };
3712
3721
  }
3713
- const regex2 = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
3714
- content = content.replace(regex2, "\n");
3722
+ const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
3723
+ content = content.replace(regex, "\n");
3715
3724
  if (content.trim() === "#!/bin/sh" || content.trim() === "") {
3716
- fs17.unlinkSync(hookPath);
3725
+ fs18.unlinkSync(hookPath);
3717
3726
  } else {
3718
- fs17.writeFileSync(hookPath, content);
3727
+ fs18.writeFileSync(hookPath, content);
3719
3728
  }
3720
3729
  return { removed: true, notFound: false };
3721
3730
  }
3722
3731
 
3723
3732
  // src/lib/learning-hooks.ts
3724
- import fs18 from "fs";
3725
- import path13 from "path";
3726
- 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");
3727
3736
  var HOOK_TAILS = [
3728
3737
  { event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
3729
3738
  { event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
@@ -3740,17 +3749,17 @@ function getHookConfigs() {
3740
3749
  }));
3741
3750
  }
3742
3751
  function readSettings2() {
3743
- if (!fs18.existsSync(SETTINGS_PATH2)) return {};
3752
+ if (!fs19.existsSync(SETTINGS_PATH2)) return {};
3744
3753
  try {
3745
- return JSON.parse(fs18.readFileSync(SETTINGS_PATH2, "utf-8"));
3754
+ return JSON.parse(fs19.readFileSync(SETTINGS_PATH2, "utf-8"));
3746
3755
  } catch {
3747
3756
  return {};
3748
3757
  }
3749
3758
  }
3750
3759
  function writeSettings2(settings) {
3751
- const dir = path13.dirname(SETTINGS_PATH2);
3752
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
3753
- 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));
3754
3763
  }
3755
3764
  function hasLearningHook(matchers, tail) {
3756
3765
  return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
@@ -3784,7 +3793,7 @@ function installLearningHooks() {
3784
3793
  writeSettings2(settings);
3785
3794
  return { installed: true, alreadyInstalled: false };
3786
3795
  }
3787
- var CURSOR_HOOKS_PATH = path13.join(".cursor", "hooks.json");
3796
+ var CURSOR_HOOKS_PATH = path14.join(".cursor", "hooks.json");
3788
3797
  var CURSOR_HOOK_EVENTS = [
3789
3798
  { event: "postToolUse", tail: "learn observe" },
3790
3799
  { event: "postToolUseFailure", tail: "learn observe --failure" },
@@ -3792,17 +3801,17 @@ var CURSOR_HOOK_EVENTS = [
3792
3801
  { event: "sessionEnd", tail: "learn finalize" }
3793
3802
  ];
3794
3803
  function readCursorHooks() {
3795
- if (!fs18.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
3804
+ if (!fs19.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
3796
3805
  try {
3797
- return JSON.parse(fs18.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
3806
+ return JSON.parse(fs19.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
3798
3807
  } catch {
3799
3808
  return { version: 1, hooks: {} };
3800
3809
  }
3801
3810
  }
3802
3811
  function writeCursorHooks(config) {
3803
- const dir = path13.dirname(CURSOR_HOOKS_PATH);
3804
- if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
3805
- 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));
3806
3815
  }
3807
3816
  function hasCursorHook(entries, tail) {
3808
3817
  return entries.some((e) => isCaliberCommand(e.command, tail));
@@ -3872,10 +3881,10 @@ function removeLearningHooks() {
3872
3881
 
3873
3882
  // src/lib/state.ts
3874
3883
  init_constants();
3875
- import fs19 from "fs";
3876
- import path14 from "path";
3884
+ import fs20 from "fs";
3885
+ import path15 from "path";
3877
3886
  import { execSync as execSync8 } from "child_process";
3878
- var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
3887
+ var STATE_FILE = path15.join(CALIBER_DIR, ".caliber-state.json");
3879
3888
  function normalizeTargetAgent(value) {
3880
3889
  if (Array.isArray(value)) return value;
3881
3890
  if (typeof value === "string") {
@@ -3886,8 +3895,8 @@ function normalizeTargetAgent(value) {
3886
3895
  }
3887
3896
  function readState() {
3888
3897
  try {
3889
- if (!fs19.existsSync(STATE_FILE)) return null;
3890
- 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"));
3891
3900
  if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
3892
3901
  return raw;
3893
3902
  } catch {
@@ -3895,10 +3904,10 @@ function readState() {
3895
3904
  }
3896
3905
  }
3897
3906
  function writeState(state) {
3898
- if (!fs19.existsSync(CALIBER_DIR)) {
3899
- fs19.mkdirSync(CALIBER_DIR, { recursive: true });
3907
+ if (!fs20.existsSync(CALIBER_DIR)) {
3908
+ fs20.mkdirSync(CALIBER_DIR, { recursive: true });
3900
3909
  }
3901
- fs19.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
3910
+ fs20.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
3902
3911
  }
3903
3912
  function getCurrentHeadSha() {
3904
3913
  try {
@@ -5255,22 +5264,22 @@ function checkBonus(dir) {
5255
5264
 
5256
5265
  // src/scoring/dismissed.ts
5257
5266
  init_constants();
5258
- import fs20 from "fs";
5259
- import path15 from "path";
5260
- 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");
5261
5270
  function readDismissedChecks() {
5262
5271
  try {
5263
- if (!fs20.existsSync(DISMISSED_FILE)) return [];
5264
- 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"));
5265
5274
  } catch {
5266
5275
  return [];
5267
5276
  }
5268
5277
  }
5269
5278
  function writeDismissedChecks(checks) {
5270
- if (!fs20.existsSync(CALIBER_DIR)) {
5271
- fs20.mkdirSync(CALIBER_DIR, { recursive: true });
5279
+ if (!fs21.existsSync(CALIBER_DIR)) {
5280
+ fs21.mkdirSync(CALIBER_DIR, { recursive: true });
5272
5281
  }
5273
- fs20.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
5282
+ fs21.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
5274
5283
  }
5275
5284
  function getDismissedIds() {
5276
5285
  return new Set(readDismissedChecks().map((c) => c.id));
@@ -5466,13 +5475,13 @@ import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4,
5466
5475
  import { join as join9, dirname as dirname2 } from "path";
5467
5476
 
5468
5477
  // src/scanner/index.ts
5469
- import fs21 from "fs";
5470
- import path16 from "path";
5478
+ import fs22 from "fs";
5479
+ import path17 from "path";
5471
5480
  import crypto2 from "crypto";
5472
5481
  function scanLocalState(dir) {
5473
5482
  const items = [];
5474
- const claudeMdPath = path16.join(dir, "CLAUDE.md");
5475
- if (fs21.existsSync(claudeMdPath)) {
5483
+ const claudeMdPath = path17.join(dir, "CLAUDE.md");
5484
+ if (fs22.existsSync(claudeMdPath)) {
5476
5485
  items.push({
5477
5486
  type: "rule",
5478
5487
  platform: "claude",
@@ -5481,10 +5490,10 @@ function scanLocalState(dir) {
5481
5490
  path: claudeMdPath
5482
5491
  });
5483
5492
  }
5484
- const skillsDir = path16.join(dir, ".claude", "skills");
5485
- if (fs21.existsSync(skillsDir)) {
5486
- for (const file of fs21.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5487
- 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);
5488
5497
  items.push({
5489
5498
  type: "skill",
5490
5499
  platform: "claude",
@@ -5494,10 +5503,10 @@ function scanLocalState(dir) {
5494
5503
  });
5495
5504
  }
5496
5505
  }
5497
- const mcpJsonPath = path16.join(dir, ".mcp.json");
5498
- if (fs21.existsSync(mcpJsonPath)) {
5506
+ const mcpJsonPath = path17.join(dir, ".mcp.json");
5507
+ if (fs22.existsSync(mcpJsonPath)) {
5499
5508
  try {
5500
- const mcpJson = JSON.parse(fs21.readFileSync(mcpJsonPath, "utf-8"));
5509
+ const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
5501
5510
  if (mcpJson.mcpServers) {
5502
5511
  for (const name of Object.keys(mcpJson.mcpServers)) {
5503
5512
  items.push({
@@ -5512,8 +5521,8 @@ function scanLocalState(dir) {
5512
5521
  } catch {
5513
5522
  }
5514
5523
  }
5515
- const agentsMdPath = path16.join(dir, "AGENTS.md");
5516
- if (fs21.existsSync(agentsMdPath)) {
5524
+ const agentsMdPath = path17.join(dir, "AGENTS.md");
5525
+ if (fs22.existsSync(agentsMdPath)) {
5517
5526
  items.push({
5518
5527
  type: "rule",
5519
5528
  platform: "codex",
@@ -5522,12 +5531,12 @@ function scanLocalState(dir) {
5522
5531
  path: agentsMdPath
5523
5532
  });
5524
5533
  }
5525
- const codexSkillsDir = path16.join(dir, ".agents", "skills");
5526
- if (fs21.existsSync(codexSkillsDir)) {
5534
+ const codexSkillsDir = path17.join(dir, ".agents", "skills");
5535
+ if (fs22.existsSync(codexSkillsDir)) {
5527
5536
  try {
5528
- for (const name of fs21.readdirSync(codexSkillsDir)) {
5529
- const skillFile = path16.join(codexSkillsDir, name, "SKILL.md");
5530
- 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)) {
5531
5540
  items.push({
5532
5541
  type: "skill",
5533
5542
  platform: "codex",
@@ -5540,8 +5549,8 @@ function scanLocalState(dir) {
5540
5549
  } catch {
5541
5550
  }
5542
5551
  }
5543
- const cursorrulesPath = path16.join(dir, ".cursorrules");
5544
- if (fs21.existsSync(cursorrulesPath)) {
5552
+ const cursorrulesPath = path17.join(dir, ".cursorrules");
5553
+ if (fs22.existsSync(cursorrulesPath)) {
5545
5554
  items.push({
5546
5555
  type: "rule",
5547
5556
  platform: "cursor",
@@ -5550,10 +5559,10 @@ function scanLocalState(dir) {
5550
5559
  path: cursorrulesPath
5551
5560
  });
5552
5561
  }
5553
- const cursorRulesDir = path16.join(dir, ".cursor", "rules");
5554
- if (fs21.existsSync(cursorRulesDir)) {
5555
- for (const file of fs21.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5556
- 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);
5557
5566
  items.push({
5558
5567
  type: "rule",
5559
5568
  platform: "cursor",
@@ -5563,12 +5572,12 @@ function scanLocalState(dir) {
5563
5572
  });
5564
5573
  }
5565
5574
  }
5566
- const cursorSkillsDir = path16.join(dir, ".cursor", "skills");
5567
- if (fs21.existsSync(cursorSkillsDir)) {
5575
+ const cursorSkillsDir = path17.join(dir, ".cursor", "skills");
5576
+ if (fs22.existsSync(cursorSkillsDir)) {
5568
5577
  try {
5569
- for (const name of fs21.readdirSync(cursorSkillsDir)) {
5570
- const skillFile = path16.join(cursorSkillsDir, name, "SKILL.md");
5571
- 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)) {
5572
5581
  items.push({
5573
5582
  type: "skill",
5574
5583
  platform: "cursor",
@@ -5581,10 +5590,10 @@ function scanLocalState(dir) {
5581
5590
  } catch {
5582
5591
  }
5583
5592
  }
5584
- const cursorMcpPath = path16.join(dir, ".cursor", "mcp.json");
5585
- if (fs21.existsSync(cursorMcpPath)) {
5593
+ const cursorMcpPath = path17.join(dir, ".cursor", "mcp.json");
5594
+ if (fs22.existsSync(cursorMcpPath)) {
5586
5595
  try {
5587
- const mcpJson = JSON.parse(fs21.readFileSync(cursorMcpPath, "utf-8"));
5596
+ const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
5588
5597
  if (mcpJson.mcpServers) {
5589
5598
  for (const name of Object.keys(mcpJson.mcpServers)) {
5590
5599
  items.push({
@@ -5602,7 +5611,7 @@ function scanLocalState(dir) {
5602
5611
  return items;
5603
5612
  }
5604
5613
  function hashFile(filePath) {
5605
- const text = fs21.readFileSync(filePath, "utf-8");
5614
+ const text = fs22.readFileSync(filePath, "utf-8");
5606
5615
  return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
5607
5616
  }
5608
5617
  function hashJson(obj) {
@@ -5617,27 +5626,27 @@ import { PostHog } from "posthog-node";
5617
5626
  import chalk7 from "chalk";
5618
5627
 
5619
5628
  // src/telemetry/config.ts
5620
- import fs22 from "fs";
5621
- import path17 from "path";
5622
- import os3 from "os";
5629
+ import fs23 from "fs";
5630
+ import path18 from "path";
5631
+ import os4 from "os";
5623
5632
  import crypto3 from "crypto";
5624
5633
  import { execSync as execSync12 } from "child_process";
5625
- var CONFIG_DIR2 = path17.join(os3.homedir(), ".caliber");
5626
- 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");
5627
5636
  var runtimeDisabled = false;
5628
5637
  function readConfig() {
5629
5638
  try {
5630
- if (!fs22.existsSync(CONFIG_FILE2)) return {};
5631
- 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"));
5632
5641
  } catch {
5633
5642
  return {};
5634
5643
  }
5635
5644
  }
5636
5645
  function writeConfig(config) {
5637
- if (!fs22.existsSync(CONFIG_DIR2)) {
5638
- fs22.mkdirSync(CONFIG_DIR2, { recursive: true });
5646
+ if (!fs23.existsSync(CONFIG_DIR2)) {
5647
+ fs23.mkdirSync(CONFIG_DIR2, { recursive: true });
5639
5648
  }
5640
- 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 });
5641
5650
  }
5642
5651
  function getMachineId() {
5643
5652
  const config = readConfig();
@@ -6361,8 +6370,8 @@ function printSkills(recs) {
6361
6370
  }
6362
6371
 
6363
6372
  // src/lib/debug-report.ts
6364
- import fs23 from "fs";
6365
- import path18 from "path";
6373
+ import fs24 from "fs";
6374
+ import path19 from "path";
6366
6375
  var DebugReport = class {
6367
6376
  sections = [];
6368
6377
  startTime;
@@ -6431,11 +6440,11 @@ var DebugReport = class {
6431
6440
  lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
6432
6441
  lines.push("");
6433
6442
  }
6434
- const dir = path18.dirname(outputPath);
6435
- if (!fs23.existsSync(dir)) {
6436
- fs23.mkdirSync(dir, { recursive: true });
6443
+ const dir = path19.dirname(outputPath);
6444
+ if (!fs24.existsSync(dir)) {
6445
+ fs24.mkdirSync(dir, { recursive: true });
6437
6446
  }
6438
- fs23.writeFileSync(outputPath, lines.join("\n"));
6447
+ fs24.writeFileSync(outputPath, lines.join("\n"));
6439
6448
  }
6440
6449
  };
6441
6450
  function formatMs(ms) {
@@ -6449,31 +6458,10 @@ function formatMs(ms) {
6449
6458
 
6450
6459
  // src/utils/parallel-tasks.ts
6451
6460
  import chalk9 from "chalk";
6452
-
6453
- // node_modules/ansi-regex/index.js
6454
- function ansiRegex({ onlyFirst = false } = {}) {
6455
- const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
6456
- const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`;
6457
- const csi = "[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]";
6458
- const pattern = `${osc}|${csi}`;
6459
- return new RegExp(pattern, onlyFirst ? void 0 : "g");
6460
- }
6461
-
6462
- // node_modules/strip-ansi/index.js
6463
- var regex = ansiRegex();
6464
- function stripAnsi(string) {
6465
- if (typeof string !== "string") {
6466
- throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
6467
- }
6468
- if (!string.includes("\x1B") && !string.includes("\x9B")) {
6469
- return string;
6470
- }
6471
- return string.replace(regex, "");
6472
- }
6473
-
6474
- // src/utils/parallel-tasks.ts
6475
6461
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
6476
6462
  var SPINNER_INTERVAL_MS = 80;
6463
+ var NAME_COL_WIDTH = 26;
6464
+ var PREFIX = " ";
6477
6465
  var ParallelTaskDisplay = class {
6478
6466
  tasks = [];
6479
6467
  lineCount = 0;
@@ -6518,48 +6506,48 @@ var ParallelTaskDisplay = class {
6518
6506
  if (secs < 60) return `${secs}s`;
6519
6507
  return `${Math.floor(secs / 60)}m ${secs % 60}s`;
6520
6508
  }
6521
- truncate(text, maxVisible) {
6522
- const plain = stripAnsi(text);
6523
- if (plain.length <= maxVisible) return text;
6524
- let visible = 0;
6525
- let i = 0;
6526
- while (i < text.length && visible < maxVisible - 3) {
6527
- if (text[i] === "\x1B") {
6528
- const end = text.indexOf("m", i);
6529
- if (end !== -1) {
6530
- i = end + 1;
6531
- continue;
6532
- }
6533
- }
6534
- visible++;
6535
- i++;
6536
- }
6537
- return text.slice(0, i) + "...";
6509
+ smartTruncate(text, max) {
6510
+ if (text.length <= max) return text;
6511
+ const cut = text.slice(0, max - 1);
6512
+ const lastSpace = cut.lastIndexOf(" ");
6513
+ const boundary = lastSpace > max * 0.5 ? lastSpace : max - 1;
6514
+ return text.slice(0, boundary) + "\u2026";
6538
6515
  }
6539
6516
  renderLine(task) {
6540
- const maxWidth = process.stdout.columns || 80;
6517
+ const cols = process.stdout.columns || 80;
6541
6518
  const elapsed = task.startTime ? this.formatTime((task.endTime ?? Date.now()) - task.startTime) : "";
6542
- let line;
6519
+ const timeStr = elapsed ? ` ${chalk9.dim(elapsed)}` : "";
6520
+ const timePlain = elapsed ? ` ${elapsed}` : "";
6521
+ let icon;
6522
+ let nameStyle;
6523
+ let msgStyle;
6543
6524
  switch (task.status) {
6544
6525
  case "pending":
6545
- line = ` ${chalk9.dim("\u25CB")} ${chalk9.dim(task.name)}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}`;
6526
+ icon = chalk9.dim("\u25CB");
6527
+ nameStyle = chalk9.dim;
6528
+ msgStyle = chalk9.dim;
6546
6529
  break;
6547
- case "running": {
6548
- const spinner = chalk9.cyan(SPINNER_FRAMES[this.spinnerFrame]);
6549
- const time = elapsed ? chalk9.dim(` (${elapsed})`) : "";
6550
- line = ` ${spinner} ${task.name}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}${time}`;
6530
+ case "running":
6531
+ icon = chalk9.cyan(SPINNER_FRAMES[this.spinnerFrame]);
6532
+ nameStyle = chalk9.white;
6533
+ msgStyle = chalk9.dim;
6551
6534
  break;
6552
- }
6553
- case "done": {
6554
- const time = elapsed ? chalk9.dim(` (${elapsed})`) : "";
6555
- line = ` ${chalk9.green("\u2713")} ${task.name}${task.message ? chalk9.dim(` \u2014 ${task.message}`) : ""}${time}`;
6535
+ case "done":
6536
+ icon = chalk9.green("\u2713");
6537
+ nameStyle = chalk9.white;
6538
+ msgStyle = chalk9.dim;
6556
6539
  break;
6557
- }
6558
6540
  case "failed":
6559
- line = ` ${chalk9.red("\u2717")} ${task.name}${task.message ? chalk9.red(` \u2014 ${task.message}`) : ""}`;
6541
+ icon = chalk9.red("\u2717");
6542
+ nameStyle = chalk9.white;
6543
+ msgStyle = chalk9.red;
6560
6544
  break;
6561
6545
  }
6562
- return this.truncate(line, maxWidth - 1);
6546
+ const paddedName = task.name.padEnd(NAME_COL_WIDTH);
6547
+ const usedByFixed = PREFIX.length + 2 + NAME_COL_WIDTH + timePlain.length;
6548
+ const msgMax = Math.max(cols - usedByFixed - 2, 10);
6549
+ const msg = task.message ? this.smartTruncate(task.message, msgMax) : "";
6550
+ return `${PREFIX}${icon} ${nameStyle(paddedName)}${msg ? msgStyle(msg) : ""}${timeStr}`;
6563
6551
  }
6564
6552
  draw(initial) {
6565
6553
  const { stdout } = process;
@@ -6568,9 +6556,6 @@ var ParallelTaskDisplay = class {
6568
6556
  }
6569
6557
  stdout.write("\x1B[0J");
6570
6558
  const lines = this.tasks.map((t) => this.renderLine(t));
6571
- const totalElapsed = this.formatTime(Date.now() - this.startTime);
6572
- lines.push(chalk9.dim(`
6573
- Total: ${totalElapsed}`));
6574
6559
  const output = lines.join("\n");
6575
6560
  stdout.write(output + "\n");
6576
6561
  this.lineCount = output.split("\n").length;
@@ -6710,57 +6695,59 @@ async function initCommand(options) {
6710
6695
  let genStopReason;
6711
6696
  let skillSearchResult = { results: [], contentMap: /* @__PURE__ */ new Map() };
6712
6697
  let fingerprint;
6713
- const fpSpinner = ora2("Scanning project...").start();
6714
- try {
6715
- fingerprint = await collectFingerprint(process.cwd());
6716
- fpSpinner.succeed(`Stack detected \u2014 ${fingerprint.languages.join(", ") || "no languages"}${fingerprint.frameworks.length > 0 ? `, ${fingerprint.frameworks.join(", ")}` : ""}`);
6717
- } catch (err) {
6718
- fpSpinner.fail("Failed to scan project");
6719
- throw new Error("__exit__");
6720
- }
6721
- trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
6722
- log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
6723
- if (report) {
6724
- report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
6725
- report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
6726
- report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
6727
- report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
6728
- if (fingerprint.codeAnalysis) report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
6729
- }
6730
- const isEmpty = fingerprint.fileTree.length < 3;
6731
- if (isEmpty) {
6732
- fingerprint.description = await promptInput("What will you build in this project?");
6733
- }
6734
- const failingForDismissal = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
6735
- if (failingForDismissal.length > 0) {
6736
- const newDismissals = await evaluateDismissals(failingForDismissal, fingerprint);
6737
- if (newDismissals.length > 0) {
6738
- const existing = readDismissedChecks();
6739
- const existingIds = new Set(existing.map((d) => d.id));
6740
- const merged = [...existing, ...newDismissals.filter((d) => !existingIds.has(d.id))];
6741
- writeDismissedChecks(merged);
6742
- baselineScore = computeLocalScore(process.cwd(), targetAgent);
6743
- }
6744
- }
6745
- let failingChecks;
6746
- let passingChecks;
6747
- let currentScore;
6748
- if (hasExistingConfig && baselineScore.score >= 95 && !options.force) {
6749
- const currentLlmFixable = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
6750
- failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
6751
- passingChecks = baselineScore.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
6752
- currentScore = baselineScore.score;
6753
- }
6754
- if (report) {
6755
- const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
6756
- report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
6757
- }
6758
6698
  const display = new ParallelTaskDisplay();
6699
+ const TASK_STACK = display.add("Detecting project stack");
6759
6700
  const TASK_CONFIG = display.add("Generating configs");
6760
6701
  const TASK_SKILLS_GEN = display.add("Generating skills");
6761
6702
  const TASK_SKILLS_SEARCH = wantsSkills ? display.add("Searching community skills") : -1;
6762
6703
  display.start();
6763
6704
  try {
6705
+ display.update(TASK_STACK, "running");
6706
+ fingerprint = await collectFingerprint(process.cwd());
6707
+ const stackSummary = [
6708
+ ...fingerprint.languages,
6709
+ ...fingerprint.frameworks
6710
+ ].join(", ") || "no languages";
6711
+ display.update(TASK_STACK, "done", stackSummary);
6712
+ trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
6713
+ log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
6714
+ if (report) {
6715
+ report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
6716
+ report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
6717
+ report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
6718
+ report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
6719
+ if (fingerprint.codeAnalysis) report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
6720
+ }
6721
+ const isEmpty = fingerprint.fileTree.length < 3;
6722
+ if (isEmpty) {
6723
+ display.stop();
6724
+ fingerprint.description = await promptInput("What will you build in this project?");
6725
+ display.start();
6726
+ }
6727
+ const failingForDismissal = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
6728
+ if (failingForDismissal.length > 0) {
6729
+ const newDismissals = await evaluateDismissals(failingForDismissal, fingerprint);
6730
+ if (newDismissals.length > 0) {
6731
+ const existing = readDismissedChecks();
6732
+ const existingIds = new Set(existing.map((d) => d.id));
6733
+ const merged = [...existing, ...newDismissals.filter((d) => !existingIds.has(d.id))];
6734
+ writeDismissedChecks(merged);
6735
+ baselineScore = computeLocalScore(process.cwd(), targetAgent);
6736
+ }
6737
+ }
6738
+ let failingChecks;
6739
+ let passingChecks;
6740
+ let currentScore;
6741
+ if (hasExistingConfig && baselineScore.score >= 95 && !options.force) {
6742
+ const currentLlmFixable = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
6743
+ failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
6744
+ passingChecks = baselineScore.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
6745
+ currentScore = baselineScore.score;
6746
+ }
6747
+ if (report) {
6748
+ const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
6749
+ report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
6750
+ }
6764
6751
  display.update(TASK_CONFIG, "running");
6765
6752
  const generatePromise = (async () => {
6766
6753
  const result = await generateSetup(
@@ -6813,7 +6800,7 @@ async function initCommand(options) {
6813
6800
  ]);
6814
6801
  skillSearchResult = await searchWithTimeout;
6815
6802
  const count = skillSearchResult.results.length;
6816
- display.update(TASK_SKILLS_SEARCH, "done", count > 0 ? `${count} skills found` : "No matches");
6803
+ display.update(TASK_SKILLS_SEARCH, "done", count > 0 ? `${count} found` : "No matches");
6817
6804
  } catch (err) {
6818
6805
  const reason = err instanceof Error && err.message === "timeout" ? "Timed out" : "Search failed";
6819
6806
  display.update(TASK_SKILLS_SEARCH, "failed", reason);
@@ -6836,7 +6823,7 @@ async function initCommand(options) {
6836
6823
  const secs = Math.floor(elapsedMs % 6e4 / 1e3);
6837
6824
  const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
6838
6825
  console.log(chalk10.dim(`
6839
- Completed in ${timeStr}
6826
+ Done in ${timeStr}
6840
6827
  `));
6841
6828
  if (!generatedSetup) {
6842
6829
  console.log(chalk10.red(" Failed to generate setup."));
@@ -6869,8 +6856,9 @@ async function initCommand(options) {
6869
6856
  } else {
6870
6857
  console.log("");
6871
6858
  }
6859
+ const hasSkillResults = skillSearchResult.results.length > 0;
6872
6860
  let action;
6873
- if (totalChanges === 0 && skillSearchResult.results.length === 0) {
6861
+ if (totalChanges === 0 && !hasSkillResults) {
6874
6862
  console.log(chalk10.dim(" No changes needed \u2014 your configs are already up to date.\n"));
6875
6863
  cleanupStaging();
6876
6864
  action = "accept";
@@ -6880,13 +6868,20 @@ async function initCommand(options) {
6880
6868
  trackInitReviewAction(action, "auto-approved");
6881
6869
  } else {
6882
6870
  if (totalChanges > 0) {
6883
- const wantsReview = await promptWantsReview();
6884
- if (wantsReview) {
6871
+ const reviewChoice = await select5({
6872
+ message: "Review your tailored setup?",
6873
+ choices: [
6874
+ { name: "Yes, show me the diffs", value: "review" },
6875
+ ...hasSkillResults ? [{ name: `No, continue to community skills (${skillSearchResult.results.length} found)`, value: "skip" }] : [],
6876
+ { name: "No, continue", value: "skip" }
6877
+ ]
6878
+ });
6879
+ if (reviewChoice === "review") {
6885
6880
  const reviewMethod = await promptReviewMethod();
6886
6881
  await openReview(reviewMethod, staged.stagedFiles);
6887
6882
  }
6888
6883
  }
6889
- action = await promptReviewAction();
6884
+ action = await promptReviewAction(hasSkillResults);
6890
6885
  trackInitReviewAction(action, totalChanges > 0 ? "reviewed" : "skipped");
6891
6886
  }
6892
6887
  let refinementRound = 0;
@@ -6905,7 +6900,7 @@ async function initCommand(options) {
6905
6900
  `));
6906
6901
  printSetupSummary(generatedSetup);
6907
6902
  await openReview("terminal", restaged.stagedFiles);
6908
- action = await promptReviewAction();
6903
+ action = await promptReviewAction(hasSkillResults);
6909
6904
  trackInitReviewAction(action, "terminal");
6910
6905
  }
6911
6906
  cleanupStaging();
@@ -6921,7 +6916,7 @@ async function initCommand(options) {
6921
6916
  }
6922
6917
  const writeSpinner = ora2("Writing config files...").start();
6923
6918
  try {
6924
- if (targetAgent.includes("codex") && !fs24.existsSync("AGENTS.md") && !generatedSetup.codex) {
6919
+ if (targetAgent.includes("codex") && !fs25.existsSync("AGENTS.md") && !generatedSetup.codex) {
6925
6920
  const claude = generatedSetup.claude;
6926
6921
  const cursor = generatedSetup.cursor;
6927
6922
  const agentRefs = [];
@@ -7062,9 +7057,9 @@ ${agentRefs.join(" ")}
7062
7057
  }
7063
7058
  if (report) {
7064
7059
  report.markStep("Finished");
7065
- const reportPath = path19.join(process.cwd(), ".caliber", "debug-report.md");
7060
+ const reportPath = path20.join(process.cwd(), ".caliber", "debug-report.md");
7066
7061
  report.write(reportPath);
7067
- console.log(chalk10.dim(` Debug report written to ${path19.relative(process.cwd(), reportPath)}
7062
+ console.log(chalk10.dim(` Debug report written to ${path20.relative(process.cwd(), reportPath)}
7068
7063
  `));
7069
7064
  }
7070
7065
  }
@@ -7111,7 +7106,7 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
7111
7106
  }
7112
7107
  function summarizeSetup(action, setup) {
7113
7108
  const descriptions = setup.fileDescriptions;
7114
- const files = descriptions ? Object.entries(descriptions).map(([path27, desc]) => ` ${path27}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
7109
+ const files = descriptions ? Object.entries(descriptions).map(([path28, desc]) => ` ${path28}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
7115
7110
  return `${action}. Files:
7116
7111
  ${files}`;
7117
7112
  }
@@ -7205,13 +7200,14 @@ async function promptHookType(targetAgent) {
7205
7200
  choices
7206
7201
  });
7207
7202
  }
7208
- async function promptReviewAction() {
7203
+ async function promptReviewAction(hasSkillResults = false) {
7204
+ const acceptLabel = hasSkillResults ? "Accept and continue to community skills" : "Accept and apply";
7209
7205
  return select5({
7210
7206
  message: "What would you like to do?",
7211
7207
  choices: [
7212
- { name: "Accept and apply", value: "accept" },
7208
+ { name: acceptLabel, value: "accept" },
7213
7209
  { name: "Refine via chat", value: "refine" },
7214
- { name: "Decline", value: "decline" }
7210
+ { name: "Decline all changes", value: "decline" }
7215
7211
  ]
7216
7212
  });
7217
7213
  }
@@ -7221,13 +7217,13 @@ function printSetupSummary(setup) {
7221
7217
  const fileDescriptions = setup.fileDescriptions;
7222
7218
  const deletions = setup.deletions;
7223
7219
  console.log("");
7224
- console.log(chalk10.bold(" Proposed changes:\n"));
7220
+ console.log(chalk10.bold(" Your tailored setup:\n"));
7225
7221
  const getDescription = (filePath) => {
7226
7222
  return fileDescriptions?.[filePath];
7227
7223
  };
7228
7224
  if (claude) {
7229
7225
  if (claude.claudeMd) {
7230
- const icon = fs24.existsSync("CLAUDE.md") ? chalk10.yellow("~") : chalk10.green("+");
7226
+ const icon = fs25.existsSync("CLAUDE.md") ? chalk10.yellow("~") : chalk10.green("+");
7231
7227
  const desc = getDescription("CLAUDE.md");
7232
7228
  console.log(` ${icon} ${chalk10.bold("CLAUDE.md")}`);
7233
7229
  if (desc) console.log(chalk10.dim(` ${desc}`));
@@ -7237,7 +7233,7 @@ function printSetupSummary(setup) {
7237
7233
  if (Array.isArray(skills) && skills.length > 0) {
7238
7234
  for (const skill of skills) {
7239
7235
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
7240
- const icon = fs24.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7236
+ const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7241
7237
  const desc = getDescription(skillPath);
7242
7238
  console.log(` ${icon} ${chalk10.bold(skillPath)}`);
7243
7239
  console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
@@ -7248,7 +7244,7 @@ function printSetupSummary(setup) {
7248
7244
  const codex = setup.codex;
7249
7245
  if (codex) {
7250
7246
  if (codex.agentsMd) {
7251
- const icon = fs24.existsSync("AGENTS.md") ? chalk10.yellow("~") : chalk10.green("+");
7247
+ const icon = fs25.existsSync("AGENTS.md") ? chalk10.yellow("~") : chalk10.green("+");
7252
7248
  const desc = getDescription("AGENTS.md");
7253
7249
  console.log(` ${icon} ${chalk10.bold("AGENTS.md")}`);
7254
7250
  if (desc) console.log(chalk10.dim(` ${desc}`));
@@ -7258,7 +7254,7 @@ function printSetupSummary(setup) {
7258
7254
  if (Array.isArray(codexSkills) && codexSkills.length > 0) {
7259
7255
  for (const skill of codexSkills) {
7260
7256
  const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
7261
- const icon = fs24.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7257
+ const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7262
7258
  const desc = getDescription(skillPath);
7263
7259
  console.log(` ${icon} ${chalk10.bold(skillPath)}`);
7264
7260
  console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
@@ -7268,7 +7264,7 @@ function printSetupSummary(setup) {
7268
7264
  }
7269
7265
  if (cursor) {
7270
7266
  if (cursor.cursorrules) {
7271
- const icon = fs24.existsSync(".cursorrules") ? chalk10.yellow("~") : chalk10.green("+");
7267
+ const icon = fs25.existsSync(".cursorrules") ? chalk10.yellow("~") : chalk10.green("+");
7272
7268
  const desc = getDescription(".cursorrules");
7273
7269
  console.log(` ${icon} ${chalk10.bold(".cursorrules")}`);
7274
7270
  if (desc) console.log(chalk10.dim(` ${desc}`));
@@ -7278,7 +7274,7 @@ function printSetupSummary(setup) {
7278
7274
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
7279
7275
  for (const skill of cursorSkills) {
7280
7276
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
7281
- const icon = fs24.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7277
+ const icon = fs25.existsSync(skillPath) ? chalk10.yellow("~") : chalk10.green("+");
7282
7278
  const desc = getDescription(skillPath);
7283
7279
  console.log(` ${icon} ${chalk10.bold(skillPath)}`);
7284
7280
  console.log(chalk10.dim(` ${desc || skill.description || skill.name}`));
@@ -7289,7 +7285,7 @@ function printSetupSummary(setup) {
7289
7285
  if (Array.isArray(rules) && rules.length > 0) {
7290
7286
  for (const rule of rules) {
7291
7287
  const rulePath = `.cursor/rules/${rule.filename}`;
7292
- const icon = fs24.existsSync(rulePath) ? chalk10.yellow("~") : chalk10.green("+");
7288
+ const icon = fs25.existsSync(rulePath) ? chalk10.yellow("~") : chalk10.green("+");
7293
7289
  const desc = getDescription(rulePath);
7294
7290
  console.log(` ${icon} ${chalk10.bold(rulePath)}`);
7295
7291
  if (desc) {
@@ -7353,8 +7349,8 @@ function ensurePermissions(fingerprint) {
7353
7349
  const settingsPath = ".claude/settings.json";
7354
7350
  let settings = {};
7355
7351
  try {
7356
- if (fs24.existsSync(settingsPath)) {
7357
- settings = JSON.parse(fs24.readFileSync(settingsPath, "utf-8"));
7352
+ if (fs25.existsSync(settingsPath)) {
7353
+ settings = JSON.parse(fs25.readFileSync(settingsPath, "utf-8"));
7358
7354
  }
7359
7355
  } catch {
7360
7356
  }
@@ -7363,8 +7359,8 @@ function ensurePermissions(fingerprint) {
7363
7359
  if (Array.isArray(allow) && allow.length > 0) return;
7364
7360
  permissions.allow = derivePermissions(fingerprint);
7365
7361
  settings.permissions = permissions;
7366
- if (!fs24.existsSync(".claude")) fs24.mkdirSync(".claude", { recursive: true });
7367
- fs24.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
7362
+ if (!fs25.existsSync(".claude")) fs25.mkdirSync(".claude", { recursive: true });
7363
+ fs25.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
7368
7364
  }
7369
7365
  function displayTokenUsage() {
7370
7366
  const summary = getUsageSummary();
@@ -7388,7 +7384,7 @@ function displayTokenUsage() {
7388
7384
  }
7389
7385
  function writeErrorLog(config, rawOutput, error, stopReason) {
7390
7386
  try {
7391
- const logPath = path19.join(process.cwd(), ".caliber", "error-log.md");
7387
+ const logPath = path20.join(process.cwd(), ".caliber", "error-log.md");
7392
7388
  const lines = [
7393
7389
  `# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
7394
7390
  "",
@@ -7401,8 +7397,8 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
7401
7397
  lines.push("## Error", "```", error, "```", "");
7402
7398
  }
7403
7399
  lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
7404
- fs24.mkdirSync(path19.join(process.cwd(), ".caliber"), { recursive: true });
7405
- fs24.writeFileSync(logPath, lines.join("\n"));
7400
+ fs25.mkdirSync(path20.join(process.cwd(), ".caliber"), { recursive: true });
7401
+ fs25.writeFileSync(logPath, lines.join("\n"));
7406
7402
  console.log(chalk10.dim(`
7407
7403
  Error log written to .caliber/error-log.md`));
7408
7404
  } catch {
@@ -7443,7 +7439,7 @@ function undoCommand() {
7443
7439
 
7444
7440
  // src/commands/status.ts
7445
7441
  import chalk12 from "chalk";
7446
- import fs25 from "fs";
7442
+ import fs26 from "fs";
7447
7443
  init_config();
7448
7444
  async function statusCommand(options) {
7449
7445
  const config = loadConfig();
@@ -7470,7 +7466,7 @@ async function statusCommand(options) {
7470
7466
  }
7471
7467
  console.log(` Files managed: ${chalk12.cyan(manifest.entries.length.toString())}`);
7472
7468
  for (const entry of manifest.entries) {
7473
- const exists = fs25.existsSync(entry.path);
7469
+ const exists = fs26.existsSync(entry.path);
7474
7470
  const icon = exists ? chalk12.green("\u2713") : chalk12.red("\u2717");
7475
7471
  console.log(` ${icon} ${entry.path} (${entry.action})`);
7476
7472
  }
@@ -7651,8 +7647,8 @@ async function scoreCommand(options) {
7651
7647
  }
7652
7648
 
7653
7649
  // src/commands/refresh.ts
7654
- import fs29 from "fs";
7655
- import path23 from "path";
7650
+ import fs30 from "fs";
7651
+ import path24 from "path";
7656
7652
  import chalk15 from "chalk";
7657
7653
  import ora5 from "ora";
7658
7654
 
@@ -7730,37 +7726,37 @@ function collectDiff(lastSha) {
7730
7726
  }
7731
7727
 
7732
7728
  // src/writers/refresh.ts
7733
- import fs26 from "fs";
7734
- import path20 from "path";
7729
+ import fs27 from "fs";
7730
+ import path21 from "path";
7735
7731
  function writeRefreshDocs(docs) {
7736
7732
  const written = [];
7737
7733
  if (docs.claudeMd) {
7738
- fs26.writeFileSync("CLAUDE.md", docs.claudeMd);
7734
+ fs27.writeFileSync("CLAUDE.md", docs.claudeMd);
7739
7735
  written.push("CLAUDE.md");
7740
7736
  }
7741
7737
  if (docs.readmeMd) {
7742
- fs26.writeFileSync("README.md", docs.readmeMd);
7738
+ fs27.writeFileSync("README.md", docs.readmeMd);
7743
7739
  written.push("README.md");
7744
7740
  }
7745
7741
  if (docs.cursorrules) {
7746
- fs26.writeFileSync(".cursorrules", docs.cursorrules);
7742
+ fs27.writeFileSync(".cursorrules", docs.cursorrules);
7747
7743
  written.push(".cursorrules");
7748
7744
  }
7749
7745
  if (docs.cursorRules) {
7750
- const rulesDir = path20.join(".cursor", "rules");
7751
- if (!fs26.existsSync(rulesDir)) fs26.mkdirSync(rulesDir, { recursive: true });
7746
+ const rulesDir = path21.join(".cursor", "rules");
7747
+ if (!fs27.existsSync(rulesDir)) fs27.mkdirSync(rulesDir, { recursive: true });
7752
7748
  for (const rule of docs.cursorRules) {
7753
- const filePath = path20.join(rulesDir, rule.filename);
7754
- fs26.writeFileSync(filePath, rule.content);
7749
+ const filePath = path21.join(rulesDir, rule.filename);
7750
+ fs27.writeFileSync(filePath, rule.content);
7755
7751
  written.push(filePath);
7756
7752
  }
7757
7753
  }
7758
7754
  if (docs.claudeSkills) {
7759
- const skillsDir = path20.join(".claude", "skills");
7760
- if (!fs26.existsSync(skillsDir)) fs26.mkdirSync(skillsDir, { recursive: true });
7755
+ const skillsDir = path21.join(".claude", "skills");
7756
+ if (!fs27.existsSync(skillsDir)) fs27.mkdirSync(skillsDir, { recursive: true });
7761
7757
  for (const skill of docs.claudeSkills) {
7762
- const filePath = path20.join(skillsDir, skill.filename);
7763
- fs26.writeFileSync(filePath, skill.content);
7758
+ const filePath = path21.join(skillsDir, skill.filename);
7759
+ fs27.writeFileSync(filePath, skill.content);
7764
7760
  written.push(filePath);
7765
7761
  }
7766
7762
  }
@@ -7837,8 +7833,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
7837
7833
  }
7838
7834
 
7839
7835
  // src/learner/writer.ts
7840
- import fs27 from "fs";
7841
- import path21 from "path";
7836
+ import fs28 from "fs";
7837
+ import path22 from "path";
7842
7838
  var LEARNINGS_FILE = "CALIBER_LEARNINGS.md";
7843
7839
  var LEARNINGS_HEADER = `# Caliber Learnings
7844
7840
 
@@ -7922,16 +7918,16 @@ function deduplicateLearnedItems(existing, incoming) {
7922
7918
  function writeLearnedSection(content) {
7923
7919
  const existingSection = readLearnedSection();
7924
7920
  const { merged, newCount, newItems } = deduplicateLearnedItems(existingSection, content);
7925
- fs27.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
7921
+ fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + merged + "\n");
7926
7922
  return { newCount, newItems };
7927
7923
  }
7928
7924
  function writeLearnedSkill(skill) {
7929
- const skillDir = path21.join(".claude", "skills", skill.name);
7930
- if (!fs27.existsSync(skillDir)) fs27.mkdirSync(skillDir, { recursive: true });
7931
- const skillPath = path21.join(skillDir, "SKILL.md");
7932
- if (!skill.isNew && fs27.existsSync(skillPath)) {
7933
- const existing = fs27.readFileSync(skillPath, "utf-8");
7934
- fs27.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
7925
+ const skillDir = path22.join(".claude", "skills", skill.name);
7926
+ if (!fs28.existsSync(skillDir)) fs28.mkdirSync(skillDir, { recursive: true });
7927
+ const skillPath = path22.join(skillDir, "SKILL.md");
7928
+ if (!skill.isNew && fs28.existsSync(skillPath)) {
7929
+ const existing = fs28.readFileSync(skillPath, "utf-8");
7930
+ fs28.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
7935
7931
  } else {
7936
7932
  const frontmatter = [
7937
7933
  "---",
@@ -7940,37 +7936,37 @@ function writeLearnedSkill(skill) {
7940
7936
  "---",
7941
7937
  ""
7942
7938
  ].join("\n");
7943
- fs27.writeFileSync(skillPath, frontmatter + skill.content);
7939
+ fs28.writeFileSync(skillPath, frontmatter + skill.content);
7944
7940
  }
7945
7941
  return skillPath;
7946
7942
  }
7947
7943
  function readLearnedSection() {
7948
- if (fs27.existsSync(LEARNINGS_FILE)) {
7949
- const content2 = fs27.readFileSync(LEARNINGS_FILE, "utf-8");
7944
+ if (fs28.existsSync(LEARNINGS_FILE)) {
7945
+ const content2 = fs28.readFileSync(LEARNINGS_FILE, "utf-8");
7950
7946
  const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
7951
7947
  return bullets || null;
7952
7948
  }
7953
7949
  const claudeMdPath = "CLAUDE.md";
7954
- if (!fs27.existsSync(claudeMdPath)) return null;
7955
- const content = fs27.readFileSync(claudeMdPath, "utf-8");
7950
+ if (!fs28.existsSync(claudeMdPath)) return null;
7951
+ const content = fs28.readFileSync(claudeMdPath, "utf-8");
7956
7952
  const startIdx = content.indexOf(LEARNED_START);
7957
7953
  const endIdx = content.indexOf(LEARNED_END);
7958
7954
  if (startIdx === -1 || endIdx === -1) return null;
7959
7955
  return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
7960
7956
  }
7961
7957
  function migrateInlineLearnings() {
7962
- if (fs27.existsSync(LEARNINGS_FILE)) return false;
7958
+ if (fs28.existsSync(LEARNINGS_FILE)) return false;
7963
7959
  const claudeMdPath = "CLAUDE.md";
7964
- if (!fs27.existsSync(claudeMdPath)) return false;
7965
- const content = fs27.readFileSync(claudeMdPath, "utf-8");
7960
+ if (!fs28.existsSync(claudeMdPath)) return false;
7961
+ const content = fs28.readFileSync(claudeMdPath, "utf-8");
7966
7962
  const startIdx = content.indexOf(LEARNED_START);
7967
7963
  const endIdx = content.indexOf(LEARNED_END);
7968
7964
  if (startIdx === -1 || endIdx === -1) return false;
7969
7965
  const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
7970
7966
  if (!section) return false;
7971
- fs27.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
7967
+ fs28.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
7972
7968
  const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
7973
- fs27.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
7969
+ fs28.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
7974
7970
  return true;
7975
7971
  }
7976
7972
 
@@ -7982,11 +7978,11 @@ function log2(quiet, ...args) {
7982
7978
  function discoverGitRepos(parentDir) {
7983
7979
  const repos = [];
7984
7980
  try {
7985
- const entries = fs29.readdirSync(parentDir, { withFileTypes: true });
7981
+ const entries = fs30.readdirSync(parentDir, { withFileTypes: true });
7986
7982
  for (const entry of entries) {
7987
7983
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
7988
- const childPath = path23.join(parentDir, entry.name);
7989
- if (fs29.existsSync(path23.join(childPath, ".git"))) {
7984
+ const childPath = path24.join(parentDir, entry.name);
7985
+ if (fs30.existsSync(path24.join(childPath, ".git"))) {
7990
7986
  repos.push(childPath);
7991
7987
  }
7992
7988
  }
@@ -8089,7 +8085,7 @@ async function refreshCommand(options) {
8089
8085
  `));
8090
8086
  const originalDir = process.cwd();
8091
8087
  for (const repo of repos) {
8092
- const repoName = path23.basename(repo);
8088
+ const repoName = path24.basename(repo);
8093
8089
  try {
8094
8090
  process.chdir(repo);
8095
8091
  await refreshSingleRepo(repo, { ...options, label: repoName });
@@ -8313,7 +8309,7 @@ async function configCommand() {
8313
8309
  }
8314
8310
 
8315
8311
  // src/commands/learn.ts
8316
- import fs31 from "fs";
8312
+ import fs32 from "fs";
8317
8313
  import chalk18 from "chalk";
8318
8314
 
8319
8315
  // src/learner/stdin.ts
@@ -8345,8 +8341,8 @@ function readStdin() {
8345
8341
 
8346
8342
  // src/learner/storage.ts
8347
8343
  init_constants();
8348
- import fs30 from "fs";
8349
- import path24 from "path";
8344
+ import fs31 from "fs";
8345
+ import path25 from "path";
8350
8346
  var MAX_RESPONSE_LENGTH = 2e3;
8351
8347
  var DEFAULT_STATE = {
8352
8348
  sessionId: null,
@@ -8354,15 +8350,15 @@ var DEFAULT_STATE = {
8354
8350
  lastAnalysisTimestamp: null
8355
8351
  };
8356
8352
  function ensureLearningDir() {
8357
- if (!fs30.existsSync(LEARNING_DIR)) {
8358
- fs30.mkdirSync(LEARNING_DIR, { recursive: true });
8353
+ if (!fs31.existsSync(LEARNING_DIR)) {
8354
+ fs31.mkdirSync(LEARNING_DIR, { recursive: true });
8359
8355
  }
8360
8356
  }
8361
8357
  function sessionFilePath() {
8362
- return path24.join(LEARNING_DIR, LEARNING_SESSION_FILE);
8358
+ return path25.join(LEARNING_DIR, LEARNING_SESSION_FILE);
8363
8359
  }
8364
8360
  function stateFilePath() {
8365
- return path24.join(LEARNING_DIR, LEARNING_STATE_FILE);
8361
+ return path25.join(LEARNING_DIR, LEARNING_STATE_FILE);
8366
8362
  }
8367
8363
  function truncateResponse(response) {
8368
8364
  const str = JSON.stringify(response);
@@ -8373,29 +8369,29 @@ function appendEvent(event) {
8373
8369
  ensureLearningDir();
8374
8370
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
8375
8371
  const filePath = sessionFilePath();
8376
- fs30.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
8372
+ fs31.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
8377
8373
  const count = getEventCount();
8378
8374
  if (count > LEARNING_MAX_EVENTS) {
8379
- const lines = fs30.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8375
+ const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8380
8376
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
8381
- fs30.writeFileSync(filePath, kept.join("\n") + "\n");
8377
+ fs31.writeFileSync(filePath, kept.join("\n") + "\n");
8382
8378
  }
8383
8379
  }
8384
8380
  function appendPromptEvent(event) {
8385
8381
  ensureLearningDir();
8386
8382
  const filePath = sessionFilePath();
8387
- fs30.appendFileSync(filePath, JSON.stringify(event) + "\n");
8383
+ fs31.appendFileSync(filePath, JSON.stringify(event) + "\n");
8388
8384
  const count = getEventCount();
8389
8385
  if (count > LEARNING_MAX_EVENTS) {
8390
- const lines = fs30.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8386
+ const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8391
8387
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
8392
- fs30.writeFileSync(filePath, kept.join("\n") + "\n");
8388
+ fs31.writeFileSync(filePath, kept.join("\n") + "\n");
8393
8389
  }
8394
8390
  }
8395
8391
  function readAllEvents() {
8396
8392
  const filePath = sessionFilePath();
8397
- if (!fs30.existsSync(filePath)) return [];
8398
- const lines = fs30.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8393
+ if (!fs31.existsSync(filePath)) return [];
8394
+ const lines = fs31.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8399
8395
  const events = [];
8400
8396
  for (const line of lines) {
8401
8397
  try {
@@ -8407,26 +8403,26 @@ function readAllEvents() {
8407
8403
  }
8408
8404
  function getEventCount() {
8409
8405
  const filePath = sessionFilePath();
8410
- if (!fs30.existsSync(filePath)) return 0;
8411
- const content = fs30.readFileSync(filePath, "utf-8");
8406
+ if (!fs31.existsSync(filePath)) return 0;
8407
+ const content = fs31.readFileSync(filePath, "utf-8");
8412
8408
  return content.split("\n").filter(Boolean).length;
8413
8409
  }
8414
8410
  function clearSession() {
8415
8411
  const filePath = sessionFilePath();
8416
- if (fs30.existsSync(filePath)) fs30.unlinkSync(filePath);
8412
+ if (fs31.existsSync(filePath)) fs31.unlinkSync(filePath);
8417
8413
  }
8418
8414
  function readState2() {
8419
8415
  const filePath = stateFilePath();
8420
- if (!fs30.existsSync(filePath)) return { ...DEFAULT_STATE };
8416
+ if (!fs31.existsSync(filePath)) return { ...DEFAULT_STATE };
8421
8417
  try {
8422
- return JSON.parse(fs30.readFileSync(filePath, "utf-8"));
8418
+ return JSON.parse(fs31.readFileSync(filePath, "utf-8"));
8423
8419
  } catch {
8424
8420
  return { ...DEFAULT_STATE };
8425
8421
  }
8426
8422
  }
8427
8423
  function writeState2(state) {
8428
8424
  ensureLearningDir();
8429
- fs30.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
8425
+ fs31.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
8430
8426
  }
8431
8427
  function resetState() {
8432
8428
  writeState2({ ...DEFAULT_STATE });
@@ -8434,14 +8430,14 @@ function resetState() {
8434
8430
  var LOCK_FILE2 = "finalize.lock";
8435
8431
  var LOCK_STALE_MS = 5 * 60 * 1e3;
8436
8432
  function lockFilePath() {
8437
- return path24.join(LEARNING_DIR, LOCK_FILE2);
8433
+ return path25.join(LEARNING_DIR, LOCK_FILE2);
8438
8434
  }
8439
8435
  function acquireFinalizeLock() {
8440
8436
  ensureLearningDir();
8441
8437
  const lockPath = lockFilePath();
8442
- if (fs30.existsSync(lockPath)) {
8438
+ if (fs31.existsSync(lockPath)) {
8443
8439
  try {
8444
- const stat = fs30.statSync(lockPath);
8440
+ const stat = fs31.statSync(lockPath);
8445
8441
  if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
8446
8442
  return false;
8447
8443
  }
@@ -8449,7 +8445,7 @@ function acquireFinalizeLock() {
8449
8445
  }
8450
8446
  }
8451
8447
  try {
8452
- fs30.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
8448
+ fs31.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
8453
8449
  return true;
8454
8450
  } catch {
8455
8451
  return false;
@@ -8458,7 +8454,7 @@ function acquireFinalizeLock() {
8458
8454
  function releaseFinalizeLock() {
8459
8455
  const lockPath = lockFilePath();
8460
8456
  try {
8461
- if (fs30.existsSync(lockPath)) fs30.unlinkSync(lockPath);
8457
+ if (fs31.existsSync(lockPath)) fs31.unlinkSync(lockPath);
8462
8458
  } catch {
8463
8459
  }
8464
8460
  }
@@ -8690,7 +8686,7 @@ async function learnFinalizeCommand(options) {
8690
8686
  }
8691
8687
  async function learnInstallCommand() {
8692
8688
  let anyInstalled = false;
8693
- if (fs31.existsSync(".claude")) {
8689
+ if (fs32.existsSync(".claude")) {
8694
8690
  const r = installLearningHooks();
8695
8691
  if (r.installed) {
8696
8692
  console.log(chalk18.green("\u2713") + " Claude Code learning hooks installed");
@@ -8699,7 +8695,7 @@ async function learnInstallCommand() {
8699
8695
  console.log(chalk18.dim(" Claude Code hooks already installed"));
8700
8696
  }
8701
8697
  }
8702
- if (fs31.existsSync(".cursor")) {
8698
+ if (fs32.existsSync(".cursor")) {
8703
8699
  const r = installCursorLearningHooks();
8704
8700
  if (r.installed) {
8705
8701
  console.log(chalk18.green("\u2713") + " Cursor learning hooks installed");
@@ -8708,7 +8704,7 @@ async function learnInstallCommand() {
8708
8704
  console.log(chalk18.dim(" Cursor hooks already installed"));
8709
8705
  }
8710
8706
  }
8711
- if (!fs31.existsSync(".claude") && !fs31.existsSync(".cursor")) {
8707
+ if (!fs32.existsSync(".claude") && !fs32.existsSync(".cursor")) {
8712
8708
  console.log(chalk18.yellow("No .claude/ or .cursor/ directory found."));
8713
8709
  console.log(chalk18.dim(" Run `caliber init` first, or create the directory manually."));
8714
8710
  return;
@@ -8771,9 +8767,9 @@ Learned items in CALIBER_LEARNINGS.md: ${chalk18.cyan(String(lineCount))}`);
8771
8767
  }
8772
8768
 
8773
8769
  // src/cli.ts
8774
- var __dirname = path25.dirname(fileURLToPath(import.meta.url));
8770
+ var __dirname = path26.dirname(fileURLToPath(import.meta.url));
8775
8771
  var pkg = JSON.parse(
8776
- fs32.readFileSync(path25.resolve(__dirname, "..", "package.json"), "utf-8")
8772
+ fs33.readFileSync(path26.resolve(__dirname, "..", "package.json"), "utf-8")
8777
8773
  );
8778
8774
  var program = new Command();
8779
8775
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -8847,22 +8843,42 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
8847
8843
  learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
8848
8844
 
8849
8845
  // src/utils/version-check.ts
8850
- import fs33 from "fs";
8851
- import path26 from "path";
8846
+ import fs34 from "fs";
8847
+ import path27 from "path";
8852
8848
  import { fileURLToPath as fileURLToPath2 } from "url";
8853
8849
  import { execSync as execSync14 } from "child_process";
8854
8850
  import chalk19 from "chalk";
8855
8851
  import ora6 from "ora";
8856
8852
  import confirm2 from "@inquirer/confirm";
8857
- var __dirname_vc = path26.dirname(fileURLToPath2(import.meta.url));
8853
+ var __dirname_vc = path27.dirname(fileURLToPath2(import.meta.url));
8858
8854
  var pkg2 = JSON.parse(
8859
- fs33.readFileSync(path26.resolve(__dirname_vc, "..", "package.json"), "utf-8")
8855
+ fs34.readFileSync(path27.resolve(__dirname_vc, "..", "package.json"), "utf-8")
8860
8856
  );
8857
+ function getChannel(version) {
8858
+ const match = version.match(/-(dev|next)\./);
8859
+ return match ? match[1] : "latest";
8860
+ }
8861
+ function isNewer(registry, current) {
8862
+ const parse = (v) => {
8863
+ const [core, pre] = v.split("-");
8864
+ const parts = core.split(".").map(Number);
8865
+ return { major: parts[0], minor: parts[1], patch: parts[2], pre };
8866
+ };
8867
+ const r = parse(registry);
8868
+ const c = parse(current);
8869
+ if (r.major !== c.major) return r.major > c.major;
8870
+ if (r.minor !== c.minor) return r.minor > c.minor;
8871
+ if (r.patch !== c.patch) return r.patch > c.patch;
8872
+ if (!r.pre && c.pre) return true;
8873
+ if (r.pre && !c.pre) return false;
8874
+ if (r.pre && c.pre) return r.pre > c.pre;
8875
+ return false;
8876
+ }
8861
8877
  function getInstalledVersion() {
8862
8878
  try {
8863
8879
  const globalRoot = execSync14("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
8864
- const pkgPath = path26.join(globalRoot, "@rely-ai", "caliber", "package.json");
8865
- return JSON.parse(fs33.readFileSync(pkgPath, "utf-8")).version;
8880
+ const pkgPath = path27.join(globalRoot, "@rely-ai", "caliber", "package.json");
8881
+ return JSON.parse(fs34.readFileSync(pkgPath, "utf-8")).version;
8866
8882
  } catch {
8867
8883
  return null;
8868
8884
  }
@@ -8870,9 +8886,11 @@ function getInstalledVersion() {
8870
8886
  async function checkForUpdates() {
8871
8887
  if (process.env.CALIBER_SKIP_UPDATE_CHECK) return;
8872
8888
  try {
8889
+ const current = pkg2.version;
8890
+ const channel = getChannel(current);
8873
8891
  const controller = new AbortController();
8874
8892
  const timeout = setTimeout(() => controller.abort(), 2e3);
8875
- const res = await fetch("https://registry.npmjs.org/@rely-ai/caliber/latest", {
8893
+ const res = await fetch(`https://registry.npmjs.org/@rely-ai/caliber/${channel}`, {
8876
8894
  signal: controller.signal
8877
8895
  });
8878
8896
  clearTimeout(timeout);
@@ -8880,15 +8898,15 @@ async function checkForUpdates() {
8880
8898
  const data = await res.json();
8881
8899
  const latest = data.version;
8882
8900
  if (!latest) return;
8883
- const current = pkg2.version;
8884
- if (current === latest) return;
8901
+ if (!isNewer(latest, current)) return;
8885
8902
  const isInteractive = process.stdin.isTTY === true;
8886
8903
  if (!isInteractive) {
8904
+ const installTag = channel === "latest" ? "" : `@${channel}`;
8887
8905
  console.log(
8888
8906
  chalk19.yellow(
8889
8907
  `
8890
8908
  Update available: ${current} -> ${latest}
8891
- Run ${chalk19.bold("npm install -g @rely-ai/caliber")} to upgrade.
8909
+ Run ${chalk19.bold(`npm install -g @rely-ai/caliber${installTag}`)} to upgrade.
8892
8910
  `
8893
8911
  )
8894
8912
  );
@@ -8903,9 +8921,10 @@ Update available: ${current} -> ${latest}`)
8903
8921
  console.log();
8904
8922
  return;
8905
8923
  }
8924
+ const tag = channel === "latest" ? latest : channel;
8906
8925
  const spinner = ora6("Updating caliber...").start();
8907
8926
  try {
8908
- execSync14(`npm install -g @rely-ai/caliber@${latest}`, {
8927
+ execSync14(`npm install -g @rely-ai/caliber@${tag}`, {
8909
8928
  stdio: "pipe",
8910
8929
  timeout: 12e4,
8911
8930
  env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
@@ -8913,7 +8932,7 @@ Update available: ${current} -> ${latest}`)
8913
8932
  const installed = getInstalledVersion();
8914
8933
  if (installed !== latest) {
8915
8934
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
8916
- console.log(chalk19.yellow(`Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
8935
+ console.log(chalk19.yellow(`Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
8917
8936
  `));
8918
8937
  return;
8919
8938
  }
@@ -8936,7 +8955,7 @@ Restarting: caliber ${args.join(" ")}
8936
8955
  }
8937
8956
  console.log(
8938
8957
  chalk19.yellow(
8939
- `Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
8958
+ `Run ${chalk19.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually to upgrade.
8940
8959
  `
8941
8960
  )
8942
8961
  );