@rely-ai/caliber 1.7.4 → 1.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.js +369 -194
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -165,17 +165,18 @@ var init_constants = __esm({
165
165
 
166
166
  // src/cli.ts
167
167
  import { Command } from "commander";
168
- import fs28 from "fs";
169
- import path22 from "path";
168
+ import fs30 from "fs";
169
+ import path24 from "path";
170
170
  import { fileURLToPath } from "url";
171
171
 
172
172
  // src/commands/onboard.ts
173
+ import path19 from "path";
173
174
  import chalk8 from "chalk";
174
175
  import ora2 from "ora";
175
176
  import readline3 from "readline";
176
177
  import select5 from "@inquirer/select";
177
178
  import checkbox from "@inquirer/checkbox";
178
- import fs22 from "fs";
179
+ import fs24 from "fs";
179
180
 
180
181
  // src/fingerprint/index.ts
181
182
  import fs6 from "fs";
@@ -2670,28 +2671,64 @@ ${agentRefs.join(" ")}
2670
2671
  }
2671
2672
 
2672
2673
  // src/lib/hooks.ts
2673
- import fs16 from "fs";
2674
+ import fs17 from "fs";
2674
2675
  import path12 from "path";
2676
+ import { execSync as execSync6 } from "child_process";
2677
+
2678
+ // src/lib/resolve-caliber.ts
2679
+ import fs16 from "fs";
2675
2680
  import { execSync as execSync5 } from "child_process";
2681
+ var _resolved = null;
2682
+ function resolveCaliber() {
2683
+ if (_resolved) return _resolved;
2684
+ try {
2685
+ const found = execSync5("which caliber", {
2686
+ encoding: "utf-8",
2687
+ stdio: ["pipe", "pipe", "pipe"]
2688
+ }).trim();
2689
+ if (found) {
2690
+ _resolved = found;
2691
+ return _resolved;
2692
+ }
2693
+ } catch {
2694
+ }
2695
+ const binPath = process.argv[1];
2696
+ if (binPath && fs16.existsSync(binPath)) {
2697
+ _resolved = binPath;
2698
+ return _resolved;
2699
+ }
2700
+ _resolved = "caliber";
2701
+ return _resolved;
2702
+ }
2703
+ function isCaliberCommand(command, subcommandTail) {
2704
+ if (command === `caliber ${subcommandTail}`) return true;
2705
+ if (command.endsWith(`/caliber ${subcommandTail}`)) return true;
2706
+ return false;
2707
+ }
2708
+
2709
+ // src/lib/hooks.ts
2676
2710
  var SETTINGS_PATH = path12.join(".claude", "settings.json");
2677
- var HOOK_COMMAND = "caliber refresh --quiet";
2711
+ var REFRESH_TAIL = "refresh --quiet";
2678
2712
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
2713
+ function getHookCommand() {
2714
+ return `${resolveCaliber()} ${REFRESH_TAIL}`;
2715
+ }
2679
2716
  function readSettings() {
2680
- if (!fs16.existsSync(SETTINGS_PATH)) return {};
2717
+ if (!fs17.existsSync(SETTINGS_PATH)) return {};
2681
2718
  try {
2682
- return JSON.parse(fs16.readFileSync(SETTINGS_PATH, "utf-8"));
2719
+ return JSON.parse(fs17.readFileSync(SETTINGS_PATH, "utf-8"));
2683
2720
  } catch {
2684
2721
  return {};
2685
2722
  }
2686
2723
  }
2687
2724
  function writeSettings(settings) {
2688
2725
  const dir = path12.dirname(SETTINGS_PATH);
2689
- if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
2690
- fs16.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
2726
+ if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
2727
+ fs17.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
2691
2728
  }
2692
2729
  function findHookIndex(sessionEnd) {
2693
2730
  return sessionEnd.findIndex(
2694
- (entry) => entry.hooks?.some((h) => h.command === HOOK_COMMAND)
2731
+ (entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, REFRESH_TAIL))
2695
2732
  );
2696
2733
  }
