@caliber-ai/cli 0.20.2 → 0.21.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.
package/dist/bin.js CHANGED
@@ -84,7 +84,7 @@ import chalk3 from "chalk";
84
84
  import ora2 from "ora";
85
85
  import readline from "readline";
86
86
  import select from "@inquirer/select";
87
- import fs18 from "fs";
87
+ import fs17 from "fs";
88
88
 
89
89
  // src/auth/token-store.ts
90
90
  init_constants();
@@ -1115,219 +1115,77 @@ async function enrichFingerprintWithLLM(fingerprint, dir) {
1115
1115
  }
1116
1116
  }
1117
1117
 
1118
- // src/scanner/index.ts
1119
- import fs9 from "fs";
1120
- import path10 from "path";
1121
- import crypto3 from "crypto";
1122
- function scanLocalState(dir) {
1123
- const items = [];
1124
- const claudeMdPath = path10.join(dir, "CLAUDE.md");
1125
- if (fs9.existsSync(claudeMdPath)) {
1126
- items.push({
1127
- type: "rule",
1128
- platform: "claude",
1129
- name: "CLAUDE.md",
1130
- contentHash: hashFile(claudeMdPath),
1131
- path: claudeMdPath
1132
- });
1133
- }
1134
- const skillsDir = path10.join(dir, ".claude", "skills");
1135
- if (fs9.existsSync(skillsDir)) {
1136
- for (const file of fs9.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
1137
- const filePath = path10.join(skillsDir, file);
1138
- items.push({
1139
- type: "skill",
1140
- platform: "claude",
1141
- name: file,
1142
- contentHash: hashFile(filePath),
1143
- path: filePath
1144
- });
1145
- }
1146
- }
1147
- const mcpJsonPath = path10.join(dir, ".mcp.json");
1148
- if (fs9.existsSync(mcpJsonPath)) {
1149
- try {
1150
- const mcpJson = JSON.parse(fs9.readFileSync(mcpJsonPath, "utf-8"));
1151
- if (mcpJson.mcpServers) {
1152
- for (const name of Object.keys(mcpJson.mcpServers)) {
1153
- items.push({
1154
- type: "mcp",
1155
- platform: "claude",
1156
- name,
1157
- contentHash: hashJson(mcpJson.mcpServers[name]),
1158
- path: mcpJsonPath
1159
- });
1160
- }
1161
- }
1162
- } catch {
1163
- }
1164
- }
1165
- const cursorrulesPath = path10.join(dir, ".cursorrules");
1166
- if (fs9.existsSync(cursorrulesPath)) {
1167
- items.push({
1168
- type: "rule",
1169
- platform: "cursor",
1170
- name: ".cursorrules",
1171
- contentHash: hashFile(cursorrulesPath),
1172
- path: cursorrulesPath
1173
- });
1174
- }
1175
- const cursorRulesDir = path10.join(dir, ".cursor", "rules");
1176
- if (fs9.existsSync(cursorRulesDir)) {
1177
- for (const file of fs9.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
1178
- const filePath = path10.join(cursorRulesDir, file);
1179
- items.push({
1180
- type: "rule",
1181
- platform: "cursor",
1182
- name: file,
1183
- contentHash: hashFile(filePath),
1184
- path: filePath
1185
- });
1186
- }
1187
- }
1188
- const cursorSkillsDir = path10.join(dir, ".cursor", "skills");
1189
- if (fs9.existsSync(cursorSkillsDir)) {
1190
- try {
1191
- for (const slug of fs9.readdirSync(cursorSkillsDir)) {
1192
- const skillFile = path10.join(cursorSkillsDir, slug, "SKILL.md");
1193
- if (fs9.existsSync(skillFile)) {
1194
- items.push({
1195
- type: "skill",
1196
- platform: "cursor",
1197
- name: `${slug}/SKILL.md`,
1198
- contentHash: hashFile(skillFile),
1199
- path: skillFile
1200
- });
1201
- }
1202
- }
1203
- } catch {
1204
- }
1205
- }
1206
- const cursorMcpPath = path10.join(dir, ".cursor", "mcp.json");
1207
- if (fs9.existsSync(cursorMcpPath)) {
1208
- try {
1209
- const mcpJson = JSON.parse(fs9.readFileSync(cursorMcpPath, "utf-8"));
1210
- if (mcpJson.mcpServers) {
1211
- for (const name of Object.keys(mcpJson.mcpServers)) {
1212
- items.push({
1213
- type: "mcp",
1214
- platform: "cursor",
1215
- name,
1216
- contentHash: hashJson(mcpJson.mcpServers[name]),
1217
- path: cursorMcpPath
1218
- });
1219
- }
1220
- }
1221
- } catch {
1222
- }
1223
- }
1224
- return items;
1225
- }
1226
- function compareState(serverItems, localItems) {
1227
- const installed = [];
1228
- const missing = [];
1229
- const outdated = [];
1230
- const extra = [];
1231
- const localMap = /* @__PURE__ */ new Map();
1232
- for (const item of localItems) {
1233
- localMap.set(`${item.type}:${item.platform}:${item.name}`, item);
1234
- }
1235
- for (const server of serverItems) {
1236
- const key = `${server.type}:${server.platform}:${server.name}`;
1237
- const local = localMap.get(key);
1238
- localMap.delete(key);
1239
- if (!local) {
1240
- missing.push(server);
1241
- } else if (local.contentHash !== server.content_hash) {
1242
- outdated.push({ server, local });
1243
- } else {
1244
- installed.push({ server, local });
1245
- }
1246
- }
1247
- for (const local of localMap.values()) {
1248
- extra.push(local);
1249
- }
1250
- return { installed, missing, outdated, extra };
1251
- }
1252
- function hashFile(filePath) {
1253
- const text = fs9.readFileSync(filePath, "utf-8");
1254
- return crypto3.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
1255
- }
1256
- function hashJson(obj) {
1257
- return crypto3.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
1258
- }
1259
-
1260
1118
  // src/writers/index.ts
