@rely-ai/caliber 1.6.1 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.js +945 -508
  2. package/package.json +3 -2
package/dist/bin.js CHANGED
@@ -20,6 +20,120 @@ var __copyProps = (to, from, except, desc) => {
20
20
  };
21
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
22
 
23
+ // src/llm/config.ts
24
+ var config_exports = {};
25
+ __export(config_exports, {
26
+ DEFAULT_FAST_MODELS: () => DEFAULT_FAST_MODELS,
27
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
28
+ getConfigFilePath: () => getConfigFilePath,
29
+ getFastModel: () => getFastModel,
30
+ loadConfig: () => loadConfig,
31
+ readConfigFile: () => readConfigFile,
32
+ resolveFromEnv: () => resolveFromEnv,
33
+ writeConfigFile: () => writeConfigFile
34
+ });
35
+ import fs4 from "fs";
36
+ import path4 from "path";
37
+ import os from "os";
38
+ function loadConfig() {
39
+ const envConfig = resolveFromEnv();
40
+ if (envConfig) return envConfig;
41
+ return readConfigFile();
42
+ }
43
+ function resolveFromEnv() {
44
+ if (process.env.ANTHROPIC_API_KEY) {
45
+ return {
46
+ provider: "anthropic",
47
+ apiKey: process.env.ANTHROPIC_API_KEY,
48
+ model: process.env.CALIBER_MODEL || DEFAULT_MODELS.anthropic
49
+ };
50
+ }
51
+ if (process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID) {
52
+ return {
53
+ provider: "vertex",
54
+ model: process.env.CALIBER_MODEL || DEFAULT_MODELS.vertex,
55
+ vertexProjectId: process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID,
56
+ vertexRegion: process.env.VERTEX_REGION || process.env.GCP_REGION || "us-east5",
57
+ vertexCredentials: process.env.VERTEX_SA_CREDENTIALS || process.env.GOOGLE_APPLICATION_CREDENTIALS
58
+ };
59
+ }
60
+ if (process.env.OPENAI_API_KEY) {
61
+ return {
62
+ provider: "openai",
63
+ apiKey: process.env.OPENAI_API_KEY,
64
+ model: process.env.CALIBER_MODEL || DEFAULT_MODELS.openai,
65
+ baseUrl: process.env.OPENAI_BASE_URL
66
+ };
67
+ }
68
+ if (process.env.CALIBER_USE_CURSOR_SEAT === "1" || process.env.CALIBER_USE_CURSOR_SEAT === "true") {
69
+ return {
70
+ provider: "cursor",
71
+ model: DEFAULT_MODELS.cursor
72
+ };
73
+ }
74
+ if (process.env.CALIBER_USE_CLAUDE_CLI === "1" || process.env.CALIBER_USE_CLAUDE_CLI === "true") {
75
+ return {
76
+ provider: "claude-cli",
77
+ model: DEFAULT_MODELS["claude-cli"]
78
+ };
79
+ }
80
+ return null;
81
+ }
82
+ function readConfigFile() {
83
+ try {
84
+ if (!fs4.existsSync(CONFIG_FILE)) return null;
85
+ const raw = fs4.readFileSync(CONFIG_FILE, "utf-8");
86
+ const parsed = JSON.parse(raw);
87
+ if (!parsed.provider || !["anthropic", "vertex", "openai", "cursor", "claude-cli"].includes(parsed.provider)) {
88
+ return null;
89
+ }
90
+ return parsed;
91
+ } catch {
92
+ return null;
93
+ }
94
+ }
95
+ function writeConfigFile(config) {
96
+ if (!fs4.existsSync(CONFIG_DIR)) {
97
+ fs4.mkdirSync(CONFIG_DIR, { recursive: true });
98
+ }
99
+ const sanitized = { ...config };
100
+ if (sanitized.apiKey) {
101
+ sanitized.apiKey = sanitized.apiKey.trim();
102
+ }
103
+ fs4.writeFileSync(CONFIG_FILE, JSON.stringify(sanitized, null, 2) + "\n", { mode: 384 });
104
+ }
105
+ function getConfigFilePath() {
106
+ return CONFIG_FILE;
107
+ }
108
+ function getFastModel() {
109
+ if (process.env.CALIBER_FAST_MODEL) return process.env.CALIBER_FAST_MODEL;
110
+ if (process.env.ANTHROPIC_SMALL_FAST_MODEL) return process.env.ANTHROPIC_SMALL_FAST_MODEL;
111
+ const config = loadConfig();
112
+ if (config?.fastModel) return config.fastModel;
113
+ if (config?.provider) return DEFAULT_FAST_MODELS[config.provider];
114
+ return void 0;
115
+ }
116
+ var CONFIG_DIR, CONFIG_FILE, DEFAULT_MODELS, DEFAULT_FAST_MODELS;
117
+ var init_config = __esm({
118
+ "src/llm/config.ts"() {
119
+ "use strict";
120
+ CONFIG_DIR = path4.join(os.homedir(), ".caliber");
121
+ CONFIG_FILE = path4.join(CONFIG_DIR, "config.json");
122
+ DEFAULT_MODELS = {
123
+ anthropic: "claude-sonnet-4-6",
124
+ vertex: "claude-sonnet-4-6",
125
+ openai: "gpt-4.1",
126
+ cursor: "default",
127
+ "claude-cli": "default"
128
+ };
129
+ DEFAULT_FAST_MODELS = {
130
+ anthropic: "claude-haiku-4-5-20251001",
131
+ vertex: "claude-haiku-4-5-20251001",
132
+ openai: "gpt-4.1-mini"
133
+ };
134
+ }
135
+ });
136
+
23
137
  // src/constants.ts
24
138
  var constants_exports = {};
