@rely-ai/caliber 1.30.7 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.js +704 -406
  2. package/package.json +21 -2
package/dist/bin.js CHANGED
@@ -25,7 +25,7 @@ __export(config_exports, {
25
25
  writeConfigFile: () => writeConfigFile
26
26
  });
27
27
  import fs4 from "fs";
28
- import path5 from "path";
28
+ import path6 from "path";
29
29
  import os2 from "os";
30
30
  function getMaxPromptTokens() {
31
31
  const config = loadConfig();
@@ -125,8 +125,8 @@ var CONFIG_DIR, CONFIG_FILE, DEFAULT_MODELS, MODEL_CONTEXT_WINDOWS, DEFAULT_CONT
125
125
  var init_config = __esm({
126
126
  "src/llm/config.ts"() {
127
127
  "use strict";
128
- CONFIG_DIR = path5.join(os2.homedir(), ".caliber");
129
- CONFIG_FILE = path5.join(CONFIG_DIR, "config.json");
128
+ CONFIG_DIR = path6.join(os2.homedir(), ".caliber");
129
+ CONFIG_FILE = path6.join(CONFIG_DIR, "config.json");
130
130
  DEFAULT_MODELS = {
131
131
  anthropic: "claude-sonnet-4-6",
132
132
  vertex: "claude-sonnet-4-6",
@@ -233,11 +233,11 @@ var init_types = __esm({
233
233
  // src/utils/editor.ts
234
234
  import { execSync as execSync13, spawn as spawn3 } from "child_process";
235
235
  import fs26 from "fs";
236
- import path22 from "path";
236
+ import path23 from "path";
237
237
  import os6 from "os";
238
238
  function getEmptyFilePath(proposedPath) {
239
239
  fs26.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
240
- const tempPath = path22.join(DIFF_TEMP_DIR, path22.basename(proposedPath));
240
+ const tempPath = path23.join(DIFF_TEMP_DIR, path23.basename(proposedPath));
241
241
  fs26.writeFileSync(tempPath, "");
242
242
  return tempPath;
243
243
  }
@@ -278,7 +278,7 @@ var init_editor = __esm({
278
278
  "src/utils/editor.ts"() {
279
279
  "use strict";
280
280
  IS_WINDOWS3 = process.platform === "win32";
281
- DIFF_TEMP_DIR = path22.join(os6.tmpdir(), "caliber-diff");
281
+ DIFF_TEMP_DIR = path23.join(os6.tmpdir(), "caliber-diff");
282
282
  }
283
283
  });
284
284
 
@@ -504,7 +504,7 @@ __export(lock_exports, {
504
504
  releaseLock: () => releaseLock
505
505
  });
506
506
  import fs37 from "fs";
507
- import path29 from "path";
507
+ import path30 from "path";
508
508
  import os8 from "os";
509
509
  function isCaliberRunning() {
510
510
  try {
@@ -538,7 +538,7 @@ var LOCK_FILE, STALE_MS;
538
538
  var init_lock = __esm({
539
539
  "src/lib/lock.ts"() {
540
540
  "use strict";
541
- LOCK_FILE = path29.join(os8.tmpdir(), ".caliber.lock");
541
+ LOCK_FILE = path30.join(os8.tmpdir(), ".caliber.lock");
542
542
  STALE_MS = 10 * 60 * 1e3;
543
543
  }
544
544
  });
@@ -546,17 +546,17 @@ var init_lock = __esm({
546
546
  // src/cli.ts
547
547
  import { Command } from "commander";
548
548
  import fs47 from "fs";
549
- import path38 from "path";
549
+ import path39 from "path";
550
550
  import { fileURLToPath } from "url";
551
551
 
552
552
  // src/commands/init.ts
553
- import path25 from "path";
553
+ import path26 from "path";
554
554
  import chalk14 from "chalk";
555
555
  import fs32 from "fs";
556
556
 
557
557
  // src/fingerprint/index.ts
558
558
  import fs8 from "fs";
559
- import path7 from "path";
559
+ import path8 from "path";
560
560
 
561
561
  // src/fingerprint/git.ts
562
562
  import { execSync } from "child_process";
@@ -801,10 +801,25 @@ function readExistingConfigs(dir) {
801
801
 
802
802
  // src/fingerprint/code-analysis.ts
803
803
  import fs3 from "fs";
804
- import path4 from "path";
804
+ import path5 from "path";
805
805
  import { execSync as execSync3 } from "child_process";
806
806
 
807
807
  // src/lib/sanitize.ts
808
+ import path4 from "path";
809
+ function sanitizePath(component) {
810
+ const cleaned = component.replace(/\.\./g, "").replace(/[/\\]/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
811
+ if (!cleaned) {
812
+ throw new Error(`Invalid path component: ${component}`);
813
+ }
814
+ return cleaned;
815
+ }
816
+ function assertPathWithinDir(filePath, baseDir) {
817
+ const resolved = path4.resolve(baseDir, filePath);
818
+ const resolvedBase = path4.resolve(baseDir);
819
+ if (!resolved.startsWith(resolvedBase + path4.sep) && resolved !== resolvedBase) {
820
+ throw new Error(`Path traversal detected: ${filePath} escapes ${baseDir}`);
821
+ }
822
+ }
808
823
  var KNOWN_PREFIX_PATTERNS = [
809
824
  // Anthropic (before generic sk- pattern)
810
825
  [/sk-ant-[A-Za-z0-9_-]{20,}/g, "[REDACTED]"],
@@ -828,9 +843,13 @@ var KNOWN_PREFIX_PATTERNS = [
828
843
  // Bearer tokens
829
844
  [/[Bb]earer\s+[A-Za-z0-9_\-.]{20,}/g, "[REDACTED]"],
830
845
  // PEM private keys
831
- [/-----BEGIN[A-Z ]+KEY-----[\s\S]+?-----END[A-Z ]+KEY-----/g, "[REDACTED]"]
846
+ [/-----BEGIN[A-Z ]+KEY-----[\s\S]+?-----END[A-Z ]+KEY-----/g, "[REDACTED]"],
847
+ // Database connection strings with credentials
848
+ [/(postgresql|mysql|mongodb(\+srv)?|redis|amqp):\/\/[^@\s]+:[^@\s]+@[^\s'"]+/g, "[REDACTED]"],
849
+ // GitLab tokens
850
+ [/glpat-[a-zA-Z0-9_-]{20,}/g, "[REDACTED]"]
832
851
  ];
833
- var SENSITIVE_ASSIGNMENT = /(?:api[_-]?key|secret[_-]?key|password|token|credential|auth[_-]?token|private[_-]?key)\s*[:=]\s*['"]?([^\s'"]{8,500})['"]?/gi;
852
+ var SENSITIVE_ASSIGNMENT = /(?:api[_-]?key|secret[_-]?key|password|token|credential|auth[_-]?token|private[_-]?key|database[_-]?url|connection[_-]?string)\s*[:=]\s*['"]?([^\s'"]{8,500})['"]?/gi;
834
853
  function sanitizeSecrets(text) {
835
854
  let result = text;
836
855
  for (const [pattern, replacement] of KNOWN_PREFIX_PATTERNS) {
@@ -949,12 +968,15 @@ var SKIP_PATTERNS = [
949
968
  /\.d\.ts$/,
950
969
  /\.generated\./,
951
970
  /\.snap$/,
952
- /^\.env($|\.)/
971
+ /^\.env($|\.)/,
972
+ /\.(pem|key|crt|cer|pfx|p12|jks|keystore)$/,
973
+ /^id_(rsa|ed25519|ecdsa)$/,
974
+ /^(known_hosts|authorized_keys)$/
953
975
  ];
954
976
  var COMMENT_LINE = {
955
- "c": /^\s*\/\//,
956
- "h": /^\s*#/,
957
- "x": /^\s*<!--.*-->\s*$/
977
+ c: /^\s*\/\//,
978
+ h: /^\s*#/,
979
+ x: /^\s*<!--.*-->\s*$/
958
980
  };
959
981
  var EXT_COMMENT = {
960
982
  ".ts": "c",
@@ -1060,7 +1082,6 @@ function extractSkeleton(content, ext) {
1060
1082
  const lines = content.split("\n");
1061
1083
  const result = [];
1062
1084
  let braceDepth = 0;
1063
- let inSignature = false;
1064
1085
  let skipBody = false;
1065
1086
  if ([".py", ".pyw", ".rb"].includes(ext)) {
1066
1087
  return extractSkeletonIndentBased(lines, ext);
@@ -1086,7 +1107,9 @@ function extractSkeleton(content, ext) {
1086
1107
  }
1087
1108
  continue;
1088
1109
  }
1089
- const isFnOrClass = /^\s*(export\s+)?(default\s+)?(async\s+)?(function|class|const\s+\w+\s*=\s*(async\s*)?\(|pub\s+fn|fn|func)\s/.test(trimmed) || /^\s*(def|func|fn|pub fn|pub async fn)\s/.test(trimmed);
1110
+ const isFnOrClass = /^\s*(export\s+)?(default\s+)?(async\s+)?(function|class|const\s+\w+\s*=\s*(async\s*)?\(|pub\s+fn|fn|func)\s/.test(
1111
+ trimmed
1112
+ ) || /^\s*(def|func|fn|pub fn|pub async fn)\s/.test(trimmed);
1090
1113
  if (isFnOrClass && braceDepth === 0) {
1091
1114
  result.push(line);
1092
1115
  const opens = (line.match(/{/g) || []).length;
@@ -1114,7 +1137,7 @@ function extractSkeleton(content, ext) {
1114
1137
  }
1115
1138
  return result.join("\n");
1116
1139
  }
1117
- function extractSkeletonIndentBased(lines, ext) {
1140
+ function extractSkeletonIndentBased(lines, _ext) {
1118
1141
  const result = [];
1119
1142
  let skipIndent = -1;
1120
1143
  for (const line of lines) {
@@ -1146,18 +1169,18 @@ function extractSkeletonIndentBased(lines, ext) {
1146
1169
  }
1147
1170
  function extractImports(content, filePath) {
1148
1171
  const imports = [];
1149
- const dir = path4.dirname(filePath);
1172
+ const dir = path5.dirname(filePath);
1150
1173
  for (const line of content.split("\n")) {
1151
1174
  const trimmed = line.trim();
1152
1175
  const jsMatch = trimmed.match(/(?:from|require\()\s*['"]([^'"]+)['"]/);
1153
1176
  if (jsMatch && jsMatch[1].startsWith(".")) {
1154
- imports.push(path4.normalize(path4.join(dir, jsMatch[1])));
1177
+ imports.push(path5.normalize(path5.join(dir, jsMatch[1])));
1155
1178
  continue;
1156
1179
  }
1157
1180
  const pyMatch = trimmed.match(/^from\s+(\.[.\w]*)\s+import/);
1158
1181
  if (pyMatch) {
1159
1182
  const modulePath = pyMatch[1].replace(/\./g, "/");
1160
- imports.push(path4.normalize(path4.join(dir, modulePath)));
1183
+ imports.push(path5.normalize(path5.join(dir, modulePath)));
1161
1184
  continue;
1162
1185
  }
1163
1186
  const goMatch = trimmed.match(/^\s*"([^"]+)"/);
@@ -1170,11 +1193,20 @@ function extractImports(content, filePath) {
1170
1193
  function buildImportCounts(files) {
1171
1194
  const counts = /* @__PURE__ */ new Map();
1172
1195
  for (const [filePath, content] of files) {
1173
- const ext = path4.extname(filePath).toLowerCase();
1196
+ const ext = path5.extname(filePath).toLowerCase();
1174
1197
  if (!SOURCE_EXTENSIONS.has(ext)) continue;
1175
1198
  const imports = extractImports(content, filePath);
1176
1199
  for (const imp of imports) {
1177
- const candidates = [imp, imp + ".ts", imp + ".js", imp + ".tsx", imp + ".jsx", imp + "/index.ts", imp + "/index.js", imp + ".py"];
1200
+ const candidates = [
1201
+ imp,
1202
+ imp + ".ts",
1203
+ imp + ".js",
1204
+ imp + ".tsx",
1205
+ imp + ".jsx",
1206
+ imp + "/index.ts",
1207
+ imp + "/index.js",
1208
+ imp + ".py"
1209
+ ];
1178
1210
  for (const candidate of candidates) {
1179
1211
  const normalized = candidate.replace(/\\/g, "/");
1180
1212
  if (files.has(normalized)) {
@@ -1204,7 +1236,7 @@ function getGitFrequency(dir) {
1204
1236
  function groupByDirectory(files) {
1205
1237
  const groups = /* @__PURE__ */ new Map();
1206
1238
  for (const f of files) {
1207
- const dir = path4.dirname(f.path);
1239
+ const dir = path5.dirname(f.path);
1208
1240
  const group = groups.get(dir) || [];
1209
1241
  group.push(f);
1210
1242
  groups.set(dir, group);
@@ -1216,7 +1248,9 @@ function structuralFingerprint(content, ext) {
1216
1248
  const bucket = Math.floor(lines.length / 10) * 10;
1217
1249
  const first = (lines[0] || "").trim().slice(0, 50);
1218
1250
  const imports = lines.filter((l) => /^\s*(import |from |require\(|use )/.test(l)).length;
1219
- const fns = lines.filter((l) => /^\s*(export\s+)?(async\s+)?(function |def |func |fn |pub fn |class )/.test(l)).length;
1251
+ const fns = lines.filter(
1252
+ (l) => /^\s*(export\s+)?(async\s+)?(function |def |func |fn |pub fn |class )/.test(l)
1253
+ ).length;
1220
1254
  return `${ext}:${bucket}:${imports}:${fns}:${first}`;
1221
1255
  }
1222
1256
  function analyzeCode(dir) {
@@ -1225,14 +1259,14 @@ function analyzeCode(dir) {
1225
1259
  let totalChars = 0;
1226
1260
  for (const relPath of allPaths) {
1227
1261
  try {
1228
- totalChars += fs3.statSync(path4.join(dir, relPath)).size;
1262
+ totalChars += fs3.statSync(path5.join(dir, relPath)).size;
1229
1263
  } catch {
1230
1264
  }
1231
1265
  }
1232
1266
  const fileContents = /* @__PURE__ */ new Map();
1233
1267
  for (const relPath of allPaths) {
1234
1268
  try {
1235
- const content = fs3.readFileSync(path4.join(dir, relPath), "utf-8");
1269
+ const content = fs3.readFileSync(path5.join(dir, relPath), "utf-8");
1236
1270
  if (content.split("\n").length <= 500) fileContents.set(relPath, content);
1237
1271
  } catch {
1238
1272
  }
@@ -1242,7 +1276,7 @@ function analyzeCode(dir) {
1242
1276
  const scored = [];
1243
1277
  let compressedChars = 0;
1244
1278
  for (const [relPath, rawContent] of fileContents) {
1245
- const ext = path4.extname(relPath).toLowerCase();
1279
+ const ext = path5.extname(relPath).toLowerCase();
1246
1280
  const compressed = compressContent(rawContent, ext);
1247
1281
  const skeleton = extractSkeleton(compressed, ext);
1248
1282
  compressedChars += compressed.length;
@@ -1263,7 +1297,12 @@ function analyzeCode(dir) {
1263
1297
  const repFP = structuralFingerprint(rep.compressed, rep.ext);
1264
1298
  const similar = group.slice(1).filter((f) => structuralFingerprint(f.compressed, f.ext) === repFP);
1265
1299
  const unique = group.slice(1).filter((f) => structuralFingerprint(f.compressed, f.ext) !== repFP);
1266
- const repEntry = { path: rep.path, content: sanitizeSecrets(rep.compressed), size: rep.compressed.length, priority: rep.score };
1300
+ const repEntry = {
1301
+ path: rep.path,
1302
+ content: sanitizeSecrets(rep.compressed),
1303
+ size: rep.compressed.length,
1304
+ priority: rep.score
1305
+ };
1267
1306
  const repSize = rep.path.length + rep.compressed.length + 10;
1268
1307
  if (includedChars + repSize <= CHAR_BUDGET) {
1269
1308
  result.push(repEntry);
@@ -1271,18 +1310,28 @@ function analyzeCode(dir) {
1271
1310
  }
1272
1311
  if (similar.length > 0) {
1273
1312
  dupGroups++;
1274
- const names = similar.map((f) => path4.basename(f.path));
1313
+ const names = similar.map((f) => path5.basename(f.path));
1275
1314
  const summary = `(${similar.length} similar file${similar.length === 1 ? "" : "s"} in ${dirPath}/: ${names.join(", ")})`;
1276
1315
  const summarySize = summary.length + 30;
1277
1316
  if (includedChars + summarySize <= CHAR_BUDGET) {
1278
- result.push({ path: `[similar to ${rep.path}]`, content: summary, size: summary.length, priority: rep.score });
1317
+ result.push({
1318
+ path: `[similar to ${rep.path}]`,
1319
+ content: summary,
1320
+ size: summary.length,
1321
+ priority: rep.score
1322
+ });
1279
1323
  includedChars += summarySize;
1280
1324
  }
1281
1325
  }
1282
1326
  for (const f of unique) {
1283
1327
  const skeletonSize = f.path.length + f.skeleton.length + 10;
1284
1328
  if (includedChars + skeletonSize <= CHAR_BUDGET) {
1285
- result.push({ path: f.path, content: sanitizeSecrets(f.skeleton), size: f.skeleton.length, priority: f.score });
1329
+ result.push({
1330
+ path: f.path,
1331
+ content: sanitizeSecrets(f.skeleton),
1332
+ size: f.skeleton.length,
1333
+ priority: f.score
1334
+ });
1286
1335
  includedChars += skeletonSize;
1287
1336
  }
1288
1337
  }
@@ -1292,7 +1341,12 @@ function analyzeCode(dir) {
1292
1341
  if (includedPaths.has(f.path)) continue;
1293
1342
  const skeletonSize = f.path.length + f.skeleton.length + 10;
1294
1343
  if (includedChars + skeletonSize > CHAR_BUDGET) continue;
1295
- result.push({ path: f.path, content: sanitizeSecrets(f.skeleton), size: f.skeleton.length, priority: f.score });
1344
+ result.push({
1345
+ path: f.path,
1346
+ content: sanitizeSecrets(f.skeleton),
1347
+ size: f.skeleton.length,
1348
+ priority: f.score
1349
+ });
1296
1350
  includedChars += skeletonSize;
1297
1351
  }
1298
1352
  return {
@@ -1308,7 +1362,7 @@ function analyzeCode(dir) {
1308
1362
  }
1309
1363
  function walkDir(base, rel, depth, maxDepth, files) {
1310
1364
  if (depth > maxDepth) return;
1311
- const fullPath = path4.join(base, rel);
1365
+ const fullPath = path5.join(base, rel);
1312
1366
  let entries;
1313
1367
  try {
1314
1368
  entries = fs3.readdirSync(fullPath, { withFileTypes: true });
@@ -1324,7 +1378,7 @@ function walkDir(base, rel, depth, maxDepth, files) {
1324
1378
  } else if (entry.isFile()) {
1325
1379
  if (SKIP_FILES.has(entry.name)) continue;
1326
1380
  if (SKIP_PATTERNS.some((p) => p.test(entry.name))) continue;
1327
- const ext = path4.extname(entry.name).toLowerCase();
1381
+ const ext = path5.extname(entry.name).toLowerCase();
1328
1382
  if (TEXT_EXTENSIONS.has(ext) || depth === 0 && !ext && !entry.name.startsWith(".")) {
1329
1383
  files.push(relPath);
1330
1384
  }
@@ -1332,7 +1386,7 @@ function walkDir(base, rel, depth, maxDepth, files) {
1332
1386
  }
1333
1387
  }
1334
1388
  function filePriority(filePath) {
1335
- const base = path4.basename(filePath);
1389
+ const base = path5.basename(filePath);
1336
1390
  const entryPoints = /* @__PURE__ */ new Set([
1337
1391
  "index.ts",
1338
1392
  "index.js",
@@ -2076,7 +2130,7 @@ function isClaudeCliAvailable() {
2076
2130
 
2077
2131
  // src/llm/utils.ts
2078
2132
  function extractJson(text) {
2079
- const startIdx = text.search(/[\[{]/);
2133
+ const startIdx = text.search(/[[{]/);
2080
2134
  if (startIdx === -1) return null;
2081
2135
  let depth = 0;
2082
2136
  let inString = false;
@@ -2831,14 +2885,14 @@ init_config();
2831
2885
 
2832
2886
  // src/fingerprint/cache.ts
2833
2887
  import fs7 from "fs";
2834
- import path6 from "path";
2888
+ import path7 from "path";
2835
2889
  import crypto from "crypto";
2836
2890
  import { execSync as execSync7 } from "child_process";
2837
2891
  var CACHE_VERSION = 1;
2838
2892
  var CACHE_DIR = ".caliber/cache";
2839
2893
  var CACHE_FILE = "fingerprint.json";
2840
2894
  function getCachePath(dir) {
2841
- return path6.join(dir, CACHE_DIR, CACHE_FILE);
2895
+ return path7.join(dir, CACHE_DIR, CACHE_FILE);
2842
2896
  }
2843
2897
  function getGitHead(dir) {
2844
2898
  try {
@@ -2897,7 +2951,7 @@ function loadFingerprintCache(dir, fileTree) {
2897
2951
  function saveFingerprintCache(dir, fileTree, codeAnalysis, languages, frameworks, tools, workspaces) {
2898
2952
  const cachePath = getCachePath(dir);
2899
2953
  try {
2900
- const cacheDir = path6.dirname(cachePath);
2954
+ const cacheDir = path7.dirname(cachePath);
2901
2955
  if (!fs7.existsSync(cacheDir)) {
2902
2956
  fs7.mkdirSync(cacheDir, { recursive: true });
2903
2957
  }
@@ -2971,7 +3025,7 @@ async function collectFingerprint(dir) {
2971
3025
  }
2972
3026
  function readPackageName(dir) {
2973
3027
  try {
2974
- const pkgPath = path7.join(dir, "package.json");
3028
+ const pkgPath = path8.join(dir, "package.json");
2975
3029
  if (!fs8.existsSync(pkgPath)) return void 0;
2976
3030
  const pkg3 = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
2977
3031
  return pkg3.name;
@@ -2987,7 +3041,7 @@ async function enrichWithLLM(fingerprint) {
2987
3041
  const suffixCounts = {};
2988
3042
  for (const entry of fingerprint.fileTree) {
2989
3043
  if (entry.endsWith("/")) continue;
2990
- const ext = path7.extname(entry).toLowerCase();
3044
+ const ext = path8.extname(entry).toLowerCase();
2991
3045
  if (ext) {
2992
3046
  suffixCounts[ext] = (suffixCounts[ext] || 0) + 1;
2993
3047
  }
@@ -3004,20 +3058,20 @@ async function enrichWithLLM(fingerprint) {
3004
3058
 
3005
3059
  // src/scanner/index.ts
3006
3060
  import fs9 from "fs";
3007
- import path8 from "path";
3061
+ import path9 from "path";
3008
3062
  import crypto2 from "crypto";
3009
3063
  import os4 from "os";
3010
3064
  function detectPlatforms() {
3011
3065
  const home = os4.homedir();
3012
3066
  return {
3013
- claude: fs9.existsSync(path8.join(home, ".claude")),
3067
+ claude: fs9.existsSync(path9.join(home, ".claude")),
3014
3068
  cursor: fs9.existsSync(getCursorConfigDir()),
3015
- codex: fs9.existsSync(path8.join(home, ".codex"))
3069
+ codex: fs9.existsSync(path9.join(home, ".codex"))
3016
3070
  };
3017
3071
  }
3018
3072
  function scanLocalState(dir) {
3019
3073
  const items = [];
3020
- const claudeMdPath = path8.join(dir, "CLAUDE.md");
3074
+ const claudeMdPath = path9.join(dir, "CLAUDE.md");
3021
3075
  if (fs9.existsSync(claudeMdPath)) {
3022
3076
  items.push({
3023
3077
  type: "rule",
@@ -3027,10 +3081,10 @@ function scanLocalState(dir) {
3027
3081
  path: claudeMdPath
3028
3082
  });
3029
3083
  }
3030
- const skillsDir = path8.join(dir, ".claude", "skills");
3084
+ const skillsDir = path9.join(dir, ".claude", "skills");
3031
3085
  if (fs9.existsSync(skillsDir)) {
3032
3086
  for (const file of fs9.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
3033
- const filePath = path8.join(skillsDir, file);
3087
+ const filePath = path9.join(skillsDir, file);
3034
3088
  items.push({
3035
3089
  type: "skill",
3036
3090
  platform: "claude",
@@ -3040,7 +3094,7 @@ function scanLocalState(dir) {
3040
3094
  });
3041
3095
  }
3042
3096
  }
3043
- const mcpJsonPath = path8.join(dir, ".mcp.json");
3097
+ const mcpJsonPath = path9.join(dir, ".mcp.json");
3044
3098
  if (fs9.existsSync(mcpJsonPath)) {
3045
3099
  try {
3046
3100
  const mcpJson = JSON.parse(fs9.readFileSync(mcpJsonPath, "utf-8"));
@@ -3059,7 +3113,7 @@ function scanLocalState(dir) {
3059
3113
  warnScanSkip(".mcp.json", error);
3060
3114
  }
3061
3115
  }
3062
- const agentsMdPath = path8.join(dir, "AGENTS.md");
3116
+ const agentsMdPath = path9.join(dir, "AGENTS.md");
3063
3117
  if (fs9.existsSync(agentsMdPath)) {
3064
3118
  items.push({
3065
3119
  type: "rule",
@@ -3069,11 +3123,11 @@ function scanLocalState(dir) {
3069
3123
  path: agentsMdPath
3070
3124
  });
3071
3125
  }
3072
- const codexSkillsDir = path8.join(dir, ".agents", "skills");
3126
+ const codexSkillsDir = path9.join(dir, ".agents", "skills");
3073
3127
  if (fs9.existsSync(codexSkillsDir)) {
3074
3128
  try {
3075
3129
  for (const name of fs9.readdirSync(codexSkillsDir)) {
3076
- const skillFile = path8.join(codexSkillsDir, name, "SKILL.md");
3130
+ const skillFile = path9.join(codexSkillsDir, name, "SKILL.md");
3077
3131
  if (fs9.existsSync(skillFile)) {
3078
3132
  items.push({
3079
3133
  type: "skill",
@@ -3088,7 +3142,7 @@ function scanLocalState(dir) {
3088
3142
  warnScanSkip(".agents/skills", error);
3089
3143
  }
3090
3144
  }
3091
- const cursorrulesPath = path8.join(dir, ".cursorrules");
3145
+ const cursorrulesPath = path9.join(dir, ".cursorrules");
3092
3146
  if (fs9.existsSync(cursorrulesPath)) {
3093
3147
  items.push({
3094
3148
  type: "rule",
@@ -3098,10 +3152,10 @@ function scanLocalState(dir) {
3098
3152
  path: cursorrulesPath
3099
3153
  });
3100
3154
  }
3101
- const cursorRulesDir = path8.join(dir, ".cursor", "rules");
3155
+ const cursorRulesDir = path9.join(dir, ".cursor", "rules");
3102
3156
  if (fs9.existsSync(cursorRulesDir)) {
3103
3157
  for (const file of fs9.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
3104
- const filePath = path8.join(cursorRulesDir, file);
3158
+ const filePath = path9.join(cursorRulesDir, file);
3105
3159
  items.push({
3106
3160
  type: "rule",
3107
3161
  platform: "cursor",
@@ -3111,11 +3165,11 @@ function scanLocalState(dir) {
3111
3165
  });
3112
3166
  }
3113
3167
  }
3114
- const cursorSkillsDir = path8.join(dir, ".cursor", "skills");
3168
+ const cursorSkillsDir = path9.join(dir, ".cursor", "skills");
3115
3169
  if (fs9.existsSync(cursorSkillsDir)) {
3116
3170
  try {
3117
3171
  for (const name of fs9.readdirSync(cursorSkillsDir)) {
3118
- const skillFile = path8.join(cursorSkillsDir, name, "SKILL.md");
3172
+ const skillFile = path9.join(cursorSkillsDir, name, "SKILL.md");
3119
3173
  if (fs9.existsSync(skillFile)) {
3120
3174
  items.push({
3121
3175
  type: "skill",
@@ -3130,7 +3184,7 @@ function scanLocalState(dir) {
3130
3184
  warnScanSkip(".cursor/skills", error);
3131
3185
  }
3132
3186
  }
3133
- const cursorMcpPath = path8.join(dir, ".cursor", "mcp.json");
3187
+ const cursorMcpPath = path9.join(dir, ".cursor", "mcp.json");
3134
3188
  if (fs9.existsSync(cursorMcpPath)) {
3135
3189
  try {
3136
3190
  const mcpJson = JSON.parse(fs9.readFileSync(cursorMcpPath, "utf-8"));
@@ -3165,17 +3219,17 @@ function warnScanSkip(target, error) {
3165
3219
  function getCursorConfigDir() {
3166
3220
  const home = os4.homedir();
3167
3221
  if (process.platform === "darwin") {
3168
- return path8.join(home, "Library", "Application Support", "Cursor");
3222
+ return path9.join(home, "Library", "Application Support", "Cursor");
3169
3223
  }
3170
3224
  if (process.platform === "win32") {
3171
- return path8.join(home, "AppData", "Roaming", "Cursor");
3225
+ return path9.join(home, "AppData", "Roaming", "Cursor");
3172
3226
  }
3173
- return path8.join(home, ".config", "Cursor");
3227
+ return path9.join(home, ".config", "Cursor");
3174
3228
  }
3175
3229
 
3176
3230
  // src/fingerprint/sources.ts
3177
3231
  import fs10 from "fs";
3178
- import path9 from "path";
3232
+ import path10 from "path";
3179
3233
 
3180
3234
  // src/scoring/utils.ts
3181
3235
  import { existsSync as existsSync2, readFileSync, readdirSync } from "fs";
@@ -3242,12 +3296,14 @@ function isGitRepo2(dir) {
3242
3296
  function checkGitIgnored(dir, paths) {
3243
3297
  if (paths.length === 0) return /* @__PURE__ */ new Set();
3244
3298
  try {
3245
- const result = execFileSync(
3246
- "git",
3247
- ["check-ignore", ...paths],
3248
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
3299
+ const result = execFileSync("git", ["check-ignore", ...paths], {
3300
+ cwd: dir,
3301
+ encoding: "utf-8",
3302
+ stdio: ["pipe", "pipe", "pipe"]
3303
+ });
3304
+ return new Set(
3305
+ result.split("\n").map((l) => l.trim()).filter(Boolean)
3249
3306
  );
3250
- return new Set(result.split("\n").map((l) => l.trim()).filter(Boolean));
3251
3307
  } catch (err) {
3252
3308
  if (err && typeof err === "object" && "status" in err && err.status === 1) {
3253
3309
  return /* @__PURE__ */ new Set();
@@ -3271,7 +3327,10 @@ function collectProjectStructure(dir, maxDepth = 2) {
3271
3327
  if (name.startsWith(".") && IGNORED_DIRS.has(name)) continue;
3272
3328
  dirEntries.push({ name, rel: relative(dir, join(currentDir, name)) });
3273
3329
  }
3274
- const gitIgnored = useGit ? checkGitIgnored(dir, dirEntries.map((d) => d.rel)) : null;
3330
+ const gitIgnored = useGit ? checkGitIgnored(
3331
+ dir,
3332
+ dirEntries.map((d) => d.rel)
3333
+ ) : null;
3275
3334
  for (const entry of entries) {
3276
3335
  const name = entry.name;
3277
3336
  if (name.startsWith(".") && IGNORED_DIRS.has(name)) continue;
@@ -3454,7 +3513,9 @@ function countTreeLines(content) {
3454
3513
  return count;
3455
3514
  }
3456
3515
  function calculateDuplicatePercent(content1, content2) {
3457
- const lines1 = new Set(content1.split("\n").map((l) => l.trim()).filter((l) => l.length > 10));
3516
+ const lines1 = new Set(
3517
+ content1.split("\n").map((l) => l.trim()).filter((l) => l.length > 10)
3518
+ );
3458
3519
  const lines2 = content2.split("\n").map((l) => l.trim()).filter((l) => l.length > 10);
3459
3520
  const overlapping = lines2.filter((l) => lines1.has(l)).length;
3460
3521
  return lines2.length > 0 ? Math.round(overlapping / lines2.length * 100) : 0;
@@ -3473,7 +3534,9 @@ function isEntryMentioned(entry, contentLower) {
3473
3534
  if (lastSegment && lastSegment.length > 3) variants.push(lastSegment);
3474
3535
  return variants.some((v) => {
3475
3536
  const escaped = v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3476
- return new RegExp(`(?:^|[\\s\`/"'\\.,(])${escaped}(?:[\\s\`/"'.,;:!?)\\\\]|$)`, "i").test(contentLower);
3537
+ return new RegExp(`(?:^|[\\s\`/"'\\.,(])${escaped}(?:[\\s\`/"'.,;:!?)\\\\]|$)`, "i").test(
3538
+ contentLower
3539
+ );
3477
3540
  });
3478
3541
  }
3479
3542
  function classifyLine(line, inCodeBlock) {
@@ -3484,7 +3547,8 @@ function classifyLine(line, inCodeBlock) {
3484
3547
  if (/`[^`]+`/.test(trimmed)) return "concrete";
3485
3548
  if (/[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+\.[a-zA-Z]{1,5}/.test(trimmed)) return "concrete";
3486
3549
  if (/[a-zA-Z0-9_]{4,}\/[a-zA-Z0-9_.-]/.test(trimmed)) return "concrete";
3487
- if (/\b[a-zA-Z0-9_-]+\.[a-zA-Z]{1,5}\b/.test(trimmed) && !/\b(e\.g|i\.e|vs|etc)\b/i.test(trimmed)) return "concrete";
3550
+ if (/\b[a-zA-Z0-9_-]+\.[a-zA-Z]{1,5}\b/.test(trimmed) && !/\b(e\.g|i\.e|vs|etc)\b/i.test(trimmed))
3551
+ return "concrete";
3488
3552
  return "abstract";
3489
3553
  }
3490
3554
 
@@ -3494,29 +3558,29 @@ var SOURCE_CONTENT_LIMIT = 2e3;
3494
3558
  var README_CONTENT_LIMIT = 1e3;
3495
3559
  var ORIGIN_PRIORITY = { cli: 0, config: 1, workspace: 2 };
3496
3560
  function loadSourcesConfig(dir) {
3497
- const configPath = path9.join(dir, ".caliber", "sources.json");
3561
+ const configPath = path10.join(dir, ".caliber", "sources.json");
3498
3562
  const content = readFileOrNull(configPath);
3499
3563
  if (!content) return [];
3500
3564
  try {
3501
3565
  const parsed = JSON.parse(content);
3502
3566
  if (!Array.isArray(parsed.sources)) {
3503
- console.warn("Warning: .caliber/sources.json is malformed (missing sources array), skipping sources");
3567
+ console.warn(
3568
+ "Warning: .caliber/sources.json is malformed (missing sources array), skipping sources"
3569
+ );
3504
3570
  return [];
3505
3571
  }
3506
- return parsed.sources.filter(
3507
- (s) => s.type && (s.path || s.url)
3508
- );
3572
+ return parsed.sources.filter((s) => s.type && (s.path || s.url));
3509
3573
  } catch {
3510
3574
  console.warn("Warning: .caliber/sources.json is malformed, skipping sources");
3511
3575
  return [];
3512
3576
  }
3513
3577
  }
3514
3578
  function writeSourcesConfig(dir, sources2) {
3515
- const configDir = path9.join(dir, ".caliber");
3579
+ const configDir = path10.join(dir, ".caliber");
3516
3580
  if (!fs10.existsSync(configDir)) {
3517
3581
  fs10.mkdirSync(configDir, { recursive: true });
3518
3582
  }
3519
- const configPath = path9.join(configDir, "sources.json");
3583
+ const configPath = path10.join(configDir, "sources.json");
3520
3584
  fs10.writeFileSync(configPath, JSON.stringify({ sources: sources2 }, null, 2) + "\n", "utf-8");
3521
3585
  }
3522
3586
  function detectSourceType(absPath) {
@@ -3527,14 +3591,14 @@ function detectSourceType(absPath) {
3527
3591
  }
3528
3592
  }
3529
3593
  function isInsideDir(childPath, parentDir) {
3530
- const relative2 = path9.relative(parentDir, childPath);
3531
- return !relative2.startsWith("..") && !path9.isAbsolute(relative2);
3594
+ const relative2 = path10.relative(parentDir, childPath);
3595
+ return !relative2.startsWith("..") && !path10.isAbsolute(relative2);
3532
3596
  }
3533
3597
  function resolveAllSources(dir, cliSources, workspaces) {
3534
3598
  const seen = /* @__PURE__ */ new Map();
3535
- const projectRoot = path9.resolve(dir);
3599
+ const projectRoot = path10.resolve(dir);
3536
3600
  for (const src of cliSources) {
3537
- const absPath = path9.resolve(dir, src);
3601
+ const absPath = path10.resolve(dir, src);
3538
3602
  if (seen.has(absPath)) continue;
3539
3603
  const type = detectSourceType(absPath);
3540
3604
  seen.set(absPath, {
@@ -3547,12 +3611,12 @@ function resolveAllSources(dir, cliSources, workspaces) {
3547
3611
  for (const cfg of configSources) {
3548
3612
  if (cfg.type === "url") continue;
3549
3613
  if (!cfg.path) continue;
3550
- const absPath = path9.resolve(dir, cfg.path);
3614
+ const absPath = path10.resolve(dir, cfg.path);
3551
3615
  if (seen.has(absPath)) continue;
3552
3616
  seen.set(absPath, { absPath, config: cfg, origin: "config" });
3553
3617
  }
3554
3618
  for (const ws of workspaces) {
3555
- const absPath = path9.resolve(dir, ws);
3619
+ const absPath = path10.resolve(dir, ws);
3556
3620
  if (seen.has(absPath)) continue;
3557
3621
  if (!isInsideDir(absPath, projectRoot)) continue;
3558
3622
  seen.set(absPath, {
@@ -3594,13 +3658,13 @@ function collectSourceSummary(resolved, projectDir) {
3594
3658
  if (config.type === "file") {
3595
3659
  return collectFileSummary(resolved, projectDir);
3596
3660
  }
3597
- const summaryPath = path9.join(absPath, ".caliber", "summary.json");
3661
+ const summaryPath = path10.join(absPath, ".caliber", "summary.json");
3598
3662
  const summaryContent = readFileOrNull(summaryPath);
3599
3663
  if (summaryContent) {
3600
3664
  try {
3601
3665
  const published = JSON.parse(summaryContent);
3602
3666
  return {
3603
- name: published.name || path9.basename(absPath),
3667
+ name: published.name || path10.basename(absPath),
3604
3668
  type: "repo",
3605
3669
  role: config.role || published.role || "related-repo",
3606
3670
  description: config.description || published.description || "",
@@ -3614,7 +3678,7 @@ function collectSourceSummary(resolved, projectDir) {
3614
3678
  }
3615
3679
  return collectRepoSummary(resolved, projectDir);
3616
3680
  }
3617
- function collectRepoSummary(resolved, projectDir) {
3681
+ function collectRepoSummary(resolved, _projectDir) {
3618
3682
  const { config, origin, absPath } = resolved;
3619
3683
  const packageName = readPackageName(absPath);
3620
3684
  let topLevelDirs;
@@ -3625,13 +3689,13 @@ function collectRepoSummary(resolved, projectDir) {
3625
3689
  keyFiles = entries.filter((e) => e.isFile() && !e.name.startsWith(".")).map((e) => e.name).slice(0, 15);
3626
3690
  } catch {
3627
3691
  }
3628
- const claudeMdContent = readFileOrNull(path9.join(absPath, "CLAUDE.md"));
3692
+ const claudeMdContent = readFileOrNull(path10.join(absPath, "CLAUDE.md"));
3629
3693
  const existingClaudeMd = claudeMdContent ? claudeMdContent.slice(0, SOURCE_CONTENT_LIMIT) : void 0;
3630
- const readmeContent = readFileOrNull(path9.join(absPath, "README.md"));
3694
+ const readmeContent = readFileOrNull(path10.join(absPath, "README.md"));
3631
3695
  const readmeExcerpt = readmeContent ? readmeContent.slice(0, README_CONTENT_LIMIT) : void 0;
3632
3696
  const gitRemoteUrl = getGitRemoteUrl(absPath);
3633
3697
  return {
3634
- name: packageName || path9.basename(absPath),
3698
+ name: packageName || path10.basename(absPath),
3635
3699
  type: "repo",
3636
3700
  role: config.role || "related-repo",
3637
3701
  description: config.description || "",
@@ -3644,11 +3708,11 @@ function collectRepoSummary(resolved, projectDir) {
3644
3708
  packageName
3645
3709
  };
3646
3710
  }
3647
- function collectFileSummary(resolved, projectDir) {
3711
+ function collectFileSummary(resolved, _projectDir) {
3648
3712
  const { config, origin, absPath } = resolved;
3649
3713
  const content = readFileOrNull(absPath);
3650
3714
  return {
3651
- name: path9.basename(absPath),
3715
+ name: path10.basename(absPath),
3652
3716
  type: "file",
3653
3717
  role: config.role || "reference-doc",
3654
3718
  description: config.description || content?.slice(0, 100).split("\n")[0] || "",
@@ -3692,15 +3756,15 @@ init_config();
3692
3756
  // src/utils/dependencies.ts
3693
3757
  import { readFileSync as readFileSync2 } from "fs";
3694
3758
  import { join as join2 } from "path";
3695
- function readFileOrNull2(path40) {
3759
+ function readFileOrNull2(path41) {
3696
3760
  try {
3697
- return readFileSync2(path40, "utf-8");
3761
+ return readFileSync2(path41, "utf-8");
3698
3762
  } catch {
3699
3763
  return null;
3700
3764
  }
3701
3765
  }
3702
- function readJsonOrNull(path40) {
3703
- const content = readFileOrNull2(path40);
3766
+ function readJsonOrNull(path41) {
3767
+ const content = readFileOrNull2(path41);
3704
3768
  if (!content) return null;
3705
3769
  try {
3706
3770
  return JSON.parse(content);
@@ -3742,18 +3806,24 @@ function extractNpmDeps(dir) {
3742
3806
  /^prettier-/,
3743
3807
  /^@typescript-eslint\//
3744
3808
  ];
3745
- return Object.keys(deps).filter((d) => !trivial.has(d) && !d.startsWith("@types/") && !trivialPatterns.some((p) => p.test(d))).slice(0, 30);
3809
+ return Object.keys(deps).filter(
3810
+ (d) => !trivial.has(d) && !d.startsWith("@types/") && !trivialPatterns.some((p) => p.test(d))
3811
+ ).slice(0, 30);
3746
3812
  }
3747
3813
  function extractPythonDeps(dir) {
3748
3814
  const reqTxt = readFileOrNull2(join2(dir, "requirements.txt"));
3749
3815
  if (reqTxt) {
3750
- return reqTxt.split("\n").map((l) => l.trim().split(/[=<>!~\[]/)[0].trim()).filter((l) => l && !l.startsWith("#")).slice(0, 30);
3816
+ return reqTxt.split("\n").map(
3817
+ (l) => l.trim().split(/[=<>!~[]/)[0].trim()
3818
+ ).filter((l) => l && !l.startsWith("#")).slice(0, 30);
3751
3819
  }
3752
3820
  const pyproject = readFileOrNull2(join2(dir, "pyproject.toml"));
3753
3821
  if (pyproject) {
3754
3822
  const depMatch = pyproject.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
3755
3823
  if (depMatch) {
3756
- return depMatch[1].split("\n").map((l) => l.trim().replace(/["',]/g, "").split(/[=<>!~\[]/)[0].trim()).filter((l) => l.length > 0).slice(0, 30);
3824
+ return depMatch[1].split("\n").map(
3825
+ (l) => l.trim().replace(/["',]/g, "").split(/[=<>!~[]/)[0].trim()
3826
+ ).filter((l) => l.length > 0).slice(0, 30);
3757
3827
  }
3758
3828
  }
3759
3829
  return [];
@@ -4291,7 +4361,7 @@ import fs18 from "fs";
4291
4361
 
4292
4362
  // src/writers/claude/index.ts
4293
4363
  import fs11 from "fs";
4294
- import path10 from "path";
4364
+ import path11 from "path";
4295
4365
 
4296
4366
  // src/writers/pre-commit-block.ts
4297
4367
  init_resolve_caliber();
@@ -4368,9 +4438,9 @@ function writeClaudeConfig(config) {
4368
4438
  written.push("CLAUDE.md");
4369
4439
  if (config.skills?.length) {
4370
4440
  for (const skill of config.skills) {
4371
- const skillDir = path10.join(".claude", "skills", skill.name);
4441
+ const skillDir = path11.join(".claude", "skills", skill.name);
4372
4442
  if (!fs11.existsSync(skillDir)) fs11.mkdirSync(skillDir, { recursive: true });
4373
- const skillPath = path10.join(skillDir, "SKILL.md");
4443
+ const skillPath = path11.join(skillDir, "SKILL.md");
4374
4444
  const frontmatter = [
4375
4445
  "---",
4376
4446
  `name: ${skill.name}`,
@@ -4400,7 +4470,7 @@ function writeClaudeConfig(config) {
4400
4470
 
4401
4471
  // src/writers/cursor/index.ts
4402
4472
  import fs12 from "fs";
4403
- import path11 from "path";
4473
+ import path12 from "path";
4404
4474
  function writeCursorConfig(config) {
4405
4475
  const written = [];
4406
4476
  if (config.cursorrules) {
@@ -4410,18 +4480,18 @@ function writeCursorConfig(config) {
4410
4480
  const preCommitRule = getCursorPreCommitRule();
4411
4481
  const learningsRule = getCursorLearningsRule();
4412
4482
  const allRules = [...config.rules || [], preCommitRule, learningsRule];
4413
- const rulesDir = path11.join(".cursor", "rules");
4483
+ const rulesDir = path12.join(".cursor", "rules");
4414
4484
  if (!fs12.existsSync(rulesDir)) fs12.mkdirSync(rulesDir, { recursive: true });
4415
4485
  for (const rule of allRules) {
4416
- const rulePath = path11.join(rulesDir, rule.filename);
4486
+ const rulePath = path12.join(rulesDir, rule.filename);
4417
4487
  fs12.writeFileSync(rulePath, rule.content);
4418
4488
  written.push(rulePath);
4419
4489
  }
4420
4490
  if (config.skills?.length) {
4421
4491
  for (const skill of config.skills) {
4422
- const skillDir = path11.join(".cursor", "skills", skill.name);
4492
+ const skillDir = path12.join(".cursor", "skills", skill.name);
4423
4493
  if (!fs12.existsSync(skillDir)) fs12.mkdirSync(skillDir, { recursive: true });
4424
- const skillPath = path11.join(skillDir, "SKILL.md");
4494
+ const skillPath = path12.join(skillDir, "SKILL.md");
4425
4495
  const frontmatter = [
4426
4496
  "---",
4427
4497
  `name: ${skill.name}`,
@@ -4436,7 +4506,7 @@ function writeCursorConfig(config) {
4436
4506
  if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
4437
4507
  const cursorDir = ".cursor";
4438
4508
  if (!fs12.existsSync(cursorDir)) fs12.mkdirSync(cursorDir, { recursive: true });
4439
- const mcpPath = path11.join(cursorDir, "mcp.json");
4509
+ const mcpPath = path12.join(cursorDir, "mcp.json");
4440
4510
  let existingServers = {};
4441
4511
  try {
4442
4512
  if (fs12.existsSync(mcpPath)) {
@@ -4454,16 +4524,16 @@ function writeCursorConfig(config) {
4454
4524
 
4455
4525
  // src/writers/codex/index.ts
4456
4526
  import fs13 from "fs";
4457
- import path12 from "path";
4527
+ import path13 from "path";
4458
4528
  function writeCodexConfig(config) {
4459
4529
  const written = [];
4460
4530
  fs13.writeFileSync("AGENTS.md", appendLearningsBlock(appendPreCommitBlock(config.agentsMd)));
4461
4531
  written.push("AGENTS.md");
4462
4532
  if (config.skills?.length) {
4463
4533
  for (const skill of config.skills) {
4464
- const skillDir = path12.join(".agents", "skills", skill.name);
4534
+ const skillDir = path13.join(".agents", "skills", skill.name);
4465
4535
  if (!fs13.existsSync(skillDir)) fs13.mkdirSync(skillDir, { recursive: true });
4466
- const skillPath = path12.join(skillDir, "SKILL.md");
4536
+ const skillPath = path13.join(skillDir, "SKILL.md");
4467
4537
  const frontmatter = [
4468
4538
  "---",
4469
4539
  `name: ${skill.name}`,
@@ -4480,19 +4550,19 @@ function writeCodexConfig(config) {
4480
4550
 
4481
4551
  // src/writers/github-copilot/index.ts
4482
4552
  import fs14 from "fs";
4483
- import path13 from "path";
4553
+ import path14 from "path";
4484
4554
  function writeGithubCopilotConfig(config) {
4485
4555
  const written = [];
4486
4556
  if (config.instructions) {
4487
4557
  fs14.mkdirSync(".github", { recursive: true });
4488
- fs14.writeFileSync(path13.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(config.instructions)));
4558
+ fs14.writeFileSync(path14.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(config.instructions)));
4489
4559
  written.push(".github/copilot-instructions.md");
4490
4560
  }
4491
4561
  if (config.instructionFiles?.length) {
4492
- const instructionsDir = path13.join(".github", "instructions");
4562
+ const instructionsDir = path14.join(".github", "instructions");
4493
4563
  fs14.mkdirSync(instructionsDir, { recursive: true });
4494
4564
  for (const file of config.instructionFiles) {
4495
- fs14.writeFileSync(path13.join(instructionsDir, file.filename), file.content);
4565
+ fs14.writeFileSync(path14.join(instructionsDir, file.filename), file.content);
4496
4566
  written.push(`.github/instructions/${file.filename}`);
4497
4567
  }
4498
4568
  }
@@ -4501,14 +4571,14 @@ function writeGithubCopilotConfig(config) {
4501
4571
 
4502
4572
  // src/writers/backup.ts
4503
4573
  import fs15 from "fs";
4504
- import path14 from "path";
4574
+ import path15 from "path";
4505
4575
  function createBackup(files) {
4506
4576
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4507
- const backupDir = path14.join(BACKUPS_DIR, timestamp);
4577
+ const backupDir = path15.join(BACKUPS_DIR, timestamp);
4508
4578
  for (const file of files) {
4509
4579
  if (!fs15.existsSync(file)) continue;
4510
- const dest = path14.join(backupDir, file);
4511
- const destDir = path14.dirname(dest);
4580
+ const dest = path15.join(backupDir, file);
4581
+ const destDir = path15.dirname(dest);
4512
4582
  if (!fs15.existsSync(destDir)) {
4513
4583
  fs15.mkdirSync(destDir, { recursive: true });
4514
4584
  }
@@ -4517,9 +4587,9 @@ function createBackup(files) {
4517
4587
  return backupDir;
4518
4588
  }
4519
4589
  function restoreBackup(backupDir, file) {
4520
- const backupFile = path14.join(backupDir, file);
4590
+ const backupFile = path15.join(backupDir, file);
4521
4591
  if (!fs15.existsSync(backupFile)) return false;
4522
- const destDir = path14.dirname(file);
4592
+ const destDir = path15.dirname(file);
4523
4593
  if (!fs15.existsSync(destDir)) {
4524
4594
  fs15.mkdirSync(destDir, { recursive: true });
4525
4595
  }
@@ -4530,7 +4600,7 @@ function restoreBackup(backupDir, file) {
4530
4600
  // src/lib/builtin-skills.ts
4531
4601
  init_resolve_caliber();
4532
4602
  import fs16 from "fs";
4533
- import path15 from "path";
4603
+ import path16 from "path";
4534
4604
  function buildSkillContent(skill) {
4535
4605
  const frontmatter = `---
4536
4606
  name: ${skill.name}
@@ -4668,18 +4738,18 @@ var SAVE_LEARNING_SKILL = {
4668
4738
  };
4669
4739
  var BUILTIN_SKILLS = [FIND_SKILLS_SKILL, SAVE_LEARNING_SKILL];
4670
4740
  var PLATFORM_CONFIGS = [
4671
- { platformDir: ".claude", skillsDir: path15.join(".claude", "skills") },
4672
- { platformDir: ".cursor", skillsDir: path15.join(".cursor", "skills") },
4673
- { platformDir: ".agents", skillsDir: path15.join(".agents", "skills") }
4741
+ { platformDir: ".claude", skillsDir: path16.join(".claude", "skills") },
4742
+ { platformDir: ".cursor", skillsDir: path16.join(".cursor", "skills") },
4743
+ { platformDir: ".agents", skillsDir: path16.join(".agents", "skills") }
4674
4744
  ];
4675
4745
  function ensureBuiltinSkills() {
4676
4746
  const written = [];
4677
4747
  for (const { platformDir, skillsDir } of PLATFORM_CONFIGS) {
4678
4748
  if (!fs16.existsSync(platformDir)) continue;
4679
4749
  for (const skill of BUILTIN_SKILLS) {
4680
- const skillPath = path15.join(skillsDir, skill.name, "SKILL.md");
4750
+ const skillPath = path16.join(skillsDir, skill.name, "SKILL.md");
4681
4751
  if (fs16.existsSync(skillPath)) continue;
4682
- fs16.mkdirSync(path15.dirname(skillPath), { recursive: true });
4752
+ fs16.mkdirSync(path16.dirname(skillPath), { recursive: true });
4683
4753
  fs16.writeFileSync(skillPath, buildSkillContent(skill));
4684
4754
  written.push(skillPath);
4685
4755
  }
@@ -4713,10 +4783,7 @@ function fileChecksum(filePath) {
4713
4783
  function writeSetup(setup) {
4714
4784
  const filesToWrite = getFilesToWrite(setup);
4715
4785
  const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs18.existsSync(f));
4716
- const existingFiles = [
4717
- ...filesToWrite.filter((f) => fs18.existsSync(f)),
4718
- ...filesToDelete
4719
- ];
4786
+ const existingFiles = [...filesToWrite.filter((f) => fs18.existsSync(f)), ...filesToDelete];
4720
4787
  const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
4721
4788
  const written = [];
4722
4789
  if (setup.targetAgent.includes("claude") && setup.claude) {
@@ -4809,7 +4876,8 @@ function getFilesToWrite(setup) {
4809
4876
  if (setup.targetAgent.includes("github-copilot") && setup.copilot) {
4810
4877
  if (setup.copilot.instructions) files.push(".github/copilot-instructions.md");
4811
4878
  if (setup.copilot.instructionFiles) {
4812
- for (const f of setup.copilot.instructionFiles) files.push(`.github/instructions/${f.filename}`);
4879
+ for (const f of setup.copilot.instructionFiles)
4880
+ files.push(`.github/instructions/${f.filename}`);
4813
4881
  }
4814
4882
  }
4815
4883
  return files;
@@ -4828,10 +4896,10 @@ function ensureGitignore() {
4828
4896
 
4829
4897
  // src/writers/staging.ts
4830
4898
  import fs19 from "fs";
4831
- import path16 from "path";
4832
- var STAGED_DIR = path16.join(CALIBER_DIR, "staged");
4833
- var PROPOSED_DIR = path16.join(STAGED_DIR, "proposed");
4834
- var CURRENT_DIR = path16.join(STAGED_DIR, "current");
4899
+ import path17 from "path";
4900
+ var STAGED_DIR = path17.join(CALIBER_DIR, "staged");
4901
+ var PROPOSED_DIR = path17.join(STAGED_DIR, "proposed");
4902
+ var CURRENT_DIR = path17.join(STAGED_DIR, "current");
4835
4903
  function normalizeContent(content) {
4836
4904
  return content.split("\n").map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
4837
4905
  }
@@ -4841,22 +4909,29 @@ function stageFiles(files, projectDir) {
4841
4909
  let modifiedFiles = 0;
4842
4910
  const stagedFiles = [];
4843
4911
  for (const file of files) {
4844
- const originalPath = path16.join(projectDir, file.path);
4912
+ assertPathWithinDir(file.path, projectDir);
4913
+ const originalPath = path17.join(projectDir, file.path);
4845
4914
  if (fs19.existsSync(originalPath)) {
4846
4915
  const existing = fs19.readFileSync(originalPath, "utf-8");
4847
4916
  if (normalizeContent(existing) === normalizeContent(file.content)) {
4848
4917
  continue;
4849
4918
  }
4850
4919
  }
4851
- const proposedPath = path16.join(PROPOSED_DIR, file.path);
4852
- fs19.mkdirSync(path16.dirname(proposedPath), { recursive: true });
4920
+ const proposedPath = path17.join(PROPOSED_DIR, file.path);
4921
+ fs19.mkdirSync(path17.dirname(proposedPath), { recursive: true });
4853
4922
  fs19.writeFileSync(proposedPath, file.content);
4854
4923
  if (fs19.existsSync(originalPath)) {
4855
- const currentPath = path16.join(CURRENT_DIR, file.path);
4856
- fs19.mkdirSync(path16.dirname(currentPath), { recursive: true });
4924
+ const currentPath = path17.join(CURRENT_DIR, file.path);
4925
+ fs19.mkdirSync(path17.dirname(currentPath), { recursive: true });
4857
4926
  fs19.copyFileSync(originalPath, currentPath);
4858
4927
  modifiedFiles++;
4859
- stagedFiles.push({ relativePath: file.path, proposedPath, currentPath, originalPath, isNew: false });
4928
+ stagedFiles.push({
4929
+ relativePath: file.path,
4930
+ proposedPath,
4931
+ currentPath,
4932
+ originalPath,
4933
+ isNew: false
4934
+ });
4860
4935
  } else {
4861
4936
  newFiles++;
4862
4937
  stagedFiles.push({ relativePath: file.path, proposedPath, isNew: true });
@@ -4882,11 +4957,17 @@ function collectSetupFiles(setup, targetAgent) {
4882
4957
  const skills = claude.skills;
4883
4958
  if (Array.isArray(skills)) {
4884
4959
  for (const skill of skills) {
4885
- files.push({ path: `.claude/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
4960
+ files.push({
4961
+ path: `.claude/skills/${sanitizePath(skill.name)}/SKILL.md`,
4962
+ content: buildSkillContent(skill)
4963
+ });
4886
4964
  }
4887
4965
  }
4888
4966
  for (const builtin of BUILTIN_SKILLS) {
4889
- files.push({ path: `.claude/skills/${builtin.name}/SKILL.md`, content: buildSkillContent(builtin) });
4967
+ files.push({
4968
+ path: `.claude/skills/${builtin.name}/SKILL.md`,
4969
+ content: buildSkillContent(builtin)
4970
+ });
4890
4971
  }
4891
4972
  }
4892
4973
  if (codex) {
@@ -4894,38 +4975,58 @@ function collectSetupFiles(setup, targetAgent) {
4894
4975
  const codexSkills = codex.skills;
4895
4976
  if (Array.isArray(codexSkills)) {
4896
4977
  for (const skill of codexSkills) {
4897
- files.push({ path: `.agents/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
4978
+ files.push({
4979
+ path: `.agents/skills/${sanitizePath(skill.name)}/SKILL.md`,
4980
+ content: buildSkillContent(skill)
4981
+ });
4898
4982
  }
4899
4983
  }
4900
4984
  for (const builtin of BUILTIN_SKILLS) {
4901
- files.push({ path: `.agents/skills/${builtin.name}/SKILL.md`, content: buildSkillContent(builtin) });
4985
+ files.push({
4986
+ path: `.agents/skills/${builtin.name}/SKILL.md`,
4987
+ content: buildSkillContent(builtin)
4988
+ });
4902
4989
  }
4903
4990
  }
4904
4991
  if (cursor) {
4905
- if (cursor.cursorrules) files.push({ path: ".cursorrules", content: cursor.cursorrules });
4992
+ if (cursor.cursorrules)
4993
+ files.push({ path: ".cursorrules", content: cursor.cursorrules });
4906
4994
  const cursorSkills = cursor.skills;
4907
4995
  if (Array.isArray(cursorSkills)) {
4908
4996
  for (const skill of cursorSkills) {
4909
- files.push({ path: `.cursor/skills/${skill.name}/SKILL.md`, content: buildSkillContent(skill) });
4997
+ files.push({
4998
+ path: `.cursor/skills/${sanitizePath(skill.name)}/SKILL.md`,
4999
+ content: buildSkillContent(skill)
5000
+ });
4910
5001
  }
4911
5002
  }
4912
5003
  for (const builtin of BUILTIN_SKILLS) {
4913
- files.push({ path: `.cursor/skills/${builtin.name}/SKILL.md`, content: buildSkillContent(builtin) });
5004
+ files.push({
5005
+ path: `.cursor/skills/${builtin.name}/SKILL.md`,
5006
+ content: buildSkillContent(builtin)
5007
+ });
4914
5008
  }
4915
5009
  const rules = cursor.rules;
4916
5010
  if (Array.isArray(rules)) {
4917
5011
  for (const rule of rules) {
4918
- files.push({ path: `.cursor/rules/${rule.filename}`, content: rule.content });
5012
+ files.push({ path: `.cursor/rules/${sanitizePath(rule.filename)}`, content: rule.content });
4919
5013
  }
4920
5014
  }
4921
5015
  }
4922
5016
  const copilot = setup.copilot;
4923
5017
  if (copilot) {
4924
- if (copilot.instructions) files.push({ path: ".github/copilot-instructions.md", content: copilot.instructions });
5018
+ if (copilot.instructions)
5019
+ files.push({
5020
+ path: ".github/copilot-instructions.md",
5021
+ content: copilot.instructions
5022
+ });
4925
5023
  const instructionFiles = copilot.instructionFiles;
4926
5024
  if (Array.isArray(instructionFiles)) {
4927
5025
  for (const file of instructionFiles) {
4928
- files.push({ path: `.github/instructions/${file.filename}`, content: file.content });
5026
+ files.push({
5027
+ path: `.github/instructions/${sanitizePath(file.filename)}`,
5028
+ content: file.content
5029
+ });
4929
5030
  }
4930
5031
  }
4931
5032
  }
@@ -4934,7 +5035,8 @@ function collectSetupFiles(setup, targetAgent) {
4934
5035
  const agentRefs = [];
4935
5036
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
4936
5037
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
4937
- if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
5038
+ if (agentRefs.length === 0)
5039
+ agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
4938
5040
  const stubContent = `# AGENTS.md
4939
5041
 
4940
5042
  This project uses AI coding agents configured by [Caliber](https://github.com/caliber-ai-org/ai-setup).
@@ -4949,8 +5051,8 @@ ${agentRefs.join(" ")}
4949
5051
  // src/lib/learning-hooks.ts
4950
5052
  init_resolve_caliber();
4951
5053
  import fs21 from "fs";
4952
- import path17 from "path";
4953
- var SETTINGS_PATH = path17.join(".claude", "settings.json");
5054
+ import path18 from "path";
5055
+ var SETTINGS_PATH = path18.join(".claude", "settings.json");
4954
5056
  var HOOK_TAILS = [
4955
5057
  { event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
4956
5058
  { event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
@@ -4975,7 +5077,7 @@ function readSettings() {
4975
5077
  }
4976
5078
  }
4977
5079
  function writeSettings(settings) {
4978
- const dir = path17.dirname(SETTINGS_PATH);
5080
+ const dir = path18.dirname(SETTINGS_PATH);
4979
5081
  if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
4980
5082
  fs21.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
4981
5083
  }
@@ -5011,7 +5113,7 @@ function installLearningHooks() {
5011
5113
  writeSettings(settings);
5012
5114
  return { installed: true, alreadyInstalled: false };
5013
5115
  }
5014
- var CURSOR_HOOKS_PATH = path17.join(".cursor", "hooks.json");
5116
+ var CURSOR_HOOKS_PATH = path18.join(".cursor", "hooks.json");
5015
5117
  var CURSOR_HOOK_EVENTS = [
5016
5118
  { event: "postToolUse", tail: "learn observe" },
5017
5119
  { event: "postToolUseFailure", tail: "learn observe --failure" },
@@ -5027,7 +5129,7 @@ function readCursorHooks() {
5027
5129
  }
5028
5130
  }
5029
5131
  function writeCursorHooks(config) {
5030
- const dir = path17.dirname(CURSOR_HOOKS_PATH);
5132
+ const dir = path18.dirname(CURSOR_HOOKS_PATH);
5031
5133
  if (!fs21.existsSync(dir)) fs21.mkdirSync(dir, { recursive: true });
5032
5134
  fs21.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
5033
5135
  }
@@ -5102,9 +5204,9 @@ init_resolve_caliber();
5102
5204
 
5103
5205
  // src/lib/state.ts
5104
5206
  import fs22 from "fs";
5105
- import path18 from "path";
5207
+ import path19 from "path";
5106
5208
  import { execSync as execSync8 } from "child_process";
5107
- var STATE_FILE = path18.join(CALIBER_DIR, ".caliber-state.json");
5209
+ var STATE_FILE = path19.join(CALIBER_DIR, ".caliber-state.json");
5108
5210
  function normalizeTargetAgent(value) {
5109
5211
  if (Array.isArray(value)) return value;
5110
5212
  if (typeof value === "string") {
@@ -5312,8 +5414,8 @@ var SECRET_PATTERNS = [
5312
5414
  /AKIA[A-Z0-9]{16}/,
5313
5415
  /ghp_[a-zA-Z0-9]{36}/,
5314
5416
  /ghu_[a-zA-Z0-9]{36}/,
5315
- /glpat-[a-zA-Z0-9\-_]{20,}/,
5316
- /xox[bpors]-[a-zA-Z0-9\-]{10,}/,
5417
+ /glpat-[a-zA-Z0-9_-]{20,}/,
5418
+ /xox[bpors]-[a-zA-Z0-9-]{10,}/,
5317
5419
  /(?:password|secret|token|api_key)\s*[:=]\s*["'][^"']{8,}["']/i
5318
5420
  ];
5319
5421
  var SECRET_PLACEHOLDER_PATTERNS = [
@@ -5325,31 +5427,13 @@ var SECRET_PLACEHOLDER_PATTERNS = [
5325
5427
  /CHANGE[_-]?ME/i,
5326
5428
  /<[^>]+>/
5327
5429
  ];
5328
- var CURSOR_ONLY_CHECKS = /* @__PURE__ */ new Set([
5329
- "cursor_rules_exist",
5330
- "cursor_mdc_rules"
5331
- ]);
5332
- var CLAUDE_ONLY_CHECKS = /* @__PURE__ */ new Set([
5333
- "claude_md_exists",
5334
- "claude_md_freshness"
5335
- ]);
5336
- var BOTH_ONLY_CHECKS = /* @__PURE__ */ new Set([
5337
- "cross_platform_parity",
5338
- "no_duplicate_content"
5339
- ]);
5340
- var CODEX_ONLY_CHECKS = /* @__PURE__ */ new Set([
5341
- "codex_agents_md_exists"
5342
- ]);
5343
- var COPILOT_ONLY_CHECKS = /* @__PURE__ */ new Set([
5344
- "copilot_instructions_exists"
5345
- ]);
5346
- var NON_CODEX_CHECKS = /* @__PURE__ */ new Set([
5347
- "agents_md_exists"
5348
- ]);
5349
- var CLAUDE_OR_CODEX_CHECKS = /* @__PURE__ */ new Set([
5350
- "skills_exist",
5351
- "open_skills_format"
5352
- ]);
5430
+ var CURSOR_ONLY_CHECKS = /* @__PURE__ */ new Set(["cursor_rules_exist", "cursor_mdc_rules"]);
5431
+ var CLAUDE_ONLY_CHECKS = /* @__PURE__ */ new Set(["claude_md_exists", "claude_md_freshness"]);
5432
+ var BOTH_ONLY_CHECKS = /* @__PURE__ */ new Set(["cross_platform_parity", "no_duplicate_content"]);
5433
+ var CODEX_ONLY_CHECKS = /* @__PURE__ */ new Set(["codex_agents_md_exists"]);
5434
+ var COPILOT_ONLY_CHECKS = /* @__PURE__ */ new Set(["copilot_instructions_exists"]);
5435
+ var NON_CODEX_CHECKS = /* @__PURE__ */ new Set(["agents_md_exists"]);
5436
+ var CLAUDE_OR_CODEX_CHECKS = /* @__PURE__ */ new Set(["skills_exist", "open_skills_format"]);
5353
5437
  var GRADE_THRESHOLDS = [
5354
5438
  { minScore: 85, grade: "A" },
5355
5439
  { minScore: 70, grade: "B" },
@@ -5616,7 +5700,12 @@ function checkQuality(dir) {
5616
5700
  suggestion: concretenessPoints < 3 && totalMeaningful > 0 ? `${abstractCount} lines are generic prose \u2014 replace with specific instructions referencing project files` : void 0,
5617
5701
  fix: concretenessPoints < 3 && totalMeaningful > 0 ? {
5618
5702
  action: "replace_vague",
5619
- data: { abstractLines: abstractExamples, abstractCount, concreteCount, ratio: Math.round(concreteRatio * 100) },
5703
+ data: {
5704
+ abstractLines: abstractExamples,
5705
+ abstractCount,
5706
+ concreteCount,
5707
+ ratio: Math.round(concreteRatio * 100)
5708
+ },
5620
5709
  instruction: `Replace generic prose with specific references. Examples of vague lines: ${abstractExamples.join("; ")}`
5621
5710
  } : void 0
5622
5711
  });
@@ -5743,7 +5832,7 @@ function checkGrounding(dir) {
5743
5832
  }
5744
5833
 
5745
5834
  // src/scoring/checks/accuracy.ts
5746
- import { existsSync as existsSync4, statSync as statSync2 } from "fs";
5835
+ import { existsSync as existsSync4, statSync } from "fs";
5747
5836
  import { execSync as execSync9 } from "child_process";
5748
5837
  import { join as join5 } from "path";
5749
5838
  init_resolve_caliber();
@@ -5769,7 +5858,7 @@ function detectGitDrift(dir) {
5769
5858
  const filePath = join5(dir, file);
5770
5859
  if (!existsSync4(filePath)) continue;
5771
5860
  try {
5772
- const mtime = statSync2(filePath).mtime.getTime();
5861
+ const mtime = statSync(filePath).mtime.getTime();
5773
5862
  if (mtime > headTime) {
5774
5863
  return { commitsSinceConfigUpdate: 0, lastConfigCommit: "uncommitted (recently modified)", isGitRepo: true };
5775
5864
  }
@@ -5882,7 +5971,7 @@ function checkAccuracy(dir) {
5882
5971
 
5883
5972
  // src/scoring/checks/freshness.ts
5884
5973
  init_resolve_caliber();
5885
- import { existsSync as existsSync5, statSync as statSync3 } from "fs";
5974
+ import { existsSync as existsSync5, statSync as statSync2 } from "fs";
5886
5975
  import { execSync as execSync10 } from "child_process";
5887
5976
  import { join as join6 } from "path";
5888
5977
  function getCommitsSinceConfigUpdate(dir) {
@@ -5897,7 +5986,7 @@ function getCommitsSinceConfigUpdate(dir) {
5897
5986
  const filePath = join6(dir, file);
5898
5987
  if (!existsSync5(filePath)) continue;
5899
5988
  try {
5900
- const mtime = statSync3(filePath).mtime.getTime();
5989
+ const mtime = statSync2(filePath).mtime.getTime();
5901
5990
  if (mtime > headTime) {
5902
5991
  return 0;
5903
5992
  }
@@ -6194,8 +6283,8 @@ function checkSources(dir) {
6194
6283
 
6195
6284
  // src/scoring/dismissed.ts
6196
6285
  import fs23 from "fs";
6197
- import path19 from "path";
6198
- var DISMISSED_FILE = path19.join(CALIBER_DIR, "dismissed-checks.json");
6286
+ import path20 from "path";
6287
+ var DISMISSED_FILE = path20.join(CALIBER_DIR, "dismissed-checks.json");
6199
6288
  function readDismissedChecks() {
6200
6289
  try {
6201
6290
  if (!fs23.existsSync(DISMISSED_FILE)) return [];
@@ -6464,12 +6553,12 @@ import chalk5 from "chalk";
6464
6553
 
6465
6554
  // src/telemetry/config.ts
6466
6555
  import fs24 from "fs";
6467
- import path20 from "path";
6556
+ import path21 from "path";
6468
6557
  import os5 from "os";
6469
6558
  import crypto4 from "crypto";
6470
6559
  import { execSync as execSync12 } from "child_process";
6471
- var CONFIG_DIR2 = path20.join(os5.homedir(), ".caliber");
6472
- var CONFIG_FILE2 = path20.join(CONFIG_DIR2, "config.json");
6560
+ var CONFIG_DIR2 = path21.join(os5.homedir(), ".caliber");
6561
+ var CONFIG_FILE2 = path21.join(CONFIG_DIR2, "config.json");
6473
6562
  var runtimeDisabled = false;
6474
6563
  function readConfig() {
6475
6564
  try {
@@ -6668,7 +6757,7 @@ function detectLocalPlatforms() {
6668
6757
  return platforms.size > 0 ? Array.from(platforms) : ["claude"];
6669
6758
  }
6670
6759
  function sanitizeSlug(slug) {
6671
- return slug.replace(/[^a-zA-Z0-9_\-]/g, "-").replace(/^-+|-+$/g, "");
6760
+ return slug.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/^-+|-+$/g, "");
6672
6761
  }
6673
6762
  function getSkillPath(platform, slug) {
6674
6763
  const safe = sanitizeSlug(slug);
@@ -6706,9 +6795,12 @@ async function searchSkillsSh(technologies) {
6706
6795
  const bestBySlug = /* @__PURE__ */ new Map();
6707
6796
  for (const tech of technologies) {
6708
6797
  try {
6709
- const resp = await fetch(`https://skills.sh/api/search?q=${encodeURIComponent(tech)}&limit=10`, {
6710
- signal: AbortSignal.timeout(1e4)
6711
- });
6798
+ const resp = await fetch(
6799
+ `https://skills.sh/api/search?q=${encodeURIComponent(tech)}&limit=10`,
6800
+ {
6801
+ signal: AbortSignal.timeout(1e4)
6802
+ }
6803
+ );
6712
6804
  if (!resp.ok) continue;
6713
6805
  const data = await resp.json();
6714
6806
  if (!data.skills?.length) continue;
@@ -6767,9 +6859,7 @@ async function searchAwesomeClaudeCode(technologies) {
6767
6859
  }
6768
6860
  }
6769
6861
  async function searchAllProviders(technologies, platform) {
6770
- const searches = [
6771
- searchSkillsSh(technologies)
6772
- ];
6862
+ const searches = [searchSkillsSh(technologies)];
6773
6863
  if (platform === "claude" || !platform) {
6774
6864
  searches.push(searchAwesomeClaudeCode(technologies));
6775
6865
  }
@@ -6829,18 +6919,24 @@ ${candidateList}`,
6829
6919
  function buildProjectContext(fingerprint, platforms) {
6830
6920
  const parts = [];
6831
6921
  if (fingerprint.packageName) parts.push(`Package: ${fingerprint.packageName}`);
6832
- if (fingerprint.languages.length > 0) parts.push(`Languages: ${fingerprint.languages.join(", ")}`);
6833
- if (fingerprint.frameworks.length > 0) parts.push(`Frameworks: ${fingerprint.frameworks.join(", ")}`);
6922
+ if (fingerprint.languages.length > 0)
6923
+ parts.push(`Languages: ${fingerprint.languages.join(", ")}`);
6924
+ if (fingerprint.frameworks.length > 0)
6925
+ parts.push(`Frameworks: ${fingerprint.frameworks.join(", ")}`);
6834
6926
  if (fingerprint.description) parts.push(`Description: ${fingerprint.description}`);
6835
6927
  if (fingerprint.fileTree.length > 0) {
6836
- parts.push(`
6928
+ parts.push(
6929
+ `
6837
6930
  File tree (${fingerprint.fileTree.length} files):
6838
- ${fingerprint.fileTree.slice(0, 50).join("\n")}`);
6931
+ ${fingerprint.fileTree.slice(0, 50).join("\n")}`
6932
+ );
6839
6933
  }
6840
6934
  if (fingerprint.existingConfigs.claudeMd) {
6841
- parts.push(`
6935
+ parts.push(
6936
+ `
6842
6937
  Existing CLAUDE.md (first 500 chars):
6843
- ${fingerprint.existingConfigs.claudeMd.slice(0, 500)}`);
6938
+ ${fingerprint.existingConfigs.claudeMd.slice(0, 500)}`
6939
+ );
6844
6940
  }
6845
6941
  const deps = extractTopDeps();
6846
6942
  if (deps.length > 0) {
@@ -6923,20 +7019,18 @@ function extractTopDeps() {
6923
7019
  /^@typescript-eslint\//,
6924
7020
  /^@commitlint\//
6925
7021
  ];
6926
- return deps.filter(
6927
- (d) => !trivial.has(d) && !trivialPatterns.some((p) => p.test(d))
6928
- );
7022
+ return deps.filter((d) => !trivial.has(d) && !trivialPatterns.some((p) => p.test(d)));
6929
7023
  } catch {
6930
7024
  return [];
6931
7025
  }
6932
7026
  }
6933
7027
  async function searchSkills(fingerprint, targetPlatforms, onStatus) {
6934
7028
  const installedSkills = getInstalledSkills(targetPlatforms);
6935
- const technologies = [...new Set([
6936
- ...fingerprint.languages,
6937
- ...fingerprint.frameworks,
6938
- ...extractTopDeps()
6939
- ].filter(Boolean))];
7029
+ const technologies = [
7030
+ ...new Set(
7031
+ [...fingerprint.languages, ...fingerprint.frameworks, ...extractTopDeps()].filter(Boolean)
7032
+ )
7033
+ ];
6940
7034
  if (technologies.length === 0) {
6941
7035
  return { results: [], contentMap: /* @__PURE__ */ new Map() };
6942
7036
  }
@@ -6968,10 +7062,12 @@ async function searchSkills(fingerprint, targetPlatforms, onStatus) {
6968
7062
  }
6969
7063
  onStatus?.("Fetching skill content...");
6970
7064
  const contentMap = /* @__PURE__ */ new Map();
6971
- await Promise.all(results.map(async (rec) => {
6972
- const content = await fetchSkillContent(rec);
6973
- if (content) contentMap.set(rec.slug, content);
6974
- }));
7065
+ await Promise.all(
7066
+ results.map(async (rec) => {
7067
+ const content = await fetchSkillContent(rec);
7068
+ if (content) contentMap.set(rec.slug, content);
7069
+ })
7070
+ );
6975
7071
  const available = results.filter((r) => contentMap.has(r.slug));
6976
7072
  return { results: available, contentMap };
6977
7073
  }
@@ -7017,10 +7113,12 @@ async function querySkills(query) {
7017
7113
  const top = results.slice(0, 5);
7018
7114
  const fetchSpinner = ora("Verifying availability...").start();
7019
7115
  const contentMap = /* @__PURE__ */ new Map();
7020
- await Promise.all(top.map(async (rec) => {
7021
- const content = await fetchSkillContent(rec);
7022
- if (content) contentMap.set(rec.slug, content);
7023
- }));
7116
+ await Promise.all(
7117
+ top.map(async (rec) => {
7118
+ const content = await fetchSkillContent(rec);
7119
+ if (content) contentMap.set(rec.slug, content);
7120
+ })
7121
+ );
7024
7122
  const available = top.filter((r) => contentMap.has(r.slug));
7025
7123
  fetchSpinner.succeed(`${available.length} available`);
7026
7124
  if (!available.length) {
@@ -7035,7 +7133,11 @@ async function querySkills(query) {
7035
7133
  console.log(` ${r.reason || r.name}`);
7036
7134
  }
7037
7135
  console.log("");
7038
- console.log(chalk6.dim(` Install with: ${resolveCaliber()} skills --install ${available.map((r) => r.slug).join(",")}`));
7136
+ console.log(
7137
+ chalk6.dim(
7138
+ ` Install with: ${resolveCaliber()} skills --install ${available.map((r) => r.slug).join(",")}`
7139
+ )
7140
+ );
7039
7141
  console.log("");
7040
7142
  }
7041
7143
  async function installBySlug(slugStr) {
@@ -7057,10 +7159,12 @@ async function installBySlug(slugStr) {
7057
7159
  return;
7058
7160
  }
7059
7161
  const contentMap = /* @__PURE__ */ new Map();
7060
- await Promise.all(matched.map(async (rec) => {
7061
- const content = await fetchSkillContent(rec);
7062
- if (content) contentMap.set(rec.slug, content);
7063
- }));
7162
+ await Promise.all(
7163
+ matched.map(async (rec) => {
7164
+ const content = await fetchSkillContent(rec);
7165
+ if (content) contentMap.set(rec.slug, content);
7166
+ })
7167
+ );
7064
7168
  const installable = matched.filter((r) => contentMap.has(r.slug));
7065
7169
  if (!installable.length) {
7066
7170
  spinner.fail("Could not fetch skill content.");
@@ -7097,13 +7201,17 @@ async function searchAndInstallSkills(targetPlatforms) {
7097
7201
  const fingerprint = await collectFingerprint(process.cwd());
7098
7202
  const platforms = targetPlatforms ?? detectLocalPlatforms();
7099
7203
  const installedSkills = getInstalledSkills(platforms);
7100
- const technologies = [...new Set([
7101
- ...fingerprint.languages,
7102
- ...fingerprint.frameworks,
7103
- ...extractTopDeps()
7104
- ].filter(Boolean))];
7204
+ const technologies = [
7205
+ ...new Set(
7206
+ [...fingerprint.languages, ...fingerprint.frameworks, ...extractTopDeps()].filter(Boolean)
7207
+ )
7208
+ ];
7105
7209
  if (technologies.length === 0) {
7106
- console.log(chalk6.yellow("Could not detect any languages or dependencies. Try running from a project root."));
7210
+ console.log(
7211
+ chalk6.yellow(
7212
+ "Could not detect any languages or dependencies. Try running from a project root."
7213
+ )
7214
+ );
7107
7215
  throw new Error("__exit__");
7108
7216
  }
7109
7217
  const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
@@ -7133,7 +7241,9 @@ async function searchAndInstallSkills(targetPlatforms) {
7133
7241
  scoreSpinner.succeed("No highly relevant skills found for your specific project.");
7134
7242
  return;
7135
7243
  }
7136
- scoreSpinner.succeed(`${results.length} relevant skill${results.length > 1 ? "s" : ""} for your project`);
7244
+ scoreSpinner.succeed(
7245
+ `${results.length} relevant skill${results.length > 1 ? "s" : ""} for your project`
7246
+ );
7137
7247
  } catch {
7138
7248
  scoreSpinner.warn("Could not score relevance \u2014 showing top results");
7139
7249
  results = newCandidates.slice(0, 20);
@@ -7143,10 +7253,12 @@ async function searchAndInstallSkills(targetPlatforms) {
7143
7253
  }
7144
7254
  const fetchSpinner = ora("Verifying skill availability...").start();
7145
7255
  const contentMap = /* @__PURE__ */ new Map();
7146
- await Promise.all(results.map(async (rec) => {
7147
- const content = await fetchSkillContent(rec);
7148
- if (content) contentMap.set(rec.slug, content);
7149
- }));
7256
+ await Promise.all(
7257
+ results.map(async (rec) => {
7258
+ const content = await fetchSkillContent(rec);
7259
+ if (content) contentMap.set(rec.slug, content);
7260
+ })
7261
+ );
7150
7262
  const available = results.filter((r) => contentMap.has(r.slug));
7151
7263
  if (!available.length) {
7152
7264
  fetchSpinner.fail("No installable skills found \u2014 content could not be fetched.");
@@ -7194,9 +7306,13 @@ async function interactiveSelect(recs) {
7194
7306
  if (hasScores) {
7195
7307
  const scoreColor = rec.score >= 90 ? chalk6.green : rec.score >= 70 ? chalk6.yellow : chalk6.dim;
7196
7308
  const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
7197
- lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${chalk6.dim(rec.reason.slice(0, reasonMax))}`);
7309
+ lines.push(
7310
+ ` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${chalk6.dim(rec.reason.slice(0, reasonMax))}`
7311
+ );
7198
7312
  } else {
7199
- lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk6.dim(rec.source_url || "")}`);
7313
+ lines.push(
7314
+ ` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk6.dim(rec.source_url || "")}`
7315
+ );
7200
7316
  }
7201
7317
  }
7202
7318
  lines.push("");
@@ -7252,7 +7368,9 @@ async function interactiveSelect(recs) {
7252
7368
  console.log(chalk6.dim("\n No skills selected.\n"));
7253
7369
  resolve3(null);
7254
7370
  } else {
7255
- resolve3(Array.from(selected).sort().map((i) => recs[i]));
7371
+ resolve3(
7372
+ Array.from(selected).sort().map((i) => recs[i])
7373
+ );
7256
7374
  }
7257
7375
  break;
7258
7376
  case "q":
@@ -7321,17 +7439,25 @@ function printSkills(recs) {
7321
7439
  const prefixWidth = 2;
7322
7440
  console.log(chalk6.bold("\n Skills\n"));
7323
7441
  if (hasScores) {
7324
- console.log(" ".repeat(prefixWidth) + chalk6.dim("Score".padEnd(scoreWidth)) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Why"));
7442
+ console.log(
7443
+ " ".repeat(prefixWidth) + chalk6.dim("Score".padEnd(scoreWidth)) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Why")
7444
+ );
7325
7445
  } else {
7326
- console.log(" ".repeat(prefixWidth) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Technology".padEnd(18)) + chalk6.dim("Source"));
7446
+ console.log(
7447
+ " ".repeat(prefixWidth) + chalk6.dim("Name".padEnd(nameWidth)) + chalk6.dim("Technology".padEnd(18)) + chalk6.dim("Source")
7448
+ );
7327
7449
  }
7328
7450
  console.log(chalk6.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
7329
7451
  for (const rec of recs) {
7330
7452
  if (hasScores) {
7331
7453
  const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
7332
- console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${chalk6.dim(rec.reason.slice(0, reasonMax))}`);
7454
+ console.log(
7455
+ ` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${chalk6.dim(rec.reason.slice(0, reasonMax))}`
7456
+ );
7333
7457
  } else {
7334
- console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk6.dim(rec.source_url || "")}`);
7458
+ console.log(
7459
+ ` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk6.dim(rec.source_url || "")}`
7460
+ );
7335
7461
  }
7336
7462
  }
7337
7463
  console.log("");
@@ -7551,11 +7677,11 @@ function countIssuePoints(issues) {
7551
7677
  }
7552
7678
  async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
7553
7679
  const existsCache = /* @__PURE__ */ new Map();
7554
- const cachedExists = (path40) => {
7555
- const cached = existsCache.get(path40);
7680
+ const cachedExists = (path41) => {
7681
+ const cached = existsCache.get(path41);
7556
7682
  if (cached !== void 0) return cached;
7557
- const result = existsSync9(path40);
7558
- existsCache.set(path40, result);
7683
+ const result = existsSync9(path41);
7684
+ existsCache.set(path41, result);
7559
7685
  return result;
7560
7686
  };
7561
7687
  const projectStructure = collectProjectStructure(dir);
@@ -7695,7 +7821,7 @@ async function runScoreRefineWithSpinner(setup, dir, sessionHistory) {
7695
7821
 
7696
7822
  // src/lib/debug-report.ts
7697
7823
  import fs25 from "fs";
7698
- import path21 from "path";
7824
+ import path22 from "path";
7699
7825
  var DebugReport = class {
7700
7826
  sections = [];
7701
7827
  startTime;
@@ -7764,7 +7890,7 @@ var DebugReport = class {
7764
7890
  lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
7765
7891
  lines.push("");
7766
7892
  }
7767
- const dir = path21.dirname(outputPath);
7893
+ const dir = path22.dirname(outputPath);
7768
7894
  if (!fs25.existsSync(dir)) {
7769
7895
  fs25.mkdirSync(dir, { recursive: true });
7770
7896
  }
@@ -8450,7 +8576,11 @@ function formatWhatChanged(setup) {
8450
8576
  lines.push(`${action} AGENTS.md`);
8451
8577
  }
8452
8578
  const allSkills = [];
8453
- for (const [platform, obj] of [["claude", claude], ["codex", codex], ["cursor", cursor]]) {
8579
+ for (const [_platform, obj] of [
8580
+ ["claude", claude],
8581
+ ["codex", codex],
8582
+ ["cursor", cursor]
8583
+ ]) {
8454
8584
  const skills = obj?.skills;
8455
8585
  if (Array.isArray(skills)) {
8456
8586
  for (const s of skills) allSkills.push(s.name);
@@ -8467,7 +8597,9 @@ function formatWhatChanged(setup) {
8467
8597
  }
8468
8598
  const deletions = setup.deletions;
8469
8599
  if (Array.isArray(deletions) && deletions.length > 0) {
8470
- lines.push(`Removing ${deletions.length} file${deletions.length === 1 ? "" : "s"}: ${deletions.map((d) => d.filePath).join(", ")}`);
8600
+ lines.push(
8601
+ `Removing ${deletions.length} file${deletions.length === 1 ? "" : "s"}: ${deletions.map((d) => d.filePath).join(", ")}`
8602
+ );
8471
8603
  }
8472
8604
  return lines;
8473
8605
  }
@@ -8565,7 +8697,9 @@ function printSetupSummary(setup) {
8565
8697
  console.log("");
8566
8698
  }
8567
8699
  }
8568
- console.log(` ${chalk12.green("+")} ${chalk12.dim("new")} ${chalk12.yellow("~")} ${chalk12.dim("modified")} ${chalk12.red("-")} ${chalk12.dim("removed")}`);
8700
+ console.log(
8701
+ ` ${chalk12.green("+")} ${chalk12.dim("new")} ${chalk12.yellow("~")} ${chalk12.dim("modified")} ${chalk12.red("-")} ${chalk12.dim("removed")}`
8702
+ );
8569
8703
  console.log("");
8570
8704
  }
8571
8705
  function displayTokenUsage() {
@@ -8580,11 +8714,17 @@ function displayTokenUsage() {
8580
8714
  for (const m of summary) {
8581
8715
  totalIn += m.inputTokens;
8582
8716
  totalOut += m.outputTokens;
8583
- const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ? chalk12.dim(` (cache: ${m.cacheReadTokens.toLocaleString()} read, ${m.cacheWriteTokens.toLocaleString()} write)`) : "";
8584
- console.log(` ${chalk12.dim(m.model)}: ${m.inputTokens.toLocaleString()} in / ${m.outputTokens.toLocaleString()} out (${m.calls} call${m.calls === 1 ? "" : "s"})${cacheInfo}`);
8717
+ const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ? chalk12.dim(
8718
+ ` (cache: ${m.cacheReadTokens.toLocaleString()} read, ${m.cacheWriteTokens.toLocaleString()} write)`
8719
+ ) : "";
8720
+ console.log(
8721
+ ` ${chalk12.dim(m.model)}: ${m.inputTokens.toLocaleString()} in / ${m.outputTokens.toLocaleString()} out (${m.calls} call${m.calls === 1 ? "" : "s"})${cacheInfo}`
8722
+ );
8585
8723
  }
8586
8724
  if (summary.length > 1) {
8587
- console.log(` ${chalk12.dim("Total")}: ${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out`);
8725
+ console.log(
8726
+ ` ${chalk12.dim("Total")}: ${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out`
8727
+ );
8588
8728
  }
8589
8729
  console.log("");
8590
8730
  }
@@ -8593,9 +8733,9 @@ function displayTokenUsage() {
8593
8733
  init_config();
8594
8734
  import chalk13 from "chalk";
8595
8735
  import fs30 from "fs";
8596
- import path23 from "path";
8736
+ import path24 from "path";
8597
8737
  function isFirstRun(dir) {
8598
- const caliberDir = path23.join(dir, ".caliber");
8738
+ const caliberDir = path24.join(dir, ".caliber");
8599
8739
  try {
8600
8740
  const stat = fs30.statSync(caliberDir);
8601
8741
  return !stat.isDirectory();
@@ -8665,7 +8805,7 @@ function ensurePermissions(fingerprint) {
8665
8805
  }
8666
8806
  function writeErrorLog(config, rawOutput, error, stopReason) {
8667
8807
  try {
8668
- const logPath = path23.join(process.cwd(), ".caliber", "error-log.md");
8808
+ const logPath = path24.join(process.cwd(), ".caliber", "error-log.md");
8669
8809
  const lines = [
8670
8810
  `# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
8671
8811
  "",
@@ -8678,7 +8818,7 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
8678
8818
  lines.push("## Error", "```", error, "```", "");
8679
8819
  }
8680
8820
  lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
8681
- fs30.mkdirSync(path23.join(process.cwd(), ".caliber"), { recursive: true });
8821
+ fs30.mkdirSync(path24.join(process.cwd(), ".caliber"), { recursive: true });
8682
8822
  fs30.writeFileSync(logPath, lines.join("\n"));
8683
8823
  console.log(chalk13.dim(`
8684
8824
  Error log written to .caliber/error-log.md`));
@@ -8731,12 +8871,12 @@ ${JSON.stringify(checkList, null, 2)}`,
8731
8871
 
8732
8872
  // src/scoring/history.ts
8733
8873
  import fs31 from "fs";
8734
- import path24 from "path";
8874
+ import path25 from "path";
8735
8875
  var HISTORY_FILE = "score-history.jsonl";
8736
8876
  var MAX_ENTRIES = 500;
8737
8877
  var TRIM_THRESHOLD = MAX_ENTRIES + 50;
8738
8878
  function historyFilePath() {
8739
- return path24.join(CALIBER_DIR, HISTORY_FILE);
8879
+ return path25.join(CALIBER_DIR, HISTORY_FILE);
8740
8880
  }
8741
8881
  function recordScore(result, trigger) {
8742
8882
  const entry = {
@@ -8801,14 +8941,16 @@ async function initCommand(options) {
8801
8941
  const bin = resolveCaliber();
8802
8942
  const firstRun = isFirstRun(process.cwd());
8803
8943
  if (firstRun) {
8804
- console.log(brand.bold(`
8944
+ console.log(
8945
+ brand.bold(`
8805
8946
  \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
8806
8947
  \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
8807
8948
  \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
8808
8949
  \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
8809
8950
  \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
8810
8951
  \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
8811
- `));
8952
+ `)
8953
+ );
8812
8954
  console.log(chalk14.dim(" Scan your project and generate tailored config files for"));
8813
8955
  console.log(chalk14.dim(" Claude Code, Cursor, Codex, and GitHub Copilot.\n"));
8814
8956
  console.log(title.bold(" How it works:\n"));
@@ -8822,7 +8964,11 @@ async function initCommand(options) {
8822
8964
  const platforms = detectPlatforms();
8823
8965
  if (!platforms.claude && !platforms.cursor && !platforms.codex) {
8824
8966
  console.log(chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex)."));
8825
- console.log(chalk14.yellow(" Caliber will still generate config files, but they won't be auto-installed.\n"));
8967
+ console.log(
8968
+ chalk14.yellow(
8969
+ " Caliber will still generate config files, but they won't be auto-installed.\n"
8970
+ )
8971
+ );
8826
8972
  }
8827
8973
  const report = options.debugReport ? new DebugReport() : null;
8828
8974
  console.log(title.bold(" Step 1/4 \u2014 Connect\n"));
@@ -8846,9 +8992,12 @@ async function initCommand(options) {
8846
8992
  console.log(chalk14.dim(modelLine + "\n"));
8847
8993
  if (report) {
8848
8994
  report.markStep("Provider connection");
8849
- report.addSection("LLM Provider", `- **Provider**: ${config.provider}
8995
+ report.addSection(
8996
+ "LLM Provider",
8997
+ `- **Provider**: ${config.provider}
8850
8998
  - **Model**: ${displayModel}
8851
- - **Fast model**: ${fastModel || "none"}`);
8999
+ - **Fast model**: ${fastModel || "none"}`
9000
+ );
8852
9001
  }
8853
9002
  await validateModel({ fast: true });
8854
9003
  let targetAgent;
@@ -8865,21 +9014,29 @@ async function initCommand(options) {
8865
9014
  console.log(chalk14.dim(` Target: ${targetAgent.join(", ")}
8866
9015
  `));
8867
9016
  trackInitAgentSelected(targetAgent, agentAutoDetected);
8868
- let baselineScore = computeLocalScore(process.cwd(), targetAgent);
9017
+ const baselineScore = computeLocalScore(process.cwd(), targetAgent);
8869
9018
  console.log(chalk14.dim("\n Current config score:"));
8870
9019
  displayScoreSummary(baselineScore);
8871
9020
  if (options.verbose) {
8872
9021
  for (const c of baselineScore.checks) {
8873
- log(options.verbose, ` ${c.passed ? "\u2713" : "\u2717"} ${c.name}: ${c.earnedPoints}/${c.maxPoints}${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
9022
+ log(
9023
+ options.verbose,
9024
+ ` ${c.passed ? "\u2713" : "\u2717"} ${c.name}: ${c.earnedPoints}/${c.maxPoints}${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`
9025
+ );
8874
9026
  }
8875
9027
  }
8876
9028
  if (report) {
8877
9029
  report.markStep("Baseline scoring");
8878
- report.addSection("Scoring: Baseline", `**Score**: ${baselineScore.score}/100
9030
+ report.addSection(
9031
+ "Scoring: Baseline",
9032
+ `**Score**: ${baselineScore.score}/100
8879
9033
 
8880
9034
  | Check | Passed | Points | Max |
8881
9035
  |-------|--------|--------|-----|
8882
- ` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
9036
+ ` + baselineScore.checks.map(
9037
+ (c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`
9038
+ ).join("\n")
9039
+ );
8883
9040
  report.addSection("Generation: Target Agents", targetAgent.join(", "));
8884
9041
  }
8885
9042
  const hasExistingConfig = !!(baselineScore.checks.some((c) => c.id === "claude_md_exists" && c.passed) || baselineScore.checks.some((c) => c.id === "cursorrules_exists" && c.passed));
@@ -8896,7 +9053,9 @@ async function initCommand(options) {
8896
9053
  if (hasExistingConfig && baselineScore.score === 100) {
8897
9054
  trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
8898
9055
  console.log(chalk14.bold.green(" Your config is already optimal \u2014 nothing to change.\n"));
8899
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n"));
9056
+ console.log(
9057
+ chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n")
9058
+ );
8900
9059
  if (!options.force) return;
8901
9060
  }
8902
9061
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
@@ -8912,7 +9071,9 @@ async function initCommand(options) {
8912
9071
  }
8913
9072
  }
8914
9073
  console.log("");
8915
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n"));
9074
+ console.log(
9075
+ chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to regenerate anyway.\n")
9076
+ );
8916
9077
  return;
8917
9078
  }
8918
9079
  console.log(title.bold(" Step 2/4 \u2014 Engine\n"));
@@ -8931,8 +9092,14 @@ async function initCommand(options) {
8931
9092
  const TASK_STACK = display.add("Detecting project stack", { pipelineLabel: "Scan" });
8932
9093
  const TASK_CONFIG = display.add("Generating configs", { depth: 1, pipelineLabel: "Generate" });
8933
9094
  const TASK_SKILLS_GEN = display.add("Generating skills", { depth: 2, pipelineLabel: "Skills" });
8934
- const TASK_SKILLS_SEARCH = display.add("Searching community skills", { depth: 1, pipelineLabel: "Search", pipelineRow: 1 });
8935
- const TASK_SCORE_REFINE = display.add("Validating & refining config", { pipelineLabel: "Validate" });
9095
+ const TASK_SKILLS_SEARCH = display.add("Searching community skills", {
9096
+ depth: 1,
9097
+ pipelineLabel: "Search",
9098
+ pipelineRow: 1
9099
+ });
9100
+ const TASK_SCORE_REFINE = display.add("Validating & refining config", {
9101
+ pipelineLabel: "Validate"
9102
+ });
8936
9103
  display.start();
8937
9104
  display.enableWaitingContent();
8938
9105
  try {
@@ -8942,21 +9109,39 @@ async function initCommand(options) {
8942
9109
  const stackSummary = stackParts.join(", ") || "no languages";
8943
9110
  const largeRepoNote = fingerprint.fileTree.length > 5e3 ? ` (${fingerprint.fileTree.length.toLocaleString()} files, smart sampling active)` : "";
8944
9111
  display.update(TASK_STACK, "done", stackSummary + largeRepoNote);
8945
- trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
8946
- log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
9112
+ trackInitProjectDiscovered(
9113
+ fingerprint.languages.length,
9114
+ fingerprint.frameworks.length,
9115
+ fingerprint.fileTree.length
9116
+ );
9117
+ log(
9118
+ options.verbose,
9119
+ `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`
9120
+ );
8947
9121
  const cliSources = options.source || [];
8948
9122
  const workspaces = getDetectedWorkspaces(process.cwd());
8949
9123
  const sources2 = resolveAllSources(process.cwd(), cliSources, workspaces);
8950
9124
  if (sources2.length > 0) {
8951
9125
  fingerprint.sources = sources2;
8952
- log(options.verbose, `Sources: ${sources2.length} resolved (${sources2.map((s) => s.name).join(", ")})`);
9126
+ log(
9127
+ options.verbose,
9128
+ `Sources: ${sources2.length} resolved (${sources2.map((s) => s.name).join(", ")})`
9129
+ );
8953
9130
  }
8954
9131
  if (report) {
8955
- report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
9132
+ report.addJson("Fingerprint: Git", {
9133
+ remote: fingerprint.gitRemoteUrl,
9134
+ packageName: fingerprint.packageName
9135
+ });
8956
9136
  report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
8957
- report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
9137
+ report.addJson("Fingerprint: Detected Stack", {
9138
+ languages: fingerprint.languages,
9139
+ frameworks: fingerprint.frameworks,
9140
+ tools: fingerprint.tools
9141
+ });
8958
9142
  report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
8959
- if (fingerprint.codeAnalysis) report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
9143
+ if (fingerprint.codeAnalysis)
9144
+ report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
8960
9145
  }
8961
9146
  const isEmpty = fingerprint.fileTree.length < 3;
8962
9147
  if (isEmpty) {
@@ -8987,13 +9172,26 @@ async function initCommand(options) {
8987
9172
  let passingChecks;
8988
9173
  let currentScore;
8989
9174
  if (hasExistingConfig && localBaseline.score >= 95 && !options.force) {
8990
- const currentLlmFixable = localBaseline.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
8991
- failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
9175
+ const currentLlmFixable = localBaseline.checks.filter(
9176
+ (c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id)
9177
+ );
9178
+ failingChecks = currentLlmFixable.map((c) => ({
9179
+ name: c.name,
9180
+ suggestion: c.suggestion,
9181
+ fix: c.fix
9182
+ }));
8992
9183
  passingChecks = localBaseline.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
8993
9184
  currentScore = localBaseline.score;
8994
9185
  }
8995
9186
  if (report) {
8996
- const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
9187
+ const fullPrompt = buildGeneratePrompt(
9188
+ fingerprint,
9189
+ targetAgent,
9190
+ fingerprint.description,
9191
+ failingChecks,
9192
+ currentScore,
9193
+ passingChecks
9194
+ );
8997
9195
  report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
8998
9196
  }
8999
9197
  const result = await generateSetup(
@@ -9113,7 +9311,10 @@ async function initCommand(options) {
9113
9311
  if (rawOutput) report.addCodeBlock("Generation: Raw LLM Response", rawOutput);
9114
9312
  report.addJson("Generation: Parsed Config", generatedSetup);
9115
9313
  }
9116
- log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
9314
+ log(
9315
+ options.verbose,
9316
+ `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`
9317
+ );
9117
9318
  console.log(title.bold(" Step 3/4 \u2014 Review\n"));
9118
9319
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
9119
9320
  const staged = stageFiles(setupFiles, process.cwd());
@@ -9125,10 +9326,18 @@ async function initCommand(options) {
9125
9326
  }
9126
9327
  console.log("");
9127
9328
  }
9128
- console.log(chalk14.dim(` ${chalk14.green(`${staged.newFiles} new`)} / ${chalk14.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`));
9329
+ console.log(
9330
+ chalk14.dim(
9331
+ ` ${chalk14.green(`${staged.newFiles} new`)} / ${chalk14.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`
9332
+ )
9333
+ );
9129
9334
  if (skillSearchResult.results.length > 0) {
9130
- console.log(chalk14.dim(` ${chalk14.cyan(`${skillSearchResult.results.length}`)} community skills available to install
9131
- `));
9335
+ console.log(
9336
+ chalk14.dim(
9337
+ ` ${chalk14.cyan(`${skillSearchResult.results.length}`)} community skills available to install
9338
+ `
9339
+ )
9340
+ );
9132
9341
  } else {
9133
9342
  console.log("");
9134
9343
  }
@@ -9164,8 +9373,12 @@ async function initCommand(options) {
9164
9373
  }
9165
9374
  const updatedFiles = collectSetupFiles(generatedSetup, targetAgent);
9166
9375
  const restaged = stageFiles(updatedFiles, process.cwd());
9167
- console.log(chalk14.dim(` ${chalk14.green(`${restaged.newFiles} new`)} / ${chalk14.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
9168
- `));
9376
+ console.log(
9377
+ chalk14.dim(
9378
+ ` ${chalk14.green(`${restaged.newFiles} new`)} / ${chalk14.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
9379
+ `
9380
+ )
9381
+ );
9169
9382
  printSetupSummary(generatedSetup);
9170
9383
  const { openReview: openRev } = await Promise.resolve().then(() => (init_review(), review_exports));
9171
9384
  await openRev("terminal", restaged.stagedFiles);
@@ -9192,7 +9405,8 @@ async function initCommand(options) {
9192
9405
  const agentRefs = [];
9193
9406
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
9194
9407
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
9195
- if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
9408
+ if (agentRefs.length === 0)
9409
+ agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
9196
9410
  const stubContent = `# AGENTS.md
9197
9411
 
9198
9412
  This project uses AI coding agents configured by [Caliber](https://github.com/caliber-ai-org/ai-setup).
@@ -9239,31 +9453,49 @@ ${agentRefs.join(" ")}
9239
9453
  if (afterScore.score < baselineScore.score) {
9240
9454
  trackInitScoreRegression(baselineScore.score, afterScore.score);
9241
9455
  console.log("");
9242
- console.log(chalk14.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
9456
+ console.log(
9457
+ chalk14.yellow(
9458
+ ` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`
9459
+ )
9460
+ );
9243
9461
  try {
9244
9462
  const { restored, removed } = undoSetup();
9245
9463
  if (restored.length > 0 || removed.length > 0) {
9246
- console.log(chalk14.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
9464
+ console.log(
9465
+ chalk14.dim(
9466
+ ` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`
9467
+ )
9468
+ );
9247
9469
  }
9248
9470
  } catch {
9249
9471
  }
9250
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n"));
9472
+ console.log(
9473
+ chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n")
9474
+ );
9251
9475
  return;
9252
9476
  }
9253
9477
  if (report) {
9254
9478
  report.markStep("Post-write scoring");
9255
- report.addSection("Scoring: Post-Write", `**Score**: ${afterScore.score}/100 (delta: ${afterScore.score - baselineScore.score >= 0 ? "+" : ""}${afterScore.score - baselineScore.score})
9479
+ report.addSection(
9480
+ "Scoring: Post-Write",
9481
+ `**Score**: ${afterScore.score}/100 (delta: ${afterScore.score - baselineScore.score >= 0 ? "+" : ""}${afterScore.score - baselineScore.score})
9256
9482
 
9257
9483
  | Check | Passed | Points | Max |
9258
9484
  |-------|--------|--------|-----|
9259
- ` + afterScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
9485
+ ` + afterScore.checks.map(
9486
+ (c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`
9487
+ ).join("\n")
9488
+ );
9260
9489
  }
9261
9490
  recordScore(afterScore, "init");
9262
9491
  displayScoreDelta(baselineScore, afterScore);
9263
9492
  if (options.verbose) {
9264
9493
  log(options.verbose, `Final score: ${afterScore.score}/100`);
9265
9494
  for (const c of afterScore.checks.filter((ch) => !ch.passed)) {
9266
- log(options.verbose, ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
9495
+ log(
9496
+ options.verbose,
9497
+ ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`
9498
+ );
9267
9499
  }
9268
9500
  }
9269
9501
  let communitySkillsInstalled = 0;
@@ -9277,7 +9509,9 @@ ${agentRefs.join(" ")}
9277
9509
  }
9278
9510
  }
9279
9511
  console.log("");
9280
- console.log(` ${chalk14.green("\u2713")} Docs auto-refresh ${chalk14.dim(`agents run ${resolveCaliber()} refresh before commits`)}`);
9512
+ console.log(
9513
+ ` ${chalk14.green("\u2713")} Docs auto-refresh ${chalk14.dim(`agents run ${resolveCaliber()} refresh before commits`)}`
9514
+ );
9281
9515
  trackInitHookSelected("config-instructions");
9282
9516
  const hasLearnableAgent = targetAgent.includes("claude") || targetAgent.includes("cursor");
9283
9517
  let enableLearn = false;
@@ -9288,17 +9522,24 @@ ${agentRefs.join(" ")}
9288
9522
  if (enableLearn) {
9289
9523
  if (targetAgent.includes("claude")) {
9290
9524
  const r = installLearningHooks();
9291
- if (r.installed) console.log(` ${chalk14.green("\u2713")} Learning hooks installed for Claude Code`);
9292
- else if (r.alreadyInstalled) console.log(chalk14.dim(" Claude Code learning hooks already installed"));
9525
+ if (r.installed)
9526
+ console.log(` ${chalk14.green("\u2713")} Learning hooks installed for Claude Code`);
9527
+ else if (r.alreadyInstalled)
9528
+ console.log(chalk14.dim(" Claude Code learning hooks already installed"));
9293
9529
  }
9294
9530
  if (targetAgent.includes("cursor")) {
9295
9531
  const r = installCursorLearningHooks();
9296
9532
  if (r.installed) console.log(` ${chalk14.green("\u2713")} Learning hooks installed for Cursor`);
9297
- else if (r.alreadyInstalled) console.log(chalk14.dim(" Cursor learning hooks already installed"));
9533
+ else if (r.alreadyInstalled)
9534
+ console.log(chalk14.dim(" Cursor learning hooks already installed"));
9298
9535
  }
9299
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} learn status`) + chalk14.dim(" to see insights"));
9536
+ console.log(
9537
+ chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} learn status`) + chalk14.dim(" to see insights")
9538
+ );
9300
9539
  } else {
9301
- console.log(chalk14.dim(" Skipped. Run ") + chalk14.hex("#83D1EB")(`${bin} learn install`) + chalk14.dim(" later to enable."));
9540
+ console.log(
9541
+ chalk14.dim(" Skipped. Run ") + chalk14.hex("#83D1EB")(`${bin} learn install`) + chalk14.dim(" later to enable.")
9542
+ );
9302
9543
  }
9303
9544
  } else {
9304
9545
  enableLearn = true;
@@ -9307,28 +9548,46 @@ ${agentRefs.join(" ")}
9307
9548
  }
9308
9549
  }
9309
9550
  console.log(chalk14.bold.green("\n Configuration complete!"));
9310
- console.log(chalk14.dim(" Your AI agents now understand your project's architecture, build commands,"));
9311
- console.log(chalk14.dim(" testing patterns, and conventions. All changes are backed up automatically.\n"));
9551
+ console.log(
9552
+ chalk14.dim(" Your AI agents now understand your project's architecture, build commands,")
9553
+ );
9554
+ console.log(
9555
+ chalk14.dim(" testing patterns, and conventions. All changes are backed up automatically.\n")
9556
+ );
9312
9557
  const done = chalk14.green("\u2713");
9313
9558
  const skip = chalk14.dim("\u2013");
9314
9559
  console.log(chalk14.bold(" What was configured:\n"));
9315
- console.log(` ${done} Config generated ${title(`${bin} score`)} ${chalk14.dim("for full breakdown")}`);
9316
- console.log(` ${done} Docs auto-refresh ${chalk14.dim(`agents run ${bin} refresh before commits`)}`);
9560
+ console.log(
9561
+ ` ${done} Config generated ${title(`${bin} score`)} ${chalk14.dim("for full breakdown")}`
9562
+ );
9563
+ console.log(
9564
+ ` ${done} Docs auto-refresh ${chalk14.dim(`agents run ${bin} refresh before commits`)}`
9565
+ );
9317
9566
  if (hasLearnableAgent) {
9318
9567
  if (enableLearn) {
9319
- console.log(` ${done} Session learning ${chalk14.dim("agent learns from your feedback")}`);
9568
+ console.log(
9569
+ ` ${done} Session learning ${chalk14.dim("agent learns from your feedback")}`
9570
+ );
9320
9571
  } else {
9321
- console.log(` ${skip} Session learning ${title(`${bin} learn install`)} to enable later`);
9572
+ console.log(
9573
+ ` ${skip} Session learning ${title(`${bin} learn install`)} to enable later`
9574
+ );
9322
9575
  }
9323
9576
  }
9324
9577
  if (communitySkillsInstalled > 0) {
9325
- console.log(` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} skill${communitySkillsInstalled > 1 ? "s" : ""} installed for your stack`)}`);
9578
+ console.log(
9579
+ ` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} skill${communitySkillsInstalled > 1 ? "s" : ""} installed for your stack`)}`
9580
+ );
9326
9581
  } else if (skillSearchResult.results.length > 0) {
9327
9582
  console.log(` ${skip} Community skills ${chalk14.dim("available but skipped")}`);
9328
9583
  }
9329
9584
  console.log(chalk14.bold("\n Explore next:\n"));
9330
- console.log(` ${title(`${bin} skills`)} Find more community skills as your codebase evolves`);
9331
- console.log(` ${title(`${bin} score`)} See the full scoring breakdown with improvement tips`);
9585
+ console.log(
9586
+ ` ${title(`${bin} skills`)} Find more community skills as your codebase evolves`
9587
+ );
9588
+ console.log(
9589
+ ` ${title(`${bin} score`)} See the full scoring breakdown with improvement tips`
9590
+ );
9332
9591
  console.log(` ${title(`${bin} undo`)} Revert all changes from this run`);
9333
9592
  console.log("");
9334
9593
  if (options.showTokens) {
@@ -9336,10 +9595,12 @@ ${agentRefs.join(" ")}
9336
9595
  }
9337
9596
  if (report) {
9338
9597
  report.markStep("Finished");
9339
- const reportPath = path25.join(process.cwd(), ".caliber", "debug-report.md");
9598
+ const reportPath = path26.join(process.cwd(), ".caliber", "debug-report.md");
9340
9599
  report.write(reportPath);
9341
- console.log(chalk14.dim(` Debug report written to ${path25.relative(process.cwd(), reportPath)}
9342
- `));
9600
+ console.log(
9601
+ chalk14.dim(` Debug report written to ${path26.relative(process.cwd(), reportPath)}
9602
+ `)
9603
+ );
9343
9604
  }
9344
9605
  }
9345
9606
 
@@ -9565,30 +9826,39 @@ async function regenerateCommand(options) {
9565
9826
  // src/commands/score.ts
9566
9827
  import fs34 from "fs";
9567
9828
  import os7 from "os";
9568
- import path26 from "path";
9829
+ import path27 from "path";
9569
9830
  import { execFileSync as execFileSync2 } from "child_process";
9570
9831
  import chalk18 from "chalk";
9571
9832
  init_resolve_caliber();
9572
9833
  var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".cursorrules", "CALIBER_LEARNINGS.md"];
9573
9834
  var CONFIG_DIRS = [".claude", ".cursor"];
9574
9835
  function scoreBaseRef(ref, target) {
9575
- if (!/^[\w.\-\/~^@{}]+$/.test(ref)) return null;
9576
- const tmpDir = fs34.mkdtempSync(path26.join(os7.tmpdir(), "caliber-compare-"));
9836
+ if (!/^[\w.\-/~^@{}]+$/.test(ref)) return null;
9837
+ const tmpDir = fs34.mkdtempSync(path27.join(os7.tmpdir(), "caliber-compare-"));
9577
9838
  try {
9578
9839
  for (const file of CONFIG_FILES) {
9579
9840
  try {
9580
- const content = execFileSync2("git", ["show", `${ref}:${file}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
9581
- fs34.writeFileSync(path26.join(tmpDir, file), content);
9841
+ const content = execFileSync2("git", ["show", `${ref}:${file}`], {
9842
+ encoding: "utf-8",
9843
+ stdio: ["pipe", "pipe", "pipe"]
9844
+ });
9845
+ fs34.writeFileSync(path27.join(tmpDir, file), content);
9582
9846
  } catch {
9583
9847
  }
9584
9848
  }
9585
9849
  for (const dir of CONFIG_DIRS) {
9586
9850
  try {
9587
- const files = execFileSync2("git", ["ls-tree", "-r", "--name-only", ref, `${dir}/`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim().split("\n").filter(Boolean);
9851
+ const files = execFileSync2("git", ["ls-tree", "-r", "--name-only", ref, `${dir}/`], {
9852
+ encoding: "utf-8",
9853
+ stdio: ["pipe", "pipe", "pipe"]
9854
+ }).trim().split("\n").filter(Boolean);
9588
9855
  for (const file of files) {
9589
- const filePath = path26.join(tmpDir, file);
9590
- fs34.mkdirSync(path26.dirname(filePath), { recursive: true });
9591
- const content = execFileSync2("git", ["show", `${ref}:${file}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
9856
+ const filePath = path27.join(tmpDir, file);
9857
+ fs34.mkdirSync(path27.dirname(filePath), { recursive: true });
9858
+ const content = execFileSync2("git", ["show", `${ref}:${file}`], {
9859
+ encoding: "utf-8",
9860
+ stdio: ["pipe", "pipe", "pipe"]
9861
+ });
9592
9862
  fs34.writeFileSync(filePath, content);
9593
9863
  }
9594
9864
  } catch {
@@ -9611,13 +9881,25 @@ async function scoreCommand(options) {
9611
9881
  if (options.compare) {
9612
9882
  const baseResult = scoreBaseRef(options.compare, target);
9613
9883
  if (!baseResult) {
9614
- console.error(chalk18.red(`Could not score ref "${options.compare}" \u2014 branch or ref not found.`));
9884
+ console.error(
9885
+ chalk18.red(`Could not score ref "${options.compare}" \u2014 branch or ref not found.`)
9886
+ );
9615
9887
  process.exitCode = 1;
9616
9888
  return;
9617
9889
  }
9618
9890
  const delta = result.score - baseResult.score;
9619
9891
  if (options.json) {
9620
- console.log(JSON.stringify({ current: result, base: { score: baseResult.score, grade: baseResult.grade, ref: options.compare }, delta }, null, 2));
9892
+ console.log(
9893
+ JSON.stringify(
9894
+ {
9895
+ current: result,
9896
+ base: { score: baseResult.score, grade: baseResult.grade, ref: options.compare },
9897
+ delta
9898
+ },
9899
+ null,
9900
+ 2
9901
+ )
9902
+ );
9621
9903
  return;
9622
9904
  }
9623
9905
  if (options.quiet) {
@@ -9629,9 +9911,13 @@ async function scoreCommand(options) {
9629
9911
  const separator2 = chalk18.gray(" " + "\u2500".repeat(53));
9630
9912
  console.log(separator2);
9631
9913
  if (delta > 0) {
9632
- console.log(chalk18.green(` +${delta}`) + chalk18.gray(` from ${options.compare} (${baseResult.score}/100)`));
9914
+ console.log(
9915
+ chalk18.green(` +${delta}`) + chalk18.gray(` from ${options.compare} (${baseResult.score}/100)`)
9916
+ );
9633
9917
  } else if (delta < 0) {
9634
- console.log(chalk18.red(` ${delta}`) + chalk18.gray(` from ${options.compare} (${baseResult.score}/100)`));
9918
+ console.log(
9919
+ chalk18.red(` ${delta}`) + chalk18.gray(` from ${options.compare} (${baseResult.score}/100)`)
9920
+ );
9635
9921
  } else {
9636
9922
  console.log(chalk18.gray(` No change from ${options.compare} (${baseResult.score}/100)`));
9637
9923
  }
@@ -9651,18 +9937,24 @@ async function scoreCommand(options) {
9651
9937
  console.log(separator);
9652
9938
  const bin = resolveCaliber();
9653
9939
  if (result.score < 40) {
9654
- console.log(chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate a complete, optimized config."));
9940
+ console.log(
9941
+ chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate a complete, optimized config.")
9942
+ );
9655
9943
  } else if (result.score < 70) {
9656
- console.log(chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve your config."));
9944
+ console.log(
9945
+ chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve your config.")
9946
+ );
9657
9947
  } else {
9658
- console.log(chalk18.green(" Looking good!") + chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch."));
9948
+ console.log(
9949
+ chalk18.green(" Looking good!") + chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch.")
9950
+ );
9659
9951
  }
9660
9952
  console.log("");
9661
9953
  }
9662
9954
 
9663
9955
  // src/commands/refresh.ts
9664
9956
  import fs38 from "fs";
9665
- import path30 from "path";
9957
+ import path31 from "path";
9666
9958
  import chalk19 from "chalk";
9667
9959
  import ora6 from "ora";
9668
9960
 
@@ -9741,7 +10033,7 @@ function collectDiff(lastSha) {
9741
10033
 
9742
10034
  // src/writers/refresh.ts
9743
10035
  import fs35 from "fs";
9744
- import path27 from "path";
10036
+ import path28 from "path";
9745
10037
  function writeRefreshDocs(docs) {
9746
10038
  const written = [];
9747
10039
  if (docs.claudeMd) {
@@ -9757,31 +10049,31 @@ function writeRefreshDocs(docs) {
9757
10049
  written.push(".cursorrules");
9758
10050
  }
9759
10051
  if (docs.cursorRules) {
9760
- const rulesDir = path27.join(".cursor", "rules");
10052
+ const rulesDir = path28.join(".cursor", "rules");
9761
10053
  if (!fs35.existsSync(rulesDir)) fs35.mkdirSync(rulesDir, { recursive: true });
9762
10054
  for (const rule of docs.cursorRules) {
9763
- fs35.writeFileSync(path27.join(rulesDir, rule.filename), rule.content);
10055
+ fs35.writeFileSync(path28.join(rulesDir, rule.filename), rule.content);
9764
10056
  written.push(`.cursor/rules/${rule.filename}`);
9765
10057
  }
9766
10058
  }
9767
10059
  if (docs.claudeSkills) {
9768
- const skillsDir = path27.join(".claude", "skills");
10060
+ const skillsDir = path28.join(".claude", "skills");
9769
10061
  if (!fs35.existsSync(skillsDir)) fs35.mkdirSync(skillsDir, { recursive: true });
9770
10062
  for (const skill of docs.claudeSkills) {
9771
- fs35.writeFileSync(path27.join(skillsDir, skill.filename), skill.content);
10063
+ fs35.writeFileSync(path28.join(skillsDir, skill.filename), skill.content);
9772
10064
  written.push(`.claude/skills/${skill.filename}`);
9773
10065
  }
9774
10066
  }
9775
10067
  if (docs.copilotInstructions) {
9776
10068
  fs35.mkdirSync(".github", { recursive: true });
9777
- fs35.writeFileSync(path27.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(docs.copilotInstructions)));
10069
+ fs35.writeFileSync(path28.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(docs.copilotInstructions)));
9778
10070
  written.push(".github/copilot-instructions.md");
9779
10071
  }
9780
10072
  if (docs.copilotInstructionFiles) {
9781
- const instructionsDir = path27.join(".github", "instructions");
10073
+ const instructionsDir = path28.join(".github", "instructions");
9782
10074
  fs35.mkdirSync(instructionsDir, { recursive: true });
9783
10075
  for (const file of docs.copilotInstructionFiles) {
9784
- fs35.writeFileSync(path27.join(instructionsDir, file.filename), file.content);
10076
+ fs35.writeFileSync(path28.join(instructionsDir, file.filename), file.content);
9785
10077
  written.push(`.github/instructions/${file.filename}`);
9786
10078
  }
9787
10079
  }
@@ -9868,7 +10160,7 @@ Changed files: ${diff.changedFiles.join(", ")}`);
9868
10160
 
9869
10161
  // src/learner/writer.ts
9870
10162
  import fs36 from "fs";
9871
- import path28 from "path";
10163
+ import path29 from "path";
9872
10164
 
9873
10165
  // src/learner/utils.ts
9874
10166
  var TYPE_PREFIX_RE = /^\*\*\[[^\]]+\]\*\*\s*/;
@@ -9993,9 +10285,9 @@ function writeLearnedSection(content) {
9993
10285
  return writeLearnedSectionTo(LEARNINGS_FILE, LEARNINGS_HEADER, readLearnedSection(), content);
9994
10286
  }
9995
10287
  function writeLearnedSkill(skill) {
9996
- const skillDir = path28.join(".claude", "skills", skill.name);
10288
+ const skillDir = path29.join(".claude", "skills", skill.name);
9997
10289
  if (!fs36.existsSync(skillDir)) fs36.mkdirSync(skillDir, { recursive: true });
9998
- const skillPath = path28.join(skillDir, "SKILL.md");
10290
+ const skillPath = path29.join(skillDir, "SKILL.md");
9999
10291
  if (!skill.isNew && fs36.existsSync(skillPath)) {
10000
10292
  const existing = fs36.readFileSync(skillPath, "utf-8");
10001
10293
  fs36.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
@@ -10072,8 +10364,8 @@ function discoverGitRepos(parentDir) {
10072
10364
  const entries = fs38.readdirSync(parentDir, { withFileTypes: true });
10073
10365
  for (const entry of entries) {
10074
10366
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
10075
- const childPath = path30.join(parentDir, entry.name);
10076
- if (fs38.existsSync(path30.join(childPath, ".git"))) {
10367
+ const childPath = path31.join(parentDir, entry.name);
10368
+ if (fs38.existsSync(path31.join(childPath, ".git"))) {
10077
10369
  repos.push(childPath);
10078
10370
  }
10079
10371
  }
@@ -10159,7 +10451,7 @@ async function refreshSingleRepo(repoDir, options) {
10159
10451
  const filesToWrite = response.docsUpdated || [];
10160
10452
  const preRefreshContents = /* @__PURE__ */ new Map();
10161
10453
  for (const filePath of filesToWrite) {
10162
- const fullPath = path30.resolve(repoDir, filePath);
10454
+ const fullPath = path31.resolve(repoDir, filePath);
10163
10455
  try {
10164
10456
  preRefreshContents.set(filePath, fs38.readFileSync(fullPath, "utf-8"));
10165
10457
  } catch {
@@ -10171,7 +10463,7 @@ async function refreshSingleRepo(repoDir, options) {
10171
10463
  const postScore = computeLocalScore(repoDir, targetAgent);
10172
10464
  if (postScore.score < preScore.score) {
10173
10465
  for (const [filePath, content] of preRefreshContents) {
10174
- const fullPath = path30.resolve(repoDir, filePath);
10466
+ const fullPath = path31.resolve(repoDir, filePath);
10175
10467
  if (content === null) {
10176
10468
  try {
10177
10469
  fs38.unlinkSync(fullPath);
@@ -10233,7 +10525,7 @@ async function refreshCommand(options) {
10233
10525
  `));
10234
10526
  const originalDir = process.cwd();
10235
10527
  for (const repo of repos) {
10236
- const repoName = path30.basename(repo);
10528
+ const repoName = path31.basename(repo);
10237
10529
  try {
10238
10530
  process.chdir(repo);
10239
10531
  await refreshSingleRepo(repo, { ...options, label: repoName });
@@ -10259,9 +10551,9 @@ import fs40 from "fs";
10259
10551
  // src/lib/hooks.ts
10260
10552
  init_resolve_caliber();
10261
10553
  import fs39 from "fs";
10262
- import path31 from "path";
10554
+ import path32 from "path";
10263
10555
  import { execSync as execSync15 } from "child_process";
10264
- var SETTINGS_PATH2 = path31.join(".claude", "settings.json");
10556
+ var SETTINGS_PATH2 = path32.join(".claude", "settings.json");
10265
10557
  var REFRESH_TAIL = "refresh --quiet";
10266
10558
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
10267
10559
  function getHookCommand() {
@@ -10276,7 +10568,7 @@ function readSettings2() {
10276
10568
  }
10277
10569
  }
10278
10570
  function writeSettings2(settings) {
10279
- const dir = path31.dirname(SETTINGS_PATH2);
10571
+ const dir = path32.dirname(SETTINGS_PATH2);
10280
10572
  if (!fs39.existsSync(dir)) fs39.mkdirSync(dir, { recursive: true });
10281
10573
  fs39.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
10282
10574
  }
@@ -10344,14 +10636,14 @@ ${PRECOMMIT_END}`;
10344
10636
  function getGitHooksDir() {
10345
10637
  try {
10346
10638
  const gitDir = execSync15("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
10347
- return path31.join(gitDir, "hooks");
10639
+ return path32.join(gitDir, "hooks");
10348
10640
  } catch {
10349
10641
  return null;
10350
10642
  }
10351
10643
  }
10352
10644
  function getPreCommitPath() {
10353
10645
  const hooksDir = getGitHooksDir();
10354
- return hooksDir ? path31.join(hooksDir, "pre-commit") : null;
10646
+ return hooksDir ? path32.join(hooksDir, "pre-commit") : null;
10355
10647
  }
10356
10648
  function isPreCommitHookInstalled() {
10357
10649
  const hookPath = getPreCommitPath();
@@ -10365,7 +10657,7 @@ function installPreCommitHook() {
10365
10657
  }
10366
10658
  const hookPath = getPreCommitPath();
10367
10659
  if (!hookPath) return { installed: false, alreadyInstalled: false };
10368
- const hooksDir = path31.dirname(hookPath);
10660
+ const hooksDir = path32.dirname(hookPath);
10369
10661
  if (!fs39.existsSync(hooksDir)) fs39.mkdirSync(hooksDir, { recursive: true });
10370
10662
  let content = "";
10371
10663
  if (fs39.existsSync(hookPath)) {
@@ -10615,7 +10907,7 @@ async function configCommand() {
10615
10907
 
10616
10908
  // src/commands/learn.ts
10617
10909
  import fs44 from "fs";
10618
- import path35 from "path";
10910
+ import path36 from "path";
10619
10911
  import chalk23 from "chalk";
10620
10912
 
10621
10913
  // src/learner/stdin.ts
@@ -10647,7 +10939,7 @@ function readStdin() {
10647
10939
 
10648
10940
  // src/learner/storage.ts
10649
10941
  import fs41 from "fs";
10650
- import path32 from "path";
10942
+ import path33 from "path";
10651
10943
  var MAX_RESPONSE_LENGTH = 2e3;
10652
10944
  var DEFAULT_STATE = {
10653
10945
  sessionId: null,
@@ -10661,10 +10953,10 @@ function ensureLearningDir() {
10661
10953
  }
10662
10954
  }
10663
10955
  function sessionFilePath() {
10664
- return path32.join(getLearningDir(), LEARNING_SESSION_FILE);
10956
+ return path33.join(getLearningDir(), LEARNING_SESSION_FILE);
10665
10957
  }
10666
10958
  function stateFilePath() {
10667
- return path32.join(getLearningDir(), LEARNING_STATE_FILE);
10959
+ return path33.join(getLearningDir(), LEARNING_STATE_FILE);
10668
10960
  }
10669
10961
  function truncateResponse(response) {
10670
10962
  const str = JSON.stringify(response);
@@ -10736,7 +11028,7 @@ function resetState() {
10736
11028
  var LOCK_FILE2 = "finalize.lock";
10737
11029
  var LOCK_STALE_MS = 5 * 60 * 1e3;
10738
11030
  function lockFilePath() {
10739
- return path32.join(getLearningDir(), LOCK_FILE2);
11031
+ return path33.join(getLearningDir(), LOCK_FILE2);
10740
11032
  }
10741
11033
  function acquireFinalizeLock() {
10742
11034
  ensureLearningDir();
@@ -10782,10 +11074,10 @@ function releaseFinalizeLock() {
10782
11074
 
10783
11075
  // src/lib/notifications.ts
10784
11076
  import fs42 from "fs";
10785
- import path33 from "path";
11077
+ import path34 from "path";
10786
11078
  import chalk22 from "chalk";
10787
11079
  function notificationFilePath() {
10788
- return path33.join(getLearningDir(), "last-finalize-summary.json");
11080
+ return path34.join(getLearningDir(), "last-finalize-summary.json");
10789
11081
  }
10790
11082
  function writeFinalizeSummary(summary) {
10791
11083
  try {
@@ -10967,7 +11259,7 @@ init_config();
10967
11259
 
10968
11260
  // src/learner/roi.ts
10969
11261
  import fs43 from "fs";
10970
- import path34 from "path";
11262
+ import path35 from "path";
10971
11263
  var DEFAULT_TOTALS = {
10972
11264
  totalWasteTokens: 0,
10973
11265
  totalWasteSeconds: 0,
@@ -10981,7 +11273,7 @@ var DEFAULT_TOTALS = {
10981
11273
  lastSessionTimestamp: ""
10982
11274
  };
10983
11275
  function roiFilePath() {
10984
- return path34.join(getLearningDir(), LEARNING_ROI_FILE);
11276
+ return path35.join(getLearningDir(), LEARNING_ROI_FILE);
10985
11277
  }
10986
11278
  function readROIStats() {
10987
11279
  const filePath = roiFilePath();
@@ -11171,7 +11463,9 @@ Return a JSON object: {"matchedIndices": [0, 2]} or {"matchedIndices": []} if no
11171
11463
  const json = extractJson(raw);
11172
11464
  if (json) {
11173
11465
  const parsed = JSON.parse(json);
11174
- const indices = (parsed.matchedIndices || []).filter((i) => typeof i === "number" && i >= 0 && i < learnings.length);
11466
+ const indices = (parsed.matchedIndices || []).filter(
11467
+ (i) => typeof i === "number" && i >= 0 && i < learnings.length
11468
+ );
11175
11469
  return { matchedIndices: indices, unmatchedFailures: failureEvents.length - indices.length };
11176
11470
  }
11177
11471
  } catch {
@@ -11209,7 +11503,7 @@ var AUTO_SETTLE_MS = 200;
11209
11503
  var INCREMENTAL_INTERVAL = 50;
11210
11504
  function writeFinalizeError(message) {
11211
11505
  try {
11212
- const errorPath = path35.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
11506
+ const errorPath = path36.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
11213
11507
  if (!fs44.existsSync(getLearningDir())) fs44.mkdirSync(getLearningDir(), { recursive: true });
11214
11508
  fs44.writeFileSync(errorPath, JSON.stringify({
11215
11509
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -11221,7 +11515,7 @@ function writeFinalizeError(message) {
11221
11515
  }
11222
11516
  function readFinalizeError() {
11223
11517
  try {
11224
- const errorPath = path35.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
11518
+ const errorPath = path36.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
11225
11519
  if (!fs44.existsSync(errorPath)) return null;
11226
11520
  return JSON.parse(fs44.readFileSync(errorPath, "utf-8"));
11227
11521
  } catch {
@@ -11270,7 +11564,7 @@ async function learnObserveCommand(options) {
11270
11564
  const { resolveCaliber: resolveCaliber2 } = await Promise.resolve().then(() => (init_resolve_caliber(), resolve_caliber_exports));
11271
11565
  const bin = resolveCaliber2();
11272
11566
  const { spawn: spawn4 } = await import("child_process");
11273
- const logPath = path35.join(getLearningDir(), LEARNING_FINALIZE_LOG);
11567
+ const logPath = path36.join(getLearningDir(), LEARNING_FINALIZE_LOG);
11274
11568
  if (!fs44.existsSync(getLearningDir())) fs44.mkdirSync(getLearningDir(), { recursive: true });
11275
11569
  const logFd = fs44.openSync(logPath, "a");
11276
11570
  spawn4(bin, ["learn", "finalize", "--auto", "--incremental"], {
@@ -11560,7 +11854,7 @@ async function learnStatusCommand() {
11560
11854
  if (lastError) {
11561
11855
  console.log(`Last error: ${chalk23.red(lastError.error)}`);
11562
11856
  console.log(chalk23.dim(` at ${lastError.timestamp}`));
11563
- const logPath = path35.join(getLearningDir(), LEARNING_FINALIZE_LOG);
11857
+ const logPath = path36.join(getLearningDir(), LEARNING_FINALIZE_LOG);
11564
11858
  if (fs44.existsSync(logPath)) {
11565
11859
  console.log(chalk23.dim(` Full log: ${logPath}`));
11566
11860
  }
@@ -11842,7 +12136,7 @@ async function insightsCommand(options) {
11842
12136
 
11843
12137
  // src/commands/sources.ts
11844
12138
  import fs45 from "fs";
11845
- import path36 from "path";
12139
+ import path37 from "path";
11846
12140
  import chalk25 from "chalk";
11847
12141
  init_resolve_caliber();
11848
12142
  async function sourcesListCommand() {
@@ -11859,9 +12153,9 @@ async function sourcesListCommand() {
11859
12153
  if (configSources.length > 0) {
11860
12154
  for (const source of configSources) {
11861
12155
  const sourcePath = source.path || source.url || "";
11862
- const exists = source.path ? fs45.existsSync(path36.resolve(dir, source.path)) : false;
12156
+ const exists = source.path ? fs45.existsSync(path37.resolve(dir, source.path)) : false;
11863
12157
  const status = exists ? chalk25.green("reachable") : chalk25.red("not found");
11864
- const hasSummary = source.path && fs45.existsSync(path36.join(path36.resolve(dir, source.path), ".caliber", "summary.json"));
12158
+ const hasSummary = source.path && fs45.existsSync(path37.join(path37.resolve(dir, source.path), ".caliber", "summary.json"));
11865
12159
  console.log(` ${chalk25.bold(source.role || source.type)} ${chalk25.dim(sourcePath)}`);
11866
12160
  console.log(` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`);
11867
12161
  if (source.description) console.log(` ${chalk25.dim(source.description)}`);
@@ -11871,7 +12165,7 @@ async function sourcesListCommand() {
11871
12165
  if (workspaces.length > 0) {
11872
12166
  console.log(chalk25.dim(" Auto-detected workspaces:"));
11873
12167
  for (const ws of workspaces) {
11874
- const exists = fs45.existsSync(path36.resolve(dir, ws));
12168
+ const exists = fs45.existsSync(path37.resolve(dir, ws));
11875
12169
  console.log(` ${exists ? chalk25.green("\u25CF") : chalk25.red("\u25CF")} ${ws}`);
11876
12170
  }
11877
12171
  console.log("");
@@ -11879,7 +12173,7 @@ async function sourcesListCommand() {
11879
12173
  }
11880
12174
  async function sourcesAddCommand(sourcePath) {
11881
12175
  const dir = process.cwd();
11882
- const absPath = path36.resolve(dir, sourcePath);
12176
+ const absPath = path37.resolve(dir, sourcePath);
11883
12177
  if (!fs45.existsSync(absPath)) {
11884
12178
  console.log(chalk25.red(`
11885
12179
  Path not found: ${sourcePath}
@@ -11895,7 +12189,7 @@ async function sourcesAddCommand(sourcePath) {
11895
12189
  }
11896
12190
  const existing = loadSourcesConfig(dir);
11897
12191
  const alreadyConfigured = existing.some(
11898
- (s) => s.path && path36.resolve(dir, s.path) === absPath
12192
+ (s) => s.path && path37.resolve(dir, s.path) === absPath
11899
12193
  );
11900
12194
  if (alreadyConfigured) {
11901
12195
  console.log(chalk25.yellow(`
@@ -11944,7 +12238,7 @@ async function sourcesRemoveCommand(name) {
11944
12238
 
11945
12239
  // src/commands/publish.ts
11946
12240
  import fs46 from "fs";
11947
- import path37 from "path";
12241
+ import path38 from "path";
11948
12242
  import chalk26 from "chalk";
11949
12243
  import ora7 from "ora";
11950
12244
  init_config();
@@ -11959,10 +12253,10 @@ async function publishCommand() {
11959
12253
  const spinner = ora7("Generating project summary...").start();
11960
12254
  try {
11961
12255
  const fingerprint = await collectFingerprint(dir);
11962
- const claudeMd = readFileOrNull(path37.join(dir, "CLAUDE.md"));
12256
+ const claudeMd = readFileOrNull(path38.join(dir, "CLAUDE.md"));
11963
12257
  const topLevelDirs = fingerprint.fileTree.filter((f) => f.endsWith("/") && !f.includes("/")).map((f) => f.replace(/\/$/, ""));
11964
12258
  const summary = {
11965
- name: fingerprint.packageName || path37.basename(dir),
12259
+ name: fingerprint.packageName || path38.basename(dir),
11966
12260
  version: "1.0.0",
11967
12261
  description: fingerprint.description || "",
11968
12262
  languages: fingerprint.languages,
@@ -11974,7 +12268,7 @@ async function publishCommand() {
11974
12268
  summary.conventions = claudeMd.slice(0, 2e3);
11975
12269
  }
11976
12270
  try {
11977
- const pkgContent = readFileOrNull(path37.join(dir, "package.json"));
12271
+ const pkgContent = readFileOrNull(path38.join(dir, "package.json"));
11978
12272
  if (pkgContent) {
11979
12273
  const pkg3 = JSON.parse(pkgContent);
11980
12274
  if (pkg3.scripts) {
@@ -11987,14 +12281,14 @@ async function publishCommand() {
11987
12281
  }
11988
12282
  } catch {
11989
12283
  }
11990
- const outputDir = path37.join(dir, ".caliber");
12284
+ const outputDir = path38.join(dir, ".caliber");
11991
12285
  if (!fs46.existsSync(outputDir)) {
11992
12286
  fs46.mkdirSync(outputDir, { recursive: true });
11993
12287
  }
11994
- const outputPath = path37.join(outputDir, "summary.json");
12288
+ const outputPath = path38.join(outputDir, "summary.json");
11995
12289
  fs46.writeFileSync(outputPath, JSON.stringify(summary, null, 2) + "\n", "utf-8");
11996
12290
  spinner.succeed("Project summary published");
11997
- console.log(` ${chalk26.green("\u2713")} ${path37.relative(dir, outputPath)}`);
12291
+ console.log(` ${chalk26.green("\u2713")} ${path38.relative(dir, outputPath)}`);
11998
12292
  console.log(chalk26.dim("\n Other projects can now reference this repo as a source."));
11999
12293
  console.log(chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n"));
12000
12294
  } catch (err) {
@@ -12006,9 +12300,9 @@ async function publishCommand() {
12006
12300
  }
12007
12301
 
12008
12302
  // src/cli.ts
12009
- var __dirname = path38.dirname(fileURLToPath(import.meta.url));
12303
+ var __dirname = path39.dirname(fileURLToPath(import.meta.url));
12010
12304
  var pkg = JSON.parse(
12011
- fs47.readFileSync(path38.resolve(__dirname, "..", "package.json"), "utf-8")
12305
+ fs47.readFileSync(path39.resolve(__dirname, "..", "package.json"), "utf-8")
12012
12306
  );
12013
12307
  var program = new Command();
12014
12308
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -12096,16 +12390,14 @@ learn.command("add <content>").description("Add a learning directly (used by age
12096
12390
 
12097
12391
  // src/utils/version-check.ts
12098
12392
  import fs48 from "fs";
12099
- import path39 from "path";
12393
+ import path40 from "path";
12100
12394
  import { fileURLToPath as fileURLToPath2 } from "url";
12101
12395
  import { execSync as execSync16, execFileSync as execFileSync3 } from "child_process";
12102
12396
  import chalk27 from "chalk";
12103
12397
  import ora8 from "ora";
12104
12398
  import confirm2 from "@inquirer/confirm";
12105
- var __dirname_vc = path39.dirname(fileURLToPath2(import.meta.url));
12106
- var pkg2 = JSON.parse(
12107
- fs48.readFileSync(path39.resolve(__dirname_vc, "..", "package.json"), "utf-8")
12108
- );
12399
+ var __dirname_vc = path40.dirname(fileURLToPath2(import.meta.url));
12400
+ var pkg2 = JSON.parse(fs48.readFileSync(path40.resolve(__dirname_vc, "..", "package.json"), "utf-8"));
12109
12401
  function getChannel(version) {
12110
12402
  const match = version.match(/-(dev|next)\./);
12111
12403
  return match ? match[1] : "latest";
@@ -12128,8 +12420,11 @@ function isNewer(registry, current) {
12128
12420
  }
12129
12421
  function getInstalledVersion() {
12130
12422
  try {
12131
- const globalRoot = execSync16("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
12132
- const pkgPath = path39.join(globalRoot, "@rely-ai", "caliber", "package.json");
12423
+ const globalRoot = execSync16("npm root -g", {
12424
+ encoding: "utf-8",
12425
+ stdio: ["pipe", "pipe", "pipe"]
12426
+ }).trim();
12427
+ const pkgPath = path40.join(globalRoot, "@rely-ai", "caliber", "package.json");
12133
12428
  return JSON.parse(fs48.readFileSync(pkgPath, "utf-8")).version;
12134
12429
  } catch {
12135
12430
  return null;
@@ -12164,17 +12459,18 @@ Run ${chalk27.bold(`npm install -g @rely-ai/caliber${installTag}`)} to upgrade.
12164
12459
  );
12165
12460
  return;
12166
12461
  }
12167
- console.log(
12168
- chalk27.yellow(`
12169
- Update available: ${current} -> ${latest}`)
12170
- );
12171
- const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
12462
+ console.log(chalk27.yellow(`
12463
+ Update available: ${current} -> ${latest}`));
12464
+ const shouldUpdate = await confirm2({
12465
+ message: "Would you like to update now? (Y/n)",
12466
+ default: true
12467
+ });
12172
12468
  if (!shouldUpdate) {
12173
12469
  console.log();
12174
12470
  return;
12175
12471
  }
12176
12472
  const tag = channel === "latest" ? latest : channel;
12177
- if (!/^[\w.\-]+$/.test(tag)) return;
12473
+ if (!/^[\w.-]+$/.test(tag)) return;
12178
12474
  const spinner = ora8("Updating caliber...").start();
12179
12475
  try {
12180
12476
  execFileSync3("npm", ["install", "-g", `@rely-ai/caliber@${tag}`], {
@@ -12185,8 +12481,10 @@ Update available: ${current} -> ${latest}`)
12185
12481
  const installed = getInstalledVersion();
12186
12482
  if (installed !== latest) {
12187
12483
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
12188
- console.log(chalk27.yellow(`Run ${chalk27.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
12189
- `));
12484
+ console.log(
12485
+ chalk27.yellow(`Run ${chalk27.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
12486
+ `)
12487
+ );
12190
12488
  return;
12191
12489
  }
12192
12490
  spinner.succeed(chalk27.green(`Updated to ${latest}`));