1261
- import fs14 from "fs";
1119
+ import fs13 from "fs";
1262
1120
 
1263
1121
  // src/writers/claude/index.ts
1264
- import fs10 from "fs";
1265
- import path11 from "path";
1122
+ import fs9 from "fs";
1123
+ import path10 from "path";
1266
1124
  function writeClaudeConfig(config) {
1267
1125
  const written = [];
1268
- fs10.writeFileSync("CLAUDE.md", config.claudeMd);
1126
+ fs9.writeFileSync("CLAUDE.md", config.claudeMd);
1269
1127
  written.push("CLAUDE.md");
1270
1128
  if (config.skills?.length) {
1271
- const skillsDir = path11.join(".claude", "skills");
1272
- if (!fs10.existsSync(skillsDir)) fs10.mkdirSync(skillsDir, { recursive: true });
1129
+ const skillsDir = path10.join(".claude", "skills");
1130
+ if (!fs9.existsSync(skillsDir)) fs9.mkdirSync(skillsDir, { recursive: true });
1273
1131
  for (const skill of config.skills) {
1274
1132
  const filename = `${skill.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}.md`;
1275
- const skillPath = path11.join(skillsDir, filename);
1276
- fs10.writeFileSync(skillPath, skill.content);
1133
+ const skillPath = path10.join(skillsDir, filename);
1134
+ fs9.writeFileSync(skillPath, skill.content);
1277
1135
  written.push(skillPath);
1278
1136
  }
1279
1137
  }
1280
1138
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
1281
1139
  let existingServers = {};
1282
1140
  try {
1283
- if (fs10.existsSync(".mcp.json")) {
1284
- const existing = JSON.parse(fs10.readFileSync(".mcp.json", "utf-8"));
1141
+ if (fs9.existsSync(".mcp.json")) {
1142
+ const existing = JSON.parse(fs9.readFileSync(".mcp.json", "utf-8"));
1285
1143
  if (existing.mcpServers) existingServers = existing.mcpServers;
1286
1144
  }
1287
1145
  } catch {
1288
1146
  }
1289
1147
  const mergedServers = { ...existingServers, ...config.mcpServers };
1290
- fs10.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
1148
+ fs9.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
1291
1149
  written.push(".mcp.json");
1292
1150
  }
1293
1151
  return written;
1294
1152
  }
1295
1153
 
1296
1154
  // src/writers/cursor/index.ts
