@caliber-ai/cli 0.11.3 → 0.13.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
@@ -80,10 +80,11 @@ import path17 from "path";
80
80
  import { fileURLToPath as fileURLToPath3 } from "url";
81
81
 
82
82
  // src/commands/init.ts
83
- import chalk2 from "chalk";
83
+ import chalk3 from "chalk";
84
84
  import ora2 from "ora";
85
85
  import readline from "readline";
86
- import fs15 from "fs";
86
+ import select from "@inquirer/select";
87
+ import fs16 from "fs";
87
88
 
88
89
  // src/auth/token-store.ts
89
90
  init_constants();
@@ -598,6 +599,26 @@ function readExistingConfigs(dir) {
598
599
  } catch {
599
600
  }
600
601
  }
602
+ const mcpJsonPath = path7.join(dir, ".mcp.json");
603
+ if (fs6.existsSync(mcpJsonPath)) {
604
+ try {
605
+ const mcpJson = JSON.parse(fs6.readFileSync(mcpJsonPath, "utf-8"));
606
+ if (mcpJson.mcpServers) {
607
+ configs.claudeMcpServers = mcpJson.mcpServers;
608
+ }
609
+ } catch {
610
+ }
611
+ }
612
+ const cursorMcpPath = path7.join(dir, ".cursor", "mcp.json");
613
+ if (fs6.existsSync(cursorMcpPath)) {
614
+ try {
615
+ const cursorMcpJson = JSON.parse(fs6.readFileSync(cursorMcpPath, "utf-8"));
616
+ if (cursorMcpJson.mcpServers) {
617
+ configs.cursorMcpServers = cursorMcpJson.mcpServers;
618
+ }
619
+ } catch {
620
+ }
621
+ }
601
622
  return configs;
602
623
  }
603
624
 
@@ -899,6 +920,140 @@ function computeFingerprintHash(fingerprint) {
899
920
  return crypto2.createHash("sha256").update(key).digest("hex");
900
921
  }
901
922
 
923
+ // src/scanner/index.ts
924
+ import fs8 from "fs";
925
+ import path9 from "path";
926
+ import crypto3 from "crypto";
927
+ function scanLocalState(dir) {
928
+ const items = [];
929
+ const claudeMdPath = path9.join(dir, "CLAUDE.md");
930
+ if (fs8.existsSync(claudeMdPath)) {
931
+ items.push({
932
+ type: "rule",
933
+ platform: "claude",
934
+ name: "CLAUDE.md",
935
+ contentHash: hashFile(claudeMdPath),
936
+ path: claudeMdPath
937
+ });
938
+ }
939
+ const settingsPath = path9.join(dir, ".claude", "settings.json");
940
+ if (fs8.existsSync(settingsPath)) {
941
+ items.push({
942
+ type: "config",
943
+ platform: "claude",
944
+ name: "settings.json",
945
+ contentHash: hashFile(settingsPath),
946
+ path: settingsPath
947
+ });
948
+ }
949
+ const skillsDir = path9.join(dir, ".claude", "skills");
950
+ if (fs8.existsSync(skillsDir)) {
951
+ for (const file of fs8.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
952
+ const filePath = path9.join(skillsDir, file);
953
+ items.push({
954
+ type: "skill",
955
+ platform: "claude",
956
+ name: file,
957
+ contentHash: hashFile(filePath),
958
+ path: filePath
959
+ });
960
+ }
961
+ }
962
+ const mcpJsonPath = path9.join(dir, ".mcp.json");
963
+ if (fs8.existsSync(mcpJsonPath)) {
964
+ try {
965
+ const mcpJson = JSON.parse(fs8.readFileSync(mcpJsonPath, "utf-8"));
966
+ if (mcpJson.mcpServers) {
967
+ for (const name of Object.keys(mcpJson.mcpServers)) {
968
+ items.push({
969
+ type: "mcp",
970
+ platform: "claude",
971
+ name,
972
+ contentHash: hashContent(JSON.stringify(mcpJson.mcpServers[name])),
973
+ path: mcpJsonPath
974
+ });
975
+ }
976
+ }
977
+ } catch {
978
+ }
979
+ }
980
+ const cursorrulesPath = path9.join(dir, ".cursorrules");
981
+ if (fs8.existsSync(cursorrulesPath)) {
982
+ items.push({
983
+ type: "rule",
984
+ platform: "cursor",
985
+ name: ".cursorrules",
986
+ contentHash: hashFile(cursorrulesPath),
987
+ path: cursorrulesPath
988
+ });
989
+ }
990
+ const cursorRulesDir = path9.join(dir, ".cursor", "rules");
991
+ if (fs8.existsSync(cursorRulesDir)) {
992
+ for (const file of fs8.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
993
+ const filePath = path9.join(cursorRulesDir, file);
994
+ items.push({
995
+ type: "rule",
996
+ platform: "cursor",
997
+ name: file,
998
+ contentHash: hashFile(filePath),
999
+ path: filePath
1000
+ });
1001
+ }
1002
+ }
1003
+ const cursorMcpPath = path9.join(dir, ".cursor", "mcp.json");
1004
+ if (fs8.existsSync(cursorMcpPath)) {
1005
+ try {
1006
+ const mcpJson = JSON.parse(fs8.readFileSync(cursorMcpPath, "utf-8"));
1007
+ if (mcpJson.mcpServers) {
1008
+ for (const name of Object.keys(mcpJson.mcpServers)) {
1009
+ items.push({
1010
+ type: "mcp",
1011
+ platform: "cursor",
1012
+ name,
1013
+ contentHash: hashContent(JSON.stringify(mcpJson.mcpServers[name])),
1014
+ path: cursorMcpPath
1015
+ });
1016
+ }
1017
+ }
1018
+ } catch {
1019
+ }
1020
+ }
1021
+ return items;
1022
+ }
1023
+ function compareState(serverItems, localItems) {
1024
+ const installed = [];
1025
+ const missing = [];
1026
+ const outdated = [];
1027
+ const extra = [];
1028
+ const localMap = /* @__PURE__ */ new Map();
1029
+ for (const item of localItems) {
1030
+ localMap.set(`${item.type}:${item.platform}:${item.name}`, item);
1031
+ }
1032
+ for (const server of serverItems) {
1033
+ const key = `${server.type}:${server.platform}:${server.name}`;
1034
+ const local = localMap.get(key);
1035
+ localMap.delete(key);
1036
+ if (!local) {
1037
+ missing.push(server);
1038
+ } else if (local.contentHash !== server.content_hash) {
1039
+ outdated.push({ server, local });
1040
+ } else {
1041
+ installed.push({ server, local });
1042
+ }
1043
+ }
1044
+ for (const local of localMap.values()) {
1045
+ extra.push(local);
1046
+ }
1047
+ return { installed, missing, outdated, extra };
1048
+ }
1049
+ function hashFile(filePath) {
1050
+ const content = fs8.readFileSync(filePath);
1051
+ return crypto3.createHash("sha256").update(content).digest("hex");
1052
+ }
1053
+ function hashContent(content) {
1054
+ return crypto3.createHash("sha256").update(JSON.stringify({ text: content })).digest("hex");
1055
+ }
1056
+
902
1057
  // src/api/client.ts
903
1058
  init_constants();
