@caliber-ai/cli 0.14.0 → 0.14.1

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.
package/dist/bin.js CHANGED
@@ -1185,20 +1185,8 @@ function writeClaudeConfig(config) {
1185
1185
  const written = [];
1186
1186
  fs9.writeFileSync("CLAUDE.md", config.claudeMd);
1187
1187
  written.push("CLAUDE.md");
1188
- const claudeDir = ".claude";
1189
- if (!fs9.existsSync(claudeDir)) fs9.mkdirSync(claudeDir, { recursive: true });
1190
- fs9.writeFileSync(
1191
- path10.join(claudeDir, "settings.json"),
1192
- JSON.stringify(config.settings, null, 2)
1193
- );
1194
- written.push(path10.join(claudeDir, "settings.json"));
1195
- fs9.writeFileSync(
1196
- path10.join(claudeDir, "settings.local.json"),
1197
- JSON.stringify(config.settingsLocal, null, 2)
1198
- );
1199
- written.push(path10.join(claudeDir, "settings.local.json"));
1200
1188
  if (config.skills?.length) {
1201
- const skillsDir = path10.join(claudeDir, "skills");
1189
+ const skillsDir = path10.join(".claude", "skills");
1202
1190
  if (!fs9.existsSync(skillsDir)) fs9.mkdirSync(skillsDir, { recursive: true });
1203
1191
  for (const skill of config.skills) {
1204
1192
  const filename = `${skill.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}.md`;
@@ -1212,9 +1200,7 @@ function writeClaudeConfig(config) {
1212
1200
  try {
1213
1201
  if (fs9.existsSync(".mcp.json")) {
1214
1202
  const existing = JSON.parse(fs9.readFileSync(".mcp.json", "utf-8"));
1215
- if (existing.mcpServers) {
1216
- existingServers = existing.mcpServers;
1217
- }
1203
+ if (existing.mcpServers) existingServers = existing.mcpServers;
1218
1204
  }
1219
1205
  } catch {
1220
1206
  }
@@ -1319,7 +1305,11 @@ function fileChecksum(filePath) {
1319
1305
  // src/writers/index.ts
1320
1306
  function writeSetup(setup) {
1321
1307
  const filesToWrite = getFilesToWrite(setup);
1322
- const existingFiles = filesToWrite.filter((f) => fs13.existsSync(f));
1308
+ const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs13.existsSync(f));
1309
+ const existingFiles = [
1310
+ ...filesToWrite.filter((f) => fs13.existsSync(f)),
1311
+ ...filesToDelete
1312
+ ];
1323
1313
  const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
1324
1314
  const written = [];
1325
1315
  if ((setup.targetAgent === "claude" || setup.targetAgent === "both") && setup.claude) {
@@ -1328,15 +1318,28 @@ function writeSetup(setup) {
1328
1318
  if ((setup.targetAgent === "cursor" || setup.targetAgent === "both") && setup.cursor) {
1329
1319
  written.push(...writeCursorConfig(setup.cursor));
1330
1320
  }
1321
+ const deleted = [];
1322
+ for (const filePath of filesToDelete) {
1323
+ fs13.unlinkSync(filePath);
1324
+ deleted.push(filePath);
1325
+ }
1331
1326
  ensureGitignore();
1332
- const entries = written.map((file) => ({
1333
- path: file,
1334
- action: existingFiles.includes(file) ? "modified" : "created",
1335
- checksum: fileChecksum(file),
1336
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1337
- }));
1327
+ const entries = [
1328
+ ...written.map((file) => ({
1329
+ path: file,
1330
+ action: existingFiles.includes(file) ? "modified" : "created",
1331
+ checksum: fileChecksum(file),
1332
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1333
+ })),
1334
+ ...deleted.map((file) => ({
1335
+ path: file,
1336
+ action: "deleted",
1337
+ checksum: "",
1338
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1339
+ }))
1340
+ ];
1338
1341
  writeManifest({ version: 1, backupDir, entries });
1339
- return { written, backupDir };
1342
+ return { written, deleted, backupDir };
1340
1343
  }
1341
1344
  function undoSetup() {
1342
1345
  const manifest = readManifest();
@@ -1351,7 +1354,7 @@ function undoSetup() {
1351
1354
  fs13.unlinkSync(entry.path);
1352
1355
  removed.push(entry.path);
1353
1356
  }
1354
- } else if (entry.action === "modified" && manifest.backupDir) {
1357
+ } else if ((entry.action === "modified" || entry.action === "deleted") && manifest.backupDir) {
1355
1358
  if (restoreBackup(manifest.backupDir, entry.path)) {
1356
1359
  restored.push(entry.path);
1357
1360
  }
@@ -1366,7 +1369,7 @@ function undoSetup() {
1366
1369
  function getFilesToWrite(setup) {
1367
1370
  const files = [];
1368
1371
  if ((setup.targetAgent === "claude" || setup.targetAgent === "both") && setup.claude) {
1369
- files.push("CLAUDE.md", ".claude/settings.json", ".claude/settings.local.json");
1372
+ files.push("CLAUDE.md");
1370
1373
  if (setup.claude.mcpServers) files.push(".mcp.json");
1371
1374
  if (setup.claude.skills) {
1372
1375
  for (const s of setup.claude.skills) {
@@ -1582,10 +1585,10 @@ async function initCommand(options) {
1582
1585
  `));
1583
1586
  console.log(chalk3.dim(" Configure your coding agent environment\n"));
1584
1587
  console.log(chalk3.bold(" What is Caliber?\n"));
1585
- console.log(chalk3.dim(" Caliber analyzes your project and generates optimized configurations"));
1586
- console.log(chalk3.dim(" for AI coding agents (Claude Code, Cursor). It creates CLAUDE.md,"));
1587
- console.log(chalk3.dim(" .cursorrules, skills, permissions, and MCP servers tailored to your"));
1588
- console.log(chalk3.dim(" codebase \u2014 so your AI agent understands your project from day one.\n"));
1588
+ console.log(chalk3.dim(" Caliber audits your AI agent configurations and suggests targeted"));
1589
+ console.log(chalk3.dim(" improvements. It analyzes CLAUDE.md, .cursorrules, skills, and MCP"));
1590
+ console.log(chalk3.dim(" servers against your actual codebase \u2014 keeping what works, fixing"));
1591
+ console.log(chalk3.dim(" what's stale, and adding what's missing.\n"));
1589
1592
  console.log(chalk3.bold(" How it works:\n"));
1590
1593
  console.log(chalk3.dim(" 1. Scan Analyze your code, dependencies, and file structure"));
1591
1594
  console.log(chalk3.dim(" 2. Match Detect existing configs and check for teammate setups"));
@@ -1704,9 +1707,9 @@ async function initCommand(options) {
1704
1707
  if (isEmpty) {
1705
1708
  fingerprint.description = await promptInput("What will you build in this project?");
1706
1709
  }
1707
- console.log(chalk3.hex("#6366f1").bold(" Step 4/6 \u2014 Planning a better setup\n"));
1708
- console.log(chalk3.dim(" AI is building CLAUDE.md, permissions, skills, and rules based on"));
1709
- console.log(chalk3.dim(" your project's stack and conventions.\n"));
1710
+ console.log(chalk3.hex("#6366f1").bold(" Step 4/6 \u2014 Auditing your configs\n"));
1711
+ console.log(chalk3.dim(" AI is auditing your CLAUDE.md, skills, and rules against your"));
1712
+ console.log(chalk3.dim(" project's actual codebase and conventions.\n"));
1710
1713
  console.log(chalk3.dim(" This usually takes 1\u20133 minutes on first run.\n"));
1711
1714
  let generatedSetup = null;
1712
1715
  let rawOutput;
@@ -1795,11 +1798,21 @@ async function initCommand(options) {
1795
1798
  try {
1796
1799
  const result = writeSetup(generatedSetup);
1797
1800
  writeSpinner.succeed("Config files written");
1798
- trackEvent("setup_applied", { files_written: result.written.length, target_agent: targetAgent });
1801
+ trackEvent("setup_applied", {
1802
+ files_written: result.written.length,
1803
+ files_deleted: result.deleted.length,
1804
+ target_agent: targetAgent
1805
+ });
1799
1806
  console.log(chalk3.bold("\nFiles created/updated:"));
1800
1807
  for (const file of result.written) {
1801
1808
  console.log(` ${chalk3.green("\u2713")} ${file}`);
1802
1809
  }
1810
+ if (result.deleted.length > 0) {
1811
+ console.log(chalk3.bold("\nFiles removed:"));
1812
+ for (const file of result.deleted) {
1813
+ console.log(` ${chalk3.red("\u2717")} ${file}`);
1814
+ }
1815
+ }
1803
1816
  if (result.backupDir) {
1804
1817
  console.log(chalk3.dim(`
1805
1818
  Backups saved to ${result.backupDir}`));
@@ -1936,39 +1949,20 @@ async function promptAction() {
1936
1949
  function printSetupSummary(setup) {
1937
1950
  const claude = setup.claude;
1938
1951
  const cursor = setup.cursor;
1952
+ const fileDescriptions = setup.fileDescriptions;
1953
+ const deletions = setup.deletions;
1939
1954
  console.log("");
1940
- console.log(chalk3.bold(" Files to create:\n"));
1955
+ console.log(chalk3.bold(" Proposed changes:\n"));
1956
+ const getDescription = (filePath) => {
1957
+ return fileDescriptions?.[filePath];
1958
+ };
1941
1959
  if (claude) {
1942
1960
  if (claude.claudeMd) {
1943
1961
  const icon = fs16.existsSync("CLAUDE.md") ? chalk3.yellow("~") : chalk3.green("+");
1944
- const sections = extractClaudeMdSections(claude.claudeMd);
1962
+ const desc = getDescription("CLAUDE.md");
1945
1963
  console.log(` ${icon} ${chalk3.bold("CLAUDE.md")}`);
1946
- console.log(chalk3.dim(" Your project's knowledge base for the AI agent \u2014 architecture, build"));
1947
- console.log(chalk3.dim(" commands, conventions. Claude reads this at the start of every session."));
1948
- if (sections.length > 0) {
1949
- console.log(chalk3.dim(` Sections: ${sections.join(", ")}`));
1950
- }
1951
- console.log("");
1952
- }
1953
- if (claude.settings) {
1954
- const icon = fs16.existsSync(".claude/settings.json") ? chalk3.yellow("~") : chalk3.green("+");
1955
- const settings = claude.settings;
1956
- const perms = settings.permissions?.allow || [];
1957
- console.log(` ${icon} ${chalk3.bold(".claude/settings.json")}`);
1958
- console.log(chalk3.dim(" Pre-approved shell commands so Claude doesn't ask permission each time."));
1959
- if (perms.length > 0) {
1960
- console.log(chalk3.dim(` Allows: ${summarizePermissions(perms)}`));
1961
- }
1962
- console.log("");
1963
- }
1964
- if (claude.settingsLocal) {
1965
- const icon = fs16.existsSync(".claude/settings.local.json") ? chalk3.yellow("~") : chalk3.green("+");
1966
- const settings = claude.settingsLocal;
1967
- const perms = settings.permissions?.allow || [];
1968
- console.log(` ${icon} ${chalk3.bold(".claude/settings.local.json")}`);
1969
- console.log(chalk3.dim(" Your personal permission overrides (not shared with teammates)."));
1970
- if (perms.length > 0) {
1971
- console.log(chalk3.dim(` Allows: ${summarizePermissions(perms)}`));
1964
+ if (desc) {
1965
+ console.log(chalk3.dim(` ${desc}`));
1972
1966
  }
1973
1967
  console.log("");
1974
1968
  }
@@ -1977,8 +1971,9 @@ function printSetupSummary(setup) {
1977
1971
  for (const skill of skills) {
1978
1972
  const skillPath = `.claude/skills/${skill.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}.md`;
1979
1973
  const icon = fs16.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
1974
+ const desc = getDescription(skillPath);
1980
1975
  console.log(` ${icon} ${chalk3.bold(skillPath)}`);
1981
- console.log(chalk3.dim(` ${summarizeSkill(skill)}`));
1976
+ console.log(chalk3.dim(` ${desc || summarizeSkill(skill)}`));
1982
1977
  console.log("");
1983
1978
  }
1984
1979
  }
@@ -1986,18 +1981,18 @@ function printSetupSummary(setup) {
1986
1981
  if (mcpServers && Object.keys(mcpServers).length > 0) {
1987
1982
  const icon = fs16.existsSync(".mcp.json") ? chalk3.yellow("~") : chalk3.green("+");
1988
1983
  const serverNames = Object.keys(mcpServers);
1984
+ const desc = getDescription(".mcp.json");
1989
1985
  console.log(` ${icon} ${chalk3.bold(".mcp.json")}`);
1990
- console.log(chalk3.dim(" Connects Claude to external tools it can call directly."));
1991
- console.log(chalk3.dim(` Servers: ${serverNames.join(", ")}`));
1986
+ console.log(chalk3.dim(` ${desc || `servers: ${serverNames.join(", ")}`}`));
1992
1987
  console.log("");
1993
1988
  }
1994
1989
  }
1995
1990
  if (cursor) {
1996
1991
  if (cursor.cursorrules) {
1997
1992
  const icon = fs16.existsSync(".cursorrules") ? chalk3.yellow("~") : chalk3.green("+");
1993
+ const desc = getDescription(".cursorrules");
1998
1994
  console.log(` ${icon} ${chalk3.bold(".cursorrules")}`);
1999
- console.log(chalk3.dim(" Project-wide instructions for Cursor \u2014 coding style, architecture,"));
2000
- console.log(chalk3.dim(" and conventions. Cursor reads this at the start of every session."));
1995
+ if (desc) console.log(chalk3.dim(` ${desc}`));
2001
1996
  console.log("");
2002
1997
  }
2003
1998
  const rules = cursor.rules;
@@ -2005,9 +2000,14 @@ function printSetupSummary(setup) {
2005
2000
  for (const rule of rules) {
2006
2001
  const rulePath = `.cursor/rules/${rule.filename}`;
2007
2002
  const icon = fs16.existsSync(rulePath) ? chalk3.yellow("~") : chalk3.green("+");
2003
+ const desc = getDescription(rulePath);
2008
2004
  console.log(` ${icon} ${chalk3.bold(rulePath)}`);
2009
- const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
2010
- if (firstLine) console.log(chalk3.dim(` ${firstLine.trim().slice(0, 80)}`));
2005
+ if (desc) {
2006
+ console.log(chalk3.dim(` ${desc}`));
2007
+ } else {
2008
+ const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
2009
+ if (firstLine) console.log(chalk3.dim(` ${firstLine.trim().slice(0, 80)}`));
2010
+ }
2011
2011
  console.log("");
2012
2012
  }
2013
2013
  }
@@ -2015,24 +2015,22 @@ function printSetupSummary(setup) {
2015
2015
  if (mcpServers && Object.keys(mcpServers).length > 0) {
2016
2016
  const icon = fs16.existsSync(".cursor/mcp.json") ? chalk3.yellow("~") : chalk3.green("+");
2017
2017
  const serverNames = Object.keys(mcpServers);
2018
+ const desc = getDescription(".cursor/mcp.json");
2018
2019
  console.log(` ${icon} ${chalk3.bold(".cursor/mcp.json")}`);
2019
- console.log(chalk3.dim(" Connects Cursor to external tools it can call directly."));
2020
- console.log(chalk3.dim(` Servers: ${serverNames.join(", ")}`));
2020
+ console.log(chalk3.dim(` ${desc || `servers: ${serverNames.join(", ")}`}`));
2021
+ console.log("");
2022
+ }
2023
+ }
2024
+ if (Array.isArray(deletions) && deletions.length > 0) {
2025
+ for (const del of deletions) {
2026
+ console.log(` ${chalk3.red("-")} ${chalk3.bold(del.filePath)}`);
2027
+ console.log(chalk3.dim(` ${del.reason}`));
2021
2028
  console.log("");
2022
2029
  }
2023
2030
  }
2024
- console.log(` ${chalk3.green("+")} ${chalk3.dim("new")} ${chalk3.yellow("~")} ${chalk3.dim("modified")}`);
2031
+ console.log(` ${chalk3.green("+")} ${chalk3.dim("new")} ${chalk3.yellow("~")} ${chalk3.dim("modified")} ${chalk3.red("-")} ${chalk3.dim("removed")}`);
2025
2032
  console.log("");
2026
2033
  }
2027
- function extractClaudeMdSections(md) {
2028
- return md.split("\n").filter((line) => /^##\s+/.test(line)).map((line) => line.replace(/^##\s+/, "").trim());
2029
- }
2030
- function summarizePermissions(permissions, maxShow = 3) {
2031
- if (permissions.length === 0) return "None";
2032
- const shown = permissions.slice(0, maxShow).join(", ");
2033
- const remaining = permissions.length - maxShow;
2034
- return remaining > 0 ? `${shown} (+${remaining} more)` : shown;
2035
- }
2036
2034
  function summarizeSkill(skill) {
2037
2035
  const lines = skill.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"));
2038
2036
  return lines[0]?.trim().slice(0, 80) || skill.name;
@@ -2043,8 +2041,6 @@ function collectSetupFiles(setup) {
2043
2041
  const cursor = setup.cursor;
2044
2042
  if (claude) {
2045
2043
  if (claude.claudeMd) files.push({ path: "CLAUDE.md", content: claude.claudeMd });
2046
- if (claude.settings) files.push({ path: ".claude/settings.json", content: JSON.stringify(claude.settings, null, 2) });
2047
- if (claude.settingsLocal) files.push({ path: ".claude/settings.local.json", content: JSON.stringify(claude.settingsLocal, null, 2) });
2048
2044
  const skills = claude.skills;
2049
2045
  if (Array.isArray(skills)) {
2050
2046
  for (const skill of skills) {