2697
2734
  function isHookInstalled() {
@@ -2709,7 +2746,7 @@ function installHook() {
2709
2746
  }
2710
2747
  settings.hooks.SessionEnd.push({
2711
2748
  matcher: "",
2712
- hooks: [{ type: "command", command: HOOK_COMMAND, description: HOOK_DESCRIPTION }]
2749
+ hooks: [{ type: "command", command: getHookCommand(), description: HOOK_DESCRIPTION }]
2713
2750
  });
2714
2751
  writeSettings(settings);
2715
2752
  return { installed: true, alreadyInstalled: false };
@@ -2736,16 +2773,19 @@ function removeHook() {
2736
2773
  }
2737
2774
  var PRECOMMIT_START = "# caliber:pre-commit:start";
2738
2775
  var PRECOMMIT_END = "# caliber:pre-commit:end";
2739
- var PRECOMMIT_BLOCK = `${PRECOMMIT_START}
2740
- if command -v caliber >/dev/null 2>&1; then
2776
+ function getPrecommitBlock() {
2777
+ const bin = resolveCaliber();
2778
+ return `${PRECOMMIT_START}
2779
+ if [ -x "${bin}" ] || command -v "${bin}" >/dev/null 2>&1; then
2741
2780
  echo "\\033[2mcaliber: refreshing docs...\\033[0m"
2742
- caliber refresh 2>/dev/null || true
2781
+ "${bin}" refresh 2>/dev/null || true
2743
2782
  git diff --name-only -- CLAUDE.md .claude/ .cursor/ AGENTS.md 2>/dev/null | xargs git add 2>/dev/null || true
2744
2783
  fi
2745
2784
  ${PRECOMMIT_END}`;
2785
+ }
2746
2786
  function getGitHooksDir() {
2747
2787
  try {
2748
- const gitDir = execSync5("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
2788
+ const gitDir = execSync6("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
2749
2789
  return path12.join(gitDir, "hooks");
2750
2790
  } catch {
2751
2791
  return null;
@@ -2757,8 +2797,8 @@ function getPreCommitPath() {
2757
2797
  }
2758
2798
  function isPreCommitHookInstalled() {
2759
2799
  const hookPath = getPreCommitPath();
2760
- if (!hookPath || !fs16.existsSync(hookPath)) return false;
2761
- const content = fs16.readFileSync(hookPath, "utf-8");
2800
+ if (!hookPath || !fs17.existsSync(hookPath)) return false;
2801
+ const content = fs17.readFileSync(hookPath, "utf-8");
2762
2802
  return content.includes(PRECOMMIT_START);
2763
2803
  }
2764
2804
  function installPreCommitHook() {
@@ -2768,81 +2808,78 @@ function installPreCommitHook() {
2768
2808
  const hookPath = getPreCommitPath();
2769
2809
  if (!hookPath) return { installed: false, alreadyInstalled: false };
2770
2810
  const hooksDir = path12.dirname(hookPath);
2771
- if (!fs16.existsSync(hooksDir)) fs16.mkdirSync(hooksDir, { recursive: true });
2811
+ if (!fs17.existsSync(hooksDir)) fs17.mkdirSync(hooksDir, { recursive: true });
2772
2812
  let content = "";
2773
- if (fs16.existsSync(hookPath)) {
2774
- content = fs16.readFileSync(hookPath, "utf-8");
2813
+ if (fs17.existsSync(hookPath)) {
2814
+ content = fs17.readFileSync(hookPath, "utf-8");
2775
2815
  if (!content.endsWith("\n")) content += "\n";
2776
- content += "\n" + PRECOMMIT_BLOCK + "\n";
2816
+ content += "\n" + getPrecommitBlock() + "\n";
2777
2817
  } else {
2778
- content = "#!/bin/sh\n\n" + PRECOMMIT_BLOCK + "\n";
2818
+ content = "#!/bin/sh\n\n" + getPrecommitBlock() + "\n";
2779
2819
  }
2780
- fs16.writeFileSync(hookPath, content);
2781
- fs16.chmodSync(hookPath, 493);
2820
+ fs17.writeFileSync(hookPath, content);
2821
+ fs17.chmodSync(hookPath, 493);
2782
2822
  return { installed: true, alreadyInstalled: false };
2783
2823
  }
2784
2824
  function removePreCommitHook() {
2785
2825
  const hookPath = getPreCommitPath();
2786
- if (!hookPath || !fs16.existsSync(hookPath)) {
2826
+ if (!hookPath || !fs17.existsSync(hookPath)) {
2787
2827
  return { removed: false, notFound: true };
2788
2828
  }
2789
- let content = fs16.readFileSync(hookPath, "utf-8");
2829
+ let content = fs17.readFileSync(hookPath, "utf-8");
2790
2830
  if (!content.includes(PRECOMMIT_START)) {
2791
2831
  return { removed: false, notFound: true };
2792
2832
  }
2793
2833
  const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
2794
2834
  content = content.replace(regex, "\n");
2795
2835
  if (content.trim() === "#!/bin/sh" || content.trim() === "") {
2796
- fs16.unlinkSync(hookPath);
2836
+ fs17.unlinkSync(hookPath);
2797
2837
  } else {
2798
- fs16.writeFileSync(hookPath, content);
2838
+ fs17.writeFileSync(hookPath, content);
2799
2839
  }
2800
2840
  return { removed: true, notFound: false };
2801
2841
  }
2802
2842
 
2803
2843
  // src/lib/learning-hooks.ts
2804
- import fs17 from "fs";
2844
+ import fs18 from "fs";
2805
2845
  import path13 from "path";
2806
2846
  var SETTINGS_PATH2 = path13.join(".claude", "settings.json");
2807
- var HOOK_CONFIGS = [
2808
- {
2809
- event: "PostToolUse",
2810
- command: "caliber learn observe",
2811
- description: "Caliber: recording tool usage for session learning"
2812
- },
2813
- {
2814
- event: "PostToolUseFailure",
2815
- command: "caliber learn observe --failure",
2816
- description: "Caliber: recording tool failure for session learning"
2817
- },
2818
- {
2819
- event: "SessionEnd",
2820
- command: "caliber learn finalize",
2821
- description: "Caliber: finalizing session learnings"
2822
- }
2847
+ var HOOK_TAILS = [
2848
+ { event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
2849
+ { event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
2850
+ { event: "SessionEnd", tail: "learn finalize", description: "Caliber: finalizing session learnings" }
2823
2851
  ];
2852
+ function getHookConfigs() {
2853
+ const bin = resolveCaliber();
2854
+ return HOOK_TAILS.map(({ event, tail, description }) => ({
2855
+ event,
2856
+ command: `${bin} ${tail}`,
2857
+ tail,
2858
+ description
2859
+ }));
2860
+ }
2824
2861
  function readSettings2() {
2825
- if (!fs17.existsSync(SETTINGS_PATH2)) return {};
2862
+ if (!fs18.existsSync(SETTINGS_PATH2)) return {};
2826
2863
  try {
2827
- return JSON.parse(fs17.readFileSync(SETTINGS_PATH2, "utf-8"));
2864
+ return JSON.parse(fs18.readFileSync(SETTINGS_PATH2, "utf-8"));
2828
2865
  } catch {
2829
2866
  return {};
2830
2867
  }
2831
2868
  }
2832
2869
  function writeSettings2(settings) {
2833
2870
  const dir = path13.dirname(SETTINGS_PATH2);
2834
- if (!fs17.existsSync(dir)) fs17.mkdirSync(dir, { recursive: true });
2835
- fs17.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
2871
+ if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
2872
+ fs18.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
2836
2873
  }
2837
- function hasLearningHook(matchers, command) {
2838
- return matchers.some((entry) => entry.hooks?.some((h) => h.command === command));
2874
+ function hasLearningHook(matchers, tail) {
2875
+ return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
2839
2876
  }
2840
2877
  function areLearningHooksInstalled() {
2841
2878
  const settings = readSettings2();
2842
2879
  if (!settings.hooks) return false;
2843
- return HOOK_CONFIGS.every((cfg) => {
2880
+ return HOOK_TAILS.every((cfg) => {
2844
2881
  const matchers = settings.hooks[cfg.event];
2845
- return Array.isArray(matchers) && hasLearningHook(matchers, cfg.command);
2882
+ return Array.isArray(matchers) && hasLearningHook(matchers, cfg.tail);
2846
2883
  });
2847
2884
  }
2848
2885
  function installLearningHooks() {
@@ -2851,11 +2888,12 @@ function installLearningHooks() {
2851
2888
  }
2852
2889
  const settings = readSettings2();
2853
2890
  if (!settings.hooks) settings.hooks = {};
2854
- for (const cfg of HOOK_CONFIGS) {
2891
+ const configs = getHookConfigs();
2892
+ for (const cfg of configs) {
2855
2893
  if (!Array.isArray(settings.hooks[cfg.event])) {
2856
2894
  settings.hooks[cfg.event] = [];
2857
2895
  }
2858
- if (!hasLearningHook(settings.hooks[cfg.event], cfg.command)) {
2896
+ if (!hasLearningHook(settings.hooks[cfg.event], cfg.tail)) {
2859
2897
  settings.hooks[cfg.event].push({
2860
2898
  matcher: "",
2861
2899
  hooks: [{ type: "command", command: cfg.command, description: cfg.description }]
@@ -2869,10 +2907,10 @@ function removeLearningHooks() {
2869
2907
  const settings = readSettings2();
2870
2908
  if (!settings.hooks) return { removed: false, notFound: true };
2871
2909
  let removedAny = false;
2872
- for (const cfg of HOOK_CONFIGS) {
2910
+ for (const cfg of HOOK_TAILS) {
2873
2911
  const matchers = settings.hooks[cfg.event];
2874
2912
  if (!Array.isArray(matchers)) continue;
2875
- const idx = matchers.findIndex((entry) => entry.hooks?.some((h) => h.command === cfg.command));
2913
+ const idx = matchers.findIndex((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, cfg.tail)));
2876
2914
  if (idx !== -1) {
2877
2915
  matchers.splice(idx, 1);
2878
2916
  removedAny = true;
@@ -2889,9 +2927,9 @@ function removeLearningHooks() {
2889
2927
 
2890
2928
  // src/lib/state.ts
2891
2929
  init_constants();
2892
- import fs18 from "fs";
2930
+ import fs19 from "fs";
2893
2931
  import path14 from "path";
2894
- import { execSync as execSync6 } from "child_process";
2932
+ import { execSync as execSync7 } from "child_process";
2895
2933
  var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
2896
2934
  function normalizeTargetAgent(value) {
2897
2935
  if (Array.isArray(value)) return value;
@@ -2903,8 +2941,8 @@ function normalizeTargetAgent(value) {
2903
2941
  }
2904
2942
  function readState() {
2905
2943
  try {
2906
- if (!fs18.existsSync(STATE_FILE)) return null;
2907
- const raw = JSON.parse(fs18.readFileSync(STATE_FILE, "utf-8"));
2944
+ if (!fs19.existsSync(STATE_FILE)) return null;
2945
+ const raw = JSON.parse(fs19.readFileSync(STATE_FILE, "utf-8"));
2908
2946
  if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
2909
2947
  return raw;
2910
2948
  } catch {
@@ -2912,14 +2950,14 @@ function readState() {
2912
2950
  }
2913
2951
  }
2914
2952
  function writeState(state) {
2915
- if (!fs18.existsSync(CALIBER_DIR)) {
2916
- fs18.mkdirSync(CALIBER_DIR, { recursive: true });
2953
+ if (!fs19.existsSync(CALIBER_DIR)) {
2954
+ fs19.mkdirSync(CALIBER_DIR, { recursive: true });
2917
2955
  }
2918
- fs18.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
2956
+ fs19.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
2919
2957
  }
2920
2958
  function getCurrentHeadSha() {
2921
2959
  try {
2922
- return execSync6("git rev-parse HEAD", {
2960
+ return execSync7("git rev-parse HEAD", {
2923
2961
  encoding: "utf-8",
2924
2962
  stdio: ["pipe", "pipe", "pipe"]
2925
2963
  }).trim();
@@ -3205,15 +3243,15 @@ function computeGrade(score) {
3205
3243
  // src/scoring/checks/coverage.ts
3206
3244
  import { readFileSync, readdirSync } from "fs";
3207
3245
  import { join } from "path";
3208
- function readFileOrNull(path24) {
3246
+ function readFileOrNull(path26) {
3209
3247
  try {
3210
- return readFileSync(path24, "utf-8");
3248
+ return readFileSync(path26, "utf-8");
3211
3249
  } catch {
3212
3250
  return null;
3213
3251
  }
3214
3252
  }
3215
- function readJsonOrNull(path24) {
3216
- const content = readFileOrNull(path24);
3253
+ function readJsonOrNull(path26) {
3254
+ const content = readFileOrNull(path26);
3217
3255
  if (!content) return null;
3218
3256
  try {
3219
3257
  return JSON.parse(content);
@@ -3581,9 +3619,9 @@ function checkExistence(dir) {
3581
3619
  // src/scoring/checks/quality.ts
3582
3620
  import { readFileSync as readFileSync3 } from "fs";
3583
3621
  import { join as join3 } from "path";
3584
- function readFileOrNull2(path24) {
3622
+ function readFileOrNull2(path26) {
3585
3623
  try {
3586
- return readFileSync3(path24, "utf-8");
3624
+ return readFileSync3(path26, "utf-8");
3587
3625
  } catch {
3588
3626
  return null;
3589
3627
  }
@@ -3736,15 +3774,15 @@ function checkQuality(dir) {
3736
3774
  // src/scoring/checks/accuracy.ts
3737
3775
  import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync } from "fs";
3738
3776
  import { join as join4 } from "path";
3739
- function readFileOrNull3(path24) {
3777
+ function readFileOrNull3(path26) {
3740
3778
  try {
3741
- return readFileSync4(path24, "utf-8");
3779
+ return readFileSync4(path26, "utf-8");
3742
3780
  } catch {
3743
3781
  return null;
3744
3782
  }
3745
3783
  }
3746
- function readJsonOrNull2(path24) {
3747
- const content = readFileOrNull3(path24);
3784
+ function readJsonOrNull2(path26) {
3785
+ const content = readFileOrNull3(path26);
3748
3786
  if (!content) return null;
3749
3787
  try {
3750
3788
  return JSON.parse(content);
@@ -3927,9 +3965,9 @@ function checkAccuracy(dir) {
3927
3965
  // src/scoring/checks/freshness.ts
3928
3966
  import { existsSync as existsSync6, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
3929
3967
  import { join as join5 } from "path";
3930
- function readFileOrNull4(path24) {
3968
+ function readFileOrNull4(path26) {
3931
3969
  try {
3932
- return readFileSync5(path24, "utf-8");
3970
+ return readFileSync5(path26, "utf-8");
3933
3971
  } catch {
3934
3972
  return null;
3935
3973
  }
@@ -4041,18 +4079,18 @@ function checkFreshness(dir) {
4041
4079
 
4042
4080
  // src/scoring/checks/bonus.ts
4043
4081
  import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
4044
- import { execSync as execSync7 } from "child_process";
4082
+ import { execSync as execSync8 } from "child_process";
4045
4083
  import { join as join6 } from "path";
4046
- function readFileOrNull5(path24) {
4084
+ function readFileOrNull5(path26) {
4047
4085
  try {
4048
- return readFileSync6(path24, "utf-8");
4086
+ return readFileSync6(path26, "utf-8");
4049
4087
  } catch {
4050
4088
  return null;
4051
4089
  }
4052
4090
  }
4053
4091
  function hasPreCommitHook(dir) {
4054
4092
  try {
4055
- const gitDir = execSync7("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
4093
+ const gitDir = execSync8("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
4056
4094
  const hookPath = join6(gitDir, "hooks", "pre-commit");
4057
4095
  const content = readFileOrNull5(hookPath);
4058
4096
  return content ? content.includes("caliber") : false;
@@ -4140,22 +4178,22 @@ function checkBonus(dir) {
4140
4178
 
4141
4179
  // src/scoring/dismissed.ts
4142
4180
  init_constants();
4143
- import fs19 from "fs";
4181
+ import fs20 from "fs";
4144
4182
  import path15 from "path";
4145
4183
  var DISMISSED_FILE = path15.join(CALIBER_DIR, "dismissed-checks.json");
4146
4184
  function readDismissedChecks() {
4147
4185
  try {
4148
- if (!fs19.existsSync(DISMISSED_FILE)) return [];
4149
- return JSON.parse(fs19.readFileSync(DISMISSED_FILE, "utf-8"));
4186
+ if (!fs20.existsSync(DISMISSED_FILE)) return [];
4187
+ return JSON.parse(fs20.readFileSync(DISMISSED_FILE, "utf-8"));
4150
4188
  } catch {
4151
4189
  return [];
4152
4190
  }
4153
4191
  }
4154
4192
  function writeDismissedChecks(checks) {
4155
- if (!fs19.existsSync(CALIBER_DIR)) {
4156
- fs19.mkdirSync(CALIBER_DIR, { recursive: true });
4193
+ if (!fs20.existsSync(CALIBER_DIR)) {
4194
+ fs20.mkdirSync(CALIBER_DIR, { recursive: true });
4157
4195
  }
4158
- fs19.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
4196
+ fs20.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
4159
4197
  }
4160
4198
  function getDismissedIds() {
4161
4199
  return new Set(readDismissedChecks().map((c) => c.id));
@@ -4350,13 +4388,13 @@ import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5,
4350
4388
  import { join as join8, dirname as dirname2 } from "path";
4351
4389
 
4352
4390
  // src/scanner/index.ts
4353
- import fs20 from "fs";
4391
+ import fs21 from "fs";
4354
4392
  import path16 from "path";
4355
4393
  import crypto2 from "crypto";
4356
4394
  function scanLocalState(dir) {
4357
4395
  const items = [];
4358
4396
  const claudeMdPath = path16.join(dir, "CLAUDE.md");
4359
- if (fs20.existsSync(claudeMdPath)) {
4397
+ if (fs21.existsSync(claudeMdPath)) {
4360
4398
  items.push({
4361
4399
  type: "rule",
4362
4400
  platform: "claude",
@@ -4366,8 +4404,8 @@ function scanLocalState(dir) {
4366
4404
  });
4367
4405
  }
4368
4406
  const skillsDir = path16.join(dir, ".claude", "skills");
4369
- if (fs20.existsSync(skillsDir)) {
4370
- for (const file of fs20.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
4407
+ if (fs21.existsSync(skillsDir)) {
4408
+ for (const file of fs21.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
4371
4409
  const filePath = path16.join(skillsDir, file);
4372
4410
  items.push({
4373
4411
  type: "skill",
@@ -4379,9 +4417,9 @@ function scanLocalState(dir) {
4379
4417
  }
4380
4418
  }
4381
4419
  const mcpJsonPath = path16.join(dir, ".mcp.json");
4382
- if (fs20.existsSync(mcpJsonPath)) {
4420
+ if (fs21.existsSync(mcpJsonPath)) {
4383
4421
  try {
4384
- const mcpJson = JSON.parse(fs20.readFileSync(mcpJsonPath, "utf-8"));
4422
+ const mcpJson = JSON.parse(fs21.readFileSync(mcpJsonPath, "utf-8"));
4385
4423
  if (mcpJson.mcpServers) {
4386
4424
  for (const name of Object.keys(mcpJson.mcpServers)) {
4387
4425
  items.push({
@@ -4397,7 +4435,7 @@ function scanLocalState(dir) {
4397
4435
  }
4398
4436
  }
4399
4437
  const agentsMdPath = path16.join(dir, "AGENTS.md");
4400
- if (fs20.existsSync(agentsMdPath)) {
4438
+ if (fs21.existsSync(agentsMdPath)) {
4401
4439
  items.push({
4402
4440
  type: "rule",
4403
4441
  platform: "codex",
@@ -4407,11 +4445,11 @@ function scanLocalState(dir) {
4407
4445
  });
4408
4446
  }
4409
4447
  const codexSkillsDir = path16.join(dir, ".agents", "skills");
4410
- if (fs20.existsSync(codexSkillsDir)) {
4448
+ if (fs21.existsSync(codexSkillsDir)) {
4411
4449
  try {
4412
- for (const name of fs20.readdirSync(codexSkillsDir)) {
4450
+ for (const name of fs21.readdirSync(codexSkillsDir)) {
4413
4451
  const skillFile = path16.join(codexSkillsDir, name, "SKILL.md");
4414
- if (fs20.existsSync(skillFile)) {
4452
+ if (fs21.existsSync(skillFile)) {
4415
4453
  items.push({
4416
4454
  type: "skill",
4417
4455
  platform: "codex",
@@ -4425,7 +4463,7 @@ function scanLocalState(dir) {
4425
4463
  }
4426
4464
  }
4427
4465
  const cursorrulesPath = path16.join(dir, ".cursorrules");
4428
- if (fs20.existsSync(cursorrulesPath)) {
4466
+ if (fs21.existsSync(cursorrulesPath)) {
4429
4467
  items.push({
4430
4468
  type: "rule",
4431
4469
  platform: "cursor",
@@ -4435,8 +4473,8 @@ function scanLocalState(dir) {
4435
4473
  });
4436
4474
  }
4437
4475
  const cursorRulesDir = path16.join(dir, ".cursor", "rules");
4438
- if (fs20.existsSync(cursorRulesDir)) {
4439
- for (const file of fs20.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
4476
+ if (fs21.existsSync(cursorRulesDir)) {
4477
+ for (const file of fs21.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
4440
4478
  const filePath = path16.join(cursorRulesDir, file);
4441
4479
  items.push({
4442
4480
  type: "rule",
@@ -4448,11 +4486,11 @@ function scanLocalState(dir) {
4448
4486
  }
4449
4487
  }
4450
4488
  const cursorSkillsDir = path16.join(dir, ".cursor", "skills");
4451
- if (fs20.existsSync(cursorSkillsDir)) {
4489
+ if (fs21.existsSync(cursorSkillsDir)) {
4452
4490
  try {
4453
- for (const name of fs20.readdirSync(cursorSkillsDir)) {
4491
+ for (const name of fs21.readdirSync(cursorSkillsDir)) {
4454
4492
  const skillFile = path16.join(cursorSkillsDir, name, "SKILL.md");
4455
- if (fs20.existsSync(skillFile)) {
4493
+ if (fs21.existsSync(skillFile)) {
4456
4494
  items.push({
4457
4495
  type: "skill",
4458
4496
  platform: "cursor",
@@ -4466,9 +4504,9 @@ function scanLocalState(dir) {
4466
4504
  }
4467
4505
  }
4468
4506
  const cursorMcpPath = path16.join(dir, ".cursor", "mcp.json");
4469
- if (fs20.existsSync(cursorMcpPath)) {
4507
+ if (fs21.existsSync(cursorMcpPath)) {
4470
4508
  try {
4471
- const mcpJson = JSON.parse(fs20.readFileSync(cursorMcpPath, "utf-8"));
4509
+ const mcpJson = JSON.parse(fs21.readFileSync(cursorMcpPath, "utf-8"));
4472
4510
  if (mcpJson.mcpServers) {
4473
4511
  for (const name of Object.keys(mcpJson.mcpServers)) {
4474
4512
  items.push({
@@ -4486,7 +4524,7 @@ function scanLocalState(dir) {
4486
4524
  return items;
4487
4525
  }
4488
4526
  function hashFile(filePath) {
4489
- const text = fs20.readFileSync(filePath, "utf-8");
4527
+ const text = fs21.readFileSync(filePath, "utf-8");
4490
4528
  return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
4491
4529
  }
4492
4530
  function hashJson(obj) {
@@ -4501,27 +4539,27 @@ import { PostHog } from "posthog-node";
4501
4539
  import chalk6 from "chalk";
4502
4540
 
4503
4541
  // src/telemetry/config.ts
4504
- import fs21 from "fs";
4542
+ import fs22 from "fs";
4505
4543
  import path17 from "path";
4506
4544
  import os3 from "os";
4507
4545
  import crypto3 from "crypto";
4508
- import { execSync as execSync8 } from "child_process";
4546
+ import { execSync as execSync9 } from "child_process";
4509
4547
  var CONFIG_DIR2 = path17.join(os3.homedir(), ".caliber");
4510
4548
  var CONFIG_FILE2 = path17.join(CONFIG_DIR2, "config.json");
4511
4549
  var runtimeDisabled = false;
4512
4550
  function readConfig() {
4513
4551
  try {
4514
- if (!fs21.existsSync(CONFIG_FILE2)) return {};
4515
- return JSON.parse(fs21.readFileSync(CONFIG_FILE2, "utf-8"));
4552
+ if (!fs22.existsSync(CONFIG_FILE2)) return {};
4553
+ return JSON.parse(fs22.readFileSync(CONFIG_FILE2, "utf-8"));
4516
4554
  } catch {
4517
4555
  return {};
4518
4556
  }
4519
4557
  }
4520
4558
  function writeConfig(config) {
4521
- if (!fs21.existsSync(CONFIG_DIR2)) {
4522
- fs21.mkdirSync(CONFIG_DIR2, { recursive: true });
4559
+ if (!fs22.existsSync(CONFIG_DIR2)) {
4560
+ fs22.mkdirSync(CONFIG_DIR2, { recursive: true });
4523
4561
  }
4524
- fs21.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
4562
+ fs22.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
4525
4563
  }
4526
4564
  function getMachineId() {
4527
4565
  const config = readConfig();
@@ -4532,7 +4570,7 @@ function getMachineId() {
4532
4570
  }
4533
4571
  function getGitEmailHash() {
4534
4572
  try {
4535
- const email = execSync8("git config user.email", { encoding: "utf-8" }).trim();
4573
+ const email = execSync9("git config user.email", { encoding: "utf-8" }).trim();
4536
4574
  if (!email) return void 0;
4537
4575
  return crypto3.createHash("sha256").update(email).digest("hex");
4538
4576
  } catch {
@@ -5229,6 +5267,93 @@ function printSkills(recs) {
5229
5267
  console.log("");
5230
5268
  }
5231
5269
 
5270
+ // src/lib/debug-report.ts
5271
+ import fs23 from "fs";
5272
+ import path18 from "path";
5273
+ var DebugReport = class {
5274
+ sections = [];
5275
+ startTime;
5276
+ stepTimings = [];
5277
+ lastStepStart;
5278
+ lastStepName = null;
5279
+ constructor() {
5280
+ this.startTime = Date.now();
5281
+ this.lastStepStart = this.startTime;
5282
+ }
5283
+ markStep(name) {
5284
+ if (this.lastStepName) {
5285
+ this.stepTimings.push({
5286
+ step: this.lastStepName,
5287
+ durationMs: Date.now() - this.lastStepStart
5288
+ });
5289
+ }
5290
+ this.lastStepName = name;
5291
+ this.lastStepStart = Date.now();
5292
+ }
5293
+ addSection(title, content) {
5294
+ this.sections.push({ title, content });
5295
+ }
5296
+ addJson(title, data) {
5297
+ this.sections.push({
5298
+ title,
5299
+ content: "```json\n" + JSON.stringify(data, null, 2) + "\n```"
5300
+ });
5301
+ }
5302
+ addCodeBlock(title, code, lang = "text") {
5303
+ this.sections.push({
5304
+ title,
5305
+ content: "```" + lang + "\n" + code + "\n```"
5306
+ });
5307
+ }
5308
+ write(outputPath) {
5309
+ if (this.lastStepName) {
5310
+ this.stepTimings.push({
5311
+ step: this.lastStepName,
5312
+ durationMs: Date.now() - this.lastStepStart
5313
+ });
5314
+ }
5315
+ const totalMs = Date.now() - this.startTime;
5316
+ const lines = [];
5317
+ lines.push("# Caliber Debug Report");
5318
+ lines.push("");
5319
+ lines.push(`- **Generated**: ${(/* @__PURE__ */ new Date()).toISOString()}`);
5320
+ lines.push(`- **CWD**: ${process.cwd()}`);
5321
+ lines.push(`- **Node**: ${process.version}`);
5322
+ lines.push(`- **Total elapsed**: ${formatMs(totalMs)}`);
5323
+ lines.push("");
5324
+ for (const section of this.sections) {
5325
+ lines.push(`## ${section.title}`);
5326
+ lines.push("");
5327
+ lines.push(section.content);
5328
+ lines.push("");
5329
+ }
5330
+ if (this.stepTimings.length > 0) {
5331
+ lines.push("## Timing");
5332
+ lines.push("");
5333
+ lines.push("| Step | Duration |");
5334
+ lines.push("|------|----------|");
5335
+ for (const t of this.stepTimings) {
5336
+ lines.push(`| ${t.step} | ${formatMs(t.durationMs)} |`);
5337
+ }
5338
+ lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
5339
+ lines.push("");
5340
+ }
5341
+ const dir = path18.dirname(outputPath);
5342
+ if (!fs23.existsSync(dir)) {
5343
+ fs23.mkdirSync(dir, { recursive: true });
5344
+ }
5345
+ fs23.writeFileSync(outputPath, lines.join("\n"));
5346
+ }
5347
+ };
5348
+ function formatMs(ms) {
5349
+ if (ms < 1e3) return `${ms}ms`;
5350
+ const secs = Math.floor(ms / 1e3);
5351
+ const mins = Math.floor(secs / 60);
5352
+ const remSecs = secs % 60;
5353
+ if (mins > 0) return `${mins}m ${remSecs}s`;
5354
+ return `${secs}s`;
5355
+ }
5356
+
5232
5357
  // src/commands/onboard.ts