904
1059
  async function forceRefreshToken() {
@@ -1021,132 +1176,150 @@ async function apiStream(path19, body, onChunk, onComplete, onError, onStatus) {
1021
1176
  }
1022
1177
 
1023
1178
  // src/writers/index.ts
1024
- import fs12 from "fs";
1179
+ import fs13 from "fs";
1025
1180
 
1026
1181
  // src/writers/claude/index.ts
1027
- import fs8 from "fs";
1028
- import path9 from "path";
1182
+ import fs9 from "fs";
1183
+ import path10 from "path";
1029
1184
  function writeClaudeConfig(config) {
1030
1185
  const written = [];
1031
- fs8.writeFileSync("CLAUDE.md", config.claudeMd);
1186
+ fs9.writeFileSync("CLAUDE.md", config.claudeMd);
1032
1187
  written.push("CLAUDE.md");
1033
1188
  const claudeDir = ".claude";
1034
- if (!fs8.existsSync(claudeDir)) fs8.mkdirSync(claudeDir, { recursive: true });
1035
- fs8.writeFileSync(
1036
- path9.join(claudeDir, "settings.json"),
1189
+ if (!fs9.existsSync(claudeDir)) fs9.mkdirSync(claudeDir, { recursive: true });
1190
+ fs9.writeFileSync(
1191
+ path10.join(claudeDir, "settings.json"),
1037
1192
  JSON.stringify(config.settings, null, 2)
1038
1193
  );
1039
- written.push(path9.join(claudeDir, "settings.json"));
1040
- fs8.writeFileSync(
1041
- path9.join(claudeDir, "settings.local.json"),
1194
+ written.push(path10.join(claudeDir, "settings.json"));
1195
+ fs9.writeFileSync(
1196
+ path10.join(claudeDir, "settings.local.json"),
1042
1197
  JSON.stringify(config.settingsLocal, null, 2)
1043
1198
  );
1044
- written.push(path9.join(claudeDir, "settings.local.json"));
1199
+ written.push(path10.join(claudeDir, "settings.local.json"));
1045
1200
  if (config.skills?.length) {
1046
- const skillsDir = path9.join(claudeDir, "skills");
1047
- if (!fs8.existsSync(skillsDir)) fs8.mkdirSync(skillsDir, { recursive: true });
1201
+ const skillsDir = path10.join(claudeDir, "skills");
1202
+ if (!fs9.existsSync(skillsDir)) fs9.mkdirSync(skillsDir, { recursive: true });
1048
1203
  for (const skill of config.skills) {
1049
1204
  const filename = `${skill.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}.md`;
1050
- const skillPath = path9.join(skillsDir, filename);
1051
- fs8.writeFileSync(skillPath, skill.content);
1205
+ const skillPath = path10.join(skillsDir, filename);
1206
+ fs9.writeFileSync(skillPath, skill.content);
1052
1207
  written.push(skillPath);
1053
1208
  }
1054
1209
  }
1055
1210
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
1056
- const mcpConfig = { mcpServers: config.mcpServers };
1057
- fs8.writeFileSync(".mcp.json", JSON.stringify(mcpConfig, null, 2));
1211
+ let existingServers = {};
1212
+ try {
1213
+ if (fs9.existsSync(".mcp.json")) {
1214
+ const existing = JSON.parse(fs9.readFileSync(".mcp.json", "utf-8"));
1215
+ if (existing.mcpServers) {
1216
+ existingServers = existing.mcpServers;
1217
+ }
1218
+ }
1219
+ } catch {
1220
+ }
1221
+ const mergedServers = { ...existingServers, ...config.mcpServers };
1222
+ fs9.writeFileSync(".mcp.json", JSON.stringify({ mcpServers: mergedServers }, null, 2));
1058
1223
  written.push(".mcp.json");
1059
1224
  }
1060
1225
  return written;
1061
1226
  }
1062
1227
 
1063
1228
  // src/writers/cursor/index.ts
1064
- import fs9 from "fs";
1065
- import path10 from "path";
1229
+ import fs10 from "fs";
1230
+ import path11 from "path";
1066
1231
  function writeCursorConfig(config) {
1067
1232
  const written = [];
1068
1233
  if (config.cursorrules) {
1069
- fs9.writeFileSync(".cursorrules", config.cursorrules);
1234
+ fs10.writeFileSync(".cursorrules", config.cursorrules);
1070
1235
  written.push(".cursorrules");
1071
1236
  }
1072
1237
  if (config.rules?.length) {
1073
- const rulesDir = path10.join(".cursor", "rules");
1074
- if (!fs9.existsSync(rulesDir)) fs9.mkdirSync(rulesDir, { recursive: true });
1238
+ const rulesDir = path11.join(".cursor", "rules");
1239
+ if (!fs10.existsSync(rulesDir)) fs10.mkdirSync(rulesDir, { recursive: true });
1075
1240
  for (const rule of config.rules) {
1076
- const rulePath = path10.join(rulesDir, rule.filename);
1077
- fs9.writeFileSync(rulePath, rule.content);
1241
+ const rulePath = path11.join(rulesDir, rule.filename);
1242
+ fs10.writeFileSync(rulePath, rule.content);
1078
1243
  written.push(rulePath);
1079
1244
  }
1080
1245
  }
1081
1246
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
1082
1247
  const cursorDir = ".cursor";
1083
- if (!fs9.existsSync(cursorDir)) fs9.mkdirSync(cursorDir, { recursive: true });
1084
- const mcpConfig = { mcpServers: config.mcpServers };
1085
- fs9.writeFileSync(
1086
- path10.join(cursorDir, "mcp.json"),
1087
- JSON.stringify(mcpConfig, null, 2)
1088
- );
1089
- written.push(path10.join(cursorDir, "mcp.json"));
1248
+ if (!fs10.existsSync(cursorDir)) fs10.mkdirSync(cursorDir, { recursive: true });
1249
+ const mcpPath = path11.join(cursorDir, "mcp.json");
1250
+ let existingServers = {};
1251
+ try {
1252
+ if (fs10.existsSync(mcpPath)) {
1253
+ const existing = JSON.parse(fs10.readFileSync(mcpPath, "utf-8"));
1254
+ if (existing.mcpServers) {
1255
+ existingServers = existing.mcpServers;
1256
+ }
1257
+ }
1258
+ } catch {
1259
+ }
1260
+ const mergedServers = { ...existingServers, ...config.mcpServers };
1261
+ fs10.writeFileSync(mcpPath, JSON.stringify({ mcpServers: mergedServers }, null, 2));
1262
+ written.push(mcpPath);
1090
1263
  }
1091
1264
  return written;
1092
1265
  }
1093
1266
 
1094
1267
  // src/writers/backup.ts
1095
1268
  init_constants();
1096
- import fs10 from "fs";
1097
- import path11 from "path";
1269
+ import fs11 from "fs";
1270
+ import path12 from "path";
1098
1271
  function createBackup(files) {
1099
1272
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1100
- const backupDir = path11.join(BACKUPS_DIR, timestamp);
1273
+ const backupDir = path12.join(BACKUPS_DIR, timestamp);
1101
1274
  for (const file of files) {
1102
- if (!fs10.existsSync(file)) continue;
1103
- const dest = path11.join(backupDir, file);
1104
- const destDir = path11.dirname(dest);
1105
- if (!fs10.existsSync(destDir)) {
1106
- fs10.mkdirSync(destDir, { recursive: true });
1275
+ if (!fs11.existsSync(file)) continue;
1276
+ const dest = path12.join(backupDir, file);
1277
+ const destDir = path12.dirname(dest);
1278
+ if (!fs11.existsSync(destDir)) {
1279
+ fs11.mkdirSync(destDir, { recursive: true });
1107
1280
  }
1108
- fs10.copyFileSync(file, dest);
1281
+ fs11.copyFileSync(file, dest);
1109
1282
  }
1110
1283
  return backupDir;
1111
1284
  }
1112
1285
  function restoreBackup(backupDir, file) {
1113
- const backupFile = path11.join(backupDir, file);
1114
- if (!fs10.existsSync(backupFile)) return false;
1115
- const destDir = path11.dirname(file);
1116
- if (!fs10.existsSync(destDir)) {
1117
- fs10.mkdirSync(destDir, { recursive: true });
1286
+ const backupFile = path12.join(backupDir, file);
1287
+ if (!fs11.existsSync(backupFile)) return false;
1288
+ const destDir = path12.dirname(file);
1289
+ if (!fs11.existsSync(destDir)) {
1290
+ fs11.mkdirSync(destDir, { recursive: true });
1118
1291
  }
1119
- fs10.copyFileSync(backupFile, file);
1292
+ fs11.copyFileSync(backupFile, file);
1120
1293
  return true;
1121
1294
  }
1122
1295
 
1123
1296
  // src/writers/manifest.ts
1124
1297
  init_constants();
1125
- import fs11 from "fs";
1126
- import crypto3 from "crypto";
1298
+ import fs12 from "fs";
1299
+ import crypto4 from "crypto";
1127
1300
  function readManifest() {
1128
1301
  try {
1129
- if (!fs11.existsSync(MANIFEST_FILE)) return null;
1130
- return JSON.parse(fs11.readFileSync(MANIFEST_FILE, "utf-8"));
1302
+ if (!fs12.existsSync(MANIFEST_FILE)) return null;
1303
+ return JSON.parse(fs12.readFileSync(MANIFEST_FILE, "utf-8"));
1131
1304
  } catch {
1132
1305
  return null;
1133
1306
  }
1134
1307
  }
1135
1308
  function writeManifest(manifest) {
1136
- if (!fs11.existsSync(CALIBER_DIR)) {
1137
- fs11.mkdirSync(CALIBER_DIR, { recursive: true });
1309
+ if (!fs12.existsSync(CALIBER_DIR)) {
1310
+ fs12.mkdirSync(CALIBER_DIR, { recursive: true });
1138
1311
  }
1139
- fs11.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
1312
+ fs12.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
1140
1313
  }
1141
1314
  function fileChecksum(filePath) {
1142
- const content = fs11.readFileSync(filePath);
1143
- return crypto3.createHash("sha256").update(content).digest("hex");
1315
+ const content = fs12.readFileSync(filePath);
1316
+ return crypto4.createHash("sha256").update(content).digest("hex");
1144
1317
  }
1145
1318
 
1146
1319
  // src/writers/index.ts
1147
1320
  function writeSetup(setup) {
1148
1321
  const filesToWrite = getFilesToWrite(setup);
1149
- const existingFiles = filesToWrite.filter((f) => fs12.existsSync(f));
1322
+ const existingFiles = filesToWrite.filter((f) => fs13.existsSync(f));
1150
1323
  const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
1151
1324
  const written = [];
1152
1325
  if ((setup.targetAgent === "claude" || setup.targetAgent === "both") && setup.claude) {
@@ -1174,8 +1347,8 @@ function undoSetup() {
1174
1347
  const removed = [];
1175
1348
  for (const entry of manifest.entries) {
1176
1349
  if (entry.action === "created") {
1177
- if (fs12.existsSync(entry.path)) {
1178
- fs12.unlinkSync(entry.path);
1350
+ if (fs13.existsSync(entry.path)) {
1351
+ fs13.unlinkSync(entry.path);
1179
1352
  removed.push(entry.path);
1180
1353
  }
1181
1354
  } else if (entry.action === "modified" && manifest.backupDir) {
@@ -1185,8 +1358,8 @@ function undoSetup() {
1185
1358
  }
1186
1359
  }
1187
1360
  const { MANIFEST_FILE: MANIFEST_FILE2 } = (init_constants(), __toCommonJS(constants_exports));
1188
- if (fs12.existsSync(MANIFEST_FILE2)) {
1189
- fs12.unlinkSync(MANIFEST_FILE2);
1361
+ if (fs13.existsSync(MANIFEST_FILE2)) {
1362
+ fs13.unlinkSync(MANIFEST_FILE2);
1190
1363
  }
1191
1364
  return { restored, removed };
1192
1365
  }
@@ -1212,34 +1385,34 @@ function getFilesToWrite(setup) {
1212
1385
  }
1213
1386
  function ensureGitignore() {
1214
1387
  const gitignorePath = ".gitignore";
1215
- if (fs12.existsSync(gitignorePath)) {
1216
- const content = fs12.readFileSync(gitignorePath, "utf-8");
1388
+ if (fs13.existsSync(gitignorePath)) {
1389
+ const content = fs13.readFileSync(gitignorePath, "utf-8");
1217
1390
  if (!content.includes(".caliber/")) {
1218
- fs12.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
1391
+ fs13.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
1219
1392
  }
1220
1393
  } else {
1221
- fs12.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
1394
+ fs13.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
1222
1395
  }
1223
1396
  }
1224
1397
 
1225
1398
  // src/lib/hooks.ts
1226
- import fs13 from "fs";
1227
- import path12 from "path";
1228
- var SETTINGS_PATH = path12.join(".claude", "settings.json");
1399
+ import fs14 from "fs";
1400
+ import path13 from "path";
1401
+ var SETTINGS_PATH = path13.join(".claude", "settings.json");
1229
1402
  var HOOK_COMMAND = "caliber refresh --quiet";
1230
1403
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
1231
1404
  function readSettings() {
1232
- if (!fs13.existsSync(SETTINGS_PATH)) return {};
1405
+ if (!fs14.existsSync(SETTINGS_PATH)) return {};
1233
1406
  try {
1234
- return JSON.parse(fs13.readFileSync(SETTINGS_PATH, "utf-8"));
1407
+ return JSON.parse(fs14.readFileSync(SETTINGS_PATH, "utf-8"));
1235
1408
  } catch {
1236
1409
  return {};
1237
1410
  }
1238
1411
  }
1239
1412
  function writeSettings(settings) {
1240
- const dir = path12.dirname(SETTINGS_PATH);
1241
- if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
1242
- fs13.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
1413
+ const dir = path13.dirname(SETTINGS_PATH);
1414
+ if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
1415
+ fs14.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
1243
1416
  }
1244
1417
  function findHookIndex(sessionEnd) {
1245
1418
  return sessionEnd.findIndex(
@@ -1289,23 +1462,23 @@ function removeHook() {
1289
1462
 
1290
1463
  // src/lib/state.ts
1291
1464
  init_constants();
1292
- import fs14 from "fs";
1293
- import path13 from "path";
1465
+ import fs15 from "fs";
1466
+ import path14 from "path";
1294
1467
  import { execSync as execSync2 } from "child_process";
1295
- var STATE_FILE = path13.join(CALIBER_DIR, ".caliber-state.json");
1468
+ var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
1296
1469
  function readState() {
1297
1470
  try {
1298
- if (!fs14.existsSync(STATE_FILE)) return null;
1299
- return JSON.parse(fs14.readFileSync(STATE_FILE, "utf-8"));
1471
+ if (!fs15.existsSync(STATE_FILE)) return null;
1472
+ return JSON.parse(fs15.readFileSync(STATE_FILE, "utf-8"));
1300
1473
  } catch {
1301
1474
  return null;
1302
1475
  }
1303
1476
  }
1304
1477
  function writeState(state) {
1305
- if (!fs14.existsSync(CALIBER_DIR)) {
1306
- fs14.mkdirSync(CALIBER_DIR, { recursive: true });
1478
+ if (!fs15.existsSync(CALIBER_DIR)) {
1479
+ fs15.mkdirSync(CALIBER_DIR, { recursive: true });
1307
1480
  }
1308
- fs14.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
1481
+ fs15.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
1309
1482
  }
1310
1483
  function getCurrentHeadSha() {
1311
1484
  try {
@@ -1319,6 +1492,7 @@ function getCurrentHeadSha() {
1319
1492
  }
1320
1493
 
1321
1494
  // src/utils/spinner-messages.ts
1495
+ import chalk2 from "chalk";
1322
1496
  var GENERATION_MESSAGES = [
1323
1497
  "Analyzing your project structure and dependencies...",
1324
1498
  "Mapping out build commands and test workflows...",
@@ -1344,25 +1518,46 @@ var SpinnerMessages = class {
1344
1518
  messages;
1345
1519
  index = 0;
1346
1520
  timer = null;
1347
- constructor(spinner, messages) {
1521
+ startTime = 0;
1522
+ showElapsedTime;
1523
+ currentBaseMessage = "";
1524
+ constructor(spinner, messages, options) {
1348
1525
  this.spinner = spinner;
1349
1526
  this.messages = messages;
1527
+ this.showElapsedTime = options?.showElapsedTime ?? false;
1528
+ }
1529
+ formatElapsed() {
1530
+ const seconds = Math.floor((Date.now() - this.startTime) / 1e3);
1531
+ const mins = Math.floor(seconds / 60);
1532
+ const secs = seconds % 60;
1533
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
1534
+ }
1535
+ updateSpinnerText() {
1536
+ this.spinner.text = this.currentBaseMessage;
1350
1537
  }
1351
1538
  start() {
1352
1539
  this.index = 0;
1353
- this.spinner.text = this.messages[0];
1540
+ this.startTime = Date.now();
1541
+ this.currentBaseMessage = this.messages[0];
1542
+ this.updateSpinnerText();
1543
+ if (this.showElapsedTime) {
1544
+ this.spinner.suffixText = () => chalk2.dim(`(${this.formatElapsed()})`);
1545
+ }
1354
1546
  this.timer = setInterval(() => {
1355
1547
  this.index = (this.index + 1) % this.messages.length;
1356
- this.spinner.text = this.messages[this.index];
1548
+ this.currentBaseMessage = this.messages[this.index];
1549
+ this.updateSpinnerText();
1357
1550
  }, 3e3);
1358
1551
  }
1359
1552
  handleServerStatus(status) {
1360
- this.spinner.text = status;
1553
+ this.currentBaseMessage = status;
1554
+ this.updateSpinnerText();
1361
1555
  if (this.timer) {
1362
1556
  clearInterval(this.timer);
1363
1557
  this.timer = setInterval(() => {
1364
1558
  this.index = (this.index + 1) % this.messages.length;
1365
- this.spinner.text = this.messages[this.index];
1559
+ this.currentBaseMessage = this.messages[this.index];
1560
+ this.updateSpinnerText();
1366
1561
  }, 3e3);
1367
1562
  }
1368
1563
  }
@@ -1371,12 +1566,13 @@ var SpinnerMessages = class {
1371
1566
  clearInterval(this.timer);
1372
1567
  this.timer = null;
1373
1568
  }
1569
+ this.spinner.suffixText = "";
1374
1570
  }
1375
1571
  };
1376
1572
 
1377
1573
  // src/commands/init.ts
1378
1574
  async function initCommand(options) {
1379
- console.log(chalk2.bold.hex("#6366f1")(`
1575
+ console.log(chalk3.bold.hex("#6366f1")(`
1380
1576
  \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
1381
1577
  \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
1382
1578
  \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
@@ -1384,34 +1580,34 @@ async function initCommand(options) {
1384
1580
  \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551
1385
1581
  \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
1386
1582
  `));
1387
- console.log(chalk2.dim(" Configure your coding agent environment\n"));
1388
- console.log(chalk2.bold(" What is Caliber?\n"));
1389
- console.log(chalk2.dim(" Caliber analyzes your project and generates optimized configurations"));
1390
- console.log(chalk2.dim(" for AI coding agents (Claude Code, Cursor). It creates CLAUDE.md,"));
1391
- console.log(chalk2.dim(" .cursorrules, skills, permissions, and MCP servers tailored to your"));
1392
- console.log(chalk2.dim(" codebase \u2014 so your AI agent understands your project from day one.\n"));
1393
- console.log(chalk2.bold(" How it works:\n"));
1394
- console.log(chalk2.dim(" 1. Scan Analyze your code, dependencies, and file structure"));
1395
- console.log(chalk2.dim(" 2. Match Check if a teammate already configured this project"));
1396
- console.log(chalk2.dim(" 3. Generate AI creates config files tailored to your project"));
1397
- console.log(chalk2.dim(" 4. Review You accept, refine, or decline the generated setup"));
1398
- console.log(chalk2.dim(" 5. Apply Config files are written to your project"));
1399
- console.log(chalk2.dim(" 6. Sync Setup is saved so teammates get the same config\n"));
1400
- console.log(chalk2.hex("#6366f1").bold(" Step 1/6 \u2014 Authenticate\n"));
1583
+ console.log(chalk3.dim(" Configure your coding agent environment\n"));
1584
+ 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"));
1589
+ console.log(chalk3.bold(" How it works:\n"));
1590
+ console.log(chalk3.dim(" 1. Scan Analyze your code, dependencies, and file structure"));
1591
+ console.log(chalk3.dim(" 2. Match Detect existing configs and check for teammate setups"));
1592
+ console.log(chalk3.dim(" 3. Generate AI creates config files tailored to your project"));
1593
+ console.log(chalk3.dim(" 4. Review You accept, refine, or decline the generated setup"));
1594
+ console.log(chalk3.dim(" 5. Apply Config files are written to your project"));
1595
+ console.log(chalk3.dim(" 6. Sync Setup is saved so teammates get the same config\n"));
1596
+ console.log(chalk3.hex("#6366f1").bold(" Step 1/6 \u2014 Authenticate\n"));
1401
1597
  let auth2 = getStoredAuth();
1402
1598
  if (!auth2) {
1403
- console.log(chalk2.yellow("Not logged in. Starting authentication...\n"));
1599
+ console.log(chalk3.yellow("Not logged in. Starting authentication...\n"));
1404
1600
  await loginCommand();
1405
1601
  auth2 = getStoredAuth();
1406
1602
  if (!auth2) {
1407
- console.log(chalk2.red("Authentication required. Exiting."));
1603
+ console.log(chalk3.red("Authentication required. Exiting."));
1408
1604
  throw new Error("__exit__");
1409
1605
  }
1410
1606
  }
1411
- console.log(chalk2.dim(`Authenticated as ${auth2.email}
1607
+ console.log(chalk3.dim(`Authenticated as ${auth2.email}
1412
1608
  `));
1413
- console.log(chalk2.hex("#6366f1").bold(" Step 2/6 \u2014 Scan project\n"));
1414
- console.log(chalk2.dim(" Detecting languages, frameworks, file structure, and existing configs.\n"));
1609
+ console.log(chalk3.hex("#6366f1").bold(" Step 2/6 \u2014 Scan project\n"));
1610
+ console.log(chalk3.dim(" Detecting languages, frameworks, file structure, and existing configs.\n"));
1415
1611
  const spinner = ora2("Analyzing project...").start();
1416
1612
  const fingerprint = collectFingerprint(process.cwd());
1417
1613
  const hash = computeFingerprintHash(fingerprint);
@@ -1425,17 +1621,46 @@ async function initCommand(options) {
1425
1621
  has_cursorrules: !!fingerprint.existingConfigs.cursorrules,
1426
1622
  cursor_rules_count: fingerprint.existingConfigs.cursorRules?.length ?? 0,
1427
1623
  skills_count: fingerprint.existingConfigs.claudeSkills?.length ?? 0,
1624
+ has_claude_mcp_servers: !!fingerprint.existingConfigs.claudeMcpServers,
1625
+ has_cursor_mcp_servers: !!fingerprint.existingConfigs.cursorMcpServers,
1626
+ claude_mcp_server_count: fingerprint.existingConfigs.claudeMcpServers ? Object.keys(fingerprint.existingConfigs.claudeMcpServers).length : 0,
1627
+ cursor_mcp_server_count: fingerprint.existingConfigs.cursorMcpServers ? Object.keys(fingerprint.existingConfigs.cursorMcpServers).length : 0,
1428
1628
  file_count: fingerprint.fileTree.length
1429
1629
  });
1430
- console.log(chalk2.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
1431
- console.log(chalk2.dim(` Frameworks: ${fingerprint.frameworks.join(", ") || "none detected"}`));
1432
- console.log(chalk2.dim(` Files: ${fingerprint.fileTree.length} found
1630
+ console.log(chalk3.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
1631
+ console.log(chalk3.dim(` Frameworks: ${fingerprint.frameworks.join(", ") || "none detected"}`));
1632
+ console.log(chalk3.dim(` Files: ${fingerprint.fileTree.length} found
1433
1633
  `));
1434
- console.log(chalk2.hex("#6366f1").bold(" Step 3/6 \u2014 Match project\n"));
1435
- console.log(chalk2.dim(" Checking if a teammate already set up Caliber for this repo.\n"));
1436
- const matchSpinner = ora2("Checking for existing setup...").start();
1634
+ console.log(chalk3.hex("#6366f1").bold(" Step 3/6 \u2014 Match project\n"));
1635
+ console.log(chalk3.dim(" Scanning for existing rules, skills, MCP servers, and teammate setups.\n"));
1636
+ const matchSpinner = ora2("Scanning for existing setup...").start();
1637
+ const localConfigs = [];
1638
+ const ec = fingerprint.existingConfigs;
1639
+ if (ec.claudeMd) localConfigs.push("CLAUDE.md");
1640
+ if (ec.claudeSettings) localConfigs.push(".claude/settings.json");
1641
+ if (Array.isArray(ec.claudeSkills)) {
1642
+ for (const skill of ec.claudeSkills) {
1643
+ localConfigs.push(`.claude/skills/${skill.filename}`);
1644
+ }
1645
+ }
1646
+ if (ec.cursorrules) localConfigs.push(".cursorrules");
1647
+ if (Array.isArray(ec.cursorRules)) {
1648
+ for (const rule of ec.cursorRules) {
1649
+ localConfigs.push(`.cursor/rules/${rule.filename}`);
1650
+ }
1651
+ }
1652
+ const localState = scanLocalState(process.cwd());
1653
+ const claudeMcpServers = localState.filter((i) => i.type === "mcp" && i.platform === "claude").map((i) => i.name);
1654
+ const cursorMcpServers = localState.filter((i) => i.type === "mcp" && i.platform === "cursor").map((i) => i.name);
1655
+ if (claudeMcpServers.length > 0) {
1656
+ localConfigs.push(`.mcp.json (${claudeMcpServers.join(", ")} \u2014 will merge)`);
1657
+ }
1658
+ if (cursorMcpServers.length > 0) {
1659
+ localConfigs.push(`.cursor/mcp.json (${cursorMcpServers.join(", ")} \u2014 will merge)`);
1660
+ }
1437
1661
  let existingSetup = null;
1438
1662
  let existingProjectId = null;
1663
+ let hasTeammateSetup = false;
1439
1664
  try {
1440
1665
  const match = await apiRequest("/api/projects/match", {
1441
1666
  method: "POST",
@@ -1446,34 +1671,50 @@ async function initCommand(options) {
1446
1671
  }
1447
1672
  if (match.setup) {
1448
1673
  existingSetup = match.setup;
1674
+ hasTeammateSetup = true;
1449
1675
  trackEvent("existing_config_detected", {
1450
1676
  has_claude_md: !!fingerprint.existingConfigs.claudeMd,
1451
1677
  has_cursorrules: !!fingerprint.existingConfigs.cursorrules,
1452
1678
  has_cursor_rules: (fingerprint.existingConfigs.cursorRules?.length ?? 0) > 0,
1453
1679
  has_skills: (fingerprint.existingConfigs.claudeSkills?.length ?? 0) > 0
1454
1680
  });
1455
- matchSpinner.succeed("Found existing setup");
1456
- } else {
1457
- matchSpinner.info("No existing setup found");
1458
1681
  }
1459
1682
  } catch {
1460
- matchSpinner.info("No existing setup found");
1461
1683
  }
1684
+ matchSpinner.stop();
1685
+ console.log(chalk3.dim(" Local configs:"));
1686
+ if (localConfigs.length > 0) {
1687
+ for (const config of localConfigs) {
1688
+ console.log(` ${chalk3.green("\u2713")} ${config}`);
1689
+ }
1690
+ } else {
1691
+ console.log(` ${chalk3.dim("\u2139 None found")}`);
1692
+ }
1693
+ console.log("");
1694
+ console.log(chalk3.dim(" Teammate setup:"));
1695
+ if (hasTeammateSetup) {
1696
+ console.log(` ${chalk3.green("\u2713")} Found on Caliber`);
1697
+ } else {
1698
+ console.log(` ${chalk3.dim("\u2139 None found")}`);
1699
+ }
1700
+ console.log("");
1462
1701
  const targetAgent = options.agent || await promptAgent();
1463
1702
  trackEvent("target_agent_selected", { target_agent: targetAgent });
1464
1703
  const isEmpty = fingerprint.fileTree.length < 3;
1465
1704
  if (isEmpty) {
1466
1705
  fingerprint.description = await promptInput("What will you build in this project?");
1467
1706
  }
1468
- console.log(chalk2.hex("#6366f1").bold(" Step 4/6 \u2014 Generate config\n"));
1469
- console.log(chalk2.dim(" AI is building CLAUDE.md, permissions, skills, and rules based on"));
1470
- console.log(chalk2.dim(" your project's stack and conventions.\n"));
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.dim(" This usually takes 1\u20133 minutes on first run.\n"));
1471
1711
  let generatedSetup = null;
1472
1712
  let setupExplanation;
1473
1713
  let rawOutput;
1474
1714
  trackEvent("generation_started", { target_agent: targetAgent });
1715
+ const hasExistingConfig = !!(ec.claudeMd || ec.claudeSettings || ec.claudeSkills?.length || ec.cursorrules || ec.cursorRules?.length || ec.claudeMcpServers || ec.cursorMcpServers);
1475
1716
  const genSpinner = ora2("Generating setup...").start();
1476
- const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES);
1717
+ const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
1477
1718
  genMessages.start();
1478
1719
  try {
1479
1720
  await apiStream(
@@ -1481,7 +1722,8 @@ async function initCommand(options) {
1481
1722
  {
1482
1723
  fingerprint,
1483
1724
  targetAgent,
1484
- prompt: fingerprint.description
1725
+ prompt: fingerprint.description,
1726
+ mode: hasExistingConfig ? "improve" : "create"
1485
1727
  },
1486
1728
  () => {
1487
1729
  },
@@ -1510,45 +1752,45 @@ async function initCommand(options) {
1510
1752
  if (!generatedSetup) {
1511
1753
  genSpinner.fail("Failed to generate setup.");
1512
1754
  if (rawOutput) {
1513
- console.log(chalk2.dim("\nRaw LLM output (JSON parse failed):"));
1514
- console.log(chalk2.dim(rawOutput.slice(0, 500)));
1755
+ console.log(chalk3.dim("\nRaw LLM output (JSON parse failed):"));
1756
+ console.log(chalk3.dim(rawOutput.slice(0, 500)));
1515
1757
  }
1516
1758
  throw new Error("__exit__");
1517
1759
  }
1518
1760
  genSpinner.succeed("Setup generated");
1519
1761
  printSetupSummary(generatedSetup);
1520
- console.log(chalk2.hex("#6366f1").bold(" Step 5/6 \u2014 Review\n"));
1521
- console.log(chalk2.dim(" Review the proposed files below. You can accept, refine via chat,"));
1522
- console.log(chalk2.dim(" or see an explanation of why each item was recommended.\n"));
1762
+ console.log(chalk3.hex("#6366f1").bold(" Step 5/6 \u2014 Review\n"));
1763
+ console.log(chalk3.dim(" Review the proposed files below. You can accept, refine via chat,"));
1764
+ console.log(chalk3.dim(" or see an explanation of why each item was recommended.\n"));
1523
1765
  let explained = false;
1524
1766
  let action = await promptAction(explained);
1525
1767
  while (action === "explain") {
1526
1768
  if (setupExplanation) {
1527
1769
  printExplanation(setupExplanation);
1528
1770
  } else {
1529
- console.log(chalk2.dim("\nNo explanation available for this setup.\n"));
1771
+ console.log(chalk3.dim("\nNo explanation available for this setup.\n"));
1530
1772
  }
1531
1773
  explained = true;
1532
1774
  action = await promptAction(explained);
1533
1775
  }
1534
1776
  if (action === "decline") {
1535
1777
  trackEvent("setup_declined");
1536
- console.log(chalk2.dim("Setup declined. No files were modified."));
1778
+ console.log(chalk3.dim("Setup declined. No files were modified."));
1537
1779
  return;
1538
1780
  }
1539
1781
  if (action === "refine") {
1540
1782
  generatedSetup = await refineLoop(generatedSetup, targetAgent);
1541
1783
  if (!generatedSetup) {
1542
1784
  trackEvent("refinement_cancelled");
1543
- console.log(chalk2.dim("Refinement cancelled. No files were modified."));
1785
+ console.log(chalk3.dim("Refinement cancelled. No files were modified."));
1544
1786
  return;
1545
1787
  }
1546
1788
  }
1547
- console.log(chalk2.hex("#6366f1").bold(" Step 6/6 \u2014 Apply & sync\n"));
1548
- console.log(chalk2.dim(" Writing config files to your project and syncing to Caliber so"));
1549
- console.log(chalk2.dim(" teammates get the same setup when they run `caliber init`.\n"));
1789
+ console.log(chalk3.hex("#6366f1").bold(" Step 6/6 \u2014 Apply & sync\n"));
1790
+ console.log(chalk3.dim(" Writing config files to your project and syncing to Caliber so"));
1791
+ console.log(chalk3.dim(" teammates get the same setup when they run `caliber init`.\n"));
1550
1792
  if (options.dryRun) {
1551
- console.log(chalk2.yellow("\n[Dry run] Would write the following files:"));
1793
+ console.log(chalk3.yellow("\n[Dry run] Would write the following files:"));
1552
1794
  console.log(JSON.stringify(generatedSetup, null, 2));
1553
1795
  return;
1554
1796
  }
@@ -1557,30 +1799,30 @@ async function initCommand(options) {
1557
1799
  const result = writeSetup(generatedSetup);
1558
1800
  writeSpinner.succeed("Config files written");
1559
1801
  trackEvent("setup_applied", { files_written: result.written.length, target_agent: targetAgent });
1560
- console.log(chalk2.bold("\nFiles created/updated:"));
1802
+ console.log(chalk3.bold("\nFiles created/updated:"));
1561
1803
  for (const file of result.written) {
1562
- console.log(` ${chalk2.green("\u2713")} ${file}`);
1804
+ console.log(` ${chalk3.green("\u2713")} ${file}`);
1563
1805
  }
1564
1806
  if (result.backupDir) {
1565
- console.log(chalk2.dim(`
1807
+ console.log(chalk3.dim(`
1566
1808
  Backups saved to ${result.backupDir}`));
1567
1809
  }
1568
1810
  } catch (err) {
1569
1811
  writeSpinner.fail("Failed to write files");
1570
- console.error(chalk2.red(err instanceof Error ? err.message : "Unknown error"));
1812
+ console.error(chalk3.red(err instanceof Error ? err.message : "Unknown error"));
1571
1813
  throw new Error("__exit__");
1572
1814
  }
1573
1815
  if (targetAgent === "claude" || targetAgent === "both") {
1574
1816
  const hookResult = installHook();
1575
1817
  if (hookResult.installed) {
1576
- console.log(` ${chalk2.green("\u2713")} Auto-refresh hook installed \u2014 docs update on Claude Code session end`);
1577
- console.log(chalk2.dim(" Run `caliber hooks remove` to disable"));
1818
+ console.log(` ${chalk3.green("\u2713")} Auto-refresh hook installed \u2014 docs update on Claude Code session end`);
1819
+ console.log(chalk3.dim(" Run `caliber hooks remove` to disable"));
1578
1820
  const sha = getCurrentHeadSha();
1579
1821
  if (sha) {
1580
1822
  writeState({ lastRefreshSha: sha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
1581
1823
  }
1582
1824
  } else if (hookResult.alreadyInstalled) {
1583
- console.log(chalk2.dim(" Auto-refresh hook already installed"));
1825
+ console.log(chalk3.dim(" Auto-refresh hook already installed"));
1584
1826
  }
1585
1827
  }
1586
1828
  try {
@@ -1606,14 +1848,14 @@ async function initCommand(options) {
1606
1848
  }
1607
1849
  });
1608
1850
  } catch (err) {
1609
- console.log(chalk2.yellow(`
1851
+ console.log(chalk3.yellow(`
1610
1852
  Warning: Could not save project to server.`));
1611
- console.log(chalk2.dim(` ${err instanceof Error ? err.message : String(err)}`));
1612
- console.log(chalk2.dim(` Your local setup is unaffected.
1853
+ console.log(chalk3.dim(` ${err instanceof Error ? err.message : String(err)}`));
1854
+ console.log(chalk3.dim(` Your local setup is unaffected.
1613
1855
  `));
1614
1856
  }
1615
- console.log(chalk2.bold.green("\nSetup complete! Your coding agent is now configured."));
1616
- console.log(chalk2.dim("Run `caliber undo` to revert changes.\n"));
1857
+ console.log(chalk3.bold.green("\nSetup complete! Your coding agent is now configured."));
1858
+ console.log(chalk3.dim("Run `caliber undo` to revert changes.\n"));
1617
1859
  }
1618
1860
  async function refineLoop(currentSetup, _targetAgent) {
1619
1861
  const history = [];
@@ -1655,71 +1897,41 @@ async function refineLoop(currentSetup, _targetAgent) {
1655
1897
  history.push({ role: "assistant", content: JSON.stringify(refined) });
1656
1898
  refineSpinner.succeed("Setup updated");
1657
1899
  printSetupSummary(refined);
1658
- console.log(chalk2.dim('Type "done" to accept, or describe more changes.'));
1900
+ console.log(chalk3.dim('Type "done" to accept, or describe more changes.'));
1659
1901
  }
1660
1902
  }
1661
1903
  }
1662
1904
  function promptInput(question) {
1663
1905
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1664
1906
  return new Promise((resolve2) => {
1665
- rl.question(chalk2.cyan(`${question} `), (answer) => {
1907
+ rl.question(chalk3.cyan(`${question} `), (answer) => {
1666
1908
  rl.close();
1667
1909
  resolve2(answer.trim());
1668
1910
  });
1669
1911
  });
1670
1912
  }
1671
- function promptAgent() {
1672
- return new Promise((resolve2) => {
1673
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1674
- console.log(chalk2.bold("Which coding agent are you using?"));
1675
- console.log(" 1. Claude Code");
1676
- console.log(" 2. Cursor");
1677
- console.log(" 3. Both");
1678
- rl.question(chalk2.cyan("\nChoose (1-3): "), (answer) => {
1679
- rl.close();
1680
- const map = { "1": "claude", "2": "cursor", "3": "both" };
1681
- resolve2(map[answer.trim()] || "claude");
1682
- });
1913
+ async function promptAgent() {
1914
+ return select({
1915
+ message: "Which coding agent are you using?",
1916
+ choices: [
1917
+ { name: "Claude Code", value: "claude" },
1918
+ { name: "Cursor", value: "cursor" },
1919
+ { name: "Both", value: "both" }
1920
+ ]
1683
1921
  });
1684
1922
  }
1685
- function promptAction(explained) {
1686
- return new Promise((resolve2) => {
1687
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1688
- console.log(chalk2.bold("What would you like to do?"));
1689
- if (explained) {
1690
- console.log(" 1. Accept and apply");
1691
- console.log(" 2. Refine via chat");
1692
- console.log(" 3. Decline");
1693
- rl.question(chalk2.cyan("\nChoose (1-3): "), (answer) => {
1694
- rl.close();
1695
- const map = {
1696
- "1": "accept",
1697
- "2": "refine",
1698
- "3": "decline"
1699
- };
1700
- resolve2(map[answer.trim()] || "accept");
1701
- });
1702
- } else {
1703
- console.log(" 1. Accept and apply");
1704
- console.log(" 2. Refine via chat");
1705
- console.log(" 3. Explain recommendations");
1706
- console.log(" 4. Decline");
1707
- rl.question(chalk2.cyan("\nChoose (1-4): "), (answer) => {
1708
- rl.close();
1709
- const map = {
1710
- "1": "accept",
1711
- "2": "refine",
1712
- "3": "explain",
1713
- "4": "decline"
1714
- };
1715
- resolve2(map[answer.trim()] || "accept");
1716
- });
1717
- }
1718
- });
1923
+ async function promptAction(explained) {
1924
+ const choices = [
1925
+ { name: "Accept and apply", value: "accept" },
1926
+ { name: "Refine via chat", value: "refine" },
1927
+ ...!explained ? [{ name: "Explain recommendations", value: "explain" }] : [],
1928
+ { name: "Decline", value: "decline" }
1929
+ ];
1930
+ return select({ message: "What would you like to do?", choices });
1719
1931
  }
1720
1932
  function fileEntry(filePath, desc) {
1721
- const icon = fs15.existsSync(filePath) ? chalk2.yellow("~") : chalk2.green("+");
1722
- const description = desc ? chalk2.dim(`\u2014 ${desc}`) : "";
1933
+ const icon = fs16.existsSync(filePath) ? chalk3.yellow("~") : chalk3.green("+");
1934
+ const description = desc ? chalk3.dim(`\u2014 ${desc}`) : "";
1723
1935
  return ` ${icon} ${filePath} ${description}`;
1724
1936
  }
1725
1937
  function printSetupSummary(setup) {
@@ -1766,39 +1978,39 @@ function printSetupSummary(setup) {
1766
1978
  }
1767
1979
  }
1768
1980
  console.log("");
1769
- console.log(` ${chalk2.green("+")} ${chalk2.dim("new")} ${chalk2.yellow("~")} ${chalk2.dim("modified")}`);
1981
+ console.log(` ${chalk3.green("+")} ${chalk3.dim("new")} ${chalk3.yellow("~")} ${chalk3.dim("modified")}`);
1770
1982
  console.log("");
1771
1983
  }
1772
1984
  function printExplanation(explanation) {
1773
- console.log(chalk2.bold("\n Why this setup?\n"));
1985
+ console.log(chalk3.bold("\n Why this setup?\n"));
1774
1986
  const lines = explanation.split("\n");
1775
1987
  for (const line of lines) {
1776
1988
  const trimmed = line.trim();
1777
1989
  if (!trimmed) continue;
1778
1990
  const headerMatch = trimmed.match(/^\[(.+)\]$/);
1779
1991
  if (headerMatch) {
1780
- console.log(` ${chalk2.bold.hex("#6366f1")(headerMatch[1])}`);
1992
+ console.log(` ${chalk3.bold.hex("#6366f1")(headerMatch[1])}`);
1781
1993
  continue;
1782
1994
  }
1783
1995
  const itemMatch = trimmed.match(/^-\s+\*\*(.+?)\*\*[:\s]*(.*)$/);
1784
1996
  if (itemMatch) {
1785
1997
  const name = itemMatch[1];
1786
1998
  const desc = itemMatch[2].replace(/^\s*[-—:]\s*/, "");
1787
- console.log(` ${chalk2.dim("\u25B8")} ${chalk2.white(name)} ${chalk2.dim(desc)}`);
1999
+ console.log(` ${chalk3.dim("\u25B8")} ${chalk3.white(name)} ${chalk3.dim(desc)}`);
1788
2000
  continue;
1789
2001
  }
1790
2002
  const plainMatch = trimmed.match(/^-\s+(.*)$/);
1791
2003
  if (plainMatch) {
1792
- console.log(` ${chalk2.dim("\u25B8")} ${chalk2.dim(plainMatch[1])}`);
2004
+ console.log(` ${chalk3.dim("\u25B8")} ${chalk3.dim(plainMatch[1])}`);
1793
2005
  continue;
1794
2006
  }
1795
- console.log(` ${chalk2.dim(trimmed)}`);
2007
+ console.log(` ${chalk3.dim(trimmed)}`);
1796
2008
  }
1797
2009
  console.log("");
1798
2010
  }
1799
2011
 
1800
2012
  // src/commands/undo.ts
1801
- import chalk3 from "chalk";
2013
+ import chalk4 from "chalk";
1802
2014
  import ora3 from "ora";
1803
2015
  function undoCommand() {
1804
2016
  const spinner = ora3("Reverting setup...").start();
@@ -1811,163 +2023,27 @@ function undoCommand() {
1811
2023
  spinner.succeed("Setup reverted successfully.\n");
1812
2024
  trackEvent("setup_undone", { restored: restored.length, removed: removed.length });
1813
2025
  if (restored.length > 0) {
1814
- console.log(chalk3.cyan(" Restored from backup:"));
2026
+ console.log(chalk4.cyan(" Restored from backup:"));
1815
2027
  for (const file of restored) {
1816
- console.log(` ${chalk3.green("\u21A9")} ${file}`);
2028
+ console.log(` ${chalk4.green("\u21A9")} ${file}`);
1817
2029
  }
1818
2030
  }
1819
2031
  if (removed.length > 0) {
1820
- console.log(chalk3.cyan(" Removed:"));
2032
+ console.log(chalk4.cyan(" Removed:"));
1821
2033
  for (const file of removed) {
1822
- console.log(` ${chalk3.red("\u2717")} ${file}`);
2034
+ console.log(` ${chalk4.red("\u2717")} ${file}`);
1823
2035
  }
1824
2036
  }
1825
2037
  console.log("");
1826
2038
  } catch (err) {
1827
- spinner.fail(chalk3.red(err instanceof Error ? err.message : "Undo failed"));
2039
+ spinner.fail(chalk4.red(err instanceof Error ? err.message : "Undo failed"));
1828
2040
  throw new Error("__exit__");
1829
2041
  }
1830
2042
  }
1831
2043
 
1832
2044
  // src/commands/status.ts
1833
- import chalk4 from "chalk";
2045
+ import chalk5 from "chalk";
1834
2046
  import fs17 from "fs";
1835
-
1836
- // src/scanner/index.ts
1837
- import fs16 from "fs";
1838
- import path14 from "path";
1839
- import crypto4 from "crypto";
1840
- function scanLocalState(dir) {
1841
- const items = [];
1842
- const claudeMdPath = path14.join(dir, "CLAUDE.md");
1843
- if (fs16.existsSync(claudeMdPath)) {
1844
- items.push({
1845
- type: "rule",
1846
- platform: "claude",
1847
- name: "CLAUDE.md",
1848
- contentHash: hashFile(claudeMdPath),
1849
- path: claudeMdPath
1850
- });
1851
- }
1852
- const settingsPath = path14.join(dir, ".claude", "settings.json");
1853
- if (fs16.existsSync(settingsPath)) {
1854
- items.push({
1855
- type: "config",
1856
- platform: "claude",
1857
- name: "settings.json",
1858
- contentHash: hashFile(settingsPath),
1859
- path: settingsPath
1860
- });
1861
- }
1862
- const skillsDir = path14.join(dir, ".claude", "skills");
1863
- if (fs16.existsSync(skillsDir)) {
1864
- for (const file of fs16.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
1865
- const filePath = path14.join(skillsDir, file);
1866
- items.push({
1867
- type: "skill",
1868
- platform: "claude",
1869
- name: file,
1870
- contentHash: hashFile(filePath),
1871
- path: filePath
1872
- });
1873
- }
1874
- }
1875
- const mcpJsonPath = path14.join(dir, ".mcp.json");
1876
- if (fs16.existsSync(mcpJsonPath)) {
1877
- try {
1878
- const mcpJson = JSON.parse(fs16.readFileSync(mcpJsonPath, "utf-8"));
1879
- if (mcpJson.mcpServers) {
1880
- for (const name of Object.keys(mcpJson.mcpServers)) {
1881
- items.push({
1882
- type: "mcp",
1883
- platform: "claude",
1884
- name,
1885
- contentHash: hashContent(JSON.stringify(mcpJson.mcpServers[name])),
1886
- path: mcpJsonPath
1887
- });
1888
- }
1889
- }
1890
- } catch {
1891
- }
1892
- }
1893
- const cursorrulesPath = path14.join(dir, ".cursorrules");
1894
- if (fs16.existsSync(cursorrulesPath)) {
1895
- items.push({
1896
- type: "rule",
1897
- platform: "cursor",
1898
- name: ".cursorrules",
1899
- contentHash: hashFile(cursorrulesPath),
1900
- path: cursorrulesPath
1901
- });
1902
- }
1903
- const cursorRulesDir = path14.join(dir, ".cursor", "rules");
1904
- if (fs16.existsSync(cursorRulesDir)) {
1905
- for (const file of fs16.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
1906
- const filePath = path14.join(cursorRulesDir, file);
1907
- items.push({
1908
- type: "rule",
1909
- platform: "cursor",
1910
- name: file,
1911
- contentHash: hashFile(filePath),
1912
- path: filePath
1913
- });
1914
- }
1915
- }
1916
- const cursorMcpPath = path14.join(dir, ".cursor", "mcp.json");
1917
- if (fs16.existsSync(cursorMcpPath)) {
1918
- try {
1919
- const mcpJson = JSON.parse(fs16.readFileSync(cursorMcpPath, "utf-8"));
1920
- if (mcpJson.mcpServers) {
1921
- for (const name of Object.keys(mcpJson.mcpServers)) {
1922
- items.push({
1923
- type: "mcp",
1924
- platform: "cursor",
1925
- name,
1926
- contentHash: hashContent(JSON.stringify(mcpJson.mcpServers[name])),
1927
- path: cursorMcpPath
1928
- });
1929
- }
1930
- }
1931
- } catch {
1932
- }
1933
- }
1934
- return items;
1935
- }
1936
- function compareState(serverItems, localItems) {
1937
- const installed = [];
1938
- const missing = [];
1939
- const outdated = [];
1940
- const extra = [];
1941
- const localMap = /* @__PURE__ */ new Map();
1942
- for (const item of localItems) {
1943
- localMap.set(`${item.type}:${item.platform}:${item.name}`, item);
1944
- }
1945
- for (const server of serverItems) {
1946
- const key = `${server.type}:${server.platform}:${server.name}`;
1947
- const local = localMap.get(key);
1948
- localMap.delete(key);
1949
- if (!local) {
1950
- missing.push(server);
1951
- } else if (local.contentHash !== server.content_hash) {
1952
- outdated.push({ server, local });
1953
- } else {
1954
- installed.push({ server, local });
1955
- }
1956
- }
1957
- for (const local of localMap.values()) {
1958
- extra.push(local);
1959
- }
1960
- return { installed, missing, outdated, extra };
1961
- }
1962
- function hashFile(filePath) {
1963
- const content = fs16.readFileSync(filePath);
1964
- return crypto4.createHash("sha256").update(content).digest("hex");
1965
- }
1966
- function hashContent(content) {
1967
- return crypto4.createHash("sha256").update(JSON.stringify({ text: content })).digest("hex");
1968
- }
1969
-
1970
- // src/commands/status.ts
1971
2047
  async function statusCommand(options) {
1972
2048
  const auth2 = getStoredAuth();
1973
2049
  const manifest = readManifest();
@@ -1979,21 +2055,21 @@ async function statusCommand(options) {
1979
2055
  }, null, 2));
1980
2056
  return;
1981
2057
  }
1982
- console.log(chalk4.bold("\nCaliber Status\n"));
2058
+ console.log(chalk5.bold("\nCaliber Status\n"));
1983
2059
  if (auth2) {
1984
- console.log(` Auth: ${chalk4.green("Logged in")} as ${auth2.email}`);
2060
+ console.log(` Auth: ${chalk5.green("Logged in")} as ${auth2.email}`);
1985
2061
  } else {
1986
- console.log(` Auth: ${chalk4.yellow("Not logged in")}`);
2062
+ console.log(` Auth: ${chalk5.yellow("Not logged in")}`);
1987
2063
  }
1988
2064
  if (!manifest) {
1989
- console.log(` Setup: ${chalk4.dim("No setup applied")}`);
1990
- console.log(chalk4.dim("\n Run `caliber init` to get started.\n"));
2065
+ console.log(` Setup: ${chalk5.dim("No setup applied")}`);
2066
+ console.log(chalk5.dim("\n Run `caliber init` to get started.\n"));
1991
2067
  return;
1992
2068
  }
1993
- console.log(` Files managed: ${chalk4.cyan(manifest.entries.length.toString())}`);
2069
+ console.log(` Files managed: ${chalk5.cyan(manifest.entries.length.toString())}`);
1994
2070
  for (const entry of manifest.entries) {
1995
2071
  const exists = fs17.existsSync(entry.path);
1996
- const icon = exists ? chalk4.green("\u2713") : chalk4.red("\u2717");
2072
+ const icon = exists ? chalk5.green("\u2713") : chalk5.red("\u2717");
1997
2073
  console.log(` ${icon} ${entry.path} (${entry.action})`);
1998
2074
  }
1999
2075
  if (auth2) {
@@ -2011,10 +2087,10 @@ async function statusCommand(options) {
2011
2087
  if (serverItems?.length) {
2012
2088
  const localItems = scanLocalState(process.cwd());
2013
2089
  const diff = compareState(serverItems, localItems);
2014
- console.log(chalk4.bold("\n Sync"));
2015
- console.log(` ${chalk4.green("\u2713")} Installed: ${diff.installed.length}`);
2016
- if (diff.missing.length) console.log(` ${chalk4.red("\u2717")} Missing: ${diff.missing.length}`);
2017
- if (diff.outdated.length) console.log(` ${chalk4.yellow("~")} Outdated: ${diff.outdated.length}`);
2090
+ console.log(chalk5.bold("\n Sync"));
2091
+ console.log(` ${chalk5.green("\u2713")} Installed: ${diff.installed.length}`);
2092
+ if (diff.missing.length) console.log(` ${chalk5.red("\u2717")} Missing: ${diff.missing.length}`);
2093
+ if (diff.outdated.length) console.log(` ${chalk5.yellow("~")} Outdated: ${diff.outdated.length}`);
2018
2094
  }
2019
2095
  }
2020
2096
  } catch {
@@ -2023,19 +2099,19 @@ async function statusCommand(options) {
2023
2099
  console.log("");
2024
2100
  }
2025
2101
 
2026
- // src/commands/update.ts
2027
- import chalk5 from "chalk";
2102
+ // src/commands/regenerate.ts
2103
+ import chalk6 from "chalk";
2028
2104
  import ora4 from "ora";
2029
- import readline2 from "readline";
2030
- async function updateCommand(options) {
2105
+ import confirm from "@inquirer/confirm";
2106
+ async function regenerateCommand(options) {
2031
2107
  const auth2 = getStoredAuth();
2032
2108
  if (!auth2) {
2033
- console.log(chalk5.red("Not logged in. Run `caliber login` first."));
2109
+ console.log(chalk6.red("Not logged in. Run `caliber login` first."));
2034
2110
  throw new Error("__exit__");
2035
2111
  }
2036
2112
  const manifest = readManifest();
2037
2113
  if (!manifest) {
2038
- console.log(chalk5.yellow("No existing setup found. Run `caliber init` first."));
2114
+ console.log(chalk6.yellow("No existing setup found. Run `caliber init` first."));
2039
2115
  throw new Error("__exit__");
2040
2116
  }
2041
2117
  const spinner = ora4("Re-analyzing project...").start();
@@ -2071,7 +2147,7 @@ async function updateCommand(options) {
2071
2147
  },
2072
2148
  (error) => {
2073
2149
  genMessages.stop();
2074
- trackEvent("error_occurred", { error_type: "generation_failed", error_message: error, command: "update" });
2150
+ trackEvent("error_occurred", { error_type: "generation_failed", error_message: error, command: "regenerate" });
2075
2151
  genSpinner.fail(`Generation error: ${error}`);
2076
2152
  },
2077
2153
  (status) => {
@@ -2081,7 +2157,7 @@ async function updateCommand(options) {
2081
2157
  } catch (err) {
2082
2158
  genMessages.stop();
2083
2159
  const msg = err instanceof Error ? err.message : "Unknown error";
2084
- trackEvent("error_occurred", { error_type: "generation_request_failed", error_message: msg, command: "update" });
2160
+ trackEvent("error_occurred", { error_type: "generation_request_failed", error_message: msg, command: "regenerate" });
2085
2161
  genSpinner.fail(`Regeneration failed: ${msg}`);
2086
2162
  throw new Error("__exit__");
2087
2163
  }
@@ -2092,52 +2168,48 @@ async function updateCommand(options) {
2092
2168
  }
2093
2169
  genSpinner.succeed("Setup regenerated");
2094
2170
  if (options.dryRun) {
2095
- console.log(chalk5.yellow("\n[Dry run] Would write:"));
2171
+ console.log(chalk6.yellow("\n[Dry run] Would write:"));
2096
2172
  console.log(JSON.stringify(generatedSetup, null, 2));
2097
2173
  return;
2098
2174
  }
2099
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
2100
- const answer = await new Promise((resolve2) => {
2101
- rl.question(chalk5.cyan("\n\nApply updated setup? (y/n): "), resolve2);
2102
- });
2103
- rl.close();
2104
- if (answer.trim().toLowerCase() !== "y") {
2105
- trackEvent("update_declined");
2106
- console.log(chalk5.dim("Update cancelled."));
2175
+ const shouldApply = await confirm({ message: "Apply regenerated setup?", default: true });
2176
+ if (!shouldApply) {
2177
+ trackEvent("regenerate_declined");
2178
+ console.log(chalk6.dim("Regeneration cancelled."));
2107
2179
  return;
2108
2180
  }
2109
2181
  const writeSpinner = ora4("Updating config files...").start();
2110
2182
  const result = writeSetup(generatedSetup);
2111
2183
  writeSpinner.succeed("Config files updated");
2112
- trackEvent("setup_updated", { files_written: result.written.length });
2184
+ trackEvent("setup_regenerated", { files_written: result.written.length });
2113
2185
  for (const file of result.written) {
2114
- console.log(` ${chalk5.green("\u2713")} ${file}`);
2186
+ console.log(` ${chalk6.green("\u2713")} ${file}`);
2115
2187
  }
2116
2188
  console.log("");
2117
2189
  }
2118
2190
 
2119
2191
  // src/commands/logout.ts
2120
- import chalk6 from "chalk";
2192
+ import chalk7 from "chalk";
2121
2193
  function logoutCommand() {
2122
2194
  const auth2 = getStoredAuth();
2123
2195
  if (!auth2) {
2124
- console.log(chalk6.dim("Not currently logged in."));
2196
+ console.log(chalk7.dim("Not currently logged in."));
2125
2197
  return;
2126
2198
  }
2127
2199
  clearAuth();
2128
2200
  trackEvent("logout");
2129
- console.log(chalk6.green("Logged out successfully."));
2201
+ console.log(chalk7.green("Logged out successfully."));
2130
2202
  }
2131
2203
 
2132
2204
  // src/commands/recommend.ts
2133
- import chalk7 from "chalk";
2205
+ import chalk8 from "chalk";
2134
2206
  import ora5 from "ora";
2135
2207
  import { mkdirSync, writeFileSync } from "fs";
2136
2208
  import { join } from "path";
2137
2209
  async function recommendCommand(options) {
2138
2210
  const auth2 = getStoredAuth();
2139
2211
  if (!auth2) {
2140
- console.log(chalk7.red("Not authenticated. Run `caliber login` first."));
2212
+ console.log(chalk8.red("Not authenticated. Run `caliber login` first."));
2141
2213
  throw new Error("__exit__");
2142
2214
  }
2143
2215
  const fingerprint = collectFingerprint(process.cwd());
@@ -2147,7 +2219,7 @@ async function recommendCommand(options) {
2147
2219
  { method: "POST", body: { fingerprintHash: hash } }
2148
2220
  );
2149
2221
  if (!match?.project) {
2150
- console.log(chalk7.yellow("No project found. Run `caliber init` first."));
2222
+ console.log(chalk8.yellow("No project found. Run `caliber init` first."));
2151
2223
  throw new Error("__exit__");
2152
2224
  }
2153
2225
  const projectId = match.project.id;
@@ -2177,7 +2249,7 @@ async function recommendCommand(options) {
2177
2249
  `/api/recommendations/project/${projectId}?status=${statusFilter}`
2178
2250
  );
2179
2251
  if (!recs?.length) {
2180
- console.log(chalk7.dim(`
2252
+ console.log(chalk8.dim(`
2181
2253
  No ${statusFilter} recommendations. Run \`caliber recommend --generate\` to discover skills.
2182
2254
  `));
2183
2255
  return;
@@ -2202,19 +2274,19 @@ async function interactiveSelect(recs) {
2202
2274
  let lineCount = 0;
2203
2275
  function render() {
2204
2276
  const lines = [];
2205
- lines.push(chalk7.bold(" Skill Recommendations"));
2277
+ lines.push(chalk8.bold(" Skill Recommendations"));
2206
2278
  lines.push("");
2207
- lines.push(` ${chalk7.dim("Name".padEnd(30))} ${chalk7.dim("Score".padEnd(8))} ${chalk7.dim("Technology")}`);
2208
- lines.push(chalk7.dim(" " + "\u2500".repeat(55)));
2279
+ lines.push(` ${chalk8.dim("Name".padEnd(30))} ${chalk8.dim("Score".padEnd(8))} ${chalk8.dim("Technology")}`);
2280
+ lines.push(chalk8.dim(" " + "\u2500".repeat(55)));
2209
2281
  for (let i = 0; i < recs.length; i++) {
2210
2282
  const rec = recs[i];
2211
- const check = selected.has(i) ? chalk7.green("[x]") : "[ ]";
2212
- const ptr = i === cursor ? chalk7.cyan("\u276F") : " ";
2213
- const scoreColor = rec.score >= 90 ? chalk7.green : rec.score >= 70 ? chalk7.blue : chalk7.yellow;
2283
+ const check = selected.has(i) ? chalk8.green("[x]") : "[ ]";
2284
+ const ptr = i === cursor ? chalk8.cyan("\u276F") : " ";
2285
+ const scoreColor = rec.score >= 90 ? chalk8.green : rec.score >= 70 ? chalk8.blue : chalk8.yellow;
2214
2286
  lines.push(` ${ptr} ${check} ${rec.skill_name.padEnd(26)} ${scoreColor(`${rec.score}%`.padEnd(8))} ${rec.detected_technology}`);
2215
2287
  }
2216
2288
  lines.push("");
2217
- lines.push(chalk7.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
2289
+ lines.push(chalk8.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
2218
2290
  return lines.join("\n");
2219
2291
  }
2220
2292
  function draw(initial) {
@@ -2263,7 +2335,7 @@ async function interactiveSelect(recs) {
2263
2335
  case "\n":
2264
2336
  cleanup();
2265
2337
  if (selected.size === 0) {
2266
- console.log(chalk7.dim("\n No skills selected.\n"));
2338
+ console.log(chalk8.dim("\n No skills selected.\n"));
2267
2339
  resolve2(null);
2268
2340
  } else {
2269
2341
  resolve2(Array.from(selected).sort().map((i) => recs[i]));
@@ -2273,7 +2345,7 @@ async function interactiveSelect(recs) {
2273
2345
  case "\x1B":
2274
2346
  case "":
2275
2347
  cleanup();
2276
- console.log(chalk7.dim("\n Cancelled.\n"));
2348
+ console.log(chalk8.dim("\n Cancelled.\n"));
2277
2349
  resolve2(null);
2278
2350
  break;
2279
2351
  }
@@ -2313,41 +2385,41 @@ async function installSkills(recs) {
2313
2385
  if (installed.length > 0) {
2314
2386
  spinner.succeed(`Installed ${installed.length} skill${installed.length > 1 ? "s" : ""}`);
2315
2387
  for (const p of installed) {
2316
- console.log(chalk7.green(` \u2713 ${p}`));
2388
+ console.log(chalk8.green(` \u2713 ${p}`));
2317
2389
  }
2318
2390
  } else {
2319
2391
  spinner.fail("No skills were installed");
2320
2392
  }
2321
2393
  for (const w of warnings) {
2322
- console.log(chalk7.yellow(` \u26A0 ${w}`));
2394
+ console.log(chalk8.yellow(` \u26A0 ${w}`));
2323
2395
  }
2324
2396
  console.log("");
2325
2397
  }
2326
2398
  function printRecommendations(recs) {
2327
- console.log(chalk7.bold("\n Skill Recommendations\n"));
2399
+ console.log(chalk8.bold("\n Skill Recommendations\n"));
2328
2400
  console.log(
2329
- ` ${chalk7.dim("Name".padEnd(30))} ${chalk7.dim("Score".padEnd(8))} ${chalk7.dim("Technology".padEnd(15))} ${chalk7.dim("Status")}`
2401
+ ` ${chalk8.dim("Name".padEnd(30))} ${chalk8.dim("Score".padEnd(8))} ${chalk8.dim("Technology".padEnd(15))} ${chalk8.dim("Status")}`
2330
2402
  );
2331
- console.log(chalk7.dim(" " + "\u2500".repeat(70)));
2403
+ console.log(chalk8.dim(" " + "\u2500".repeat(70)));
2332
2404
  for (const rec of recs) {
2333
- const scoreColor = rec.score >= 90 ? chalk7.green : rec.score >= 70 ? chalk7.blue : chalk7.yellow;
2405
+ const scoreColor = rec.score >= 90 ? chalk8.green : rec.score >= 70 ? chalk8.blue : chalk8.yellow;
2334
2406
  console.log(
2335
2407
  ` ${rec.skill_name.padEnd(30)} ${scoreColor(`${rec.score}%`.padEnd(8))} ${rec.detected_technology.padEnd(15)} ${rec.status}`
2336
2408
  );
2337
2409
  if (rec.reason) {
2338
- console.log(` ${chalk7.dim(rec.reason)}`);
2410
+ console.log(` ${chalk8.dim(rec.reason)}`);
2339
2411
  }
2340
2412
  }
2341
2413
  console.log("");
2342
2414
  }
2343
2415
 
2344
2416
  // src/commands/health.ts
2345
- import chalk8 from "chalk";
2417
+ import chalk9 from "chalk";
2346
2418
  import ora6 from "ora";
2347
2419
  async function healthCommand(options) {
2348
2420
  const auth2 = getStoredAuth();
2349
2421
  if (!auth2) {
2350
- console.log(chalk8.red("Not authenticated. Run `caliber login` first."));
2422
+ console.log(chalk9.red("Not authenticated. Run `caliber login` first."));
2351
2423
  throw new Error("__exit__");
2352
2424
  }
2353
2425
  const fingerprint = collectFingerprint(process.cwd());
@@ -2357,7 +2429,7 @@ async function healthCommand(options) {
2357
2429
  { method: "POST", body: { fingerprintHash: hash } }
2358
2430
  );
2359
2431
  if (!match?.project) {
2360
- console.log(chalk8.yellow("No project found. Run `caliber init` first."));
2432
+ console.log(chalk9.yellow("No project found. Run `caliber init` first."));
2361
2433
  throw new Error("__exit__");
2362
2434
  }
2363
2435
  const projectId = match.project.id;
@@ -2379,21 +2451,21 @@ async function healthCommand(options) {
2379
2451
  }
2380
2452
  printReport(report);
2381
2453
  if (options.fix) {
2382
- console.log(chalk8.bold("\nGenerating fix plan..."));
2454
+ console.log(chalk9.bold("\nGenerating fix plan..."));
2383
2455
  const plan = await apiRequest(
2384
2456
  `/api/context/reports/${report.id}/fix-plan`,
2385
2457
  { method: "POST", body: { projectId } }
2386
2458
  );
2387
2459
  if (!plan?.actions.length) {
2388
- console.log(chalk8.dim("No fixes needed."));
2460
+ console.log(chalk9.dim("No fixes needed."));
2389
2461
  return;
2390
2462
  }
2391
- console.log(chalk8.bold("\nProposed actions:"));
2463
+ console.log(chalk9.bold("\nProposed actions:"));
2392
2464
  for (const action of plan.actions) {
2393
- const icon = action.type === "remove" ? chalk8.red("- ") : action.type === "add" ? chalk8.green("+ ") : chalk8.yellow("~ ");
2465
+ const icon = action.type === "remove" ? chalk9.red("- ") : action.type === "add" ? chalk9.green("+ ") : chalk9.yellow("~ ");
2394
2466
  console.log(` ${icon}${action.type}: ${action.items.join(", ")}`);
2395
2467
  }
2396
- console.log(chalk8.dim(`
2468
+ console.log(chalk9.dim(`
2397
2469
  Estimated improvement: +${plan.estimatedScoreImprovement} points`));
2398
2470
  const fixSpinner = ora6("Executing fix plan...").start();
2399
2471
  try {
@@ -2403,7 +2475,7 @@ Estimated improvement: +${plan.estimatedScoreImprovement} points`));
2403
2475
  );
2404
2476
  fixSpinner.succeed("Fix applied");
2405
2477
  console.log("");
2406
- console.log(` Score: ${result.scoreBefore} \u2192 ${chalk8.green(String(result.scoreAfter))} (${chalk8.green(`+${result.improvement}`)})`);
2478
+ console.log(` Score: ${result.scoreBefore} \u2192 ${chalk9.green(String(result.scoreAfter))} (${chalk9.green(`+${result.improvement}`)})`);
2407
2479
  if (result.itemsRemoved) console.log(` Removed: ${result.itemsRemoved} items`);
2408
2480
  if (result.itemsConsolidated) console.log(` Consolidated: ${result.itemsConsolidated} items`);
2409
2481
  if (result.itemsAdded) console.log(` Added: ${result.itemsAdded} items`);
@@ -2416,18 +2488,18 @@ Estimated improvement: +${plan.estimatedScoreImprovement} points`));
2416
2488
  }
2417
2489
  function printReport(report) {
2418
2490
  const gradeColors = {
2419
- A: chalk8.green,
2420
- B: chalk8.blue,
2421
- C: chalk8.yellow,
2422
- D: chalk8.hex("#FFA500"),
2423
- F: chalk8.red
2491
+ A: chalk9.green,
2492
+ B: chalk9.blue,
2493
+ C: chalk9.yellow,
2494
+ D: chalk9.hex("#FFA500"),
2495
+ F: chalk9.red
2424
2496
  };
2425
- const gradeColor = gradeColors[report.grade] || chalk8.white;
2426
- console.log(chalk8.bold("\n Context Health Report\n"));
2497
+ const gradeColor = gradeColors[report.grade] || chalk9.white;
2498
+ console.log(chalk9.bold("\n Context Health Report\n"));
2427
2499
  console.log(` Grade: ${gradeColor(report.grade)} Score: ${gradeColor(String(report.score))}/100
2428
2500
  `);
2429
2501
  if (Object.keys(report.category_breakdown).length) {
2430
- console.log(chalk8.dim(" Category Breakdown:"));
2502
+ console.log(chalk9.dim(" Category Breakdown:"));
2431
2503
  const categories = Object.entries(report.category_breakdown);
2432
2504
  const maxCount = Math.max(...categories.map(([, v]) => v.count));
2433
2505
  for (const [name, data] of categories) {
@@ -2438,9 +2510,9 @@ function printReport(report) {
2438
2510
  console.log("");
2439
2511
  }
2440
2512
  if (report.recommendations.length) {
2441
- console.log(chalk8.dim(" Recommendations:"));
2513
+ console.log(chalk9.dim(" Recommendations:"));
2442
2514
  for (const rec of report.recommendations) {
2443
- const icon = rec.priority === "high" ? chalk8.red("!") : rec.priority === "medium" ? chalk8.yellow("~") : chalk8.dim("-");
2515
+ const icon = rec.priority === "high" ? chalk9.red("!") : rec.priority === "medium" ? chalk9.yellow("~") : chalk9.dim("-");
2444
2516
  console.log(` ${icon} ${rec.description}`);
2445
2517
  }
2446
2518
  console.log("");
@@ -2448,12 +2520,12 @@ function printReport(report) {
2448
2520
  }
2449
2521
 
2450
2522
  // src/commands/sync.ts
2451
- import chalk9 from "chalk";
2523
+ import chalk10 from "chalk";
2452
2524
  import ora7 from "ora";
2453
2525
  async function syncCommand(options) {
2454
2526
  const auth2 = getStoredAuth();
2455
2527
  if (!auth2) {
2456
- console.log(chalk9.red("Not authenticated. Run `caliber login` first."));
2528
+ console.log(chalk10.red("Not authenticated. Run `caliber login` first."));
2457
2529
  throw new Error("__exit__");
2458
2530
  }
2459
2531
  const fingerprint = collectFingerprint(process.cwd());
@@ -2463,7 +2535,7 @@ async function syncCommand(options) {
2463
2535
  { method: "POST", body: { fingerprintHash: hash } }
2464
2536
  );
2465
2537
  if (!match?.project) {
2466
- console.log(chalk9.yellow("No project found. Run `caliber init` first."));
2538
+ console.log(chalk10.yellow("No project found. Run `caliber init` first."));
2467
2539
  throw new Error("__exit__");
2468
2540
  }
2469
2541
  const projectId = match.project.id;
@@ -2475,7 +2547,7 @@ async function syncCommand(options) {
2475
2547
  );
2476
2548
  spinner.succeed(`Found ${localItems.length} local items, ${serverItems?.length || 0} server items`);
2477
2549
  if (!serverItems?.length) {
2478
- console.log(chalk9.dim("\nNo items configured on server. Run `caliber init` to set up your project.\n"));
2550
+ console.log(chalk10.dim("\nNo items configured on server. Run `caliber init` to set up your project.\n"));
2479
2551
  return;
2480
2552
  }
2481
2553
  const platformFilter = options.platform;
@@ -2484,12 +2556,12 @@ async function syncCommand(options) {
2484
2556
  const diff = compareState(filteredServer, filteredLocal);
2485
2557
  printDiff(diff);
2486
2558
  if (diff.missing.length === 0 && diff.outdated.length === 0) {
2487
- console.log(chalk9.green("\nAll items synced.\n"));
2559
+ console.log(chalk10.green("\nAll items synced.\n"));
2488
2560
  await reportToServer(projectId, filteredServer, diff);
2489
2561
  return;
2490
2562
  }
2491
2563
  if (options.dryRun) {
2492
- console.log(chalk9.dim("\nDry run \u2014 no changes made.\n"));
2564
+ console.log(chalk10.dim("\nDry run \u2014 no changes made.\n"));
2493
2565
  return;
2494
2566
  }
2495
2567
  const installSpinner = ora7("Installing missing and outdated items...").start();
@@ -2545,26 +2617,26 @@ async function reportToServer(projectId, serverItems, diff) {
2545
2617
  }
2546
2618
  }
2547
2619
  function printDiff(diff) {
2548
- console.log(chalk9.bold("\n Sync Status\n"));
2620
+ console.log(chalk10.bold("\n Sync Status\n"));
2549
2621
  if (diff.installed.length) {
2550
- console.log(` ${chalk9.green("\u2713")} Installed: ${diff.installed.length}`);
2622
+ console.log(` ${chalk10.green("\u2713")} Installed: ${diff.installed.length}`);
2551
2623
  }
2552
2624
  if (diff.missing.length) {
2553
- console.log(` ${chalk9.red("\u2717")} Missing: ${diff.missing.length}`);
2625
+ console.log(` ${chalk10.red("\u2717")} Missing: ${diff.missing.length}`);
2554
2626
  for (const item of diff.missing) {
2555
- console.log(` ${chalk9.red("-")} ${item.name} (${item.type}/${item.platform})`);
2627
+ console.log(` ${chalk10.red("-")} ${item.name} (${item.type}/${item.platform})`);
2556
2628
  }
2557
2629
  }
2558
2630
  if (diff.outdated.length) {
2559
- console.log(` ${chalk9.yellow("~")} Outdated: ${diff.outdated.length}`);
2631
+ console.log(` ${chalk10.yellow("~")} Outdated: ${diff.outdated.length}`);
2560
2632
  for (const item of diff.outdated) {
2561
- console.log(` ${chalk9.yellow("~")} ${item.server.name} (${item.server.type}/${item.server.platform})`);
2633
+ console.log(` ${chalk10.yellow("~")} ${item.server.name} (${item.server.type}/${item.server.platform})`);
2562
2634
  }
2563
2635
  }
2564
2636
  if (diff.extra.length) {
2565
- console.log(` ${chalk9.dim("+")} Extra (local only): ${diff.extra.length}`);
2637
+ console.log(` ${chalk10.dim("+")} Extra (local only): ${diff.extra.length}`);
2566
2638
  for (const item of diff.extra) {
2567
- console.log(` ${chalk9.dim("+")} ${item.name} (${item.type}/${item.platform})`);
2639
+ console.log(` ${chalk10.dim("+")} ${item.name} (${item.type}/${item.platform})`);
2568
2640
  }
2569
2641
  }
2570
2642
  console.log("");
@@ -2625,12 +2697,12 @@ function buildSetupFromItems(items) {
2625
2697
  }
2626
2698
 
2627
2699
  // src/commands/diff.ts
2628
- import chalk10 from "chalk";
2700
+ import chalk11 from "chalk";
2629
2701
  import ora8 from "ora";
2630
2702
  async function diffCommand(options) {
2631
2703
  const auth2 = getStoredAuth();
2632
2704
  if (!auth2) {
2633
- console.log(chalk10.red("Not authenticated. Run `caliber login` first."));
2705
+ console.log(chalk11.red("Not authenticated. Run `caliber login` first."));
2634
2706
  throw new Error("__exit__");
2635
2707
  }
2636
2708
  const fingerprint = collectFingerprint(process.cwd());
@@ -2640,7 +2712,7 @@ async function diffCommand(options) {
2640
2712
  { method: "POST", body: { fingerprintHash: hash } }
2641
2713
  );
2642
2714
  if (!match?.project) {
2643
- console.log(chalk10.yellow("No project found. Run `caliber init` first."));
2715
+ console.log(chalk11.yellow("No project found. Run `caliber init` first."));
2644
2716
  throw new Error("__exit__");
2645
2717
  }
2646
2718
  const projectId = match.project.id;
@@ -2651,46 +2723,46 @@ async function diffCommand(options) {
2651
2723
  );
2652
2724
  spinner.stop();
2653
2725
  if (!serverItems?.length) {
2654
- console.log(chalk10.dim("\nNo items configured on server.\n"));
2726
+ console.log(chalk11.dim("\nNo items configured on server.\n"));
2655
2727
  return;
2656
2728
  }
2657
2729
  const platformFilter = options.platform;
2658
2730
  const filteredServer = platformFilter ? serverItems.filter((i) => i.platform === platformFilter || i.platform === "both") : serverItems;
2659
2731
  const filteredLocal = platformFilter ? localItems.filter((i) => i.platform === platformFilter) : localItems;
2660
2732
  const diff = compareState(filteredServer, filteredLocal);
2661
- console.log(chalk10.bold("\n Config Diff\n"));
2733
+ console.log(chalk11.bold("\n Config Diff\n"));
2662
2734
  if (diff.installed.length) {
2663
- console.log(` ${chalk10.green("\u2713")} In sync: ${diff.installed.length}`);
2735
+ console.log(` ${chalk11.green("\u2713")} In sync: ${diff.installed.length}`);
2664
2736
  }
2665
2737
  if (diff.missing.length) {
2666
- console.log(` ${chalk10.red("\u2717")} Missing locally: ${diff.missing.length}`);
2738
+ console.log(` ${chalk11.red("\u2717")} Missing locally: ${diff.missing.length}`);
2667
2739
  for (const item of diff.missing) {
2668
- console.log(` ${chalk10.red("-")} ${item.name} (${item.type}/${item.platform})`);
2740
+ console.log(` ${chalk11.red("-")} ${item.name} (${item.type}/${item.platform})`);
2669
2741
  }
2670
2742
  }
2671
2743
  if (diff.outdated.length) {
2672
- console.log(` ${chalk10.yellow("~")} Outdated: ${diff.outdated.length}`);
2744
+ console.log(` ${chalk11.yellow("~")} Outdated: ${diff.outdated.length}`);
2673
2745
  for (const item of diff.outdated) {
2674
- console.log(` ${chalk10.yellow("~")} ${item.server.name} (${item.server.type}/${item.server.platform})`);
2746
+ console.log(` ${chalk11.yellow("~")} ${item.server.name} (${item.server.type}/${item.server.platform})`);
2675
2747
  }
2676
2748
  }
2677
2749
  if (diff.extra.length) {
2678
- console.log(` ${chalk10.dim("+")} Local only: ${diff.extra.length}`);
2750
+ console.log(` ${chalk11.dim("+")} Local only: ${diff.extra.length}`);
2679
2751
  for (const item of diff.extra) {
2680
- console.log(` ${chalk10.dim("+")} ${item.name} (${item.type}/${item.platform})`);
2752
+ console.log(` ${chalk11.dim("+")} ${item.name} (${item.type}/${item.platform})`);
2681
2753
  }
2682
2754
  }
2683
2755
  if (diff.missing.length === 0 && diff.outdated.length === 0) {
2684
- console.log(chalk10.green("\n Everything is in sync.\n"));
2756
+ console.log(chalk11.green("\n Everything is in sync.\n"));
2685
2757
  } else {
2686
- console.log(chalk10.dim("\n Run `caliber sync` to apply changes.\n"));
2758
+ console.log(chalk11.dim("\n Run `caliber sync` to apply changes.\n"));
2687
2759
  }
2688
2760
  }
2689
2761
 
2690
2762
  // src/commands/refresh.ts
2691
2763
  import fs19 from "fs";
2692
2764
  import path16 from "path";
2693
- import chalk11 from "chalk";
2765
+ import chalk12 from "chalk";
2694
2766
  import ora9 from "ora";
2695
2767
 
2696
2768
  // src/lib/git-diff.ts
@@ -2824,7 +2896,7 @@ function discoverGitRepos(parentDir) {
2824
2896
  }
2825
2897
  async function refreshSingleRepo(repoDir, options) {
2826
2898
  const quiet = !!options.quiet;
2827
- const prefix = options.label ? `${chalk11.bold(options.label)} ` : "";
2899
+ const prefix = options.label ? `${chalk12.bold(options.label)} ` : "";
2828
2900
  const state = readState();
2829
2901
  const lastSha = state?.lastRefreshSha ?? null;
2830
2902
  const diff = collectDiff(lastSha);
@@ -2833,7 +2905,7 @@ async function refreshSingleRepo(repoDir, options) {
2833
2905
  if (currentSha) {
2834
2906
  writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
2835
2907
  }
2836
- log(quiet, chalk11.dim(`${prefix}No changes since last refresh.`));
2908
+ log(quiet, chalk12.dim(`${prefix}No changes since last refresh.`));
2837
2909
  return;
2838
2910
  }
2839
2911
  const spinner = quiet ? null : ora9(`${prefix}Analyzing changes...`).start();
@@ -2868,10 +2940,10 @@ async function refreshSingleRepo(repoDir, options) {
2868
2940
  if (options.dryRun) {
2869
2941
  spinner?.info(`${prefix}Dry run \u2014 would update:`);
2870
2942
  for (const doc of response.docsUpdated) {
2871
- console.log(` ${chalk11.yellow("~")} ${doc}`);
2943
+ console.log(` ${chalk12.yellow("~")} ${doc}`);
2872
2944
  }
2873
2945
  if (response.changesSummary) {
2874
- console.log(chalk11.dim(`
2946
+ console.log(chalk12.dim(`
2875
2947
  ${response.changesSummary}`));
2876
2948
  }
2877
2949
  return;
@@ -2879,10 +2951,10 @@ async function refreshSingleRepo(repoDir, options) {
2879
2951
  const written = writeRefreshDocs(response.updatedDocs);
2880
2952
  spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
2881
2953
  for (const file of written) {
2882
- log(quiet, ` ${chalk11.green("\u2713")} ${file}`);
2954
+ log(quiet, ` ${chalk12.green("\u2713")} ${file}`);
2883
2955
  }
2884
2956
  if (response.changesSummary) {
2885
- log(quiet, chalk11.dim(`
2957
+ log(quiet, chalk12.dim(`
2886
2958
  ${response.changesSummary}`));
2887
2959
  }
2888
2960
  if (currentSha) {
@@ -2899,7 +2971,7 @@ async function refreshCommand(options) {
2899
2971
  const auth2 = getStoredAuth();
2900
2972
  if (!auth2) {
2901
2973
  if (quiet) return;
2902
- console.log(chalk11.red("Not authenticated. Run `caliber login` first."));
2974
+ console.log(chalk12.red("Not authenticated. Run `caliber login` first."));
2903
2975
  throw new Error("__exit__");
2904
2976
  }
2905
2977
  if (isGitRepo()) {
@@ -2909,10 +2981,10 @@ async function refreshCommand(options) {
2909
2981
  const repos = discoverGitRepos(process.cwd());
2910
2982
  if (repos.length === 0) {
2911
2983
  if (quiet) return;
2912
- console.log(chalk11.red("Not inside a git repository and no git repos found in child directories."));
2984
+ console.log(chalk12.red("Not inside a git repository and no git repos found in child directories."));
2913
2985
  throw new Error("__exit__");
2914
2986
  }
2915
- log(quiet, chalk11.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
2987
+ log(quiet, chalk12.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
2916
2988
  `));
2917
2989
  const originalDir = process.cwd();
2918
2990
  for (const repo of repos) {
@@ -2922,7 +2994,7 @@ async function refreshCommand(options) {
2922
2994
  await refreshSingleRepo(repo, { ...options, label: repoName });
2923
2995
  } catch (err) {
2924
2996
  if (err instanceof Error && err.message === "__exit__") continue;
2925
- log(quiet, chalk11.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
2997
+ log(quiet, chalk12.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
2926
2998
  }
2927
2999
  }
2928
3000
  process.chdir(originalDir);
@@ -2930,46 +3002,48 @@ async function refreshCommand(options) {
2930
3002
  if (err instanceof Error && err.message === "__exit__") throw err;
2931
3003
  if (quiet) return;
2932
3004
  const msg = err instanceof Error ? err.message : "Unknown error";
2933
- console.log(chalk11.red(`Refresh failed: ${msg}`));
3005
+ console.log(chalk12.red(`Refresh failed: ${msg}`));
2934
3006
  throw new Error("__exit__");
2935
3007
  }
2936
3008
  }
2937
3009
 
2938
3010
  // src/commands/hooks.ts
2939
- import chalk12 from "chalk";
3011
+ import chalk13 from "chalk";
2940
3012
  async function hooksInstallCommand() {
2941
3013
  const result = installHook();
2942
3014
  if (result.alreadyInstalled) {
2943
- console.log(chalk12.dim("Hook already installed."));
3015
+ console.log(chalk13.dim("Hook already installed."));
2944
3016
  return;
2945
3017
  }
2946
- console.log(chalk12.green("\u2713") + " SessionEnd hook installed in .claude/settings.json");
2947
- console.log(chalk12.dim(" Docs will auto-refresh when Claude Code sessions end."));
3018
+ console.log(chalk13.green("\u2713") + " SessionEnd hook installed in .claude/settings.json");
3019
+ console.log(chalk13.dim(" Docs will auto-refresh when Claude Code sessions end."));
2948
3020
  }
2949
3021
  async function hooksRemoveCommand() {
2950
3022
  const result = removeHook();
2951
3023
  if (result.notFound) {
2952
- console.log(chalk12.dim("Hook not found."));
3024
+ console.log(chalk13.dim("Hook not found."));
2953
3025
  return;
2954
3026
  }
2955
- console.log(chalk12.green("\u2713") + " SessionEnd hook removed from .claude/settings.json");
3027
+ console.log(chalk13.green("\u2713") + " SessionEnd hook removed from .claude/settings.json");
2956
3028
  }
2957
3029
  async function hooksStatusCommand() {
2958
3030
  const installed = isHookInstalled();
2959
3031
  if (installed) {
2960
- console.log(chalk12.green("\u2713") + " Auto-refresh hook is " + chalk12.green("installed"));
3032
+ console.log(chalk13.green("\u2713") + " Auto-refresh hook is " + chalk13.green("installed"));
2961
3033
  } else {
2962
- console.log(chalk12.dim("\u2717") + " Auto-refresh hook is " + chalk12.yellow("not installed"));
2963
- console.log(chalk12.dim(" Run `caliber hooks install` to enable auto-refresh on session end."));
3034
+ console.log(chalk13.dim("\u2717") + " Auto-refresh hook is " + chalk13.yellow("not installed"));
3035
+ console.log(chalk13.dim(" Run `caliber hooks install` to enable auto-refresh on session end."));
2964
3036
  }
2965
3037
  }
2966
3038
 
2967
3039
  // src/commands/review.ts
2968
- import chalk13 from "chalk";
2969
- import readline3 from "readline";
3040
+ import chalk14 from "chalk";
3041
+ import readline2 from "readline";
2970
3042
  import ora10 from "ora";
3043
+ import select2 from "@inquirer/select";
3044
+ import confirm2 from "@inquirer/confirm";
2971
3045
  function prompt(question) {
2972
- const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
3046
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
2973
3047
  return new Promise((resolve2) => {
2974
3048
  rl.question(question, (answer) => {
2975
3049
  rl.close();
@@ -2978,30 +3052,26 @@ function prompt(question) {
2978
3052
  });
2979
3053
  }
2980
3054
  async function promptRating() {
2981
- console.log(chalk13.bold("\n How helpful was Caliber in setting up your coding agent?\n"));
2982
- console.log(" 1. Not helpful at all");
2983
- console.log(" 2. Slightly helpful");
2984
- console.log(" 3. Moderately helpful");
2985
- console.log(" 4. Very helpful");
2986
- console.log(" 5. Extremely helpful");
2987
- while (true) {
2988
- const answer = await prompt(chalk13.cyan("\n Rating (1-5): "));
2989
- const num = parseInt(answer, 10);
2990
- if (num >= 1 && num <= 5) return num;
2991
- console.log(chalk13.yellow(" Please enter a number between 1 and 5."));
2992
- }
3055
+ return select2({
3056
+ message: "How helpful was Caliber in setting up your coding agent?",
3057
+ choices: [
3058
+ { name: "Not helpful at all", value: 1 },
3059
+ { name: "Slightly helpful", value: 2 },
3060
+ { name: "Moderately helpful", value: 3 },
3061
+ { name: "Very helpful", value: 4 },
3062
+ { name: "Extremely helpful", value: 5 }
3063
+ ]
3064
+ });
2993
3065
  }
2994
3066
  async function promptRecommend() {
2995
- console.log(chalk13.bold("\n Would you recommend Caliber to a colleague?\n"));
2996
- console.log(" 1. Yes");
2997
- console.log(" 2. No");
2998
- console.log(" 3. Maybe");
2999
- while (true) {
3000
- const answer = await prompt(chalk13.cyan("\n Choose (1-3): "));
3001
- const map = { "1": "yes", "2": "no", "3": "maybe" };
3002
- if (map[answer]) return map[answer];
3003
- console.log(chalk13.yellow(" Please enter 1, 2, or 3."));
3004
- }
3067
+ return select2({
3068
+ message: "Would you recommend Caliber to a colleague?",
3069
+ choices: [
3070
+ { name: "Yes", value: "yes" },
3071
+ { name: "No", value: "no" },
3072
+ { name: "Maybe", value: "maybe" }
3073
+ ]
3074
+ });
3005
3075
  }
3006
3076
  function starRating(rating) {
3007
3077
  return "\u2605".repeat(rating) + "\u2606".repeat(5 - rating);
@@ -3012,7 +3082,7 @@ async function submitReview(body) {
3012
3082
  await apiRequest("/api/reviews", { method: "POST", body });
3013
3083
  spinner.succeed("Review submitted");
3014
3084
  trackEvent("review_submitted", { rating: body.rating, would_recommend: body.wouldRecommend });
3015
- console.log(chalk13.green.bold("\n Thank you for your feedback!\n"));
3085
+ console.log(chalk14.green.bold("\n Thank you for your feedback!\n"));
3016
3086
  } catch (err) {
3017
3087
  const msg = err instanceof Error ? err.message : "Unknown error";
3018
3088
  spinner.fail(`Failed to submit review: ${msg}`);
@@ -3023,37 +3093,37 @@ async function submitReview(body) {
3023
3093
  async function reviewCommand(message, options) {
3024
3094
  const auth2 = getStoredAuth();
3025
3095
  if (!auth2) {
3026
- console.log(chalk13.red("\n Not authenticated. Run `caliber login` first.\n"));
3096
+ console.log(chalk14.red("\n Not authenticated. Run `caliber login` first.\n"));
3027
3097
  throw new Error("__exit__");
3028
3098
  }
3029
3099
  if (message) {
3030
3100
  const rating2 = options.rating ? parseInt(options.rating, 10) : 5;
3031
3101
  if (rating2 < 1 || rating2 > 5 || isNaN(rating2)) {
3032
- console.log(chalk13.red("Rating must be between 1 and 5."));
3102
+ console.log(chalk14.red("Rating must be between 1 and 5."));
3033
3103
  throw new Error("__exit__");
3034
3104
  }
3035
- console.log(chalk13.dim(`
3105
+ console.log(chalk14.dim(`
3036
3106
  ${starRating(rating2)} "${message}"
3037
3107
  `));
3038
3108
  await submitReview({ rating: rating2, bestPart: message, biggestGap: "", wouldRecommend: "yes" });
3039
3109
  return;
3040
3110
  }
3041
- console.log(chalk13.hex("#6366f1").bold("\n Share your feedback\n"));
3042
- console.log(chalk13.dim(" We'd love to hear how Caliber is working for you."));
3043
- console.log(chalk13.dim(" This takes under 2 minutes.\n"));
3044
- console.log(chalk13.dim(' Tip: use `caliber review "your feedback"` for a quick review.\n'));
3111
+ console.log(chalk14.hex("#6366f1").bold("\n Share your feedback\n"));
3112
+ console.log(chalk14.dim(" We'd love to hear how Caliber is working for you."));
3113
+ console.log(chalk14.dim(" This takes under 2 minutes.\n"));
3114
+ console.log(chalk14.dim(' Tip: use `caliber review "your feedback"` for a quick review.\n'));
3045
3115
  const rating = await promptRating();
3046
- const bestPart = await prompt(chalk13.cyan("\n What did you find most useful? "));
3047
- const biggestGap = await prompt(chalk13.cyan("\n What was missing or could be better? "));
3116
+ const bestPart = await prompt(chalk14.cyan("\n What did you find most useful? "));
3117
+ const biggestGap = await prompt(chalk14.cyan("\n What was missing or could be better? "));
3048
3118
  const wouldRecommend = await promptRecommend();
3049
- console.log(chalk13.bold("\n Your review:\n"));
3119
+ console.log(chalk14.bold("\n Your review:\n"));
3050
3120
  console.log(` Rating: ${starRating(rating)} (${rating}/5)`);
3051
- console.log(` Most useful: ${bestPart || chalk13.dim("(skipped)")}`);
3052
- console.log(` Could be better: ${biggestGap || chalk13.dim("(skipped)")}`);
3121
+ console.log(` Most useful: ${bestPart || chalk14.dim("(skipped)")}`);
3122
+ console.log(` Could be better: ${biggestGap || chalk14.dim("(skipped)")}`);
3053
3123
  console.log(` Would recommend: ${wouldRecommend}`);
3054
- const confirm = await prompt(chalk13.cyan("\n Submit this review? (Y/n): "));
3055
- if (confirm.toLowerCase() === "n") {
3056
- console.log(chalk13.dim("\n Review cancelled.\n"));
3124
+ const shouldSubmit = await confirm2({ message: "Submit this review?", default: true });
3125
+ if (!shouldSubmit) {
3126
+ console.log(chalk14.dim("\n Review cancelled.\n"));
3057
3127
  return;
3058
3128
  }
3059
3129
  await submitReview({ rating, bestPart, biggestGap, wouldRecommend });
@@ -3069,7 +3139,7 @@ program.name("caliber").description("Configure your coding agent environment").v
3069
3139
  program.command("init").description("Initialize coding agent setup for this project").option("--agent <type>", "Target agent: claude, cursor, or both").option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(initCommand);
3070
3140
  program.command("undo").description("Revert all config changes made by Caliber").action(undoCommand);
3071
3141
  program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(statusCommand);
3072
- program.command("update").description("Re-analyze project and update setup").option("--dry-run", "Preview changes without writing files").action(updateCommand);
3142
+ 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);
3073
3143
  program.command("login").description("Authenticate with Caliber").action(loginCommand);
3074
3144
  program.command("logout").description("Clear stored credentials").action(logoutCommand);
3075
3145
  program.command("recommend").description("Discover and manage skill recommendations").option("--generate", "Generate new recommendations").option("--status <status>", "Filter by status: pending, accepted, dismissed").action(recommendCommand);
@@ -3087,23 +3157,16 @@ hooks.command("status").description("Check if auto-refresh hook is installed").a
3087
3157
  import fs21 from "fs";
3088
3158
  import path18 from "path";
3089
3159
  import { fileURLToPath as fileURLToPath4 } from "url";
3090
- import readline4 from "readline";
3091
3160
  import { execSync as execSync4 } from "child_process";
3092
- import chalk14 from "chalk";
3161
+ import chalk15 from "chalk";
3093
3162
  import ora11 from "ora";
3163
+ import confirm3 from "@inquirer/confirm";
3094
3164
  var __dirname_vc = path18.dirname(fileURLToPath4(import.meta.url));
3095
3165
  var pkg4 = JSON.parse(
3096
3166
  fs21.readFileSync(path18.resolve(__dirname_vc, "..", "package.json"), "utf-8")
3097
3167
  );
3098
- function promptYesNo(question) {
3099
- const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
3100
- return new Promise((resolve2) => {
3101
- rl.question(chalk14.cyan(`${question} `), (answer) => {
3102
- rl.close();
3103
- const normalized = answer.trim().toLowerCase();
3104
- resolve2(normalized === "" || normalized === "y" || normalized === "yes");
3105
- });
3106
- });
3168
+ async function promptYesNo(question) {
3169
+ return confirm3({ message: question, default: true });
3107
3170
  }
3108
3171
  async function checkForUpdates() {
3109
3172
  if (process.env.CALIBER_SKIP_UPDATE_CHECK) return;
@@ -3123,17 +3186,17 @@ async function checkForUpdates() {
3123
3186
  const isInteractive = process.stdin.isTTY === true;
3124
3187
  if (!isInteractive) {
3125
3188
  console.log(
3126
- chalk14.yellow(
3189
+ chalk15.yellow(
3127
3190
  `
3128
3191
  Update available: ${current} -> ${latest}
3129
- Run ${chalk14.bold("npm install -g @caliber-ai/cli")} to upgrade.
3192
+ Run ${chalk15.bold("npm install -g @caliber-ai/cli")} to upgrade.
3130
3193
  `
3131
3194
  )
3132
3195
  );
3133
3196
  return;
3134
3197
  }
3135
3198
  console.log(
3136
- chalk14.yellow(`
3199
+ chalk15.yellow(`
3137
3200
  Update available: ${current} -> ${latest}`)
3138
3201
  );
3139
3202
  const shouldUpdate = await promptYesNo("Would you like to update now? (Y/n)");
@@ -3144,9 +3207,9 @@ Update available: ${current} -> ${latest}`)
3144
3207
  const spinner = ora11("Updating @caliber-ai/cli...").start();
3145
3208
  try {
3146
3209
  execSync4("npm install -g @caliber-ai/cli --force", { stdio: "pipe" });
3147
- spinner.succeed(chalk14.green(`Updated to ${latest}`));
3210
+ spinner.succeed(chalk15.green(`Updated to ${latest}`));
3148
3211
  const args = process.argv.slice(2);
3149
- console.log(chalk14.dim(`
3212
+ console.log(chalk15.dim(`
3150
3213
  Restarting: caliber ${args.join(" ")}
3151
3214
  `));
3152
3215
  execSync4(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
@@ -3157,8 +3220,8 @@ Restarting: caliber ${args.join(" ")}
3157
3220
  } catch {
3158
3221
  spinner.fail("Update failed");
3159
3222
  console.log(
3160
- chalk14.yellow(
3161
- `Run ${chalk14.bold("npm install -g @caliber-ai/cli")} manually to upgrade.
3223
+ chalk15.yellow(
3224
+ `Run ${chalk15.bold("npm install -g @caliber-ai/cli")} manually to upgrade.
3162
3225
  `
3163
3226
  )
3164
3227
  );