25
139
  __export(constants_exports, {
@@ -51,17 +165,17 @@ var init_constants = __esm({
51
165
 
52
166
  // src/cli.ts
53
167
  import { Command } from "commander";
54
- import fs27 from "fs";
55
- import path21 from "path";
168
+ import fs28 from "fs";
169
+ import path22 from "path";
56
170
  import { fileURLToPath } from "url";
57
171
 
58
172
  // src/commands/onboard.ts
59
- import chalk6 from "chalk";
173
+ import chalk8 from "chalk";
60
174
  import ora2 from "ora";
61
175
  import readline3 from "readline";
62
- import select4 from "@inquirer/select";
176
+ import select5 from "@inquirer/select";
63
177
  import checkbox from "@inquirer/checkbox";
64
- import fs21 from "fs";
178
+ import fs22 from "fs";
65
179
 
66
180
  // src/fingerprint/index.ts
67
181
  import fs6 from "fs";
@@ -507,102 +621,8 @@ function estimateSummarySize(summary) {
507
621
  return summary.path.length + summary.imports.reduce((s, i) => s + i.length, 0) + summary.exports.reduce((s, e) => s + e.length, 0) + summary.functions.reduce((s, f) => s + f.length, 0) + summary.classes.reduce((s, c) => s + c.length, 0) + summary.types.reduce((s, t) => s + t.length, 0) + summary.routes.reduce((s, r) => s + r.length, 0);
508
622
  }
509
623
 
510
- // src/llm/config.ts
511
- import fs4 from "fs";
512
- import path4 from "path";
513
- import os from "os";
514
- var CONFIG_DIR = path4.join(os.homedir(), ".caliber");
515
- var CONFIG_FILE = path4.join(CONFIG_DIR, "config.json");
516
- var DEFAULT_MODELS = {
517
- anthropic: "claude-sonnet-4-6",
518
- vertex: "claude-sonnet-4-6",
519
- openai: "gpt-4.1",
520
- cursor: "default",
521
- "claude-cli": "default"
522
- };
523
- var DEFAULT_FAST_MODELS = {
524
- anthropic: "claude-haiku-4-5-20251001",
525
- vertex: "claude-haiku-4-5-20251001",
526
- openai: "gpt-4.1-mini"
527
- };
528
- function loadConfig() {
529
- const envConfig = resolveFromEnv();
530
- if (envConfig) return envConfig;
531
- return readConfigFile();
532
- }
533
- function resolveFromEnv() {
534
- if (process.env.ANTHROPIC_API_KEY) {
535
- return {
536
- provider: "anthropic",
537
- apiKey: process.env.ANTHROPIC_API_KEY,
538
- model: process.env.CALIBER_MODEL || DEFAULT_MODELS.anthropic
539
- };
540
- }
541
- if (process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID) {
542
- return {
543
- provider: "vertex",
544
- model: process.env.CALIBER_MODEL || DEFAULT_MODELS.vertex,
545
- vertexProjectId: process.env.VERTEX_PROJECT_ID || process.env.GCP_PROJECT_ID,
546
- vertexRegion: process.env.VERTEX_REGION || process.env.GCP_REGION || "us-east5",
547
- vertexCredentials: process.env.VERTEX_SA_CREDENTIALS || process.env.GOOGLE_APPLICATION_CREDENTIALS
548
- };
549
- }
550
- if (process.env.OPENAI_API_KEY) {
551
- return {
552
- provider: "openai",
553
- apiKey: process.env.OPENAI_API_KEY,
554
- model: process.env.CALIBER_MODEL || DEFAULT_MODELS.openai,
555
- baseUrl: process.env.OPENAI_BASE_URL
556
- };
557
- }
558
- if (process.env.CALIBER_USE_CURSOR_SEAT === "1" || process.env.CALIBER_USE_CURSOR_SEAT === "true") {
559
- return {
560
- provider: "cursor",
561
- model: DEFAULT_MODELS.cursor
562
- };
563
- }
564
- if (process.env.CALIBER_USE_CLAUDE_CLI === "1" || process.env.CALIBER_USE_CLAUDE_CLI === "true") {
565
- return {
566
- provider: "claude-cli",
567
- model: DEFAULT_MODELS["claude-cli"]
568
- };
569
- }
570
- return null;
571
- }
572
- function readConfigFile() {
573
- try {
574
- if (!fs4.existsSync(CONFIG_FILE)) return null;
575
- const raw = fs4.readFileSync(CONFIG_FILE, "utf-8");
576
- const parsed = JSON.parse(raw);
577
- if (!parsed.provider || !["anthropic", "vertex", "openai", "cursor", "claude-cli"].includes(parsed.provider)) {
578
- return null;
579
- }
580
- return parsed;
581
- } catch {
582
- return null;
583
- }
584
- }
585
- function writeConfigFile(config) {
586
- if (!fs4.existsSync(CONFIG_DIR)) {
587
- fs4.mkdirSync(CONFIG_DIR, { recursive: true });
588
- }
589
- const sanitized = { ...config };
590
- if (sanitized.apiKey) {
591
- sanitized.apiKey = sanitized.apiKey.trim();
592
- }
593
- fs4.writeFileSync(CONFIG_FILE, JSON.stringify(sanitized, null, 2) + "\n", { mode: 384 });
594
- }
595
- function getConfigFilePath() {
596
- return CONFIG_FILE;
597
- }
598
- function getFastModel() {
599
- if (process.env.CALIBER_FAST_MODEL) return process.env.CALIBER_FAST_MODEL;
600
- if (process.env.ANTHROPIC_SMALL_FAST_MODEL) return process.env.ANTHROPIC_SMALL_FAST_MODEL;
601
- const config = loadConfig();
602
- if (config?.fastModel) return config.fastModel;
603
- if (config?.provider) return DEFAULT_FAST_MODELS[config.provider];
604
- return void 0;
605
- }
624
+ // src/llm/index.ts
625
+ init_config();
606
626
 
607
627
  // src/llm/anthropic.ts
608
628
  import Anthropic from "@anthropic-ai/sdk";
@@ -623,6 +643,14 @@ var AnthropicProvider = class {
623
643
  const block = response.content[0];
624
644
  return block.type === "text" ? block.text : "";
625
645
  }
646
+ async listModels() {
647
+ const models = [];
648
+ const page = await this.client.models.list({ limit: 100 });
649
+ for (const model of page.data) {
650
+ models.push(model.id);
651
+ }
652
+ return models;
653
+ }
626
654
  async stream(options, callbacks) {
627
655
  const messages = options.messages ? [
628
656
  ...options.messages.map((msg) => ({
@@ -743,6 +771,13 @@ var OpenAICompatProvider = class {
743
771
  });
744
772
  return response.choices[0]?.message?.content || "";
745
773
  }
774
+ async listModels() {
775
+ const models = [];
776
+ for await (const model of this.client.models.list()) {
777
+ models.push(model.id);
778
+ }
779
+ return models;
780
+ }
746
781
  async stream(options, callbacks) {
747
782
  const messages = [
748
783
  { role: "system", content: options.system }
@@ -1108,7 +1143,108 @@ function estimateTokens(text) {
1108
1143
  return Math.ceil(text.length / 4);
1109
1144
  }
1110
1145
 
1146
+ // src/llm/model-recovery.ts
1147
+ init_config();
1148
+ import chalk from "chalk";
1149
+ import select from "@inquirer/select";
1150
+ var KNOWN_MODELS = {
1151
+ anthropic: [
1152
+ "claude-sonnet-4-6",
1153
+ "claude-sonnet-4-5-20250514",
1154
+ "claude-haiku-4-5-20251001",
1155
+ "claude-opus-4-6",
1156
+ "claude-opus-4-1-20250620"
1157
+ ],
1158
+ vertex: [
1159
+ "claude-sonnet-4-6@20250514",
1160
+ "claude-sonnet-4-5-20250514",
1161
+ "claude-haiku-4-5-20251001",
1162
+ "claude-opus-4-6@20250605",
1163
+ "claude-opus-4-1-20250620"
1164
+ ],
1165
+ openai: [
1166
+ "gpt-4.1",
1167
+ "gpt-4.1-mini",
1168
+ "gpt-4o",
1169
+ "gpt-4o-mini",
1170
+ "o3-mini"
1171
+ ],
1172
+ cursor: [],
1173
+ "claude-cli": []
1174
+ };
1175
+ function isModelNotAvailableError(error) {
1176
+ const msg = error.message.toLowerCase();
1177
+ const status = error.status;
1178
+ if (status === 404 && msg.includes("model")) return true;
1179
+ if (msg.includes("model") && (msg.includes("not found") || msg.includes("not_found"))) return true;
1180
+ if (msg.includes("model") && msg.includes("not available")) return true;
1181
+ if (msg.includes("model") && msg.includes("does not exist")) return true;
1182
+ if (msg.includes("publisher model")) return true;
1183
+ return false;
1184
+ }
1185
+ function filterRelevantModels(models, provider) {
1186
+ switch (provider) {
1187
+ case "anthropic":
1188
+ case "vertex":
1189
+ return models.filter((m) => m.startsWith("claude-"));
1190
+ case "openai":
1191
+ return models.filter(
1192
+ (m) => m.startsWith("gpt-4") || m.startsWith("gpt-3.5") || m.startsWith("o1") || m.startsWith("o3")
1193
+ );
1194
+ default:
1195
+ return models;
1196
+ }
1197
+ }
1198
+ async function handleModelNotAvailable(failedModel, provider, config) {
1199
+ if (!process.stdin.isTTY) {
1200
+ console.error(
1201
+ chalk.red(`Model "${failedModel}" is not available. Run \`caliber config\` to select a different model.`)
1202
+ );
1203
+ return null;
1204
+ }
1205
+ console.log(chalk.yellow(`
1206
+ \u26A0 Model "${failedModel}" is not available on your ${config.provider} deployment.`));
1207
+ let models = [];
1208
+ if (provider.listModels) {
1209
+ try {
1210
+ const allModels = await provider.listModels();
1211
+ models = filterRelevantModels(allModels, config.provider);
1212
+ } catch {
1213
+ }
1214
+ }
1215
+ if (models.length === 0) {
1216
+ models = KNOWN_MODELS[config.provider] ?? [];
1217
+ }
1218
+ models = models.filter((m) => m !== failedModel);
1219
+ if (models.length === 0) {
1220
+ console.log(chalk.red(" No alternative models found. Run `caliber config` to configure manually."));
1221
+ return null;
1222
+ }
1223
+ console.log("");
1224
+ let selected;
1225
+ try {
1226
+ selected = await select({
1227
+ message: "Pick an available model",
1228
+ choices: models.map((m) => ({ name: m, value: m }))
1229
+ });
1230
+ } catch {
1231
+ return null;
1232
+ }
1233
+ const isDefaultModel = failedModel === config.model;
1234
+ const updatedConfig = isDefaultModel ? { ...config, model: selected } : { ...config, fastModel: selected };
1235
+ writeConfigFile(updatedConfig);
1236
+ if (isDefaultModel) {
1237
+ process.env.CALIBER_MODEL = selected;
1238
+ } else {
1239
+ process.env.CALIBER_FAST_MODEL = selected;
1240
+ }
1241
+ console.log(chalk.green(`\u2713 Switched to ${selected}
1242
+ `));
1243
+ return selected;
1244
+ }
1245
+
1111
1246
  // src/llm/index.ts
1247
+ init_config();
1112
1248
  var cachedProvider = null;
1113
1249
  var cachedConfig = null;
1114
1250
  function createProvider(config) {
@@ -1151,6 +1287,10 @@ function getProvider() {
1151
1287
  cachedProvider = createProvider(config);
1152
1288
  return cachedProvider;
1153
1289
  }
1290
+ function resetProvider() {
1291
+ cachedProvider = null;
1292
+ cachedConfig = null;
1293
+ }
1154
1294
  var TRANSIENT_ERRORS = ["terminated", "ECONNRESET", "ETIMEDOUT", "socket hang up", "other side closed"];
1155
1295
  var MAX_RETRIES = 3;
1156
1296
  function isTransientError(error) {
@@ -1168,6 +1308,16 @@ async function llmCall(options) {
1168
1308
  return await provider.call(options);
1169
1309
  } catch (err) {
1170
1310
  const error = err instanceof Error ? err : new Error(String(err));
1311
+ if (isModelNotAvailableError(error) && cachedConfig) {
1312
+ const failedModel = options.model || cachedConfig.model;
1313
+ const newModel = await handleModelNotAvailable(failedModel, provider, cachedConfig);
1314
+ if (newModel) {
1315
+ resetProvider();
1316
+ const newProvider = getProvider();
1317
+ return await newProvider.call({ ...options, model: newModel });
1318
+ }
1319
+ throw error;
1320
+ }
1171
1321
  if (isOverloaded(error) && attempt < MAX_RETRIES) {
1172
1322
  await new Promise((r) => setTimeout(r, 2e3));
1173
1323
  continue;
@@ -1185,6 +1335,40 @@ async function llmJsonCall(options) {
1185
1335
  const text = await llmCall(options);
1186
1336
  return parseJsonResponse(text);
1187
1337
  }
1338
+ async function validateModel(options) {
1339
+ const provider = getProvider();
1340
+ const config = cachedConfig;
1341
+ if (!config) return;
1342
+ const modelsToCheck = [config.model];
1343
+ if (options?.fast) {
1344
+ const { getFastModel: getFastModel2 } = await Promise.resolve().then(() => (init_config(), config_exports));
1345
+ const fast = getFastModel2();
1346
+ if (fast && fast !== config.model) modelsToCheck.push(fast);
1347
+ }
1348
+ for (const model of modelsToCheck) {
1349
+ try {
1350
+ await provider.call({
1351
+ system: "Respond with OK",
1352
+ prompt: "ping",
1353
+ model,
1354
+ maxTokens: 1
1355
+ });
1356
+ } catch (err) {
1357
+ const error = err instanceof Error ? err : new Error(String(err));
1358
+ if (isModelNotAvailableError(error)) {
1359
+ const newModel = await handleModelNotAvailable(model, provider, config);
1360
+ if (newModel) {
1361
+ resetProvider();
1362
+ return;
1363
+ }
1364
+ throw error;
1365
+ }
1366
+ }
1367
+ }
1368
+ }
1369
+
1370
+ // src/ai/detect.ts
1371
+ init_config();
1188
1372
 
1189
1373
  // src/ai/prompts.ts
1190
1374
  var GENERATION_SYSTEM_PROMPT = `You are an expert auditor for coding agent configurations (Claude Code, Cursor, and Codex).
@@ -1479,6 +1663,7 @@ async function detectProjectStack(fileTree, fileContents) {
1479
1663
  }
1480
1664
 
1481
1665
  // src/fingerprint/index.ts
1666
+ init_config();
1482
1667
  async function collectFingerprint(dir) {
1483
1668
  const gitRemoteUrl = getGitRemoteUrl();
1484
1669
  const fileTree = getFileTree(dir);
@@ -2176,9 +2361,9 @@ function cleanupStaging() {
2176
2361
  }
2177
2362
 
2178
2363
  // src/utils/review.ts
2179
- import chalk from "chalk";
2364
+ import chalk2 from "chalk";
2180
2365
  import fs14 from "fs";
2181
- import select from "@inquirer/select";
2366
+ import select2 from "@inquirer/select";
2182
2367
  import { createTwoFilesPatch } from "diff";
2183
2368
 
2184
2369
  // src/utils/editor.ts
@@ -2221,7 +2406,7 @@ function openDiffsInEditor(editor, files) {
2221
2406
 
2222
2407
  // src/utils/review.ts
2223
2408
  async function promptWantsReview() {
2224
- return select({
2409
+ return select2({
2225
2410
  message: "Would you like to review the diffs before deciding?",
2226
2411
  choices: [
2227
2412
  { name: "Yes, show me the diffs", value: true },
@@ -2242,7 +2427,7 @@ async function promptReviewMethod() {
2242
2427
  return { name: "Terminal", value: "terminal" };
2243
2428
  }
2244
2429
  });
2245
- return select({ message: "How would you like to review the changes?", choices });
2430
+ return select2({ message: "How would you like to review the changes?", choices });
2246
2431
  }
2247
2432
  async function openReview(method, stagedFiles) {
2248
2433
  if (method === "cursor" || method === "vscode") {
@@ -2250,7 +2435,7 @@ async function openReview(method, stagedFiles) {
2250
2435
  originalPath: f.originalPath,
2251
2436
  proposedPath: f.proposedPath
2252
2437
  })));
2253
- console.log(chalk.dim(" Diffs opened in your editor.\n"));
2438
+ console.log(chalk2.dim(" Diffs opened in your editor.\n"));
2254
2439
  return;
2255
2440
  }
2256
2441
  const fileInfos = stagedFiles.map((file) => {
@@ -2281,8 +2466,8 @@ async function openReview(method, stagedFiles) {
2281
2466
  async function interactiveDiffExplorer(files) {
2282
2467
  if (!process.stdin.isTTY) {
2283
2468
  for (const f of files) {
2284
- const icon = f.isNew ? chalk.green("+") : chalk.yellow("~");
2285
- const stats = f.isNew ? chalk.dim(`${f.lines} lines`) : `${chalk.green(`+${f.added}`)} ${chalk.red(`-${f.removed}`)}`;
2469
+ const icon = f.isNew ? chalk2.green("+") : chalk2.yellow("~");
2470
+ const stats = f.isNew ? chalk2.dim(`${f.lines} lines`) : `${chalk2.green(`+${f.added}`)} ${chalk2.red(`-${f.removed}`)}`;
2286
2471
  console.log(` ${icon} ${f.relativePath} ${stats}`);
2287
2472
  }
2288
2473
  console.log("");
@@ -2298,47 +2483,47 @@ async function interactiveDiffExplorer(files) {
2298
2483
  }
2299
2484
  function renderFileList() {
2300
2485
  const lines = [];
2301
- lines.push(chalk.bold(" Review changes"));
2486
+ lines.push(chalk2.bold(" Review changes"));
2302
2487
  lines.push("");
2303
2488
  for (let i = 0; i < files.length; i++) {
2304
2489
  const f = files[i];
2305
- const ptr = i === cursor ? chalk.cyan(">") : " ";
2306
- const icon = f.isNew ? chalk.green("+") : chalk.yellow("~");
2307
- const stats = f.isNew ? chalk.dim(`${f.lines} lines`) : `${chalk.green(`+${f.added}`)} ${chalk.red(`-${f.removed}`)}`;
2490
+ const ptr = i === cursor ? chalk2.cyan(">") : " ";
2491
+ const icon = f.isNew ? chalk2.green("+") : chalk2.yellow("~");
2492
+ const stats = f.isNew ? chalk2.dim(`${f.lines} lines`) : `${chalk2.green(`+${f.added}`)} ${chalk2.red(`-${f.removed}`)}`;
2308
2493
  lines.push(` ${ptr} ${icon} ${f.relativePath} ${stats}`);
2309
2494
  }
2310
2495
  lines.push("");
2311
- lines.push(chalk.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
2496
+ lines.push(chalk2.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
2312
2497
  return lines.join("\n");
2313
2498
  }
2314
2499
  function renderDiff(index) {
2315
2500
  const f = files[index];
2316
2501
  const lines = [];
2317
- const header = f.isNew ? ` ${chalk.green("+")} ${f.relativePath} ${chalk.dim("(new file)")}` : ` ${chalk.yellow("~")} ${f.relativePath} ${chalk.green(`+${f.added}`)} ${chalk.red(`-${f.removed}`)}`;
2502
+ const header = f.isNew ? ` ${chalk2.green("+")} ${f.relativePath} ${chalk2.dim("(new file)")}` : ` ${chalk2.yellow("~")} ${f.relativePath} ${chalk2.green(`+${f.added}`)} ${chalk2.red(`-${f.removed}`)}`;
2318
2503
  lines.push(header);
2319
- lines.push(chalk.dim(" " + "\u2500".repeat(60)));
2504
+ lines.push(chalk2.dim(" " + "\u2500".repeat(60)));
2320
2505
  const patchLines = f.patch.split("\n");
2321
2506
  const bodyLines = patchLines.slice(4);
2322
2507
  const maxVisible = getTermHeight() - 4;
2323
2508
  const visibleLines = bodyLines.slice(scrollOffset, scrollOffset + maxVisible);
2324
2509
  for (const line of visibleLines) {
2325
2510
  if (line.startsWith("+")) {
2326
- lines.push(chalk.green(" " + line));
2511
+ lines.push(chalk2.green(" " + line));
2327
2512
  } else if (line.startsWith("-")) {
2328
- lines.push(chalk.red(" " + line));
2513
+ lines.push(chalk2.red(" " + line));
2329
2514
  } else if (line.startsWith("@@")) {
2330
- lines.push(chalk.cyan(" " + line));
2515
+ lines.push(chalk2.cyan(" " + line));
2331
2516
  } else {
2332
- lines.push(chalk.dim(" " + line));
2517
+ lines.push(chalk2.dim(" " + line));
2333
2518
  }
2334
2519
  }
2335
2520
  const totalBody = bodyLines.length;
2336
2521
  if (totalBody > maxVisible) {
2337
2522
  const pct = Math.round((scrollOffset + maxVisible) / totalBody * 100);
2338
- lines.push(chalk.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
2523
+ lines.push(chalk2.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
2339
2524
  }
2340
2525
  lines.push("");
2341
- lines.push(chalk.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
2526
+ lines.push(chalk2.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
2342
2527
  return lines.join("\n");
2343
2528
  }
2344
2529
  function draw(initial) {
@@ -2744,7 +2929,7 @@ function getCurrentHeadSha() {
2744
2929
  }
2745
2930
 
2746
2931
  // src/utils/spinner-messages.ts
2747
- import chalk2 from "chalk";
2932
+ import chalk3 from "chalk";
2748
2933
  var GENERATION_MESSAGES = [
2749
2934
  "Analyzing your project structure and dependencies...",
2750
2935
  "Mapping out build commands and test workflows...",
@@ -2794,9 +2979,9 @@ var SpinnerMessages = class {
2794
2979
  this.currentBaseMessage = this.messages[0];
2795
2980
  this.updateSpinnerText();
2796
2981
  if (this.showElapsedTime) {
2797
- this.spinner.suffixText = chalk2.dim(`(${this.formatElapsed()})`);
2982
+ this.spinner.suffixText = chalk3.dim(`(${this.formatElapsed()})`);
2798
2983
  this.elapsedTimer = setInterval(() => {
2799
- this.spinner.suffixText = chalk2.dim(`(${this.formatElapsed()})`);
2984
+ this.spinner.suffixText = chalk3.dim(`(${this.formatElapsed()})`);
2800
2985
  }, 1e3);
2801
2986
  }
2802
2987
  this.timer = setInterval(() => {
@@ -2830,14 +3015,18 @@ var SpinnerMessages = class {
2830
3015
  }
2831
3016
  };
2832
3017
 
3018
+ // src/commands/onboard.ts
3019
+ init_config();
3020
+
2833
3021
  // src/commands/interactive-provider-setup.ts
2834
- import chalk3 from "chalk";
3022
+ init_config();
3023
+ import chalk4 from "chalk";
2835
3024
  import readline2 from "readline";
2836
- import select2 from "@inquirer/select";
3025
+ import select3 from "@inquirer/select";
2837
3026
  function promptInput(question) {
2838
3027
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
2839
3028
  return new Promise((resolve2) => {
2840
- rl.question(chalk3.cyan(`${question} `), (answer) => {
3029
+ rl.question(chalk4.cyan(`${question} `), (answer) => {
2841
3030
  rl.close();
2842
3031
  resolve2(answer.trim());
2843
3032
  });
@@ -2852,7 +3041,7 @@ var PROVIDER_CHOICES = [
2852
3041
  ];
2853
3042
  async function runInteractiveProviderSetup(options) {
2854
3043
  const message = options?.selectMessage ?? "Select LLM provider";
2855
- const provider = await select2({
3044
+ const provider = await select3({
2856
3045
  message,
2857
3046
  choices: PROVIDER_CHOICES
2858
3047
  });
@@ -2860,19 +3049,19 @@ async function runInteractiveProviderSetup(options) {
2860
3049
  switch (provider) {
2861
3050
  case "claude-cli": {
2862
3051
  config.model = "default";
2863
- console.log(chalk3.dim(" Run `claude` once and log in with your Pro/Max/Team account if you haven't."));
3052
+ console.log(chalk4.dim(" Run `claude` once and log in with your Pro/Max/Team account if you haven't."));
2864
3053
  break;
2865
3054
  }
2866
3055
  case "cursor": {
2867
3056
  config.model = "default";
2868
- console.log(chalk3.dim(" Run `agent login` if you haven't, or set CURSOR_API_KEY."));
3057
+ console.log(chalk4.dim(" Run `agent login` if you haven't, or set CURSOR_API_KEY."));
2869
3058
  break;
2870
3059
  }
2871
3060
  case "anthropic": {
2872
- console.log(chalk3.dim(" Get a key at https://console.anthropic.com (same account as Claude Pro/Team/Max)."));
3061
+ console.log(chalk4.dim(" Get a key at https://console.anthropic.com (same account as Claude Pro/Team/Max)."));
2873
3062
  config.apiKey = await promptInput("Anthropic API key:");
2874
3063
  if (!config.apiKey) {
2875
- console.log(chalk3.red("API key is required."));
3064
+ console.log(chalk4.red("API key is required."));
2876
3065
  throw new Error("__exit__");
2877
3066
  }
2878
3067
  config.model = await promptInput(`Model (default: ${DEFAULT_MODELS.anthropic}):`) || DEFAULT_MODELS.anthropic;
@@ -2881,7 +3070,7 @@ async function runInteractiveProviderSetup(options) {
2881
3070
  case "vertex": {
2882
3071
  config.vertexProjectId = await promptInput("GCP Project ID:");
2883
3072
  if (!config.vertexProjectId) {
2884
- console.log(chalk3.red("Project ID is required."));
3073
+ console.log(chalk4.red("Project ID is required."));
2885
3074
  throw new Error("__exit__");
2886
3075
  }
2887
3076
  config.vertexRegion = await promptInput("Region (default: us-east5):") || "us-east5";
@@ -2892,7 +3081,7 @@ async function runInteractiveProviderSetup(options) {
2892
3081
  case "openai": {
2893
3082
  config.apiKey = await promptInput("API key:");
2894
3083
  if (!config.apiKey) {
2895
- console.log(chalk3.red("API key is required."));
3084
+ console.log(chalk4.red("API key is required."));
2896
3085
  throw new Error("__exit__");
2897
3086
  }
2898
3087
  config.baseUrl = await promptInput("Base URL (leave empty for OpenAI, or enter custom endpoint):") || void 0;
@@ -3016,15 +3205,15 @@ function computeGrade(score) {
3016
3205
  // src/scoring/checks/coverage.ts
3017
3206
  import { readFileSync, readdirSync } from "fs";
3018
3207
  import { join } from "path";
3019
- function readFileOrNull(path23) {
3208
+ function readFileOrNull(path24) {
3020
3209
  try {
3021
- return readFileSync(path23, "utf-8");
3210
+ return readFileSync(path24, "utf-8");
3022
3211
  } catch {
3023
3212
  return null;
3024
3213
  }
3025
3214
  }
3026
- function readJsonOrNull(path23) {
3027
- const content = readFileOrNull(path23);
3215
+ function readJsonOrNull(path24) {
3216
+ const content = readFileOrNull(path24);
3028
3217
  if (!content) return null;
3029
3218
  try {
3030
3219
  return JSON.parse(content);
@@ -3392,9 +3581,9 @@ function checkExistence(dir) {
3392
3581
  // src/scoring/checks/quality.ts
3393
3582
  import { readFileSync as readFileSync3 } from "fs";
3394
3583
  import { join as join3 } from "path";
3395
- function readFileOrNull2(path23) {
3584
+ function readFileOrNull2(path24) {
3396
3585
  try {
3397
- return readFileSync3(path23, "utf-8");
3586
+ return readFileSync3(path24, "utf-8");
3398
3587
  } catch {
3399
3588
  return null;
3400
3589
  }
@@ -3547,15 +3736,15 @@ function checkQuality(dir) {
3547
3736
  // src/scoring/checks/accuracy.ts
3548
3737
  import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync } from "fs";
3549
3738
  import { join as join4 } from "path";
3550
- function readFileOrNull3(path23) {
3739
+ function readFileOrNull3(path24) {
3551
3740
  try {
3552
- return readFileSync4(path23, "utf-8");
3741
+ return readFileSync4(path24, "utf-8");
3553
3742
  } catch {
3554
3743
  return null;
3555
3744
  }
3556
3745
  }
3557
- function readJsonOrNull2(path23) {
3558
- const content = readFileOrNull3(path23);
3746
+ function readJsonOrNull2(path24) {
3747
+ const content = readFileOrNull3(path24);
3559
3748
  if (!content) return null;
3560
3749
  try {
3561
3750
  return JSON.parse(content);
@@ -3738,9 +3927,9 @@ function checkAccuracy(dir) {
3738
3927
  // src/scoring/checks/freshness.ts
3739
3928
  import { existsSync as existsSync6, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
3740
3929
  import { join as join5 } from "path";
3741
- function readFileOrNull4(path23) {
3930
+ function readFileOrNull4(path24) {
3742
3931
  try {
3743
- return readFileSync5(path23, "utf-8");
3932
+ return readFileSync5(path24, "utf-8");
3744
3933
  } catch {
3745
3934
  return null;
3746
3935
  }
@@ -3854,9 +4043,9 @@ function checkFreshness(dir) {
3854
4043
  import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
3855
4044
  import { execSync as execSync7 } from "child_process";
3856
4045
  import { join as join6 } from "path";
3857
- function readFileOrNull5(path23) {
4046
+ function readFileOrNull5(path24) {
3858
4047
  try {
3859
- return readFileSync6(path23, "utf-8");
4048
+ return readFileSync6(path24, "utf-8");
3860
4049
  } catch {
3861
4050
  return null;
3862
4051
  }
@@ -4030,7 +4219,7 @@ function computeLocalScore(dir, targetAgent) {
4030
4219
  }
4031
4220
 
4032
4221
  // src/scoring/display.ts
4033
- import chalk4 from "chalk";
4222
+ import chalk5 from "chalk";
4034
4223
  var AGENT_DISPLAY_NAMES = {
4035
4224
  claude: "Claude Code",
4036
4225
  cursor: "Cursor",
@@ -4048,31 +4237,31 @@ var CATEGORY_ORDER = ["existence", "quality", "coverage", "accuracy", "freshness
4048
4237
  function gradeColor(grade) {
4049
4238
  switch (grade) {
4050
4239
  case "A":
4051
- return chalk4.green;
4240
+ return chalk5.green;
4052
4241
  case "B":
4053
- return chalk4.greenBright;
4242
+ return chalk5.greenBright;
4054
4243
  case "C":
4055
- return chalk4.yellow;
4244
+ return chalk5.yellow;
4056
4245
  case "D":
4057
- return chalk4.hex("#f97316");
4246
+ return chalk5.hex("#f97316");
4058
4247
  case "F":
4059
- return chalk4.red;
4248
+ return chalk5.red;
4060
4249
  default:
4061
- return chalk4.white;
4250
+ return chalk5.white;
4062
4251
  }
4063
4252
  }
4064
4253
  function progressBar(score, max, width = 40) {
4065
4254
  const filled = Math.round(score / max * width);
4066
4255
  const empty = width - filled;
4067
- const bar = chalk4.hex("#f97316")("\u2593".repeat(filled)) + chalk4.gray("\u2591".repeat(empty));
4256
+ const bar = chalk5.hex("#f97316")("\u2593".repeat(filled)) + chalk5.gray("\u2591".repeat(empty));
4068
4257
  return bar;
4069
4258
  }
4070
4259
  function formatCheck(check) {
4071
- const icon = check.passed ? chalk4.green("\u2713") : check.earnedPoints < 0 ? chalk4.red("\u2717") : chalk4.gray("\u2717");
4072
- const points = check.passed ? chalk4.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk4.red(`${check.earnedPoints}`.padStart(4)) : chalk4.gray(" \u2014");
4073
- const name = check.passed ? chalk4.white(check.name) : chalk4.gray(check.name);
4074
- const detail = check.detail ? chalk4.gray(` (${check.detail})`) : "";
4075
- const suggestion = !check.passed && check.suggestion ? chalk4.gray(`
4260
+ const icon = check.passed ? chalk5.green("\u2713") : check.earnedPoints < 0 ? chalk5.red("\u2717") : chalk5.gray("\u2717");
4261
+ const points = check.passed ? chalk5.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk5.red(`${check.earnedPoints}`.padStart(4)) : chalk5.gray(" \u2014");
4262
+ const name = check.passed ? chalk5.white(check.name) : chalk5.gray(check.name);
4263
+ const detail = check.detail ? chalk5.gray(` (${check.detail})`) : "";
4264
+ const suggestion = !check.passed && check.suggestion ? chalk5.gray(`
4076
4265
  \u2192 ${check.suggestion}`) : "";
4077
4266
  return ` ${icon} ${name.padEnd(38)}${points}${detail}${suggestion}`;
4078
4267
  }
@@ -4080,19 +4269,19 @@ function displayScore(result) {
4080
4269
  const gc = gradeColor(result.grade);
4081
4270
  const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
4082
4271
  console.log("");
4083
- console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4272
+ console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4084
4273
  console.log("");
4085
- console.log(` ${chalk4.bold("Agent Config Score")} ${gc(chalk4.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk4.bold(result.grade))}`);
4274
+ console.log(` ${chalk5.bold("Agent Config Score")} ${gc(chalk5.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk5.bold(result.grade))}`);
4086
4275
  console.log(` ${progressBar(result.score, result.maxScore)}`);
4087
- console.log(chalk4.dim(` Target: ${agentLabel}`));
4276
+ console.log(chalk5.dim(` Target: ${agentLabel}`));
4088
4277
  console.log("");
4089
- console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4278
+ console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4090
4279
  console.log("");
4091
4280
  for (const category of CATEGORY_ORDER) {
4092
4281
  const summary = result.categories[category];
4093
4282
  const categoryChecks = result.checks.filter((c) => c.category === category);
4094
4283
  console.log(
4095
- chalk4.gray(` ${CATEGORY_LABELS[category]}`) + chalk4.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk4.white(`${summary.earned}`) + chalk4.gray(` / ${summary.max}`)
4284
+ chalk5.gray(` ${CATEGORY_LABELS[category]}`) + chalk5.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk5.white(`${summary.earned}`) + chalk5.gray(` / ${summary.max}`)
4096
4285
  );
4097
4286
  for (const check of categoryChecks) {
4098
4287
  console.log(formatCheck(check));
@@ -4105,48 +4294,48 @@ function displayScoreSummary(result) {
4105
4294
  const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
4106
4295
  console.log("");
4107
4296
  console.log(
4108
- chalk4.gray(" ") + gc(`${result.score}/${result.maxScore}`) + chalk4.gray(` (Grade ${result.grade})`) + chalk4.gray(` \xB7 ${agentLabel}`) + chalk4.gray(` \xB7 ${progressBar(result.score, result.maxScore, 20)}`)
4297
+ chalk5.gray(" ") + gc(`${result.score}/${result.maxScore}`) + chalk5.gray(` (Grade ${result.grade})`) + chalk5.gray(` \xB7 ${agentLabel}`) + chalk5.gray(` \xB7 ${progressBar(result.score, result.maxScore, 20)}`)
4109
4298
  );
4110
4299
  const failing = result.checks.filter((c) => !c.passed);
4111
4300
  if (failing.length > 0) {
4112
4301
  const shown = failing.slice(0, 5);
4113
4302
  for (const check of shown) {
4114
- console.log(chalk4.gray(` \u2717 ${check.name}`));
4303
+ console.log(chalk5.gray(` \u2717 ${check.name}`));
4115
4304
  }
4116
4305
  const remaining = failing.length - shown.length;
4117
4306
  const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
4118
- console.log(chalk4.dim(`
4119
- Run ${chalk4.hex("#83D1EB")("caliber score")} for details.${moreText}`));
4307
+ console.log(chalk5.dim(`
4308
+ Run ${chalk5.hex("#83D1EB")("caliber score")} for details.${moreText}`));
4120
4309
  }
4121
4310
  console.log("");
4122
4311
  }
4123
4312
  function displayScoreDelta(before, after) {
4124
4313
  const delta = after.score - before.score;
4125
4314
  const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
4126
- const deltaColor = delta >= 0 ? chalk4.green : chalk4.red;
4315
+ const deltaColor = delta >= 0 ? chalk5.green : chalk5.red;
4127
4316
  const beforeGc = gradeColor(before.grade);
4128
4317
  const afterGc = gradeColor(after.grade);
4129
4318
  console.log("");
4130
- console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4319
+ console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4131
4320
  console.log("");
4132
4321
  console.log(
4133
- ` Score: ${beforeGc(`${before.score}`)} ${chalk4.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk4.gray("\u2192")} ${afterGc(after.grade)}`
4322
+ ` Score: ${beforeGc(`${before.score}`)} ${chalk5.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk5.gray("\u2192")} ${afterGc(after.grade)}`
4134
4323
  );
4135
- console.log(` ${progressBar(before.score, before.maxScore, 19)} ${chalk4.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`);
4324
+ console.log(` ${progressBar(before.score, before.maxScore, 19)} ${chalk5.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`);
4136
4325
  console.log("");
4137
- console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4326
+ console.log(chalk5.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4138
4327
  console.log("");
4139
4328
  const improved = after.checks.filter((ac) => {
4140
4329
  const bc = before.checks.find((b) => b.id === ac.id);
4141
4330
  return bc && ac.earnedPoints > bc.earnedPoints;
4142
4331
  });
4143
4332
  if (improved.length > 0) {
4144
- console.log(chalk4.gray(" What improved:"));
4333
+ console.log(chalk5.gray(" What improved:"));
4145
4334
  for (const check of improved) {
4146
4335
  const bc = before.checks.find((b) => b.id === check.id);
4147
4336
  const gain = check.earnedPoints - bc.earnedPoints;
4148
4337
  console.log(
4149
- chalk4.green(" +") + chalk4.white(` ${check.name.padEnd(50)}`) + chalk4.green(`+${gain}`)
4338
+ chalk5.green(" +") + chalk5.white(` ${check.name.padEnd(50)}`) + chalk5.green(`+${gain}`)
4150
4339
  );
4151
4340
  }
4152
4341
  console.log("");
@@ -4154,9 +4343,9 @@ function displayScoreDelta(before, after) {
4154
4343
  }
4155
4344
 
4156
4345
  // src/commands/recommend.ts
4157
- import chalk5 from "chalk";
4346
+ import chalk7 from "chalk";
4158
4347
  import ora from "ora";
4159
- import select3 from "@inquirer/select";
4348
+ import select4 from "@inquirer/select";
4160
4349
  import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5, existsSync as existsSync9, writeFileSync } from "fs";
4161
4350
  import { join as join8, dirname as dirname2 } from "path";
4162
4351
 
@@ -4304,6 +4493,168 @@ function hashJson(obj) {
4304
4493
  return crypto2.createHash("sha256").update(JSON.stringify(obj)).digest("hex");
4305
4494
  }
4306
4495
 
4496
+ // src/commands/recommend.ts
4497
+ init_config();
4498
+
4499
+ // src/telemetry/index.ts
4500
+ import { PostHog } from "posthog-node";
4501
+ import chalk6 from "chalk";
4502
+
4503
+ // src/telemetry/config.ts
4504
+ import fs21 from "fs";
4505
+ import path17 from "path";
4506
+ import os3 from "os";
4507
+ import crypto3 from "crypto";
4508
+ import { execSync as execSync8 } from "child_process";
4509
+ var CONFIG_DIR2 = path17.join(os3.homedir(), ".caliber");
4510
+ var CONFIG_FILE2 = path17.join(CONFIG_DIR2, "config.json");
4511
+ var runtimeDisabled = false;
4512
+ function readConfig() {
4513
+ try {
4514
+ if (!fs21.existsSync(CONFIG_FILE2)) return {};
4515
+ return JSON.parse(fs21.readFileSync(CONFIG_FILE2, "utf-8"));
4516
+ } catch {
4517
+ return {};
4518
+ }
4519
+ }
4520
+ function writeConfig(config) {
4521
+ if (!fs21.existsSync(CONFIG_DIR2)) {
4522
+ fs21.mkdirSync(CONFIG_DIR2, { recursive: true });
4523
+ }
4524
+ fs21.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
4525
+ }
4526
+ function getMachineId() {
4527
+ const config = readConfig();
4528
+ if (config.machineId) return config.machineId;
4529
+ const machineId = crypto3.randomUUID();
4530
+ writeConfig({ ...config, machineId });
4531
+ return machineId;
4532
+ }
4533
+ function getGitEmailHash() {
4534
+ try {
4535
+ const email = execSync8("git config user.email", { encoding: "utf-8" }).trim();
4536
+ if (!email) return void 0;
4537
+ return crypto3.createHash("sha256").update(email).digest("hex");
4538
+ } catch {
4539
+ return void 0;
4540
+ }
4541
+ }
4542
+ function isTelemetryDisabled() {
4543
+ if (runtimeDisabled) return true;
4544
+ const envVal = process.env.CALIBER_TELEMETRY_DISABLED;
4545
+ return envVal === "1" || envVal === "true";
4546
+ }
4547
+ function setTelemetryDisabled(disabled) {
4548
+ runtimeDisabled = disabled;
4549
+ }
4550
+ function wasNoticeShown() {
4551
+ return readConfig().telemetryNoticeShown === true;
4552
+ }
4553
+ function markNoticeShown() {
4554
+ const config = readConfig();
4555
+ writeConfig({ ...config, telemetryNoticeShown: true });
4556
+ }
4557
+
4558
+ // src/telemetry/index.ts
4559
+ var POSTHOG_KEY = "phx_o1APdJxfIEvJ2RM0XyUX635wUms4mAWXNjPiIbLjGbU0lIi";
4560
+ var client = null;
4561
+ var distinctId = null;
4562
+ function initTelemetry() {
4563
+ if (isTelemetryDisabled()) return;
4564
+ const machineId = getMachineId();
4565
+ distinctId = machineId;
4566
+ client = new PostHog(POSTHOG_KEY, {
4567
+ host: "https://us.i.posthog.com",
4568
+ flushAt: 20,
4569
+ flushInterval: 0
4570
+ });
4571
+ if (!wasNoticeShown()) {
4572
+ console.log(
4573
+ chalk6.dim(" Caliber collects anonymous usage data to improve the product.") + "\n" + chalk6.dim(" Disable with --no-traces or CALIBER_TELEMETRY_DISABLED=1\n")
4574
+ );
4575
+ markNoticeShown();
4576
+ }
4577
+ const gitEmailHash = getGitEmailHash();
4578
+ client.identify({
4579
+ distinctId: machineId,
4580
+ properties: {
4581
+ ...gitEmailHash ? { git_email_hash: gitEmailHash } : {}
4582
+ }
4583
+ });
4584
+ }
4585
+ function trackEvent(name, properties) {
4586
+ if (!client || !distinctId || isTelemetryDisabled()) return;
4587
+ client.capture({
4588
+ distinctId,
4589
+ event: name,
4590
+ properties: properties ?? {}
4591
+ });
4592
+ }
4593
+ async function flushTelemetry() {
4594
+ if (!client) return;
4595
+ try {
4596
+ await client.shutdown();
4597
+ } catch {
4598
+ }
4599
+ client = null;
4600
+ }
4601
+
4602
+ // src/telemetry/events.ts
4603
+ function trackInitProviderSelected(provider, model) {
4604
+ trackEvent("init_provider_selected", { provider, model });
4605
+ }
4606
+ function trackInitProjectDiscovered(languageCount, dependencyCount, fileCount) {
4607
+ trackEvent("init_project_discovered", { language_count: languageCount, dependency_count: dependencyCount, file_count: fileCount });
4608
+ }
4609
+ function trackInitAgentSelected(agents) {
4610
+ trackEvent("init_agent_selected", { agents });
4611
+ }
4612
+ function trackInitScoreComputed(score, passingCount, failingCount, earlyExit) {
4613
+ trackEvent("init_score_computed", { score, passing_count: passingCount, failing_count: failingCount, early_exit: earlyExit });
4614
+ }
4615
+ function trackInitGenerationStarted(isTargetedFix) {
4616
+ trackEvent("init_generation_started", { is_targeted_fix: isTargetedFix });
4617
+ }
4618
+ function trackInitGenerationCompleted(durationMs, retryCount) {
4619
+ trackEvent("init_generation_completed", { duration_ms: durationMs, retry_count: retryCount });
4620
+ }
4621
+ function trackInitReviewAction(action, reviewMethod) {
4622
+ trackEvent("init_review_action", { action, review_method: reviewMethod });
4623
+ }
4624
+ function trackInitRefinementRound(roundNumber, wasValid) {
4625
+ trackEvent("init_refinement_round", { round_number: roundNumber, was_valid: wasValid });
4626
+ }
4627
+ function trackInitFilesWritten(fileCount, createdCount, modifiedCount, deletedCount) {
4628
+ trackEvent("init_files_written", { file_count: fileCount, created_count: createdCount, modified_count: modifiedCount, deleted_count: deletedCount });
4629
+ }
4630
+ function trackInitHookSelected(hookType) {
4631
+ trackEvent("init_hook_selected", { hook_type: hookType });
4632
+ }
4633
+ function trackInitSkillsSearch(searched, installedCount) {
4634
+ trackEvent("init_skills_search", { searched, installed_count: installedCount });
4635
+ }
4636
+ function trackInitScoreRegression(oldScore, newScore) {
4637
+ trackEvent("init_score_regression", { old_score: oldScore, new_score: newScore });
4638
+ }
4639
+ function trackRegenerateCompleted(action, durationMs) {
4640
+ trackEvent("regenerate_completed", { action, duration_ms: durationMs });
4641
+ }
4642
+ function trackRefreshCompleted(changesCount, durationMs) {
4643
+ trackEvent("refresh_completed", { changes_count: changesCount, duration_ms: durationMs });
4644
+ }
4645
+ function trackScoreComputed(score, agent) {
4646
+ trackEvent("score_computed", { score, agent });
4647
+ }
4648
+ function trackConfigProviderSet(provider) {
4649
+ trackEvent("config_provider_set", { provider });
4650
+ }
4651
+ function trackSkillsInstalled(count) {
4652
+ trackEvent("skills_installed", { count });
4653
+ }
4654
+ function trackUndoExecuted() {
4655
+ trackEvent("undo_executed");
4656
+ }
4657
+
4307
4658
  // src/commands/recommend.ts
4308
4659
  function detectLocalPlatforms() {
4309
4660
  const items = scanLocalState(process.cwd());
@@ -4604,7 +4955,7 @@ function extractTopDeps() {
4604
4955
  }
4605
4956
  }
4606
4957
  async function recommendCommand() {
4607
- const proceed = await select3({
4958
+ const proceed = await select4({
4608
4959
  message: "Search public repos for relevant skills to add to this project?",
4609
4960
  choices: [
4610
4961
  { name: "Yes, find skills for my project", value: true },
@@ -4612,7 +4963,7 @@ async function recommendCommand() {
4612
4963
  ]
4613
4964
  });
4614
4965
  if (!proceed) {
4615
- console.log(chalk5.dim(" Cancelled.\n"));
4966
+ console.log(chalk7.dim(" Cancelled.\n"));
4616
4967
  return;
4617
4968
  }
4618
4969
  await searchAndInstallSkills();
@@ -4627,7 +4978,7 @@ async function searchAndInstallSkills() {
4627
4978
  ...extractTopDeps()
4628
4979
  ].filter(Boolean))];
4629
4980
  if (technologies.length === 0) {
4630
- console.log(chalk5.yellow("Could not detect any languages or dependencies. Try running from a project root."));
4981
+ console.log(chalk7.yellow("Could not detect any languages or dependencies. Try running from a project root."));
4631
4982
  throw new Error("__exit__");
4632
4983
  }
4633
4984
  const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
@@ -4644,7 +4995,7 @@ async function searchAndInstallSkills() {
4644
4995
  return;
4645
4996
  }
4646
4997
  searchSpinner.succeed(
4647
- `Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk5.dim(` (${filteredCount} already installed)`) : "")
4998
+ `Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk7.dim(` (${filteredCount} already installed)`) : "")
4648
4999
  );
4649
5000
  let results;
4650
5001
  const config = loadConfig();
@@ -4678,7 +5029,7 @@ async function searchAndInstallSkills() {
4678
5029
  }
4679
5030
  const unavailableCount = results.length - available.length;
4680
5031
  fetchSpinner.succeed(
4681
- `${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk5.dim(` (${unavailableCount} unavailable)`) : "")
5032
+ `${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk7.dim(` (${unavailableCount} unavailable)`) : "")
4682
5033
  );
4683
5034
  const selected = await interactiveSelect(available);
4684
5035
  if (selected?.length) {
@@ -4701,30 +5052,30 @@ async function interactiveSelect(recs) {
4701
5052
  const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
4702
5053
  const prefixWidth = 8;
4703
5054
  const scoreWidth = 6;
4704
- lines.push(chalk5.bold(" Skills"));
5055
+ lines.push(chalk7.bold(" Skills"));
4705
5056
  lines.push("");
4706
5057
  if (hasScores) {
4707
- const header = " ".repeat(prefixWidth) + chalk5.dim("Score".padEnd(scoreWidth)) + chalk5.dim("Name".padEnd(nameWidth)) + chalk5.dim("Why");
5058
+ const header = " ".repeat(prefixWidth) + chalk7.dim("Score".padEnd(scoreWidth)) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Why");
4708
5059
  lines.push(header);
4709
5060
  } else {
4710
- const header = " ".repeat(prefixWidth) + chalk5.dim("Name".padEnd(nameWidth)) + chalk5.dim("Technology".padEnd(18)) + chalk5.dim("Source");
5061
+ const header = " ".repeat(prefixWidth) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Technology".padEnd(18)) + chalk7.dim("Source");
4711
5062
  lines.push(header);
4712
5063
  }
4713
- lines.push(chalk5.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
5064
+ lines.push(chalk7.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
4714
5065
  for (let i = 0; i < recs.length; i++) {
4715
5066
  const rec = recs[i];
4716
- const check = selected.has(i) ? chalk5.green("[x]") : "[ ]";
4717
- const ptr = i === cursor ? chalk5.cyan(">") : " ";
5067
+ const check = selected.has(i) ? chalk7.green("[x]") : "[ ]";
5068
+ const ptr = i === cursor ? chalk7.cyan(">") : " ";
4718
5069
  if (hasScores) {
4719
- const scoreColor = rec.score >= 90 ? chalk5.green : rec.score >= 70 ? chalk5.yellow : chalk5.dim;
5070
+ const scoreColor = rec.score >= 90 ? chalk7.green : rec.score >= 70 ? chalk7.yellow : chalk7.dim;
4720
5071
  const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
4721
- lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${chalk5.dim(rec.reason.slice(0, reasonMax))}`);
5072
+ lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${chalk7.dim(rec.reason.slice(0, reasonMax))}`);
4722
5073
  } else {
4723
- lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk5.dim(rec.source_url || "")}`);
5074
+ lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk7.dim(rec.source_url || "")}`);
4724
5075
  }
4725
5076
  }
4726
5077
  lines.push("");
4727
- lines.push(chalk5.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
5078
+ lines.push(chalk7.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
4728
5079
  return lines.join("\n");
4729
5080
  }
4730
5081
  function draw(initial) {
@@ -4773,7 +5124,7 @@ async function interactiveSelect(recs) {
4773
5124
  case "\n":
4774
5125
  cleanup();
4775
5126
  if (selected.size === 0) {
4776
- console.log(chalk5.dim("\n No skills selected.\n"));
5127
+ console.log(chalk7.dim("\n No skills selected.\n"));
4777
5128
  resolve2(null);
4778
5129
  } else {
4779
5130
  resolve2(Array.from(selected).sort().map((i) => recs[i]));
@@ -4783,7 +5134,7 @@ async function interactiveSelect(recs) {
4783
5134
  case "\x1B":
4784
5135
  case "":
4785
5136
  cleanup();
4786
- console.log(chalk5.dim("\n Cancelled.\n"));
5137
+ console.log(chalk7.dim("\n Cancelled.\n"));
4787
5138
  resolve2(null);
4788
5139
  break;
4789
5140
  }
@@ -4844,9 +5195,10 @@ async function installSkills(recs, platforms, contentMap) {
4844
5195
  }
4845
5196
  }
4846
5197
  if (installed.length > 0) {
5198
+ trackSkillsInstalled(installed.length);
4847
5199
  spinner.succeed(`Installed ${installed.length} file${installed.length > 1 ? "s" : ""}`);
4848
5200
  for (const p of installed) {
4849
- console.log(chalk5.green(` \u2713 ${p}`));
5201
+ console.log(chalk7.green(` \u2713 ${p}`));
4850
5202
  }
4851
5203
  } else {
4852
5204
  spinner.fail("No skills were installed");
@@ -4859,19 +5211,19 @@ function printSkills(recs) {
4859
5211
  const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
4860
5212
  const scoreWidth = 6;
4861
5213
  const prefixWidth = 2;
4862
- console.log(chalk5.bold("\n Skills\n"));
5214
+ console.log(chalk7.bold("\n Skills\n"));
4863
5215
  if (hasScores) {
4864
- console.log(" ".repeat(prefixWidth) + chalk5.dim("Score".padEnd(scoreWidth)) + chalk5.dim("Name".padEnd(nameWidth)) + chalk5.dim("Why"));
5216
+ console.log(" ".repeat(prefixWidth) + chalk7.dim("Score".padEnd(scoreWidth)) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Why"));
4865
5217
  } else {
4866
- console.log(" ".repeat(prefixWidth) + chalk5.dim("Name".padEnd(nameWidth)) + chalk5.dim("Technology".padEnd(18)) + chalk5.dim("Source"));
5218
+ console.log(" ".repeat(prefixWidth) + chalk7.dim("Name".padEnd(nameWidth)) + chalk7.dim("Technology".padEnd(18)) + chalk7.dim("Source"));
4867
5219
  }
4868
- console.log(chalk5.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
5220
+ console.log(chalk7.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
4869
5221
  for (const rec of recs) {
4870
5222
  if (hasScores) {
4871
5223
  const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
4872
- console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${chalk5.dim(rec.reason.slice(0, reasonMax))}`);
5224
+ console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${chalk7.dim(rec.reason.slice(0, reasonMax))}`);
4873
5225
  } else {
4874
- console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk5.dim(rec.source_url || "")}`);
5226
+ console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk7.dim(rec.source_url || "")}`);
4875
5227
  }
4876
5228
  }
4877
5229
  console.log("");
@@ -4879,8 +5231,8 @@ function printSkills(recs) {
4879
5231
 
4880
5232
  // src/commands/onboard.ts
4881
5233
  async function initCommand(options) {
4882
- const brand = chalk6.hex("#EB9D83");
4883
- const title = chalk6.hex("#83D1EB");
5234
+ const brand = chalk8.hex("#EB9D83");
5235
+ const title = chalk8.hex("#83D1EB");
4884
5236
  console.log(brand.bold(`
4885
5237
  \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
4886
5238
  \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
@@ -4889,21 +5241,21 @@ async function initCommand(options) {
4889
5241
  \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
4890
5242
  \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
4891
5243
  `));
4892
- console.log(chalk6.dim(" Onboard your project for AI-assisted development\n"));
5244
+ console.log(chalk8.dim(" Onboard your project for AI-assisted development\n"));
4893
5245
  console.log(title.bold(" Welcome to Caliber\n"));
4894
- console.log(chalk6.dim(" Caliber analyzes your codebase and creates tailored config files"));
4895
- console.log(chalk6.dim(" so your AI coding agents understand your project from day one.\n"));
5246
+ console.log(chalk8.dim(" Caliber analyzes your codebase and creates tailored config files"));
5247
+ console.log(chalk8.dim(" so your AI coding agents understand your project from day one.\n"));
4896
5248
  console.log(title.bold(" How onboarding works:\n"));
4897
- console.log(chalk6.dim(" 1. Connect Set up your LLM provider"));
4898
- console.log(chalk6.dim(" 2. Discover Analyze your code, dependencies, and structure"));
4899
- console.log(chalk6.dim(" 3. Generate Create config files tailored to your project"));
4900
- console.log(chalk6.dim(" 4. Review Preview, refine, and apply the changes"));
4901
- console.log(chalk6.dim(" 5. Enhance Discover MCP servers for your tools"));
4902
- console.log(chalk6.dim(" 6. Skills Browse community skills for your stack\n"));
5249
+ console.log(chalk8.dim(" 1. Connect Set up your LLM provider"));
5250
+ console.log(chalk8.dim(" 2. Discover Analyze your code, dependencies, and structure"));
5251
+ console.log(chalk8.dim(" 3. Generate Create config files tailored to your project"));
5252
+ console.log(chalk8.dim(" 4. Review Preview, refine, and apply the changes"));
5253
+ console.log(chalk8.dim(" 5. Enhance Discover MCP servers for your tools"));
5254
+ console.log(chalk8.dim(" 6. Skills Browse community skills for your stack\n"));
4903
5255
  console.log(title.bold(" Step 1/6 \u2014 Connect your LLM\n"));
4904
5256
  let config = loadConfig();
4905
5257
  if (!config) {
4906
- console.log(chalk6.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
5258
+ console.log(chalk8.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
4907
5259
  try {
4908
5260
  await runInteractiveProviderSetup({
4909
5261
  selectMessage: "How do you want to use Caliber? (choose LLM provider)"
@@ -4914,24 +5266,28 @@ async function initCommand(options) {
4914
5266
  }
4915
5267
  config = loadConfig();
4916
5268
  if (!config) {
4917
- console.log(chalk6.red(" Setup was cancelled or failed.\n"));
5269
+ console.log(chalk8.red(" Setup was cancelled or failed.\n"));
4918
5270
  throw new Error("__exit__");
4919
5271
  }
4920
- console.log(chalk6.green(" \u2713 Provider saved. Let's continue.\n"));
5272
+ console.log(chalk8.green(" \u2713 Provider saved. Let's continue.\n"));
4921
5273
  }
5274
+ trackInitProviderSelected(config.provider, config.model);
4922
5275
  const displayModel = config.model === "default" && config.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : config.model;
4923
5276
  const fastModel = getFastModel();
4924
5277
  const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
4925
- console.log(chalk6.dim(modelLine + "\n"));
5278
+ console.log(chalk8.dim(modelLine + "\n"));
5279
+ await validateModel({ fast: true });
4926
5280
  console.log(title.bold(" Step 2/6 \u2014 Discover your project\n"));
4927
- console.log(chalk6.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
5281
+ console.log(chalk8.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
4928
5282
  const spinner = ora2("Analyzing project...").start();
4929
5283
  const fingerprint = await collectFingerprint(process.cwd());
4930
5284
  spinner.succeed("Project analyzed");
4931
- console.log(chalk6.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
4932
- console.log(chalk6.dim(` Files: ${fingerprint.fileTree.length} found
5285
+ trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
5286
+ console.log(chalk8.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
5287
+ console.log(chalk8.dim(` Files: ${fingerprint.fileTree.length} found
4933
5288
  `));
4934
5289
  const targetAgent = options.agent || await promptAgent();
5290
+ trackInitAgentSelected(targetAgent);
4935
5291
  const preScore = computeLocalScore(process.cwd(), targetAgent);
4936
5292
  const failingForDismissal = preScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
4937
5293
  if (failingForDismissal.length > 0) {
@@ -4945,26 +5301,30 @@ async function initCommand(options) {
4945
5301
  }
4946
5302
  const baselineScore = computeLocalScore(process.cwd(), targetAgent);
4947
5303
  displayScoreSummary(baselineScore);
5304
+ const passingCount = baselineScore.checks.filter((c) => c.passed).length;
5305
+ const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
4948
5306
  const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length || fingerprint.existingConfigs.agentsMd);
4949
5307
  const NON_LLM_CHECKS = /* @__PURE__ */ new Set(["hooks_configured", "agents_md_exists", "permissions_configured", "mcp_servers"]);
4950
5308
  if (hasExistingConfig && baselineScore.score === 100) {
4951
- console.log(chalk6.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
4952
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber onboard --force") + chalk6.dim(" to regenerate anyway.\n"));
5309
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
5310
+ console.log(chalk8.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
5311
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to regenerate anyway.\n"));
4953
5312
  if (!options.force) return;
4954
5313
  }
4955
5314
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
4956
5315
  const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
5316
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
4957
5317
  if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
4958
- console.log(chalk6.bold.green("\n Your config is fully optimized for LLM generation.\n"));
4959
- console.log(chalk6.dim(" Remaining items need CLI actions:\n"));
5318
+ console.log(chalk8.bold.green("\n Your config is fully optimized for LLM generation.\n"));
5319
+ console.log(chalk8.dim(" Remaining items need CLI actions:\n"));
4960
5320
  for (const check of allFailingChecks) {
4961
- console.log(chalk6.dim(` \u2022 ${check.name}`));
5321
+ console.log(chalk8.dim(` \u2022 ${check.name}`));
4962
5322
  if (check.suggestion) {
4963
- console.log(` ${chalk6.hex("#83D1EB")(check.suggestion)}`);
5323
+ console.log(` ${chalk8.hex("#83D1EB")(check.suggestion)}`);
4964
5324
  }
4965
5325
  }
4966
5326
  console.log("");
4967
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber onboard --force") + chalk6.dim(" to regenerate anyway.\n"));
5327
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to regenerate anyway.\n"));
4968
5328
  return;
4969
5329
  }
4970
5330
  const isEmpty = fingerprint.fileTree.length < 3;
@@ -4980,22 +5340,23 @@ async function initCommand(options) {
4980
5340
  currentScore = baselineScore.score;
4981
5341
  if (failingChecks.length > 0) {
4982
5342
  console.log(title.bold(" Step 3/6 \u2014 Fine-tuning\n"));
4983
- console.log(chalk6.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
5343
+ console.log(chalk8.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
4984
5344
  `));
4985
5345
  for (const check of failingChecks) {
4986
- console.log(chalk6.dim(` \u2022 ${check.name}`));
5346
+ console.log(chalk8.dim(` \u2022 ${check.name}`));
4987
5347
  }
4988
5348
  console.log("");
4989
5349
  }
4990
5350
  } else if (hasExistingConfig) {
4991
5351
  console.log(title.bold(" Step 3/6 \u2014 Improve your setup\n"));
4992
- console.log(chalk6.dim(" Reviewing your existing configs against your codebase"));
4993
- console.log(chalk6.dim(" and preparing improvements.\n"));
5352
+ console.log(chalk8.dim(" Reviewing your existing configs against your codebase"));
5353
+ console.log(chalk8.dim(" and preparing improvements.\n"));
4994
5354
  } else {
4995
5355
  console.log(title.bold(" Step 3/6 \u2014 Build your agent setup\n"));
4996
- console.log(chalk6.dim(" Creating config files tailored to your project.\n"));
5356
+ console.log(chalk8.dim(" Creating config files tailored to your project.\n"));
4997
5357
  }
4998
- console.log(chalk6.dim(" This can take a couple of minutes depending on your model and provider.\n"));
5358
+ console.log(chalk8.dim(" This can take a couple of minutes depending on your model and provider.\n"));
5359
+ trackInitGenerationStarted(!!failingChecks);
4999
5360
  const genStartTime = Date.now();
5000
5361
  const genSpinner = ora2("Generating setup...").start();
5001
5362
  const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
@@ -5037,16 +5398,17 @@ async function initCommand(options) {
5037
5398
  if (!generatedSetup) {
5038
5399
  genSpinner.fail("Failed to generate setup.");
5039
5400
  if (rawOutput) {
5040
- console.log(chalk6.dim("\nRaw LLM output (JSON parse failed):"));
5041
- console.log(chalk6.dim(rawOutput.slice(0, 500)));
5401
+ console.log(chalk8.dim("\nRaw LLM output (JSON parse failed):"));
5402
+ console.log(chalk8.dim(rawOutput.slice(0, 500)));
5042
5403
  }
5043
5404
  throw new Error("__exit__");
5044
5405
  }
5045
5406
  const elapsedMs = Date.now() - genStartTime;
5407
+ trackInitGenerationCompleted(elapsedMs, 0);
5046
5408
  const mins = Math.floor(elapsedMs / 6e4);
5047
5409
  const secs = Math.floor(elapsedMs % 6e4 / 1e3);
5048
5410
  const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
5049
- genSpinner.succeed(`Setup generated ${chalk6.dim(`in ${timeStr}`)}`);
5411
+ genSpinner.succeed(`Setup generated ${chalk8.dim(`in ${timeStr}`)}`);
5050
5412
  printSetupSummary(generatedSetup);
5051
5413
  const sessionHistory = [];
5052
5414
  sessionHistory.push({
@@ -5057,11 +5419,11 @@ async function initCommand(options) {
5057
5419
  const setupFiles = collectSetupFiles(generatedSetup);
5058
5420
  const staged = stageFiles(setupFiles, process.cwd());
5059
5421
  const totalChanges = staged.newFiles + staged.modifiedFiles;
5060
- console.log(chalk6.dim(` ${chalk6.green(`${staged.newFiles} new`)} / ${chalk6.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
5422
+ console.log(chalk8.dim(` ${chalk8.green(`${staged.newFiles} new`)} / ${chalk8.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
5061
5423
  `));
5062
5424
  let action;
5063
5425
  if (totalChanges === 0) {
5064
- console.log(chalk6.dim(" No changes needed \u2014 your configs are already up to date.\n"));
5426
+ console.log(chalk8.dim(" No changes needed \u2014 your configs are already up to date.\n"));
5065
5427
  cleanupStaging();
5066
5428
  action = "accept";
5067
5429
  } else {
@@ -5071,29 +5433,34 @@ async function initCommand(options) {
5071
5433
  await openReview(reviewMethod, staged.stagedFiles);
5072
5434
  }
5073
5435
  action = await promptReviewAction();
5436
+ trackInitReviewAction(action, wantsReview ? "reviewed" : "skipped");
5074
5437
  }
5438
+ let refinementRound = 0;
5075
5439
  while (action === "refine") {
5440
+ refinementRound++;
5076
5441
  generatedSetup = await refineLoop(generatedSetup, targetAgent, sessionHistory);
5442
+ trackInitRefinementRound(refinementRound, !!generatedSetup);
5077
5443
  if (!generatedSetup) {
5078
5444
  cleanupStaging();
5079
- console.log(chalk6.dim("Refinement cancelled. No files were modified."));
5445
+ console.log(chalk8.dim("Refinement cancelled. No files were modified."));
5080
5446
  return;
5081
5447
  }
5082
5448
  const updatedFiles = collectSetupFiles(generatedSetup);
5083
5449
  const restaged = stageFiles(updatedFiles, process.cwd());
5084
- console.log(chalk6.dim(` ${chalk6.green(`${restaged.newFiles} new`)} / ${chalk6.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
5450
+ console.log(chalk8.dim(` ${chalk8.green(`${restaged.newFiles} new`)} / ${chalk8.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
5085
5451
  `));
5086
5452
  printSetupSummary(generatedSetup);
5087
5453
  await openReview("terminal", restaged.stagedFiles);
5088
5454
  action = await promptReviewAction();
5455
+ trackInitReviewAction(action, "terminal");
5089
5456
  }
5090
5457
  cleanupStaging();
5091
5458
  if (action === "decline") {
5092
- console.log(chalk6.dim("Setup declined. No files were modified."));
5459
+ console.log(chalk8.dim("Setup declined. No files were modified."));
5093
5460
  return;
5094
5461
  }
5095
5462
  if (options.dryRun) {
5096
- console.log(chalk6.yellow("\n[Dry run] Would write the following files:"));
5463
+ console.log(chalk8.yellow("\n[Dry run] Would write the following files:"));
5097
5464
  console.log(JSON.stringify(generatedSetup, null, 2));
5098
5465
  return;
5099
5466
  }
@@ -5101,23 +5468,29 @@ async function initCommand(options) {
5101
5468
  try {
5102
5469
  const result = writeSetup(generatedSetup);
5103
5470
  writeSpinner.succeed("Config files written");
5104
- console.log(chalk6.bold("\nFiles created/updated:"));
5471
+ trackInitFilesWritten(
5472
+ result.written.length + result.deleted.length,
5473
+ result.written.length,
5474
+ 0,
5475
+ result.deleted.length
5476
+ );
5477
+ console.log(chalk8.bold("\nFiles created/updated:"));
5105
5478
  for (const file of result.written) {
5106
- console.log(` ${chalk6.green("\u2713")} ${file}`);
5479
+ console.log(` ${chalk8.green("\u2713")} ${file}`);
5107
5480
  }
5108
5481
  if (result.deleted.length > 0) {
5109
- console.log(chalk6.bold("\nFiles removed:"));
5482
+ console.log(chalk8.bold("\nFiles removed:"));
5110
5483
  for (const file of result.deleted) {
5111
- console.log(` ${chalk6.red("\u2717")} ${file}`);
5484
+ console.log(` ${chalk8.red("\u2717")} ${file}`);
5112
5485
  }
5113
5486
  }
5114
5487
  if (result.backupDir) {
5115
- console.log(chalk6.dim(`
5488
+ console.log(chalk8.dim(`
5116
5489
  Backups saved to ${result.backupDir}`));
5117
5490
  }
5118
5491
  } catch (err) {
5119
5492
  writeSpinner.fail("Failed to write files");
5120
- console.error(chalk6.red(err instanceof Error ? err.message : "Unknown error"));
5493
+ console.error(chalk8.red(err instanceof Error ? err.message : "Unknown error"));
5121
5494
  throw new Error("__exit__");
5122
5495
  }
5123
5496
  ensurePermissions();
@@ -5129,56 +5502,58 @@ async function initCommand(options) {
5129
5502
  });
5130
5503
  console.log("");
5131
5504
  console.log(title.bold(" Keep your configs fresh\n"));
5132
- console.log(chalk6.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
5505
+ console.log(chalk8.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
5133
5506
  const hookChoice = await promptHookType(targetAgent);
5507
+ trackInitHookSelected(hookChoice);
5134
5508
  if (hookChoice === "claude" || hookChoice === "both") {
5135
5509
  const hookResult = installHook();
5136
5510
  if (hookResult.installed) {
5137
- console.log(` ${chalk6.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
5138
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber hooks --remove") + chalk6.dim(" to disable"));
5511
+ console.log(` ${chalk8.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
5512
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber hooks --remove") + chalk8.dim(" to disable"));
5139
5513
  } else if (hookResult.alreadyInstalled) {
5140
- console.log(chalk6.dim(" Claude Code hook already installed"));
5514
+ console.log(chalk8.dim(" Claude Code hook already installed"));
5141
5515
  }
5142
5516
  const learnResult = installLearningHooks();
5143
5517
  if (learnResult.installed) {
5144
- console.log(` ${chalk6.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
5145
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber learn remove") + chalk6.dim(" to disable"));
5518
+ console.log(` ${chalk8.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
5519
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber learn remove") + chalk8.dim(" to disable"));
5146
5520
  } else if (learnResult.alreadyInstalled) {
5147
- console.log(chalk6.dim(" Learning hooks already installed"));
5521
+ console.log(chalk8.dim(" Learning hooks already installed"));
5148
5522
  }
5149
5523
  }
5150
5524
  if (hookChoice === "precommit" || hookChoice === "both") {
5151
5525
  const precommitResult = installPreCommitHook();
5152
5526
  if (precommitResult.installed) {
5153
- console.log(` ${chalk6.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
5154
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber hooks --remove") + chalk6.dim(" to disable"));
5527
+ console.log(` ${chalk8.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
5528
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber hooks --remove") + chalk8.dim(" to disable"));
5155
5529
  } else if (precommitResult.alreadyInstalled) {
5156
- console.log(chalk6.dim(" Pre-commit hook already installed"));
5530
+ console.log(chalk8.dim(" Pre-commit hook already installed"));
5157
5531
  } else {
5158
- console.log(chalk6.yellow(" Could not install pre-commit hook (not a git repository?)"));
5532
+ console.log(chalk8.yellow(" Could not install pre-commit hook (not a git repository?)"));
5159
5533
  }
5160
5534
  }
5161
5535
  if (hookChoice === "skip") {
5162
- console.log(chalk6.dim(" Skipped auto-refresh hooks. Run ") + chalk6.hex("#83D1EB")("caliber hooks --install") + chalk6.dim(" later to enable."));
5536
+ console.log(chalk8.dim(" Skipped auto-refresh hooks. Run ") + chalk8.hex("#83D1EB")("caliber hooks --install") + chalk8.dim(" later to enable."));
5163
5537
  }
5164
5538
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
5165
5539
  if (afterScore.score < baselineScore.score) {
5540
+ trackInitScoreRegression(baselineScore.score, afterScore.score);
5166
5541
  console.log("");
5167
- console.log(chalk6.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
5542
+ console.log(chalk8.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
5168
5543
  try {
5169
5544
  const { restored, removed } = undoSetup();
5170
5545
  if (restored.length > 0 || removed.length > 0) {
5171
- console.log(chalk6.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
5546
+ console.log(chalk8.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
5172
5547
  }
5173
5548
  } catch {
5174
5549
  }
5175
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber onboard --force") + chalk6.dim(" to override.\n"));
5550
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber onboard --force") + chalk8.dim(" to override.\n"));
5176
5551
  return;
5177
5552
  }
5178
5553
  displayScoreDelta(baselineScore, afterScore);
5179
5554
  console.log(title.bold("\n Step 6/6 \u2014 Community skills\n"));
5180
- console.log(chalk6.dim(" Search public skill registries for skills that match your tech stack.\n"));
5181
- const wantsSkills = await select4({
5555
+ console.log(chalk8.dim(" Search public skill registries for skills that match your tech stack.\n"));
5556
+ const wantsSkills = await select5({
5182
5557
  message: "Search public repos for relevant skills to add to this project?",
5183
5558
  choices: [
5184
5559
  { name: "Yes, find skills for my project", value: true },
@@ -5186,20 +5561,22 @@ async function initCommand(options) {
5186
5561
  ]
5187
5562
  });
5188
5563
  if (wantsSkills) {
5564
+ trackInitSkillsSearch(true, 0);
5189
5565
  try {
5190
5566
  await searchAndInstallSkills();
5191
5567
  } catch (err) {
5192
5568
  if (err.message !== "__exit__") {
5193
- console.log(chalk6.dim(" Skills search failed: " + (err.message || "unknown error")));
5569
+ console.log(chalk8.dim(" Skills search failed: " + (err.message || "unknown error")));
5194
5570
  }
5195
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber skills") + chalk6.dim(" later to try again.\n"));
5571
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber skills") + chalk8.dim(" later to try again.\n"));
5196
5572
  }
5197
5573
  } else {
5198
- console.log(chalk6.dim(" Skipped. Run ") + chalk6.hex("#83D1EB")("caliber skills") + chalk6.dim(" later to browse.\n"));
5574
+ trackInitSkillsSearch(false, 0);
5575
+ console.log(chalk8.dim(" Skipped. Run ") + chalk8.hex("#83D1EB")("caliber skills") + chalk8.dim(" later to browse.\n"));
5199
5576
  }
5200
- console.log(chalk6.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
5201
- console.log(chalk6.dim(" Run ") + chalk6.hex("#83D1EB")("caliber undo") + chalk6.dim(" to revert changes.\n"));
5202
- console.log(chalk6.bold(" Next steps:\n"));
5577
+ console.log(chalk8.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
5578
+ console.log(chalk8.dim(" Run ") + chalk8.hex("#83D1EB")("caliber undo") + chalk8.dim(" to revert changes.\n"));
5579
+ console.log(chalk8.bold(" Next steps:\n"));
5203
5580
  console.log(` ${title("caliber score")} See your full config breakdown`);
5204
5581
  console.log(` ${title("caliber skills")} Discover community skills for your stack`);
5205
5582
  console.log(` ${title("caliber undo")} Revert all changes from this run`);
@@ -5216,9 +5593,9 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
5216
5593
  }
5217
5594
  const isValid = await classifyRefineIntent(message);
5218
5595
  if (!isValid) {
5219
- console.log(chalk6.dim(" This doesn't look like a config change request."));
5220
- console.log(chalk6.dim(" Describe what to add, remove, or modify in your configs."));
5221
- console.log(chalk6.dim(' Type "done" to accept the current setup.\n'));
5596
+ console.log(chalk8.dim(" This doesn't look like a config change request."));
5597
+ console.log(chalk8.dim(" Describe what to add, remove, or modify in your configs."));
5598
+ console.log(chalk8.dim(' Type "done" to accept the current setup.\n'));
5222
5599
  continue;
5223
5600
  }
5224
5601
  const refineSpinner = ora2("Refining setup...").start();
@@ -5239,16 +5616,16 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
5239
5616
  });
5240
5617
  refineSpinner.succeed("Setup updated");
5241
5618
  printSetupSummary(refined);
5242
- console.log(chalk6.dim('Type "done" to accept, or describe more changes.'));
5619
+ console.log(chalk8.dim('Type "done" to accept, or describe more changes.'));
5243
5620
  } else {
5244
5621
  refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
5245
- console.log(chalk6.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
5622
+ console.log(chalk8.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
5246
5623
  }
5247
5624
  }
5248
5625
  }
5249
5626
  function summarizeSetup(action, setup) {
5250
5627
  const descriptions = setup.fileDescriptions;
5251
- const files = descriptions ? Object.entries(descriptions).map(([path23, desc]) => ` ${path23}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
5628
+ const files = descriptions ? Object.entries(descriptions).map(([path24, desc]) => ` ${path24}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
5252
5629
  return `${action}. Files:
5253
5630
  ${files}`;
5254
5631
  }
@@ -5302,7 +5679,7 @@ ${JSON.stringify(checkList, null, 2)}`,
5302
5679
  function promptInput2(question) {
5303
5680
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
5304
5681
  return new Promise((resolve2) => {
5305
- rl.question(chalk6.cyan(`${question} `), (answer) => {
5682
+ rl.question(chalk8.cyan(`${question} `), (answer) => {
5306
5683
  rl.close();
5307
5684
  resolve2(answer.trim());
5308
5685
  });
@@ -5334,13 +5711,13 @@ async function promptHookType(targetAgent) {
5334
5711
  choices.push({ name: "Both (Claude Code + pre-commit)", value: "both" });
5335
5712
  }
5336
5713
  choices.push({ name: "Skip for now", value: "skip" });
5337
- return select4({
5714
+ return select5({
5338
5715
  message: "How would you like to auto-refresh your docs?",
5339
5716
  choices
5340
5717
  });
5341
5718
  }
5342
5719
  async function promptReviewAction() {
5343
- return select4({
5720
+ return select5({
5344
5721
  message: "What would you like to do?",
5345
5722
  choices: [
5346
5723
  { name: "Accept and apply", value: "accept" },
@@ -5355,26 +5732,26 @@ function printSetupSummary(setup) {
5355
5732
  const fileDescriptions = setup.fileDescriptions;
5356
5733
  const deletions = setup.deletions;
5357
5734
  console.log("");
5358
- console.log(chalk6.bold(" Proposed changes:\n"));
5735
+ console.log(chalk8.bold(" Proposed changes:\n"));
5359
5736
  const getDescription = (filePath) => {
5360
5737
  return fileDescriptions?.[filePath];
5361
5738
  };
5362
5739
  if (claude) {
5363
5740
  if (claude.claudeMd) {
5364
- const icon = fs21.existsSync("CLAUDE.md") ? chalk6.yellow("~") : chalk6.green("+");
5741
+ const icon = fs22.existsSync("CLAUDE.md") ? chalk8.yellow("~") : chalk8.green("+");
5365
5742
  const desc = getDescription("CLAUDE.md");
5366
- console.log(` ${icon} ${chalk6.bold("CLAUDE.md")}`);
5367
- if (desc) console.log(chalk6.dim(` ${desc}`));
5743
+ console.log(` ${icon} ${chalk8.bold("CLAUDE.md")}`);
5744
+ if (desc) console.log(chalk8.dim(` ${desc}`));
5368
5745
  console.log("");
5369
5746
  }
5370
5747
  const skills = claude.skills;
5371
5748
  if (Array.isArray(skills) && skills.length > 0) {
5372
5749
  for (const skill of skills) {
5373
5750
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
5374
- const icon = fs21.existsSync(skillPath) ? chalk6.yellow("~") : chalk6.green("+");
5751
+ const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5375
5752
  const desc = getDescription(skillPath);
5376
- console.log(` ${icon} ${chalk6.bold(skillPath)}`);
5377
- console.log(chalk6.dim(` ${desc || skill.description || skill.name}`));
5753
+ console.log(` ${icon} ${chalk8.bold(skillPath)}`);
5754
+ console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
5378
5755
  console.log("");
5379
5756
  }
5380
5757
  }
@@ -5382,40 +5759,40 @@ function printSetupSummary(setup) {
5382
5759
  const codex = setup.codex;
5383
5760
  if (codex) {
5384
5761
  if (codex.agentsMd) {
5385
- const icon = fs21.existsSync("AGENTS.md") ? chalk6.yellow("~") : chalk6.green("+");
5762
+ const icon = fs22.existsSync("AGENTS.md") ? chalk8.yellow("~") : chalk8.green("+");
5386
5763
  const desc = getDescription("AGENTS.md");
5387
- console.log(` ${icon} ${chalk6.bold("AGENTS.md")}`);
5388
- if (desc) console.log(chalk6.dim(` ${desc}`));
5764
+ console.log(` ${icon} ${chalk8.bold("AGENTS.md")}`);
5765
+ if (desc) console.log(chalk8.dim(` ${desc}`));
5389
5766
  console.log("");
5390
5767
  }
5391
5768
  const codexSkills = codex.skills;
5392
5769
  if (Array.isArray(codexSkills) && codexSkills.length > 0) {
5393
5770
  for (const skill of codexSkills) {
5394
5771
  const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
5395
- const icon = fs21.existsSync(skillPath) ? chalk6.yellow("~") : chalk6.green("+");
5772
+ const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5396
5773
  const desc = getDescription(skillPath);
5397
- console.log(` ${icon} ${chalk6.bold(skillPath)}`);
5398
- console.log(chalk6.dim(` ${desc || skill.description || skill.name}`));
5774
+ console.log(` ${icon} ${chalk8.bold(skillPath)}`);
5775
+ console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
5399
5776
  console.log("");
5400
5777
  }
5401
5778
  }
5402
5779
  }
5403
5780
  if (cursor) {
5404
5781
  if (cursor.cursorrules) {
5405
- const icon = fs21.existsSync(".cursorrules") ? chalk6.yellow("~") : chalk6.green("+");
5782
+ const icon = fs22.existsSync(".cursorrules") ? chalk8.yellow("~") : chalk8.green("+");
5406
5783
  const desc = getDescription(".cursorrules");
5407
- console.log(` ${icon} ${chalk6.bold(".cursorrules")}`);
5408
- if (desc) console.log(chalk6.dim(` ${desc}`));
5784
+ console.log(` ${icon} ${chalk8.bold(".cursorrules")}`);
5785
+ if (desc) console.log(chalk8.dim(` ${desc}`));
5409
5786
  console.log("");
5410
5787
  }
5411
5788
  const cursorSkills = cursor.skills;
5412
5789
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
5413
5790
  for (const skill of cursorSkills) {
5414
5791
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
5415
- const icon = fs21.existsSync(skillPath) ? chalk6.yellow("~") : chalk6.green("+");
5792
+ const icon = fs22.existsSync(skillPath) ? chalk8.yellow("~") : chalk8.green("+");
5416
5793
  const desc = getDescription(skillPath);
5417
- console.log(` ${icon} ${chalk6.bold(skillPath)}`);
5418
- console.log(chalk6.dim(` ${desc || skill.description || skill.name}`));
5794
+ console.log(` ${icon} ${chalk8.bold(skillPath)}`);
5795
+ console.log(chalk8.dim(` ${desc || skill.description || skill.name}`));
5419
5796
  console.log("");
5420
5797
  }
5421
5798
  }
@@ -5423,40 +5800,40 @@ function printSetupSummary(setup) {
5423
5800
  if (Array.isArray(rules) && rules.length > 0) {
5424
5801
  for (const rule of rules) {
5425
5802
  const rulePath = `.cursor/rules/${rule.filename}`;
5426
- const icon = fs21.existsSync(rulePath) ? chalk6.yellow("~") : chalk6.green("+");
5803
+ const icon = fs22.existsSync(rulePath) ? chalk8.yellow("~") : chalk8.green("+");
5427
5804
  const desc = getDescription(rulePath);
5428
- console.log(` ${icon} ${chalk6.bold(rulePath)}`);
5805
+ console.log(` ${icon} ${chalk8.bold(rulePath)}`);
5429
5806
  if (desc) {
5430
- console.log(chalk6.dim(` ${desc}`));
5807
+ console.log(chalk8.dim(` ${desc}`));
5431
5808
  } else {
5432
5809
  const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
5433
- if (firstLine) console.log(chalk6.dim(` ${firstLine.trim().slice(0, 80)}`));
5810
+ if (firstLine) console.log(chalk8.dim(` ${firstLine.trim().slice(0, 80)}`));
5434
5811
  }
5435
5812
  console.log("");
5436
5813
  }
5437
5814
  }
5438
5815
  }
5439
- if (!codex && !fs21.existsSync("AGENTS.md")) {
5440
- console.log(` ${chalk6.green("+")} ${chalk6.bold("AGENTS.md")}`);
5441
- console.log(chalk6.dim(" Cross-agent coordination file"));
5816
+ if (!codex && !fs22.existsSync("AGENTS.md")) {
5817
+ console.log(` ${chalk8.green("+")} ${chalk8.bold("AGENTS.md")}`);
5818
+ console.log(chalk8.dim(" Cross-agent coordination file"));
5442
5819
  console.log("");
5443
5820
  }
5444
5821
  if (Array.isArray(deletions) && deletions.length > 0) {
5445
5822
  for (const del of deletions) {
5446
- console.log(` ${chalk6.red("-")} ${chalk6.bold(del.filePath)}`);
5447
- console.log(chalk6.dim(` ${del.reason}`));
5823
+ console.log(` ${chalk8.red("-")} ${chalk8.bold(del.filePath)}`);
5824
+ console.log(chalk8.dim(` ${del.reason}`));
5448
5825
  console.log("");
5449
5826
  }
5450
5827
  }
5451
- console.log(` ${chalk6.green("+")} ${chalk6.dim("new")} ${chalk6.yellow("~")} ${chalk6.dim("modified")} ${chalk6.red("-")} ${chalk6.dim("removed")}`);
5828
+ console.log(` ${chalk8.green("+")} ${chalk8.dim("new")} ${chalk8.yellow("~")} ${chalk8.dim("modified")} ${chalk8.red("-")} ${chalk8.dim("removed")}`);
5452
5829
  console.log("");
5453
5830
  }
5454
5831
  function ensurePermissions() {
5455
5832
  const settingsPath = ".claude/settings.json";
5456
5833
  let settings = {};
5457
5834
  try {
5458
- if (fs21.existsSync(settingsPath)) {
5459
- settings = JSON.parse(fs21.readFileSync(settingsPath, "utf-8"));
5835
+ if (fs22.existsSync(settingsPath)) {
5836
+ settings = JSON.parse(fs22.readFileSync(settingsPath, "utf-8"));
5460
5837
  }
5461
5838
  } catch {
5462
5839
  }
@@ -5470,12 +5847,12 @@ function ensurePermissions() {
5470
5847
  "Bash(git *)"
5471
5848
  ];
5472
5849
  settings.permissions = permissions;
5473
- if (!fs21.existsSync(".claude")) fs21.mkdirSync(".claude", { recursive: true });
5474
- fs21.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5850
+ if (!fs22.existsSync(".claude")) fs22.mkdirSync(".claude", { recursive: true });
5851
+ fs22.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5475
5852
  }
5476
5853
 
5477
5854
  // src/commands/undo.ts
5478
- import chalk7 from "chalk";
5855
+ import chalk9 from "chalk";
5479
5856
  import ora3 from "ora";
5480
5857
  function undoCommand() {
5481
5858
  const spinner = ora3("Reverting setup...").start();
@@ -5485,29 +5862,31 @@ function undoCommand() {
5485
5862
  spinner.info("Nothing to undo.");
5486
5863
  return;
5487
5864
  }
5865
+ trackUndoExecuted();
5488
5866
  spinner.succeed("Setup reverted successfully.\n");
5489
5867
  if (restored.length > 0) {
5490
- console.log(chalk7.cyan(" Restored from backup:"));
5868
+ console.log(chalk9.cyan(" Restored from backup:"));
5491
5869
  for (const file of restored) {
5492
- console.log(` ${chalk7.green("\u21A9")} ${file}`);
5870
+ console.log(` ${chalk9.green("\u21A9")} ${file}`);
5493
5871
  }
5494
5872
  }
5495
5873
  if (removed.length > 0) {
5496
- console.log(chalk7.cyan(" Removed:"));
5874
+ console.log(chalk9.cyan(" Removed:"));
5497
5875
  for (const file of removed) {
5498
- console.log(` ${chalk7.red("\u2717")} ${file}`);
5876
+ console.log(` ${chalk9.red("\u2717")} ${file}`);
5499
5877
  }
5500
5878
  }
5501
5879
  console.log("");
5502
5880
  } catch (err) {
5503
- spinner.fail(chalk7.red(err instanceof Error ? err.message : "Undo failed"));
5881
+ spinner.fail(chalk9.red(err instanceof Error ? err.message : "Undo failed"));
5504
5882
  throw new Error("__exit__");
5505
5883
  }
5506
5884
  }
5507
5885
 
5508
5886
  // src/commands/status.ts
5509
- import chalk8 from "chalk";
5510
- import fs22 from "fs";
5887
+ import chalk10 from "chalk";
5888
+ import fs23 from "fs";
5889
+ init_config();
5511
5890
  async function statusCommand(options) {
5512
5891
  const config = loadConfig();
5513
5892
  const manifest = readManifest();
@@ -5520,49 +5899,51 @@ async function statusCommand(options) {
5520
5899
  }, null, 2));
5521
5900
  return;
5522
5901
  }
5523
- console.log(chalk8.bold("\nCaliber Status\n"));
5902
+ console.log(chalk10.bold("\nCaliber Status\n"));
5524
5903
  if (config) {
5525
- console.log(` LLM: ${chalk8.green(config.provider)} (${config.model})`);
5904
+ console.log(` LLM: ${chalk10.green(config.provider)} (${config.model})`);
5526
5905
  } else {
5527
- console.log(` LLM: ${chalk8.yellow("Not configured")} \u2014 run ${chalk8.hex("#83D1EB")("caliber config")}`);
5906
+ console.log(` LLM: ${chalk10.yellow("Not configured")} \u2014 run ${chalk10.hex("#83D1EB")("caliber config")}`);
5528
5907
  }
5529
5908
  if (!manifest) {
5530
- console.log(` Setup: ${chalk8.dim("No setup applied")}`);
5531
- console.log(chalk8.dim("\n Run ") + chalk8.hex("#83D1EB")("caliber onboard") + chalk8.dim(" to get started.\n"));
5909
+ console.log(` Setup: ${chalk10.dim("No setup applied")}`);
5910
+ console.log(chalk10.dim("\n Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.dim(" to get started.\n"));
5532
5911
  return;
5533
5912
  }
5534
- console.log(` Files managed: ${chalk8.cyan(manifest.entries.length.toString())}`);
5913
+ console.log(` Files managed: ${chalk10.cyan(manifest.entries.length.toString())}`);
5535
5914
  for (const entry of manifest.entries) {
5536
- const exists = fs22.existsSync(entry.path);
5537
- const icon = exists ? chalk8.green("\u2713") : chalk8.red("\u2717");
5915
+ const exists = fs23.existsSync(entry.path);
5916
+ const icon = exists ? chalk10.green("\u2713") : chalk10.red("\u2717");
5538
5917
  console.log(` ${icon} ${entry.path} (${entry.action})`);
5539
5918
  }
5540
5919
  console.log("");
5541
5920
  }
5542
5921
 
5543
5922
  // src/commands/regenerate.ts
5544
- import chalk9 from "chalk";
5923
+ import chalk11 from "chalk";
5545
5924
  import ora4 from "ora";
5546
- import select5 from "@inquirer/select";
5925
+ import select6 from "@inquirer/select";
5926
+ init_config();
5547
5927
  async function regenerateCommand(options) {
5548
5928
  const config = loadConfig();
5549
5929
  if (!config) {
5550
- console.log(chalk9.red("No LLM provider configured. Run ") + chalk9.hex("#83D1EB")("caliber config") + chalk9.red(" first."));
5930
+ console.log(chalk11.red("No LLM provider configured. Run ") + chalk11.hex("#83D1EB")("caliber config") + chalk11.red(" first."));
5551
5931
  throw new Error("__exit__");
5552
5932
  }
5553
5933
  const manifest = readManifest();
5554
5934
  if (!manifest) {
5555
- console.log(chalk9.yellow("No existing setup found. Run ") + chalk9.hex("#83D1EB")("caliber onboard") + chalk9.yellow(" first."));
5935
+ console.log(chalk11.yellow("No existing setup found. Run ") + chalk11.hex("#83D1EB")("caliber onboard") + chalk11.yellow(" first."));
5556
5936
  throw new Error("__exit__");
5557
5937
  }
5558
5938
  const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
5939
+ await validateModel({ fast: true });
5559
5940
  const spinner = ora4("Analyzing project...").start();
5560
5941
  const fingerprint = await collectFingerprint(process.cwd());
5561
5942
  spinner.succeed("Project analyzed");
5562
5943
  const baselineScore = computeLocalScore(process.cwd(), targetAgent);
5563
5944
  displayScoreSummary(baselineScore);
5564
5945
  if (baselineScore.score === 100) {
5565
- console.log(chalk9.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
5946
+ console.log(chalk11.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
5566
5947
  return;
5567
5948
  }
5568
5949
  const genSpinner = ora4("Regenerating setup...").start();
@@ -5603,18 +5984,18 @@ async function regenerateCommand(options) {
5603
5984
  const setupFiles = collectSetupFiles(generatedSetup);
5604
5985
  const staged = stageFiles(setupFiles, process.cwd());
5605
5986
  const totalChanges = staged.newFiles + staged.modifiedFiles;
5606
- console.log(chalk9.dim(`
5607
- ${chalk9.green(`${staged.newFiles} new`)} / ${chalk9.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
5987
+ console.log(chalk11.dim(`
5988
+ ${chalk11.green(`${staged.newFiles} new`)} / ${chalk11.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
5608
5989
  `));
5609
5990
  if (totalChanges === 0) {
5610
- console.log(chalk9.dim(" No changes needed \u2014 your configs are already up to date.\n"));
5991
+ console.log(chalk11.dim(" No changes needed \u2014 your configs are already up to date.\n"));
5611
5992
  cleanupStaging();
5612
5993
  return;
5613
5994
  }
5614
5995
  if (options.dryRun) {
5615
- console.log(chalk9.yellow("[Dry run] Would write:"));
5996
+ console.log(chalk11.yellow("[Dry run] Would write:"));
5616
5997
  for (const f of staged.stagedFiles) {
5617
- console.log(` ${f.isNew ? chalk9.green("+") : chalk9.yellow("~")} ${f.relativePath}`);
5998
+ console.log(` ${f.isNew ? chalk11.green("+") : chalk11.yellow("~")} ${f.relativePath}`);
5618
5999
  }
5619
6000
  cleanupStaging();
5620
6001
  return;
@@ -5624,7 +6005,7 @@ async function regenerateCommand(options) {
5624
6005
  const reviewMethod = await promptReviewMethod();
5625
6006
  await openReview(reviewMethod, staged.stagedFiles);
5626
6007
  }
5627
- const action = await select5({
6008
+ const action = await select6({
5628
6009
  message: "Apply regenerated setup?",
5629
6010
  choices: [
5630
6011
  { name: "Accept and apply", value: "accept" },
@@ -5633,7 +6014,7 @@ async function regenerateCommand(options) {
5633
6014
  });
5634
6015
  cleanupStaging();
5635
6016
  if (action === "decline") {
5636
- console.log(chalk9.dim("Regeneration cancelled. No files were modified."));
6017
+ console.log(chalk11.dim("Regeneration cancelled. No files were modified."));
5637
6018
  return;
5638
6019
  }
5639
6020
  const writeSpinner = ora4("Writing config files...").start();
@@ -5641,20 +6022,20 @@ async function regenerateCommand(options) {
5641
6022
  const result = writeSetup(generatedSetup);
5642
6023
  writeSpinner.succeed("Config files written");
5643
6024
  for (const file of result.written) {
5644
- console.log(` ${chalk9.green("\u2713")} ${file}`);
6025
+ console.log(` ${chalk11.green("\u2713")} ${file}`);
5645
6026
  }
5646
6027
  if (result.deleted.length > 0) {
5647
6028
  for (const file of result.deleted) {
5648
- console.log(` ${chalk9.red("\u2717")} ${file}`);
6029
+ console.log(` ${chalk11.red("\u2717")} ${file}`);
5649
6030
  }
5650
6031
  }
5651
6032
  if (result.backupDir) {
5652
- console.log(chalk9.dim(`
6033
+ console.log(chalk11.dim(`
5653
6034
  Backups saved to ${result.backupDir}`));
5654
6035
  }
5655
6036
  } catch (err) {
5656
6037
  writeSpinner.fail("Failed to write files");
5657
- console.error(chalk9.red(err instanceof Error ? err.message : "Unknown error"));
6038
+ console.error(chalk11.red(err instanceof Error ? err.message : "Unknown error"));
5658
6039
  throw new Error("__exit__");
5659
6040
  }
5660
6041
  const sha = getCurrentHeadSha();
@@ -5666,28 +6047,30 @@ async function regenerateCommand(options) {
5666
6047
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
5667
6048
  if (afterScore.score < baselineScore.score) {
5668
6049
  console.log("");
5669
- console.log(chalk9.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
6050
+ console.log(chalk11.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
5670
6051
  try {
5671
6052
  const { restored, removed } = undoSetup();
5672
6053
  if (restored.length > 0 || removed.length > 0) {
5673
- console.log(chalk9.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
6054
+ console.log(chalk11.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
5674
6055
  }
5675
6056
  } catch {
5676
6057
  }
5677
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber onboard --force") + chalk9.dim(" to override.\n"));
6058
+ console.log(chalk11.dim(" Run ") + chalk11.hex("#83D1EB")("caliber onboard --force") + chalk11.dim(" to override.\n"));
5678
6059
  return;
5679
6060
  }
5680
6061
  displayScoreDelta(baselineScore, afterScore);
5681
- console.log(chalk9.bold.green(" Regeneration complete!"));
5682
- console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber undo") + chalk9.dim(" to revert changes.\n"));
6062
+ trackRegenerateCompleted(action, Date.now());
6063
+ console.log(chalk11.bold.green(" Regeneration complete!"));
6064
+ console.log(chalk11.dim(" Run ") + chalk11.hex("#83D1EB")("caliber undo") + chalk11.dim(" to revert changes.\n"));
5683
6065
  }
5684
6066
 
5685
6067
  // src/commands/score.ts
5686
- import chalk10 from "chalk";
6068
+ import chalk12 from "chalk";
5687
6069
  async function scoreCommand(options) {
5688
6070
  const dir = process.cwd();
5689
6071
  const target = options.agent ?? readState()?.targetAgent;
5690
6072
  const result = computeLocalScore(dir, target);
6073
+ trackScoreComputed(result.score, target);
5691
6074
  if (options.json) {
5692
6075
  console.log(JSON.stringify(result, null, 2));
5693
6076
  return;
@@ -5697,26 +6080,26 @@ async function scoreCommand(options) {
5697
6080
  return;
5698
6081
  }
5699
6082
  displayScore(result);
5700
- const separator = chalk10.gray(" " + "\u2500".repeat(53));
6083
+ const separator = chalk12.gray(" " + "\u2500".repeat(53));
5701
6084
  console.log(separator);
5702
6085
  if (result.score < 40) {
5703
- console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to generate a complete, optimized setup."));
6086
+ console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber onboard") + chalk12.gray(" to generate a complete, optimized setup."));
5704
6087
  } else if (result.score < 70) {
5705
- console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to improve your setup."));
6088
+ console.log(chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber onboard") + chalk12.gray(" to improve your setup."));
5706
6089
  } else {
5707
- console.log(chalk10.green(" Looking good!") + chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber regenerate") + chalk10.gray(" to rebuild from scratch."));
6090
+ console.log(chalk12.green(" Looking good!") + chalk12.gray(" Run ") + chalk12.hex("#83D1EB")("caliber regenerate") + chalk12.gray(" to rebuild from scratch."));
5708
6091
  }
5709
6092
  console.log("");
5710
6093
  }
5711
6094
 
5712
6095
  // src/commands/refresh.ts
5713
- import fs24 from "fs";
5714
- import path18 from "path";
5715
- import chalk11 from "chalk";
6096
+ import fs25 from "fs";
6097
+ import path19 from "path";
6098
+ import chalk13 from "chalk";
5716
6099
  import ora5 from "ora";
5717
6100
 
5718
6101
  // src/lib/git-diff.ts
5719
- import { execSync as execSync8 } from "child_process";
6102
+ import { execSync as execSync9 } from "child_process";
5720
6103
  var MAX_DIFF_BYTES = 1e5;
5721
6104
  var DOC_PATTERNS = [
5722
6105
  "CLAUDE.md",
@@ -5730,7 +6113,7 @@ function excludeArgs() {
5730
6113
  }
5731
6114
  function safeExec(cmd) {
5732
6115
  try {
5733
- return execSync8(cmd, {
6116
+ return execSync9(cmd, {
5734
6117
  encoding: "utf-8",
5735
6118
  stdio: ["pipe", "pipe", "pipe"],
5736
6119
  maxBuffer: 10 * 1024 * 1024
@@ -5788,37 +6171,37 @@ function collectDiff(lastSha) {
5788
6171
  }
5789
6172
 
5790
6173
  // src/writers/refresh.ts
5791
- import fs23 from "fs";
5792
- import path17 from "path";
6174
+ import fs24 from "fs";
6175
+ import path18 from "path";
5793
6176
  function writeRefreshDocs(docs) {
5794
6177
  const written = [];
5795
6178
  if (docs.claudeMd) {
5796
- fs23.writeFileSync("CLAUDE.md", docs.claudeMd);
6179
+ fs24.writeFileSync("CLAUDE.md", docs.claudeMd);
5797
6180
  written.push("CLAUDE.md");
5798
6181
  }
5799
6182
  if (docs.readmeMd) {
5800
- fs23.writeFileSync("README.md", docs.readmeMd);
6183
+ fs24.writeFileSync("README.md", docs.readmeMd);
5801
6184
  written.push("README.md");
5802
6185
  }
5803
6186
  if (docs.cursorrules) {
5804
- fs23.writeFileSync(".cursorrules", docs.cursorrules);
6187
+ fs24.writeFileSync(".cursorrules", docs.cursorrules);
5805
6188
  written.push(".cursorrules");
5806
6189
  }
5807
6190
  if (docs.cursorRules) {
5808
- const rulesDir = path17.join(".cursor", "rules");
5809
- if (!fs23.existsSync(rulesDir)) fs23.mkdirSync(rulesDir, { recursive: true });
6191
+ const rulesDir = path18.join(".cursor", "rules");
6192
+ if (!fs24.existsSync(rulesDir)) fs24.mkdirSync(rulesDir, { recursive: true });
5810
6193
  for (const rule of docs.cursorRules) {
5811
- const filePath = path17.join(rulesDir, rule.filename);
5812
- fs23.writeFileSync(filePath, rule.content);
6194
+ const filePath = path18.join(rulesDir, rule.filename);
6195
+ fs24.writeFileSync(filePath, rule.content);
5813
6196
  written.push(filePath);
5814
6197
  }
5815
6198
  }
5816
6199
  if (docs.claudeSkills) {
5817
- const skillsDir = path17.join(".claude", "skills");
5818
- if (!fs23.existsSync(skillsDir)) fs23.mkdirSync(skillsDir, { recursive: true });
6200
+ const skillsDir = path18.join(".claude", "skills");
6201
+ if (!fs24.existsSync(skillsDir)) fs24.mkdirSync(skillsDir, { recursive: true });
5819
6202
  for (const skill of docs.claudeSkills) {
5820
- const filePath = path17.join(skillsDir, skill.filename);
5821
- fs23.writeFileSync(filePath, skill.content);
6203
+ const filePath = path18.join(skillsDir, skill.filename);
6204
+ fs24.writeFileSync(filePath, skill.content);
5822
6205
  written.push(filePath);
5823
6206
  }
5824
6207
  }
@@ -5826,6 +6209,7 @@ function writeRefreshDocs(docs) {
5826
6209
  }
5827
6210
 
5828
6211
  // src/ai/refresh.ts
6212
+ init_config();
5829
6213
  async function refreshDocs(diff, existingDocs, projectContext) {
5830
6214
  const prompt = buildRefreshPrompt(diff, existingDocs, projectContext);
5831
6215
  const fastModel = getFastModel();
@@ -5889,17 +6273,18 @@ Changed files: ${diff.changedFiles.join(", ")}`);
5889
6273
  }
5890
6274
 
5891
6275
  // src/commands/refresh.ts
6276
+ init_config();
5892
6277
  function log(quiet, ...args) {
5893
6278
  if (!quiet) console.log(...args);
5894
6279
  }
5895
6280
  function discoverGitRepos(parentDir) {
5896
6281
  const repos = [];
5897
6282
  try {
5898
- const entries = fs24.readdirSync(parentDir, { withFileTypes: true });
6283
+ const entries = fs25.readdirSync(parentDir, { withFileTypes: true });
5899
6284
  for (const entry of entries) {
5900
6285
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
5901
- const childPath = path18.join(parentDir, entry.name);
5902
- if (fs24.existsSync(path18.join(childPath, ".git"))) {
6286
+ const childPath = path19.join(parentDir, entry.name);
6287
+ if (fs25.existsSync(path19.join(childPath, ".git"))) {
5903
6288
  repos.push(childPath);
5904
6289
  }
5905
6290
  }
@@ -5909,7 +6294,7 @@ function discoverGitRepos(parentDir) {
5909
6294
  }
5910
6295
  async function refreshSingleRepo(repoDir, options) {
5911
6296
  const quiet = !!options.quiet;
5912
- const prefix = options.label ? `${chalk11.bold(options.label)} ` : "";
6297
+ const prefix = options.label ? `${chalk13.bold(options.label)} ` : "";
5913
6298
  const state = readState();
5914
6299
  const lastSha = state?.lastRefreshSha ?? null;
5915
6300
  const diff = collectDiff(lastSha);
@@ -5918,7 +6303,7 @@ async function refreshSingleRepo(repoDir, options) {
5918
6303
  if (currentSha) {
5919
6304
  writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
5920
6305
  }
5921
- log(quiet, chalk11.dim(`${prefix}No changes since last refresh.`));
6306
+ log(quiet, chalk13.dim(`${prefix}No changes since last refresh.`));
5922
6307
  return;
5923
6308
  }
5924
6309
  const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
@@ -5950,21 +6335,22 @@ async function refreshSingleRepo(repoDir, options) {
5950
6335
  if (options.dryRun) {
5951
6336
  spinner?.info(`${prefix}Dry run \u2014 would update:`);
5952
6337
  for (const doc of response.docsUpdated) {
5953
- console.log(` ${chalk11.yellow("~")} ${doc}`);
6338
+ console.log(` ${chalk13.yellow("~")} ${doc}`);
5954
6339
  }
5955
6340
  if (response.changesSummary) {
5956
- console.log(chalk11.dim(`
6341
+ console.log(chalk13.dim(`
5957
6342
  ${response.changesSummary}`));
5958
6343
  }
5959
6344
  return;
5960
6345
  }
5961
6346
  const written = writeRefreshDocs(response.updatedDocs);
6347
+ trackRefreshCompleted(written.length, Date.now());
5962
6348
  spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
5963
6349
  for (const file of written) {
5964
- log(quiet, ` ${chalk11.green("\u2713")} ${file}`);
6350
+ log(quiet, ` ${chalk13.green("\u2713")} ${file}`);
5965
6351
  }
5966
6352
  if (response.changesSummary) {
5967
- log(quiet, chalk11.dim(`
6353
+ log(quiet, chalk13.dim(`
5968
6354
  ${response.changesSummary}`));
5969
6355
  }
5970
6356
  if (currentSha) {
@@ -5977,9 +6363,10 @@ async function refreshCommand(options) {
5977
6363
  const config = loadConfig();
5978
6364
  if (!config) {
5979
6365
  if (quiet) return;
5980
- console.log(chalk11.red("No LLM provider configured. Run ") + chalk11.hex("#83D1EB")("caliber config") + chalk11.red(" (e.g. choose Cursor) or set an API key."));
6366
+ console.log(chalk13.red("No LLM provider configured. Run ") + chalk13.hex("#83D1EB")("caliber config") + chalk13.red(" (e.g. choose Cursor) or set an API key."));
5981
6367
  throw new Error("__exit__");
5982
6368
  }
6369
+ await validateModel({ fast: true });
5983
6370
  if (isGitRepo()) {
5984
6371
  await refreshSingleRepo(process.cwd(), options);
5985
6372
  return;
@@ -5987,20 +6374,20 @@ async function refreshCommand(options) {
5987
6374
  const repos = discoverGitRepos(process.cwd());
5988
6375
  if (repos.length === 0) {
5989
6376
  if (quiet) return;
5990
- console.log(chalk11.red("Not inside a git repository and no git repos found in child directories."));
6377
+ console.log(chalk13.red("Not inside a git repository and no git repos found in child directories."));
5991
6378
  throw new Error("__exit__");
5992
6379
  }
5993
- log(quiet, chalk11.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
6380
+ log(quiet, chalk13.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
5994
6381
  `));
5995
6382
  const originalDir = process.cwd();
5996
6383
  for (const repo of repos) {
5997
- const repoName = path18.basename(repo);
6384
+ const repoName = path19.basename(repo);
5998
6385
  try {
5999
6386
  process.chdir(repo);
6000
6387
  await refreshSingleRepo(repo, { ...options, label: repoName });
6001
6388
  } catch (err) {
6002
6389
  if (err instanceof Error && err.message === "__exit__") continue;
6003
- log(quiet, chalk11.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
6390
+ log(quiet, chalk13.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
6004
6391
  }
6005
6392
  }
6006
6393
  process.chdir(originalDir);
@@ -6008,13 +6395,13 @@ async function refreshCommand(options) {
6008
6395
  if (err instanceof Error && err.message === "__exit__") throw err;
6009
6396
  if (quiet) return;
6010
6397
  const msg = err instanceof Error ? err.message : "Unknown error";
6011
- console.log(chalk11.red(`Refresh failed: ${msg}`));
6398
+ console.log(chalk13.red(`Refresh failed: ${msg}`));
6012
6399
  throw new Error("__exit__");
6013
6400
  }
6014
6401
  }
6015
6402
 
6016
6403
  // src/commands/hooks.ts
6017
- import chalk12 from "chalk";
6404
+ import chalk14 from "chalk";
6018
6405
  var HOOKS = [
6019
6406
  {
6020
6407
  id: "session-end",
@@ -6034,13 +6421,13 @@ var HOOKS = [
6034
6421
  }
6035
6422
  ];
6036
6423
  function printStatus() {
6037
- console.log(chalk12.bold("\n Hooks\n"));
6424
+ console.log(chalk14.bold("\n Hooks\n"));
6038
6425
  for (const hook of HOOKS) {
6039
6426
  const installed = hook.isInstalled();
6040
- const icon = installed ? chalk12.green("\u2713") : chalk12.dim("\u2717");
6041
- const state = installed ? chalk12.green("enabled") : chalk12.dim("disabled");
6427
+ const icon = installed ? chalk14.green("\u2713") : chalk14.dim("\u2717");
6428
+ const state = installed ? chalk14.green("enabled") : chalk14.dim("disabled");
6042
6429
  console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
6043
- console.log(chalk12.dim(` ${hook.description}`));
6430
+ console.log(chalk14.dim(` ${hook.description}`));
6044
6431
  }
6045
6432
  console.log("");
6046
6433
  }
@@ -6049,9 +6436,9 @@ async function hooksCommand(options) {
6049
6436
  for (const hook of HOOKS) {
6050
6437
  const result = hook.install();
6051
6438
  if (result.alreadyInstalled) {
6052
- console.log(chalk12.dim(` ${hook.label} already enabled.`));
6439
+ console.log(chalk14.dim(` ${hook.label} already enabled.`));
6053
6440
  } else {
6054
- console.log(chalk12.green(" \u2713") + ` ${hook.label} enabled`);
6441
+ console.log(chalk14.green(" \u2713") + ` ${hook.label} enabled`);
6055
6442
  }
6056
6443
  }
6057
6444
  return;
@@ -6060,9 +6447,9 @@ async function hooksCommand(options) {
6060
6447
  for (const hook of HOOKS) {
6061
6448
  const result = hook.remove();
6062
6449
  if (result.notFound) {
6063
- console.log(chalk12.dim(` ${hook.label} already disabled.`));
6450
+ console.log(chalk14.dim(` ${hook.label} already disabled.`));
6064
6451
  } else {
6065
- console.log(chalk12.green(" \u2713") + ` ${hook.label} removed`);
6452
+ console.log(chalk14.green(" \u2713") + ` ${hook.label} removed`);
6066
6453
  }
6067
6454
  }
6068
6455
  return;
@@ -6077,18 +6464,18 @@ async function hooksCommand(options) {
6077
6464
  const states = HOOKS.map((h) => h.isInstalled());
6078
6465
  function render() {
6079
6466
  const lines = [];
6080
- lines.push(chalk12.bold(" Hooks"));
6467
+ lines.push(chalk14.bold(" Hooks"));
6081
6468
  lines.push("");
6082
6469
  for (let i = 0; i < HOOKS.length; i++) {
6083
6470
  const hook = HOOKS[i];
6084
6471
  const enabled = states[i];
6085
- const toggle = enabled ? chalk12.green("[on] ") : chalk12.dim("[off]");
6086
- const ptr = i === cursor ? chalk12.cyan(">") : " ";
6472
+ const toggle = enabled ? chalk14.green("[on] ") : chalk14.dim("[off]");
6473
+ const ptr = i === cursor ? chalk14.cyan(">") : " ";
6087
6474
  lines.push(` ${ptr} ${toggle} ${hook.label}`);
6088
- lines.push(chalk12.dim(` ${hook.description}`));
6475
+ lines.push(chalk14.dim(` ${hook.description}`));
6089
6476
  }
6090
6477
  lines.push("");
6091
- lines.push(chalk12.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
6478
+ lines.push(chalk14.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
6092
6479
  return lines.join("\n");
6093
6480
  }
6094
6481
  function draw(initial) {
@@ -6119,16 +6506,16 @@ async function hooksCommand(options) {
6119
6506
  const wantEnabled = states[i];
6120
6507
  if (wantEnabled && !wasInstalled) {
6121
6508
  hook.install();
6122
- console.log(chalk12.green(" \u2713") + ` ${hook.label} enabled`);
6509
+ console.log(chalk14.green(" \u2713") + ` ${hook.label} enabled`);
6123
6510
  changed++;
6124
6511
  } else if (!wantEnabled && wasInstalled) {
6125
6512
  hook.remove();
6126
- console.log(chalk12.green(" \u2713") + ` ${hook.label} disabled`);
6513
+ console.log(chalk14.green(" \u2713") + ` ${hook.label} disabled`);
6127
6514
  changed++;
6128
6515
  }
6129
6516
  }
6130
6517
  if (changed === 0) {
6131
- console.log(chalk12.dim(" No changes."));
6518
+ console.log(chalk14.dim(" No changes."));
6132
6519
  }
6133
6520
  console.log("");
6134
6521
  }
@@ -6164,7 +6551,7 @@ async function hooksCommand(options) {
6164
6551
  case "\x1B":
6165
6552
  case "":
6166
6553
  cleanup();
6167
- console.log(chalk12.dim("\n Cancelled.\n"));
6554
+ console.log(chalk14.dim("\n Cancelled.\n"));
6168
6555
  resolve2();
6169
6556
  break;
6170
6557
  }
@@ -6174,48 +6561,51 @@ async function hooksCommand(options) {
6174
6561
  }
6175
6562
 
6176
6563
  // src/commands/config.ts
6177
- import chalk13 from "chalk";
6564
+ init_config();
6565
+ import chalk15 from "chalk";
6178
6566
  async function configCommand() {
6179
6567
  const existing = loadConfig();
6180
6568
  if (existing) {
6181
6569
  const displayModel = existing.model === "default" && existing.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : existing.model;
6182
6570
  const fastModel = getFastModel();
6183
- console.log(chalk13.bold("\nCurrent Configuration\n"));
6184
- console.log(` Provider: ${chalk13.cyan(existing.provider)}`);
6185
- console.log(` Model: ${chalk13.cyan(displayModel)}`);
6571
+ console.log(chalk15.bold("\nCurrent Configuration\n"));
6572
+ console.log(` Provider: ${chalk15.cyan(existing.provider)}`);
6573
+ console.log(` Model: ${chalk15.cyan(displayModel)}`);
6186
6574
  if (fastModel) {
6187
- console.log(` Scan: ${chalk13.cyan(fastModel)}`);
6575
+ console.log(` Scan: ${chalk15.cyan(fastModel)}`);
6188
6576
  }
6189
6577
  if (existing.apiKey) {
6190
6578
  const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
6191
- console.log(` API Key: ${chalk13.dim(masked)}`);
6579
+ console.log(` API Key: ${chalk15.dim(masked)}`);
6192
6580
  }
6193
6581
  if (existing.provider === "cursor") {
6194
- console.log(` Seat: ${chalk13.dim("Cursor (agent acp)")}`);
6582
+ console.log(` Seat: ${chalk15.dim("Cursor (agent acp)")}`);
6195
6583
  }
6196
6584
  if (existing.provider === "claude-cli") {
6197
- console.log(` Seat: ${chalk13.dim("Claude Code (claude -p)")}`);
6585
+ console.log(` Seat: ${chalk15.dim("Claude Code (claude -p)")}`);
6198
6586
  }
6199
6587
  if (existing.baseUrl) {
6200
- console.log(` Base URL: ${chalk13.dim(existing.baseUrl)}`);
6588
+ console.log(` Base URL: ${chalk15.dim(existing.baseUrl)}`);
6201
6589
  }
6202
6590
  if (existing.vertexProjectId) {
6203
- console.log(` Vertex Project: ${chalk13.dim(existing.vertexProjectId)}`);
6204
- console.log(` Vertex Region: ${chalk13.dim(existing.vertexRegion || "us-east5")}`);
6591
+ console.log(` Vertex Project: ${chalk15.dim(existing.vertexProjectId)}`);
6592
+ console.log(` Vertex Region: ${chalk15.dim(existing.vertexRegion || "us-east5")}`);
6205
6593
  }
6206
- console.log(` Source: ${chalk13.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID || process.env.CALIBER_USE_CURSOR_SEAT || process.env.CALIBER_USE_CLAUDE_CLI ? "environment variables" : getConfigFilePath())}`);
6594
+ console.log(` Source: ${chalk15.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID || process.env.CALIBER_USE_CURSOR_SEAT || process.env.CALIBER_USE_CLAUDE_CLI ? "environment variables" : getConfigFilePath())}`);
6207
6595
  console.log("");
6208
6596
  }
6209
6597
  await runInteractiveProviderSetup();
6210
- console.log(chalk13.green("\n\u2713 Configuration saved"));
6211
- console.log(chalk13.dim(` ${getConfigFilePath()}
6598
+ const updated = loadConfig();
6599
+ if (updated) trackConfigProviderSet(updated.provider);
6600
+ console.log(chalk15.green("\n\u2713 Configuration saved"));
6601
+ console.log(chalk15.dim(` ${getConfigFilePath()}
6212
6602
  `));
6213
- console.log(chalk13.dim(" You can also set environment variables instead:"));
6214
- console.log(chalk13.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
6603
+ console.log(chalk15.dim(" You can also set environment variables instead:"));
6604
+ console.log(chalk15.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
6215
6605
  }
6216
6606
 
6217
6607
  // src/commands/learn.ts
6218
- import chalk14 from "chalk";
6608
+ import chalk16 from "chalk";
6219
6609
 
6220
6610
  // src/learner/stdin.ts
6221
6611
  var STDIN_TIMEOUT_MS = 5e3;
@@ -6246,8 +6636,8 @@ function readStdin() {
6246
6636
 
6247
6637
  // src/learner/storage.ts
6248
6638
  init_constants();
6249
- import fs25 from "fs";
6250
- import path19 from "path";
6639
+ import fs26 from "fs";
6640
+ import path20 from "path";
6251
6641
  var MAX_RESPONSE_LENGTH = 2e3;
6252
6642
  var DEFAULT_STATE = {
6253
6643
  sessionId: null,
@@ -6255,15 +6645,15 @@ var DEFAULT_STATE = {
6255
6645
  lastAnalysisTimestamp: null
6256
6646
  };
6257
6647
  function ensureLearningDir() {
6258
- if (!fs25.existsSync(LEARNING_DIR)) {
6259
- fs25.mkdirSync(LEARNING_DIR, { recursive: true });
6648
+ if (!fs26.existsSync(LEARNING_DIR)) {
6649
+ fs26.mkdirSync(LEARNING_DIR, { recursive: true });
6260
6650
  }
6261
6651
  }
6262
6652
  function sessionFilePath() {
6263
- return path19.join(LEARNING_DIR, LEARNING_SESSION_FILE);
6653
+ return path20.join(LEARNING_DIR, LEARNING_SESSION_FILE);
6264
6654
  }
6265
6655
  function stateFilePath() {
6266
- return path19.join(LEARNING_DIR, LEARNING_STATE_FILE);
6656
+ return path20.join(LEARNING_DIR, LEARNING_STATE_FILE);
6267
6657
  }
6268
6658
  function truncateResponse(response) {
6269
6659
  const str = JSON.stringify(response);
@@ -6274,50 +6664,50 @@ function appendEvent(event) {
6274
6664
  ensureLearningDir();
6275
6665
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
6276
6666
  const filePath = sessionFilePath();
6277
- fs25.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6667
+ fs26.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6278
6668
  const count = getEventCount();
6279
6669
  if (count > LEARNING_MAX_EVENTS) {
6280
- const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6670
+ const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6281
6671
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
6282
- fs25.writeFileSync(filePath, kept.join("\n") + "\n");
6672
+ fs26.writeFileSync(filePath, kept.join("\n") + "\n");
6283
6673
  }
6284
6674
  }
6285
6675
  function readAllEvents() {
6286
6676
  const filePath = sessionFilePath();
6287
- if (!fs25.existsSync(filePath)) return [];
6288
- const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6677
+ if (!fs26.existsSync(filePath)) return [];
6678
+ const lines = fs26.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6289
6679
  return lines.map((line) => JSON.parse(line));
6290
6680
  }
6291
6681
  function getEventCount() {
6292
6682
  const filePath = sessionFilePath();
6293
- if (!fs25.existsSync(filePath)) return 0;
6294
- const content = fs25.readFileSync(filePath, "utf-8");
6683
+ if (!fs26.existsSync(filePath)) return 0;
6684
+ const content = fs26.readFileSync(filePath, "utf-8");
6295
6685
  return content.split("\n").filter(Boolean).length;
6296
6686
  }
6297
6687
  function clearSession() {
6298
6688
  const filePath = sessionFilePath();
6299
- if (fs25.existsSync(filePath)) fs25.unlinkSync(filePath);
6689
+ if (fs26.existsSync(filePath)) fs26.unlinkSync(filePath);
6300
6690
  }
6301
6691
  function readState2() {
6302
6692
  const filePath = stateFilePath();
6303
- if (!fs25.existsSync(filePath)) return { ...DEFAULT_STATE };
6693
+ if (!fs26.existsSync(filePath)) return { ...DEFAULT_STATE };
6304
6694
  try {
6305
- return JSON.parse(fs25.readFileSync(filePath, "utf-8"));
6695
+ return JSON.parse(fs26.readFileSync(filePath, "utf-8"));
6306
6696
  } catch {
6307
6697
  return { ...DEFAULT_STATE };
6308
6698
  }
6309
6699
  }
6310
6700
  function writeState2(state) {
6311
6701
  ensureLearningDir();
6312
- fs25.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6702
+ fs26.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6313
6703
  }
6314
6704
  function resetState() {
6315
6705
  writeState2({ ...DEFAULT_STATE });
6316
6706
  }
6317
6707
 
6318
6708
  // src/learner/writer.ts
6319
- import fs26 from "fs";
6320
- import path20 from "path";
6709
+ import fs27 from "fs";
6710
+ import path21 from "path";
6321
6711
  var LEARNED_START = "<!-- caliber:learned -->";
6322
6712
  var LEARNED_END = "<!-- /caliber:learned -->";
6323
6713
  function writeLearnedContent(update) {
@@ -6337,8 +6727,8 @@ function writeLearnedContent(update) {
6337
6727
  function writeLearnedSection(content) {
6338
6728
  const claudeMdPath = "CLAUDE.md";
6339
6729
  let existing = "";
6340
- if (fs26.existsSync(claudeMdPath)) {
6341
- existing = fs26.readFileSync(claudeMdPath, "utf-8");
6730
+ if (fs27.existsSync(claudeMdPath)) {
6731
+ existing = fs27.readFileSync(claudeMdPath, "utf-8");
6342
6732
  }
6343
6733
  const section = `${LEARNED_START}
6344
6734
  ${content}
@@ -6352,15 +6742,15 @@ ${LEARNED_END}`;
6352
6742
  const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
6353
6743
  updated = existing + separator + "\n" + section + "\n";
6354
6744
  }
6355
- fs26.writeFileSync(claudeMdPath, updated);
6745
+ fs27.writeFileSync(claudeMdPath, updated);
6356
6746
  }
6357
6747
  function writeLearnedSkill(skill) {
6358
- const skillDir = path20.join(".claude", "skills", skill.name);
6359
- if (!fs26.existsSync(skillDir)) fs26.mkdirSync(skillDir, { recursive: true });
6360
- const skillPath = path20.join(skillDir, "SKILL.md");
6361
- if (!skill.isNew && fs26.existsSync(skillPath)) {
6362
- const existing = fs26.readFileSync(skillPath, "utf-8");
6363
- fs26.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6748
+ const skillDir = path21.join(".claude", "skills", skill.name);
6749
+ if (!fs27.existsSync(skillDir)) fs27.mkdirSync(skillDir, { recursive: true });
6750
+ const skillPath = path21.join(skillDir, "SKILL.md");
6751
+ if (!skill.isNew && fs27.existsSync(skillPath)) {
6752
+ const existing = fs27.readFileSync(skillPath, "utf-8");
6753
+ fs27.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6364
6754
  } else {
6365
6755
  const frontmatter = [
6366
6756
  "---",
@@ -6369,14 +6759,14 @@ function writeLearnedSkill(skill) {
6369
6759
  "---",
6370
6760
  ""
6371
6761
  ].join("\n");
6372
- fs26.writeFileSync(skillPath, frontmatter + skill.content);
6762
+ fs27.writeFileSync(skillPath, frontmatter + skill.content);
6373
6763
  }
6374
6764
  return skillPath;
6375
6765
  }
6376
6766
  function readLearnedSection() {
6377
6767
  const claudeMdPath = "CLAUDE.md";
6378
- if (!fs26.existsSync(claudeMdPath)) return null;
6379
- const content = fs26.readFileSync(claudeMdPath, "utf-8");
6768
+ if (!fs27.existsSync(claudeMdPath)) return null;
6769
+ const content = fs27.readFileSync(claudeMdPath, "utf-8");
6380
6770
  const startIdx = content.indexOf(LEARNED_START);
6381
6771
  const endIdx = content.indexOf(LEARNED_END);
6382
6772
  if (startIdx === -1 || endIdx === -1) return null;
@@ -6384,6 +6774,7 @@ function readLearnedSection() {
6384
6774
  }
6385
6775
 
6386
6776
  // src/ai/learn.ts
6777
+ init_config();
6387
6778
  var MAX_PROMPT_TOKENS = 1e5;
6388
6779
  function formatEventsForPrompt(events) {
6389
6780
  return events.map((e, i) => {
@@ -6457,6 +6848,7 @@ ${eventsText}`;
6457
6848
  }
6458
6849
 
6459
6850
  // src/commands/learn.ts
6851
+ init_config();
6460
6852
  async function learnObserveCommand(options) {
6461
6853
  try {
6462
6854
  const raw = await readStdin();
@@ -6494,6 +6886,7 @@ async function learnFinalizeCommand() {
6494
6886
  resetState();
6495
6887
  return;
6496
6888
  }
6889
+ await validateModel();
6497
6890
  const existingConfigs = readExistingConfigs(process.cwd());
6498
6891
  const existingLearnedSection = readLearnedSection();
6499
6892
  const existingSkills = existingConfigs.claudeSkills || [];
@@ -6518,57 +6911,98 @@ async function learnFinalizeCommand() {
6518
6911
  async function learnInstallCommand() {
6519
6912
  const result = installLearningHooks();
6520
6913
  if (result.alreadyInstalled) {
6521
- console.log(chalk14.dim("Learning hooks already installed."));
6914
+ console.log(chalk16.dim("Learning hooks already installed."));
6522
6915
  return;
6523
6916
  }
6524
- console.log(chalk14.green("\u2713") + " Learning hooks installed in .claude/settings.json");
6525
- console.log(chalk14.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
6526
- console.log(chalk14.dim(" Session learnings will be written to CLAUDE.md and skills."));
6917
+ console.log(chalk16.green("\u2713") + " Learning hooks installed in .claude/settings.json");
6918
+ console.log(chalk16.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
6919
+ console.log(chalk16.dim(" Session learnings will be written to CLAUDE.md and skills."));
6527
6920
  }
6528
6921
  async function learnRemoveCommand() {
6529
6922
  const result = removeLearningHooks();
6530
6923
  if (result.notFound) {
6531
- console.log(chalk14.dim("Learning hooks not found."));
6924
+ console.log(chalk16.dim("Learning hooks not found."));
6532
6925
  return;
6533
6926
  }
6534
- console.log(chalk14.green("\u2713") + " Learning hooks removed from .claude/settings.json");
6927
+ console.log(chalk16.green("\u2713") + " Learning hooks removed from .claude/settings.json");
6535
6928
  }
6536
6929
  async function learnStatusCommand() {
6537
6930
  const installed = areLearningHooksInstalled();
6538
6931
  const state = readState2();
6539
6932
  const eventCount = getEventCount();
6540
- console.log(chalk14.bold("Session Learning Status"));
6933
+ console.log(chalk16.bold("Session Learning Status"));
6541
6934
  console.log();
6542
6935
  if (installed) {
6543
- console.log(chalk14.green("\u2713") + " Learning hooks are " + chalk14.green("installed"));
6936
+ console.log(chalk16.green("\u2713") + " Learning hooks are " + chalk16.green("installed"));
6544
6937
  } else {
6545
- console.log(chalk14.dim("\u2717") + " Learning hooks are " + chalk14.yellow("not installed"));
6546
- console.log(chalk14.dim(" Run `caliber learn install` to enable session learning."));
6938
+ console.log(chalk16.dim("\u2717") + " Learning hooks are " + chalk16.yellow("not installed"));
6939
+ console.log(chalk16.dim(" Run `caliber learn install` to enable session learning."));
6547
6940
  }
6548
6941
  console.log();
6549
- console.log(`Events recorded: ${chalk14.cyan(String(eventCount))}`);
6550
- console.log(`Total this session: ${chalk14.cyan(String(state.eventCount))}`);
6942
+ console.log(`Events recorded: ${chalk16.cyan(String(eventCount))}`);
6943
+ console.log(`Total this session: ${chalk16.cyan(String(state.eventCount))}`);
6551
6944
  if (state.lastAnalysisTimestamp) {
6552
- console.log(`Last analysis: ${chalk14.cyan(state.lastAnalysisTimestamp)}`);
6945
+ console.log(`Last analysis: ${chalk16.cyan(state.lastAnalysisTimestamp)}`);
6553
6946
  } else {
6554
- console.log(`Last analysis: ${chalk14.dim("none")}`);
6947
+ console.log(`Last analysis: ${chalk16.dim("none")}`);
6555
6948
  }
6556
6949
  const learnedSection = readLearnedSection();
6557
6950
  if (learnedSection) {
6558
6951
  const lineCount = learnedSection.split("\n").filter(Boolean).length;
6559
6952
  console.log(`
6560
- Learned items in CLAUDE.md: ${chalk14.cyan(String(lineCount))}`);
6953
+ Learned items in CLAUDE.md: ${chalk16.cyan(String(lineCount))}`);
6561
6954
  }
6562
6955
  }
6563
6956
 
6564
6957
  // src/cli.ts
6565
- var __dirname = path21.dirname(fileURLToPath(import.meta.url));
6958
+ var __dirname = path22.dirname(fileURLToPath(import.meta.url));
6566
6959
  var pkg = JSON.parse(
6567
- fs27.readFileSync(path21.resolve(__dirname, "..", "package.json"), "utf-8")
6960
+ fs28.readFileSync(path22.resolve(__dirname, "..", "package.json"), "utf-8")
6568
6961
  );
6569
6962
  var program = new Command();
6570
6963
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
6571
- program.name(process.env.CALIBER_LOCAL ? "caloc" : "caliber").description("Configure your coding agent environment").version(displayVersion);
6964
+ program.name(process.env.CALIBER_LOCAL ? "caloc" : "caliber").description("Configure your coding agent environment").version(displayVersion).option("--no-traces", "Disable anonymous telemetry for this run");
6965
+ function tracked(commandName, handler) {
6966
+ const wrapper = async (...args) => {
6967
+ const start = Date.now();
6968
+ trackEvent("command_started", {
6969
+ command: commandName,
6970
+ cli_version: pkg.version
6971
+ });
6972
+ try {
6973
+ await handler(...args);
6974
+ trackEvent("command_completed", {
6975
+ command: commandName,
6976
+ duration_ms: Date.now() - start,
6977
+ success: true
6978
+ });
6979
+ } catch (err) {
6980
+ const errorMessage = err instanceof Error ? err.message : "Unknown error";
6981
+ const errorType = err instanceof Error ? err.constructor.name : typeof err;
6982
+ if (errorMessage !== "__exit__") {
6983
+ trackEvent("command_error", {
6984
+ command: commandName,
6985
+ error_type: errorType,
6986
+ error_message: errorMessage
6987
+ });
6988
+ }
6989
+ trackEvent("command_completed", {
6990
+ command: commandName,
6991
+ duration_ms: Date.now() - start,
6992
+ success: false
6993
+ });
6994
+ throw err;
6995
+ }
6996
+ };
6997
+ return wrapper;
6998
+ }
6999
+ program.hook("preAction", (thisCommand) => {
7000
+ const opts = thisCommand.optsWithGlobals();
7001
+ if (opts.traces === false) {
7002
+ setTelemetryDisabled(true);
7003
+ }
7004
+ initTelemetry();
7005
+ });
6572
7006
  function parseAgentOption(value) {
6573
7007
  if (value === "both") return ["claude", "cursor"];
6574
7008
  if (value === "all") return ["claude", "cursor", "codex"];
@@ -6580,39 +7014,39 @@ function parseAgentOption(value) {
6580
7014
  }
6581
7015
  return agents;
6582
7016
  }
6583
- program.command("onboard").alias("init").description("Onboard your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(initCommand);
6584
- program.command("undo").description("Revert all config changes made by Caliber").action(undoCommand);
6585
- program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(statusCommand);
6586
- program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(regenerateCommand);
6587
- program.command("config").description("Configure LLM provider, API key, and model").action(configCommand);
6588
- program.command("skills").description("Discover and install community skills for your project").action(recommendCommand);
6589
- program.command("score").description("Score your current agent config setup (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).action(scoreCommand);
6590
- program.command("refresh").description("Update docs based on recent code changes").option("--quiet", "Suppress output (for use in hooks)").option("--dry-run", "Preview changes without writing files").action(refreshCommand);
6591
- program.command("hooks").description("Manage auto-refresh hooks (toggle interactively)").option("--install", "Enable all hooks non-interactively").option("--remove", "Disable all hooks non-interactively").action(hooksCommand);
7017
+ program.command("onboard").alias("init").description("Onboard your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing setup without prompting").action(tracked("onboard", initCommand));
7018
+ program.command("undo").description("Revert all config changes made by Caliber").action(tracked("undo", undoCommand));
7019
+ program.command("status").description("Show current Caliber setup status").option("--json", "Output as JSON").action(tracked("status", statusCommand));
7020
+ program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate setup").option("--dry-run", "Preview changes without writing files").action(tracked("regenerate", regenerateCommand));
7021
+ program.command("config").description("Configure LLM provider, API key, and model").action(tracked("config", configCommand));
7022
+ program.command("skills").description("Discover and install community skills for your project").action(tracked("skills", recommendCommand));
7023
+ program.command("score").description("Score your current agent config setup (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex", parseAgentOption).action(tracked("score", scoreCommand));
7024
+ program.command("refresh").description("Update docs based on recent code changes").option("--quiet", "Suppress output (for use in hooks)").option("--dry-run", "Preview changes without writing files").action(tracked("refresh", refreshCommand));
7025
+ program.command("hooks").description("Manage auto-refresh hooks (toggle interactively)").option("--install", "Enable all hooks non-interactively").option("--remove", "Disable all hooks non-interactively").action(tracked("hooks", hooksCommand));
6592
7026
  var learn = program.command("learn", { hidden: true }).description("[dev] Session learning \u2014 observe tool usage and extract reusable instructions");
6593
- learn.command("observe").description("Record a tool event from stdin (called by hooks)").option("--failure", "Mark event as a tool failure").action(learnObserveCommand);
6594
- learn.command("finalize").description("Analyze session events and update CLAUDE.md (called on SessionEnd)").action(learnFinalizeCommand);
6595
- learn.command("install").description("Install learning hooks into .claude/settings.json").action(learnInstallCommand);
6596
- learn.command("remove").description("Remove learning hooks from .claude/settings.json").action(learnRemoveCommand);
6597
- learn.command("status").description("Show learning system status").action(learnStatusCommand);
7027
+ learn.command("observe").description("Record a tool event from stdin (called by hooks)").option("--failure", "Mark event as a tool failure").action(tracked("learn:observe", learnObserveCommand));
7028
+ learn.command("finalize").description("Analyze session events and update CLAUDE.md (called on SessionEnd)").action(tracked("learn:finalize", learnFinalizeCommand));
7029
+ learn.command("install").description("Install learning hooks into .claude/settings.json").action(tracked("learn:install", learnInstallCommand));
7030
+ learn.command("remove").description("Remove learning hooks from .claude/settings.json").action(tracked("learn:remove", learnRemoveCommand));
7031
+ learn.command("status").description("Show learning system status").action(tracked("learn:status", learnStatusCommand));
6598
7032
 
6599
7033
  // src/utils/version-check.ts
6600
- import fs28 from "fs";
6601
- import path22 from "path";
7034
+ import fs29 from "fs";
7035
+ import path23 from "path";
6602
7036
  import { fileURLToPath as fileURLToPath2 } from "url";
6603
- import { execSync as execSync9 } from "child_process";
6604
- import chalk15 from "chalk";
7037
+ import { execSync as execSync10 } from "child_process";
7038
+ import chalk17 from "chalk";
6605
7039
  import ora6 from "ora";
6606
7040
  import confirm from "@inquirer/confirm";
6607
- var __dirname_vc = path22.dirname(fileURLToPath2(import.meta.url));
7041
+ var __dirname_vc = path23.dirname(fileURLToPath2(import.meta.url));
6608
7042
  var pkg2 = JSON.parse(
6609
- fs28.readFileSync(path22.resolve(__dirname_vc, "..", "package.json"), "utf-8")
7043
+ fs29.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
6610
7044
  );
6611
7045
  function getInstalledVersion() {
6612
7046
  try {
6613
- const globalRoot = execSync9("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
6614
- const pkgPath = path22.join(globalRoot, "@rely-ai", "caliber", "package.json");
6615
- return JSON.parse(fs28.readFileSync(pkgPath, "utf-8")).version;
7047
+ const globalRoot = execSync10("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
7048
+ const pkgPath = path23.join(globalRoot, "@rely-ai", "caliber", "package.json");
7049
+ return JSON.parse(fs29.readFileSync(pkgPath, "utf-8")).version;
6616
7050
  } catch {
6617
7051
  return null;
6618
7052
  }
@@ -6635,17 +7069,17 @@ async function checkForUpdates() {
6635
7069
  const isInteractive = process.stdin.isTTY === true;
6636
7070
  if (!isInteractive) {
6637
7071
  console.log(
6638
- chalk15.yellow(
7072
+ chalk17.yellow(
6639
7073
  `
6640
7074
  Update available: ${current} -> ${latest}
6641
- Run ${chalk15.bold("npm install -g @rely-ai/caliber")} to upgrade.
7075
+ Run ${chalk17.bold("npm install -g @rely-ai/caliber")} to upgrade.
6642
7076
  `
6643
7077
  )
6644
7078
  );
6645
7079
  return;
6646
7080
  }
6647
7081
  console.log(
6648
- chalk15.yellow(`
7082
+ chalk17.yellow(`
6649
7083
  Update available: ${current} -> ${latest}`)
6650
7084
  );
6651
7085
  const shouldUpdate = await confirm({ message: "Would you like to update now? (Y/n)", default: true });
@@ -6655,7 +7089,7 @@ Update available: ${current} -> ${latest}`)
6655
7089
  }
6656
7090
  const spinner = ora6("Updating caliber...").start();
6657
7091
  try {
6658
- execSync9(`npm install -g @rely-ai/caliber@${latest}`, {
7092
+ execSync10(`npm install -g @rely-ai/caliber@${latest}`, {
6659
7093
  stdio: "pipe",
6660
7094
  timeout: 12e4,
6661
7095
  env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
@@ -6663,16 +7097,16 @@ Update available: ${current} -> ${latest}`)
6663
7097
  const installed = getInstalledVersion();
6664
7098
  if (installed !== latest) {
6665
7099
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
6666
- console.log(chalk15.yellow(`Run ${chalk15.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
7100
+ console.log(chalk17.yellow(`Run ${chalk17.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
6667
7101
  `));
6668
7102
  return;
6669
7103
  }
6670
- spinner.succeed(chalk15.green(`Updated to ${latest}`));
7104
+ spinner.succeed(chalk17.green(`Updated to ${latest}`));
6671
7105
  const args = process.argv.slice(2);
6672
- console.log(chalk15.dim(`
7106
+ console.log(chalk17.dim(`
6673
7107
  Restarting: caliber ${args.join(" ")}
6674
7108
  `));
6675
- execSync9(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
7109
+ execSync10(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
6676
7110
  stdio: "inherit",
6677
7111
  env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
6678
7112
  });
@@ -6682,11 +7116,11 @@ Restarting: caliber ${args.join(" ")}
6682
7116
  if (err instanceof Error) {
6683
7117
  const stderr = err.stderr;
6684
7118
  const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
6685
- if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk15.dim(` ${errMsg}`));
7119
+ if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk17.dim(` ${errMsg}`));
6686
7120
  }
6687
7121
  console.log(
6688
- chalk15.yellow(
6689
- `Run ${chalk15.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
7122
+ chalk17.yellow(
7123
+ `Run ${chalk17.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
6690
7124
  `
6691
7125
  )
6692
7126
  );
@@ -6706,5 +7140,8 @@ program.parseAsync().catch((err) => {
6706
7140
  console.error(msg);
6707
7141
  }
6708
7142
  process.exitCode = 1;
6709
- }).finally(() => process.exit(Number(process.exitCode ?? 0)));
7143
+ }).finally(async () => {
7144
+ await flushTelemetry();
7145
+ process.exit(Number(process.exitCode ?? 0));
7146
+ });
6710
7147
  //# sourceMappingURL=bin.js.map