@rely-ai/caliber 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +23 -12
  2. package/dist/bin.js +629 -317
  3. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -56,10 +56,10 @@ import path21 from "path";
56
56
  import { fileURLToPath } from "url";
57
57
 
58
58
  // src/commands/init.ts
59
- import chalk3 from "chalk";
59
+ import chalk4 from "chalk";
60
60
  import ora from "ora";
61
- import readline from "readline";
62
- import select from "@inquirer/select";
61
+ import readline3 from "readline";
62
+ import select2 from "@inquirer/select";
63
63
  import fs17 from "fs";
64
64
 
65
65
  // src/fingerprint/index.ts
@@ -586,7 +586,9 @@ var CONFIG_FILE = path6.join(CONFIG_DIR, "config.json");
586
586
  var DEFAULT_MODELS = {
587
587
  anthropic: "claude-sonnet-4-6",
588
588
  vertex: "claude-sonnet-4-6",
589
- openai: "gpt-4.1"
589
+ openai: "gpt-4.1",
590
+ cursor: "default",
591
+ "claude-cli": "default"
590
592
  };
591
593
  function loadConfig() {
592
594
  const envConfig = resolveFromEnv();
@@ -618,6 +620,18 @@ function resolveFromEnv() {
618
620
  baseUrl: process.env.OPENAI_BASE_URL
619
621
  };
620
622
  }
623
+ if (process.env.CALIBER_USE_CURSOR_SEAT === "1" || process.env.CALIBER_USE_CURSOR_SEAT === "true") {
624
+ return {
625
+ provider: "cursor",
626
+ model: DEFAULT_MODELS.cursor
627
+ };
628
+ }
629
+ if (process.env.CALIBER_USE_CLAUDE_CLI === "1" || process.env.CALIBER_USE_CLAUDE_CLI === "true") {
630
+ return {
631
+ provider: "claude-cli",
632
+ model: DEFAULT_MODELS["claude-cli"]
633
+ };
634
+ }
621
635
  return null;
622
636
  }