5233
5358
  async function initCommand(options) {
5234
5359
  const brand = chalk8.hex("#EB9D83");
@@ -5245,6 +5370,7 @@ async function initCommand(options) {
5245
5370
  console.log(title.bold(" Welcome to Caliber\n"));
5246
5371
  console.log(chalk8.dim(" Caliber analyzes your codebase and creates tailored config files"));
5247
5372
  console.log(chalk8.dim(" so your AI coding agents understand your project from day one.\n"));
5373
+ const report = options.debugReport ? new DebugReport() : null;
5248
5374
  console.log(title.bold(" How onboarding works:\n"));
5249
5375
  console.log(chalk8.dim(" 1. Connect Set up your LLM provider"));
5250
5376
  console.log(chalk8.dim(" 2. Discover Analyze your code, dependencies, and structure"));
@@ -5276,6 +5402,12 @@ async function initCommand(options) {
5276
5402
  const fastModel = getFastModel();
5277
5403
  const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
5278
5404
  console.log(chalk8.dim(modelLine + "\n"));
5405
+ if (report) {
5406
+ report.markStep("Provider setup");
5407
+ report.addSection("LLM Provider", `- **Provider**: ${config.provider}
5408
+ - **Model**: ${displayModel}
5409
+ - **Fast model**: ${fastModel || "none"}`);
5410
+ }
5279
5411
  await validateModel({ fast: true });
5280
5412
  console.log(title.bold(" Step 2/6 \u2014 Discover your project\n"));
5281
5413
  console.log(chalk8.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
@@ -5286,6 +5418,16 @@ async function initCommand(options) {
5286
5418
  console.log(chalk8.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
5287
5419
  console.log(chalk8.dim(` Files: ${fingerprint.fileTree.length} found
5288
5420
  `));
5421
+ if (report) {
5422
+ report.markStep("Fingerprint");
5423
+ report.addJson("Fingerprint: Git", { remote: fingerprint.remote, packageName: fingerprint.packageName });
5424
+ report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
5425
+ report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
5426
+ report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
5427
+ if (fingerprint.codeAnalysis) {
5428
+ report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
5429
+ }
5430
+ }
5289
5431
  const targetAgent = options.agent || await promptAgent();
5290
5432
  trackInitAgentSelected(targetAgent);
5291
5433
  const preScore = computeLocalScore(process.cwd(), targetAgent);
@@ -5303,6 +5445,15 @@ async function initCommand(options) {
5303
5445
  displayScoreSummary(baselineScore);
5304
5446
  const passingCount = baselineScore.checks.filter((c) => c.passed).length;
5305
5447
  const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
5448
+ if (report) {
5449
+ report.markStep("Baseline scoring");
5450
+ report.addSection("Scoring: Baseline", `**Score**: ${baselineScore.score}/100
5451
+
5452
+ | Check | Passed | Points | Max |
5453
+ |-------|--------|--------|-----|
5454
+ ` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.points} | ${c.maxPoints} |`).join("\n"));
5455
+ report.addSection("Generation: Target Agents", targetAgent.join(", "));
5456
+ }
5306
5457
  const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length || fingerprint.existingConfigs.agentsMd);
5307
5458
  const NON_LLM_CHECKS = /* @__PURE__ */ new Set(["hooks_configured", "agents_md_exists", "permissions_configured", "mcp_servers"]);
5308
5459
  if (hasExistingConfig && baselineScore.score === 100) {
@@ -5356,6 +5507,11 @@ async function initCommand(options) {
5356
5507
  console.log(chalk8.dim(" Creating config files tailored to your project.\n"));
5357
5508
  }
5358
5509
  console.log(chalk8.dim(" This can take a couple of minutes depending on your model and provider.\n"));
5510
+ if (report) {
5511
+ report.markStep("Generation");
5512
+ const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
5513
+ report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
5514
+ }
5359
5515
  trackInitGenerationStarted(!!failingChecks);
5360
5516
  const genStartTime = Date.now();
5361
5517
  const genSpinner = ora2("Generating setup...").start();
@@ -5403,6 +5559,10 @@ async function initCommand(options) {
5403
5559
  }
5404
5560
  throw new Error("__exit__");
5405
5561
  }
5562
+ if (report) {
5563
+ if (rawOutput) report.addCodeBlock("Generation: Raw LLM Response", rawOutput);
5564
+ report.addJson("Generation: Parsed Setup", generatedSetup);
5565
+ }
5406
5566
  const elapsedMs = Date.now() - genStartTime;
5407
5567
  trackInitGenerationCompleted(elapsedMs, 0);
5408
5568
  const mins = Math.floor(elapsedMs / 6e4);
@@ -5550,6 +5710,14 @@ async function initCommand(options) {
5550
5710
  console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to override.\n"));
5551
5711
  return;
5552
5712
  }
5713
+ if (report) {
5714
+ report.markStep("Post-write scoring");
5715
+ report.addSection("Scoring: Post-Write", `**Score**: ${afterScore.score}/100 (delta: ${afterScore.score - baselineScore.score >= 0 ? "+" : ""}${afterScore.score - baselineScore.score})
5716
+
5717
+ | Check | Passed | Points | Max |
5718
+ |-------|--------|--------|-----|
5719
+ ` + afterScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.points} | ${c.maxPoints} |`).join("\n"));
5720
+ }
5553
5721
  displayScoreDelta(baselineScore, afterScore);
5554
5722
  console.log(title.bold("\n Step 6/6 \u2014 Community skills\n"));
5555
5723
  console.log(chalk8.dim(" Search public skill registries for skills that match your tech stack.\n"));
@@ -5581,6 +5749,13 @@ async function initCommand(options) {
5581
5749
  console.log(` ${title("caliber skills")} Discover community skills for your stack`);
5582
5750
  console.log(` ${title("caliber undo")} Revert all changes from this run`);
5583
5751
  console.log("");
5752
+ if (report) {
5753
+ report.markStep("Finished");
5754
+ const reportPath = path19.join(process.cwd(), ".caliber", "debug-report.md");
5755
+ report.write(reportPath);
5756
+ console.log(chalk8.dim(` Debug report written to ${path19.relative(process.cwd(), reportPath)}
5757
+ `));
5758
+ }
5584
5759
  }
5585
5760
  async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
5586
5761
  while (true) {
@@ -5625,7 +5800,7 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
5625
5800
  }
5626
5801
  function summarizeSetup(action, setup) {
5627
5802
  const descriptions = setup.fileDescriptions;
5628
- const files = descriptions ? Object.entries(descriptions).map(([path24, desc]) => ` ${path24}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
5803
+ const files = descriptions ? Object.entries(descriptions).map(([path26, desc]) => ` ${path26}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
5629
5804
  return `${action}. Files:
5630
5805
  ${files}`;
5631
5806
  }
@@ -5738,7 +5913,7 @@ function printSetupSummary(setup) {
5738
5913
  };
5739
5914
  if (claude) {
5740
5915
  if (claude.claudeMd) {
5741
- const icon = fs22.existsSync("CLAUDE.md") ? chalk8.yellow("~") : chalk8.green("+");
5916
+ const icon = fs24.existsSync("CLAUDE.md") ? chalk8.yellow("~") : chalk8.green("+");
5742
5917
  const desc = getDescription("CLAUDE.md");
5743
5918
  console.log(` ${icon} ${chalk8.bold("CLAUDE.md")}`);
5744
5919
  if (desc) console.log(chalk8.dim(` ${desc}`));
@@ -5748,7 +5923,7 @@ function printSetupSummary(setup) {
5748
5923
  if (Array.isArray(skills) && skills.length > 0) {
5749
5924
  for (const skill of skills) {
5750
5925
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
5751
- const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5926
+ const icon = fs24.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5752
5927
  const desc = getDescription(skillPath);
5753
5928
  console.log(` ${icon} ${chalk8.bold(skillPath)}`);
5754
5929
  console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
@@ -5759,7 +5934,7 @@ function printSetupSummary(setup) {
5759
5934
  const codex = setup.codex;
5760
5935
  if (codex) {
5761
5936
  if (codex.agentsMd) {
5762
- const icon = fs22.existsSync("AGENTS.md") ? chalk8.yellow("~") : chalk8.green("+");
5937
+ const icon = fs24.existsSync("AGENTS.md") ? chalk8.yellow("~") : chalk8.green("+");
5763
5938
  const desc = getDescription("AGENTS.md");
5764
5939
  console.log(` ${icon} ${chalk8.bold("AGENTS.md")}`);
5765
5940
  if (desc) console.log(chalk8.dim(` ${desc}`));
@@ -5769,7 +5944,7 @@ function printSetupSummary(setup) {
5769
5944
  if (Array.isArray(codexSkills) && codexSkills.length > 0) {
5770
5945
  for (const skill of codexSkills) {
5771
5946
  const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
5772
- const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5947
+ const icon = fs24.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5773
5948
  const desc = getDescription(skillPath);
5774
5949
  console.log(` ${icon} ${chalk8.bold(skillPath)}`);
5775
5950
  console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
@@ -5779,7 +5954,7 @@ function printSetupSummary(setup) {
5779
5954
  }
5780
5955
  if (cursor) {
5781
5956
  if (cursor.cursorrules) {
5782
- const icon = fs22.existsSync(".cursorrules") ? chalk8.yellow("~") : chalk8.green("+");
5957
+ const icon = fs24.existsSync(".cursorrules") ? chalk8.yellow("~") : chalk8.green("+");
5783
5958
  const desc = getDescription(".cursorrules");
5784
5959
  console.log(` ${icon} ${chalk8.bold(".cursorrules")}`);
5785
5960
  if (desc) console.log(chalk8.dim(` ${desc}`));
@@ -5789,7 +5964,7 @@ function printSetupSummary(setup) {
5789
5964
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
5790
5965
  for (const skill of cursorSkills) {
5791
5966
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
5792
- const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5967
+ const icon = fs24.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5793
5968
  const desc = getDescription(skillPath);
5794
5969
  console.log(` ${icon} ${chalk8.bold(skillPath)}`);
5795
5970
  console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
@@ -5800,7 +5975,7 @@ function printSetupSummary(setup) {
5800
5975
  if (Array.isArray(rules) && rules.length > 0) {
5801
5976
  for (const rule of rules) {
5802
5977
  const rulePath = `.cursor/rules/${rule.filename}`;
5803
- const icon = fs22.existsSync(rulePath) ? chalk8.yellow("~") : chalk8.green("+");
5978
+ const icon = fs24.existsSync(rulePath) ? chalk8.yellow("~") : chalk8.green("+");
5804
5979
  const desc = getDescription(rulePath);
5805
5980
  console.log(` ${icon} ${chalk8.bold(rulePath)}`);
5806
5981
  if (desc) {
@@ -5813,7 +5988,7 @@ function printSetupSummary(setup) {
5813
5988
  }
5814
5989
  }
5815
5990
  }
5816
- if (!codex && !fs22.existsSync("AGENTS.md")) {
5991
+ if (!codex && !fs24.existsSync("AGENTS.md")) {
5817
5992
  console.log(` ${chalk8.green("+")} ${chalk8.bold("AGENTS.md")}`);
5818
5993
  console.log(chalk8.dim(" Cross-agent coordination file"));
5819
5994
  console.log("");
@@ -5832,8 +6007,8 @@ function ensurePermissions() {
5832
6007
  const settingsPath = ".claude/settings.json";
5833
6008
  let settings = {};
5834
6009
  try {
5835
- if (fs22.existsSync(settingsPath)) {
5836
- settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
6010
+ if (fs24.existsSync(settingsPath)) {
6011
+ settings = JSON.parse(fs24.readFileSync(settingsPath, "utf-8"));
5837
6012
  }
5838
6013
  } catch {
5839
6014
  }
@@ -5847,8 +6022,8 @@ function ensurePermissions() {
5847
6022
  "Bash(git *)"
5848
6023
  ];
5849
6024
  settings.permissions = permissions;
5850
- if (!fs22.existsSync(".claude")) fs22.mkdirSync(".claude", { recursive: true });
5851
- fs22.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
6025
+ if (!fs24.existsSync(".claude")) fs24.mkdirSync(".claude", { recursive: true });
6026
+ fs24.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5852
6027
  }
5853
6028
 
5854
6029
  // src/commands/undo.ts
@@ -5885,7 +6060,7 @@ function undoCommand() {
5885
6060
 
5886
6061
  // src/commands/status.ts
5887
6062
  import chalk10 from "chalk";
5888
- import fs23 from "fs";
6063
+ import fs25 from "fs";
5889
6064
  init_config();
5890
6065
  async function statusCommand(options) {
5891
6066
  const config = loadConfig();
@@ -5912,7 +6087,7 @@ async function statusCommand(options) {
5912
6087
  }
5913
6088
  console.log(` Files managed: ${chalk10.cyan(manifest.entries.length.toString())}`);
5914
6089
  for (const entry of manifest.entries) {
5915
- const exists = fs23.existsSync(entry.path);
6090
+ const exists = fs25.existsSync(entry.path);
5916
6091
  const icon = exists ? chalk10.green("\u2713") : chalk10.red("\u2717");
5917
6092
  console.log(` ${icon} ${entry.path} (${entry.action})`);
5918
6093
  }
@@ -6093,13 +6268,13 @@ async function scoreCommand(options) {
6093
6268
  }
6094
6269
 
6095
6270
  // src/commands/refresh.ts
6096
- import fs25 from "fs";
6097
- import path19 from "path";
6271
+ import fs27 from "fs";
6272
+ import path21 from "path";
6098
6273
  import chalk13 from "chalk";
6099
6274
  import ora5 from "ora";
6100
6275
 
6101
6276
  // src/lib/git-diff.ts
6102
- import { execSync as execSync9 } from "child_process";
6277
+ import { execSync as execSync10 } from "child_process";
6103
6278
  var MAX_DIFF_BYTES = 1e5;
6104
6279
  var DOC_PATTERNS = [
6105
6280
  "CLAUDE.md",
@@ -6113,7 +6288,7 @@ function excludeArgs() {
6113
6288
  }
6114
6289
  function safeExec(cmd) {
6115
6290
  try {
6116
- return execSync9(cmd, {
6291
+ return execSync10(cmd, {
6117
6292
  encoding: "utf-8",
6118
6293
  stdio: ["pipe", "pipe", "pipe"],
6119
6294
  maxBuffer: 10 * 1024 * 1024
@@ -6171,37 +6346,37 @@ function collectDiff(lastSha) {
6171
6346
  }
6172
6347
 
6173
6348
  // src/writers/refresh.ts
6174
- import fs24 from "fs";
6175
- import path18 from "path";
6349
+ import fs26 from "fs";
6350
+ import path20 from "path";
6176
6351
  function writeRefreshDocs(docs) {
6177
6352
  const written = [];
6178
6353
  if (docs.claudeMd) {
6179
- fs24.writeFileSync("CLAUDE.md", docs.claudeMd);
6354
+ fs26.writeFileSync("CLAUDE.md", docs.claudeMd);
6180
6355
  written.push("CLAUDE.md");
6181
6356
  }
6182
6357
  if (docs.readmeMd) {
6183
- fs24.writeFileSync("README.md", docs.readmeMd);
6358
+ fs26.writeFileSync("README.md", docs.readmeMd);
6184
6359
  written.push("README.md");
6185
6360
  }
6186
6361
  if (docs.cursorrules) {
6187
- fs24.writeFileSync(".cursorrules", docs.cursorrules);
6362
+ fs26.writeFileSync(".cursorrules", docs.cursorrules);
6188
6363
  written.push(".cursorrules");
6189
6364
  }
6190
6365
  if (docs.cursorRules) {
6191
- const rulesDir = path18.join(".cursor", "rules");
6192
- if (!fs24.existsSync(rulesDir)) fs24.mkdirSync(rulesDir, { recursive: true });
6366
+ const rulesDir = path20.join(".cursor", "rules");
6367
+ if (!fs26.existsSync(rulesDir)) fs26.mkdirSync(rulesDir, { recursive: true });
6193
6368
  for (const rule of docs.cursorRules) {
6194
- const filePath = path18.join(rulesDir, rule.filename);
6195
- fs24.writeFileSync(filePath, rule.content);
6369
+ const filePath = path20.join(rulesDir, rule.filename);
6370
+ fs26.writeFileSync(filePath, rule.content);
6196
6371
  written.push(filePath);
6197
6372
  }
6198
6373
  }
6199
6374
  if (docs.claudeSkills) {
6200
- const skillsDir = path18.join(".claude", "skills");
6201
- if (!fs24.existsSync(skillsDir)) fs24.mkdirSync(skillsDir, { recursive: true });
6375
+ const skillsDir = path20.join(".claude", "skills");
6376
+ if (!fs26.existsSync(skillsDir)) fs26.mkdirSync(skillsDir, { recursive: true });
6202
6377
  for (const skill of docs.claudeSkills) {
6203
- const filePath = path18.join(skillsDir, skill.filename);
6204
- fs24.writeFileSync(filePath, skill.content);
6378
+ const filePath = path20.join(skillsDir, skill.filename);
6379
+ fs26.writeFileSync(filePath, skill.content);
6205
6380
  written.push(filePath);
6206
6381
  }
6207
6382
  }
@@ -6280,11 +6455,11 @@ function log(quiet, ...args) {
6280
6455
  function discoverGitRepos(parentDir) {
6281
6456
  const repos = [];
6282
6457
  try {
6283
- const entries = fs25.readdirSync(parentDir, { withFileTypes: true });
6458
+ const entries = fs27.readdirSync(parentDir, { withFileTypes: true });
6284
6459
  for (const entry of entries) {
6285
6460
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
6286
- const childPath = path19.join(parentDir, entry.name);
6287
- if (fs25.existsSync(path19.join(childPath, ".git"))) {
6461
+ const childPath = path21.join(parentDir, entry.name);
6462
+ if (fs27.existsSync(path21.join(childPath, ".git"))) {
6288
6463
  repos.push(childPath);
6289
6464
  }
6290
6465
  }
@@ -6381,7 +6556,7 @@ async function refreshCommand(options) {
6381
6556
  `));
6382
6557
  const originalDir = process.cwd();
6383
6558
  for (const repo of repos) {
6384
- const repoName = path19.basename(repo);
6559
+ const repoName = path21.basename(repo);
6385
6560
  try {
6386
6561
  process.chdir(repo);
6387
6562
  await refreshSingleRepo(repo, { ...options, label: repoName });
@@ -6636,8 +6811,8 @@ function readStdin() {
6636
6811
 
6637
6812
  // src/learner/storage.ts
6638
6813
  init_constants();
6639
- import fs26 from "fs";
6640
- import path20 from "path";
6814
+ import fs28 from "fs";
6815
+ import path22 from "path";
6641
6816
  var MAX_RESPONSE_LENGTH = 2e3;
6642
6817
  var DEFAULT_STATE = {
6643
6818
  sessionId: null,
@@ -6645,15 +6820,15 @@ var DEFAULT_STATE = {
6645
6820
  lastAnalysisTimestamp: null
6646
6821
  };
6647
6822
  function ensureLearningDir() {
6648
- if (!fs26.existsSync(LEARNING_DIR)) {
6649
- fs26.mkdirSync(LEARNING_DIR, { recursive: true });
6823
+ if (!fs28.existsSync(LEARNING_DIR)) {
6824
+ fs28.mkdirSync(LEARNING_DIR, { recursive: true });
6650
6825
  }
6651
6826
  }
6652
6827
  function sessionFilePath() {
6653
- return path20.join(LEARNING_DIR, LEARNING_SESSION_FILE);
6828
+ return path22.join(LEARNING_DIR, LEARNING_SESSION_FILE);
6654
6829
  }
6655
6830
  function stateFilePath() {
6656
- return path20.join(LEARNING_DIR, LEARNING_STATE_FILE);
6831
+ return path22.join(LEARNING_DIR, LEARNING_STATE_FILE);
6657
6832
  }
6658
6833
  function truncateResponse(response) {
6659
6834
  const str = JSON.stringify(response);
@@ -6664,50 +6839,50 @@ function appendEvent(event) {
6664
6839
  ensureLearningDir();
6665
6840
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
6666
6841
  const filePath = sessionFilePath();
6667
- fs26.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6842
+ fs28.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6668
6843
  const count = getEventCount();
6669
6844
  if (count > LEARNING_MAX_EVENTS) {
6670
- const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6845
+ const lines = fs28.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6671
6846
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
6672
- fs26.writeFileSync(filePath, kept.join("\n") + "\n");
6847
+ fs28.writeFileSync(filePath, kept.join("\n") + "\n");
6673
6848
  }
6674
6849
  }
6675
6850
  function readAllEvents() {
6676
6851
  const filePath = sessionFilePath();
6677
- if (!fs26.existsSync(filePath)) return [];
6678
- const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6852
+ if (!fs28.existsSync(filePath)) return [];
6853
+ const lines = fs28.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6679
6854
  return lines.map((line) => JSON.parse(line));
6680
6855
  }
6681
6856
  function getEventCount() {
6682
6857
  const filePath = sessionFilePath();
6683
- if (!fs26.existsSync(filePath)) return 0;
6684
- const content = fs26.readFileSync(filePath, "utf-8");
6858
+ if (!fs28.existsSync(filePath)) return 0;
6859
+ const content = fs28.readFileSync(filePath, "utf-8");
6685
6860
  return content.split("\n").filter(Boolean).length;
6686
6861
  }
6687
6862
  function clearSession() {
6688
6863
  const filePath = sessionFilePath();
6689
- if (fs26.existsSync(filePath)) fs26.unlinkSync(filePath);
6864
+ if (fs28.existsSync(filePath)) fs28.unlinkSync(filePath);
6690
6865
  }
6691
6866
  function readState2() {
6692
6867
  const filePath = stateFilePath();
6693
- if (!fs26.existsSync(filePath)) return { ...DEFAULT_STATE };
6868
+ if (!fs28.existsSync(filePath)) return { ...DEFAULT_STATE };
6694
6869
  try {
6695
- return JSON.parse(fs26.readFileSync(filePath, "utf-8"));
6870
+ return JSON.parse(fs28.readFileSync(filePath, "utf-8"));
6696
6871
  } catch {
6697
6872
  return { ...DEFAULT_STATE };
6698
6873
  }
6699
6874
  }
6700
6875
  function writeState2(state) {
6701
6876
  ensureLearningDir();
6702
- fs26.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6877
+ fs28.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6703
6878
  }
6704
6879
  function resetState() {
6705
6880
  writeState2({ ...DEFAULT_STATE });
6706
6881
  }
6707
6882
 
6708
6883
  // src/learner/writer.ts
6709
- import fs27 from "fs";
6710
- import path21 from "path";
6884
+ import fs29 from "fs";
6885
+ import path23 from "path";
6711
6886
  var LEARNED_START = "<!-- caliber:learned -->";
6712
6887
  var LEARNED_END = "<!-- /caliber:learned -->";
6713
6888
  function writeLearnedContent(update) {
@@ -6727,8 +6902,8 @@ function writeLearnedContent(update) {
6727
6902
  function writeLearnedSection(content) {
6728
6903
  const claudeMdPath = "CLAUDE.md";
6729
6904
  let existing = "";
6730
- if (fs27.existsSync(claudeMdPath)) {
6731
- existing = fs27.readFileSync(claudeMdPath, "utf-8");
6905
+ if (fs29.existsSync(claudeMdPath)) {
6906
+ existing = fs29.readFileSync(claudeMdPath, "utf-8");
6732
6907
  }
6733
6908
  const section = `${LEARNED_START}
6734
6909
  ${content}
@@ -6742,15 +6917,15 @@ ${LEARNED_END}`;
6742
6917
  const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
6743
6918
  updated = existing + separator + "\n" + section + "\n";
6744
6919
  }
6745
- fs27.writeFileSync(claudeMdPath, updated);
6920
+ fs29.writeFileSync(claudeMdPath, updated);
6746
6921
  }
6747
6922
  function writeLearnedSkill(skill) {
6748
- const skillDir = path21.join(".claude", "skills", skill.name);
6749
- if (!fs27.existsSync(skillDir)) fs27.mkdirSync(skillDir, { recursive: true });
6750
- const skillPath = path21.join(skillDir, "SKILL.md");
6751
- if (!skill.isNew && fs27.existsSync(skillPath)) {
6752
- const existing = fs27.readFileSync(skillPath, "utf-8");
6753
- fs27.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6923
+ const skillDir = path23.join(".claude", "skills", skill.name);
6924
+ if (!fs29.existsSync(skillDir)) fs29.mkdirSync(skillDir, { recursive: true });
6925
+ const skillPath = path23.join(skillDir, "SKILL.md");
6926
+ if (!skill.isNew && fs29.existsSync(skillPath)) {
6927
+ const existing = fs29.readFileSync(skillPath, "utf-8");
6928
+ fs29.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6754
6929
  } else {
6755
6930
  const frontmatter = [
6756
6931
  "---",
@@ -6759,14 +6934,14 @@ function writeLearnedSkill(skill) {
6759
6934
  "---",
6760
6935
  ""
6761
6936
  ].join("\n");
6762
- fs27.writeFileSync(skillPath, frontmatter + skill.content);
6937
+ fs29.writeFileSync(skillPath, frontmatter + skill.content);
6763
6938
  }
6764
6939
  return skillPath;
6765
6940
  }
6766
6941
  function readLearnedSection() {
6767
6942
  const claudeMdPath = "CLAUDE.md";
6768
- if (!fs27.existsSync(claudeMdPath)) return null;
6769
- const content = fs27.readFileSync(claudeMdPath, "utf-8");
6943
+ if (!fs29.existsSync(claudeMdPath)) return null;
6944
+ const content = fs29.readFileSync(claudeMdPath, "utf-8");
6770
6945
  const startIdx = content.indexOf(LEARNED_START);
6771
6946
  const endIdx = content.indexOf(LEARNED_END);
6772
6947
  if (startIdx === -1 || endIdx === -1) return null;
@@ -6955,9 +7130,9 @@ Learned items in CLAUDE.md: ${chalk16.cyan(String(lineCount))}`);
6955
7130
  }
6956
7131
 
6957
7132
  // src/cli.ts
6958
- var __dirname = path22.dirname(fileURLToPath(import.meta.url));
7133
+ var __dirname = path24.dirname(fileURLToPath(import.meta.url));
6959
7134
  var pkg = JSON.parse(
6960
- fs28.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
7135
+ fs30.readFileSync(path24.resolve(__dirname, "..", "package.json"), "utf-8")
6961
7136
  );
6962
7137
  var program = new Command();
6963
7138
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -7014,7 +7189,7 @@ function parseAgentOption(value) {
7014
7189
  }
7015
7190
  return agents;
7016
7191
  }
7017
- program.command("onboard").alias("init").description("Onboard your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(tracked("onboard", initCommand));
7192
+ program.command("onboard").alias("init").description("Onboard your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").option("--debug-report", void 0, false).action(tracked("onboard", initCommand));
7018
7193
  program.command("undo").description("Revert all config changes made by Caliber").action(tracked("undo", undoCommand));
7019
7194
  program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(tracked("status", statusCommand));
7020
7195
  program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(tracked("regenerate", regenerateCommand));
@@ -7031,22 +7206,22 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
7031
7206
  learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
7032
7207
 
7033
7208
  // src/utils/version-check.ts
7034
- import fs29 from "fs";
7035
- import path23 from "path";
7209
+ import fs31 from "fs";
7210
+ import path25 from "path";
7036
7211
  import { fileURLToPath as fileURLToPath2 } from "url";
7037
- import { execSync as execSync10 } from "child_process";
7212
+ import { execSync as execSync11 } from "child_process";
7038
7213
  import chalk17 from "chalk";
7039
7214
  import ora6 from "ora";
7040
7215
  import confirm from "@inquirer/confirm";
7041
- var __dirname_vc = path23.dirname(fileURLToPath2(import.meta.url));
7216
+ var __dirname_vc = path25.dirname(fileURLToPath2(import.meta.url));
7042
7217
  var pkg2 = JSON.parse(
7043
- fs29.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
7218
+ fs31.readFileSync(path25.resolve(__dirname_vc, "..", "package.json"), "utf-8")
7044
7219
  );
7045
7220
  function getInstalledVersion() {
7046
7221
  try {
7047
- const globalRoot = execSync10("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
7048
- const pkgPath = path23.join(globalRoot, "@rely-ai", "caliber", "package.json");
7049
- return JSON.parse(fs29.readFileSync(pkgPath, "utf-8")).version;
7222
+ const globalRoot = execSync11("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
7223
+ const pkgPath = path25.join(globalRoot, "@rely-ai", "caliber", "package.json");
7224
+ return JSON.parse(fs31.readFileSync(pkgPath, "utf-8")).version;
7050
7225
  } catch {
7051
7226
  return null;
7052
7227
  }
@@ -7089,7 +7264,7 @@ Update available: ${current} -> ${latest}`)
7089
7264
  }
7090
7265
  const spinner = ora6("Updating caliber...").start();
7091
7266
  try {
7092
- execSync10(`npm install -g @rely-ai/caliber@${latest}`, {
7267
+ execSync11(`npm install -g @rely-ai/caliber@${latest}`, {
7093
7268
  stdio: "pipe",
7094
7269
  timeout: 12e4,
7095
7270
  env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
@@ -7106,7 +7281,7 @@ Update available: ${current} -> ${latest}`)
7106
7281
  console.log(chalk17.dim(`
7107
7282
  Restarting: caliber ${args.join(" ")}
7108
7283
  `));
7109
- execSync10(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
7284
+ execSync11(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
7110
7285
  stdio: "inherit",
7111
7286
  env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
7112
7287
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.7.4",
3
+ "version": "1.7.6",
4
4
  "description": "Analyze your codebase and generate optimized AI agent configs (CLAUDE.md, .cursorrules, skills) — no API key needed",
5
5
  "type": "module",
6
6
  "bin": {