@rely-ai/caliber 1.3.3 → 1.4.0

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 +266 -203
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -51,7 +51,7 @@ var init_constants = __esm({
51
51
 
52
52
  // src/cli.ts
53
53
  import { Command } from "commander";
54
- import fs26 from "fs";
54
+ import fs27 from "fs";
55
55
  import path22 from "path";
56
56
  import { fileURLToPath } from "url";
57
57
 
@@ -61,7 +61,7 @@ import ora2 from "ora";
61
61
  import readline4 from "readline";
62
62
  import select2 from "@inquirer/select";
63
63
  import checkbox from "@inquirer/checkbox";
64
- import fs19 from "fs";
64
+ import fs20 from "fs";
65
65
 
66
66
  // src/fingerprint/index.ts
67
67
  import fs6 from "fs";
@@ -2204,25 +2204,92 @@ function openDiffsInEditor(editor, files) {
2204
2204
  // src/commands/onboard.ts
2205
2205
  import { createTwoFilesPatch } from "diff";
2206
2206
 
2207
- // src/lib/hooks.ts
2207
+ // src/commands/setup-files.ts
2208
2208
  import fs14 from "fs";
2209
+ function buildSkillContent(skill) {
2210
+ const frontmatter = `---
2211
+ name: ${skill.name}
2212
+ description: ${skill.description}
2213
+ ---
2214
+
2215
+ `;
2216
+ return frontmatter + skill.content;
2217
+ }
2218
+ function collectSetupFiles(setup) {
2219
+ const files = [];
2220
+ const claude = setup.claude;
2221
+ const cursor = setup.cursor;
2222
+ const codex = setup.codex;
2223
+ if (claude) {
2224
+ if (claude.claudeMd) files.push({ path: "CLAUDE.md", content: claude.claudeMd });
2225
+ const skills = claude.skills;
2226
+ if (Array.isArray(skills)) {
2227
+ for (const skill of skills) {
2228
+ files.push({ path: `.claude/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
2229
+ }
2230
+ }
2231
+ }
2232
+ if (codex) {
2233
+ if (codex.agentsMd) files.push({ path: "AGENTS.md", content: codex.agentsMd });
2234
+ const codexSkills = codex.skills;
2235
+ if (Array.isArray(codexSkills)) {
2236
+ for (const skill of codexSkills) {
2237
+ files.push({ path: `.agents/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
2238
+ }
2239
+ }
2240
+ }
2241
+ if (cursor) {
2242
+ if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
2243
+ const cursorSkills = cursor.skills;
2244
+ if (Array.isArray(cursorSkills)) {
2245
+ for (const skill of cursorSkills) {
2246
+ files.push({ path: `.cursor/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
2247
+ }
2248
+ }
2249
+ const rules = cursor.rules;
2250
+ if (Array.isArray(rules)) {
2251
+ for (const rule of rules) {
2252
+ files.push({ path: `.cursor/rules/${rule.filename}`, content: rule.content });
2253
+ }
2254
+ }
2255
+ }
2256
+ if (!fs14.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
2257
+ const agentRefs = [];
2258
+ if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
2259
+ if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
2260
+ if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
2261
+ files.push({
2262
+ path: "AGENTS.md",
2263
+ content: `# AGENTS.md
2264
+
2265
+ This project uses AI coding agents configured by [Caliber](https://github.com/rely-ai-org/caliber).
2266
+
2267
+ ${agentRefs.join(" ")}
2268
+ `
2269
+ });
2270
+ }
2271
+ return files;
2272
+ }
2273
+
2274
+ // src/lib/hooks.ts
2275
+ import fs15 from "fs";
2209
2276
  import path12 from "path";
2210
2277
  import { execSync as execSync5 } from "child_process";
2211
2278
  var SETTINGS_PATH = path12.join(".claude", "settings.json");
2212
2279
  var HOOK_COMMAND = "caliber refresh --quiet";
2213
2280
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
2214
2281
  function readSettings() {
2215
- if (!fs14.existsSync(SETTINGS_PATH)) return {};
2282
+ if (!fs15.existsSync(SETTINGS_PATH)) return {};
2216
2283
  try {
2217
- return JSON.parse(fs14.readFileSync(SETTINGS_PATH, "utf-8"));
2284
+ return JSON.parse(fs15.readFileSync(SETTINGS_PATH, "utf-8"));
2218
2285
  } catch {
2219
2286
  return {};
2220
2287
  }
2221
2288
  }
2222
2289
  function writeSettings(settings) {
2223
2290
  const dir = path12.dirname(SETTINGS_PATH);
2224
- if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
2225
- fs14.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
2291
+ if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
2292
+ fs15.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
2226
2293
  }
2227
2294
  function findHookIndex(sessionEnd) {
2228
2295
  return sessionEnd.findIndex(
@@ -2291,8 +2358,8 @@ function getPreCommitPath() {
2291
2358
  }
2292
2359
  function isPreCommitHookInstalled() {
2293
2360
  const hookPath = getPreCommitPath();
2294
- if (!hookPath || !fs14.existsSync(hookPath)) return false;
2295
- const content = fs14.readFileSync(hookPath, "utf-8");
2361
+ if (!hookPath || !fs15.existsSync(hookPath)) return false;
2362
+ const content = fs15.readFileSync(hookPath, "utf-8");
2296
2363
  return content.includes(PRECOMMIT_START);
2297
2364
  }
2298
2365
  function installPreCommitHook() {
@@ -2302,40 +2369,40 @@ function installPreCommitHook() {
2302
2369
  const hookPath = getPreCommitPath();
2303
2370
  if (!hookPath) return { installed: false, alreadyInstalled: false };
2304
2371
  const hooksDir = path12.dirname(hookPath);
2305
- if (!fs14.existsSync(hooksDir)) fs14.mkdirSync(hooksDir, { recursive: true });
2372
+ if (!fs15.existsSync(hooksDir)) fs15.mkdirSync(hooksDir, { recursive: true });
2306
2373
  let content = "";
2307
- if (fs14.existsSync(hookPath)) {
2308
- content = fs14.readFileSync(hookPath, "utf-8");
2374
+ if (fs15.existsSync(hookPath)) {
2375
+ content = fs15.readFileSync(hookPath, "utf-8");
2309
2376
  if (!content.endsWith("\n")) content += "\n";
2310
2377
  content += "\n" + PRECOMMIT_BLOCK + "\n";
2311
2378
  } else {
2312
2379
  content = "#!/bin/sh\n\n" + PRECOMMIT_BLOCK + "\n";
2313
2380
  }
2314
- fs14.writeFileSync(hookPath, content);
2315
- fs14.chmodSync(hookPath, 493);
2381
+ fs15.writeFileSync(hookPath, content);
2382
+ fs15.chmodSync(hookPath, 493);
2316
2383
  return { installed: true, alreadyInstalled: false };
2317
2384
  }
2318
2385
  function removePreCommitHook() {
2319
2386
  const hookPath = getPreCommitPath();
2320
- if (!hookPath || !fs14.existsSync(hookPath)) {
2387
+ if (!hookPath || !fs15.existsSync(hookPath)) {
2321
2388
  return { removed: false, notFound: true };
2322
2389
  }
2323
- let content = fs14.readFileSync(hookPath, "utf-8");
2390
+ let content = fs15.readFileSync(hookPath, "utf-8");
2324
2391
  if (!content.includes(PRECOMMIT_START)) {
2325
2392
  return { removed: false, notFound: true };
2326
2393
  }
2327
2394
  const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
2328
2395
  content = content.replace(regex, "\n");
2329
2396
  if (content.trim() === "#!/bin/sh" || content.trim() === "") {
2330
- fs14.unlinkSync(hookPath);
2397
+ fs15.unlinkSync(hookPath);
2331
2398
  } else {
2332
- fs14.writeFileSync(hookPath, content);
2399
+ fs15.writeFileSync(hookPath, content);
2333
2400
  }
2334
2401
  return { removed: true, notFound: false };
2335
2402
  }
2336
2403
 
2337
2404
  // src/lib/learning-hooks.ts
2338
- import fs15 from "fs";
2405
+ import fs16 from "fs";
2339
2406
  import path13 from "path";
2340
2407
  var SETTINGS_PATH2 = path13.join(".claude", "settings.json");
2341
2408
  var HOOK_CONFIGS = [
@@ -2356,17 +2423,17 @@ var HOOK_CONFIGS = [
2356
2423
  }
2357
2424
  ];
2358
2425
  function readSettings2() {
2359
- if (!fs15.existsSync(SETTINGS_PATH2)) return {};
2426
+ if (!fs16.existsSync(SETTINGS_PATH2)) return {};
2360
2427
  try {
2361
- return JSON.parse(fs15.readFileSync(SETTINGS_PATH2, "utf-8"));
2428
+ return JSON.parse(fs16.readFileSync(SETTINGS_PATH2, "utf-8"));
2362
2429
  } catch {
2363
2430
  return {};
2364
2431
  }
2365
2432
  }
2366
2433
  function writeSettings2(settings) {
2367
2434
  const dir = path13.dirname(SETTINGS_PATH2);
2368
- if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
2369
- fs15.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
2435
+ if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
2436
+ fs16.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
2370
2437
  }
2371
2438
  function hasLearningHook(matchers, command) {
2372
2439
  return matchers.some((entry) => entry.hooks?.some((h) => h.command === command));
@@ -2423,7 +2490,7 @@ function removeLearningHooks() {
2423
2490
 
2424
2491
  // src/lib/state.ts
2425
2492
  init_constants();
2426
- import fs16 from "fs";
2493
+ import fs17 from "fs";
2427
2494
  import path14 from "path";
2428
2495
  import { execSync as execSync6 } from "child_process";
2429
2496
  var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
@@ -2437,8 +2504,8 @@ function normalizeTargetAgent(value) {
2437
2504
  }
2438
2505
  function readState() {
2439
2506
  try {
2440
- if (!fs16.existsSync(STATE_FILE)) return null;
2441
- const raw = JSON.parse(fs16.readFileSync(STATE_FILE, "utf-8"));
2507
+ if (!fs17.existsSync(STATE_FILE)) return null;
2508
+ const raw = JSON.parse(fs17.readFileSync(STATE_FILE, "utf-8"));
2442
2509
  if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
2443
2510
  return raw;
2444
2511
  } catch {
@@ -2446,10 +2513,10 @@ function readState() {
2446
2513
  }
2447
2514
  }
2448
2515
  function writeState(state) {
2449
- if (!fs16.existsSync(CALIBER_DIR)) {
2450
- fs16.mkdirSync(CALIBER_DIR, { recursive: true });
2516
+ if (!fs17.existsSync(CALIBER_DIR)) {
2517
+ fs17.mkdirSync(CALIBER_DIR, { recursive: true });
2451
2518
  }
2452
- fs16.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
2519
+ fs17.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
2453
2520
  }
2454
2521
  function getCurrentHeadSha() {
2455
2522
  try {
@@ -3670,22 +3737,22 @@ function checkBonus(dir) {
3670
3737
 
3671
3738
  // src/scoring/dismissed.ts
3672
3739
  init_constants();
3673
- import fs17 from "fs";
3740
+ import fs18 from "fs";
3674
3741
  import path15 from "path";
3675
3742
  var DISMISSED_FILE = path15.join(CALIBER_DIR, "dismissed-checks.json");
3676
3743
  function readDismissedChecks() {
3677
3744
  try {
3678
- if (!fs17.existsSync(DISMISSED_FILE)) return [];
3679
- return JSON.parse(fs17.readFileSync(DISMISSED_FILE, "utf-8"));
3745
+ if (!fs18.existsSync(DISMISSED_FILE)) return [];
3746
+ return JSON.parse(fs18.readFileSync(DISMISSED_FILE, "utf-8"));
3680
3747
  } catch {
3681
3748
  return [];
3682
3749
  }
3683
3750
  }
3684
3751
  function writeDismissedChecks(checks) {
3685
- if (!fs17.existsSync(CALIBER_DIR)) {
3686
- fs17.mkdirSync(CALIBER_DIR, { recursive: true });
3752
+ if (!fs18.existsSync(CALIBER_DIR)) {
3753
+ fs18.mkdirSync(CALIBER_DIR, { recursive: true });
3687
3754
  }
3688
- fs17.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
3755
+ fs18.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
3689
3756
  }
3690
3757
  function getDismissedIds() {
3691
3758
  return new Set(readDismissedChecks().map((c) => c.id));
@@ -3876,7 +3943,7 @@ function displayScoreDelta(before, after) {
3876
3943
  import chalk4 from "chalk";
3877
3944
  import ora from "ora";
3878
3945
  import readline3 from "readline";
3879
- import fs18 from "fs";
3946
+ import fs19 from "fs";
3880
3947
  import path16 from "path";
3881
3948
 
3882
3949
  // src/mcp/search.ts
@@ -4229,7 +4296,7 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4229
4296
  }
4230
4297
  if (targetAgent.includes("cursor")) {
4231
4298
  const cursorDir = path16.join(dir, ".cursor");
4232
- if (!fs18.existsSync(cursorDir)) fs18.mkdirSync(cursorDir, { recursive: true });
4299
+ if (!fs19.existsSync(cursorDir)) fs19.mkdirSync(cursorDir, { recursive: true });
4233
4300
  writeMcpJson(path16.join(cursorDir, "mcp.json"), mcpServers);
4234
4301
  }
4235
4302
  return { installed: installedNames.length, names: installedNames };
@@ -4237,14 +4304,14 @@ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4237
4304
  function writeMcpJson(filePath, mcpServers) {
4238
4305
  let existing = {};
4239
4306
  try {
4240
- if (fs18.existsSync(filePath)) {
4241
- const parsed = JSON.parse(fs18.readFileSync(filePath, "utf-8"));
4307
+ if (fs19.existsSync(filePath)) {
4308
+ const parsed = JSON.parse(fs19.readFileSync(filePath, "utf-8"));
4242
4309
  if (parsed.mcpServers) existing = parsed.mcpServers;
4243
4310
  }
4244
4311
  } catch {
4245
4312
  }
4246
4313
  const merged = { ...existing, ...mcpServers };
4247
- fs18.writeFileSync(filePath, JSON.stringify({ mcpServers: merged }, null, 2) + "\n");
4314
+ fs19.writeFileSync(filePath, JSON.stringify({ mcpServers: merged }, null, 2) + "\n");
4248
4315
  }
4249
4316
  function getExistingMcpNames(fingerprint, targetAgent) {
4250
4317
  const names = [];
@@ -4859,8 +4926,8 @@ async function openReview(method, stagedFiles) {
4859
4926
  return;
4860
4927
  }
4861
4928
  const fileInfos = stagedFiles.map((file) => {
4862
- const proposed = fs19.readFileSync(file.proposedPath, "utf-8");
4863
- const current = file.currentPath ? fs19.readFileSync(file.currentPath, "utf-8") : "";
4929
+ const proposed = fs20.readFileSync(file.proposedPath, "utf-8");
4930
+ const current = file.currentPath ? fs20.readFileSync(file.currentPath, "utf-8") : "";
4864
4931
  const patch = createTwoFilesPatch(
4865
4932
  file.isNew ? "/dev/null" : file.relativePath,
4866
4933
  file.relativePath,
@@ -5043,7 +5110,7 @@ function printSetupSummary(setup) {
5043
5110
  };
5044
5111
  if (claude) {
5045
5112
  if (claude.claudeMd) {
5046
- const icon = fs19.existsSync("CLAUDE.md") ? chalk5.yellow("~") : chalk5.green("+");
5113
+ const icon = fs20.existsSync("CLAUDE.md") ? chalk5.yellow("~") : chalk5.green("+");
5047
5114
  const desc = getDescription("CLAUDE.md");
5048
5115
  console.log(` ${icon} ${chalk5.bold("CLAUDE.md")}`);
5049
5116
  if (desc) console.log(chalk5.dim(` ${desc}`));
@@ -5053,7 +5120,7 @@ function printSetupSummary(setup) {
5053
5120
  if (Array.isArray(skills) && skills.length > 0) {
5054
5121
  for (const skill of skills) {
5055
5122
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
5056
- const icon = fs19.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5123
+ const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5057
5124
  const desc = getDescription(skillPath);
5058
5125
  console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5059
5126
  console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
@@ -5064,7 +5131,7 @@ function printSetupSummary(setup) {
5064
5131
  const codex = setup.codex;
5065
5132
  if (codex) {
5066
5133
  if (codex.agentsMd) {
5067
- const icon = fs19.existsSync("AGENTS.md") ? chalk5.yellow("~") : chalk5.green("+");
5134
+ const icon = fs20.existsSync("AGENTS.md") ? chalk5.yellow("~") : chalk5.green("+");
5068
5135
  const desc = getDescription("AGENTS.md");
5069
5136
  console.log(` ${icon} ${chalk5.bold("AGENTS.md")}`);
5070
5137
  if (desc) console.log(chalk5.dim(` ${desc}`));
@@ -5074,7 +5141,7 @@ function printSetupSummary(setup) {
5074
5141
  if (Array.isArray(codexSkills) && codexSkills.length > 0) {
5075
5142
  for (const skill of codexSkills) {
5076
5143
  const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
5077
- const icon = fs19.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5144
+ const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5078
5145
  const desc = getDescription(skillPath);
5079
5146
  console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5080
5147
  console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
@@ -5084,7 +5151,7 @@ function printSetupSummary(setup) {
5084
5151
  }
5085
5152
  if (cursor) {
5086
5153
  if (cursor.cursorrules) {
5087
- const icon = fs19.existsSync(".cursorrules") ? chalk5.yellow("~") : chalk5.green("+");
5154
+ const icon = fs20.existsSync(".cursorrules") ? chalk5.yellow("~") : chalk5.green("+");
5088
5155
  const desc = getDescription(".cursorrules");
5089
5156
  console.log(` ${icon} ${chalk5.bold(".cursorrules")}`);
5090
5157
  if (desc) console.log(chalk5.dim(` ${desc}`));
@@ -5094,7 +5161,7 @@ function printSetupSummary(setup) {
5094
5161
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
5095
5162
  for (const skill of cursorSkills) {
5096
5163
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
5097
- const icon = fs19.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5164
+ const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
5098
5165
  const desc = getDescription(skillPath);
5099
5166
  console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5100
5167
  console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
@@ -5105,7 +5172,7 @@ function printSetupSummary(setup) {
5105
5172
  if (Array.isArray(rules) && rules.length > 0) {
5106
5173
  for (const rule of rules) {
5107
5174
  const rulePath = `.cursor/rules/${rule.filename}`;
5108
- const icon = fs19.existsSync(rulePath) ? chalk5.yellow("~") : chalk5.green("+");
5175
+ const icon = fs20.existsSync(rulePath) ? chalk5.yellow("~") : chalk5.green("+");
5109
5176
  const desc = getDescription(rulePath);
5110
5177
  console.log(` ${icon} ${chalk5.bold(rulePath)}`);
5111
5178
  if (desc) {
@@ -5118,7 +5185,7 @@ function printSetupSummary(setup) {
5118
5185
  }
5119
5186
  }
5120
5187
  }
5121
- if (!codex && !fs19.existsSync("AGENTS.md")) {
5188
+ if (!codex && !fs20.existsSync("AGENTS.md")) {
5122
5189
  console.log(` ${chalk5.green("+")} ${chalk5.bold("AGENTS.md")}`);
5123
5190
  console.log(chalk5.dim(" Cross-agent coordination file"));
5124
5191
  console.log("");
@@ -5133,21 +5200,12 @@ function printSetupSummary(setup) {
5133
5200
  console.log(` ${chalk5.green("+")} ${chalk5.dim("new")} ${chalk5.yellow("~")} ${chalk5.dim("modified")} ${chalk5.red("-")} ${chalk5.dim("removed")}`);
5134
5201
  console.log("");
5135
5202
  }
5136
- function buildSkillContent(skill) {
5137
- const frontmatter = `---
5138
- name: ${skill.name}
5139
- description: ${skill.description}
5140
- ---
5141
-
5142
- `;
5143
- return frontmatter + skill.content;
5144
- }
5145
5203
  function ensurePermissions() {
5146
5204
  const settingsPath = ".claude/settings.json";
5147
5205
  let settings = {};
5148
5206
  try {
5149
- if (fs19.existsSync(settingsPath)) {
5150
- settings = JSON.parse(fs19.readFileSync(settingsPath, "utf-8"));
5207
+ if (fs20.existsSync(settingsPath)) {
5208
+ settings = JSON.parse(fs20.readFileSync(settingsPath, "utf-8"));
5151
5209
  }
5152
5210
  } catch {
5153
5211
  }
@@ -5161,64 +5219,8 @@ function ensurePermissions() {
5161
5219
  "Bash(git *)"
5162
5220
  ];
5163
5221
  settings.permissions = permissions;
5164
- if (!fs19.existsSync(".claude")) fs19.mkdirSync(".claude", { recursive: true });
5165
- fs19.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5166
- }
5167
- function collectSetupFiles(setup) {
5168
- const files = [];
5169
- const claude = setup.claude;
5170
- const cursor = setup.cursor;
5171
- const codex = setup.codex;
5172
- if (claude) {
5173
- if (claude.claudeMd) files.push({ path: "CLAUDE.md", content: claude.claudeMd });
5174
- const skills = claude.skills;
5175
- if (Array.isArray(skills)) {
5176
- for (const skill of skills) {
5177
- files.push({ path: `.claude/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
5178
- }
5179
- }
5180
- }
5181
- if (codex) {
5182
- if (codex.agentsMd) files.push({ path: "AGENTS.md", content: codex.agentsMd });
5183
- const codexSkills = codex.skills;
5184
- if (Array.isArray(codexSkills)) {
5185
- for (const skill of codexSkills) {
5186
- files.push({ path: `.agents/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
5187
- }
5188
- }
5189
- }
5190
- if (cursor) {
5191
- if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
5192
- const cursorSkills = cursor.skills;
5193
- if (Array.isArray(cursorSkills)) {
5194
- for (const skill of cursorSkills) {
5195
- files.push({ path: `.cursor/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
5196
- }
5197
- }
5198
- const rules = cursor.rules;
5199
- if (Array.isArray(rules)) {
5200
- for (const rule of rules) {
5201
- files.push({ path: `.cursor/rules/${rule.filename}`, content: rule.content });
5202
- }
5203
- }
5204
- }
5205
- const hasCodexAgentsMd = codex && codex.agentsMd;
5206
- if (!fs19.existsSync("AGENTS.md") && !hasCodexAgentsMd) {
5207
- const agentRefs = [];
5208
- if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
5209
- if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
5210
- if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
5211
- files.push({
5212
- path: "AGENTS.md",
5213
- content: `# AGENTS.md
5214
-
5215
- This project uses AI coding agents configured by [Caliber](https://github.com/rely-ai-org/caliber).
5216
-
5217
- ${agentRefs.join(" ")}
5218
- `
5219
- });
5220
- }
5221
- return files;
5222
+ if (!fs20.existsSync(".claude")) fs20.mkdirSync(".claude", { recursive: true });
5223
+ fs20.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5222
5224
  }
5223
5225
 
5224
5226
  // src/commands/undo.ts
@@ -5254,7 +5256,7 @@ function undoCommand() {
5254
5256
 
5255
5257
  // src/commands/status.ts
5256
5258
  import chalk7 from "chalk";
5257
- import fs20 from "fs";
5259
+ import fs21 from "fs";
5258
5260
  async function statusCommand(options) {
5259
5261
  const config = loadConfig();
5260
5262
  const manifest = readManifest();
@@ -5280,7 +5282,7 @@ async function statusCommand(options) {
5280
5282
  }
5281
5283
  console.log(` Files managed: ${chalk7.cyan(manifest.entries.length.toString())}`);
5282
5284
  for (const entry of manifest.entries) {
5283
- const exists = fs20.existsSync(entry.path);
5285
+ const exists = fs21.existsSync(entry.path);
5284
5286
  const icon = exists ? chalk7.green("\u2713") : chalk7.red("\u2717");
5285
5287
  console.log(` ${icon} ${entry.path} (${entry.action})`);
5286
5288
  }
@@ -5290,11 +5292,11 @@ async function statusCommand(options) {
5290
5292
  // src/commands/regenerate.ts
5291
5293
  import chalk8 from "chalk";
5292
5294
  import ora4 from "ora";
5293
- import confirm from "@inquirer/confirm";
5295
+ import select3 from "@inquirer/select";
5294
5296
  async function regenerateCommand(options) {
5295
5297
  const config = loadConfig();
5296
5298
  if (!config) {
5297
- console.log(chalk8.red("No LLM provider configured. Run ") + chalk8.hex("#83D1EB")("caliber config") + chalk8.red(" (e.g. choose Cursor) or set ANTHROPIC_API_KEY."));
5299
+ console.log(chalk8.red("No LLM provider configured. Run ") + chalk8.hex("#83D1EB")("caliber config") + chalk8.red(" first."));
5298
5300
  throw new Error("__exit__");
5299
5301
  }
5300
5302
  const manifest = readManifest();
@@ -5302,16 +5304,19 @@ async function regenerateCommand(options) {
5302
5304
  console.log(chalk8.yellow("No existing setup found. Run ") + chalk8.hex("#83D1EB")("caliber onboard") + chalk8.yellow(" first."));
5303
5305
  throw new Error("__exit__");
5304
5306
  }
5305
- const spinner = ora4("Re-analyzing project...").start();
5307
+ const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
5308
+ const spinner = ora4("Analyzing project...").start();
5306
5309
  const fingerprint = collectFingerprint(process.cwd());
5307
- spinner.succeed("Project re-analyzed");
5310
+ await enrichFingerprintWithLLM(fingerprint, process.cwd());
5311
+ spinner.succeed("Project analyzed");
5312
+ const baselineScore = computeLocalScore(process.cwd(), targetAgent);
5313
+ displayScoreSummary(baselineScore);
5308
5314
  const genSpinner = ora4("Regenerating setup...").start();
5309
- const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES);
5315
+ const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
5310
5316
  genMessages.start();
5311
5317
  let generatedSetup = null;
5312
5318
  try {
5313
- const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
5314
- const result2 = await generateSetup(
5319
+ const result = await generateSetup(
5315
5320
  fingerprint,
5316
5321
  targetAgent,
5317
5322
  void 0,
@@ -5328,7 +5333,7 @@ async function regenerateCommand(options) {
5328
5333
  }
5329
5334
  }
5330
5335
  );
5331
- if (!generatedSetup) generatedSetup = result2.setup;
5336
+ if (!generatedSetup) generatedSetup = result.setup;
5332
5337
  } catch (err) {
5333
5338
  genMessages.stop();
5334
5339
  const msg = err instanceof Error ? err.message : "Unknown error";
@@ -5341,23 +5346,81 @@ async function regenerateCommand(options) {
5341
5346
  throw new Error("__exit__");
5342
5347
  }
5343
5348
  genSpinner.succeed("Setup regenerated");
5349
+ const setupFiles = collectSetupFiles(generatedSetup);
5350
+ const staged = stageFiles(setupFiles, process.cwd());
5351
+ const totalChanges = staged.newFiles + staged.modifiedFiles;
5352
+ console.log(chalk8.dim(`
5353
+ ${chalk8.green(`${staged.newFiles} new`)} / ${chalk8.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
5354
+ `));
5355
+ if (totalChanges === 0) {
5356
+ console.log(chalk8.dim(" No changes needed \u2014 your configs are already up to date.\n"));
5357
+ cleanupStaging();
5358
+ return;
5359
+ }
5344
5360
  if (options.dryRun) {
5345
- console.log(chalk8.yellow("\n[Dry run] Would write:"));
5346
- console.log(JSON.stringify(generatedSetup, null, 2));
5361
+ console.log(chalk8.yellow("[Dry run] Would write:"));
5362
+ for (const f of staged.stagedFiles) {
5363
+ console.log(` ${f.isNew ? chalk8.green("+") : chalk8.yellow("~")} ${f.relativePath}`);
5364
+ }
5365
+ cleanupStaging();
5347
5366
  return;
5348
5367
  }
5349
- const shouldApply = await confirm({ message: "Apply regenerated setup?", default: true });
5350
- if (!shouldApply) {
5351
- console.log(chalk8.dim("Regeneration cancelled."));
5368
+ const action = await select3({
5369
+ message: "Apply regenerated setup?",
5370
+ choices: [
5371
+ { name: "Accept and apply", value: "accept" },
5372
+ { name: "Decline", value: "decline" }
5373
+ ]
5374
+ });
5375
+ cleanupStaging();
5376
+ if (action === "decline") {
5377
+ console.log(chalk8.dim("Regeneration cancelled. No files were modified."));
5352
5378
  return;
5353
5379
  }
5354
- const writeSpinner = ora4("Updating config files...").start();
5355
- const result = writeSetup(generatedSetup);
5356
- writeSpinner.succeed("Config files updated");
5357
- for (const file of result.written) {
5358
- console.log(` ${chalk8.green("\u2713")} ${file}`);
5380
+ const writeSpinner = ora4("Writing config files...").start();
5381
+ try {
5382
+ const result = writeSetup(generatedSetup);
5383
+ writeSpinner.succeed("Config files written");
5384
+ for (const file of result.written) {
5385
+ console.log(` ${chalk8.green("\u2713")} ${file}`);
5386
+ }
5387
+ if (result.deleted.length > 0) {
5388
+ for (const file of result.deleted) {
5389
+ console.log(` ${chalk8.red("\u2717")} ${file}`);
5390
+ }
5391
+ }
5392
+ if (result.backupDir) {
5393
+ console.log(chalk8.dim(`
5394
+ Backups saved to ${result.backupDir}`));
5395
+ }
5396
+ } catch (err) {
5397
+ writeSpinner.fail("Failed to write files");
5398
+ console.error(chalk8.red(err instanceof Error ? err.message : "Unknown error"));
5399
+ throw new Error("__exit__");
5359
5400
  }
5360
- console.log("");
5401
+ const sha = getCurrentHeadSha();
5402
+ writeState({
5403
+ lastRefreshSha: sha ?? "",
5404
+ lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
5405
+ targetAgent
5406
+ });
5407
+ const afterScore = computeLocalScore(process.cwd(), targetAgent);
5408
+ if (afterScore.score < baselineScore.score) {
5409
+ console.log("");
5410
+ console.log(chalk8.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
5411
+ try {
5412
+ const { restored, removed } = undoSetup();
5413
+ if (restored.length > 0 || removed.length > 0) {
5414
+ console.log(chalk8.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
5415
+ }
5416
+ } catch {
5417
+ }
5418
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to override.\n"));
5419
+ return;
5420
+ }
5421
+ displayScoreDelta(baselineScore, afterScore);
5422
+ console.log(chalk8.bold.green(" Regeneration complete!"));
5423
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber undo") + chalk8.dim(" to revert changes.\n"));
5361
5424
  }
5362
5425
 
5363
5426
  // src/commands/recommend.ts
@@ -5367,13 +5430,13 @@ import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5,
5367
5430
  import { join as join8, dirname as dirname2 } from "path";
5368
5431
 
5369
5432
  // src/scanner/index.ts
5370
- import fs21 from "fs";
5433
+ import fs22 from "fs";
5371
5434
  import path17 from "path";
5372
5435
  import crypto2 from "crypto";
5373
5436
  function scanLocalState(dir) {
5374
5437
  const items = [];
5375
5438
  const claudeMdPath = path17.join(dir, "CLAUDE.md");
5376
- if (fs21.existsSync(claudeMdPath)) {
5439
+ if (fs22.existsSync(claudeMdPath)) {
5377
5440
  items.push({
5378
5441
  type: "rule",
5379
5442
  platform: "claude",
@@ -5383,8 +5446,8 @@ function scanLocalState(dir) {
5383
5446
  });
5384
5447
  }
5385
5448
  const skillsDir = path17.join(dir, ".claude", "skills");
5386
- if (fs21.existsSync(skillsDir)) {
5387
- for (const file of fs21.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5449
+ if (fs22.existsSync(skillsDir)) {
5450
+ for (const file of fs22.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5388
5451
  const filePath = path17.join(skillsDir, file);
5389
5452
  items.push({
5390
5453
  type: "skill",
@@ -5396,9 +5459,9 @@ function scanLocalState(dir) {
5396
5459
  }
5397
5460
  }
5398
5461
  const mcpJsonPath = path17.join(dir, ".mcp.json");
5399
- if (fs21.existsSync(mcpJsonPath)) {
5462
+ if (fs22.existsSync(mcpJsonPath)) {
5400
5463
  try {
5401
- const mcpJson = JSON.parse(fs21.readFileSync(mcpJsonPath, "utf-8"));
5464
+ const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
5402
5465
  if (mcpJson.mcpServers) {
5403
5466
  for (const name of Object.keys(mcpJson.mcpServers)) {
5404
5467
  items.push({
@@ -5414,7 +5477,7 @@ function scanLocalState(dir) {
5414
5477
  }
5415
5478
  }
5416
5479
  const agentsMdPath = path17.join(dir, "AGENTS.md");
5417
- if (fs21.existsSync(agentsMdPath)) {
5480
+ if (fs22.existsSync(agentsMdPath)) {
5418
5481
  items.push({
5419
5482
  type: "rule",
5420
5483
  platform: "codex",
@@ -5424,11 +5487,11 @@ function scanLocalState(dir) {
5424
5487
  });
5425
5488
  }
5426
5489
  const codexSkillsDir = path17.join(dir, ".agents", "skills");
5427
- if (fs21.existsSync(codexSkillsDir)) {
5490
+ if (fs22.existsSync(codexSkillsDir)) {
5428
5491
  try {
5429
- for (const name of fs21.readdirSync(codexSkillsDir)) {
5492
+ for (const name of fs22.readdirSync(codexSkillsDir)) {
5430
5493
  const skillFile = path17.join(codexSkillsDir, name, "SKILL.md");
5431
- if (fs21.existsSync(skillFile)) {
5494
+ if (fs22.existsSync(skillFile)) {
5432
5495
  items.push({
5433
5496
  type: "skill",
5434
5497
  platform: "codex",
@@ -5442,7 +5505,7 @@ function scanLocalState(dir) {
5442
5505
  }
5443
5506
  }
5444
5507
  const cursorrulesPath = path17.join(dir, ".cursorrules");
5445
- if (fs21.existsSync(cursorrulesPath)) {
5508
+ if (fs22.existsSync(cursorrulesPath)) {
5446
5509
  items.push({
5447
5510
  type: "rule",
5448
5511
  platform: "cursor",
@@ -5452,8 +5515,8 @@ function scanLocalState(dir) {
5452
5515
  });
5453
5516
  }
5454
5517
  const cursorRulesDir = path17.join(dir, ".cursor", "rules");
5455
- if (fs21.existsSync(cursorRulesDir)) {
5456
- for (const file of fs21.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5518
+ if (fs22.existsSync(cursorRulesDir)) {
5519
+ for (const file of fs22.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5457
5520
  const filePath = path17.join(cursorRulesDir, file);
5458
5521
  items.push({
5459
5522
  type: "rule",
@@ -5465,11 +5528,11 @@ function scanLocalState(dir) {
5465
5528
  }
5466
5529
  }
5467
5530
  const cursorSkillsDir = path17.join(dir, ".cursor", "skills");
5468
- if (fs21.existsSync(cursorSkillsDir)) {
5531
+ if (fs22.existsSync(cursorSkillsDir)) {
5469
5532
  try {
5470
- for (const name of fs21.readdirSync(cursorSkillsDir)) {
5533
+ for (const name of fs22.readdirSync(cursorSkillsDir)) {
5471
5534
  const skillFile = path17.join(cursorSkillsDir, name, "SKILL.md");
5472
- if (fs21.existsSync(skillFile)) {
5535
+ if (fs22.existsSync(skillFile)) {
5473
5536
  items.push({
5474
5537
  type: "skill",
5475
5538
  platform: "cursor",
@@ -5483,9 +5546,9 @@ function scanLocalState(dir) {
5483
5546
  }
5484
5547
  }
5485
5548
  const cursorMcpPath = path17.join(dir, ".cursor", "mcp.json");
5486
- if (fs21.existsSync(cursorMcpPath)) {
5549
+ if (fs22.existsSync(cursorMcpPath)) {
5487
5550
  try {
5488
- const mcpJson = JSON.parse(fs21.readFileSync(cursorMcpPath, "utf-8"));
5551
+ const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
5489
5552
  if (mcpJson.mcpServers) {
5490
5553
  for (const name of Object.keys(mcpJson.mcpServers)) {
5491
5554
  items.push({
@@ -5503,7 +5566,7 @@ function scanLocalState(dir) {
5503
5566
  return items;
5504
5567
  }
5505
5568
  function hashFile(filePath) {
5506
- const text = fs21.readFileSync(filePath, "utf-8");
5569
+ const text = fs22.readFileSync(filePath, "utf-8");
5507
5570
  return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
5508
5571
  }
5509
5572
  function hashJson(obj) {
@@ -6078,13 +6141,13 @@ async function scoreCommand(options) {
6078
6141
  } else if (result.score < 70) {
6079
6142
  console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to improve your setup."));
6080
6143
  } else {
6081
- console.log(chalk10.green(" Looking good!") + chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber update") + chalk10.gray(" to keep it fresh."));
6144
+ console.log(chalk10.green(" Looking good!") + chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber regenerate") + chalk10.gray(" to rebuild from scratch."));
6082
6145
  }
6083
6146
  console.log("");
6084
6147
  }
6085
6148
 
6086
6149
  // src/commands/refresh.ts
6087
- import fs23 from "fs";
6150
+ import fs24 from "fs";
6088
6151
  import path19 from "path";
6089
6152
  import chalk11 from "chalk";
6090
6153
  import ora6 from "ora";
@@ -6162,37 +6225,37 @@ function collectDiff(lastSha) {
6162
6225
  }
6163
6226
 
6164
6227
  // src/writers/refresh.ts
6165
- import fs22 from "fs";
6228
+ import fs23 from "fs";
6166
6229
  import path18 from "path";
6167
6230
  function writeRefreshDocs(docs) {
6168
6231
  const written = [];
6169
6232
  if (docs.claudeMd) {
6170
- fs22.writeFileSync("CLAUDE.md", docs.claudeMd);
6233
+ fs23.writeFileSync("CLAUDE.md", docs.claudeMd);
6171
6234
  written.push("CLAUDE.md");
6172
6235
  }
6173
6236
  if (docs.readmeMd) {
6174
- fs22.writeFileSync("README.md", docs.readmeMd);
6237
+ fs23.writeFileSync("README.md", docs.readmeMd);
6175
6238
  written.push("README.md");
6176
6239
  }
6177
6240
  if (docs.cursorrules) {
6178
- fs22.writeFileSync(".cursorrules", docs.cursorrules);
6241
+ fs23.writeFileSync(".cursorrules", docs.cursorrules);
6179
6242
  written.push(".cursorrules");
6180
6243
  }
6181
6244
  if (docs.cursorRules) {
6182
6245
  const rulesDir = path18.join(".cursor", "rules");
6183
- if (!fs22.existsSync(rulesDir)) fs22.mkdirSync(rulesDir, { recursive: true });
6246
+ if (!fs23.existsSync(rulesDir)) fs23.mkdirSync(rulesDir, { recursive: true });
6184
6247
  for (const rule of docs.cursorRules) {
6185
6248
  const filePath = path18.join(rulesDir, rule.filename);
6186
- fs22.writeFileSync(filePath, rule.content);
6249
+ fs23.writeFileSync(filePath, rule.content);
6187
6250
  written.push(filePath);
6188
6251
  }
6189
6252
  }
6190
6253
  if (docs.claudeSkills) {
6191
6254
  const skillsDir = path18.join(".claude", "skills");
6192
- if (!fs22.existsSync(skillsDir)) fs22.mkdirSync(skillsDir, { recursive: true });
6255
+ if (!fs23.existsSync(skillsDir)) fs23.mkdirSync(skillsDir, { recursive: true });
6193
6256
  for (const skill of docs.claudeSkills) {
6194
6257
  const filePath = path18.join(skillsDir, skill.filename);
6195
- fs22.writeFileSync(filePath, skill.content);
6258
+ fs23.writeFileSync(filePath, skill.content);
6196
6259
  written.push(filePath);
6197
6260
  }
6198
6261
  }
@@ -6269,11 +6332,11 @@ function log(quiet, ...args) {
6269
6332
  function discoverGitRepos(parentDir) {
6270
6333
  const repos = [];
6271
6334
  try {
6272
- const entries = fs23.readdirSync(parentDir, { withFileTypes: true });
6335
+ const entries = fs24.readdirSync(parentDir, { withFileTypes: true });
6273
6336
  for (const entry of entries) {
6274
6337
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
6275
6338
  const childPath = path19.join(parentDir, entry.name);
6276
- if (fs23.existsSync(path19.join(childPath, ".git"))) {
6339
+ if (fs24.existsSync(path19.join(childPath, ".git"))) {
6277
6340
  repos.push(childPath);
6278
6341
  }
6279
6342
  }
@@ -6620,7 +6683,7 @@ function readStdin() {
6620
6683
 
6621
6684
  // src/learner/storage.ts
6622
6685
  init_constants();
6623
- import fs24 from "fs";
6686
+ import fs25 from "fs";
6624
6687
  import path20 from "path";
6625
6688
  var MAX_RESPONSE_LENGTH = 2e3;
6626
6689
  var DEFAULT_STATE = {
@@ -6629,8 +6692,8 @@ var DEFAULT_STATE = {
6629
6692
  lastAnalysisTimestamp: null
6630
6693
  };
6631
6694
  function ensureLearningDir() {
6632
- if (!fs24.existsSync(LEARNING_DIR)) {
6633
- fs24.mkdirSync(LEARNING_DIR, { recursive: true });
6695
+ if (!fs25.existsSync(LEARNING_DIR)) {
6696
+ fs25.mkdirSync(LEARNING_DIR, { recursive: true });
6634
6697
  }
6635
6698
  }
6636
6699
  function sessionFilePath() {
@@ -6648,49 +6711,49 @@ function appendEvent(event) {
6648
6711
  ensureLearningDir();
6649
6712
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
6650
6713
  const filePath = sessionFilePath();
6651
- fs24.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6714
+ fs25.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6652
6715
  const count = getEventCount();
6653
6716
  if (count > LEARNING_MAX_EVENTS) {
6654
- const lines = fs24.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6717
+ const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6655
6718
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
6656
- fs24.writeFileSync(filePath, kept.join("\n") + "\n");
6719
+ fs25.writeFileSync(filePath, kept.join("\n") + "\n");
6657
6720
  }
6658
6721
  }
6659
6722
  function readAllEvents() {
6660
6723
  const filePath = sessionFilePath();
6661
- if (!fs24.existsSync(filePath)) return [];
6662
- const lines = fs24.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6724
+ if (!fs25.existsSync(filePath)) return [];
6725
+ const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6663
6726
  return lines.map((line) => JSON.parse(line));
6664
6727
  }
6665
6728
  function getEventCount() {
6666
6729
  const filePath = sessionFilePath();
6667
- if (!fs24.existsSync(filePath)) return 0;
6668
- const content = fs24.readFileSync(filePath, "utf-8");
6730
+ if (!fs25.existsSync(filePath)) return 0;
6731
+ const content = fs25.readFileSync(filePath, "utf-8");
6669
6732
  return content.split("\n").filter(Boolean).length;
6670
6733
  }
6671
6734
  function clearSession() {
6672
6735
  const filePath = sessionFilePath();
6673
- if (fs24.existsSync(filePath)) fs24.unlinkSync(filePath);
6736
+ if (fs25.existsSync(filePath)) fs25.unlinkSync(filePath);
6674
6737
  }
6675
6738
  function readState2() {
6676
6739
  const filePath = stateFilePath();
6677
- if (!fs24.existsSync(filePath)) return { ...DEFAULT_STATE };
6740
+ if (!fs25.existsSync(filePath)) return { ...DEFAULT_STATE };
6678
6741
  try {
6679
- return JSON.parse(fs24.readFileSync(filePath, "utf-8"));
6742
+ return JSON.parse(fs25.readFileSync(filePath, "utf-8"));
6680
6743
  } catch {
6681
6744
  return { ...DEFAULT_STATE };
6682
6745
  }
6683
6746
  }
6684
6747
  function writeState2(state) {
6685
6748
  ensureLearningDir();
6686
- fs24.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6749
+ fs25.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6687
6750
  }
6688
6751
  function resetState() {
6689
6752
  writeState2({ ...DEFAULT_STATE });
6690
6753
  }
6691
6754
 
6692
6755
  // src/learner/writer.ts
6693
- import fs25 from "fs";
6756
+ import fs26 from "fs";
6694
6757
  import path21 from "path";
6695
6758
  var LEARNED_START = "<!-- caliber:learned -->";
6696
6759
  var LEARNED_END = "<!-- /caliber:learned -->";
@@ -6711,8 +6774,8 @@ function writeLearnedContent(update) {
6711
6774
  function writeLearnedSection(content) {
6712
6775
  const claudeMdPath = "CLAUDE.md";
6713
6776
  let existing = "";
6714
- if (fs25.existsSync(claudeMdPath)) {
6715
- existing = fs25.readFileSync(claudeMdPath, "utf-8");
6777
+ if (fs26.existsSync(claudeMdPath)) {
6778
+ existing = fs26.readFileSync(claudeMdPath, "utf-8");
6716
6779
  }
6717
6780
  const section = `${LEARNED_START}
6718
6781
  ${content}
@@ -6726,15 +6789,15 @@ ${LEARNED_END}`;
6726
6789
  const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
6727
6790
  updated = existing + separator + "\n" + section + "\n";
6728
6791
  }
6729
- fs25.writeFileSync(claudeMdPath, updated);
6792
+ fs26.writeFileSync(claudeMdPath, updated);
6730
6793
  }
6731
6794
  function writeLearnedSkill(skill) {
6732
6795
  const skillDir = path21.join(".claude", "skills", skill.name);
6733
- if (!fs25.existsSync(skillDir)) fs25.mkdirSync(skillDir, { recursive: true });
6796
+ if (!fs26.existsSync(skillDir)) fs26.mkdirSync(skillDir, { recursive: true });
6734
6797
  const skillPath = path21.join(skillDir, "SKILL.md");
6735
- if (!skill.isNew && fs25.existsSync(skillPath)) {
6736
- const existing = fs25.readFileSync(skillPath, "utf-8");
6737
- fs25.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6798
+ if (!skill.isNew && fs26.existsSync(skillPath)) {
6799
+ const existing = fs26.readFileSync(skillPath, "utf-8");
6800
+ fs26.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6738
6801
  } else {
6739
6802
  const frontmatter = [
6740
6803
  "---",
@@ -6743,14 +6806,14 @@ function writeLearnedSkill(skill) {
6743
6806
  "---",
6744
6807
  ""
6745
6808
  ].join("\n");
6746
- fs25.writeFileSync(skillPath, frontmatter + skill.content);
6809
+ fs26.writeFileSync(skillPath, frontmatter + skill.content);
6747
6810
  }
6748
6811
  return skillPath;
6749
6812
  }
6750
6813
  function readLearnedSection() {
6751
6814
  const claudeMdPath = "CLAUDE.md";
6752
- if (!fs25.existsSync(claudeMdPath)) return null;
6753
- const content = fs25.readFileSync(claudeMdPath, "utf-8");
6815
+ if (!fs26.existsSync(claudeMdPath)) return null;
6816
+ const content = fs26.readFileSync(claudeMdPath, "utf-8");
6754
6817
  const startIdx = content.indexOf(LEARNED_START);
6755
6818
  const endIdx = content.indexOf(LEARNED_END);
6756
6819
  if (startIdx === -1 || endIdx === -1) return null;
@@ -6936,7 +6999,7 @@ Learned items in CLAUDE.md: ${chalk14.cyan(String(lineCount))}`);
6936
6999
  // src/cli.ts
6937
7000
  var __dirname = path22.dirname(fileURLToPath(import.meta.url));
6938
7001
  var pkg = JSON.parse(
6939
- fs26.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
7002
+ fs27.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
6940
7003
  );
6941
7004
  var program = new Command();
6942
7005
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -6955,7 +7018,7 @@ function parseAgentOption(value) {
6955
7018
  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(initCommand);
6956
7019
  program.command("undo").description("Revert all config changes made by Caliber").action(undoCommand);
6957
7020
  program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(statusCommand);
6958
- program.command("regenerate").alias("regen").alias("re").alias("update").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(regenerateCommand);
7021
+ program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(regenerateCommand);
6959
7022
  program.command("config").description("Configure LLM provider, API key, and model").action(configCommand);
6960
7023
  program.command("recommend").description("Discover and install skill recommendations").option("--generate", "Force fresh recommendation search").action(recommendCommand);
6961
7024
  program.command("score").description("Score your current agent config setup (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).action(scoreCommand);
@@ -6969,22 +7032,22 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
6969
7032
  learn.command("status").description("Show learning system status").action(learnStatusCommand);
6970
7033
 
6971
7034
  // src/utils/version-check.ts
6972
- import fs27 from "fs";
7035
+ import fs28 from "fs";
6973
7036
  import path23 from "path";
6974
7037
  import { fileURLToPath as fileURLToPath2 } from "url";
6975
7038
  import { execSync as execSync9 } from "child_process";
6976
7039
  import chalk15 from "chalk";
6977
7040
  import ora7 from "ora";
6978
- import confirm2 from "@inquirer/confirm";
7041
+ import confirm from "@inquirer/confirm";
6979
7042
  var __dirname_vc = path23.dirname(fileURLToPath2(import.meta.url));
6980
7043
  var pkg2 = JSON.parse(
6981
- fs27.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
7044
+ fs28.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
6982
7045
  );
6983
7046
  function getInstalledVersion() {
6984
7047
  try {
6985
7048
  const globalRoot = execSync9("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
6986
7049
  const pkgPath = path23.join(globalRoot, "@rely-ai", "caliber", "package.json");
6987
- return JSON.parse(fs27.readFileSync(pkgPath, "utf-8")).version;
7050
+ return JSON.parse(fs28.readFileSync(pkgPath, "utf-8")).version;
6988
7051
  } catch {
6989
7052
  return null;
6990
7053
  }
@@ -7020,7 +7083,7 @@ Run ${chalk15.bold("npm install -g @rely-ai/caliber")} to upgrade.
7020
7083
  chalk15.yellow(`
7021
7084
  Update available: ${current} -> ${latest}`)
7022
7085
  );
7023
- const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
7086
+ const shouldUpdate = await confirm({ message: "Would you like to update now? (Y/n)", default: true });
7024
7087
  if (!shouldUpdate) {
7025
7088
  console.log();
7026
7089
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
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": {