1297
- import fs11 from "fs";
1298
- import path12 from "path";
1155
+ import fs10 from "fs";
1156
+ import path11 from "path";
1299
1157
  function writeCursorConfig(config) {
1300
1158
  const written = [];
1301
1159
  if (config.cursorrules) {
1302
- fs11.writeFileSync(".cursorrules", config.cursorrules);
1160
+ fs10.writeFileSync(".cursorrules", config.cursorrules);
1303
1161
  written.push(".cursorrules");
1304
1162
  }
1305
1163
  if (config.rules?.length) {
1306
- const rulesDir = path12.join(".cursor", "rules");
1307
- if (!fs11.existsSync(rulesDir)) fs11.mkdirSync(rulesDir, { recursive: true });
1164
+ const rulesDir = path11.join(".cursor", "rules");
1165
+ if (!fs10.existsSync(rulesDir)) fs10.mkdirSync(rulesDir, { recursive: true });
1308
1166
  for (const rule of config.rules) {
1309
- const rulePath = path12.join(rulesDir, rule.filename);
1310
- fs11.writeFileSync(rulePath, rule.content);
1167
+ const rulePath = path11.join(rulesDir, rule.filename);
1168
+ fs10.writeFileSync(rulePath, rule.content);
1311
1169
  written.push(rulePath);
1312
1170
  }
1313
1171
  }
1314
1172
  if (config.skills?.length) {
1315
1173
  for (const skill of config.skills) {
1316
- const skillDir = path12.join(".cursor", "skills", skill.slug);
1317
- if (!fs11.existsSync(skillDir)) fs11.mkdirSync(skillDir, { recursive: true });
1318
- const skillPath = path12.join(skillDir, "SKILL.md");
1319
- fs11.writeFileSync(skillPath, skill.content);
1174
+ const skillDir = path11.join(".cursor", "skills", skill.slug);
1175
+ if (!fs10.existsSync(skillDir)) fs10.mkdirSync(skillDir, { recursive: true });
1176
+ const skillPath = path11.join(skillDir, "SKILL.md");
1177
+ fs10.writeFileSync(skillPath, skill.content);
1320
1178
  written.push(skillPath);
1321
1179
  }
1322
1180
  }
1323
1181
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
1324
1182
  const cursorDir = ".cursor";
1325
- if (!fs11.existsSync(cursorDir)) fs11.mkdirSync(cursorDir, { recursive: true });
1326
- const mcpPath = path12.join(cursorDir, "mcp.json");
1183
+ if (!fs10.existsSync(cursorDir)) fs10.mkdirSync(cursorDir, { recursive: true });
1184
+ const mcpPath = path11.join(cursorDir, "mcp.json");
1327
1185
  let existingServers = {};
1328
1186
  try {
1329
- if (fs11.existsSync(mcpPath)) {
1330
- const existing = JSON.parse(fs11.readFileSync(mcpPath, "utf-8"));
1187
+ if (fs10.existsSync(mcpPath)) {
1188
+ const existing = JSON.parse(fs10.readFileSync(mcpPath, "utf-8"));
1331
1189
  if (existing.mcpServers) {
1332
1190
  existingServers = existing.mcpServers;
1333
1191
  }
@@ -1335,7 +1193,7 @@ function writeCursorConfig(config) {
1335
1193
  } catch {
1336
1194
  }
1337
1195
  const mergedServers = { ...existingServers, ...config.mcpServers };
1338
- fs11.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
1196
+ fs10.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
1339
1197
  written.push(mcpPath);
1340
1198
  }
1341
1199
  return written;
@@ -1343,62 +1201,62 @@ function writeCursorConfig(config) {
1343
1201
 
1344
1202
  // src/writers/backup.ts
1345
1203
  init_constants();
1346
- import fs12 from "fs";
1347
- import path13 from "path";
1204
+ import fs11 from "fs";
1205
+ import path12 from "path";
1348
1206
  function createBackup(files) {
1349
1207
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1350
- const backupDir = path13.join(BACKUPS_DIR, timestamp);
1208
+ const backupDir = path12.join(BACKUPS_DIR, timestamp);
1351
1209
  for (const file of files) {
1352
- if (!fs12.existsSync(file)) continue;
1353
- const dest = path13.join(backupDir, file);
1354
- const destDir = path13.dirname(dest);
1355
- if (!fs12.existsSync(destDir)) {
1356
- fs12.mkdirSync(destDir, { recursive: true });
1210
+ if (!fs11.existsSync(file)) continue;
1211
+ const dest = path12.join(backupDir, file);
1212
+ const destDir = path12.dirname(dest);
1213
+ if (!fs11.existsSync(destDir)) {
1214
+ fs11.mkdirSync(destDir, { recursive: true });
1357
1215
  }
1358
- fs12.copyFileSync(file, dest);
1216
+ fs11.copyFileSync(file, dest);
1359
1217
  }
1360
1218
  return backupDir;
1361
1219
  }
1362
1220
  function restoreBackup(backupDir, file) {
1363
- const backupFile = path13.join(backupDir, file);
1364
- if (!fs12.existsSync(backupFile)) return false;
1365
- const destDir = path13.dirname(file);
1366
- if (!fs12.existsSync(destDir)) {
1367
- fs12.mkdirSync(destDir, { recursive: true });
1221
+ const backupFile = path12.join(backupDir, file);
1222
+ if (!fs11.existsSync(backupFile)) return false;
1223
+ const destDir = path12.dirname(file);
1224
+ if (!fs11.existsSync(destDir)) {
1225
+ fs11.mkdirSync(destDir, { recursive: true });
1368
1226
  }
1369
- fs12.copyFileSync(backupFile, file);
1227
+ fs11.copyFileSync(backupFile, file);
1370
1228
  return true;
1371
1229
  }
1372
1230
 
1373
1231
  // src/writers/manifest.ts
1374
1232
  init_constants();
1375
- import fs13 from "fs";
1376
- import crypto4 from "crypto";
1233
+ import fs12 from "fs";
1234
+ import crypto3 from "crypto";
1377
1235
  function readManifest() {
1378
1236
  try {
1379
- if (!fs13.existsSync(MANIFEST_FILE)) return null;
1380
- return JSON.parse(fs13.readFileSync(MANIFEST_FILE, "utf-8"));
1237
+ if (!fs12.existsSync(MANIFEST_FILE)) return null;
1238
+ return JSON.parse(fs12.readFileSync(MANIFEST_FILE, "utf-8"));
1381
1239
  } catch {
1382
1240
  return null;
1383
1241
  }
1384
1242
  }
1385
1243
  function writeManifest(manifest) {
1386
- if (!fs13.existsSync(CALIBER_DIR)) {
1387
- fs13.mkdirSync(CALIBER_DIR, { recursive: true });
1244
+ if (!fs12.existsSync(CALIBER_DIR)) {
1245
+ fs12.mkdirSync(CALIBER_DIR, { recursive: true });
1388
1246
  }
1389
- fs13.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
1247
+ fs12.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
1390
1248
  }
1391
1249
  function fileChecksum(filePath) {
1392
- const content = fs13.readFileSync(filePath);
1393
- return crypto4.createHash("sha256").update(content).digest("hex");
1250
+ const content = fs12.readFileSync(filePath);
1251
+ return crypto3.createHash("sha256").update(content).digest("hex");
1394
1252
  }
1395
1253
 
1396
1254
  // src/writers/index.ts
1397
1255
  function writeSetup(setup) {
1398
1256
  const filesToWrite = getFilesToWrite(setup);
1399
- const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs14.existsSync(f));
1257
+ const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs13.existsSync(f));
1400
1258
  const existingFiles = [
1401
- ...filesToWrite.filter((f) => fs14.existsSync(f)),
1259
+ ...filesToWrite.filter((f) => fs13.existsSync(f)),
1402
1260
  ...filesToDelete
1403
1261
  ];
1404
1262
  const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
@@ -1411,7 +1269,7 @@ function writeSetup(setup) {
1411
1269
  }
1412
1270
  const deleted = [];
1413
1271
  for (const filePath of filesToDelete) {
1414
- fs14.unlinkSync(filePath);
1272
+ fs13.unlinkSync(filePath);
1415
1273
  deleted.push(filePath);
1416
1274
  }
1417
1275
  ensureGitignore();
@@ -1441,8 +1299,8 @@ function undoSetup() {
1441
1299
  const removed = [];
1442
1300
  for (const entry of manifest.entries) {
1443
1301
  if (entry.action === "created") {
1444
- if (fs14.existsSync(entry.path)) {
1445
- fs14.unlinkSync(entry.path);
1302
+ if (fs13.existsSync(entry.path)) {
1303
+ fs13.unlinkSync(entry.path);
1446
1304
  removed.push(entry.path);
1447
1305
  }
1448
1306
  } else if ((entry.action === "modified" || entry.action === "deleted") && manifest.backupDir) {
@@ -1452,8 +1310,8 @@ function undoSetup() {
1452
1310
  }
1453
1311
  }
1454
1312
  const { MANIFEST_FILE: MANIFEST_FILE2 } = (init_constants(), __toCommonJS(constants_exports));
1455
- if (fs14.existsSync(MANIFEST_FILE2)) {
1456
- fs14.unlinkSync(MANIFEST_FILE2);
1313
+ if (fs13.existsSync(MANIFEST_FILE2)) {
1314
+ fs13.unlinkSync(MANIFEST_FILE2);
1457
1315
  }
1458
1316
  return { restored, removed };
1459
1317
  }
@@ -1482,37 +1340,37 @@ function getFilesToWrite(setup) {
1482
1340
  }
1483
1341
  function ensureGitignore() {
1484
1342
  const gitignorePath = ".gitignore";
1485
- if (fs14.existsSync(gitignorePath)) {
1486
- const content = fs14.readFileSync(gitignorePath, "utf-8");
1343
+ if (fs13.existsSync(gitignorePath)) {
1344
+ const content = fs13.readFileSync(gitignorePath, "utf-8");
1487
1345
  if (!content.includes(".caliber/")) {
1488
- fs14.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
1346
+ fs13.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
1489
1347
  }
1490
1348
  } else {
1491
- fs14.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
1349
+ fs13.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
1492
1350
  }
1493
1351
  }
1494
1352
 
1495
1353
  // src/writers/staging.ts
1496
1354
  init_constants();
1497
- import fs15 from "fs";
1498
- import path14 from "path";
1499
- var STAGED_DIR = path14.join(CALIBER_DIR, "staged");
1500
- var PROPOSED_DIR = path14.join(STAGED_DIR, "proposed");
1501
- var CURRENT_DIR = path14.join(STAGED_DIR, "current");
1355
+ import fs14 from "fs";
1356
+ import path13 from "path";
1357
+ var STAGED_DIR = path13.join(CALIBER_DIR, "staged");
1358
+ var PROPOSED_DIR = path13.join(STAGED_DIR, "proposed");
1359
+ var CURRENT_DIR = path13.join(STAGED_DIR, "current");
1502
1360
  function stageFiles(files, projectDir) {
1503
1361
  cleanupStaging();
1504
1362
  let newFiles = 0;
1505
1363
  let modifiedFiles = 0;
1506
1364
  const stagedFiles = [];
1507
1365
  for (const file of files) {
1508
- const proposedPath = path14.join(PROPOSED_DIR, file.path);
1509
- fs15.mkdirSync(path14.dirname(proposedPath), { recursive: true });
1510
- fs15.writeFileSync(proposedPath, file.content);
1511
- const originalPath = path14.join(projectDir, file.path);
1512
- if (fs15.existsSync(originalPath)) {
1513
- const currentPath = path14.join(CURRENT_DIR, file.path);
1514
- fs15.mkdirSync(path14.dirname(currentPath), { recursive: true });
1515
- fs15.copyFileSync(originalPath, currentPath);
1366
+ const proposedPath = path13.join(PROPOSED_DIR, file.path);
1367
+ fs14.mkdirSync(path13.dirname(proposedPath), { recursive: true });
1368
+ fs14.writeFileSync(proposedPath, file.content);
1369
+ const originalPath = path13.join(projectDir, file.path);
1370
+ if (fs14.existsSync(originalPath)) {
1371
+ const currentPath = path13.join(CURRENT_DIR, file.path);
1372
+ fs14.mkdirSync(path13.dirname(currentPath), { recursive: true });
1373
+ fs14.copyFileSync(originalPath, currentPath);
1516
1374
  modifiedFiles++;
1517
1375
  stagedFiles.push({ relativePath: file.path, proposedPath, currentPath, originalPath, isNew: false });
1518
1376
  } else {
@@ -1523,8 +1381,8 @@ function stageFiles(files, projectDir) {
1523
1381
  return { newFiles, modifiedFiles, stagedFiles };
1524
1382
  }
1525
1383
  function cleanupStaging() {
1526
- if (fs15.existsSync(STAGED_DIR)) {
1527
- fs15.rmSync(STAGED_DIR, { recursive: true, force: true });
1384
+ if (fs14.existsSync(STAGED_DIR)) {
1385
+ fs14.rmSync(STAGED_DIR, { recursive: true, force: true });
1528
1386
  }
1529
1387
  }
1530
1388
 
@@ -1570,23 +1428,23 @@ function openDiffsInEditor(editor, files) {
1570
1428
  import { createTwoFilesPatch } from "diff";
1571
1429
 
1572
1430
  // src/lib/hooks.ts
1573
- import fs16 from "fs";
1574
- import path15 from "path";
1575
- var SETTINGS_PATH = path15.join(".claude", "settings.json");
1431
+ import fs15 from "fs";
1432
+ import path14 from "path";
1433
+ var SETTINGS_PATH = path14.join(".claude", "settings.json");
1576
1434
  var HOOK_COMMAND = "caliber refresh --quiet";
1577
1435
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
1578
1436
  function readSettings() {
1579
- if (!fs16.existsSync(SETTINGS_PATH)) return {};
1437
+ if (!fs15.existsSync(SETTINGS_PATH)) return {};
1580
1438
  try {
1581
- return JSON.parse(fs16.readFileSync(SETTINGS_PATH, "utf-8"));
1439
+ return JSON.parse(fs15.readFileSync(SETTINGS_PATH, "utf-8"));
1582
1440
  } catch {
1583
1441
  return {};
1584
1442
  }
1585
1443
  }
1586
1444
  function writeSettings(settings) {
1587
- const dir = path15.dirname(SETTINGS_PATH);
1588
- if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
1589
- fs16.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
1445
+ const dir = path14.dirname(SETTINGS_PATH);
1446
+ if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
1447
+ fs15.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
1590
1448
  }
1591
1449
  function findHookIndex(sessionEnd) {
1592
1450
  return sessionEnd.findIndex(
@@ -1636,23 +1494,23 @@ function removeHook() {
1636
1494
 
1637
1495
  // src/lib/state.ts
1638
1496
  init_constants();
1639
- import fs17 from "fs";
1640
- import path16 from "path";
1497
+ import fs16 from "fs";
1498
+ import path15 from "path";
1641
1499
  import { execSync as execSync3 } from "child_process";
1642
- var STATE_FILE = path16.join(CALIBER_DIR, ".caliber-state.json");
1500
+ var STATE_FILE = path15.join(CALIBER_DIR, ".caliber-state.json");
1643
1501
  function readState() {
1644
1502
  try {
1645
- if (!fs17.existsSync(STATE_FILE)) return null;
1646
- return JSON.parse(fs17.readFileSync(STATE_FILE, "utf-8"));
1503
+ if (!fs16.existsSync(STATE_FILE)) return null;
1504
+ return JSON.parse(fs16.readFileSync(STATE_FILE, "utf-8"));
1647
1505
  } catch {
1648
1506
  return null;
1649
1507
  }
1650
1508
  }
1651
1509
  function writeState(state) {
1652
- if (!fs17.existsSync(CALIBER_DIR)) {
1653
- fs17.mkdirSync(CALIBER_DIR, { recursive: true });
1510
+ if (!fs16.existsSync(CALIBER_DIR)) {
1511
+ fs16.mkdirSync(CALIBER_DIR, { recursive: true });
1654
1512
  }
1655
- fs17.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
1513
+ fs16.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
1656
1514
  }
1657
1515
  function getCurrentHeadSha() {
1658
1516
  try {
@@ -1757,8 +1615,8 @@ async function initCommand(options) {
1757
1615
  console.log(chalk3.dim(" Configure your coding agent environment\n"));
1758
1616
  console.log(chalk3.bold(" What is Caliber?\n"));
1759
1617
  console.log(chalk3.dim(" Caliber audits your AI agent configurations and suggests targeted"));
1760
- console.log(chalk3.dim(" improvements. It analyzes CLAUDE.md, .cursorrules, skills, and MCP"));
1761
- console.log(chalk3.dim(" servers against your actual codebase \u2014 keeping what works, fixing"));
1618
+ console.log(chalk3.dim(" improvements. It analyzes CLAUDE.md, .cursorrules, and skills"));
1619
+ console.log(chalk3.dim(" against your actual codebase \u2014 keeping what works, fixing"));
1762
1620
  console.log(chalk3.dim(" what's stale, and adding what's missing.\n"));
1763
1621
  console.log(chalk3.bold(" How it works:\n"));
1764
1622
  console.log(chalk3.dim(" 1. Scan Analyze your code, dependencies, and file structure"));
@@ -1797,10 +1655,6 @@ async function initCommand(options) {
1797
1655
  cursor_rules_count: fingerprint.existingConfigs.cursorRules?.length ?? 0,
1798
1656
  cursor_skills_count: fingerprint.existingConfigs.cursorSkills?.length ?? 0,
1799
1657
  skills_count: fingerprint.existingConfigs.claudeSkills?.length ?? 0,
1800
- has_claude_mcp_servers: !!fingerprint.existingConfigs.claudeMcpServers,
1801
- has_cursor_mcp_servers: !!fingerprint.existingConfigs.cursorMcpServers,
1802
- claude_mcp_server_count: fingerprint.existingConfigs.claudeMcpServers ? Object.keys(fingerprint.existingConfigs.claudeMcpServers).length : 0,
1803
- cursor_mcp_server_count: fingerprint.existingConfigs.cursorMcpServers ? Object.keys(fingerprint.existingConfigs.cursorMcpServers).length : 0,
1804
1658
  file_count: fingerprint.fileTree.length
1805
1659
  });
1806
1660
  console.log(chalk3.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
@@ -1808,7 +1662,7 @@ async function initCommand(options) {
1808
1662
  console.log(chalk3.dim(` Files: ${fingerprint.fileTree.length} found
1809
1663
  `));
1810
1664
  console.log(chalk3.hex("#6366f1").bold(" Step 3/6 \u2014 Match project\n"));
1811
- console.log(chalk3.dim(" Scanning for existing rules, skills, MCP servers, and teammate setups.\n"));
1665
+ console.log(chalk3.dim(" Scanning for existing rules, skills, and teammate setups.\n"));
1812
1666
  const matchSpinner = ora2("Scanning for existing setup...").start();
1813
1667
  const localConfigs = [];
1814
1668
  const ec = fingerprint.existingConfigs;
@@ -1830,15 +1684,6 @@ async function initCommand(options) {
1830
1684
  localConfigs.push(`.cursor/skills/${skill.slug}/SKILL.md`);
1831
1685
  }
1832
1686
  }
1833
- const localState = scanLocalState(process.cwd());
1834
- const claudeMcpServers = localState.filter((i) => i.type === "mcp" && i.platform === "claude").map((i) => i.name);
1835
- const cursorMcpServers = localState.filter((i) => i.type === "mcp" && i.platform === "cursor").map((i) => i.name);
1836
- if (claudeMcpServers.length > 0) {
1837
- localConfigs.push(`.mcp.json (${claudeMcpServers.join(", ")} \u2014 will merge)`);
1838
- }
1839
- if (cursorMcpServers.length > 0) {
1840
- localConfigs.push(`.cursor/mcp.json (${cursorMcpServers.join(", ")} \u2014 will merge)`);
1841
- }
1842
1687
  let existingSetup = null;
1843
1688
  let existingProjectId = null;
1844
1689
  let hasTeammateSetup = false;
@@ -1893,7 +1738,7 @@ async function initCommand(options) {
1893
1738
  let generatedSetup = null;
1894
1739
  let rawOutput;
1895
1740
  trackEvent("generation_started", { target_agent: targetAgent });
1896
- const hasExistingConfig = !!(ec.claudeMd || ec.claudeSettings || ec.claudeSkills?.length || ec.cursorrules || ec.cursorRules?.length || ec.claudeMcpServers || ec.cursorMcpServers);
1741
+ const hasExistingConfig = !!(ec.claudeMd || ec.claudeSettings || ec.claudeSkills?.length || ec.cursorrules || ec.cursorRules?.length);
1897
1742
  const genStartTime = Date.now();
1898
1743
  const genSpinner = ora2("Generating setup...").start();
1899
1744
  const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
@@ -2154,8 +1999,8 @@ function openReview(method, stagedFiles) {
2154
1999
  for (const file of stagedFiles) {
2155
2000
  console.log(chalk3.bold(` ${file.relativePath}`));
2156
2001
  if (file.currentPath) {
2157
- const current = fs18.readFileSync(file.currentPath, "utf-8");
2158
- const proposed = fs18.readFileSync(file.proposedPath, "utf-8");
2002
+ const current = fs17.readFileSync(file.currentPath, "utf-8");
2003
+ const proposed = fs17.readFileSync(file.proposedPath, "utf-8");
2159
2004
  const patch = createTwoFilesPatch(file.relativePath, file.relativePath, current, proposed, "current", "proposed");
2160
2005
  for (const line of patch.split("\n").slice(2)) {
2161
2006
  if (line.startsWith("+")) console.log(chalk3.green(` ${line}`));
@@ -2164,7 +2009,7 @@ function openReview(method, stagedFiles) {
2164
2009
  }
2165
2010
  } else {
2166
2011
  console.log(chalk3.green(" (new file)"));
2167
- const content = fs18.readFileSync(file.proposedPath, "utf-8");
2012
+ const content = fs17.readFileSync(file.proposedPath, "utf-8");
2168
2013
  const preview = content.split("\n").slice(0, 20);
2169
2014
  for (const line of preview) console.log(chalk3.green(` +${line}`));
2170
2015
  if (content.split("\n").length > 20) console.log(chalk3.dim(` ... ${content.split("\n").length - 20} more lines`));
@@ -2195,7 +2040,7 @@ function printSetupSummary(setup) {
2195
2040
  };
2196
2041
  if (claude) {
2197
2042
  if (claude.claudeMd) {
2198
- const icon = fs18.existsSync("CLAUDE.md") ? chalk3.yellow("~") : chalk3.green("+");
2043
+ const icon = fs17.existsSync("CLAUDE.md") ? chalk3.yellow("~") : chalk3.green("+");
2199
2044
  const desc = getDescription("CLAUDE.md");
2200
2045
  console.log(` ${icon} ${chalk3.bold("CLAUDE.md")}`);
2201
2046
  if (desc) {
@@ -2207,26 +2052,17 @@ function printSetupSummary(setup) {
2207
2052
  if (Array.isArray(skills) && skills.length > 0) {
2208
2053
  for (const skill of skills) {
2209
2054
  const skillPath = `.claude/skills/${skill.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}.md`;
2210
- const icon = fs18.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
2055
+ const icon = fs17.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
2211
2056
  const desc = getDescription(skillPath);
2212
2057
  console.log(` ${icon} ${chalk3.bold(skillPath)}`);
2213
2058
  console.log(chalk3.dim(` ${desc || summarizeSkill(skill)}`));
2214
2059
  console.log("");
2215
2060
  }
2216
2061
  }
2217
- const mcpServers = claude.mcpServers;
2218
- if (mcpServers && Object.keys(mcpServers).length > 0) {
2219
- const icon = fs18.existsSync(".mcp.json") ? chalk3.yellow("~") : chalk3.green("+");
2220
- const serverNames = Object.keys(mcpServers);
2221
- const desc = getDescription(".mcp.json");
2222
- console.log(` ${icon} ${chalk3.bold(".mcp.json")}`);
2223
- console.log(chalk3.dim(` ${desc || `servers: ${serverNames.join(", ")}`}`));
2224
- console.log("");
2225
- }
2226
2062
  }
2227
2063
  if (cursor) {
2228
2064
  if (cursor.cursorrules) {
2229
- const icon = fs18.existsSync(".cursorrules") ? chalk3.yellow("~") : chalk3.green("+");
2065
+ const icon = fs17.existsSync(".cursorrules") ? chalk3.yellow("~") : chalk3.green("+");
2230
2066
  const desc = getDescription(".cursorrules");
2231
2067
  console.log(` ${icon} ${chalk3.bold(".cursorrules")}`);
2232
2068
  if (desc) console.log(chalk3.dim(` ${desc}`));
@@ -2236,7 +2072,7 @@ function printSetupSummary(setup) {
2236
2072
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
2237
2073
  for (const skill of cursorSkills) {
2238
2074
  const skillPath = `.cursor/skills/${skill.slug}/SKILL.md`;
2239
- const icon = fs18.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
2075
+ const icon = fs17.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
2240
2076
  const desc = getDescription(skillPath);
2241
2077
  console.log(` ${icon} ${chalk3.bold(skillPath)}`);
2242
2078
  if (desc) {
@@ -2252,7 +2088,7 @@ function printSetupSummary(setup) {
2252
2088
  if (Array.isArray(rules) && rules.length > 0) {
2253
2089
  for (const rule of rules) {
2254
2090
  const rulePath = `.cursor/rules/${rule.filename}`;
2255
- const icon = fs18.existsSync(rulePath) ? chalk3.yellow("~") : chalk3.green("+");
2091
+ const icon = fs17.existsSync(rulePath) ? chalk3.yellow("~") : chalk3.green("+");
2256
2092
  const desc = getDescription(rulePath);
2257
2093
  console.log(` ${icon} ${chalk3.bold(rulePath)}`);
2258
2094
  if (desc) {
@@ -2264,15 +2100,6 @@ function printSetupSummary(setup) {
2264
2100
  console.log("");
2265
2101
  }
2266
2102
  }
2267
- const mcpServers = cursor.mcpServers;
2268
- if (mcpServers && Object.keys(mcpServers).length > 0) {
2269
- const icon = fs18.existsSync(".cursor/mcp.json") ? chalk3.yellow("~") : chalk3.green("+");
2270
- const serverNames = Object.keys(mcpServers);
2271
- const desc = getDescription(".cursor/mcp.json");
2272
- console.log(` ${icon} ${chalk3.bold(".cursor/mcp.json")}`);
2273
- console.log(chalk3.dim(` ${desc || `servers: ${serverNames.join(", ")}`}`));
2274
- console.log("");
2275
- }
2276
2103
  }
2277
2104
  if (Array.isArray(deletions) && deletions.length > 0) {
2278
2105
  for (const del of deletions) {
@@ -2301,9 +2128,6 @@ function collectSetupFiles(setup) {
2301
2128
  files.push({ path: skillPath, content: skill.content });
2302
2129
  }
2303
2130
  }
2304
- if (claude.mcpServers && Object.keys(claude.mcpServers).length > 0) {
2305
- files.push({ path: ".mcp.json", content: JSON.stringify({ mcpServers: claude.mcpServers }, null, 2) });
2306
- }
2307
2131
  }
2308
2132
  if (cursor) {
2309
2133
  if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
@@ -2319,9 +2143,6 @@ function collectSetupFiles(setup) {
2319
2143
  files.push({ path: `.cursor/rules/${rule.filename}`, content: rule.content });
2320
2144
  }
2321
2145
  }
2322
- if (cursor.mcpServers && Object.keys(cursor.mcpServers).length > 0) {
2323
- files.push({ path: ".cursor/mcp.json", content: JSON.stringify({ mcpServers: cursor.mcpServers }, null, 2) });
2324
- }
2325
2146
  }
2326
2147
  return files;
2327
2148
  }
@@ -2361,6 +2182,150 @@ function undoCommand() {
2361
2182
  // src/commands/status.ts
2362
2183
  import chalk5 from "chalk";
2363
2184
  import fs19 from "fs";
2185
+
2186
+ // src/scanner/index.ts
2187
+ import fs18 from "fs";
2188
+ import path16 from "path";
2189
+ import crypto4 from "crypto";
2190
+ function scanLocalState(dir) {
2191
+ const items = [];
2192
+ const claudeMdPath = path16.join(dir, "CLAUDE.md");
2193
+ if (fs18.existsSync(claudeMdPath)) {
2194
+ items.push({
2195
+ type: "rule",
2196
+ platform: "claude",
2197
+ name: "CLAUDE.md",
2198
+ contentHash: hashFile(claudeMdPath),
2199
+ path: claudeMdPath
2200
+ });
2201
+ }
2202
+ const skillsDir = path16.join(dir, ".claude", "skills");
2203
+ if (fs18.existsSync(skillsDir)) {
2204
+ for (const file of fs18.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
2205
+ const filePath = path16.join(skillsDir, file);
2206
+ items.push({
2207
+ type: "skill",
2208
+ platform: "claude",
2209
+ name: file,
2210
+ contentHash: hashFile(filePath),
2211
+ path: filePath
2212
+ });
2213
+ }
2214
+ }
2215
+ const mcpJsonPath = path16.join(dir, ".mcp.json");
2216
+ if (fs18.existsSync(mcpJsonPath)) {
2217
+ try {
2218
+ const mcpJson = JSON.parse(fs18.readFileSync(mcpJsonPath, "utf-8"));
2219
+ if (mcpJson.mcpServers) {
2220
+ for (const name of Object.keys(mcpJson.mcpServers)) {
2221
+ items.push({
2222
+ type: "mcp",
2223
+ platform: "claude",
2224
+ name,
2225
+ contentHash: hashJson(mcpJson.mcpServers[name]),
2226
+ path: mcpJsonPath
2227
+ });
2228
+ }
2229
+ }
2230
+ } catch {
2231
+ }
2232
+ }
2233
+ const cursorrulesPath = path16.join(dir, ".cursorrules");
2234
+ if (fs18.existsSync(cursorrulesPath)) {
2235
+ items.push({
2236
+ type: "rule",
2237
+ platform: "cursor",
2238
+ name: ".cursorrules",
2239
+ contentHash: hashFile(cursorrulesPath),
2240
+ path: cursorrulesPath
2241
+ });
2242
+ }
2243
+ const cursorRulesDir = path16.join(dir, ".cursor", "rules");
2244
+ if (fs18.existsSync(cursorRulesDir)) {
2245
+ for (const file of fs18.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
2246
+ const filePath = path16.join(cursorRulesDir, file);
2247
+ items.push({
2248
+ type: "rule",
2249
+ platform: "cursor",
2250
+ name: file,
2251
+ contentHash: hashFile(filePath),
2252
+ path: filePath
2253
+ });
2254
+ }
2255
+ }
2256
+ const cursorSkillsDir = path16.join(dir, ".cursor", "skills");
2257
+ if (fs18.existsSync(cursorSkillsDir)) {
2258
+ try {
2259
+ for (const slug of fs18.readdirSync(cursorSkillsDir)) {
2260
+ const skillFile = path16.join(cursorSkillsDir, slug, "SKILL.md");
2261
+ if (fs18.existsSync(skillFile)) {
2262
+ items.push({
2263
+ type: "skill",
2264
+ platform: "cursor",
2265
+ name: `${slug}/SKILL.md`,
2266
+ contentHash: hashFile(skillFile),
2267
+ path: skillFile
2268
+ });
2269
+ }
2270
+ }
2271
+ } catch {
2272
+ }
2273
+ }
2274
+ const cursorMcpPath = path16.join(dir, ".cursor", "mcp.json");
2275
+ if (fs18.existsSync(cursorMcpPath)) {
2276
+ try {
2277
+ const mcpJson = JSON.parse(fs18.readFileSync(cursorMcpPath, "utf-8"));
2278
+ if (mcpJson.mcpServers) {
2279
+ for (const name of Object.keys(mcpJson.mcpServers)) {
2280
+ items.push({
2281
+ type: "mcp",
2282
+ platform: "cursor",
2283
+ name,
2284
+ contentHash: hashJson(mcpJson.mcpServers[name]),
2285
+ path: cursorMcpPath
2286
+ });
2287
+ }
2288
+ }
2289
+ } catch {
2290
+ }
2291
+ }
2292
+ return items;
2293
+ }
2294
+ function compareState(serverItems, localItems) {
2295
+ const installed = [];
2296
+ const missing = [];
2297
+ const outdated = [];
2298
+ const extra = [];
2299
+ const localMap = /* @__PURE__ */ new Map();
2300
+ for (const item of localItems) {
2301
+ localMap.set(`${item.type}:${item.platform}:${item.name}`, item);
2302
+ }
2303
+ for (const server of serverItems) {
2304
+ const key = `${server.type}:${server.platform}:${server.name}`;
2305
+ const local = localMap.get(key);
2306
+ localMap.delete(key);
2307
+ if (!local) {
2308
+ missing.push(server);
2309
+ } else if (local.contentHash !== server.content_hash) {
2310
+ outdated.push({ server, local });
2311
+ } else {
2312
+ installed.push({ server, local });
2313
+ }
2314
+ }
2315
+ for (const local of localMap.values()) {
2316
+ extra.push(local);
2317
+ }
2318
+ return { installed, missing, outdated, extra };
2319
+ }
2320
+ function hashFile(filePath) {
2321
+ const text = fs18.readFileSync(filePath, "utf-8");
2322
+ return crypto4.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
2323
+ }
2324
+ function hashJson(obj) {
2325
+ return crypto4.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
2326
+ }
2327
+
2328
+ // src/commands/status.ts
2364
2329
  async function statusCommand(options) {
2365
2330
  const auth2 = getStoredAuth();
2366
2331
  const manifest = readManifest();