623
637
  function readConfigFile() {
@@ -625,7 +639,7 @@ function readConfigFile() {
625
639
  if (!fs5.existsSync(CONFIG_FILE)) return null;
626
640
  const raw = fs5.readFileSync(CONFIG_FILE, "utf-8");
627
641
  const parsed = JSON.parse(raw);
628
- if (!parsed.provider || !["anthropic", "vertex", "openai"].includes(parsed.provider)) {
642
+ if (!parsed.provider || !["anthropic", "vertex", "openai", "cursor", "claude-cli"].includes(parsed.provider)) {
629
643
  return null;
630
644
  }
631
645
  return parsed;
@@ -817,6 +831,252 @@ var OpenAICompatProvider = class {
817
831
  }
818
832
  };
819
833
 
834
+ // src/llm/cursor-acp.ts
835
+ import { spawn, execSync as execSync2 } from "child_process";
836
+ import readline from "readline";
837
+ var ACP_AGENT_BIN = "agent";
838
+ var CursorAcpProvider = class {
839
+ defaultModel;
840
+ cursorApiKey;
841
+ constructor(config) {
842
+ this.defaultModel = config.model || "default";
843
+ this.cursorApiKey = process.env.CURSOR_API_KEY ?? process.env.CURSOR_AUTH_TOKEN;
844
+ }
845
+ async call(options) {
846
+ const chunks = [];
847
+ await this.runAcpPrompt(options, {
848
+ onText: (text) => chunks.push(text),
849
+ onEnd: () => {
850
+ },
851
+ onError: () => {
852
+ }
853
+ });
854
+ return chunks.join("");
855
+ }
856
+ async stream(options, callbacks) {
857
+ await this.runAcpPrompt(options, callbacks);
858
+ }
859
+ async runAcpPrompt(options, callbacks) {
860
+ const combinedPrompt = this.buildCombinedPrompt(options);
861
+ const args = ["acp"];
862
+ if (this.cursorApiKey) {
863
+ args.unshift("--api-key", this.cursorApiKey);
864
+ }
865
+ const agent = spawn(ACP_AGENT_BIN, args, {
866
+ stdio: ["pipe", "pipe", "inherit"],
867
+ cwd: process.cwd(),
868
+ env: { ...process.env, ...this.cursorApiKey && { CURSOR_API_KEY: this.cursorApiKey } }
869
+ });
870
+ const pending = /* @__PURE__ */ new Map();
871
+ let nextId = 1;
872
+ let sessionId = null;
873
+ const send = (method, params) => {
874
+ return new Promise((resolve2, reject) => {
875
+ const id = nextId++;
876
+ pending.set(id, { resolve: resolve2, reject });
877
+ const msg = { jsonrpc: "2.0", id, method, params };
878
+ agent.stdin.write(JSON.stringify(msg) + "\n", (err) => {
879
+ if (err) {
880
+ pending.delete(id);
881
+ reject(err);
882
+ }
883
+ });
884
+ });
885
+ };
886
+ const rl = readline.createInterface({ input: agent.stdout, crlfDelay: Infinity });
887
+ rl.on("line", (line) => {
888
+ let msg;
889
+ try {
890
+ msg = JSON.parse(line);
891
+ } catch {
892
+ return;
893
+ }
894
+ if (msg.id != null && (msg.result !== void 0 || msg.error !== void 0)) {
895
+ const waiter = pending.get(msg.id);
896
+ if (waiter) {
897
+ pending.delete(msg.id);
898
+ if (msg.error) {
899
+ waiter.reject(new Error(msg.error.message || "ACP error"));
900
+ } else {
901
+ waiter.resolve(msg.result);
902
+ }
903
+ }
904
+ if (msg.result && typeof msg.result === "object" && "sessionId" in msg.result) {
905
+ sessionId = msg.result.sessionId;
906
+ }
907
+ if (msg.result && typeof msg.result === "object" && "stopReason" in msg.result) {
908
+ callbacks.onEnd({
909
+ stopReason: msg.result.stopReason
910
+ });
911
+ }
912
+ return;
913
+ }
914
+ if (msg.method === "session/update" && msg.params?.update) {
915
+ const update = msg.params.update;
916
+ if (update.sessionUpdate === "agent_message_chunk" && update.content?.text) {
917
+ callbacks.onText(update.content.text);
918
+ }
919
+ return;
920
+ }
921
+ if (msg.method === "session/request_permission" && msg.id != null) {
922
+ const response = JSON.stringify({
923
+ jsonrpc: "2.0",
924
+ id: msg.id,
925
+ result: { outcome: { outcome: "selected", optionId: "allow-once" } }
926
+ }) + "\n";
927
+ agent.stdin.write(response);
928
+ }
929
+ });
930
+ agent.on("error", (err) => {
931
+ for (const w of pending.values()) w.reject(err);
932
+ callbacks.onError(err);
933
+ });
934
+ agent.on("close", (code) => {
935
+ if (code !== 0 && code !== null) {
936
+ const err = new Error(`Cursor agent exited with code ${code}`);
937
+ for (const w of pending.values()) w.reject(err);
938
+ callbacks.onError(err);
939
+ }
940
+ });
941
+ try {
942
+ await send("initialize", {
943
+ protocolVersion: 1,
944
+ clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false },
945
+ clientInfo: { name: "caliber", version: "1.0.0" }
946
+ });
947
+ await send("authenticate", { methodId: "cursor_login" });
948
+ const sessionResult = await send("session/new", {
949
+ cwd: process.cwd(),
950
+ mcpServers: []
951
+ });
952
+ sessionId = sessionResult.sessionId;
953
+ await send("session/prompt", {
954
+ sessionId,
955
+ prompt: [{ type: "text", text: combinedPrompt }]
956
+ });
957
+ } catch (err) {
958
+ const error = err instanceof Error ? err : new Error(String(err));
959
+ callbacks.onError(error);
960
+ throw error;
961
+ } finally {
962
+ agent.stdin?.end();
963
+ agent.kill("SIGTERM");
964
+ }
965
+ }
966
+ buildCombinedPrompt(options) {
967
+ const streamOpts = options;
968
+ const hasHistory = streamOpts.messages && streamOpts.messages.length > 0;
969
+ let combined = "";
970
+ combined += "[[System]]\n" + options.system + "\n\n";
971
+ if (hasHistory) {
972
+ for (const msg of streamOpts.messages) {
973
+ combined += `[[${msg.role === "user" ? "User" : "Assistant"}]]
974
+ ${msg.content}
975
+
976
+ `;
977
+ }
978
+ }
979
+ combined += "[[User]]\n" + options.prompt;
980
+ return combined;
981
+ }
982
+ };
983
+ function isCursorAgentAvailable() {
984
+ try {
985
+ execSync2(`which ${ACP_AGENT_BIN}`, { stdio: "ignore" });
986
+ return true;
987
+ } catch {
988
+ return false;
989
+ }
990
+ }
991
+
992
+ // src/llm/claude-cli.ts
993
+ import { spawn as spawn2, execSync as execSync3 } from "child_process";
994
+ var CLAUDE_CLI_BIN = "claude";
995
+ var DEFAULT_TIMEOUT_MS = 5 * 60 * 1e3;
996
+ var ClaudeCliProvider = class {
997
+ defaultModel;
998
+ timeoutMs;
999
+ constructor(config) {
1000
+ this.defaultModel = config.model || "default";
1001
+ const envTimeout = process.env.CALIBER_CLAUDE_CLI_TIMEOUT_MS;
1002
+ this.timeoutMs = envTimeout ? parseInt(envTimeout, 10) : DEFAULT_TIMEOUT_MS;
1003
+ if (!Number.isFinite(this.timeoutMs) || this.timeoutMs < 1e3) {
1004
+ this.timeoutMs = DEFAULT_TIMEOUT_MS;
1005
+ }
1006
+ }
1007
+ async call(options) {
1008
+ const combined = this.buildCombinedPrompt(options);
1009
+ return this.runClaudePrint(combined);
1010
+ }
1011
+ async stream(options, callbacks) {
1012
+ try {
1013
+ const text = await this.call(options);
1014
+ if (text) callbacks.onText(text);
1015
+ callbacks.onEnd({ stopReason: "end_turn" });
1016
+ } catch (err) {
1017
+ callbacks.onError(err instanceof Error ? err : new Error(String(err)));
1018
+ }
1019
+ }
1020
+ buildCombinedPrompt(options) {
1021
+ const streamOpts = options;
1022
+ const hasHistory = streamOpts.messages && streamOpts.messages.length > 0;
1023
+ let combined = "";
1024
+ combined += "[[System]]\n" + options.system + "\n\n";
1025
+ if (hasHistory) {
1026
+ for (const msg of streamOpts.messages) {
1027
+ combined += `[[${msg.role === "user" ? "User" : "Assistant"}]]
1028
+ ${msg.content}
1029
+
1030
+ `;
1031
+ }
1032
+ }
1033
+ combined += "[[User]]\n" + options.prompt;
1034
+ return combined;
1035
+ }
1036
+ runClaudePrint(combinedPrompt) {
1037
+ return new Promise((resolve2, reject) => {
1038
+ const child = spawn2(CLAUDE_CLI_BIN, ["-p", combinedPrompt], {
1039
+ cwd: process.cwd(),
1040
+ stdio: ["ignore", "pipe", "inherit"],
1041
+ env: process.env
1042
+ });
1043
+ const chunks = [];
1044
+ child.stdout.on("data", (chunk) => chunks.push(chunk));
1045
+ child.on("error", (err) => {
1046
+ clearTimeout(timer);
1047
+ reject(err);
1048
+ });
1049
+ child.on("close", (code, signal) => {
1050
+ clearTimeout(timer);
1051
+ const stdout = Buffer.concat(chunks).toString("utf-8").trim();
1052
+ if (code === 0) {
1053
+ resolve2(stdout);
1054
+ } else {
1055
+ const msg = signal ? `Claude CLI killed (${signal})` : code != null ? `Claude CLI exited with code ${code}` : "Claude CLI exited";
1056
+ reject(new Error(stdout ? `${msg}. Output: ${stdout.slice(0, 200)}` : msg));
1057
+ }
1058
+ });
1059
+ const timer = setTimeout(() => {
1060
+ child.kill("SIGTERM");
1061
+ reject(
1062
+ new Error(
1063
+ `Claude CLI timed out after ${this.timeoutMs / 1e3}s. Set CALIBER_CLAUDE_CLI_TIMEOUT_MS to increase.`
1064
+ )
1065
+ );
1066
+ }, this.timeoutMs);
1067
+ });
1068
+ }
1069
+ };
1070
+ function isClaudeCliAvailable() {
1071
+ try {
1072
+ const cmd = process.platform === "win32" ? `where ${CLAUDE_CLI_BIN}` : `which ${CLAUDE_CLI_BIN}`;
1073
+ execSync3(cmd, { stdio: "ignore" });
1074
+ return true;
1075
+ } catch {
1076
+ return false;
1077
+ }
1078
+ }
1079
+
820
1080
  // src/llm/utils.ts
821
1081
  function extractJson(text) {
822
1082
  const startIdx = text.search(/[\[{]/);
@@ -877,6 +1137,22 @@ function createProvider(config) {
877
1137
  return new VertexProvider(config);
878
1138
  case "openai":
879
1139
  return new OpenAICompatProvider(config);
1140
+ case "cursor": {
1141
+ if (!isCursorAgentAvailable()) {
1142
+ throw new Error(
1143
+ "Cursor provider requires the Cursor Agent CLI. Install it from https://cursor.com/install then run `agent login`. Alternatively set ANTHROPIC_API_KEY or another provider."
1144
+ );
1145
+ }
1146
+ return new CursorAcpProvider(config);
1147
+ }
1148
+ case "claude-cli": {
1149
+ if (!isClaudeCliAvailable()) {
1150
+ throw new Error(
1151
+ "Claude Code provider requires the Claude Code CLI. Install it from https://claude.ai/install (or run `claude` once and log in). Alternatively set ANTHROPIC_API_KEY or choose another provider."
1152
+ );
1153
+ }
1154
+ return new ClaudeCliProvider(config);
1155
+ }
880
1156
  default:
881
1157
  throw new Error(`Unknown provider: ${config.provider}`);
882
1158
  }
@@ -886,7 +1162,7 @@ function getProvider() {
886
1162
  const config = loadConfig();
887
1163
  if (!config) {
888
1164
  throw new Error(
889
- "No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or VERTEX_PROJECT_ID as an environment variable, or run `caliber config` to configure."
1165
+ "No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or VERTEX_PROJECT_ID; or run `caliber config` and choose Cursor or Claude Code; or set CALIBER_USE_CURSOR_SEAT=1 / CALIBER_USE_CLAUDE_CLI=1."
890
1166
  );
891
1167
  }
892
1168
  cachedConfig = config;
@@ -1818,10 +2094,10 @@ function cleanupStaging() {
1818
2094
  }
1819
2095
 
1820
2096
  // src/utils/editor.ts
1821
- import { execSync as execSync2, spawn } from "child_process";
2097
+ import { execSync as execSync4, spawn as spawn3 } from "child_process";
1822
2098
  function commandExists(cmd) {
1823
2099
  try {
1824
- execSync2(`which ${cmd}`, { stdio: "ignore" });
2100
+ execSync4(`which ${cmd}`, { stdio: "ignore" });
1825
2101
  return true;
1826
2102
  } catch {
1827
2103
  return false;
@@ -1839,12 +2115,12 @@ function openDiffsInEditor(editor, files) {
1839
2115
  for (const file of files) {
1840
2116
  try {
1841
2117
  if (file.originalPath) {
1842
- spawn(cmd, ["--diff", file.originalPath, file.proposedPath], {
2118
+ spawn3(cmd, ["--diff", file.originalPath, file.proposedPath], {
1843
2119
  stdio: "ignore",
1844
2120
  detached: true
1845
2121
  }).unref();
1846
2122
  } else {
1847
- spawn(cmd, [file.proposedPath], {
2123
+ spawn3(cmd, [file.proposedPath], {
1848
2124
  stdio: "ignore",
1849
2125
  detached: true
1850
2126
  }).unref();
@@ -1861,7 +2137,7 @@ import { createTwoFilesPatch } from "diff";
1861
2137
  // src/lib/hooks.ts
1862
2138
  import fs14 from "fs";
1863
2139
  import path13 from "path";
1864
- import { execSync as execSync3 } from "child_process";
2140
+ import { execSync as execSync5 } from "child_process";
1865
2141
  var SETTINGS_PATH = path13.join(".claude", "settings.json");
1866
2142
  var HOOK_COMMAND = "caliber refresh --quiet";
1867
2143
  var HOOK_DESCRIPTION = "Caliber: auto-refreshing docs based on code changes";
@@ -1933,7 +2209,7 @@ fi
1933
2209
  ${PRECOMMIT_END}`;
1934
2210
  function getGitHooksDir() {
1935
2211
  try {
1936
- const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
2212
+ const gitDir = execSync5("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
1937
2213
  return path13.join(gitDir, "hooks");
1938
2214
  } catch {
1939
2215
  return null;
@@ -2079,7 +2355,7 @@ function removeLearningHooks() {
2079
2355
  init_constants();
2080
2356
  import fs16 from "fs";
2081
2357
  import path15 from "path";
2082
- import { execSync as execSync4 } from "child_process";
2358
+ import { execSync as execSync6 } from "child_process";
2083
2359
  var STATE_FILE = path15.join(CALIBER_DIR, ".caliber-state.json");
2084
2360
  function readState() {
2085
2361
  try {
@@ -2097,7 +2373,7 @@ function writeState(state) {
2097
2373
  }
2098
2374
  function getCurrentHeadSha() {
2099
2375
  try {
2100
- return execSync4("git rev-parse HEAD", {
2376
+ return execSync6("git rev-parse HEAD", {
2101
2377
  encoding: "utf-8",
2102
2378
  stdio: ["pipe", "pipe", "pipe"]
2103
2379
  }).trim();
@@ -2193,6 +2469,80 @@ var SpinnerMessages = class {
2193
2469
  }
2194
2470
  };
2195
2471
 
2472
+ // src/commands/interactive-provider-setup.ts
2473
+ import chalk2 from "chalk";
2474
+ import readline2 from "readline";
2475
+ import select from "@inquirer/select";
2476
+ function promptInput(question) {
2477
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
2478
+ return new Promise((resolve2) => {
2479
+ rl.question(chalk2.cyan(`${question} `), (answer) => {
2480
+ rl.close();
2481
+ resolve2(answer.trim());
2482
+ });
2483
+ });
2484
+ }
2485
+ var PROVIDER_CHOICES = [
2486
+ { name: "Claude Code (use my app login \u2014 Pro/Max/Team, no API key)", value: "claude-cli" },
2487
+ { name: "Cursor (use my Cursor subscription \u2014 no API key)", value: "cursor" },
2488
+ { name: "Anthropic (Claude) \u2014 API key from console.anthropic.com", value: "anthropic" },
2489
+ { name: "Google Vertex AI (Claude)", value: "vertex" },
2490
+ { name: "OpenAI / OpenAI-compatible", value: "openai" }
2491
+ ];
2492
+ async function runInteractiveProviderSetup(options) {
2493
+ const message = options?.selectMessage ?? "Select LLM provider";
2494
+ const provider = await select({
2495
+ message,
2496
+ choices: PROVIDER_CHOICES
2497
+ });
2498
+ const config = { provider, model: "" };
2499
+ switch (provider) {
2500
+ case "claude-cli": {
2501
+ config.model = "default";
2502
+ console.log(chalk2.dim(" Run `claude` once and log in with your Pro/Max/Team account if you haven't."));
2503
+ break;
2504
+ }
2505
+ case "cursor": {
2506
+ config.model = "default";
2507
+ console.log(chalk2.dim(" Run `agent login` if you haven't, or set CURSOR_API_KEY."));
2508
+ break;
2509
+ }
2510
+ case "anthropic": {
2511
+ console.log(chalk2.dim(" Get a key at https://console.anthropic.com (same account as Claude Pro/Team/Max)."));
2512
+ config.apiKey = await promptInput("Anthropic API key:");
2513
+ if (!config.apiKey) {
2514
+ console.log(chalk2.red("API key is required."));
2515
+ throw new Error("__exit__");
2516
+ }
2517
+ config.model = await promptInput(`Model (default: ${DEFAULT_MODELS.anthropic}):`) || DEFAULT_MODELS.anthropic;
2518
+ break;
2519
+ }
2520
+ case "vertex": {
2521
+ config.vertexProjectId = await promptInput("GCP Project ID:");
2522
+ if (!config.vertexProjectId) {
2523
+ console.log(chalk2.red("Project ID is required."));
2524
+ throw new Error("__exit__");
2525
+ }
2526
+ config.vertexRegion = await promptInput("Region (default: us-east5):") || "us-east5";
2527
+ config.vertexCredentials = await promptInput("Service account credentials JSON (or leave empty for ADC):") || void 0;
2528
+ config.model = await promptInput(`Model (default: ${DEFAULT_MODELS.vertex}):`) || DEFAULT_MODELS.vertex;
2529
+ break;
2530
+ }
2531
+ case "openai": {
2532
+ config.apiKey = await promptInput("API key:");
2533
+ if (!config.apiKey) {
2534
+ console.log(chalk2.red("API key is required."));
2535
+ throw new Error("__exit__");
2536
+ }
2537
+ config.baseUrl = await promptInput("Base URL (leave empty for OpenAI, or enter custom endpoint):") || void 0;
2538
+ config.model = await promptInput(`Model (default: ${DEFAULT_MODELS.openai}):`) || DEFAULT_MODELS.openai;
2539
+ break;
2540
+ }
2541
+ }
2542
+ writeConfigFile(config);
2543
+ return config;
2544
+ }
2545
+
2196
2546
  // src/scoring/index.ts
2197
2547
  import { existsSync as existsSync8 } from "fs";
2198
2548
  import { join as join7 } from "path";
@@ -3107,7 +3457,7 @@ function checkFreshness(dir) {
3107
3457
 
3108
3458
  // src/scoring/checks/bonus.ts
3109
3459
  import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
3110
- import { execSync as execSync5 } from "child_process";
3460
+ import { execSync as execSync7 } from "child_process";
3111
3461
  import { join as join6 } from "path";
3112
3462
  function readFileOrNull5(path23) {
3113
3463
  try {
@@ -3118,7 +3468,7 @@ function readFileOrNull5(path23) {
3118
3468
  }
3119
3469
  function hasPreCommitHook(dir) {
3120
3470
  try {
3121
- const gitDir = execSync5("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3471
+ const gitDir = execSync7("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3122
3472
  const hookPath = join6(gitDir, "hooks", "pre-commit");
3123
3473
  const content = readFileOrNull5(hookPath);
3124
3474
  return content ? content.includes("caliber") : false;
@@ -3263,7 +3613,7 @@ function computeLocalScore(dir, targetAgent) {
3263
3613
  }
3264
3614
 
3265
3615
  // src/scoring/display.ts
3266
- import chalk2 from "chalk";
3616
+ import chalk3 from "chalk";
3267
3617
  var CATEGORY_LABELS = {
3268
3618
  existence: "FILES & SETUP",
3269
3619
  quality: "QUALITY",
@@ -3276,31 +3626,31 @@ var CATEGORY_ORDER = ["existence", "quality", "coverage", "accuracy", "freshness
3276
3626
  function gradeColor(grade) {
3277
3627
  switch (grade) {
3278
3628
  case "A":
3279
- return chalk2.green;
3629
+ return chalk3.green;
3280
3630
  case "B":
3281
- return chalk2.greenBright;
3631
+ return chalk3.greenBright;
3282
3632
  case "C":
3283
- return chalk2.yellow;
3633
+ return chalk3.yellow;
3284
3634
  case "D":
3285
- return chalk2.hex("#f97316");
3635
+ return chalk3.hex("#f97316");
3286
3636
  case "F":
3287
- return chalk2.red;
3637
+ return chalk3.red;
3288
3638
  default:
3289
- return chalk2.white;
3639
+ return chalk3.white;
3290
3640
  }
3291
3641
  }
3292
3642
  function progressBar(score, max, width = 40) {
3293
3643
  const filled = Math.round(score / max * width);
3294
3644
  const empty = width - filled;
3295
- const bar = chalk2.hex("#f97316")("\u2593".repeat(filled)) + chalk2.gray("\u2591".repeat(empty));
3645
+ const bar = chalk3.hex("#f97316")("\u2593".repeat(filled)) + chalk3.gray("\u2591".repeat(empty));
3296
3646
  return bar;
3297
3647
  }
3298
3648
  function formatCheck(check) {
3299
- const icon = check.passed ? chalk2.green("\u2713") : check.earnedPoints < 0 ? chalk2.red("\u2717") : chalk2.gray("\u2717");
3300
- const points = check.passed ? chalk2.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk2.red(`${check.earnedPoints}`.padStart(4)) : chalk2.gray(" \u2014");
3301
- const name = check.passed ? chalk2.white(check.name) : chalk2.gray(check.name);
3302
- const detail = check.detail ? chalk2.gray(` (${check.detail})`) : "";
3303
- const suggestion = !check.passed && check.suggestion ? chalk2.gray(`
3649
+ const icon = check.passed ? chalk3.green("\u2713") : check.earnedPoints < 0 ? chalk3.red("\u2717") : chalk3.gray("\u2717");
3650
+ const points = check.passed ? chalk3.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk3.red(`${check.earnedPoints}`.padStart(4)) : chalk3.gray(" \u2014");
3651
+ const name = check.passed ? chalk3.white(check.name) : chalk3.gray(check.name);
3652
+ const detail = check.detail ? chalk3.gray(` (${check.detail})`) : "";
3653
+ const suggestion = !check.passed && check.suggestion ? chalk3.gray(`
3304
3654
  \u2192 ${check.suggestion}`) : "";
3305
3655
  return ` ${icon} ${name.padEnd(38)}${points}${detail}${suggestion}`;
3306
3656
  }
@@ -3308,21 +3658,21 @@ function displayScore(result) {
3308
3658
  const gc = gradeColor(result.grade);
3309
3659
  const agentLabel = result.targetAgent === "both" ? "Claude Code + Cursor" : result.targetAgent === "claude" ? "Claude Code" : "Cursor";
3310
3660
  console.log("");
3311
- console.log(chalk2.gray(" \u256D\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\u2500\u2500\u256E"));
3312
- console.log(chalk2.gray(" \u2502") + " " + chalk2.gray("\u2502"));
3661
+ console.log(chalk3.gray(" \u256D\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\u2500\u2500\u256E"));
3662
+ console.log(chalk3.gray(" \u2502") + " " + chalk3.gray("\u2502"));
3313
3663
  console.log(
3314
- chalk2.gray(" \u2502") + " Agent Config Score" + gc(` ${String(result.score).padStart(3)} / ${result.maxScore}`) + " Grade " + gc(result.grade) + " " + chalk2.gray("\u2502")
3664
+ chalk3.gray(" \u2502") + " Agent Config Score" + gc(` ${String(result.score).padStart(3)} / ${result.maxScore}`) + " Grade " + gc(result.grade) + " " + chalk3.gray("\u2502")
3315
3665
  );
3316
- console.log(chalk2.gray(" \u2502") + ` ${progressBar(result.score, result.maxScore)} ` + chalk2.gray("\u2502"));
3317
- console.log(chalk2.gray(" \u2502") + chalk2.dim(` Target: ${agentLabel}`) + " ".repeat(Math.max(1, 40 - agentLabel.length)) + chalk2.gray("\u2502"));
3318
- console.log(chalk2.gray(" \u2502") + " " + chalk2.gray("\u2502"));
3319
- console.log(chalk2.gray(" \u2570\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\u2500\u2500\u256F"));
3666
+ console.log(chalk3.gray(" \u2502") + ` ${progressBar(result.score, result.maxScore)} ` + chalk3.gray("\u2502"));
3667
+ console.log(chalk3.gray(" \u2502") + chalk3.dim(` Target: ${agentLabel}`) + " ".repeat(Math.max(1, 40 - agentLabel.length)) + chalk3.gray("\u2502"));
3668
+ console.log(chalk3.gray(" \u2502") + " " + chalk3.gray("\u2502"));
3669
+ console.log(chalk3.gray(" \u2570\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\u2500\u2500\u256F"));
3320
3670
  console.log("");
3321
3671
  for (const category of CATEGORY_ORDER) {
3322
3672
  const summary = result.categories[category];
3323
3673
  const categoryChecks = result.checks.filter((c) => c.category === category);
3324
3674
  console.log(
3325
- chalk2.gray(` ${CATEGORY_LABELS[category]}`) + chalk2.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk2.white(`${summary.earned}`) + chalk2.gray(` / ${summary.max}`)
3675
+ chalk3.gray(` ${CATEGORY_LABELS[category]}`) + chalk3.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk3.white(`${summary.earned}`) + chalk3.gray(` / ${summary.max}`)
3326
3676
  );
3327
3677
  for (const check of categoryChecks) {
3328
3678
  console.log(formatCheck(check));
@@ -3333,7 +3683,7 @@ function displayScore(result) {
3333
3683
  function displayScoreDelta(before, after) {
3334
3684
  const delta = after.score - before.score;
3335
3685
  const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
3336
- const deltaColor = delta >= 0 ? chalk2.green : chalk2.red;
3686
+ const deltaColor = delta >= 0 ? chalk3.green : chalk3.red;
3337
3687
  const beforeGc = gradeColor(before.grade);
3338
3688
  const afterGc = gradeColor(after.grade);
3339
3689
  const BOX_INNER = 51;
@@ -3344,30 +3694,30 @@ function displayScoreDelta(before, after) {
3344
3694
  const totalPad = BOX_INNER - contentLen;
3345
3695
  const pad1 = Math.max(2, Math.ceil(totalPad / 2));
3346
3696
  const pad2 = Math.max(1, totalPad - pad1);
3347
- const scoreLineFormatted = " Score: " + beforeGc(`${before.score}`) + chalk2.gray(" \u2192 ") + afterGc(`${after.score}`) + " ".repeat(pad1) + deltaColor(deltaPart) + " ".repeat(pad2) + beforeGc(before.grade) + chalk2.gray(" \u2192 ") + afterGc(after.grade);
3697
+ const scoreLineFormatted = " Score: " + beforeGc(`${before.score}`) + chalk3.gray(" \u2192 ") + afterGc(`${after.score}`) + " ".repeat(pad1) + deltaColor(deltaPart) + " ".repeat(pad2) + beforeGc(before.grade) + chalk3.gray(" \u2192 ") + afterGc(after.grade);
3348
3698
  const visibleLen = 3 + scorePart.length + pad1 + deltaPart.length + pad2 + gradePart.length;
3349
3699
  const trailingPad = Math.max(0, BOX_INNER - visibleLen);
3350
3700
  const barWidth = Math.floor((BOX_INNER - 12) / 2);
3351
- const barLine = ` ${progressBar(before.score, before.maxScore, barWidth)}` + chalk2.gray(" \u2192 ") + progressBar(after.score, after.maxScore, barWidth) + " ";
3701
+ const barLine = ` ${progressBar(before.score, before.maxScore, barWidth)}` + chalk3.gray(" \u2192 ") + progressBar(after.score, after.maxScore, barWidth) + " ";
3352
3702
  console.log("");
3353
- console.log(chalk2.gray(" \u256D" + "\u2500".repeat(BOX_INNER) + "\u256E"));
3354
- console.log(chalk2.gray(" \u2502") + " ".repeat(BOX_INNER) + chalk2.gray("\u2502"));
3355
- console.log(chalk2.gray(" \u2502") + scoreLineFormatted + " ".repeat(trailingPad) + chalk2.gray("\u2502"));
3356
- console.log(chalk2.gray(" \u2502") + barLine + chalk2.gray("\u2502"));
3357
- console.log(chalk2.gray(" \u2502") + " ".repeat(BOX_INNER) + chalk2.gray("\u2502"));
3358
- console.log(chalk2.gray(" \u2570" + "\u2500".repeat(BOX_INNER) + "\u256F"));
3703
+ console.log(chalk3.gray(" \u256D" + "\u2500".repeat(BOX_INNER) + "\u256E"));
3704
+ console.log(chalk3.gray(" \u2502") + " ".repeat(BOX_INNER) + chalk3.gray("\u2502"));
3705
+ console.log(chalk3.gray(" \u2502") + scoreLineFormatted + " ".repeat(trailingPad) + chalk3.gray("\u2502"));
3706
+ console.log(chalk3.gray(" \u2502") + barLine + chalk3.gray("\u2502"));
3707
+ console.log(chalk3.gray(" \u2502") + " ".repeat(BOX_INNER) + chalk3.gray("\u2502"));
3708
+ console.log(chalk3.gray(" \u2570" + "\u2500".repeat(BOX_INNER) + "\u256F"));
3359
3709
  console.log("");
3360
3710
  const improved = after.checks.filter((ac) => {
3361
3711
  const bc = before.checks.find((b) => b.id === ac.id);
3362
3712
  return bc && ac.earnedPoints > bc.earnedPoints;
3363
3713
  });
3364
3714
  if (improved.length > 0) {
3365
- console.log(chalk2.gray(" What improved:"));
3715
+ console.log(chalk3.gray(" What improved:"));
3366
3716
  for (const check of improved) {
3367
3717
  const bc = before.checks.find((b) => b.id === check.id);
3368
3718
  const gain = check.earnedPoints - bc.earnedPoints;
3369
3719
  console.log(
3370
- chalk2.green(" +") + chalk2.white(` ${check.name.padEnd(50)}`) + chalk2.green(`+${gain}`)
3720
+ chalk3.green(" +") + chalk3.white(` ${check.name.padEnd(50)}`) + chalk3.green(`+${gain}`)
3371
3721
  );
3372
3722
  }
3373
3723
  console.log("");
@@ -3376,7 +3726,7 @@ function displayScoreDelta(before, after) {
3376
3726
 
3377
3727
  // src/commands/init.ts
3378
3728
  async function initCommand(options) {
3379
- console.log(chalk3.bold.hex("#6366f1")(`
3729
+ console.log(chalk4.bold.hex("#6366f1")(`
3380
3730
  \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
3381
3731
  \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
3382
3732
  \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
@@ -3384,55 +3734,63 @@ async function initCommand(options) {
3384
3734
  \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
3385
3735
  \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
3386
3736
  `));
3387
- console.log(chalk3.dim(" Configure your coding agent environment\n"));
3388
- console.log(chalk3.bold(" What is Caliber?\n"));
3389
- console.log(chalk3.dim(" Caliber audits your AI agent configurations and suggests targeted"));
3390
- console.log(chalk3.dim(" improvements. It analyzes CLAUDE.md, .cursorrules, and skills"));
3391
- console.log(chalk3.dim(" against your actual codebase \u2014 keeping what works, fixing"));
3392
- console.log(chalk3.dim(" what's stale, and adding what's missing.\n"));
3393
- console.log(chalk3.bold(" How it works:\n"));
3394
- console.log(chalk3.dim(" 1. Scan Analyze your code, dependencies, and existing configs"));
3395
- console.log(chalk3.dim(" 2. Generate AI creates or improves config files for your project"));
3396
- console.log(chalk3.dim(" 3. Review You accept, refine, or decline the proposed changes"));
3397
- console.log(chalk3.dim(" 4. Apply Config files are written with backups\n"));
3398
- console.log(chalk3.hex("#6366f1").bold(" Step 1/4 \u2014 Check LLM provider\n"));
3399
- const config = loadConfig();
3737
+ console.log(chalk4.dim(" Configure your coding agent environment\n"));
3738
+ console.log(chalk4.bold(" What is Caliber?\n"));
3739
+ console.log(chalk4.dim(" Caliber audits your AI agent configurations and suggests targeted"));
3740
+ console.log(chalk4.dim(" improvements. It analyzes CLAUDE.md, .cursorrules, and skills"));
3741
+ console.log(chalk4.dim(" against your actual codebase \u2014 keeping what works, fixing"));
3742
+ console.log(chalk4.dim(" what's stale, and adding what's missing.\n"));
3743
+ console.log(chalk4.bold(" How it works:\n"));
3744
+ console.log(chalk4.dim(" 1. Scan Analyze your code, dependencies, and existing configs"));
3745
+ console.log(chalk4.dim(" 2. Generate AI creates or improves config files for your project"));
3746
+ console.log(chalk4.dim(" 3. Review You accept, refine, or decline the proposed changes"));
3747
+ console.log(chalk4.dim(" 4. Apply Config files are written with backups\n"));
3748
+ console.log(chalk4.hex("#6366f1").bold(" Step 1/4 \u2014 How do you want to use Caliber?\n"));
3749
+ let config = loadConfig();
3400
3750
  if (!config) {
3401
- console.log(chalk3.red(" No LLM provider configured.\n"));
3402
- console.log(chalk3.dim(" Set one of these environment variables:"));
3403
- console.log(chalk3.dim(" ANTHROPIC_API_KEY \u2014 for Anthropic Claude"));
3404
- console.log(chalk3.dim(" OPENAI_API_KEY \u2014 for OpenAI or compatible endpoints"));
3405
- console.log(chalk3.dim(" VERTEX_PROJECT_ID \u2014 for Google Vertex AI\n"));
3406
- console.log(chalk3.dim(" Or run `caliber config` for interactive setup.\n"));
3407
- throw new Error("__exit__");
3751
+ console.log(chalk4.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
3752
+ try {
3753
+ await runInteractiveProviderSetup({
3754
+ selectMessage: "How do you want to use Caliber? (choose LLM provider)"
3755
+ });
3756
+ } catch (err) {
3757
+ if (err.message === "__exit__") throw err;
3758
+ throw err;
3759
+ }
3760
+ config = loadConfig();
3761
+ if (!config) {
3762
+ console.log(chalk4.red(" Setup was cancelled or failed.\n"));
3763
+ throw new Error("__exit__");
3764
+ }
3765
+ console.log(chalk4.green(" \u2713 Provider saved. Continuing with init.\n"));
3408
3766
  }
3409
- console.log(chalk3.dim(` Provider: ${config.provider} | Model: ${config.model}
3767
+ console.log(chalk4.dim(` Provider: ${config.provider} | Model: ${config.model}
3410
3768
  `));
3411
- console.log(chalk3.hex("#6366f1").bold(" Step 2/4 \u2014 Scan project\n"));
3412
- console.log(chalk3.dim(" Detecting languages, dependencies, file structure, and existing configs.\n"));
3769
+ console.log(chalk4.hex("#6366f1").bold(" Step 2/4 \u2014 Scan project\n"));
3770
+ console.log(chalk4.dim(" Detecting languages, dependencies, file structure, and existing configs.\n"));
3413
3771
  const spinner = ora("Analyzing project...").start();
3414
3772
  const fingerprint = collectFingerprint(process.cwd());
3415
3773
  await enrichFingerprintWithLLM(fingerprint, process.cwd());
3416
3774
  spinner.succeed("Project analyzed");
3417
- console.log(chalk3.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
3418
- console.log(chalk3.dim(` Files: ${fingerprint.fileTree.length} found
3775
+ console.log(chalk4.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
3776
+ console.log(chalk4.dim(` Files: ${fingerprint.fileTree.length} found
3419
3777
  `));
3420
3778
  const targetAgent = options.agent || await promptAgent();
3421
3779
  const baselineScore = computeLocalScore(process.cwd(), targetAgent);
3422
3780
  const isEmpty = fingerprint.fileTree.length < 3;
3423
3781
  if (isEmpty) {
3424
- fingerprint.description = await promptInput("What will you build in this project?");
3782
+ fingerprint.description = await promptInput2("What will you build in this project?");
3425
3783
  }
3426
3784
  const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length);
3427
3785
  if (hasExistingConfig) {
3428
- console.log(chalk3.hex("#6366f1").bold(" Step 3/4 \u2014 Auditing your configs\n"));
3429
- console.log(chalk3.dim(" AI is reviewing your existing configs against your codebase"));
3430
- console.log(chalk3.dim(" and suggesting improvements.\n"));
3786
+ console.log(chalk4.hex("#6366f1").bold(" Step 3/4 \u2014 Auditing your configs\n"));
3787
+ console.log(chalk4.dim(" AI is reviewing your existing configs against your codebase"));
3788
+ console.log(chalk4.dim(" and suggesting improvements.\n"));
3431
3789
  } else {
3432
- console.log(chalk3.hex("#6366f1").bold(" Step 3/4 \u2014 Generating configs\n"));
3433
- console.log(chalk3.dim(" AI is creating agent config files tailored to your project.\n"));
3790
+ console.log(chalk4.hex("#6366f1").bold(" Step 3/4 \u2014 Generating configs\n"));
3791
+ console.log(chalk4.dim(" AI is creating agent config files tailored to your project.\n"));
3434
3792
  }
3435
- console.log(chalk3.dim(" This usually takes 1\u20133 minutes.\n"));
3793
+ console.log(chalk4.dim(" This usually takes 1\u20133 minutes.\n"));
3436
3794
  const genStartTime = Date.now();
3437
3795
  const genSpinner = ora("Generating setup...").start();
3438
3796
  const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
@@ -3471,8 +3829,8 @@ async function initCommand(options) {
3471
3829
  if (!generatedSetup) {
3472
3830
  genSpinner.fail("Failed to generate setup.");
3473
3831
  if (rawOutput) {
3474
- console.log(chalk3.dim("\nRaw LLM output (JSON parse failed):"));
3475
- console.log(chalk3.dim(rawOutput.slice(0, 500)));
3832
+ console.log(chalk4.dim("\nRaw LLM output (JSON parse failed):"));
3833
+ console.log(chalk4.dim(rawOutput.slice(0, 500)));
3476
3834
  }
3477
3835
  throw new Error("__exit__");
3478
3836
  }
@@ -3480,12 +3838,12 @@ async function initCommand(options) {
3480
3838
  const mins = Math.floor(elapsedMs / 6e4);
3481
3839
  const secs = Math.floor(elapsedMs % 6e4 / 1e3);
3482
3840
  const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
3483
- genSpinner.succeed(`Setup generated ${chalk3.dim(`in ${timeStr}`)}`);
3841
+ genSpinner.succeed(`Setup generated ${chalk4.dim(`in ${timeStr}`)}`);
3484
3842
  printSetupSummary(generatedSetup);
3485
- console.log(chalk3.hex("#6366f1").bold(" Step 4/4 \u2014 Review\n"));
3843
+ console.log(chalk4.hex("#6366f1").bold(" Step 4/4 \u2014 Review\n"));
3486
3844
  const setupFiles = collectSetupFiles(generatedSetup);
3487
3845
  const staged = stageFiles(setupFiles, process.cwd());
3488
- console.log(chalk3.dim(` ${chalk3.green(`${staged.newFiles} new`)} / ${chalk3.yellow(`${staged.modifiedFiles} modified`)} file${staged.newFiles + staged.modifiedFiles !== 1 ? "s" : ""}
3846
+ console.log(chalk4.dim(` ${chalk4.green(`${staged.newFiles} new`)} / ${chalk4.yellow(`${staged.modifiedFiles} modified`)} file${staged.newFiles + staged.modifiedFiles !== 1 ? "s" : ""}
3489
3847
  `));
3490
3848
  const wantsReview = await promptWantsReview();
3491
3849
  if (wantsReview) {
@@ -3497,12 +3855,12 @@ async function initCommand(options) {
3497
3855
  generatedSetup = await refineLoop(generatedSetup, targetAgent);
3498
3856
  if (!generatedSetup) {
3499
3857
  cleanupStaging();
3500
- console.log(chalk3.dim("Refinement cancelled. No files were modified."));
3858
+ console.log(chalk4.dim("Refinement cancelled. No files were modified."));
3501
3859
  return;
3502
3860
  }
3503
3861
  const updatedFiles = collectSetupFiles(generatedSetup);
3504
3862
  const restaged = stageFiles(updatedFiles, process.cwd());
3505
- console.log(chalk3.dim(` ${chalk3.green(`${restaged.newFiles} new`)} / ${chalk3.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
3863
+ console.log(chalk4.dim(` ${chalk4.green(`${restaged.newFiles} new`)} / ${chalk4.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
3506
3864
  `));
3507
3865
  printSetupSummary(generatedSetup);
3508
3866
  const wantsReviewAgain = await promptWantsReview();
@@ -3514,11 +3872,11 @@ async function initCommand(options) {
3514
3872
  }
3515
3873
  cleanupStaging();
3516
3874
  if (action === "decline") {
3517
- console.log(chalk3.dim("Setup declined. No files were modified."));
3875
+ console.log(chalk4.dim("Setup declined. No files were modified."));
3518
3876
  return;
3519
3877
  }
3520
3878
  if (options.dryRun) {
3521
- console.log(chalk3.yellow("\n[Dry run] Would write the following files:"));
3879
+ console.log(chalk4.yellow("\n[Dry run] Would write the following files:"));
3522
3880
  console.log(JSON.stringify(generatedSetup, null, 2));
3523
3881
  return;
3524
3882
  }
@@ -3526,29 +3884,29 @@ async function initCommand(options) {
3526
3884
  try {
3527
3885
  const result = writeSetup(generatedSetup);
3528
3886
  writeSpinner.succeed("Config files written");
3529
- console.log(chalk3.bold("\nFiles created/updated:"));
3887
+ console.log(chalk4.bold("\nFiles created/updated:"));
3530
3888
  for (const file of result.written) {
3531
- console.log(` ${chalk3.green("\u2713")} ${file}`);
3889
+ console.log(` ${chalk4.green("\u2713")} ${file}`);
3532
3890
  }
3533
3891
  if (result.deleted.length > 0) {
3534
- console.log(chalk3.bold("\nFiles removed:"));
3892
+ console.log(chalk4.bold("\nFiles removed:"));
3535
3893
  for (const file of result.deleted) {
3536
- console.log(` ${chalk3.red("\u2717")} ${file}`);
3894
+ console.log(` ${chalk4.red("\u2717")} ${file}`);
3537
3895
  }
3538
3896
  }
3539
3897
  if (result.backupDir) {
3540
- console.log(chalk3.dim(`
3898
+ console.log(chalk4.dim(`
3541
3899
  Backups saved to ${result.backupDir}`));
3542
3900
  }
3543
3901
  } catch (err) {
3544
3902
  writeSpinner.fail("Failed to write files");
3545
- console.error(chalk3.red(err instanceof Error ? err.message : "Unknown error"));
3903
+ console.error(chalk4.red(err instanceof Error ? err.message : "Unknown error"));
3546
3904
  throw new Error("__exit__");
3547
3905
  }
3548
3906
  if (!fs17.existsSync("AGENTS.md")) {
3549
3907
  const agentsContent = "# AGENTS.md\n\nThis project uses AI coding agents. See CLAUDE.md for Claude Code configuration and .cursor/rules/ for Cursor rules.\n";
3550
3908
  fs17.writeFileSync("AGENTS.md", agentsContent);
3551
- console.log(` ${chalk3.green("\u2713")} AGENTS.md`);
3909
+ console.log(` ${chalk4.green("\u2713")} AGENTS.md`);
3552
3910
  }
3553
3911
  ensurePermissions();
3554
3912
  const sha = getCurrentHeadSha();
@@ -3561,45 +3919,45 @@ async function initCommand(options) {
3561
3919
  if (hookChoice === "claude" || hookChoice === "both") {
3562
3920
  const hookResult = installHook();
3563
3921
  if (hookResult.installed) {
3564
- console.log(` ${chalk3.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
3565
- console.log(chalk3.dim(" Run `caliber hooks remove` to disable"));
3922
+ console.log(` ${chalk4.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
3923
+ console.log(chalk4.dim(" Run `caliber hooks remove` to disable"));
3566
3924
  } else if (hookResult.alreadyInstalled) {
3567
- console.log(chalk3.dim(" Claude Code hook already installed"));
3925
+ console.log(chalk4.dim(" Claude Code hook already installed"));
3568
3926
  }
3569
3927
  const learnResult = installLearningHooks();
3570
3928
  if (learnResult.installed) {
3571
- console.log(` ${chalk3.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
3572
- console.log(chalk3.dim(" Run `caliber learn remove` to disable"));
3929
+ console.log(` ${chalk4.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
3930
+ console.log(chalk4.dim(" Run `caliber learn remove` to disable"));
3573
3931
  } else if (learnResult.alreadyInstalled) {
3574
- console.log(chalk3.dim(" Learning hooks already installed"));
3932
+ console.log(chalk4.dim(" Learning hooks already installed"));
3575
3933
  }
3576
3934
  }
3577
3935
  if (hookChoice === "precommit" || hookChoice === "both") {
3578
3936
  const precommitResult = installPreCommitHook();
3579
3937
  if (precommitResult.installed) {
3580
- console.log(` ${chalk3.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
3581
- console.log(chalk3.dim(" Run `caliber hooks remove-precommit` to disable"));
3938
+ console.log(` ${chalk4.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
3939
+ console.log(chalk4.dim(" Run `caliber hooks remove-precommit` to disable"));
3582
3940
  } else if (precommitResult.alreadyInstalled) {
3583
- console.log(chalk3.dim(" Pre-commit hook already installed"));
3941
+ console.log(chalk4.dim(" Pre-commit hook already installed"));
3584
3942
  } else {
3585
- console.log(chalk3.yellow(" Could not install pre-commit hook (not a git repository?)"));
3943
+ console.log(chalk4.yellow(" Could not install pre-commit hook (not a git repository?)"));
3586
3944
  }
3587
3945
  }
3588
3946
  if (hookChoice === "skip") {
3589
- console.log(chalk3.dim(" Skipped auto-refresh hooks. Run `caliber hooks install` later to enable."));
3947
+ console.log(chalk4.dim(" Skipped auto-refresh hooks. Run `caliber hooks install` later to enable."));
3590
3948
  }
3591
3949
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
3592
3950
  displayScoreDelta(baselineScore, afterScore);
3593
- console.log(chalk3.bold.green(" Setup complete! Your coding agent is now configured."));
3594
- console.log(chalk3.dim(" Run `caliber undo` to revert changes.\n"));
3595
- console.log(chalk3.bold(" Next steps:\n"));
3596
- console.log(` ${chalk3.hex("#6366f1")("caliber undo")} Revert all changes from this run`);
3951
+ console.log(chalk4.bold.green(" Setup complete! Your coding agent is now configured."));
3952
+ console.log(chalk4.dim(" Run `caliber undo` to revert changes.\n"));
3953
+ console.log(chalk4.bold(" Next steps:\n"));
3954
+ console.log(` ${chalk4.hex("#6366f1")("caliber undo")} Revert all changes from this run`);
3597
3955
  console.log("");
3598
3956
  }
3599
3957
  async function refineLoop(currentSetup, _targetAgent) {
3600
3958
  const history = [];
3601
3959
  while (true) {
3602
- const message = await promptInput("\nWhat would you like to change?");
3960
+ const message = await promptInput2("\nWhat would you like to change?");
3603
3961
  if (!message || message.toLowerCase() === "done" || message.toLowerCase() === "accept") {
3604
3962
  return currentSetup;
3605
3963
  }
@@ -3621,24 +3979,24 @@ async function refineLoop(currentSetup, _targetAgent) {
3621
3979
  history.push({ role: "assistant", content: JSON.stringify(refined) });
3622
3980
  refineSpinner.succeed("Setup updated");
3623
3981
  printSetupSummary(refined);
3624
- console.log(chalk3.dim('Type "done" to accept, or describe more changes.'));
3982
+ console.log(chalk4.dim('Type "done" to accept, or describe more changes.'));
3625
3983
  } else {
3626
3984
  refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
3627
- console.log(chalk3.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
3985
+ console.log(chalk4.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
3628
3986
  }
3629
3987
  }
3630
3988
  }
3631
- function promptInput(question) {
3632
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
3989
+ function promptInput2(question) {
3990
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
3633
3991
  return new Promise((resolve2) => {
3634
- rl.question(chalk3.cyan(`${question} `), (answer) => {
3992
+ rl.question(chalk4.cyan(`${question} `), (answer) => {
3635
3993
  rl.close();
3636
3994
  resolve2(answer.trim());
3637
3995
  });
3638
3996
  });
3639
3997
  }
3640
3998
  async function promptAgent() {
3641
- return select({
3999
+ return select2({
3642
4000
  message: "Which coding agent are you using?",
3643
4001
  choices: [
3644
4002
  { name: "Claude Code", value: "claude" },
@@ -3657,13 +4015,13 @@ async function promptHookType(targetAgent) {
3657
4015
  choices.push({ name: "Both (Claude Code + pre-commit)", value: "both" });
3658
4016
  }
3659
4017
  choices.push({ name: "Skip for now", value: "skip" });
3660
- return select({
4018
+ return select2({
3661
4019
  message: "How would you like to auto-refresh your docs?",
3662
4020
  choices
3663
4021
  });
3664
4022
  }
3665
4023
  async function promptWantsReview() {
3666
- const answer = await select({
4024
+ const answer = await select2({
3667
4025
  message: "Would you like to review the diffs before deciding?",
3668
4026
  choices: [
3669
4027
  { name: "Yes, show me the diffs", value: true },
@@ -3685,7 +4043,7 @@ async function promptReviewMethod() {
3685
4043
  return { name: "Terminal", value: "terminal" };
3686
4044
  }
3687
4045
  });
3688
- return select({ message: "How would you like to review the changes?", choices });
4046
+ return select2({ message: "How would you like to review the changes?", choices });
3689
4047
  }
3690
4048
  function openReview(method, stagedFiles) {
3691
4049
  if (method === "cursor" || method === "vscode") {
@@ -3693,7 +4051,7 @@ function openReview(method, stagedFiles) {
3693
4051
  originalPath: f.originalPath,
3694
4052
  proposedPath: f.proposedPath
3695
4053
  })));
3696
- console.log(chalk3.dim(" Diffs opened in your editor.\n"));
4054
+ console.log(chalk4.dim(" Diffs opened in your editor.\n"));
3697
4055
  } else {
3698
4056
  for (const file of stagedFiles) {
3699
4057
  if (file.currentPath) {
@@ -3705,19 +4063,19 @@ function openReview(method, stagedFiles) {
3705
4063
  if (line.startsWith("+") && !line.startsWith("+++")) added++;
3706
4064
  if (line.startsWith("-") && !line.startsWith("---")) removed++;
3707
4065
  }
3708
- console.log(` ${chalk3.yellow("~")} ${file.relativePath} ${chalk3.green(`+${added}`)} ${chalk3.red(`-${removed}`)}`);
4066
+ console.log(` ${chalk4.yellow("~")} ${file.relativePath} ${chalk4.green(`+${added}`)} ${chalk4.red(`-${removed}`)}`);
3709
4067
  } else {
3710
4068
  const lines = fs17.readFileSync(file.proposedPath, "utf-8").split("\n").length;
3711
- console.log(` ${chalk3.green("+")} ${file.relativePath} ${chalk3.dim(`${lines} lines`)}`);
4069
+ console.log(` ${chalk4.green("+")} ${file.relativePath} ${chalk4.dim(`${lines} lines`)}`);
3712
4070
  }
3713
4071
  }
3714
4072
  console.log("");
3715
- console.log(chalk3.dim(` Files staged at .caliber/staged/ for manual inspection.
4073
+ console.log(chalk4.dim(` Files staged at .caliber/staged/ for manual inspection.
3716
4074
  `));
3717
4075
  }
3718
4076
  }
3719
4077
  async function promptReviewAction() {
3720
- return select({
4078
+ return select2({
3721
4079
  message: "What would you like to do?",
3722
4080
  choices: [
3723
4081
  { name: "Accept and apply", value: "accept" },
@@ -3732,46 +4090,46 @@ function printSetupSummary(setup) {
3732
4090
  const fileDescriptions = setup.fileDescriptions;
3733
4091
  const deletions = setup.deletions;
3734
4092
  console.log("");
3735
- console.log(chalk3.bold(" Proposed changes:\n"));
4093
+ console.log(chalk4.bold(" Proposed changes:\n"));
3736
4094
  const getDescription = (filePath) => {
3737
4095
  return fileDescriptions?.[filePath];
3738
4096
  };
3739
4097
  if (claude) {
3740
4098
  if (claude.claudeMd) {
3741
- const icon = fs17.existsSync("CLAUDE.md") ? chalk3.yellow("~") : chalk3.green("+");
4099
+ const icon = fs17.existsSync("CLAUDE.md") ? chalk4.yellow("~") : chalk4.green("+");
3742
4100
  const desc = getDescription("CLAUDE.md");
3743
- console.log(` ${icon} ${chalk3.bold("CLAUDE.md")}`);
3744
- if (desc) console.log(chalk3.dim(` ${desc}`));
4101
+ console.log(` ${icon} ${chalk4.bold("CLAUDE.md")}`);
4102
+ if (desc) console.log(chalk4.dim(` ${desc}`));
3745
4103
  console.log("");
3746
4104
  }
3747
4105
  const skills = claude.skills;
3748
4106
  if (Array.isArray(skills) && skills.length > 0) {
3749
4107
  for (const skill of skills) {
3750
4108
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
3751
- const icon = fs17.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
4109
+ const icon = fs17.existsSync(skillPath) ? chalk4.yellow("~") : chalk4.green("+");
3752
4110
  const desc = getDescription(skillPath);
3753
- console.log(` ${icon} ${chalk3.bold(skillPath)}`);
3754
- console.log(chalk3.dim(` ${desc || skill.description || skill.name}`));
4111
+ console.log(` ${icon} ${chalk4.bold(skillPath)}`);
4112
+ console.log(chalk4.dim(` ${desc || skill.description || skill.name}`));
3755
4113
  console.log("");
3756
4114
  }
3757
4115
  }
3758
4116
  }
3759
4117
  if (cursor) {
3760
4118
  if (cursor.cursorrules) {
3761
- const icon = fs17.existsSync(".cursorrules") ? chalk3.yellow("~") : chalk3.green("+");
4119
+ const icon = fs17.existsSync(".cursorrules") ? chalk4.yellow("~") : chalk4.green("+");
3762
4120
  const desc = getDescription(".cursorrules");
3763
- console.log(` ${icon} ${chalk3.bold(".cursorrules")}`);
3764
- if (desc) console.log(chalk3.dim(` ${desc}`));
4121
+ console.log(` ${icon} ${chalk4.bold(".cursorrules")}`);
4122
+ if (desc) console.log(chalk4.dim(` ${desc}`));
3765
4123
  console.log("");
3766
4124
  }
3767
4125
  const cursorSkills = cursor.skills;
3768
4126
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
3769
4127
  for (const skill of cursorSkills) {
3770
4128
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
3771
- const icon = fs17.existsSync(skillPath) ? chalk3.yellow("~") : chalk3.green("+");
4129
+ const icon = fs17.existsSync(skillPath) ? chalk4.yellow("~") : chalk4.green("+");
3772
4130
  const desc = getDescription(skillPath);
3773
- console.log(` ${icon} ${chalk3.bold(skillPath)}`);
3774
- console.log(chalk3.dim(` ${desc || skill.description || skill.name}`));
4131
+ console.log(` ${icon} ${chalk4.bold(skillPath)}`);
4132
+ console.log(chalk4.dim(` ${desc || skill.description || skill.name}`));
3775
4133
  console.log("");
3776
4134
  }
3777
4135
  }
@@ -3779,14 +4137,14 @@ function printSetupSummary(setup) {
3779
4137
  if (Array.isArray(rules) && rules.length > 0) {
3780
4138
  for (const rule of rules) {
3781
4139
  const rulePath = `.cursor/rules/${rule.filename}`;
3782
- const icon = fs17.existsSync(rulePath) ? chalk3.yellow("~") : chalk3.green("+");
4140
+ const icon = fs17.existsSync(rulePath) ? chalk4.yellow("~") : chalk4.green("+");
3783
4141
  const desc = getDescription(rulePath);
3784
- console.log(` ${icon} ${chalk3.bold(rulePath)}`);
4142
+ console.log(` ${icon} ${chalk4.bold(rulePath)}`);
3785
4143
  if (desc) {
3786
- console.log(chalk3.dim(` ${desc}`));
4144
+ console.log(chalk4.dim(` ${desc}`));
3787
4145
  } else {
3788
4146
  const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
3789
- if (firstLine) console.log(chalk3.dim(` ${firstLine.trim().slice(0, 80)}`));
4147
+ if (firstLine) console.log(chalk4.dim(` ${firstLine.trim().slice(0, 80)}`));
3790
4148
  }
3791
4149
  console.log("");
3792
4150
  }
@@ -3794,12 +4152,12 @@ function printSetupSummary(setup) {
3794
4152
  }
3795
4153
  if (Array.isArray(deletions) && deletions.length > 0) {
3796
4154
  for (const del of deletions) {
3797
- console.log(` ${chalk3.red("-")} ${chalk3.bold(del.filePath)}`);
3798
- console.log(chalk3.dim(` ${del.reason}`));
4155
+ console.log(` ${chalk4.red("-")} ${chalk4.bold(del.filePath)}`);
4156
+ console.log(chalk4.dim(` ${del.reason}`));
3799
4157
  console.log("");
3800
4158
  }
3801
4159
  }
3802
- console.log(` ${chalk3.green("+")} ${chalk3.dim("new")} ${chalk3.yellow("~")} ${chalk3.dim("modified")} ${chalk3.red("-")} ${chalk3.dim("removed")}`);
4160
+ console.log(` ${chalk4.green("+")} ${chalk4.dim("new")} ${chalk4.yellow("~")} ${chalk4.dim("modified")} ${chalk4.red("-")} ${chalk4.dim("removed")}`);
3803
4161
  console.log("");
3804
4162
  }
3805
4163
  function buildSkillContent(skill) {
@@ -3865,7 +4223,7 @@ function collectSetupFiles(setup) {
3865
4223
  }
3866
4224
 
3867
4225
  // src/commands/undo.ts
3868
- import chalk4 from "chalk";
4226
+ import chalk5 from "chalk";
3869
4227
  import ora2 from "ora";
3870
4228
  function undoCommand() {
3871
4229
  const spinner = ora2("Reverting setup...").start();
@@ -3877,26 +4235,26 @@ function undoCommand() {
3877
4235
  }
3878
4236
  spinner.succeed("Setup reverted successfully.\n");
3879
4237
  if (restored.length > 0) {
3880
- console.log(chalk4.cyan(" Restored from backup:"));
4238
+ console.log(chalk5.cyan(" Restored from backup:"));
3881
4239
  for (const file of restored) {
3882
- console.log(` ${chalk4.green("\u21A9")} ${file}`);
4240
+ console.log(` ${chalk5.green("\u21A9")} ${file}`);
3883
4241
  }
3884
4242
  }
3885
4243
  if (removed.length > 0) {
3886
- console.log(chalk4.cyan(" Removed:"));
4244
+ console.log(chalk5.cyan(" Removed:"));
3887
4245
  for (const file of removed) {
3888
- console.log(` ${chalk4.red("\u2717")} ${file}`);
4246
+ console.log(` ${chalk5.red("\u2717")} ${file}`);
3889
4247
  }
3890
4248
  }
3891
4249
  console.log("");
3892
4250
  } catch (err) {
3893
- spinner.fail(chalk4.red(err instanceof Error ? err.message : "Undo failed"));
4251
+ spinner.fail(chalk5.red(err instanceof Error ? err.message : "Undo failed"));
3894
4252
  throw new Error("__exit__");
3895
4253
  }
3896
4254
  }
3897
4255
 
3898
4256
  // src/commands/status.ts
3899
- import chalk5 from "chalk";
4257
+ import chalk6 from "chalk";
3900
4258
  import fs18 from "fs";
3901
4259
  async function statusCommand(options) {
3902
4260
  const config = loadConfig();
@@ -3910,39 +4268,39 @@ async function statusCommand(options) {
3910
4268
  }, null, 2));
3911
4269
  return;
3912
4270
  }
3913
- console.log(chalk5.bold("\nCaliber Status\n"));
4271
+ console.log(chalk6.bold("\nCaliber Status\n"));
3914
4272
  if (config) {
3915
- console.log(` LLM: ${chalk5.green(config.provider)} (${config.model})`);
4273
+ console.log(` LLM: ${chalk6.green(config.provider)} (${config.model})`);
3916
4274
  } else {
3917
- console.log(` LLM: ${chalk5.yellow("Not configured")} \u2014 run \`caliber config\``);
4275
+ console.log(` LLM: ${chalk6.yellow("Not configured")} \u2014 run \`caliber config\``);
3918
4276
  }
3919
4277
  if (!manifest) {
3920
- console.log(` Setup: ${chalk5.dim("No setup applied")}`);
3921
- console.log(chalk5.dim("\n Run `caliber init` to get started.\n"));
4278
+ console.log(` Setup: ${chalk6.dim("No setup applied")}`);
4279
+ console.log(chalk6.dim("\n Run `caliber init` to get started.\n"));
3922
4280
  return;
3923
4281
  }
3924
- console.log(` Files managed: ${chalk5.cyan(manifest.entries.length.toString())}`);
4282
+ console.log(` Files managed: ${chalk6.cyan(manifest.entries.length.toString())}`);
3925
4283
  for (const entry of manifest.entries) {
3926
4284
  const exists = fs18.existsSync(entry.path);
3927
- const icon = exists ? chalk5.green("\u2713") : chalk5.red("\u2717");
4285
+ const icon = exists ? chalk6.green("\u2713") : chalk6.red("\u2717");
3928
4286
  console.log(` ${icon} ${entry.path} (${entry.action})`);
3929
4287
  }
3930
4288
  console.log("");
3931
4289
  }
3932
4290
 
3933
4291
  // src/commands/regenerate.ts
3934
- import chalk6 from "chalk";
4292
+ import chalk7 from "chalk";
3935
4293
  import ora3 from "ora";
3936
4294
  import confirm from "@inquirer/confirm";
3937
4295
  async function regenerateCommand(options) {
3938
4296
  const config = loadConfig();
3939
4297
  if (!config) {
3940
- console.log(chalk6.red("No LLM provider configured. Run `caliber config` or set ANTHROPIC_API_KEY."));
4298
+ console.log(chalk7.red("No LLM provider configured. Run `caliber config` (e.g. choose Cursor) or set ANTHROPIC_API_KEY."));
3941
4299
  throw new Error("__exit__");
3942
4300
  }
3943
4301
  const manifest = readManifest();
3944
4302
  if (!manifest) {
3945
- console.log(chalk6.yellow("No existing setup found. Run `caliber init` first."));
4303
+ console.log(chalk7.yellow("No existing setup found. Run `caliber init` first."));
3946
4304
  throw new Error("__exit__");
3947
4305
  }
3948
4306
  const spinner = ora3("Re-analyzing project...").start();
@@ -3985,26 +4343,26 @@ async function regenerateCommand(options) {
3985
4343
  }
3986
4344
  genSpinner.succeed("Setup regenerated");
3987
4345
  if (options.dryRun) {
3988
- console.log(chalk6.yellow("\n[Dry run] Would write:"));
4346
+ console.log(chalk7.yellow("\n[Dry run] Would write:"));
3989
4347
  console.log(JSON.stringify(generatedSetup, null, 2));
3990
4348
  return;
3991
4349
  }
3992
4350
  const shouldApply = await confirm({ message: "Apply regenerated setup?", default: true });
3993
4351
  if (!shouldApply) {
3994
- console.log(chalk6.dim("Regeneration cancelled."));
4352
+ console.log(chalk7.dim("Regeneration cancelled."));
3995
4353
  return;
3996
4354
  }
3997
4355
  const writeSpinner = ora3("Updating config files...").start();
3998
4356
  const result = writeSetup(generatedSetup);
3999
4357
  writeSpinner.succeed("Config files updated");
4000
4358
  for (const file of result.written) {
4001
- console.log(` ${chalk6.green("\u2713")} ${file}`);
4359
+ console.log(` ${chalk7.green("\u2713")} ${file}`);
4002
4360
  }
4003
4361
  console.log("");
4004
4362
  }
4005
4363
 
4006
4364
  // src/commands/recommend.ts
4007
- import chalk7 from "chalk";
4365
+ import chalk8 from "chalk";
4008
4366
  import ora4 from "ora";
4009
4367
  import { mkdirSync, readFileSync as readFileSync7, existsSync as existsSync9, writeFileSync } from "fs";
4010
4368
  import { join as join8, dirname as dirname2 } from "path";
@@ -4187,7 +4545,7 @@ async function recommendCommand(options) {
4187
4545
  ...extractTopDeps()
4188
4546
  ].filter(Boolean))];
4189
4547
  if (technologies.length === 0) {
4190
- console.log(chalk7.yellow("Could not detect any languages or dependencies. Try running from a project root."));
4548
+ console.log(chalk8.yellow("Could not detect any languages or dependencies. Try running from a project root."));
4191
4549
  throw new Error("__exit__");
4192
4550
  }
4193
4551
  const spinner = ora4("Searching for skills...").start();
@@ -4213,18 +4571,18 @@ async function interactiveSelect(recs) {
4213
4571
  let lineCount = 0;
4214
4572
  function render() {
4215
4573
  const lines = [];
4216
- lines.push(chalk7.bold(" Recommendations"));
4574
+ lines.push(chalk8.bold(" Recommendations"));
4217
4575
  lines.push("");
4218
- lines.push(` ${chalk7.dim("Name".padEnd(30))} ${chalk7.dim("Technology".padEnd(18))} ${chalk7.dim("Source")}`);
4219
- lines.push(chalk7.dim(" " + "\u2500".repeat(70)));
4576
+ lines.push(` ${chalk8.dim("Name".padEnd(30))} ${chalk8.dim("Technology".padEnd(18))} ${chalk8.dim("Source")}`);
4577
+ lines.push(chalk8.dim(" " + "\u2500".repeat(70)));
4220
4578
  for (let i = 0; i < recs.length; i++) {
4221
4579
  const rec = recs[i];
4222
- const check = selected.has(i) ? chalk7.green("[x]") : "[ ]";
4223
- const ptr = i === cursor ? chalk7.cyan("\u276F") : " ";
4224
- lines.push(` ${ptr} ${check} ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk7.dim(rec.source_url || "")}`);
4580
+ const check = selected.has(i) ? chalk8.green("[x]") : "[ ]";
4581
+ const ptr = i === cursor ? chalk8.cyan("\u276F") : " ";
4582
+ lines.push(` ${ptr} ${check} ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk8.dim(rec.source_url || "")}`);
4225
4583
  }
4226
4584
  lines.push("");
4227
- lines.push(chalk7.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
4585
+ lines.push(chalk8.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
4228
4586
  return lines.join("\n");
4229
4587
  }
4230
4588
  function draw(initial) {
@@ -4273,7 +4631,7 @@ async function interactiveSelect(recs) {
4273
4631
  case "\n":
4274
4632
  cleanup();
4275
4633
  if (selected.size === 0) {
4276
- console.log(chalk7.dim("\n No skills selected.\n"));
4634
+ console.log(chalk8.dim("\n No skills selected.\n"));
4277
4635
  resolve2(null);
4278
4636
  } else {
4279
4637
  resolve2(Array.from(selected).sort().map((i) => recs[i]));
@@ -4283,7 +4641,7 @@ async function interactiveSelect(recs) {
4283
4641
  case "\x1B":
4284
4642
  case "":
4285
4643
  cleanup();
4286
- console.log(chalk7.dim("\n Cancelled.\n"));
4644
+ console.log(chalk8.dim("\n Cancelled.\n"));
4287
4645
  resolve2(null);
4288
4646
  break;
4289
4647
  }
@@ -4323,35 +4681,35 @@ async function installSkills(recs, platforms) {
4323
4681
  if (installed.length > 0) {
4324
4682
  spinner.succeed(`Installed ${installed.length} file${installed.length > 1 ? "s" : ""}`);
4325
4683
  for (const p of installed) {
4326
- console.log(chalk7.green(` \u2713 ${p}`));
4684
+ console.log(chalk8.green(` \u2713 ${p}`));
4327
4685
  }
4328
4686
  } else {
4329
4687
  spinner.fail("No skills were installed");
4330
4688
  }
4331
4689
  for (const w of warnings) {
4332
- console.log(chalk7.yellow(` \u26A0 ${w}`));
4690
+ console.log(chalk8.yellow(` \u26A0 ${w}`));
4333
4691
  }
4334
4692
  console.log("");
4335
4693
  }
4336
4694
  function printRecommendations(recs) {
4337
- console.log(chalk7.bold("\n Recommendations\n"));
4695
+ console.log(chalk8.bold("\n Recommendations\n"));
4338
4696
  console.log(
4339
- ` ${chalk7.dim("Name".padEnd(30))} ${chalk7.dim("Technology".padEnd(18))} ${chalk7.dim("Source")}`
4697
+ ` ${chalk8.dim("Name".padEnd(30))} ${chalk8.dim("Technology".padEnd(18))} ${chalk8.dim("Source")}`
4340
4698
  );
4341
- console.log(chalk7.dim(" " + "\u2500".repeat(70)));
4699
+ console.log(chalk8.dim(" " + "\u2500".repeat(70)));
4342
4700
  for (const rec of recs) {
4343
4701
  console.log(
4344
- ` ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk7.dim(rec.source_url || "")}`
4702
+ ` ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk8.dim(rec.source_url || "")}`
4345
4703
  );
4346
4704
  if (rec.reason) {
4347
- console.log(` ${chalk7.dim(" " + rec.reason)}`);
4705
+ console.log(` ${chalk8.dim(" " + rec.reason)}`);
4348
4706
  }
4349
4707
  }
4350
4708
  console.log("");
4351
4709
  }
4352
4710
 
4353
4711
  // src/commands/score.ts
4354
- import chalk8 from "chalk";
4712
+ import chalk9 from "chalk";
4355
4713
  async function scoreCommand(options) {
4356
4714
  const dir = process.cwd();
4357
4715
  const target = options.agent ?? readState()?.targetAgent;
@@ -4365,14 +4723,14 @@ async function scoreCommand(options) {
4365
4723
  return;
4366
4724
  }
4367
4725
  displayScore(result);
4368
- const separator = chalk8.gray(" " + "\u2500".repeat(53));
4726
+ const separator = chalk9.gray(" " + "\u2500".repeat(53));
4369
4727
  console.log(separator);
4370
4728
  if (result.score < 40) {
4371
- console.log(chalk8.gray(" Run ") + chalk8.hex("#f97316")("caliber init") + chalk8.gray(" to generate a complete, optimized setup."));
4729
+ console.log(chalk9.gray(" Run ") + chalk9.hex("#f97316")("caliber init") + chalk9.gray(" to generate a complete, optimized setup."));
4372
4730
  } else if (result.score < 70) {
4373
- console.log(chalk8.gray(" Run ") + chalk8.hex("#f97316")("caliber init") + chalk8.gray(" to improve your setup."));
4731
+ console.log(chalk9.gray(" Run ") + chalk9.hex("#f97316")("caliber init") + chalk9.gray(" to improve your setup."));
4374
4732
  } else {
4375
- console.log(chalk8.green(" Looking good!") + chalk8.gray(" Run ") + chalk8.hex("#f97316")("caliber update") + chalk8.gray(" to keep it fresh."));
4733
+ console.log(chalk9.green(" Looking good!") + chalk9.gray(" Run ") + chalk9.hex("#f97316")("caliber update") + chalk9.gray(" to keep it fresh."));
4376
4734
  }
4377
4735
  console.log("");
4378
4736
  }
@@ -4380,11 +4738,11 @@ async function scoreCommand(options) {
4380
4738
  // src/commands/refresh.ts
4381
4739
  import fs21 from "fs";
4382
4740
  import path18 from "path";
4383
- import chalk9 from "chalk";
4741
+ import chalk10 from "chalk";
4384
4742
  import ora5 from "ora";
4385
4743
 
4386
4744
  // src/lib/git-diff.ts
4387
- import { execSync as execSync6 } from "child_process";
4745
+ import { execSync as execSync8 } from "child_process";
4388
4746
  var MAX_DIFF_BYTES = 1e5;
4389
4747
  var DOC_PATTERNS = [
4390
4748
  "CLAUDE.md",
@@ -4398,7 +4756,7 @@ function excludeArgs() {
4398
4756
  }
4399
4757
  function safeExec(cmd) {
4400
4758
  try {
4401
- return execSync6(cmd, {
4759
+ return execSync8(cmd, {
4402
4760
  encoding: "utf-8",
4403
4761
  stdio: ["pipe", "pipe", "pipe"],
4404
4762
  maxBuffer: 10 * 1024 * 1024
@@ -4575,7 +4933,7 @@ function discoverGitRepos(parentDir) {
4575
4933
  }
4576
4934
  async function refreshSingleRepo(repoDir, options) {
4577
4935
  const quiet = !!options.quiet;
4578
- const prefix = options.label ? `${chalk9.bold(options.label)} ` : "";
4936
+ const prefix = options.label ? `${chalk10.bold(options.label)} ` : "";
4579
4937
  const state = readState();
4580
4938
  const lastSha = state?.lastRefreshSha ?? null;
4581
4939
  const diff = collectDiff(lastSha);
@@ -4584,7 +4942,7 @@ async function refreshSingleRepo(repoDir, options) {
4584
4942
  if (currentSha) {
4585
4943
  writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
4586
4944
  }
4587
- log(quiet, chalk9.dim(`${prefix}No changes since last refresh.`));
4945
+ log(quiet, chalk10.dim(`${prefix}No changes since last refresh.`));
4588
4946
  return;
4589
4947
  }
4590
4948
  const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
@@ -4616,10 +4974,10 @@ async function refreshSingleRepo(repoDir, options) {
4616
4974
  if (options.dryRun) {
4617
4975
  spinner?.info(`${prefix}Dry run \u2014 would update:`);
4618
4976
  for (const doc of response.docsUpdated) {
4619
- console.log(` ${chalk9.yellow("~")} ${doc}`);
4977
+ console.log(` ${chalk10.yellow("~")} ${doc}`);
4620
4978
  }
4621
4979
  if (response.changesSummary) {
4622
- console.log(chalk9.dim(`
4980
+ console.log(chalk10.dim(`
4623
4981
  ${response.changesSummary}`));
4624
4982
  }
4625
4983
  return;
@@ -4627,10 +4985,10 @@ async function refreshSingleRepo(repoDir, options) {
4627
4985
  const written = writeRefreshDocs(response.updatedDocs);
4628
4986
  spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
4629
4987
  for (const file of written) {
4630
- log(quiet, ` ${chalk9.green("\u2713")} ${file}`);
4988
+ log(quiet, ` ${chalk10.green("\u2713")} ${file}`);
4631
4989
  }
4632
4990
  if (response.changesSummary) {
4633
- log(quiet, chalk9.dim(`
4991
+ log(quiet, chalk10.dim(`
4634
4992
  ${response.changesSummary}`));
4635
4993
  }
4636
4994
  if (currentSha) {
@@ -4643,7 +5001,7 @@ async function refreshCommand(options) {
4643
5001
  const config = loadConfig();
4644
5002
  if (!config) {
4645
5003
  if (quiet) return;
4646
- console.log(chalk9.red("No LLM provider configured. Run `caliber config` or set ANTHROPIC_API_KEY."));
5004
+ console.log(chalk10.red("No LLM provider configured. Run `caliber config` (e.g. choose Cursor) or set an API key."));
4647
5005
  throw new Error("__exit__");
4648
5006
  }
4649
5007
  if (isGitRepo()) {
@@ -4653,10 +5011,10 @@ async function refreshCommand(options) {
4653
5011
  const repos = discoverGitRepos(process.cwd());
4654
5012
  if (repos.length === 0) {
4655
5013
  if (quiet) return;
4656
- console.log(chalk9.red("Not inside a git repository and no git repos found in child directories."));
5014
+ console.log(chalk10.red("Not inside a git repository and no git repos found in child directories."));
4657
5015
  throw new Error("__exit__");
4658
5016
  }
4659
- log(quiet, chalk9.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
5017
+ log(quiet, chalk10.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
4660
5018
  `));
4661
5019
  const originalDir = process.cwd();
4662
5020
  for (const repo of repos) {
@@ -4666,7 +5024,7 @@ async function refreshCommand(options) {
4666
5024
  await refreshSingleRepo(repo, { ...options, label: repoName });
4667
5025
  } catch (err) {
4668
5026
  if (err instanceof Error && err.message === "__exit__") continue;
4669
- log(quiet, chalk9.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
5027
+ log(quiet, chalk10.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
4670
5028
  }
4671
5029
  }
4672
5030
  process.chdir(originalDir);
@@ -4674,153 +5032,107 @@ async function refreshCommand(options) {
4674
5032
  if (err instanceof Error && err.message === "__exit__") throw err;
4675
5033
  if (quiet) return;
4676
5034
  const msg = err instanceof Error ? err.message : "Unknown error";
4677
- console.log(chalk9.red(`Refresh failed: ${msg}`));
5035
+ console.log(chalk10.red(`Refresh failed: ${msg}`));
4678
5036
  throw new Error("__exit__");
4679
5037
  }
4680
5038
  }
4681
5039
 
4682
5040
  // src/commands/hooks.ts
4683
- import chalk10 from "chalk";
5041
+ import chalk11 from "chalk";
4684
5042
  async function hooksInstallCommand() {
4685
5043
  const result = installHook();
4686
5044
  if (result.alreadyInstalled) {
4687
- console.log(chalk10.dim("Claude Code hook already installed."));
5045
+ console.log(chalk11.dim("Claude Code hook already installed."));
4688
5046
  return;
4689
5047
  }
4690
- console.log(chalk10.green("\u2713") + " SessionEnd hook installed in .claude/settings.json");
4691
- console.log(chalk10.dim(" Docs will auto-refresh when Claude Code sessions end."));
5048
+ console.log(chalk11.green("\u2713") + " SessionEnd hook installed in .claude/settings.json");
5049
+ console.log(chalk11.dim(" Docs will auto-refresh when Claude Code sessions end."));
4692
5050
  }
4693
5051
  async function hooksRemoveCommand() {
4694
5052
  const result = removeHook();
4695
5053
  if (result.notFound) {
4696
- console.log(chalk10.dim("Claude Code hook not found."));
5054
+ console.log(chalk11.dim("Claude Code hook not found."));
4697
5055
  return;
4698
5056
  }
4699
- console.log(chalk10.green("\u2713") + " SessionEnd hook removed from .claude/settings.json");
5057
+ console.log(chalk11.green("\u2713") + " SessionEnd hook removed from .claude/settings.json");
4700
5058
  }
4701
5059
  async function hooksInstallPrecommitCommand() {
4702
5060
  const result = installPreCommitHook();
4703
5061
  if (result.alreadyInstalled) {
4704
- console.log(chalk10.dim("Pre-commit hook already installed."));
5062
+ console.log(chalk11.dim("Pre-commit hook already installed."));
4705
5063
  return;
4706
5064
  }
4707
5065
  if (!result.installed) {
4708
- console.log(chalk10.red("Failed to install pre-commit hook (not a git repository?)."));
5066
+ console.log(chalk11.red("Failed to install pre-commit hook (not a git repository?)."));
4709
5067
  return;
4710
5068
  }
4711
- console.log(chalk10.green("\u2713") + " Pre-commit hook installed in .git/hooks/pre-commit");
4712
- console.log(chalk10.dim(" Docs will auto-refresh before each commit via LLM."));
5069
+ console.log(chalk11.green("\u2713") + " Pre-commit hook installed in .git/hooks/pre-commit");
5070
+ console.log(chalk11.dim(" Docs will auto-refresh before each commit via LLM."));
4713
5071
  }
4714
5072
  async function hooksRemovePrecommitCommand() {
4715
5073
  const result = removePreCommitHook();
4716
5074
  if (result.notFound) {
4717
- console.log(chalk10.dim("Pre-commit hook not found."));
5075
+ console.log(chalk11.dim("Pre-commit hook not found."));
4718
5076
  return;
4719
5077
  }
4720
- console.log(chalk10.green("\u2713") + " Pre-commit hook removed from .git/hooks/pre-commit");
5078
+ console.log(chalk11.green("\u2713") + " Pre-commit hook removed from .git/hooks/pre-commit");
4721
5079
  }
4722
5080
  async function hooksStatusCommand() {
4723
5081
  const claudeInstalled = isHookInstalled();
4724
5082
  const precommitInstalled = isPreCommitHookInstalled();
4725
5083
  if (claudeInstalled) {
4726
- console.log(chalk10.green("\u2713") + " Claude Code hook is " + chalk10.green("installed"));
5084
+ console.log(chalk11.green("\u2713") + " Claude Code hook is " + chalk11.green("installed"));
4727
5085
  } else {
4728
- console.log(chalk10.dim("\u2717") + " Claude Code hook is " + chalk10.yellow("not installed"));
5086
+ console.log(chalk11.dim("\u2717") + " Claude Code hook is " + chalk11.yellow("not installed"));
4729
5087
  }
4730
5088
  if (precommitInstalled) {
4731
- console.log(chalk10.green("\u2713") + " Pre-commit hook is " + chalk10.green("installed"));
5089
+ console.log(chalk11.green("\u2713") + " Pre-commit hook is " + chalk11.green("installed"));
4732
5090
  } else {
4733
- console.log(chalk10.dim("\u2717") + " Pre-commit hook is " + chalk10.yellow("not installed"));
5091
+ console.log(chalk11.dim("\u2717") + " Pre-commit hook is " + chalk11.yellow("not installed"));
4734
5092
  }
4735
5093
  if (!claudeInstalled && !precommitInstalled) {
4736
- console.log(chalk10.dim("\n Run `caliber hooks install` or `caliber hooks install-precommit` to enable auto-refresh."));
5094
+ console.log(chalk11.dim("\n Run `caliber hooks install` or `caliber hooks install-precommit` to enable auto-refresh."));
4737
5095
  }
4738
5096
  }
4739
5097
 
4740
5098
  // src/commands/config.ts
4741
- import chalk11 from "chalk";
4742
- import readline2 from "readline";
4743
- import select2 from "@inquirer/select";
4744
- function promptInput2(question) {
4745
- const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
4746
- return new Promise((resolve2) => {
4747
- rl.question(chalk11.cyan(`${question} `), (answer) => {
4748
- rl.close();
4749
- resolve2(answer.trim());
4750
- });
4751
- });
4752
- }
5099
+ import chalk12 from "chalk";
4753
5100
  async function configCommand() {
4754
5101
  const existing = loadConfig();
4755
5102
  if (existing) {
4756
- console.log(chalk11.bold("\nCurrent Configuration\n"));
4757
- console.log(` Provider: ${chalk11.cyan(existing.provider)}`);
4758
- console.log(` Model: ${chalk11.cyan(existing.model)}`);
5103
+ console.log(chalk12.bold("\nCurrent Configuration\n"));
5104
+ console.log(` Provider: ${chalk12.cyan(existing.provider)}`);
5105
+ console.log(` Model: ${chalk12.cyan(existing.model)}`);
4759
5106
  if (existing.apiKey) {
4760
5107
  const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
4761
- console.log(` API Key: ${chalk11.dim(masked)}`);
5108
+ console.log(` API Key: ${chalk12.dim(masked)}`);
5109
+ }
5110
+ if (existing.provider === "cursor") {
5111
+ console.log(` Seat: ${chalk12.dim("Cursor (agent acp)")}`);
5112
+ }
5113
+ if (existing.provider === "claude-cli") {
5114
+ console.log(` Seat: ${chalk12.dim("Claude Code (claude -p)")}`);
4762
5115
  }
4763
5116
  if (existing.baseUrl) {
4764
- console.log(` Base URL: ${chalk11.dim(existing.baseUrl)}`);
5117
+ console.log(` Base URL: ${chalk12.dim(existing.baseUrl)}`);
4765
5118
  }
4766
5119
  if (existing.vertexProjectId) {
4767
- console.log(` Vertex Project: ${chalk11.dim(existing.vertexProjectId)}`);
4768
- console.log(` Vertex Region: ${chalk11.dim(existing.vertexRegion || "us-east5")}`);
5120
+ console.log(` Vertex Project: ${chalk12.dim(existing.vertexProjectId)}`);
5121
+ console.log(` Vertex Region: ${chalk12.dim(existing.vertexRegion || "us-east5")}`);
4769
5122
  }
4770
- console.log(` Source: ${chalk11.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID ? "environment variables" : getConfigFilePath())}`);
5123
+ console.log(` Source: ${chalk12.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())}`);
4771
5124
  console.log("");
4772
5125
  }
4773
- const provider = await select2({
4774
- message: "Select LLM provider",
4775
- choices: [
4776
- { name: "Anthropic (Claude)", value: "anthropic" },
4777
- { name: "Google Vertex AI (Claude)", value: "vertex" },
4778
- { name: "OpenAI / OpenAI-compatible", value: "openai" }
4779
- ]
4780
- });
4781
- const config = { provider, model: "" };
4782
- switch (provider) {
4783
- case "anthropic": {
4784
- config.apiKey = await promptInput2("Anthropic API key:");
4785
- if (!config.apiKey) {
4786
- console.log(chalk11.red("API key is required."));
4787
- throw new Error("__exit__");
4788
- }
4789
- config.model = await promptInput2(`Model (default: ${DEFAULT_MODELS.anthropic}):`) || DEFAULT_MODELS.anthropic;
4790
- break;
4791
- }
4792
- case "vertex": {
4793
- config.vertexProjectId = await promptInput2("GCP Project ID:");
4794
- if (!config.vertexProjectId) {
4795
- console.log(chalk11.red("Project ID is required."));
4796
- throw new Error("__exit__");
4797
- }
4798
- config.vertexRegion = await promptInput2("Region (default: us-east5):") || "us-east5";
4799
- config.vertexCredentials = await promptInput2("Service account credentials JSON (or leave empty for ADC):") || void 0;
4800
- config.model = await promptInput2(`Model (default: ${DEFAULT_MODELS.vertex}):`) || DEFAULT_MODELS.vertex;
4801
- break;
4802
- }
4803
- case "openai": {
4804
- config.apiKey = await promptInput2("API key:");
4805
- if (!config.apiKey) {
4806
- console.log(chalk11.red("API key is required."));
4807
- throw new Error("__exit__");
4808
- }
4809
- config.baseUrl = await promptInput2("Base URL (leave empty for OpenAI, or enter custom endpoint):") || void 0;
4810
- config.model = await promptInput2(`Model (default: ${DEFAULT_MODELS.openai}):`) || DEFAULT_MODELS.openai;
4811
- break;
4812
- }
4813
- }
4814
- writeConfigFile(config);
4815
- console.log(chalk11.green("\n\u2713 Configuration saved"));
4816
- console.log(chalk11.dim(` ${getConfigFilePath()}
5126
+ await runInteractiveProviderSetup();
5127
+ console.log(chalk12.green("\n\u2713 Configuration saved"));
5128
+ console.log(chalk12.dim(` ${getConfigFilePath()}
4817
5129
  `));
4818
- console.log(chalk11.dim(" You can also set environment variables instead:"));
4819
- console.log(chalk11.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, or VERTEX_PROJECT_ID\n"));
5130
+ console.log(chalk12.dim(" You can also set environment variables instead:"));
5131
+ console.log(chalk12.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
4820
5132
  }
4821
5133
 
4822
5134
  // src/commands/learn.ts
4823
- import chalk12 from "chalk";
5135
+ import chalk13 from "chalk";
4824
5136
 
4825
5137
  // src/learner/stdin.ts
4826
5138
  var STDIN_TIMEOUT_MS = 5e3;
@@ -5121,46 +5433,46 @@ async function learnFinalizeCommand() {
5121
5433
  async function learnInstallCommand() {
5122
5434
  const result = installLearningHooks();
5123
5435
  if (result.alreadyInstalled) {
5124
- console.log(chalk12.dim("Learning hooks already installed."));
5436
+ console.log(chalk13.dim("Learning hooks already installed."));
5125
5437
  return;
5126
5438
  }
5127
- console.log(chalk12.green("\u2713") + " Learning hooks installed in .claude/settings.json");
5128
- console.log(chalk12.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
5129
- console.log(chalk12.dim(" Session learnings will be written to CLAUDE.md and skills."));
5439
+ console.log(chalk13.green("\u2713") + " Learning hooks installed in .claude/settings.json");
5440
+ console.log(chalk13.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
5441
+ console.log(chalk13.dim(" Session learnings will be written to CLAUDE.md and skills."));
5130
5442
  }
5131
5443
  async function learnRemoveCommand() {
5132
5444
  const result = removeLearningHooks();
5133
5445
  if (result.notFound) {
5134
- console.log(chalk12.dim("Learning hooks not found."));
5446
+ console.log(chalk13.dim("Learning hooks not found."));
5135
5447
  return;
5136
5448
  }
5137
- console.log(chalk12.green("\u2713") + " Learning hooks removed from .claude/settings.json");
5449
+ console.log(chalk13.green("\u2713") + " Learning hooks removed from .claude/settings.json");
5138
5450
  }
5139
5451
  async function learnStatusCommand() {
5140
5452
  const installed = areLearningHooksInstalled();
5141
5453
  const state = readState2();
5142
5454
  const eventCount = getEventCount();
5143
- console.log(chalk12.bold("Session Learning Status"));
5455
+ console.log(chalk13.bold("Session Learning Status"));
5144
5456
  console.log();
5145
5457
  if (installed) {
5146
- console.log(chalk12.green("\u2713") + " Learning hooks are " + chalk12.green("installed"));
5458
+ console.log(chalk13.green("\u2713") + " Learning hooks are " + chalk13.green("installed"));
5147
5459
  } else {
5148
- console.log(chalk12.dim("\u2717") + " Learning hooks are " + chalk12.yellow("not installed"));
5149
- console.log(chalk12.dim(" Run `caliber learn install` to enable session learning."));
5460
+ console.log(chalk13.dim("\u2717") + " Learning hooks are " + chalk13.yellow("not installed"));
5461
+ console.log(chalk13.dim(" Run `caliber learn install` to enable session learning."));
5150
5462
  }
5151
5463
  console.log();
5152
- console.log(`Events recorded: ${chalk12.cyan(String(eventCount))}`);
5153
- console.log(`Total this session: ${chalk12.cyan(String(state.eventCount))}`);
5464
+ console.log(`Events recorded: ${chalk13.cyan(String(eventCount))}`);
5465
+ console.log(`Total this session: ${chalk13.cyan(String(state.eventCount))}`);
5154
5466
  if (state.lastAnalysisTimestamp) {
5155
- console.log(`Last analysis: ${chalk12.cyan(state.lastAnalysisTimestamp)}`);
5467
+ console.log(`Last analysis: ${chalk13.cyan(state.lastAnalysisTimestamp)}`);
5156
5468
  } else {
5157
- console.log(`Last analysis: ${chalk12.dim("none")}`);
5469
+ console.log(`Last analysis: ${chalk13.dim("none")}`);
5158
5470
  }
5159
5471
  const learnedSection = readLearnedSection();
5160
5472
  if (learnedSection) {
5161
5473
  const lineCount = learnedSection.split("\n").filter(Boolean).length;
5162
5474
  console.log(`
5163
- Learned items in CLAUDE.md: ${chalk12.cyan(String(lineCount))}`);
5475
+ Learned items in CLAUDE.md: ${chalk13.cyan(String(lineCount))}`);
5164
5476
  }
5165
5477
  }
5166
5478
 
@@ -5197,8 +5509,8 @@ learn.command("status").description("Show learning system status").action(learnS
5197
5509
  import fs25 from "fs";
5198
5510
  import path22 from "path";
5199
5511
  import { fileURLToPath as fileURLToPath2 } from "url";
5200
- import { execSync as execSync7 } from "child_process";
5201
- import chalk13 from "chalk";
5512
+ import { execSync as execSync9 } from "child_process";
5513
+ import chalk14 from "chalk";
5202
5514
  import ora6 from "ora";
5203
5515
  import confirm2 from "@inquirer/confirm";
5204
5516
  var __dirname_vc = path22.dirname(fileURLToPath2(import.meta.url));
@@ -5207,7 +5519,7 @@ var pkg2 = JSON.parse(
5207
5519
  );
5208
5520
  function getInstalledVersion() {
5209
5521
  try {
5210
- const globalRoot = execSync7("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
5522
+ const globalRoot = execSync9("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
5211
5523
  const pkgPath = path22.join(globalRoot, "@rely-ai", "caliber", "package.json");
5212
5524
  return JSON.parse(fs25.readFileSync(pkgPath, "utf-8")).version;
5213
5525
  } catch {
@@ -5232,17 +5544,17 @@ async function checkForUpdates() {
5232
5544
  const isInteractive = process.stdin.isTTY === true;
5233
5545
  if (!isInteractive) {
5234
5546
  console.log(
5235
- chalk13.yellow(
5547
+ chalk14.yellow(
5236
5548
  `
5237
5549
  Update available: ${current} -> ${latest}
5238
- Run ${chalk13.bold("npm install -g @rely-ai/caliber")} to upgrade.
5550
+ Run ${chalk14.bold("npm install -g @rely-ai/caliber")} to upgrade.
5239
5551
  `
5240
5552
  )
5241
5553
  );
5242
5554
  return;
5243
5555
  }
5244
5556
  console.log(
5245
- chalk13.yellow(`
5557
+ chalk14.yellow(`
5246
5558
  Update available: ${current} -> ${latest}`)
5247
5559
  );
5248
5560
  const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
@@ -5252,7 +5564,7 @@ Update available: ${current} -> ${latest}`)
5252
5564
  }
5253
5565
  const spinner = ora6("Updating caliber...").start();
5254
5566
  try {
5255
- execSync7(`npm install -g @rely-ai/caliber@${latest}`, {
5567
+ execSync9(`npm install -g @rely-ai/caliber@${latest}`, {
5256
5568
  stdio: "pipe",
5257
5569
  timeout: 12e4,
5258
5570
  env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
@@ -5260,16 +5572,16 @@ Update available: ${current} -> ${latest}`)
5260
5572
  const installed = getInstalledVersion();
5261
5573
  if (installed !== latest) {
5262
5574
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
5263
- console.log(chalk13.yellow(`Run ${chalk13.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
5575
+ console.log(chalk14.yellow(`Run ${chalk14.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
5264
5576
  `));
5265
5577
  return;
5266
5578
  }
5267
- spinner.succeed(chalk13.green(`Updated to ${latest}`));
5579
+ spinner.succeed(chalk14.green(`Updated to ${latest}`));
5268
5580
  const args = process.argv.slice(2);
5269
- console.log(chalk13.dim(`
5581
+ console.log(chalk14.dim(`
5270
5582
  Restarting: caliber ${args.join(" ")}
5271
5583
  `));
5272
- execSync7(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
5584
+ execSync9(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
5273
5585
  stdio: "inherit",
5274
5586
  env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
5275
5587
  });
@@ -5279,11 +5591,11 @@ Restarting: caliber ${args.join(" ")}
5279
5591
  if (err instanceof Error) {
5280
5592
  const stderr = err.stderr;
5281
5593
  const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
5282
- if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk13.dim(` ${errMsg}`));
5594
+ if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk14.dim(` ${errMsg}`));
5283
5595
  }
5284
5596
  console.log(
5285
- chalk13.yellow(
5286
- `Run ${chalk13.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
5597
+ chalk14.yellow(
5598
+ `Run ${chalk14.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
5287
5599
  `
5288
5600
  )
5289
5601
  );