@rely-ai/caliber 1.30.1 → 1.30.3

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 +269 -214
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -158,30 +158,16 @@ var init_config = __esm({
158
158
  }
159
159
  });
160
160
 
161
- // src/llm/types.ts
162
- var types_exports = {};
163
- __export(types_exports, {
164
- isSeatBased: () => isSeatBased
165
- });
166
- function isSeatBased(provider) {
167
- return SEAT_BASED_PROVIDERS.has(provider);
168
- }
169
- var SEAT_BASED_PROVIDERS;
170
- var init_types = __esm({
171
- "src/llm/types.ts"() {
172
- "use strict";
173
- SEAT_BASED_PROVIDERS = /* @__PURE__ */ new Set(["cursor", "claude-cli"]);
174
- }
175
- });
176
-
177
161
  // src/lib/resolve-caliber.ts
178
162
  var resolve_caliber_exports = {};
179
163
  __export(resolve_caliber_exports, {
180
164
  isCaliberCommand: () => isCaliberCommand,
165
+ isNpxResolution: () => isNpxResolution,
166
+ resetResolvedCaliber: () => resetResolvedCaliber,
181
167
  resolveCaliber: () => resolveCaliber
182
168
  });
183
- import fs20 from "fs";
184
- import { execSync as execSync7 } from "child_process";
169
+ import fs6 from "fs";
170
+ import { execSync as execSync4 } from "child_process";
185
171
  function resolveCaliber() {
186
172
  if (_resolved) return _resolved;
187
173
  const isNpx = process.argv[1]?.includes("_npx") || process.env.npm_execpath?.includes("npx");
@@ -191,7 +177,7 @@ function resolveCaliber() {
191
177
  }
192
178
  try {
193
179
  const whichCmd = process.platform === "win32" ? "where caliber" : "which caliber";
194
- execSync7(whichCmd, {
180
+ execSync4(whichCmd, {
195
181
  encoding: "utf-8",
196
182
  stdio: ["pipe", "pipe", "pipe"]
197
183
  });
@@ -200,13 +186,19 @@ function resolveCaliber() {
200
186
  } catch {
201
187
  }
202
188
  const binPath = process.argv[1];
203
- if (binPath && fs20.existsSync(binPath)) {
189
+ if (binPath && /caliber/.test(binPath) && fs6.existsSync(binPath)) {
204
190
  _resolved = binPath;
205
191
  return _resolved;
206
192
  }
207
193
  _resolved = "caliber";
208
194
  return _resolved;
209
195
  }
196
+ function isNpxResolution() {
197
+ return resolveCaliber().startsWith("npx ");
198
+ }
199
+ function resetResolvedCaliber() {
200
+ _resolved = null;
201
+ }
210
202
  function isCaliberCommand(command, subcommandTail) {
211
203
  if (command === `caliber ${subcommandTail}`) return true;
212
204
  if (command.endsWith(`/caliber ${subcommandTail}`)) return true;
@@ -222,6 +214,22 @@ var init_resolve_caliber = __esm({
222
214
  }
223
215
  });
224
216
 
217
+ // src/llm/types.ts
218
+ var types_exports = {};
219
+ __export(types_exports, {
220
+ isSeatBased: () => isSeatBased
221
+ });
222
+ function isSeatBased(provider) {
223
+ return SEAT_BASED_PROVIDERS.has(provider);
224
+ }
225
+ var SEAT_BASED_PROVIDERS;
226
+ var init_types = __esm({
227
+ "src/llm/types.ts"() {
228
+ "use strict";
229
+ SEAT_BASED_PROVIDERS = /* @__PURE__ */ new Set(["cursor", "claude-cli"]);
230
+ }
231
+ });
232
+
225
233
  // src/utils/editor.ts
226
234
  import { execSync as execSync13, spawn as spawn3 } from "child_process";
227
235
  import fs26 from "fs";
@@ -547,7 +555,7 @@ import chalk14 from "chalk";
547
555
  import fs32 from "fs";
548
556
 
549
557
  // src/fingerprint/index.ts
550
- import fs7 from "fs";
558
+ import fs8 from "fs";
551
559
  import path7 from "path";
552
560
 
553
561
  // src/fingerprint/git.ts
@@ -1590,19 +1598,20 @@ var OpenAICompatProvider = class {
1590
1598
  };
1591
1599
 
1592
1600
  // src/llm/cursor-acp.ts
1593
- import { spawn, execSync as execSync4 } from "child_process";
1601
+ import { spawn, execSync as execSync5 } from "child_process";
1594
1602
  import os3 from "os";
1595
1603
 
1596
1604
  // src/llm/seat-based-errors.ts
1605
+ init_resolve_caliber();
1597
1606
  var ERROR_PATTERNS = [
1598
1607
  { pattern: /not logged in|not authenticated|login required|unauthorized/i, message: "Authentication required. Run the login command for your provider to re-authenticate." },
1599
1608
  { pattern: /rate limit|too many requests|429/i, message: "Rate limit exceeded. Retrying..." },
1600
- { pattern: /model.*not found|invalid model|model.*unavailable/i, message: "The requested model is not available. Run `caliber config` to select a different model." }
1609
+ { pattern: /model.*not found|invalid model|model.*unavailable/i, message: () => `The requested model is not available. Run \`${resolveCaliber()} config\` to select a different model.` }
1601
1610
  ];
1602
1611
  function parseSeatBasedError(stderr, exitCode) {
1603
1612
  if (!stderr && exitCode === 0) return null;
1604
1613
  for (const { pattern, message } of ERROR_PATTERNS) {
1605
- if (pattern.test(stderr)) return message;
1614
+ if (pattern.test(stderr)) return typeof message === "function" ? message() : message;
1606
1615
  }
1607
1616
  return null;
1608
1617
  }
@@ -1866,7 +1875,7 @@ var CursorAcpProvider = class {
1866
1875
  function isCursorAgentAvailable() {
1867
1876
  try {
1868
1877
  const cmd = IS_WINDOWS ? `where ${AGENT_BIN}` : `which ${AGENT_BIN}`;
1869
- execSync4(cmd, { stdio: "ignore" });
1878
+ execSync5(cmd, { stdio: "ignore" });
1870
1879
  return true;
1871
1880
  } catch {
1872
1881
  return false;
@@ -1874,7 +1883,7 @@ function isCursorAgentAvailable() {
1874
1883
  }
1875
1884
  function isCursorLoggedIn() {
1876
1885
  try {
1877
- const result = execSync4(`${AGENT_BIN} status`, { stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 });
1886
+ const result = execSync5(`${AGENT_BIN} status`, { stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 });
1878
1887
  return !result.toString().includes("not logged in");
1879
1888
  } catch {
1880
1889
  return false;
@@ -1882,7 +1891,7 @@ function isCursorLoggedIn() {
1882
1891
  }
1883
1892
 
1884
1893
  // src/llm/claude-cli.ts
1885
- import { spawn as spawn2, execSync as execSync5 } from "child_process";
1894
+ import { spawn as spawn2, execSync as execSync6 } from "child_process";
1886
1895
  var CLAUDE_CLI_BIN = "claude";
1887
1896
  var DEFAULT_TIMEOUT_MS2 = 10 * 60 * 1e3;
1888
1897
  var IS_WINDOWS2 = process.platform === "win32";
@@ -2017,7 +2026,7 @@ var ClaudeCliProvider = class {
2017
2026
  function isClaudeCliAvailable() {
2018
2027
  try {
2019
2028
  const cmd = process.platform === "win32" ? `where ${CLAUDE_CLI_BIN}` : `which ${CLAUDE_CLI_BIN}`;
2020
- execSync5(cmd, { stdio: "ignore" });
2029
+ execSync6(cmd, { stdio: "ignore" });
2021
2030
  return true;
2022
2031
  } catch {
2023
2032
  return false;
@@ -2075,6 +2084,7 @@ function estimateTokens(text) {
2075
2084
 
2076
2085
  // src/llm/model-recovery.ts
2077
2086
  init_config();
2087
+ init_resolve_caliber();
2078
2088
  import chalk from "chalk";
2079
2089
  import select from "@inquirer/select";
2080
2090
  var KNOWN_MODELS = {
@@ -2128,7 +2138,7 @@ function filterRelevantModels(models, provider) {
2128
2138
  async function handleModelNotAvailable(failedModel, provider, config) {
2129
2139
  if (!process.stdin.isTTY) {
2130
2140
  console.error(
2131
- chalk.red(`Model "${failedModel}" is not available. Run \`caliber config\` to select a different model.`)
2141
+ chalk.red(`Model "${failedModel}" is not available. Run \`${resolveCaliber()} config\` to select a different model.`)
2132
2142
  );
2133
2143
  return null;
2134
2144
  }
@@ -2147,7 +2157,7 @@ async function handleModelNotAvailable(failedModel, provider, config) {
2147
2157
  }
2148
2158
  models = models.filter((m) => m !== failedModel);
2149
2159
  if (models.length === 0) {
2150
- console.log(chalk.red(" No alternative models found. Run `caliber config` to configure manually."));
2160
+ console.log(chalk.red(` No alternative models found. Run \`${resolveCaliber()} config\` to configure manually.`));
2151
2161
  return null;
2152
2162
  }
2153
2163
  console.log("");
@@ -2174,6 +2184,7 @@ async function handleModelNotAvailable(failedModel, provider, config) {
2174
2184
  }
2175
2185
 
2176
2186
  // src/llm/index.ts
2187
+ init_resolve_caliber();
2177
2188
  init_types();
2178
2189
  init_config();
2179
2190
  var cachedProvider = null;
@@ -2211,7 +2222,7 @@ function getProvider() {
2211
2222
  const config = loadConfig();
2212
2223
  if (!config) {
2213
2224
  throw new Error(
2214
- "No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or VERTEX_PROJECT_ID; or run `caliber config` and choose Cursor or Claude Code; or set CALIBER_USE_CURSOR_SEAT=1 / CALIBER_USE_CLAUDE_CLI=1."
2225
+ `No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or VERTEX_PROJECT_ID; or run \`${resolveCaliber()} config\` and choose Cursor or Claude Code; or set CALIBER_USE_CURSOR_SEAT=1 / CALIBER_USE_CLAUDE_CLI=1.`
2215
2226
  );
2216
2227
  }
2217
2228
  cachedConfig = config;
@@ -2774,10 +2785,10 @@ async function detectProjectStack(fileTree, suffixCounts) {
2774
2785
  init_config();
2775
2786
 
2776
2787
  // src/fingerprint/cache.ts
2777
- import fs6 from "fs";
2788
+ import fs7 from "fs";
2778
2789
  import path6 from "path";
2779
2790
  import crypto from "crypto";
2780
- import { execSync as execSync6 } from "child_process";
2791
+ import { execSync as execSync7 } from "child_process";
2781
2792
  var CACHE_VERSION = 1;
2782
2793
  var CACHE_DIR = ".caliber/cache";
2783
2794
  var CACHE_FILE = "fingerprint.json";
@@ -2786,7 +2797,7 @@ function getCachePath(dir) {
2786
2797
  }
2787
2798
  function getGitHead(dir) {
2788
2799
  try {
2789
- return execSync6("git rev-parse HEAD", {
2800
+ return execSync7("git rev-parse HEAD", {
2790
2801
  cwd: dir,
2791
2802
  encoding: "utf-8",
2792
2803
  stdio: ["pipe", "pipe", "pipe"],
@@ -2798,7 +2809,7 @@ function getGitHead(dir) {
2798
2809
  }
2799
2810
  function getDirtySignature(dir) {
2800
2811
  try {
2801
- const output = execSync6("git diff --name-only HEAD", {
2812
+ const output = execSync7("git diff --name-only HEAD", {
2802
2813
  cwd: dir,
2803
2814
  encoding: "utf-8",
2804
2815
  stdio: ["pipe", "pipe", "pipe"],
@@ -2819,8 +2830,8 @@ function computeTreeSignature(fileTree, dir) {
2819
2830
  function loadFingerprintCache(dir, fileTree) {
2820
2831
  const cachePath = getCachePath(dir);
2821
2832
  try {
2822
- if (!fs6.existsSync(cachePath)) return null;
2823
- const raw = fs6.readFileSync(cachePath, "utf-8");
2833
+ if (!fs7.existsSync(cachePath)) return null;
2834
+ const raw = fs7.readFileSync(cachePath, "utf-8");
2824
2835
  const cache = JSON.parse(raw);
2825
2836
  if (cache.version !== CACHE_VERSION) return null;
2826
2837
  const currentHead = getGitHead(dir);
@@ -2842,8 +2853,8 @@ function saveFingerprintCache(dir, fileTree, codeAnalysis, languages, frameworks
2842
2853
  const cachePath = getCachePath(dir);
2843
2854
  try {
2844
2855
  const cacheDir = path6.dirname(cachePath);
2845
- if (!fs6.existsSync(cacheDir)) {
2846
- fs6.mkdirSync(cacheDir, { recursive: true });
2856
+ if (!fs7.existsSync(cacheDir)) {
2857
+ fs7.mkdirSync(cacheDir, { recursive: true });
2847
2858
  }
2848
2859
  const cache = {
2849
2860
  version: CACHE_VERSION,
@@ -2855,15 +2866,15 @@ function saveFingerprintCache(dir, fileTree, codeAnalysis, languages, frameworks
2855
2866
  tools,
2856
2867
  workspaces
2857
2868
  };
2858
- fs6.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
2869
+ fs7.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
2859
2870
  } catch {
2860
2871
  }
2861
2872
  }
2862
2873
  function getDetectedWorkspaces(dir) {
2863
2874
  const cachePath = getCachePath(dir);
2864
2875
  try {
2865
- if (!fs6.existsSync(cachePath)) return [];
2866
- const raw = fs6.readFileSync(cachePath, "utf-8");
2876
+ if (!fs7.existsSync(cachePath)) return [];
2877
+ const raw = fs7.readFileSync(cachePath, "utf-8");
2867
2878
  const cache = JSON.parse(raw);
2868
2879
  return cache.workspaces ?? [];
2869
2880
  } catch {
@@ -2916,8 +2927,8 @@ async function collectFingerprint(dir) {
2916
2927
  function readPackageName(dir) {
2917
2928
  try {
2918
2929
  const pkgPath = path7.join(dir, "package.json");
2919
- if (!fs7.existsSync(pkgPath)) return void 0;
2920
- const pkg3 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2930
+ if (!fs8.existsSync(pkgPath)) return void 0;
2931
+ const pkg3 = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
2921
2932
  return pkg3.name;
2922
2933
  } catch {
2923
2934
  return void 0;
@@ -2947,22 +2958,22 @@ async function enrichWithLLM(fingerprint) {
2947
2958
  }
2948
2959
 
2949
2960
  // src/scanner/index.ts
2950
- import fs8 from "fs";
2961
+ import fs9 from "fs";
2951
2962
  import path8 from "path";
2952
2963
  import crypto2 from "crypto";
2953
2964
  import os4 from "os";
2954
2965
  function detectPlatforms() {
2955
2966
  const home = os4.homedir();
2956
2967
  return {
2957
- claude: fs8.existsSync(path8.join(home, ".claude")),
2958
- cursor: fs8.existsSync(getCursorConfigDir()),
2959
- codex: fs8.existsSync(path8.join(home, ".codex"))
2968
+ claude: fs9.existsSync(path8.join(home, ".claude")),
2969
+ cursor: fs9.existsSync(getCursorConfigDir()),
2970
+ codex: fs9.existsSync(path8.join(home, ".codex"))
2960
2971
  };
2961
2972
  }
2962
2973
  function scanLocalState(dir) {
2963
2974
  const items = [];
2964
2975
  const claudeMdPath = path8.join(dir, "CLAUDE.md");
2965
- if (fs8.existsSync(claudeMdPath)) {
2976
+ if (fs9.existsSync(claudeMdPath)) {
2966
2977
  items.push({
2967
2978
  type: "rule",
2968
2979
  platform: "claude",
@@ -2972,8 +2983,8 @@ function scanLocalState(dir) {
2972
2983
  });
2973
2984
  }
2974
2985
  const skillsDir = path8.join(dir, ".claude", "skills");
2975
- if (fs8.existsSync(skillsDir)) {
2976
- for (const file of fs8.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
2986
+ if (fs9.existsSync(skillsDir)) {
2987
+ for (const file of fs9.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
2977
2988
  const filePath = path8.join(skillsDir, file);
2978
2989
  items.push({
2979
2990
  type: "skill",
@@ -2985,9 +2996,9 @@ function scanLocalState(dir) {
2985
2996
  }
2986
2997
  }
2987
2998
  const mcpJsonPath = path8.join(dir, ".mcp.json");
2988
- if (fs8.existsSync(mcpJsonPath)) {
2999
+ if (fs9.existsSync(mcpJsonPath)) {
2989
3000
  try {
2990
- const mcpJson = JSON.parse(fs8.readFileSync(mcpJsonPath, "utf-8"));
3001
+ const mcpJson = JSON.parse(fs9.readFileSync(mcpJsonPath, "utf-8"));
2991
3002
  if (mcpJson.mcpServers) {
2992
3003
  for (const name of Object.keys(mcpJson.mcpServers)) {
2993
3004
  items.push({
@@ -3004,7 +3015,7 @@ function scanLocalState(dir) {
3004
3015
  }
3005
3016
  }
3006
3017
  const agentsMdPath = path8.join(dir, "AGENTS.md");
3007
- if (fs8.existsSync(agentsMdPath)) {
3018
+ if (fs9.existsSync(agentsMdPath)) {
3008
3019
  items.push({
3009
3020
  type: "rule",
3010
3021
  platform: "codex",
@@ -3014,11 +3025,11 @@ function scanLocalState(dir) {
3014
3025
  });
3015
3026
  }
3016
3027
  const codexSkillsDir = path8.join(dir, ".agents", "skills");
3017
- if (fs8.existsSync(codexSkillsDir)) {
3028
+ if (fs9.existsSync(codexSkillsDir)) {
3018
3029
  try {
3019
- for (const name of fs8.readdirSync(codexSkillsDir)) {
3030
+ for (const name of fs9.readdirSync(codexSkillsDir)) {
3020
3031
  const skillFile = path8.join(codexSkillsDir, name, "SKILL.md");
3021
- if (fs8.existsSync(skillFile)) {
3032
+ if (fs9.existsSync(skillFile)) {
3022
3033
  items.push({
3023
3034
  type: "skill",
3024
3035
  platform: "codex",
@@ -3033,7 +3044,7 @@ function scanLocalState(dir) {
3033
3044
  }
3034
3045
  }
3035
3046
  const cursorrulesPath = path8.join(dir, ".cursorrules");
3036
- if (fs8.existsSync(cursorrulesPath)) {
3047
+ if (fs9.existsSync(cursorrulesPath)) {
3037
3048
  items.push({
3038
3049
  type: "rule",
3039
3050
  platform: "cursor",
@@ -3043,8 +3054,8 @@ function scanLocalState(dir) {
3043
3054
  });
3044
3055
  }
3045
3056
  const cursorRulesDir = path8.join(dir, ".cursor", "rules");
3046
- if (fs8.existsSync(cursorRulesDir)) {
3047
- for (const file of fs8.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
3057
+ if (fs9.existsSync(cursorRulesDir)) {
3058
+ for (const file of fs9.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
3048
3059
  const filePath = path8.join(cursorRulesDir, file);
3049
3060
  items.push({
3050
3061
  type: "rule",
@@ -3056,11 +3067,11 @@ function scanLocalState(dir) {
3056
3067
  }
3057
3068
  }
3058
3069
  const cursorSkillsDir = path8.join(dir, ".cursor", "skills");
3059
- if (fs8.existsSync(cursorSkillsDir)) {
3070
+ if (fs9.existsSync(cursorSkillsDir)) {
3060
3071
  try {
3061
- for (const name of fs8.readdirSync(cursorSkillsDir)) {
3072
+ for (const name of fs9.readdirSync(cursorSkillsDir)) {
3062
3073
  const skillFile = path8.join(cursorSkillsDir, name, "SKILL.md");
3063
- if (fs8.existsSync(skillFile)) {
3074
+ if (fs9.existsSync(skillFile)) {
3064
3075
  items.push({
3065
3076
  type: "skill",
3066
3077
  platform: "cursor",
@@ -3075,9 +3086,9 @@ function scanLocalState(dir) {
3075
3086
  }
3076
3087
  }
3077
3088
  const cursorMcpPath = path8.join(dir, ".cursor", "mcp.json");
3078
- if (fs8.existsSync(cursorMcpPath)) {
3089
+ if (fs9.existsSync(cursorMcpPath)) {
3079
3090
  try {
3080
- const mcpJson = JSON.parse(fs8.readFileSync(cursorMcpPath, "utf-8"));
3091
+ const mcpJson = JSON.parse(fs9.readFileSync(cursorMcpPath, "utf-8"));
3081
3092
  if (mcpJson.mcpServers) {
3082
3093
  for (const name of Object.keys(mcpJson.mcpServers)) {
3083
3094
  items.push({
@@ -3096,7 +3107,7 @@ function scanLocalState(dir) {
3096
3107
  return items;
3097
3108
  }
3098
3109
  function hashFile(filePath) {
3099
- const text = fs8.readFileSync(filePath, "utf-8");
3110
+ const text = fs9.readFileSync(filePath, "utf-8");
3100
3111
  return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
3101
3112
  }
3102
3113
  function hashJson(obj) {
@@ -3118,7 +3129,7 @@ function getCursorConfigDir() {
3118
3129
  }
3119
3130
 
3120
3131
  // src/fingerprint/sources.ts
3121
- import fs9 from "fs";
3132
+ import fs10 from "fs";
3122
3133
  import path9 from "path";
3123
3134
 
3124
3135
  // src/scoring/utils.ts
@@ -3457,15 +3468,15 @@ function loadSourcesConfig(dir) {
3457
3468
  }
3458
3469
  function writeSourcesConfig(dir, sources2) {
3459
3470
  const configDir = path9.join(dir, ".caliber");
3460
- if (!fs9.existsSync(configDir)) {
3461
- fs9.mkdirSync(configDir, { recursive: true });
3471
+ if (!fs10.existsSync(configDir)) {
3472
+ fs10.mkdirSync(configDir, { recursive: true });
3462
3473
  }
3463
3474
  const configPath = path9.join(configDir, "sources.json");
3464
- fs9.writeFileSync(configPath, JSON.stringify({ sources: sources2 }, null, 2) + "\n", "utf-8");
3475
+ fs10.writeFileSync(configPath, JSON.stringify({ sources: sources2 }, null, 2) + "\n", "utf-8");
3465
3476
  }
3466
3477
  function detectSourceType(absPath) {
3467
3478
  try {
3468
- return fs9.statSync(absPath).isDirectory() ? "repo" : "file";
3479
+ return fs10.statSync(absPath).isDirectory() ? "repo" : "file";
3469
3480
  } catch {
3470
3481
  return "file";
3471
3482
  }
@@ -3509,7 +3520,7 @@ function resolveAllSources(dir, cliSources, workspaces) {
3509
3520
  for (const [absPath, resolved] of seen) {
3510
3521
  let stat;
3511
3522
  try {
3512
- stat = fs9.statSync(absPath);
3523
+ stat = fs10.statSync(absPath);
3513
3524
  } catch {
3514
3525
  console.warn(`Source ${resolved.config.path || absPath} not found, skipping`);
3515
3526
  continue;
@@ -3564,7 +3575,7 @@ function collectRepoSummary(resolved, projectDir) {
3564
3575
  let topLevelDirs;
3565
3576
  let keyFiles;
3566
3577
  try {
3567
- const entries = fs9.readdirSync(absPath, { withFileTypes: true });
3578
+ const entries = fs10.readdirSync(absPath, { withFileTypes: true });
3568
3579
  topLevelDirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules").map((e) => e.name).slice(0, 20);
3569
3580
  keyFiles = entries.filter((e) => e.isFile() && !e.name.startsWith(".")).map((e) => e.name).slice(0, 15);
3570
3581
  } catch {
@@ -4231,44 +4242,51 @@ ${f.content}
4231
4242
  }
4232
4243
 
4233
4244
  // src/writers/index.ts
4234
- import fs17 from "fs";
4245
+ import fs18 from "fs";
4235
4246
 
4236
4247
  // src/writers/claude/index.ts
4237
- import fs10 from "fs";
4248
+ import fs11 from "fs";
4238
4249
  import path10 from "path";
4239
4250
 
4240
4251
  // src/writers/pre-commit-block.ts
4252
+ init_resolve_caliber();
4241
4253
  var BLOCK_START = "<!-- caliber:managed:pre-commit -->";
4242
4254
  var BLOCK_END = "<!-- /caliber:managed:pre-commit -->";
4243
4255
  var MANAGED_DOC_PATHS = "CLAUDE.md .claude/ .cursor/ .github/copilot-instructions.md AGENTS.md CALIBER_LEARNINGS.md";
4244
- var PRE_COMMIT_BLOCK = `${BLOCK_START}
4256
+ function getPreCommitBlock() {
4257
+ const bin = resolveCaliber();
4258
+ return `${BLOCK_START}
4245
4259
  ## Before Committing
4246
4260
 
4247
- Run \`caliber refresh\` before creating git commits to keep docs in sync with code changes.
4261
+ Run \`${bin} refresh\` before creating git commits to keep docs in sync with code changes.
4248
4262
  After it completes, stage any modified doc files before committing:
4249
4263
 
4250
4264
  \`\`\`bash
4251
- caliber refresh && git add ${MANAGED_DOC_PATHS} 2>/dev/null
4265
+ ${bin} refresh && git add ${MANAGED_DOC_PATHS} 2>/dev/null
4252
4266
  \`\`\`
4253
4267
  ${BLOCK_END}`;
4268
+ }
4254
4269
  var CURSOR_RULE_FILENAME = "caliber-pre-commit.mdc";
4255
- var CURSOR_RULE_CONTENT = `---
4270
+ function getCursorRuleContent() {
4271
+ const bin = resolveCaliber();
4272
+ return `---
4256
4273
  description: Run caliber refresh before git commits to keep docs in sync
4257
4274
  alwaysApply: true
4258
4275
  ---
4259
- Before creating git commits, run \`caliber refresh\` to update docs based on code changes,
4276
+ Before creating git commits, run \`${bin} refresh\` to update docs based on code changes,
4260
4277
  then stage modified doc files (${MANAGED_DOC_PATHS}).
4261
4278
  `;
4279
+ }
4262
4280
  function hasPreCommitBlock(content) {
4263
4281
  return content.includes(BLOCK_START);
4264
4282
  }
4265
4283
  function appendPreCommitBlock(content) {
4266
4284
  if (hasPreCommitBlock(content)) return content;
4267
4285
  const trimmed = content.trimEnd();
4268
- return trimmed + "\n\n" + PRE_COMMIT_BLOCK + "\n";
4286
+ return trimmed + "\n\n" + getPreCommitBlock() + "\n";
4269
4287
  }
4270
4288
  function getCursorPreCommitRule() {
4271
- return { filename: CURSOR_RULE_FILENAME, content: CURSOR_RULE_CONTENT };
4289
+ return { filename: CURSOR_RULE_FILENAME, content: getCursorRuleContent() };
4272
4290
  }
4273
4291
  var LEARNINGS_BLOCK_START = "<!-- caliber:managed:learnings -->";
4274
4292
  var LEARNINGS_BLOCK_END = "<!-- /caliber:managed:learnings -->";
@@ -4301,12 +4319,12 @@ function getCursorLearningsRule() {
4301
4319
  // src/writers/claude/index.ts
4302
4320
  function writeClaudeConfig(config) {
4303
4321
  const written = [];
4304
- fs10.writeFileSync("CLAUDE.md", appendLearningsBlock(appendPreCommitBlock(config.claudeMd)));
4322
+ fs11.writeFileSync("CLAUDE.md", appendLearningsBlock(appendPreCommitBlock(config.claudeMd)));
4305
4323
  written.push("CLAUDE.md");
4306
4324
  if (config.skills?.length) {
4307
4325
  for (const skill of config.skills) {
4308
4326
  const skillDir = path10.join(".claude", "skills", skill.name);
4309
- if (!fs10.existsSync(skillDir)) fs10.mkdirSync(skillDir, { recursive: true });
4327
+ if (!fs11.existsSync(skillDir)) fs11.mkdirSync(skillDir, { recursive: true });
4310
4328
  const skillPath = path10.join(skillDir, "SKILL.md");
4311
4329
  const frontmatter = [
4312
4330
  "---",
@@ -4315,49 +4333,49 @@ function writeClaudeConfig(config) {
4315
4333
  "---",
4316
4334
  ""
4317
4335
  ].join("\n");
4318
- fs10.writeFileSync(skillPath, frontmatter + skill.content);
4336
+ fs11.writeFileSync(skillPath, frontmatter + skill.content);
4319
4337
  written.push(skillPath);
4320
4338
  }
4321
4339
  }
4322
4340
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
4323
4341
  let existingServers = {};
4324
4342
  try {
4325
- if (fs10.existsSync(".mcp.json")) {
4326
- const existing = JSON.parse(fs10.readFileSync(".mcp.json", "utf-8"));
4343
+ if (fs11.existsSync(".mcp.json")) {
4344
+ const existing = JSON.parse(fs11.readFileSync(".mcp.json", "utf-8"));
4327
4345
  if (existing.mcpServers) existingServers = existing.mcpServers;
4328
4346
  }
4329
4347
  } catch {
4330
4348
  }
4331
4349
  const mergedServers = { ...existingServers, ...config.mcpServers };
4332
- fs10.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
4350
+ fs11.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
4333
4351
  written.push(".mcp.json");
4334
4352
  }
4335
4353
  return written;
4336
4354
  }
4337
4355
 
4338
4356
  // src/writers/cursor/index.ts
4339
- import fs11 from "fs";
4357
+ import fs12 from "fs";
4340
4358
  import path11 from "path";
4341
4359
  function writeCursorConfig(config) {
4342
4360
  const written = [];
4343
4361
  if (config.cursorrules) {
4344
- fs11.writeFileSync(".cursorrules", config.cursorrules);
4362
+ fs12.writeFileSync(".cursorrules", config.cursorrules);
4345
4363
  written.push(".cursorrules");
4346
4364
  }
4347
4365
  const preCommitRule = getCursorPreCommitRule();
4348
4366
  const learningsRule = getCursorLearningsRule();
4349
4367
  const allRules = [...config.rules || [], preCommitRule, learningsRule];
4350
4368
  const rulesDir = path11.join(".cursor", "rules");
4351
- if (!fs11.existsSync(rulesDir)) fs11.mkdirSync(rulesDir, { recursive: true });
4369
+ if (!fs12.existsSync(rulesDir)) fs12.mkdirSync(rulesDir, { recursive: true });
4352
4370
  for (const rule of allRules) {
4353
4371
  const rulePath = path11.join(rulesDir, rule.filename);
4354
- fs11.writeFileSync(rulePath, rule.content);
4372
+ fs12.writeFileSync(rulePath, rule.content);
4355
4373
  written.push(rulePath);
4356
4374
  }
4357
4375
  if (config.skills?.length) {
4358
4376
  for (const skill of config.skills) {
4359
4377
  const skillDir = path11.join(".cursor", "skills", skill.name);
4360
- if (!fs11.existsSync(skillDir)) fs11.mkdirSync(skillDir, { recursive: true });
4378
+ if (!fs12.existsSync(skillDir)) fs12.mkdirSync(skillDir, { recursive: true });
4361
4379
  const skillPath = path11.join(skillDir, "SKILL.md");
4362
4380
  const frontmatter = [
4363
4381
  "---",
@@ -4366,40 +4384,40 @@ function writeCursorConfig(config) {
4366
4384
  "---",
4367
4385
  ""
4368
4386
  ].join("\n");
4369
- fs11.writeFileSync(skillPath, frontmatter + skill.content);
4387
+ fs12.writeFileSync(skillPath, frontmatter + skill.content);
4370
4388
  written.push(skillPath);
4371
4389
  }
4372
4390
  }
4373
4391
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
4374
4392
  const cursorDir = ".cursor";
4375
- if (!fs11.existsSync(cursorDir)) fs11.mkdirSync(cursorDir, { recursive: true });
4393
+ if (!fs12.existsSync(cursorDir)) fs12.mkdirSync(cursorDir, { recursive: true });
4376
4394
  const mcpPath = path11.join(cursorDir, "mcp.json");
4377
4395
  let existingServers = {};
4378
4396
  try {
4379
- if (fs11.existsSync(mcpPath)) {
4380
- const existing = JSON.parse(fs11.readFileSync(mcpPath, "utf-8"));
4397
+ if (fs12.existsSync(mcpPath)) {
4398
+ const existing = JSON.parse(fs12.readFileSync(mcpPath, "utf-8"));
4381
4399
  if (existing.mcpServers) existingServers = existing.mcpServers;
4382
4400
  }
4383
4401
  } catch {
4384
4402
  }
4385
4403
  const mergedServers = { ...existingServers, ...config.mcpServers };
4386
- fs11.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
4404
+ fs12.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
4387
4405
  written.push(mcpPath);
4388
4406
  }
4389
4407
  return written;
4390
4408
  }
4391
4409
 
4392
4410
  // src/writers/codex/index.ts
4393
- import fs12 from "fs";
4411
+ import fs13 from "fs";
4394
4412
  import path12 from "path";
4395
4413
  function writeCodexConfig(config) {
4396
4414
  const written = [];
4397
- fs12.writeFileSync("AGENTS.md", appendLearningsBlock(appendPreCommitBlock(config.agentsMd)));
4415
+ fs13.writeFileSync("AGENTS.md", appendLearningsBlock(appendPreCommitBlock(config.agentsMd)));
4398
4416
  written.push("AGENTS.md");
4399
4417
  if (config.skills?.length) {
4400
4418
  for (const skill of config.skills) {
4401
4419
  const skillDir = path12.join(".agents", "skills", skill.name);
4402
- if (!fs12.existsSync(skillDir)) fs12.mkdirSync(skillDir, { recursive: true });
4420
+ if (!fs13.existsSync(skillDir)) fs13.mkdirSync(skillDir, { recursive: true });
4403
4421
  const skillPath = path12.join(skillDir, "SKILL.md");
4404
4422
  const frontmatter = [
4405
4423
  "---",
@@ -4408,7 +4426,7 @@ function writeCodexConfig(config) {
4408
4426
  "---",
4409
4427
  ""
4410
4428
  ].join("\n");
4411
- fs12.writeFileSync(skillPath, frontmatter + skill.content);
4429
+ fs13.writeFileSync(skillPath, frontmatter + skill.content);
4412
4430
  written.push(skillPath);
4413
4431
  }
4414
4432
  }
@@ -4416,20 +4434,20 @@ function writeCodexConfig(config) {
4416
4434
  }
4417
4435
 
4418
4436
  // src/writers/github-copilot/index.ts
4419
- import fs13 from "fs";
4437
+ import fs14 from "fs";
4420
4438
  import path13 from "path";
4421
4439
  function writeGithubCopilotConfig(config) {
4422
4440
  const written = [];
4423
4441
  if (config.instructions) {
4424
- fs13.mkdirSync(".github", { recursive: true });
4425
- fs13.writeFileSync(path13.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(config.instructions)));
4442
+ fs14.mkdirSync(".github", { recursive: true });
4443
+ fs14.writeFileSync(path13.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(config.instructions)));
4426
4444
  written.push(".github/copilot-instructions.md");
4427
4445
  }
4428
4446
  if (config.instructionFiles?.length) {
4429
4447
  const instructionsDir = path13.join(".github", "instructions");
4430
- fs13.mkdirSync(instructionsDir, { recursive: true });
4448
+ fs14.mkdirSync(instructionsDir, { recursive: true });
4431
4449
  for (const file of config.instructionFiles) {
4432
- fs13.writeFileSync(path13.join(instructionsDir, file.filename), file.content);
4450
+ fs14.writeFileSync(path13.join(instructionsDir, file.filename), file.content);
4433
4451
  written.push(`.github/instructions/${file.filename}`);
4434
4452
  }
4435
4453
  }
@@ -4437,35 +4455,36 @@ function writeGithubCopilotConfig(config) {
4437
4455
  }
4438
4456
 
4439
4457
  // src/writers/backup.ts
4440
- import fs14 from "fs";
4458
+ import fs15 from "fs";
4441
4459
  import path14 from "path";
4442
4460
  function createBackup(files) {
4443
4461
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4444
4462
  const backupDir = path14.join(BACKUPS_DIR, timestamp);
4445
4463
  for (const file of files) {
4446
- if (!fs14.existsSync(file)) continue;
4464
+ if (!fs15.existsSync(file)) continue;
4447
4465
  const dest = path14.join(backupDir, file);
4448
4466
  const destDir = path14.dirname(dest);
4449
- if (!fs14.existsSync(destDir)) {
4450
- fs14.mkdirSync(destDir, { recursive: true });
4467
+ if (!fs15.existsSync(destDir)) {
4468
+ fs15.mkdirSync(destDir, { recursive: true });
4451
4469
  }
4452
- fs14.copyFileSync(file, dest);
4470
+ fs15.copyFileSync(file, dest);
4453
4471
  }
4454
4472
  return backupDir;
4455
4473
  }
4456
4474
  function restoreBackup(backupDir, file) {
4457
4475
  const backupFile = path14.join(backupDir, file);
4458
- if (!fs14.existsSync(backupFile)) return false;
4476
+ if (!fs15.existsSync(backupFile)) return false;
4459
4477
  const destDir = path14.dirname(file);
4460
- if (!fs14.existsSync(destDir)) {
4461
- fs14.mkdirSync(destDir, { recursive: true });
4478
+ if (!fs15.existsSync(destDir)) {
4479
+ fs15.mkdirSync(destDir, { recursive: true });
4462
4480
  }
4463
- fs14.copyFileSync(backupFile, file);
4481
+ fs15.copyFileSync(backupFile, file);
4464
4482
  return true;
4465
4483
  }
4466
4484
 
4467
4485
  // src/lib/builtin-skills.ts
4468
- import fs15 from "fs";
4486
+ init_resolve_caliber();
4487
+ import fs16 from "fs";
4469
4488
  import path15 from "path";
4470
4489
  function buildSkillContent(skill) {
4471
4490
  const frontmatter = `---
@@ -4476,10 +4495,9 @@ description: ${skill.description}
4476
4495
  `;
4477
4496
  return frontmatter + skill.content;
4478
4497
  }
4479
- var FIND_SKILLS_SKILL = {
4480
- name: "find-skills",
4481
- description: "Discovers and installs community skills from the public registry. Use when the user mentions a technology, framework, or task that could benefit from specialized skills not yet installed, asks 'how do I do X', 'find a skill for X', or starts work in a new technology area. Proactively suggest when the user's task involves tools or frameworks without existing skills.",
4482
- content: `# Find Skills
4498
+ function getFindSkillsContent() {
4499
+ const bin = resolveCaliber();
4500
+ return `# Find Skills
4483
4501
 
4484
4502
  Search the public skill registry for community-contributed skills
4485
4503
  relevant to the user's current task and install them into this project.
@@ -4492,13 +4510,13 @@ relevant to the user's current task and install them into this project.
4492
4510
  for [identified technologies]?"
4493
4511
  3. If the user agrees, run:
4494
4512
  \`\`\`bash
4495
- caliber skills --query "<relevant terms>"
4513
+ ${bin} skills --query "<relevant terms>"
4496
4514
  \`\`\`
4497
4515
  This outputs the top 5 matching skills with scores and descriptions.
4498
4516
  4. Present the results to the user and ask which ones to install
4499
4517
  5. Install the selected skills:
4500
4518
  \`\`\`bash
4501
- caliber skills --install <slug1>,<slug2>
4519
+ ${bin} skills --install <slug1>,<slug2>
4502
4520
  \`\`\`
4503
4521
  6. Read the installed SKILL.md files to load them into your current
4504
4522
  context so you can use them immediately in this session
@@ -4509,18 +4527,18 @@ relevant to the user's current task and install them into this project.
4509
4527
  User: "let's build a web app using React"
4510
4528
  -> "I notice you want to work with React. Would you like me to search
4511
4529
  for community skills that could help with React development?"
4512
- -> If yes: run \`caliber skills --query "react frontend"\`
4530
+ -> If yes: run \`${bin} skills --query "react frontend"\`
4513
4531
  -> Show the user the results, ask which to install
4514
- -> Run \`caliber skills --install <selected-slugs>\`
4532
+ -> Run \`${bin} skills --install <selected-slugs>\`
4515
4533
  -> Read the installed files and continue
4516
4534
 
4517
4535
  User: "help me set up Docker for this project"
4518
4536
  -> "Would you like me to search for Docker-related skills?"
4519
- -> If yes: run \`caliber skills --query "docker deployment"\`
4537
+ -> If yes: run \`${bin} skills --query "docker deployment"\`
4520
4538
 
4521
4539
  User: "I need to write tests for this Python ML pipeline"
4522
4540
  -> "Would you like me to find skills for Python ML testing?"
4523
- -> If yes: run \`caliber skills --query "python machine-learning testing"\`
4541
+ -> If yes: run \`${bin} skills --query "python machine-learning testing"\`
4524
4542
 
4525
4543
  ## When NOT to trigger
4526
4544
 
@@ -4528,12 +4546,11 @@ User: "I need to write tests for this Python ML pipeline"
4528
4546
  - You already suggested skills for this technology in this session
4529
4547
  - The user is in the middle of urgent debugging or time-sensitive work
4530
4548
  - The technology is too generic (e.g. just "code" or "programming")
4531
- `
4532
- };
4533
- var SAVE_LEARNING_SKILL = {
4534
- name: "save-learning",
4535
- description: "Saves user instructions as persistent learnings for future sessions. Use when the user says 'remember this', 'always do X', 'from now on', 'never do Y', or gives any instruction they want persisted across sessions. Proactively suggest when the user states a preference, convention, or rule they clearly want followed in the future.",
4536
- content: `# Save Learning
4549
+ `;
4550
+ }
4551
+ function getSaveLearningContent() {
4552
+ const bin = resolveCaliber();
4553
+ return `# Save Learning
4537
4554
 
4538
4555
  Save a user's instruction or preference as a persistent learning that
4539
4556
  will be applied in all future sessions on this project.
@@ -4554,11 +4571,11 @@ will be applied in all future sessions on this project.
4554
4571
  3. Show the refined learning to the user and ask for confirmation
4555
4572
  4. If confirmed, run:
4556
4573
  \`\`\`bash
4557
- caliber learn add "<refined learning>"
4574
+ ${bin} learn add "<refined learning>"
4558
4575
  \`\`\`
4559
4576
  For personal preferences (not project-level), add \`--personal\`:
4560
4577
  \`\`\`bash
4561
- caliber learn add --personal "<refined learning>"
4578
+ ${bin} learn add --personal "<refined learning>"
4562
4579
  \`\`\`
4563
4580
  5. Stage the learnings file for the next commit:
4564
4581
  \`\`\`bash
@@ -4572,7 +4589,7 @@ User: "when developing features, push to next branch not master, remember it"
4572
4589
  -> "I'll save this as a project learning:
4573
4590
  **[convention]** Push feature commits to the \\\`next\\\` branch, not \\\`master\\\`
4574
4591
  Save for future sessions?"
4575
- -> If yes: run \`caliber learn add "**[convention]** Push feature commits to the next branch, not master"\`
4592
+ -> If yes: run \`${bin} learn add "**[convention]** Push feature commits to the next branch, not master"\`
4576
4593
  -> Run \`git add CALIBER_LEARNINGS.md\`
4577
4594
 
4578
4595
  User: "always use bun instead of npm"
@@ -4588,7 +4605,21 @@ User: "never use any in TypeScript, use unknown instead"
4588
4605
  - The user is giving a one-time instruction for the current task only
4589
4606
  - The instruction is too vague to be actionable
4590
4607
  - The user explicitly says "just for now" or "only this time"
4591
- `
4608
+ `;
4609
+ }
4610
+ var FIND_SKILLS_SKILL = {
4611
+ name: "find-skills",
4612
+ description: "Discovers and installs community skills from the public registry. Use when the user mentions a technology, framework, or task that could benefit from specialized skills not yet installed, asks 'how do I do X', 'find a skill for X', or starts work in a new technology area. Proactively suggest when the user's task involves tools or frameworks without existing skills.",
4613
+ get content() {
4614
+ return getFindSkillsContent();
4615
+ }
4616
+ };
4617
+ var SAVE_LEARNING_SKILL = {
4618
+ name: "save-learning",
4619
+ description: "Saves user instructions as persistent learnings for future sessions. Use when the user says 'remember this', 'always do X', 'from now on', 'never do Y', or gives any instruction they want persisted across sessions. Proactively suggest when the user states a preference, convention, or rule they clearly want followed in the future.",
4620
+ get content() {
4621
+ return getSaveLearningContent();
4622
+ }
4592
4623
  };
4593
4624
  var BUILTIN_SKILLS = [FIND_SKILLS_SKILL, SAVE_LEARNING_SKILL];
4594
4625
  var PLATFORM_CONFIGS = [
@@ -4599,12 +4630,12 @@ var PLATFORM_CONFIGS = [
4599
4630
  function ensureBuiltinSkills() {
4600
4631
  const written = [];
4601
4632
  for (const { platformDir, skillsDir } of PLATFORM_CONFIGS) {
4602
- if (!fs15.existsSync(platformDir)) continue;
4633
+ if (!fs16.existsSync(platformDir)) continue;
4603
4634
  for (const skill of BUILTIN_SKILLS) {
4604
4635
  const skillPath = path15.join(skillsDir, skill.name, "SKILL.md");
4605
- if (fs15.existsSync(skillPath)) continue;
4606
- fs15.mkdirSync(path15.dirname(skillPath), { recursive: true });
4607
- fs15.writeFileSync(skillPath, buildSkillContent(skill));
4636
+ if (fs16.existsSync(skillPath)) continue;
4637
+ fs16.mkdirSync(path15.dirname(skillPath), { recursive: true });
4638
+ fs16.writeFileSync(skillPath, buildSkillContent(skill));
4608
4639
  written.push(skillPath);
4609
4640
  }
4610
4641
  }
@@ -4612,33 +4643,33 @@ function ensureBuiltinSkills() {
4612
4643
  }
4613
4644
 
4614
4645
  // src/writers/manifest.ts
4615
- import fs16 from "fs";
4646
+ import fs17 from "fs";
4616
4647
  import crypto3 from "crypto";
4617
4648
  function readManifest() {
4618
4649
  try {
4619
- if (!fs16.existsSync(MANIFEST_FILE)) return null;
4620
- return JSON.parse(fs16.readFileSync(MANIFEST_FILE, "utf-8"));
4650
+ if (!fs17.existsSync(MANIFEST_FILE)) return null;
4651
+ return JSON.parse(fs17.readFileSync(MANIFEST_FILE, "utf-8"));
4621
4652
  } catch {
4622
4653
  return null;
4623
4654
  }
4624
4655
  }
4625
4656
  function writeManifest(manifest) {
4626
- if (!fs16.existsSync(CALIBER_DIR)) {
4627
- fs16.mkdirSync(CALIBER_DIR, { recursive: true });
4657
+ if (!fs17.existsSync(CALIBER_DIR)) {
4658
+ fs17.mkdirSync(CALIBER_DIR, { recursive: true });
4628
4659
  }
4629
- fs16.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
4660
+ fs17.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
4630
4661
  }
4631
4662
  function fileChecksum(filePath) {
4632
- const content = fs16.readFileSync(filePath);
4663
+ const content = fs17.readFileSync(filePath);
4633
4664
  return crypto3.createHash("sha256").update(content).digest("hex");
4634
4665
  }
4635
4666
 
4636
4667
  // src/writers/index.ts
4637
4668
  function writeSetup(setup) {
4638
4669
  const filesToWrite = getFilesToWrite(setup);
4639
- const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs17.existsSync(f));
4670
+ const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs18.existsSync(f));
4640
4671
  const existingFiles = [
4641
- ...filesToWrite.filter((f) => fs17.existsSync(f)),
4672
+ ...filesToWrite.filter((f) => fs18.existsSync(f)),
4642
4673
  ...filesToDelete
4643
4674
  ];
4644
4675
  const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
@@ -4657,7 +4688,7 @@ function writeSetup(setup) {
4657
4688
  }
4658
4689
  const deleted = [];
4659
4690
  for (const filePath of filesToDelete) {
4660
- fs17.unlinkSync(filePath);
4691
+ fs18.unlinkSync(filePath);
4661
4692
  deleted.push(filePath);
4662
4693
  }
4663
4694
  written.push(...ensureBuiltinSkills());
@@ -4688,8 +4719,8 @@ function undoSetup() {
4688
4719
  const removed = [];
4689
4720
  for (const entry of manifest.entries) {
4690
4721
  if (entry.action === "created") {
4691
- if (fs17.existsSync(entry.path)) {
4692
- fs17.unlinkSync(entry.path);
4722
+ if (fs18.existsSync(entry.path)) {
4723
+ fs18.unlinkSync(entry.path);
4693
4724
  removed.push(entry.path);
4694
4725
  }
4695
4726
  } else if ((entry.action === "modified" || entry.action === "deleted") && manifest.backupDir) {
@@ -4698,8 +4729,8 @@ function undoSetup() {
4698
4729
  }
4699
4730
  }
4700
4731
  }
4701
- if (fs17.existsSync(MANIFEST_FILE)) {
4702
- fs17.unlinkSync(MANIFEST_FILE);
4732
+ if (fs18.existsSync(MANIFEST_FILE)) {
4733
+ fs18.unlinkSync(MANIFEST_FILE);
4703
4734
  }
4704
4735
  return { restored, removed };
4705
4736
  }
@@ -4740,18 +4771,18 @@ function getFilesToWrite(setup) {
4740
4771
  }
4741
4772
  function ensureGitignore() {
4742
4773
  const gitignorePath = ".gitignore";
4743
- if (fs17.existsSync(gitignorePath)) {
4744
- const content = fs17.readFileSync(gitignorePath, "utf-8");
4774
+ if (fs18.existsSync(gitignorePath)) {
4775
+ const content = fs18.readFileSync(gitignorePath, "utf-8");
4745
4776
  if (!content.includes(".caliber/")) {
4746
- fs17.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
4777
+ fs18.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
4747
4778
  }
4748
4779
  } else {
4749
- fs17.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
4780
+ fs18.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
4750
4781
  }
4751
4782
  }
4752
4783
 
4753
4784
  // src/writers/staging.ts
4754
- import fs18 from "fs";
4785
+ import fs19 from "fs";
4755
4786
  import path16 from "path";
4756
4787
  var STAGED_DIR = path16.join(CALIBER_DIR, "staged");
4757
4788
  var PROPOSED_DIR = path16.join(STAGED_DIR, "proposed");
@@ -4766,19 +4797,19 @@ function stageFiles(files, projectDir) {
4766
4797
  const stagedFiles = [];
4767
4798
  for (const file of files) {
4768
4799
  const originalPath = path16.join(projectDir, file.path);
4769
- if (fs18.existsSync(originalPath)) {
4770
- const existing = fs18.readFileSync(originalPath, "utf-8");
4800
+ if (fs19.existsSync(originalPath)) {
4801
+ const existing = fs19.readFileSync(originalPath, "utf-8");
4771
4802
  if (normalizeContent(existing) === normalizeContent(file.content)) {
4772
4803
  continue;
4773
4804
  }
4774
4805
  }
4775
4806
  const proposedPath = path16.join(PROPOSED_DIR, file.path);
4776
- fs18.mkdirSync(path16.dirname(proposedPath), { recursive: true });
4777
- fs18.writeFileSync(proposedPath, file.content);
4778
- if (fs18.existsSync(originalPath)) {
4807
+ fs19.mkdirSync(path16.dirname(proposedPath), { recursive: true });
4808
+ fs19.writeFileSync(proposedPath, file.content);
4809
+ if (fs19.existsSync(originalPath)) {
4779
4810
  const currentPath = path16.join(CURRENT_DIR, file.path);
4780
- fs18.mkdirSync(path16.dirname(currentPath), { recursive: true });
4781
- fs18.copyFileSync(originalPath, currentPath);
4811
+ fs19.mkdirSync(path16.dirname(currentPath), { recursive: true });
4812
+ fs19.copyFileSync(originalPath, currentPath);
4782
4813
  modifiedFiles++;
4783
4814
  stagedFiles.push({ relativePath: file.path, proposedPath, currentPath, originalPath, isNew: false });
4784
4815
  } else {
@@ -4789,13 +4820,13 @@ function stageFiles(files, projectDir) {
4789
4820
  return { newFiles, modifiedFiles, stagedFiles };
4790
4821
  }
4791
4822
  function cleanupStaging() {
4792
- if (fs18.existsSync(STAGED_DIR)) {
4793
- fs18.rmSync(STAGED_DIR, { recursive: true, force: true });
4823
+ if (fs19.existsSync(STAGED_DIR)) {
4824
+ fs19.rmSync(STAGED_DIR, { recursive: true, force: true });
4794
4825
  }
4795
4826
  }
4796
4827
 
4797
4828
  // src/commands/setup-files.ts
4798
- import fs19 from "fs";
4829
+ import fs20 from "fs";
4799
4830
  function collectSetupFiles(setup, targetAgent) {
4800
4831
  const files = [];
4801
4832
  const claude = setup.claude;
@@ -4854,7 +4885,7 @@ function collectSetupFiles(setup, targetAgent) {
4854
4885
  }
4855
4886
  }
4856
4887
  const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
4857
- if (codexTargeted && !fs19.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
4888
+ if (codexTargeted && !fs20.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
4858
4889
  const agentRefs = [];
4859
4890
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
4860
4891
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
@@ -5021,6 +5052,9 @@ function removeLearningHooks() {
5021
5052
  return { removed: true, notFound: false };
5022
5053
  }
5023
5054
 
5055
+ // src/commands/init.ts
5056
+ init_resolve_caliber();
5057
+
5024
5058
  // src/lib/state.ts
5025
5059
  import fs22 from "fs";
5026
5060
  import path18 from "path";
@@ -5667,6 +5701,7 @@ function checkGrounding(dir) {
5667
5701
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
5668
5702
  import { execSync as execSync9 } from "child_process";
5669
5703
  import { join as join5 } from "path";
5704
+ init_resolve_caliber();
5670
5705
  function validateReferences(dir) {
5671
5706
  const configContent = collectPrimaryConfigContent(dir);
5672
5707
  if (!configContent) return { valid: [], invalid: [], total: 0 };
@@ -5790,7 +5825,7 @@ function checkAccuracy(dir) {
5790
5825
  earnedPoints: driftPoints,
5791
5826
  passed: drift.commitsSinceConfigUpdate <= 15 || !drift.isGitRepo,
5792
5827
  detail: !drift.isGitRepo ? "Not a git repository \u2014 skipping drift check" : !drift.lastConfigCommit ? "Config files not tracked in git" : drift.commitsSinceConfigUpdate === 0 ? "Config is up to date with latest commits" : `${drift.commitsSinceConfigUpdate} commit${drift.commitsSinceConfigUpdate === 1 ? "" : "s"} since last config update`,
5793
- suggestion: drift.commitsSinceConfigUpdate > 15 ? `Code has had ${drift.commitsSinceConfigUpdate} commits since last config update \u2014 run \`caliber refresh\` to sync` : void 0,
5828
+ suggestion: drift.commitsSinceConfigUpdate > 15 ? `Code has had ${drift.commitsSinceConfigUpdate} commits since last config update \u2014 run \`${resolveCaliber()} refresh\` to sync` : void 0,
5794
5829
  fix: drift.commitsSinceConfigUpdate > 15 ? {
5795
5830
  action: "refresh_config",
5796
5831
  data: { commitsSince: drift.commitsSinceConfigUpdate, lastConfigCommit: drift.lastConfigCommit },
@@ -5801,6 +5836,7 @@ function checkAccuracy(dir) {
5801
5836
  }
5802
5837
 
5803
5838
  // src/scoring/checks/freshness.ts
5839
+ init_resolve_caliber();
5804
5840
  import { existsSync as existsSync5, statSync as statSync3 } from "fs";
5805
5841
  import { execSync as execSync10 } from "child_process";
5806
5842
  import { join as join6 } from "path";
@@ -5864,7 +5900,7 @@ function checkFreshness(dir) {
5864
5900
  earnedPoints: freshnessPoints,
5865
5901
  passed: freshnessPoints >= 3,
5866
5902
  detail: freshnessDetail,
5867
- suggestion: commitsSince !== null && freshnessPoints < 3 ? `Config is ${commitsSince} commits behind \u2014 run \`caliber refresh\` to update it` : void 0,
5903
+ suggestion: commitsSince !== null && freshnessPoints < 3 ? `Config is ${commitsSince} commits behind \u2014 run \`${resolveCaliber()} refresh\` to update it` : void 0,
5868
5904
  fix: commitsSince !== null && freshnessPoints < 3 ? {
5869
5905
  action: "refresh_config",
5870
5906
  data: { commitsSince },
@@ -5952,6 +5988,7 @@ function checkFreshness(dir) {
5952
5988
  import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
5953
5989
  import { execSync as execSync11 } from "child_process";
5954
5990
  import { join as join7 } from "path";
5991
+ init_resolve_caliber();
5955
5992
  function hasPreCommitHook(dir) {
5956
5993
  try {
5957
5994
  const gitDir = execSync11("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
@@ -5997,11 +6034,11 @@ function checkBonus(dir) {
5997
6034
  earnedPoints: hasHooks ? POINTS_HOOKS : 0,
5998
6035
  passed: hasHooks,
5999
6036
  detail: hasHooks ? hookSources.join(", ") : "No hooks configured",
6000
- suggestion: hasHooks ? void 0 : "Run `caliber init` to add pre-commit instructions",
6037
+ suggestion: hasHooks ? void 0 : `Run \`${resolveCaliber()} init\` to add pre-commit instructions`,
6001
6038
  fix: hasHooks ? void 0 : {
6002
6039
  action: "install_hooks",
6003
6040
  data: {},
6004
- instruction: "Run caliber init to add pre-commit refresh instructions to config files."
6041
+ instruction: `Run ${resolveCaliber()} init to add pre-commit refresh instructions to config files.`
6005
6042
  }
6006
6043
  });
6007
6044
  const agentsMdExists = existsSync6(join7(dir, "AGENTS.md"));
@@ -6066,13 +6103,14 @@ function checkBonus(dir) {
6066
6103
  earnedPoints: hasLearned ? POINTS_LEARNED_CONTENT : 0,
6067
6104
  passed: hasLearned,
6068
6105
  detail: hasLearned ? "Session learnings found in CALIBER_LEARNINGS.md" : "No learned content",
6069
- suggestion: hasLearned ? void 0 : "Install learning hooks: `caliber learn install`"
6106
+ suggestion: hasLearned ? void 0 : `Install learning hooks: \`${resolveCaliber()} learn install\``
6070
6107
  });
6071
6108
  return checks;
6072
6109
  }
6073
6110
 
6074
6111
  // src/scoring/checks/sources.ts
6075
6112
  import { join as join8 } from "path";
6113
+ init_resolve_caliber();
6076
6114
  function checkSources(dir) {
6077
6115
  const checks = [];
6078
6116
  const configSources = loadSourcesConfig(dir);
@@ -6085,7 +6123,7 @@ function checkSources(dir) {
6085
6123
  earnedPoints: hasSources ? POINTS_SOURCES_CONFIGURED : 0,
6086
6124
  passed: hasSources,
6087
6125
  detail: hasSources ? `${configSources.length} source${configSources.length === 1 ? "" : "s"} configured` : "No external sources configured",
6088
- suggestion: hasSources ? void 0 : "Run `caliber sources add <path>` to add related repos or docs"
6126
+ suggestion: hasSources ? void 0 : `Run \`${resolveCaliber()} sources add <path>\` to add related repos or docs`
6089
6127
  });
6090
6128
  if (hasSources) {
6091
6129
  const claudeMd = readFileOrNull(join8(dir, "CLAUDE.md"));
@@ -6103,7 +6141,7 @@ function checkSources(dir) {
6103
6141
  earnedPoints: referenced ? POINTS_SOURCES_REFERENCED : 0,
6104
6142
  passed: referenced,
6105
6143
  detail: referenced ? "At least one source is referenced in CLAUDE.md" : "No configured sources are mentioned in CLAUDE.md",
6106
- suggestion: referenced ? void 0 : "Regenerate with `caliber init` to include source context in your config"
6144
+ suggestion: referenced ? void 0 : `Regenerate with \`${resolveCaliber()} init\` to include source context in your config`
6107
6145
  });
6108
6146
  }
6109
6147
  return checks;
@@ -6194,6 +6232,7 @@ function computeLocalScore(dir, targetAgent) {
6194
6232
  }
6195
6233
 
6196
6234
  // src/scoring/display.ts
6235
+ init_resolve_caliber();
6197
6236
  import chalk4 from "chalk";
6198
6237
  var AGENT_DISPLAY_NAMES = {
6199
6238
  claude: "Claude Code",
@@ -6329,7 +6368,7 @@ function displayScoreSummary(result) {
6329
6368
  const remaining = failing.length - shown.length;
6330
6369
  const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
6331
6370
  console.log(chalk4.dim(`
6332
- Run ${chalk4.hex("#83D1EB")("caliber score")} for details.${moreText}`));
6371
+ Run ${chalk4.hex("#83D1EB")(`${resolveCaliber()} score`)} for details.${moreText}`));
6333
6372
  }
6334
6373
  console.log("");
6335
6374
  }
@@ -6574,6 +6613,7 @@ function trackInsightsViewed(totalSessions, learningCount) {
6574
6613
  }
6575
6614
 
6576
6615
  // src/commands/recommend.ts
6616
+ init_resolve_caliber();
6577
6617
  function detectLocalPlatforms() {
6578
6618
  const items = scanLocalState(process.cwd());
6579
6619
  const platforms = /* @__PURE__ */ new Set();
@@ -6950,7 +6990,7 @@ async function querySkills(query) {
6950
6990
  console.log(` ${r.reason || r.name}`);
6951
6991
  }
6952
6992
  console.log("");
6953
- console.log(chalk6.dim(` Install with: caliber skills --install ${available.map((r) => r.slug).join(",")}`));
6993
+ console.log(chalk6.dim(` Install with: ${resolveCaliber()} skills --install ${available.map((r) => r.slug).join(",")}`));
6954
6994
  console.log("");
6955
6995
  }
6956
6996
  async function installBySlug(slugStr) {
@@ -8713,6 +8753,7 @@ function log(verbose, ...args) {
8713
8753
  async function initCommand(options) {
8714
8754
  const brand = chalk14.hex("#EB9D83");
8715
8755
  const title = chalk14.hex("#83D1EB");
8756
+ const bin = resolveCaliber();
8716
8757
  const firstRun = isFirstRun(process.cwd());
8717
8758
  if (firstRun) {
8718
8759
  console.log(brand.bold(`
@@ -8810,7 +8851,7 @@ async function initCommand(options) {
8810
8851
  if (hasExistingConfig && baselineScore.score === 100) {
8811
8852
  trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
8812
8853
  console.log(chalk14.bold.green(" Your config is already optimal \u2014 nothing to change.\n"));
8813
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")("caliber init --force") + chalk14.dim(" to regenerate anyway.\n"));
8854
+ console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n"));
8814
8855
  if (!options.force) return;
8815
8856
  }
8816
8857
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
@@ -8826,7 +8867,7 @@ async function initCommand(options) {
8826
8867
  }
8827
8868
  }
8828
8869
  console.log("");
8829
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")("caliber init --force") + chalk14.dim(" to regenerate anyway.\n"));
8870
+ console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n"));
8830
8871
  return;
8831
8872
  }
8832
8873
  console.log(title.bold(" Step 2/4 \u2014 Engine\n"));
@@ -9161,7 +9202,7 @@ ${agentRefs.join(" ")}
9161
9202
  }
9162
9203
  } catch {
9163
9204
  }
9164
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")("caliber init --force") + chalk14.dim(" to override.\n"));
9205
+ console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n"));
9165
9206
  return;
9166
9207
  }
9167
9208
  if (report) {
@@ -9191,7 +9232,7 @@ ${agentRefs.join(" ")}
9191
9232
  }
9192
9233
  }
9193
9234
  console.log("");
9194
- console.log(` ${chalk14.green("\u2713")} Docs auto-refresh ${chalk14.dim("agents run caliber refresh before commits")}`);
9235
+ console.log(` ${chalk14.green("\u2713")} Docs auto-refresh ${chalk14.dim(`agents run ${resolveCaliber()} refresh before commits`)}`);
9195
9236
  trackInitHookSelected("config-instructions");
9196
9237
  const hasLearnableAgent = targetAgent.includes("claude") || targetAgent.includes("cursor");
9197
9238
  let enableLearn = false;
@@ -9210,9 +9251,9 @@ ${agentRefs.join(" ")}
9210
9251
  if (r.installed) console.log(` ${chalk14.green("\u2713")} Learning hooks installed for Cursor`);
9211
9252
  else if (r.alreadyInstalled) console.log(chalk14.dim(" Cursor learning hooks already installed"));
9212
9253
  }
9213
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")("caliber learn status") + chalk14.dim(" to see insights"));
9254
+ console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} learn status`) + chalk14.dim(" to see insights"));
9214
9255
  } else {
9215
- console.log(chalk14.dim(" Skipped. Run ") + chalk14.hex("#83D1EB")("caliber learn install") + chalk14.dim(" later to enable."));
9256
+ console.log(chalk14.dim(" Skipped. Run ") + chalk14.hex("#83D1EB")(`${bin} learn install`) + chalk14.dim(" later to enable."));
9216
9257
  }
9217
9258
  } else {
9218
9259
  enableLearn = true;
@@ -9226,13 +9267,13 @@ ${agentRefs.join(" ")}
9226
9267
  const done = chalk14.green("\u2713");
9227
9268
  const skip = chalk14.dim("\u2013");
9228
9269
  console.log(chalk14.bold(" What was configured:\n"));
9229
- console.log(` ${done} Config generated ${title("caliber score")} ${chalk14.dim("for full breakdown")}`);
9230
- console.log(` ${done} Docs auto-refresh ${chalk14.dim("agents run caliber refresh before commits")}`);
9270
+ console.log(` ${done} Config generated ${title(`${bin} score`)} ${chalk14.dim("for full breakdown")}`);
9271
+ console.log(` ${done} Docs auto-refresh ${chalk14.dim(`agents run ${bin} refresh before commits`)}`);
9231
9272
  if (hasLearnableAgent) {
9232
9273
  if (enableLearn) {
9233
9274
  console.log(` ${done} Session learning ${chalk14.dim("agent learns from your feedback")}`);
9234
9275
  } else {
9235
- console.log(` ${skip} Session learning ${title("caliber learn install")} to enable later`);
9276
+ console.log(` ${skip} Session learning ${title(`${bin} learn install`)} to enable later`);
9236
9277
  }
9237
9278
  }
9238
9279
  if (communitySkillsInstalled > 0) {
@@ -9241,9 +9282,9 @@ ${agentRefs.join(" ")}
9241
9282
  console.log(` ${skip} Community skills ${chalk14.dim("available but skipped")}`);
9242
9283
  }
9243
9284
  console.log(chalk14.bold("\n Explore next:\n"));
9244
- console.log(` ${title("caliber skills")} Find more community skills as your codebase evolves`);
9245
- console.log(` ${title("caliber score")} See the full scoring breakdown with improvement tips`);
9246
- console.log(` ${title("caliber undo")} Revert all changes from this run`);
9285
+ console.log(` ${title(`${bin} skills`)} Find more community skills as your codebase evolves`);
9286
+ console.log(` ${title(`${bin} score`)} See the full scoring breakdown with improvement tips`);
9287
+ console.log(` ${title(`${bin} undo`)} Revert all changes from this run`);
9247
9288
  console.log("");
9248
9289
  if (options.showTokens) {
9249
9290
  displayTokenUsage();
@@ -9293,6 +9334,7 @@ function undoCommand() {
9293
9334
  import chalk16 from "chalk";
9294
9335
  import fs33 from "fs";
9295
9336
  init_config();
9337
+ init_resolve_caliber();
9296
9338
  async function statusCommand(options) {
9297
9339
  const config = loadConfig();
9298
9340
  const manifest = readManifest();
@@ -9309,11 +9351,12 @@ async function statusCommand(options) {
9309
9351
  if (config) {
9310
9352
  console.log(` LLM: ${chalk16.green(config.provider)} (${config.model})`);
9311
9353
  } else {
9312
- console.log(` LLM: ${chalk16.yellow("Not configured")} \u2014 run ${chalk16.hex("#83D1EB")("caliber config")}`);
9354
+ const bin = resolveCaliber();
9355
+ console.log(` LLM: ${chalk16.yellow("Not configured")} \u2014 run ${chalk16.hex("#83D1EB")(`${bin} config`)}`);
9313
9356
  }
9314
9357
  if (!manifest) {
9315
9358
  console.log(` Config: ${chalk16.dim("No config applied")}`);
9316
- console.log(chalk16.dim("\n Run ") + chalk16.hex("#83D1EB")("caliber init") + chalk16.dim(" to get started.\n"));
9359
+ console.log(chalk16.dim("\n Run ") + chalk16.hex("#83D1EB")(`${resolveCaliber()} init`) + chalk16.dim(" to get started.\n"));
9317
9360
  return;
9318
9361
  }
9319
9362
  console.log(` Files managed: ${chalk16.cyan(manifest.entries.length.toString())}`);
@@ -9331,15 +9374,17 @@ import ora5 from "ora";
9331
9374
  import select6 from "@inquirer/select";
9332
9375
  init_review();
9333
9376
  init_config();
9377
+ init_resolve_caliber();
9334
9378
  async function regenerateCommand(options) {
9379
+ const bin = resolveCaliber();
9335
9380
  const config = loadConfig();
9336
9381
  if (!config) {
9337
- console.log(chalk17.red("No LLM provider configured. Run ") + chalk17.hex("#83D1EB")("caliber config") + chalk17.red(" first."));
9382
+ console.log(chalk17.red("No LLM provider configured. Run ") + chalk17.hex("#83D1EB")(`${bin} config`) + chalk17.red(" first."));
9338
9383
  throw new Error("__exit__");
9339
9384
  }
9340
9385
  const manifest = readManifest();
9341
9386
  if (!manifest) {
9342
- console.log(chalk17.yellow("No existing config found. Run ") + chalk17.hex("#83D1EB")("caliber init") + chalk17.yellow(" first."));
9387
+ console.log(chalk17.yellow("No existing config found. Run ") + chalk17.hex("#83D1EB")(`${bin} init`) + chalk17.yellow(" first."));
9343
9388
  throw new Error("__exit__");
9344
9389
  }
9345
9390
  const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
@@ -9463,13 +9508,13 @@ async function regenerateCommand(options) {
9463
9508
  }
9464
9509
  } catch {
9465
9510
  }
9466
- console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")("caliber init --force") + chalk17.dim(" to override.\n"));
9511
+ console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} init --force`) + chalk17.dim(" to override.\n"));
9467
9512
  return;
9468
9513
  }
9469
9514
  displayScoreDelta(baselineScore, afterScore);
9470
9515
  trackRegenerateCompleted(action, Date.now());
9471
9516
  console.log(chalk17.bold.green(" Regeneration complete!"));
9472
- console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")("caliber undo") + chalk17.dim(" to revert changes.\n"));
9517
+ console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} undo`) + chalk17.dim(" to revert changes.\n"));
9473
9518
  }
9474
9519
 
9475
9520
  // src/commands/score.ts
@@ -9478,6 +9523,7 @@ import os7 from "os";
9478
9523
  import path26 from "path";
9479
9524
  import { execFileSync as execFileSync2 } from "child_process";
9480
9525
  import chalk18 from "chalk";
9526
+ init_resolve_caliber();
9481
9527
  var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".cursorrules", "CALIBER_LEARNINGS.md"];
9482
9528
  var CONFIG_DIRS = [".claude", ".cursor"];
9483
9529
  function scoreBaseRef(ref, target) {
@@ -9558,12 +9604,13 @@ async function scoreCommand(options) {
9558
9604
  displayScore(result);
9559
9605
  const separator = chalk18.gray(" " + "\u2500".repeat(53));
9560
9606
  console.log(separator);
9607
+ const bin = resolveCaliber();
9561
9608
  if (result.score < 40) {
9562
- console.log(chalk18.gray(" Run ") + chalk18.hex("#83D1EB")("caliber init") + chalk18.gray(" to generate a complete, optimized config."));
9609
+ console.log(chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate a complete, optimized config."));
9563
9610
  } else if (result.score < 70) {
9564
- console.log(chalk18.gray(" Run ") + chalk18.hex("#83D1EB")("caliber init") + chalk18.gray(" to improve your config."));
9611
+ console.log(chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve your config."));
9565
9612
  } else {
9566
- console.log(chalk18.green(" Looking good!") + chalk18.gray(" Run ") + chalk18.hex("#83D1EB")("caliber regenerate") + chalk18.gray(" to rebuild from scratch."));
9613
+ console.log(chalk18.green(" Looking good!") + chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch."));
9567
9614
  }
9568
9615
  console.log("");
9569
9616
  }
@@ -9970,6 +10017,7 @@ function migrateInlineLearnings() {
9970
10017
 
9971
10018
  // src/commands/refresh.ts
9972
10019
  init_config();
10020
+ init_resolve_caliber();
9973
10021
  function log2(quiet, ...args) {
9974
10022
  if (!quiet) console.log(...args);
9975
10023
  }
@@ -10122,7 +10170,7 @@ async function refreshCommand(options) {
10122
10170
  const config = loadConfig();
10123
10171
  if (!config) {
10124
10172
  if (quiet) return;
10125
- console.log(chalk19.red("No LLM provider configured. Run ") + chalk19.hex("#83D1EB")("caliber config") + chalk19.red(" (e.g. choose Cursor) or set an API key."));
10173
+ console.log(chalk19.red("No LLM provider configured. Run ") + chalk19.hex("#83D1EB")(`${resolveCaliber()} config`) + chalk19.red(" (e.g. choose Cursor) or set an API key."));
10126
10174
  throw new Error("__exit__");
10127
10175
  }
10128
10176
  await validateModel({ fast: true });
@@ -10236,11 +10284,14 @@ var PRECOMMIT_START = "# caliber:pre-commit:start";
10236
10284
  var PRECOMMIT_END = "# caliber:pre-commit:end";
10237
10285
  function getPrecommitBlock() {
10238
10286
  const bin = resolveCaliber();
10287
+ const npx = isNpxResolution();
10288
+ const guard = npx ? "command -v npx >/dev/null 2>&1" : `[ -x "${bin}" ] || command -v "${bin}" >/dev/null 2>&1`;
10289
+ const invoke = npx ? bin : `"${bin}"`;
10239
10290
  return `${PRECOMMIT_START}
10240
- if [ -x "${bin}" ] || command -v "${bin}" >/dev/null 2>&1; then
10291
+ if ${guard}; then
10241
10292
  echo "\\033[2mcaliber: refreshing docs...\\033[0m"
10242
- "${bin}" refresh 2>/dev/null || true
10243
- "${bin}" learn finalize 2>/dev/null || true
10293
+ ${invoke} refresh 2>/dev/null || true
10294
+ ${invoke} learn finalize 2>/dev/null || true
10244
10295
  git diff --name-only -- CLAUDE.md .claude/ .cursor/ AGENTS.md CALIBER_LEARNINGS.md 2>/dev/null | xargs git add 2>/dev/null || true
10245
10296
  fi
10246
10297
  ${PRECOMMIT_END}`;
@@ -11145,6 +11196,7 @@ function findStaleLearnings(stats, minSessions = DEFAULT_MIN_SESSIONS) {
11145
11196
  }
11146
11197
 
11147
11198
  // src/commands/learn.ts
11199
+ init_resolve_caliber();
11148
11200
  var MIN_EVENTS_FOR_ANALYSIS = 25;
11149
11201
  var MIN_EVENTS_AUTO = 10;
11150
11202
  var AUTO_SETTLE_MS = 200;
@@ -11248,7 +11300,7 @@ async function learnFinalizeCommand(options) {
11248
11300
  const config = loadConfig();
11249
11301
  if (!config) {
11250
11302
  if (isAuto) return;
11251
- console.log(chalk23.yellow("caliber: no LLM provider configured \u2014 run `caliber config` first"));
11303
+ console.log(chalk23.yellow(`caliber: no LLM provider configured \u2014 run \`${resolveCaliber()} config\` first`));
11252
11304
  clearSession();
11253
11305
  resetState();
11254
11306
  return;
@@ -11396,7 +11448,7 @@ async function learnFinalizeCommand(options) {
11396
11448
  if (!isIncremental) {
11397
11449
  const staleLearnings = findStaleLearnings(roiStats);
11398
11450
  if (staleLearnings.length > 0 && !isAuto) {
11399
- console.log(chalk23.yellow(`caliber: ${staleLearnings.length} learning${staleLearnings.length === 1 ? "" : "s"} never activated \u2014 run \`caliber learn list --verbose\` to review`));
11451
+ console.log(chalk23.yellow(`caliber: ${staleLearnings.length} learning${staleLearnings.length === 1 ? "" : "s"} never activated \u2014 run \`${resolveCaliber()} learn list --verbose\` to review`));
11400
11452
  }
11401
11453
  }
11402
11454
  if (!isAuto && t.estimatedSavingsTokens > 0) {
@@ -11446,7 +11498,7 @@ async function learnInstallCommand() {
11446
11498
  }
11447
11499
  if (!fs44.existsSync(".claude") && !fs44.existsSync(".cursor")) {
11448
11500
  console.log(chalk23.yellow("No .claude/ or .cursor/ directory found."));
11449
- console.log(chalk23.dim(" Run `caliber init` first, or create the directory manually."));
11501
+ console.log(chalk23.dim(` Run \`${resolveCaliber()} init\` first, or create the directory manually.`));
11450
11502
  return;
11451
11503
  }
11452
11504
  if (anyInstalled) {
@@ -11488,7 +11540,7 @@ async function learnStatusCommand() {
11488
11540
  console.log(chalk23.dim("\u2717") + " Cursor hooks " + chalk23.dim("not installed"));
11489
11541
  }
11490
11542
  if (!claudeInstalled && !cursorInstalled) {
11491
- console.log(chalk23.dim(" Run `caliber learn install` to enable session learning."));
11543
+ console.log(chalk23.dim(` Run \`${resolveCaliber()} learn install\` to enable session learning.`));
11492
11544
  }
11493
11545
  console.log();
11494
11546
  console.log(`Events recorded: ${chalk23.cyan(String(eventCount))}`);
@@ -11543,7 +11595,7 @@ function getAllLearnings() {
11543
11595
  async function learnListCommand(options) {
11544
11596
  const items = getAllLearnings();
11545
11597
  if (items.length === 0) {
11546
- console.log(chalk23.dim("No learnings yet. Run `caliber learn install` to start."));
11598
+ console.log(chalk23.dim(`No learnings yet. Run \`${resolveCaliber()} learn install\` to start.`));
11547
11599
  return;
11548
11600
  }
11549
11601
  const roiStats = options?.verbose ? readROIStats() : null;
@@ -11572,7 +11624,7 @@ async function learnListCommand(options) {
11572
11624
  async function learnDeleteCommand(indexStr) {
11573
11625
  const index = parseInt(indexStr, 10);
11574
11626
  if (isNaN(index) || index < 1) {
11575
- console.log(chalk23.red(`Invalid index: "${indexStr}". Use a number from \`caliber learn list\`.`));
11627
+ console.log(chalk23.red(`Invalid index: "${indexStr}". Use a number from \`${resolveCaliber()} learn list\`.`));
11576
11628
  return;
11577
11629
  }
11578
11630
  const items = getAllLearnings();
@@ -11637,6 +11689,7 @@ async function learnAddCommand(content, options) {
11637
11689
 
11638
11690
  // src/commands/insights.ts
11639
11691
  import chalk24 from "chalk";
11692
+ init_resolve_caliber();
11640
11693
  var MIN_SESSIONS_FULL = 20;
11641
11694
  function buildInsightsData(stats) {
11642
11695
  const t = stats.totals;
@@ -11682,7 +11735,7 @@ function displayColdStart(score) {
11682
11735
  console.log(chalk24.yellow(" Learning hooks not installed."));
11683
11736
  console.log(chalk24.dim(" Session learning captures patterns from your AI coding sessions \u2014 what"));
11684
11737
  console.log(chalk24.dim(" fails, what works, corrections you make \u2014 so your agents improve over time.\n"));
11685
- console.log(chalk24.dim(" Run ") + chalk24.cyan("caliber learn install") + chalk24.dim(" to enable."));
11738
+ console.log(chalk24.dim(" Run ") + chalk24.cyan(`${resolveCaliber()} learn install`) + chalk24.dim(" to enable."));
11686
11739
  } else {
11687
11740
  console.log(chalk24.dim(" Learning hooks are active. Use your AI agent and insights"));
11688
11741
  console.log(chalk24.dim(" will appear automatically after each session.\n"));
@@ -11785,13 +11838,14 @@ async function insightsCommand(options) {
11785
11838
  import fs45 from "fs";
11786
11839
  import path36 from "path";
11787
11840
  import chalk25 from "chalk";
11841
+ init_resolve_caliber();
11788
11842
  async function sourcesListCommand() {
11789
11843
  const dir = process.cwd();
11790
11844
  const configSources = loadSourcesConfig(dir);
11791
11845
  const workspaces = getDetectedWorkspaces(dir);
11792
11846
  if (configSources.length === 0 && workspaces.length === 0) {
11793
11847
  console.log(chalk25.dim("\n No sources configured.\n"));
11794
- console.log(chalk25.dim(" Add a source: ") + chalk25.hex("#83D1EB")("caliber sources add <path>"));
11848
+ console.log(chalk25.dim(" Add a source: ") + chalk25.hex("#83D1EB")(`${resolveCaliber()} sources add <path>`));
11795
11849
  console.log(chalk25.dim(" Or add to .caliber/sources.json manually.\n"));
11796
11850
  return;
11797
11851
  }
@@ -11888,11 +11942,12 @@ import path37 from "path";
11888
11942
  import chalk26 from "chalk";
11889
11943
  import ora7 from "ora";
11890
11944
  init_config();
11945
+ init_resolve_caliber();
11891
11946
  async function publishCommand() {
11892
11947
  const dir = process.cwd();
11893
11948
  const config = loadConfig();
11894
11949
  if (!config) {
11895
- console.log(chalk26.red("No LLM provider configured. Run ") + chalk26.hex("#83D1EB")("caliber config") + chalk26.red(" first."));
11950
+ console.log(chalk26.red("No LLM provider configured. Run ") + chalk26.hex("#83D1EB")(`${resolveCaliber()} config`) + chalk26.red(" first."));
11896
11951
  throw new Error("__exit__");
11897
11952
  }
11898
11953
  const spinner = ora7("Generating project summary...").start();