@rely-ai/caliber 1.0.0 → 1.1.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 +1198 -364
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -51,16 +51,16 @@ var init_constants = __esm({
51
51
 
52
52
  // src/cli.ts
53
53
  import { Command } from "commander";
54
- import fs24 from "fs";
55
- import path21 from "path";
54
+ import fs27 from "fs";
55
+ import path24 from "path";
56
56
  import { fileURLToPath } from "url";
57
57
 
58
58
  // src/commands/onboard.ts
59
- import chalk4 from "chalk";
60
- import ora from "ora";
61
- import readline3 from "readline";
59
+ import chalk5 from "chalk";
60
+ import ora2 from "ora";
61
+ import readline4 from "readline";
62
62
  import select2 from "@inquirer/select";
63
- import fs17 from "fs";
63
+ import fs20 from "fs";
64
64
 
65
65
  // src/fingerprint/index.ts
66
66
  import fs7 from "fs";
@@ -2127,16 +2127,25 @@ import path12 from "path";
2127
2127
  var STAGED_DIR = path12.join(CALIBER_DIR, "staged");
2128
2128
  var PROPOSED_DIR = path12.join(STAGED_DIR, "proposed");
2129
2129
  var CURRENT_DIR = path12.join(STAGED_DIR, "current");
2130
+ function normalizeContent(content) {
2131
+ return content.split("\n").map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
2132
+ }
2130
2133
  function stageFiles(files, projectDir) {
2131
2134
  cleanupStaging();
2132
2135
  let newFiles = 0;
2133
2136
  let modifiedFiles = 0;
2134
2137
  const stagedFiles = [];
2135
2138
  for (const file of files) {
2139
+ const originalPath = path12.join(projectDir, file.path);
2140
+ if (fs13.existsSync(originalPath)) {
2141
+ const existing = fs13.readFileSync(originalPath, "utf-8");
2142
+ if (normalizeContent(existing) === normalizeContent(file.content)) {
2143
+ continue;
2144
+ }
2145
+ }
2136
2146
  const proposedPath = path12.join(PROPOSED_DIR, file.path);
2137
2147
  fs13.mkdirSync(path12.dirname(proposedPath), { recursive: true });
2138
2148
  fs13.writeFileSync(proposedPath, file.content);
2139
- const originalPath = path12.join(projectDir, file.path);
2140
2149
  if (fs13.existsSync(originalPath)) {
2141
2150
  const currentPath = path12.join(CURRENT_DIR, file.path);
2142
2151
  fs13.mkdirSync(path12.dirname(currentPath), { recursive: true });
@@ -2715,15 +2724,15 @@ function computeGrade(score) {
2715
2724
  // src/scoring/checks/coverage.ts
2716
2725
  import { readFileSync, readdirSync } from "fs";
2717
2726
  import { join } from "path";
2718
- function readFileOrNull(path23) {
2727
+ function readFileOrNull(path26) {
2719
2728
  try {
2720
- return readFileSync(path23, "utf-8");
2729
+ return readFileSync(path26, "utf-8");
2721
2730
  } catch {
2722
2731
  return null;
2723
2732
  }
2724
2733
  }
2725
- function readJsonOrNull(path23) {
2726
- const content = readFileOrNull(path23);
2734
+ function readJsonOrNull(path26) {
2735
+ const content = readFileOrNull(path26);
2727
2736
  if (!content) return null;
2728
2737
  try {
2729
2738
  return JSON.parse(content);
@@ -3079,9 +3088,9 @@ function checkExistence(dir) {
3079
3088
  // src/scoring/checks/quality.ts
3080
3089
  import { readFileSync as readFileSync3 } from "fs";
3081
3090
  import { join as join3 } from "path";
3082
- function readFileOrNull2(path23) {
3091
+ function readFileOrNull2(path26) {
3083
3092
  try {
3084
- return readFileSync3(path23, "utf-8");
3093
+ return readFileSync3(path26, "utf-8");
3085
3094
  } catch {
3086
3095
  return null;
3087
3096
  }
@@ -3232,15 +3241,15 @@ function checkQuality(dir) {
3232
3241
  // src/scoring/checks/accuracy.ts
3233
3242
  import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync } from "fs";
3234
3243
  import { join as join4 } from "path";
3235
- function readFileOrNull3(path23) {
3244
+ function readFileOrNull3(path26) {
3236
3245
  try {
3237
- return readFileSync4(path23, "utf-8");
3246
+ return readFileSync4(path26, "utf-8");
3238
3247
  } catch {
3239
3248
  return null;
3240
3249
  }
3241
3250
  }
3242
- function readJsonOrNull2(path23) {
3243
- const content = readFileOrNull3(path23);
3251
+ function readJsonOrNull2(path26) {
3252
+ const content = readFileOrNull3(path26);
3244
3253
  if (!content) return null;
3245
3254
  try {
3246
3255
  return JSON.parse(content);
@@ -3423,9 +3432,9 @@ function checkAccuracy(dir) {
3423
3432
  // src/scoring/checks/freshness.ts
3424
3433
  import { readFileSync as readFileSync5, statSync as statSync2 } from "fs";
3425
3434
  import { join as join5 } from "path";
3426
- function readFileOrNull4(path23) {
3435
+ function readFileOrNull4(path26) {
3427
3436
  try {
3428
- return readFileSync5(path23, "utf-8");
3437
+ return readFileSync5(path26, "utf-8");
3429
3438
  } catch {
3430
3439
  return null;
3431
3440
  }
@@ -3535,9 +3544,9 @@ function checkFreshness(dir) {
3535
3544
  import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
3536
3545
  import { execSync as execSync7 } from "child_process";
3537
3546
  import { join as join6 } from "path";
3538
- function readFileOrNull5(path23) {
3547
+ function readFileOrNull5(path26) {
3539
3548
  try {
3540
- return readFileSync6(path23, "utf-8");
3549
+ return readFileSync6(path26, "utf-8");
3541
3550
  } catch {
3542
3551
  return null;
3543
3552
  }
@@ -3630,6 +3639,29 @@ function checkBonus(dir) {
3630
3639
  return checks;
3631
3640
  }
3632
3641
 
3642
+ // src/scoring/dismissed.ts
3643
+ init_constants();
3644
+ import fs17 from "fs";
3645
+ import path16 from "path";
3646
+ var DISMISSED_FILE = path16.join(CALIBER_DIR, "dismissed-checks.json");
3647
+ function readDismissedChecks() {
3648
+ try {
3649
+ if (!fs17.existsSync(DISMISSED_FILE)) return [];
3650
+ return JSON.parse(fs17.readFileSync(DISMISSED_FILE, "utf-8"));
3651
+ } catch {
3652
+ return [];
3653
+ }
3654
+ }
3655
+ function writeDismissedChecks(checks) {
3656
+ if (!fs17.existsSync(CALIBER_DIR)) {
3657
+ fs17.mkdirSync(CALIBER_DIR, { recursive: true });
3658
+ }
3659
+ fs17.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
3660
+ }
3661
+ function getDismissedIds() {
3662
+ return new Set(readDismissedChecks().map((c) => c.id));
3663
+ }
3664
+
3633
3665
  // src/scoring/index.ts
3634
3666
  function sumCategory(checks, category) {
3635
3667
  const categoryChecks = checks.filter((c) => c.category === category);
@@ -3666,7 +3698,8 @@ function computeLocalScore(dir, targetAgent) {
3666
3698
  ...checkFreshness(dir),
3667
3699
  ...checkBonus(dir)
3668
3700
  ];
3669
- const checks = filterChecksForTarget(allChecks, target);
3701
+ const dismissed = getDismissedIds();
3702
+ const checks = filterChecksForTarget(allChecks, target).filter((c) => !dismissed.has(c.id));
3670
3703
  const maxPossible = checks.reduce((s, c) => s + c.maxPoints, 0);
3671
3704
  const earned = checks.reduce((s, c) => s + c.earnedPoints, 0);
3672
3705
  const score = maxPossible > 0 ? Math.min(100, Math.max(0, Math.round(earned / maxPossible * 100))) : 0;
@@ -3772,7 +3805,7 @@ function displayScoreSummary(result) {
3772
3805
  const remaining = failing.length - shown.length;
3773
3806
  const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
3774
3807
  console.log(chalk3.dim(`
3775
- Run ${chalk3.reset("caliber score")} for details.${moreText}`));
3808
+ Run ${chalk3.hex("#83D1EB")("caliber score")} for details.${moreText}`));
3776
3809
  }
3777
3810
  console.log("");
3778
3811
  }
@@ -3820,10 +3853,758 @@ function displayScoreDelta(before, after) {
3820
3853
  }
3821
3854
  }
3822
3855
 
3856
+ // src/mcp/index.ts
3857
+ import chalk4 from "chalk";
3858
+ import ora from "ora";
3859
+ import readline3 from "readline";
3860
+ import fs19 from "fs";
3861
+ import path18 from "path";
3862
+
3863
+ // src/mcp/deps.ts
3864
+ import fs18 from "fs";
3865
+ import path17 from "path";
3866
+ function extractAllDeps(dir) {
3867
+ const deps = /* @__PURE__ */ new Set();
3868
+ parsePackageJson(dir, deps);
3869
+ parseRequirementsTxt(dir, deps);
3870
+ parsePyprojectToml(dir, deps);
3871
+ parseGoMod(dir, deps);
3872
+ parseCargoToml(dir, deps);
3873
+ parseGemfile(dir, deps);
3874
+ parseComposerJson(dir, deps);
3875
+ return Array.from(deps);
3876
+ }
3877
+ function readFileSafe(filePath) {
3878
+ try {
3879
+ if (fs18.existsSync(filePath)) {
3880
+ return fs18.readFileSync(filePath, "utf-8");
3881
+ }
3882
+ } catch {
3883
+ }
3884
+ return null;
3885
+ }
3886
+ function parsePackageJson(dir, deps) {
3887
+ const content = readFileSafe(path17.join(dir, "package.json"));
3888
+ if (!content) return;
3889
+ try {
3890
+ const pkg3 = JSON.parse(content);
3891
+ const allDeps = {
3892
+ ...pkg3.dependencies,
3893
+ ...pkg3.devDependencies
3894
+ };
3895
+ for (const name of Object.keys(allDeps)) {
3896
+ deps.add(name);
3897
+ }
3898
+ } catch {
3899
+ }
3900
+ }
3901
+ function parseRequirementsTxt(dir, deps) {
3902
+ const content = readFileSafe(path17.join(dir, "requirements.txt"));
3903
+ if (!content) return;
3904
+ for (const line of content.split("\n")) {
3905
+ const trimmed = line.trim();
3906
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("-")) continue;
3907
+ const match = trimmed.match(/^([a-zA-Z0-9_-]+(?:\[[^\]]*\])?)/);
3908
+ if (match) {
3909
+ deps.add(match[1].replace(/\[.*\]/, "").toLowerCase());
3910
+ }
3911
+ }
3912
+ }
3913
+ function parsePyprojectToml(dir, deps) {
3914
+ const content = readFileSafe(path17.join(dir, "pyproject.toml"));
3915
+ if (!content) return;
3916
+ const depsMatch = content.match(/\bdependencies\s*=\s*\[([\s\S]*?)\]/);
3917
+ if (depsMatch) {
3918
+ const items = depsMatch[1].matchAll(/"([a-zA-Z0-9_-]+)/g);
3919
+ for (const m of items) {
3920
+ deps.add(m[1].toLowerCase());
3921
+ }
3922
+ }
3923
+ }
3924
+ function parseGoMod(dir, deps) {
3925
+ const content = readFileSafe(path17.join(dir, "go.mod"));
3926
+ if (!content) return;
3927
+ const requireBlock = content.match(/require\s*\(([\s\S]*?)\)/g);
3928
+ if (requireBlock) {
3929
+ for (const block of requireBlock) {
3930
+ const lines = block.split("\n");
3931
+ for (const line of lines) {
3932
+ const match = line.trim().match(/^([a-zA-Z0-9./\-_]+)\s/);
3933
+ if (match && !match[1].startsWith("//") && match[1].includes("/")) {
3934
+ const parts = match[1].split("/");
3935
+ deps.add(parts[parts.length - 1]);
3936
+ }
3937
+ }
3938
+ }
3939
+ }
3940
+ }
3941
+ function parseCargoToml(dir, deps) {
3942
+ const content = readFileSafe(path17.join(dir, "Cargo.toml"));
3943
+ if (!content) return;
3944
+ const sections = content.split(/\[/);
3945
+ for (const section of sections) {
3946
+ if (section.startsWith("dependencies]") || section.startsWith("dev-dependencies]")) {
3947
+ const lines = section.split("\n").slice(1);
3948
+ for (const line of lines) {
3949
+ if (line.startsWith("[")) break;
3950
+ const match = line.match(/^([a-zA-Z0-9_-]+)\s*=/);
3951
+ if (match) {
3952
+ deps.add(match[1]);
3953
+ }
3954
+ }
3955
+ }
3956
+ }
3957
+ }
3958
+ function parseGemfile(dir, deps) {
3959
+ const content = readFileSafe(path17.join(dir, "Gemfile"));
3960
+ if (!content) return;
3961
+ const gemPattern = /gem\s+['"]([a-zA-Z0-9_-]+)['"]/g;
3962
+ let match;
3963
+ while ((match = gemPattern.exec(content)) !== null) {
3964
+ deps.add(match[1]);
3965
+ }
3966
+ }
3967
+ function parseComposerJson(dir, deps) {
3968
+ const content = readFileSafe(path17.join(dir, "composer.json"));
3969
+ if (!content) return;
3970
+ try {
3971
+ const composer = JSON.parse(content);
3972
+ const allDeps = {
3973
+ ...composer.require,
3974
+ ...composer["require-dev"]
3975
+ };
3976
+ for (const name of Object.keys(allDeps)) {
3977
+ if (name !== "php" && !name.startsWith("ext-")) {
3978
+ deps.add(name);
3979
+ }
3980
+ }
3981
+ } catch {
3982
+ }
3983
+ }
3984
+
3985
+ // src/mcp/prompts.ts
3986
+ var CLASSIFY_DEPS_PROMPT = `You classify software dependencies into two categories:
3987
+
3988
+ **Tools** (MCP-worthy): Services, platforms, APIs, databases, SaaS products, and cloud services that have their own web dashboards, APIs, or external infrastructure. Examples: supabase, stripe, sentry, datadog, firebase, mongodb, redis, slack, linear, github, vercel, aws-sdk, twilio, sendgrid, algolia, elasticsearch, prisma, planetscale, neon, clerk, auth0.
3989
+
3990
+ **Libraries** (skip): Utility packages, frameworks, build tools, test runners, and local-only code that does NOT connect to an external service. Examples: lodash, react, express, vitest, webpack, zod, chalk, commander, typescript, eslint, prettier, axios, dayjs, uuid.
3991
+
3992
+ Given a list of dependencies, return ONLY the tool dependencies as a JSON array of strings.
3993
+ Return ONLY the JSON array, no explanation.`;
3994
+ var SCORE_MCP_PROMPT = `You evaluate MCP (Model Context Protocol) server candidates for relevance to a software project.
3995
+
3996
+ Score each candidate from 0-100 based on:
3997
+ - **Relevance** (40%): How directly does it match the project's detected tool dependencies?
3998
+ - **Capabilities** (30%): Does it provide meaningful read+write operations (not just read-only)?
3999
+ - **Quality signals** (30%): Stars, recent activity, vendor/official status
4000
+
4001
+ Return a JSON array where each element has:
4002
+ - "index": the candidate's index number
4003
+ - "score": relevance score 0-100
4004
+ - "reason": one-liner explaining the score (max 80 chars)
4005
+
4006
+ Be selective. Only score candidates that would genuinely help developers working on this project.
4007
+ Return ONLY the JSON array.`;
4008
+ var EXTRACT_CONFIG_PROMPT = `You extract MCP server configuration from a README file.
4009
+
4010
+ Look for the MCP server's configuration block \u2014 typically a JSON snippet showing how to add it to claude_desktop_config.json, .mcp.json, or similar.
4011
+
4012
+ Return a JSON object with:
4013
+ - "command": the executable command (e.g., "npx", "uvx", "node", "docker")
4014
+ - "args": array of arguments (e.g., ["-y", "@supabase/mcp-server"])
4015
+ - "env": array of objects, each with:
4016
+ - "key": environment variable name (e.g., "SUPABASE_ACCESS_TOKEN")
4017
+ - "description": brief description of what this value is (e.g., "Personal access token from dashboard")
4018
+ - "required": boolean
4019
+
4020
+ If the README shows multiple configuration methods, prefer npx > uvx > node > docker.
4021
+ If you cannot determine the configuration, return {"command": "", "args": [], "env": []}.
4022
+ Return ONLY the JSON object.`;
4023
+
4024
+ // src/mcp/classify.ts
4025
+ async function classifyDeps(allDeps) {
4026
+ if (allDeps.length === 0) return [];
4027
+ try {
4028
+ const result = await llmJsonCall({
4029
+ system: CLASSIFY_DEPS_PROMPT,
4030
+ prompt: `Dependencies:
4031
+ ${JSON.stringify(allDeps)}`,
4032
+ maxTokens: 2e3
4033
+ });
4034
+ if (!Array.isArray(result)) return [];
4035
+ const inputLower = new Set(allDeps.map((d) => d.toLowerCase()));
4036
+ return result.filter((d) => typeof d === "string" && inputLower.has(d.toLowerCase()));
4037
+ } catch {
4038
+ return fallbackClassify(allDeps);
4039
+ }
4040
+ }
4041
+ function fallbackClassify(deps) {
4042
+ const utilityPatterns = [
4043
+ /^@types\//,
4044
+ /^eslint/,
4045
+ /^prettier/,
4046
+ /^@typescript-eslint\//,
4047
+ /^@commitlint\//,
4048
+ /^@eslint\//,
4049
+ /^webpack/,
4050
+ /^rollup/,
4051
+ /^babel/,
4052
+ /^@babel\//,
4053
+ /^postcss/,
4054
+ /^tailwindcss/,
4055
+ /^autoprefixer/
4056
+ ];
4057
+ const utilities = /* @__PURE__ */ new Set([
4058
+ "typescript",
4059
+ "tslib",
4060
+ "ts-node",
4061
+ "tsx",
4062
+ "prettier",
4063
+ "eslint",
4064
+ "rimraf",
4065
+ "cross-env",
4066
+ "dotenv",
4067
+ "nodemon",
4068
+ "husky",
4069
+ "lint-staged",
4070
+ "commitlint",
4071
+ "chalk",
4072
+ "ora",
4073
+ "commander",
4074
+ "yargs",
4075
+ "meow",
4076
+ "inquirer",
4077
+ "glob",
4078
+ "minimatch",
4079
+ "micromatch",
4080
+ "diff",
4081
+ "semver",
4082
+ "uuid",
4083
+ "nanoid",
4084
+ "debug",
4085
+ "ms",
4086
+ "lodash",
4087
+ "underscore",
4088
+ "ramda",
4089
+ "tsup",
4090
+ "esbuild",
4091
+ "rollup",
4092
+ "webpack",
4093
+ "vite",
4094
+ "parcel",
4095
+ "vitest",
4096
+ "jest",
4097
+ "mocha",
4098
+ "chai",
4099
+ "ava",
4100
+ "tap",
4101
+ "fs-extra",
4102
+ "mkdirp",
4103
+ "del",
4104
+ "path-to-regexp",
4105
+ "strip-ansi",
4106
+ "ansi-colors",
4107
+ "react",
4108
+ "react-dom",
4109
+ "next",
4110
+ "vue",
4111
+ "angular",
4112
+ "svelte",
4113
+ "express",
4114
+ "fastify",
4115
+ "koa",
4116
+ "hapi",
4117
+ "zod",
4118
+ "joi",
4119
+ "yup",
4120
+ "ajv",
4121
+ "axios",
4122
+ "node-fetch",
4123
+ "got",
4124
+ "undici",
4125
+ "moment",
4126
+ "dayjs",
4127
+ "date-fns",
4128
+ "luxon"
4129
+ ]);
4130
+ return deps.filter((d) => {
4131
+ const lower = d.toLowerCase();
4132
+ if (utilities.has(lower)) return false;
4133
+ if (utilityPatterns.some((p) => p.test(lower))) return false;
4134
+ return true;
4135
+ });
4136
+ }
4137
+
4138
+ // src/mcp/search.ts
4139
+ var AWESOME_MCP_URL = "https://raw.githubusercontent.com/punkpeye/awesome-mcp-servers/main/README.md";
4140
+ var GITHUB_SEARCH_URL = "https://github.com/search";
4141
+ var SEARCH_HEADERS = {
4142
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
4143
+ "Accept": "text/html"
4144
+ };
4145
+ function parseGitHubSearchHtml(html) {
4146
+ try {
4147
+ const scriptMatch = html.match(/<script type="application\/json" data-target="react-app\.embeddedData">([\s\S]*?)<\/script>/);
4148
+ if (!scriptMatch) {
4149
+ return [];
4150
+ }
4151
+ const data = JSON.parse(scriptMatch[1]);
4152
+ const results = data?.payload?.results;
4153
+ if (!Array.isArray(results)) {
4154
+ return [];
4155
+ }
4156
+ return results.map((r) => {
4157
+ const repo = r.repo?.repository;
4158
+ const ownerLogin = repo?.owner_login || "";
4159
+ const name = repo?.name || "";
4160
+ const description = typeof r.hl_trunc_description === "string" ? r.hl_trunc_description.replace(/<\/?em>/g, "") : null;
4161
+ return {
4162
+ full_name: `${ownerLogin}/${name}`,
4163
+ description,
4164
+ stargazers_count: typeof r.followers === "number" ? r.followers : 0,
4165
+ pushed_at: repo?.updated_at || "",
4166
+ owner_login: ownerLogin
4167
+ };
4168
+ });
4169
+ } catch {
4170
+ return [];
4171
+ }
4172
+ }
4173
+ async function searchAllMcpSources(toolDeps) {
4174
+ if (toolDeps.length === 0) return [];
4175
+ const searches = [
4176
+ searchAwesomeMcpLists(toolDeps),
4177
+ ...toolDeps.map((dep) => searchGitHub(dep)),
4178
+ ...toolDeps.map((dep) => searchVendorOrg(dep))
4179
+ ];
4180
+ const results = await Promise.all(searches);
4181
+ const seen = /* @__PURE__ */ new Map();
4182
+ for (const batch of results) {
4183
+ for (const candidate of batch) {
4184
+ const key = candidate.repoFullName.toLowerCase();
4185
+ const existing = seen.get(key);
4186
+ if (!existing || candidate.vendor || candidate.stars > existing.stars) {
4187
+ seen.set(key, candidate);
4188
+ }
4189
+ }
4190
+ }
4191
+ return Array.from(seen.values());
4192
+ }
4193
+ async function searchAwesomeMcpLists(toolDeps) {
4194
+ try {
4195
+ const resp = await fetch(AWESOME_MCP_URL, {
4196
+ signal: AbortSignal.timeout(1e4)
4197
+ });
4198
+ if (!resp.ok) return [];
4199
+ const markdown = await resp.text();
4200
+ const candidates = [];
4201
+ const depLower = toolDeps.map((d) => d.toLowerCase().replace(/^@[^/]+\//, ""));
4202
+ const itemPattern = /^[-*]\s+\[([^\]]+)\]\(([^)]+)\)\s*[-–—:]\s*(.*)/gm;
4203
+ let match;
4204
+ while ((match = itemPattern.exec(markdown)) !== null) {
4205
+ const [, name, url, description] = match;
4206
+ if (!url.includes("github.com")) continue;
4207
+ const text = `${name} ${description}`.toLowerCase();
4208
+ const matchedDep = depLower.find((d) => text.includes(d));
4209
+ if (!matchedDep) continue;
4210
+ const repoMatch = url.match(/github\.com\/([^/]+\/[^/]+)/);
4211
+ if (!repoMatch) continue;
4212
+ candidates.push({
4213
+ name: name.trim(),
4214
+ repoFullName: repoMatch[1],
4215
+ url: url.trim(),
4216
+ description: description.trim().slice(0, 200),
4217
+ stars: 0,
4218
+ lastPush: "",
4219
+ vendor: false,
4220
+ score: 0,
4221
+ reason: "",
4222
+ matchedDep: toolDeps.find((d) => d.toLowerCase().replace(/^@[^/]+\//, "") === matchedDep) || matchedDep
4223
+ });
4224
+ }
4225
+ return candidates;
4226
+ } catch {
4227
+ return [];
4228
+ }
4229
+ }
4230
+ async function searchGitHub(dep) {
4231
+ const depName = dep.replace(/^@[^/]+\//, "");
4232
+ try {
4233
+ const query = encodeURIComponent(`${depName} mcp server`);
4234
+ const url = `${GITHUB_SEARCH_URL}?q=${query}&type=repositories&s=stars&o=desc`;
4235
+ const resp = await fetch(url, {
4236
+ signal: AbortSignal.timeout(1e4),
4237
+ headers: SEARCH_HEADERS
4238
+ });
4239
+ if (!resp.ok) return [];
4240
+ const html = await resp.text();
4241
+ const repos = parseGitHubSearchHtml(html).slice(0, 5);
4242
+ return repos.map((repo) => ({
4243
+ name: repo.full_name.split("/")[1],
4244
+ repoFullName: repo.full_name,
4245
+ url: `https://github.com/${repo.full_name}`,
4246
+ description: repo.description || "",
4247
+ stars: repo.stargazers_count,
4248
+ lastPush: repo.pushed_at,
4249
+ vendor: false,
4250
+ score: 0,
4251
+ reason: "",
4252
+ matchedDep: dep
4253
+ }));
4254
+ } catch {
4255
+ return [];
4256
+ }
4257
+ }
4258
+ async function searchVendorOrg(dep) {
4259
+ const depName = dep.replace(/^@([^/]+)\/.*/, "$1").replace(/^@/, "");
4260
+ const orgName = depName.toLowerCase();
4261
+ try {
4262
+ const query = encodeURIComponent(`mcp org:${orgName}`);
4263
+ const url = `${GITHUB_SEARCH_URL}?q=${query}&type=repositories&s=stars&o=desc`;
4264
+ const resp = await fetch(url, {
4265
+ signal: AbortSignal.timeout(1e4),
4266
+ headers: SEARCH_HEADERS
4267
+ });
4268
+ if (!resp.ok) return [];
4269
+ const html = await resp.text();
4270
+ const repos = parseGitHubSearchHtml(html).slice(0, 5);
4271
+ return repos.map((repo) => ({
4272
+ name: repo.full_name.split("/")[1],
4273
+ repoFullName: repo.full_name,
4274
+ url: `https://github.com/${repo.full_name}`,
4275
+ description: repo.description || "",
4276
+ stars: repo.stargazers_count,
4277
+ lastPush: repo.pushed_at,
4278
+ vendor: repo.owner_login.toLowerCase() === orgName,
4279
+ score: 0,
4280
+ reason: "",
4281
+ matchedDep: dep
4282
+ }));
4283
+ } catch {
4284
+ return [];
4285
+ }
4286
+ }
4287
+
4288
+ // src/mcp/validate.ts
4289
+ var MIN_STARS = 100;
4290
+ var MAX_AGE_DAYS = 180;
4291
+ async function validateAndScore(candidates, toolDeps) {
4292
+ const qualityFiltered = candidates.filter((c) => {
4293
+ if (c.vendor) return true;
4294
+ if (c.stars > 0 && c.stars < MIN_STARS) return false;
4295
+ if (c.lastPush) {
4296
+ const pushDate = new Date(c.lastPush);
4297
+ const daysAgo = (Date.now() - pushDate.getTime()) / (1e3 * 60 * 60 * 24);
4298
+ if (daysAgo > MAX_AGE_DAYS) return false;
4299
+ }
4300
+ return true;
4301
+ });
4302
+ if (qualityFiltered.length === 0) return [];
4303
+ try {
4304
+ return await scoreWithLLM(qualityFiltered, toolDeps);
4305
+ } catch {
4306
+ return qualityFiltered.slice(0, 5).map((c) => ({
4307
+ ...c,
4308
+ score: 50,
4309
+ reason: c.description.slice(0, 80)
4310
+ }));
4311
+ }
4312
+ }
4313
+ async function scoreWithLLM(candidates, toolDeps) {
4314
+ const candidateList = candidates.map((c, i) => {
4315
+ const vendorTag = c.vendor ? " [VENDOR/OFFICIAL]" : "";
4316
+ return `${i}. "${c.name}"${vendorTag} (${c.stars} stars) \u2014 ${c.description.slice(0, 100)}`;
4317
+ }).join("\n");
4318
+ const scored = await llmJsonCall({
4319
+ system: SCORE_MCP_PROMPT,
4320
+ prompt: `TOOL DEPENDENCIES IN PROJECT:
4321
+ ${toolDeps.join(", ")}
4322
+
4323
+ MCP SERVER CANDIDATES:
4324
+ ${candidateList}`,
4325
+ maxTokens: 4e3
4326
+ });
4327
+ if (!Array.isArray(scored)) return [];
4328
+ return scored.filter((s) => s.score >= 60 && s.index >= 0 && s.index < candidates.length).sort((a, b) => b.score - a.score).slice(0, 5).map((s) => ({
4329
+ ...candidates[s.index],
4330
+ score: s.score,
4331
+ reason: s.reason || candidates[s.index].description.slice(0, 80)
4332
+ }));
4333
+ }
4334
+
4335
+ // src/mcp/config-extract.ts
4336
+ async function fetchReadme(repoFullName) {
4337
+ try {
4338
+ const resp = await fetch(
4339
+ `https://raw.githubusercontent.com/${repoFullName}/HEAD/README.md`,
4340
+ { signal: AbortSignal.timeout(1e4) }
4341
+ );
4342
+ if (resp.ok) return await resp.text();
4343
+ } catch {
4344
+ }
4345
+ try {
4346
+ const resp = await fetch(
4347
+ `https://raw.githubusercontent.com/${repoFullName}/main/README.md`,
4348
+ { signal: AbortSignal.timeout(1e4) }
4349
+ );
4350
+ if (resp.ok) return await resp.text();
4351
+ } catch {
4352
+ }
4353
+ return null;
4354
+ }
4355
+ async function extractMcpConfig(readme, serverName) {
4356
+ try {
4357
+ const truncated = readme.length > 15e3 ? readme.slice(0, 15e3) : readme;
4358
+ const result = await llmJsonCall({
4359
+ system: EXTRACT_CONFIG_PROMPT,
4360
+ prompt: `MCP Server: ${serverName}
4361
+
4362
+ README:
4363
+ ${truncated}`,
4364
+ maxTokens: 2e3
4365
+ });
4366
+ if (!result || !result.command) return null;
4367
+ return {
4368
+ command: result.command,
4369
+ args: Array.isArray(result.args) ? result.args : [],
4370
+ env: Array.isArray(result.env) ? result.env : []
4371
+ };
4372
+ } catch {
4373
+ return null;
4374
+ }
4375
+ }
4376
+
4377
+ // src/mcp/index.ts
4378
+ async function discoverAndInstallMcps(targetAgent, fingerprint, dir) {
4379
+ console.log(chalk4.hex("#6366f1").bold("\n MCP Server Discovery\n"));
4380
+ const spinner = ora("Analyzing dependencies for tool integrations...").start();
4381
+ const allDeps = extractAllDeps(dir);
4382
+ if (allDeps.length === 0) {
4383
+ spinner.succeed(chalk4.dim("No dependencies found \u2014 skipping MCP discovery"));
4384
+ return { installed: 0, names: [] };
4385
+ }
4386
+ const toolDeps = await classifyDeps(allDeps);
4387
+ if (toolDeps.length === 0) {
4388
+ spinner.succeed(chalk4.dim("No tool dependencies detected \u2014 skipping MCP discovery"));
4389
+ console.log(chalk4.dim(` All deps (${allDeps.length}): ${allDeps.slice(0, 10).join(", ")}${allDeps.length > 10 ? "..." : ""}`));
4390
+ return { installed: 0, names: [] };
4391
+ }
4392
+ spinner.succeed(`Found ${toolDeps.length} tool dependenc${toolDeps.length === 1 ? "y" : "ies"}: ${toolDeps.join(", ")}`);
4393
+ console.log(chalk4.dim(` All deps (${allDeps.length}): ${allDeps.slice(0, 10).join(", ")}${allDeps.length > 10 ? "..." : ""}`));
4394
+ console.log(chalk4.dim(` Classified as tools: ${toolDeps.join(", ")}`));
4395
+ const existingMcps = getExistingMcpNames(fingerprint, targetAgent);
4396
+ const filteredDeps = toolDeps.filter((d) => {
4397
+ const lower = d.toLowerCase().replace(/^@[^/]+\//, "");
4398
+ return !existingMcps.some((name) => name.includes(lower) || lower.includes(name));
4399
+ });
4400
+ if (filteredDeps.length === 0) {
4401
+ console.log(chalk4.dim(" All detected tools already have MCP servers configured."));
4402
+ console.log(chalk4.dim(` Existing MCPs: ${existingMcps.join(", ")}`));
4403
+ return { installed: 0, names: [] };
4404
+ }
4405
+ const searchSpinner = ora("Searching for MCP servers...").start();
4406
+ const candidates = await searchAllMcpSources(filteredDeps);
4407
+ if (candidates.length === 0) {
4408
+ searchSpinner.succeed(chalk4.dim("No MCP servers found for your dependencies"));
4409
+ console.log(chalk4.dim(` Searched for: ${filteredDeps.join(", ")}`));
4410
+ return { installed: 0, names: [] };
4411
+ }
4412
+ searchSpinner.succeed(`Found ${candidates.length} candidate${candidates.length === 1 ? "" : "s"}`);
4413
+ console.log(chalk4.dim(` Sources: ${candidates.map((c) => c.repoFullName).join(", ")}`));
4414
+ const scoreSpinner = ora("Scoring MCP candidates...").start();
4415
+ const scored = await validateAndScore(candidates, filteredDeps);
4416
+ if (scored.length === 0) {
4417
+ scoreSpinner.succeed(chalk4.dim("No quality MCP servers passed validation"));
4418
+ console.log(chalk4.dim(` Candidates checked: ${candidates.map((c) => c.name).join(", ")}`));
4419
+ return { installed: 0, names: [] };
4420
+ }
4421
+ scoreSpinner.succeed(`${scored.length} quality MCP server${scored.length === 1 ? "" : "s"} found`);
4422
+ console.log(chalk4.dim(` Scored: ${scored.map((c) => `${c.name} (${c.score})`).join(", ")}`));
4423
+ const selected = await interactiveSelect(scored);
4424
+ if (!selected || selected.length === 0) {
4425
+ return { installed: 0, names: [] };
4426
+ }
4427
+ const mcpServers = {};
4428
+ const installedNames = [];
4429
+ for (const mcp of selected) {
4430
+ console.log(chalk4.bold(`
4431
+ Configuring ${mcp.name}...`));
4432
+ const readme = await fetchReadme(mcp.repoFullName);
4433
+ if (!readme) {
4434
+ console.log(chalk4.yellow(` Could not fetch README for ${mcp.repoFullName} \u2014 skipping`));
4435
+ console.log(chalk4.dim(` Manual setup: ${mcp.url}`));
4436
+ continue;
4437
+ }
4438
+ const config = await extractMcpConfig(readme, mcp.name);
4439
+ if (!config || !config.command) {
4440
+ console.log(chalk4.yellow(` Could not extract config for ${mcp.name} \u2014 skipping`));
4441
+ console.log(chalk4.dim(` Manual setup: ${mcp.url}`));
4442
+ continue;
4443
+ }
4444
+ const env = {};
4445
+ for (const envVar of config.env) {
4446
+ if (!envVar.required) continue;
4447
+ const value = await promptInput2(` ? ${envVar.key} (${envVar.description})`);
4448
+ if (value) {
4449
+ env[envVar.key] = value;
4450
+ }
4451
+ }
4452
+ const serverConfig = {
4453
+ command: config.command
4454
+ };
4455
+ if (config.args.length > 0) serverConfig.args = config.args;
4456
+ if (Object.keys(env).length > 0) serverConfig.env = env;
4457
+ mcpServers[mcp.name] = serverConfig;
4458
+ installedNames.push(mcp.name);
4459
+ console.log(` ${chalk4.green("\u2713")} ${mcp.name} configured`);
4460
+ }
4461
+ if (installedNames.length === 0) {
4462
+ return { installed: 0, names: [] };
4463
+ }
4464
+ if (targetAgent === "claude" || targetAgent === "both") {
4465
+ writeMcpJson(path18.join(dir, ".mcp.json"), mcpServers);
4466
+ }
4467
+ if (targetAgent === "cursor" || targetAgent === "both") {
4468
+ const cursorDir = path18.join(dir, ".cursor");
4469
+ if (!fs19.existsSync(cursorDir)) fs19.mkdirSync(cursorDir, { recursive: true });
4470
+ writeMcpJson(path18.join(cursorDir, "mcp.json"), mcpServers);
4471
+ }
4472
+ return { installed: installedNames.length, names: installedNames };
4473
+ }
4474
+ function writeMcpJson(filePath, mcpServers) {
4475
+ let existing = {};
4476
+ try {
4477
+ if (fs19.existsSync(filePath)) {
4478
+ const parsed = JSON.parse(fs19.readFileSync(filePath, "utf-8"));
4479
+ if (parsed.mcpServers) existing = parsed.mcpServers;
4480
+ }
4481
+ } catch {
4482
+ }
4483
+ const merged = { ...existing, ...mcpServers };
4484
+ fs19.writeFileSync(filePath, JSON.stringify({ mcpServers: merged }, null, 2) + "\n");
4485
+ }
4486
+ function getExistingMcpNames(fingerprint, targetAgent) {
4487
+ const names = [];
4488
+ if (targetAgent === "claude" || targetAgent === "both") {
4489
+ if (fingerprint.existingConfigs.claudeMcpServers) {
4490
+ names.push(...Object.keys(fingerprint.existingConfigs.claudeMcpServers).map((k) => k.toLowerCase()));
4491
+ }
4492
+ }
4493
+ if (targetAgent === "cursor" || targetAgent === "both") {
4494
+ if (fingerprint.existingConfigs.cursorMcpServers) {
4495
+ names.push(...Object.keys(fingerprint.existingConfigs.cursorMcpServers).map((k) => k.toLowerCase()));
4496
+ }
4497
+ }
4498
+ return names;
4499
+ }
4500
+ function promptInput2(question) {
4501
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
4502
+ return new Promise((resolve2) => {
4503
+ rl.question(chalk4.cyan(`${question}: `), (answer) => {
4504
+ rl.close();
4505
+ resolve2(answer.trim());
4506
+ });
4507
+ });
4508
+ }
4509
+ async function interactiveSelect(candidates) {
4510
+ if (!process.stdin.isTTY) {
4511
+ console.log(chalk4.bold("\n Available MCP servers:\n"));
4512
+ for (const c of candidates) {
4513
+ const vendorTag = c.vendor ? chalk4.blue(" (vendor)") : "";
4514
+ console.log(` ${String(c.score).padStart(3)} ${c.name}${vendorTag} ${chalk4.dim(c.reason)}`);
4515
+ }
4516
+ console.log("");
4517
+ return null;
4518
+ }
4519
+ const selected = /* @__PURE__ */ new Set();
4520
+ let cursor = 0;
4521
+ const { stdin, stdout } = process;
4522
+ let lineCount = 0;
4523
+ function render() {
4524
+ const lines = [];
4525
+ lines.push(chalk4.bold(" Select MCP servers to install:"));
4526
+ lines.push("");
4527
+ for (let i = 0; i < candidates.length; i++) {
4528
+ const c = candidates[i];
4529
+ const check = selected.has(i) ? chalk4.green("[x]") : "[ ]";
4530
+ const ptr = i === cursor ? chalk4.cyan(">") : " ";
4531
+ const scoreColor = c.score >= 90 ? chalk4.green : c.score >= 70 ? chalk4.yellow : chalk4.dim;
4532
+ const vendorTag = c.vendor ? chalk4.blue(" (vendor)") : "";
4533
+ lines.push(` ${ptr} ${check} ${scoreColor(String(c.score).padStart(3))} ${c.name}${vendorTag} ${chalk4.dim(c.reason.slice(0, 40))}`);
4534
+ }
4535
+ lines.push("");
4536
+ lines.push(chalk4.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q skip"));
4537
+ return lines.join("\n");
4538
+ }
4539
+ function draw(initial) {
4540
+ if (!initial && lineCount > 0) {
4541
+ stdout.write(`\x1B[${lineCount}A`);
4542
+ }
4543
+ stdout.write("\x1B[0J");
4544
+ const output = render();
4545
+ stdout.write(output + "\n");
4546
+ lineCount = output.split("\n").length;
4547
+ }
4548
+ return new Promise((resolve2) => {
4549
+ console.log("");
4550
+ draw(true);
4551
+ stdin.setRawMode(true);
4552
+ stdin.resume();
4553
+ stdin.setEncoding("utf8");
4554
+ function cleanup() {
4555
+ stdin.removeListener("data", onData);
4556
+ stdin.setRawMode(false);
4557
+ stdin.pause();
4558
+ }
4559
+ function onData(key) {
4560
+ switch (key) {
4561
+ case "\x1B[A":
4562
+ cursor = (cursor - 1 + candidates.length) % candidates.length;
4563
+ draw(false);
4564
+ break;
4565
+ case "\x1B[B":
4566
+ cursor = (cursor + 1) % candidates.length;
4567
+ draw(false);
4568
+ break;
4569
+ case " ":
4570
+ selected.has(cursor) ? selected.delete(cursor) : selected.add(cursor);
4571
+ draw(false);
4572
+ break;
4573
+ case "a":
4574
+ candidates.forEach((_, i) => selected.add(i));
4575
+ draw(false);
4576
+ break;
4577
+ case "n":
4578
+ selected.clear();
4579
+ draw(false);
4580
+ break;
4581
+ case "\r":
4582
+ case "\n":
4583
+ cleanup();
4584
+ if (selected.size === 0) {
4585
+ console.log(chalk4.dim("\n No MCP servers selected.\n"));
4586
+ resolve2(null);
4587
+ } else {
4588
+ resolve2(Array.from(selected).sort().map((i) => candidates[i]));
4589
+ }
4590
+ break;
4591
+ case "q":
4592
+ case "\x1B":
4593
+ case "":
4594
+ cleanup();
4595
+ console.log(chalk4.dim("\n Skipped MCP server installation.\n"));
4596
+ resolve2(null);
4597
+ break;
4598
+ }
4599
+ }
4600
+ stdin.on("data", onData);
4601
+ });
4602
+ }
4603
+
3823
4604
  // src/commands/onboard.ts
3824
4605
  async function initCommand(options) {
3825
- const brand = chalk4.hex("#EB9D83");
3826
- const title = chalk4.hex("#83D1EB");
4606
+ const brand = chalk5.hex("#EB9D83");
4607
+ const title = chalk5.hex("#83D1EB");
3827
4608
  console.log(brand.bold(`
3828
4609
  \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
3829
4610
  \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
@@ -3832,19 +4613,19 @@ async function initCommand(options) {
3832
4613
  \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
3833
4614
  \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
3834
4615
  `));
3835
- console.log(chalk4.dim(" Onboard your project for AI-assisted development\n"));
4616
+ console.log(chalk5.dim(" Onboard your project for AI-assisted development\n"));
3836
4617
  console.log(title.bold(" Welcome to Caliber\n"));
3837
- console.log(chalk4.dim(" Caliber analyzes your codebase and creates tailored config files"));
3838
- console.log(chalk4.dim(" so your AI coding agents understand your project from day one.\n"));
4618
+ console.log(chalk5.dim(" Caliber analyzes your codebase and creates tailored config files"));
4619
+ console.log(chalk5.dim(" so your AI coding agents understand your project from day one.\n"));
3839
4620
  console.log(title.bold(" How onboarding works:\n"));
3840
- console.log(chalk4.dim(" 1. Connect Set up your LLM provider"));
3841
- console.log(chalk4.dim(" 2. Discover Analyze your code, dependencies, and structure"));
3842
- console.log(chalk4.dim(" 3. Generate Create config files tailored to your project"));
3843
- console.log(chalk4.dim(" 4. Review Preview, refine, and apply the changes\n"));
4621
+ console.log(chalk5.dim(" 1. Connect Set up your LLM provider"));
4622
+ console.log(chalk5.dim(" 2. Discover Analyze your code, dependencies, and structure"));
4623
+ console.log(chalk5.dim(" 3. Generate Create config files tailored to your project"));
4624
+ console.log(chalk5.dim(" 4. Review Preview, refine, and apply the changes\n"));
3844
4625
  console.log(title.bold(" Step 1/4 \u2014 Connect your LLM\n"));
3845
4626
  let config = loadConfig();
3846
4627
  if (!config) {
3847
- console.log(chalk4.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
4628
+ console.log(chalk5.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
3848
4629
  try {
3849
4630
  await runInteractiveProviderSetup({
3850
4631
  selectMessage: "How do you want to use Caliber? (choose LLM provider)"
@@ -3855,36 +4636,47 @@ async function initCommand(options) {
3855
4636
  }
3856
4637
  config = loadConfig();
3857
4638
  if (!config) {
3858
- console.log(chalk4.red(" Setup was cancelled or failed.\n"));
4639
+ console.log(chalk5.red(" Setup was cancelled or failed.\n"));
3859
4640
  throw new Error("__exit__");
3860
4641
  }
3861
- console.log(chalk4.green(" \u2713 Provider saved. Let's continue.\n"));
4642
+ console.log(chalk5.green(" \u2713 Provider saved. Let's continue.\n"));
3862
4643
  }
3863
4644
  const displayModel = config.model === "default" && config.provider === "claude-cli" ? process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)" : config.model;
3864
4645
  const fastModel = process.env.ANTHROPIC_SMALL_FAST_MODEL;
3865
4646
  const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
3866
- console.log(chalk4.dim(modelLine + "\n"));
4647
+ console.log(chalk5.dim(modelLine + "\n"));
3867
4648
  console.log(title.bold(" Step 2/4 \u2014 Discover your project\n"));
3868
- console.log(chalk4.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
3869
- const spinner = ora("Analyzing project...").start();
4649
+ console.log(chalk5.dim(" Learning about your languages, dependencies, structure, and existing configs.\n"));
4650
+ const spinner = ora2("Analyzing project...").start();
3870
4651
  const fingerprint = collectFingerprint(process.cwd());
3871
4652
  await enrichFingerprintWithLLM(fingerprint, process.cwd());
3872
4653
  spinner.succeed("Project analyzed");
3873
- console.log(chalk4.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
3874
- console.log(chalk4.dim(` Files: ${fingerprint.fileTree.length} found
4654
+ console.log(chalk5.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
4655
+ console.log(chalk5.dim(` Files: ${fingerprint.fileTree.length} found
3875
4656
  `));
3876
4657
  const targetAgent = options.agent || await promptAgent();
4658
+ const preScore = computeLocalScore(process.cwd(), targetAgent);
4659
+ const failingForDismissal = preScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
4660
+ if (failingForDismissal.length > 0) {
4661
+ const newDismissals = await evaluateDismissals(failingForDismissal, fingerprint);
4662
+ if (newDismissals.length > 0) {
4663
+ const existing = readDismissedChecks();
4664
+ const existingIds = new Set(existing.map((d) => d.id));
4665
+ const merged = [...existing, ...newDismissals.filter((d) => !existingIds.has(d.id))];
4666
+ writeDismissedChecks(merged);
4667
+ }
4668
+ }
3877
4669
  const baselineScore = computeLocalScore(process.cwd(), targetAgent);
3878
4670
  displayScoreSummary(baselineScore);
3879
4671
  const hasExistingConfig = !!(fingerprint.existingConfigs.claudeMd || fingerprint.existingConfigs.claudeSettings || fingerprint.existingConfigs.claudeSkills?.length || fingerprint.existingConfigs.cursorrules || fingerprint.existingConfigs.cursorRules?.length);
3880
4672
  if (hasExistingConfig && baselineScore.score === 100) {
3881
- console.log(chalk4.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
3882
- console.log(chalk4.dim(" Run `caliber onboard --force` to regenerate anyway.\n"));
4673
+ console.log(chalk5.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
4674
+ console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber onboard --force") + chalk5.dim(" to regenerate anyway.\n"));
3883
4675
  if (!options.force) return;
3884
4676
  }
3885
4677
  const isEmpty = fingerprint.fileTree.length < 3;
3886
4678
  if (isEmpty) {
3887
- fingerprint.description = await promptInput2("What will you build in this project?");
4679
+ fingerprint.description = await promptInput3("What will you build in this project?");
3888
4680
  }
3889
4681
  let failingChecks;
3890
4682
  let passingChecks;
@@ -3895,24 +4687,24 @@ async function initCommand(options) {
3895
4687
  currentScore = baselineScore.score;
3896
4688
  if (failingChecks.length > 0) {
3897
4689
  console.log(title.bold(" Step 3/4 \u2014 Fine-tuning\n"));
3898
- console.log(chalk4.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
4690
+ console.log(chalk5.dim(` Your setup scores ${baselineScore.score}/100 \u2014 fixing ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
3899
4691
  `));
3900
4692
  for (const check of failingChecks) {
3901
- console.log(chalk4.dim(` \u2022 ${check.name}`));
4693
+ console.log(chalk5.dim(` \u2022 ${check.name}`));
3902
4694
  }
3903
4695
  console.log("");
3904
4696
  }
3905
4697
  } else if (hasExistingConfig) {
3906
4698
  console.log(title.bold(" Step 3/4 \u2014 Improve your setup\n"));
3907
- console.log(chalk4.dim(" Reviewing your existing configs against your codebase"));
3908
- console.log(chalk4.dim(" and preparing improvements.\n"));
4699
+ console.log(chalk5.dim(" Reviewing your existing configs against your codebase"));
4700
+ console.log(chalk5.dim(" and preparing improvements.\n"));
3909
4701
  } else {
3910
4702
  console.log(title.bold(" Step 3/4 \u2014 Build your agent setup\n"));
3911
- console.log(chalk4.dim(" Creating config files tailored to your project.\n"));
4703
+ console.log(chalk5.dim(" Creating config files tailored to your project.\n"));
3912
4704
  }
3913
- console.log(chalk4.dim(" This can take a couple of minutes depending on your model and provider.\n"));
4705
+ console.log(chalk5.dim(" This can take a couple of minutes depending on your model and provider.\n"));
3914
4706
  const genStartTime = Date.now();
3915
- const genSpinner = ora("Generating setup...").start();
4707
+ const genSpinner = ora2("Generating setup...").start();
3916
4708
  const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
3917
4709
  genMessages.start();
3918
4710
  let generatedSetup = null;
@@ -3952,8 +4744,8 @@ async function initCommand(options) {
3952
4744
  if (!generatedSetup) {
3953
4745
  genSpinner.fail("Failed to generate setup.");
3954
4746
  if (rawOutput) {
3955
- console.log(chalk4.dim("\nRaw LLM output (JSON parse failed):"));
3956
- console.log(chalk4.dim(rawOutput.slice(0, 500)));
4747
+ console.log(chalk5.dim("\nRaw LLM output (JSON parse failed):"));
4748
+ console.log(chalk5.dim(rawOutput.slice(0, 500)));
3957
4749
  }
3958
4750
  throw new Error("__exit__");
3959
4751
  }
@@ -3961,7 +4753,7 @@ async function initCommand(options) {
3961
4753
  const mins = Math.floor(elapsedMs / 6e4);
3962
4754
  const secs = Math.floor(elapsedMs % 6e4 / 1e3);
3963
4755
  const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
3964
- genSpinner.succeed(`Setup generated ${chalk4.dim(`in ${timeStr}`)}`);
4756
+ genSpinner.succeed(`Setup generated ${chalk5.dim(`in ${timeStr}`)}`);
3965
4757
  printSetupSummary(generatedSetup);
3966
4758
  const sessionHistory = [];
3967
4759
  sessionHistory.push({
@@ -3971,7 +4763,7 @@ async function initCommand(options) {
3971
4763
  console.log(title.bold(" Step 4/4 \u2014 Review and apply\n"));
3972
4764
  const setupFiles = collectSetupFiles(generatedSetup);
3973
4765
  const staged = stageFiles(setupFiles, process.cwd());
3974
- console.log(chalk4.dim(` ${chalk4.green(`${staged.newFiles} new`)} / ${chalk4.yellow(`${staged.modifiedFiles} modified`)} file${staged.newFiles + staged.modifiedFiles !== 1 ? "s" : ""}
4766
+ console.log(chalk5.dim(` ${chalk5.green(`${staged.newFiles} new`)} / ${chalk5.yellow(`${staged.modifiedFiles} modified`)} file${staged.newFiles + staged.modifiedFiles !== 1 ? "s" : ""}
3975
4767
  `));
3976
4768
  const wantsReview = await promptWantsReview();
3977
4769
  if (wantsReview) {
@@ -3983,12 +4775,12 @@ async function initCommand(options) {
3983
4775
  generatedSetup = await refineLoop(generatedSetup, targetAgent, sessionHistory);
3984
4776
  if (!generatedSetup) {
3985
4777
  cleanupStaging();
3986
- console.log(chalk4.dim("Refinement cancelled. No files were modified."));
4778
+ console.log(chalk5.dim("Refinement cancelled. No files were modified."));
3987
4779
  return;
3988
4780
  }
3989
4781
  const updatedFiles = collectSetupFiles(generatedSetup);
3990
4782
  const restaged = stageFiles(updatedFiles, process.cwd());
3991
- console.log(chalk4.dim(` ${chalk4.green(`${restaged.newFiles} new`)} / ${chalk4.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
4783
+ console.log(chalk5.dim(` ${chalk5.green(`${restaged.newFiles} new`)} / ${chalk5.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
3992
4784
  `));
3993
4785
  printSetupSummary(generatedSetup);
3994
4786
  await openReview("terminal", restaged.stagedFiles);
@@ -3996,37 +4788,49 @@ async function initCommand(options) {
3996
4788
  }
3997
4789
  cleanupStaging();
3998
4790
  if (action === "decline") {
3999
- console.log(chalk4.dim("Setup declined. No files were modified."));
4791
+ console.log(chalk5.dim("Setup declined. No files were modified."));
4000
4792
  return;
4001
4793
  }
4002
4794
  if (options.dryRun) {
4003
- console.log(chalk4.yellow("\n[Dry run] Would write the following files:"));
4795
+ console.log(chalk5.yellow("\n[Dry run] Would write the following files:"));
4004
4796
  console.log(JSON.stringify(generatedSetup, null, 2));
4005
4797
  return;
4006
4798
  }
4007
- const writeSpinner = ora("Writing config files...").start();
4799
+ const writeSpinner = ora2("Writing config files...").start();
4008
4800
  try {
4009
4801
  const result = writeSetup(generatedSetup);
4010
4802
  writeSpinner.succeed("Config files written");
4011
- console.log(chalk4.bold("\nFiles created/updated:"));
4803
+ console.log(chalk5.bold("\nFiles created/updated:"));
4012
4804
  for (const file of result.written) {
4013
- console.log(` ${chalk4.green("\u2713")} ${file}`);
4805
+ console.log(` ${chalk5.green("\u2713")} ${file}`);
4014
4806
  }
4015
4807
  if (result.deleted.length > 0) {
4016
- console.log(chalk4.bold("\nFiles removed:"));
4808
+ console.log(chalk5.bold("\nFiles removed:"));
4017
4809
  for (const file of result.deleted) {
4018
- console.log(` ${chalk4.red("\u2717")} ${file}`);
4810
+ console.log(` ${chalk5.red("\u2717")} ${file}`);
4019
4811
  }
4020
4812
  }
4021
4813
  if (result.backupDir) {
4022
- console.log(chalk4.dim(`
4814
+ console.log(chalk5.dim(`
4023
4815
  Backups saved to ${result.backupDir}`));
4024
4816
  }
4025
4817
  } catch (err) {
4026
4818
  writeSpinner.fail("Failed to write files");
4027
- console.error(chalk4.red(err instanceof Error ? err.message : "Unknown error"));
4819
+ console.error(chalk5.red(err instanceof Error ? err.message : "Unknown error"));
4028
4820
  throw new Error("__exit__");
4029
4821
  }
4822
+ try {
4823
+ const mcpResult = await discoverAndInstallMcps(targetAgent, fingerprint, process.cwd());
4824
+ if (mcpResult.installed > 0) {
4825
+ console.log(chalk5.bold(`
4826
+ ${mcpResult.installed} MCP server${mcpResult.installed > 1 ? "s" : ""} configured`));
4827
+ for (const name of mcpResult.names) {
4828
+ console.log(` ${chalk5.green("\u2713")} ${name}`);
4829
+ }
4830
+ }
4831
+ } catch (err) {
4832
+ console.log(chalk5.dim(" MCP discovery skipped: " + (err instanceof Error ? err.message : "unknown error")));
4833
+ }
4030
4834
  ensurePermissions();
4031
4835
  const sha = getCurrentHeadSha();
4032
4836
  writeState({
@@ -4036,56 +4840,56 @@ async function initCommand(options) {
4036
4840
  });
4037
4841
  console.log("");
4038
4842
  console.log(title.bold(" Keep your configs fresh\n"));
4039
- console.log(chalk4.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
4843
+ console.log(chalk5.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
4040
4844
  const hookChoice = await promptHookType(targetAgent);
4041
4845
  if (hookChoice === "claude" || hookChoice === "both") {
4042
4846
  const hookResult = installHook();
4043
4847
  if (hookResult.installed) {
4044
- console.log(` ${chalk4.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
4045
- console.log(chalk4.dim(" Run `caliber hooks remove` to disable"));
4848
+ console.log(` ${chalk5.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
4849
+ console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber hooks remove") + chalk5.dim(" to disable"));
4046
4850
  } else if (hookResult.alreadyInstalled) {
4047
- console.log(chalk4.dim(" Claude Code hook already installed"));
4851
+ console.log(chalk5.dim(" Claude Code hook already installed"));
4048
4852
  }
4049
4853
  const learnResult = installLearningHooks();
4050
4854
  if (learnResult.installed) {
4051
- console.log(` ${chalk4.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
4052
- console.log(chalk4.dim(" Run `caliber learn remove` to disable"));
4855
+ console.log(` ${chalk5.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
4856
+ console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber learn remove") + chalk5.dim(" to disable"));
4053
4857
  } else if (learnResult.alreadyInstalled) {
4054
- console.log(chalk4.dim(" Learning hooks already installed"));
4858
+ console.log(chalk5.dim(" Learning hooks already installed"));
4055
4859
  }
4056
4860
  }
4057
4861
  if (hookChoice === "precommit" || hookChoice === "both") {
4058
4862
  const precommitResult = installPreCommitHook();
4059
4863
  if (precommitResult.installed) {
4060
- console.log(` ${chalk4.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
4061
- console.log(chalk4.dim(" Run `caliber hooks remove-precommit` to disable"));
4864
+ console.log(` ${chalk5.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
4865
+ console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber hooks remove-precommit") + chalk5.dim(" to disable"));
4062
4866
  } else if (precommitResult.alreadyInstalled) {
4063
- console.log(chalk4.dim(" Pre-commit hook already installed"));
4867
+ console.log(chalk5.dim(" Pre-commit hook already installed"));
4064
4868
  } else {
4065
- console.log(chalk4.yellow(" Could not install pre-commit hook (not a git repository?)"));
4869
+ console.log(chalk5.yellow(" Could not install pre-commit hook (not a git repository?)"));
4066
4870
  }
4067
4871
  }
4068
4872
  if (hookChoice === "skip") {
4069
- console.log(chalk4.dim(" Skipped auto-refresh hooks. Run `caliber hooks install` later to enable."));
4873
+ console.log(chalk5.dim(" Skipped auto-refresh hooks. Run ") + chalk5.hex("#83D1EB")("caliber hooks install") + chalk5.dim(" later to enable."));
4070
4874
  }
4071
4875
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
4072
4876
  if (afterScore.score < baselineScore.score) {
4073
4877
  console.log("");
4074
- console.log(chalk4.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
4878
+ console.log(chalk5.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
4075
4879
  try {
4076
4880
  const { restored, removed } = undoSetup();
4077
4881
  if (restored.length > 0 || removed.length > 0) {
4078
- console.log(chalk4.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
4882
+ console.log(chalk5.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
4079
4883
  }
4080
4884
  } catch {
4081
4885
  }
4082
- console.log(chalk4.dim(" Run `caliber onboard --force` to override.\n"));
4886
+ console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber onboard --force") + chalk5.dim(" to override.\n"));
4083
4887
  return;
4084
4888
  }
4085
4889
  displayScoreDelta(baselineScore, afterScore);
4086
- console.log(chalk4.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
4087
- console.log(chalk4.dim(" Run `caliber undo` to revert changes.\n"));
4088
- console.log(chalk4.bold(" Next steps:\n"));
4890
+ console.log(chalk5.bold.green(" Onboarding complete! Your project is ready for AI-assisted development."));
4891
+ console.log(chalk5.dim(" Run ") + chalk5.hex("#83D1EB")("caliber undo") + chalk5.dim(" to revert changes.\n"));
4892
+ console.log(chalk5.bold(" Next steps:\n"));
4089
4893
  console.log(` ${title("caliber score")} See your full config breakdown`);
4090
4894
  console.log(` ${title("caliber recommend")} Discover community skills for your stack`);
4091
4895
  console.log(` ${title("caliber undo")} Revert all changes from this run`);
@@ -4093,7 +4897,7 @@ async function initCommand(options) {
4093
4897
  }
4094
4898
  async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
4095
4899
  while (true) {
4096
- const message = await promptInput2("\nWhat would you like to change?");
4900
+ const message = await promptInput3("\nWhat would you like to change?");
4097
4901
  if (!message || message.toLowerCase() === "done" || message.toLowerCase() === "accept") {
4098
4902
  return currentSetup;
4099
4903
  }
@@ -4102,12 +4906,12 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
4102
4906
  }
4103
4907
  const isValid = await classifyRefineIntent(message);
4104
4908
  if (!isValid) {
4105
- console.log(chalk4.dim(" This doesn't look like a config change request."));
4106
- console.log(chalk4.dim(" Describe what to add, remove, or modify in your configs."));
4107
- console.log(chalk4.dim(' Type "done" to accept the current setup.\n'));
4909
+ console.log(chalk5.dim(" This doesn't look like a config change request."));
4910
+ console.log(chalk5.dim(" Describe what to add, remove, or modify in your configs."));
4911
+ console.log(chalk5.dim(' Type "done" to accept the current setup.\n'));
4108
4912
  continue;
4109
4913
  }
4110
- const refineSpinner = ora("Refining setup...").start();
4914
+ const refineSpinner = ora2("Refining setup...").start();
4111
4915
  const refineMessages = new SpinnerMessages(refineSpinner, REFINE_MESSAGES);
4112
4916
  refineMessages.start();
4113
4917
  const refined = await refineSetup(
@@ -4125,16 +4929,16 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
4125
4929
  });
4126
4930
  refineSpinner.succeed("Setup updated");
4127
4931
  printSetupSummary(refined);
4128
- console.log(chalk4.dim('Type "done" to accept, or describe more changes.'));
4932
+ console.log(chalk5.dim('Type "done" to accept, or describe more changes.'));
4129
4933
  } else {
4130
4934
  refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
4131
- console.log(chalk4.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
4935
+ console.log(chalk5.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
4132
4936
  }
4133
4937
  }
4134
4938
  }
4135
4939
  function summarizeSetup(action, setup) {
4136
4940
  const descriptions = setup.fileDescriptions;
4137
- const files = descriptions ? Object.entries(descriptions).map(([path23, desc]) => ` ${path23}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
4941
+ const files = descriptions ? Object.entries(descriptions).map(([path26, desc]) => ` ${path26}: ${desc}`).join("\n") : Object.keys(setup).filter((k) => k !== "targetAgent" && k !== "fileDescriptions").join(", ");
4138
4942
  return `${action}. Files:
4139
4943
  ${files}`;
4140
4944
  }
@@ -4155,10 +4959,40 @@ Return {"valid": true} or {"valid": false}. Nothing else.`,
4155
4959
  return true;
4156
4960
  }
4157
4961
  }
4158
- function promptInput2(question) {
4159
- const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
4962
+ async function evaluateDismissals(failingChecks, fingerprint) {
4963
+ const fastModel = process.env.ANTHROPIC_SMALL_FAST_MODEL;
4964
+ const checkList = failingChecks.map((c) => ({
4965
+ id: c.id,
4966
+ name: c.name,
4967
+ suggestion: c.suggestion
4968
+ }));
4969
+ try {
4970
+ const result = await llmJsonCall({
4971
+ system: `You evaluate whether scoring checks are applicable to a project.
4972
+ Given the project's languages/frameworks and a list of failing checks, return which checks are NOT applicable.
4973
+
4974
+ Only dismiss checks that truly don't apply \u2014 e.g. "Build/test/lint commands" for a pure Terraform/HCL repo with no build system.
4975
+ Do NOT dismiss checks that could reasonably apply even if the project doesn't use them yet.
4976
+
4977
+ Return {"dismissed": [{"id": "check_id", "reason": "brief reason"}]} or {"dismissed": []} if all apply.`,
4978
+ prompt: `Languages: ${fingerprint.languages.join(", ") || "none"}
4979
+ Frameworks: ${fingerprint.frameworks.join(", ") || "none"}
4980
+
4981
+ Failing checks:
4982
+ ${JSON.stringify(checkList, null, 2)}`,
4983
+ maxTokens: 200,
4984
+ ...fastModel ? { model: fastModel } : {}
4985
+ });
4986
+ if (!Array.isArray(result.dismissed)) return [];
4987
+ return result.dismissed.filter((d) => d.id && d.reason && failingChecks.some((c) => c.id === d.id)).map((d) => ({ id: d.id, reason: d.reason, dismissedAt: (/* @__PURE__ */ new Date()).toISOString() }));
4988
+ } catch {
4989
+ return [];
4990
+ }
4991
+ }
4992
+ function promptInput3(question) {
4993
+ const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
4160
4994
  return new Promise((resolve2) => {
4161
- rl.question(chalk4.cyan(`${question} `), (answer) => {
4995
+ rl.question(chalk5.cyan(`${question} `), (answer) => {
4162
4996
  rl.close();
4163
4997
  resolve2(answer.trim());
4164
4998
  });
@@ -4220,12 +5054,12 @@ async function openReview(method, stagedFiles) {
4220
5054
  originalPath: f.originalPath,
4221
5055
  proposedPath: f.proposedPath
4222
5056
  })));
4223
- console.log(chalk4.dim(" Diffs opened in your editor.\n"));
5057
+ console.log(chalk5.dim(" Diffs opened in your editor.\n"));
4224
5058
  return;
4225
5059
  }
4226
5060
  const fileInfos = stagedFiles.map((file) => {
4227
- const proposed = fs17.readFileSync(file.proposedPath, "utf-8");
4228
- const current = file.currentPath ? fs17.readFileSync(file.currentPath, "utf-8") : "";
5061
+ const proposed = fs20.readFileSync(file.proposedPath, "utf-8");
5062
+ const current = file.currentPath ? fs20.readFileSync(file.currentPath, "utf-8") : "";
4229
5063
  const patch = createTwoFilesPatch(
4230
5064
  file.isNew ? "/dev/null" : file.relativePath,
4231
5065
  file.relativePath,
@@ -4251,8 +5085,8 @@ async function openReview(method, stagedFiles) {
4251
5085
  async function interactiveDiffExplorer(files) {
4252
5086
  if (!process.stdin.isTTY) {
4253
5087
  for (const f of files) {
4254
- const icon = f.isNew ? chalk4.green("+") : chalk4.yellow("~");
4255
- const stats = f.isNew ? chalk4.dim(`${f.lines} lines`) : `${chalk4.green(`+${f.added}`)} ${chalk4.red(`-${f.removed}`)}`;
5088
+ const icon = f.isNew ? chalk5.green("+") : chalk5.yellow("~");
5089
+ const stats = f.isNew ? chalk5.dim(`${f.lines} lines`) : `${chalk5.green(`+${f.added}`)} ${chalk5.red(`-${f.removed}`)}`;
4256
5090
  console.log(` ${icon} ${f.relativePath} ${stats}`);
4257
5091
  }
4258
5092
  console.log("");
@@ -4268,47 +5102,47 @@ async function interactiveDiffExplorer(files) {
4268
5102
  }
4269
5103
  function renderFileList() {
4270
5104
  const lines = [];
4271
- lines.push(chalk4.bold(" Review changes"));
5105
+ lines.push(chalk5.bold(" Review changes"));
4272
5106
  lines.push("");
4273
5107
  for (let i = 0; i < files.length; i++) {
4274
5108
  const f = files[i];
4275
- const ptr = i === cursor ? chalk4.cyan(">") : " ";
4276
- const icon = f.isNew ? chalk4.green("+") : chalk4.yellow("~");
4277
- const stats = f.isNew ? chalk4.dim(`${f.lines} lines`) : `${chalk4.green(`+${f.added}`)} ${chalk4.red(`-${f.removed}`)}`;
5109
+ const ptr = i === cursor ? chalk5.cyan(">") : " ";
5110
+ const icon = f.isNew ? chalk5.green("+") : chalk5.yellow("~");
5111
+ const stats = f.isNew ? chalk5.dim(`${f.lines} lines`) : `${chalk5.green(`+${f.added}`)} ${chalk5.red(`-${f.removed}`)}`;
4278
5112
  lines.push(` ${ptr} ${icon} ${f.relativePath} ${stats}`);
4279
5113
  }
4280
5114
  lines.push("");
4281
- lines.push(chalk4.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
5115
+ lines.push(chalk5.dim(" \u2191\u2193 navigate \u23CE view diff q done"));
4282
5116
  return lines.join("\n");
4283
5117
  }
4284
5118
  function renderDiff(index) {
4285
5119
  const f = files[index];
4286
5120
  const lines = [];
4287
- const header = f.isNew ? ` ${chalk4.green("+")} ${f.relativePath} ${chalk4.dim("(new file)")}` : ` ${chalk4.yellow("~")} ${f.relativePath} ${chalk4.green(`+${f.added}`)} ${chalk4.red(`-${f.removed}`)}`;
5121
+ const header = f.isNew ? ` ${chalk5.green("+")} ${f.relativePath} ${chalk5.dim("(new file)")}` : ` ${chalk5.yellow("~")} ${f.relativePath} ${chalk5.green(`+${f.added}`)} ${chalk5.red(`-${f.removed}`)}`;
4288
5122
  lines.push(header);
4289
- lines.push(chalk4.dim(" " + "\u2500".repeat(60)));
5123
+ lines.push(chalk5.dim(" " + "\u2500".repeat(60)));
4290
5124
  const patchLines = f.patch.split("\n");
4291
5125
  const bodyLines = patchLines.slice(4);
4292
5126
  const maxVisible = getTermHeight() - 4;
4293
5127
  const visibleLines = bodyLines.slice(scrollOffset, scrollOffset + maxVisible);
4294
5128
  for (const line of visibleLines) {
4295
5129
  if (line.startsWith("+")) {
4296
- lines.push(chalk4.green(" " + line));
5130
+ lines.push(chalk5.green(" " + line));
4297
5131
  } else if (line.startsWith("-")) {
4298
- lines.push(chalk4.red(" " + line));
5132
+ lines.push(chalk5.red(" " + line));
4299
5133
  } else if (line.startsWith("@@")) {
4300
- lines.push(chalk4.cyan(" " + line));
5134
+ lines.push(chalk5.cyan(" " + line));
4301
5135
  } else {
4302
- lines.push(chalk4.dim(" " + line));
5136
+ lines.push(chalk5.dim(" " + line));
4303
5137
  }
4304
5138
  }
4305
5139
  const totalBody = bodyLines.length;
4306
5140
  if (totalBody > maxVisible) {
4307
5141
  const pct = Math.round((scrollOffset + maxVisible) / totalBody * 100);
4308
- lines.push(chalk4.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
5142
+ lines.push(chalk5.dim(` \u2500\u2500 ${Math.min(pct, 100)}% \u2500\u2500`));
4309
5143
  }
4310
5144
  lines.push("");
4311
- lines.push(chalk4.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
5145
+ lines.push(chalk5.dim(" \u2191\u2193 scroll \u23B5/esc back to file list"));
4312
5146
  return lines.join("\n");
4313
5147
  }
4314
5148
  function draw(initial) {
@@ -4402,46 +5236,46 @@ function printSetupSummary(setup) {
4402
5236
  const fileDescriptions = setup.fileDescriptions;
4403
5237
  const deletions = setup.deletions;
4404
5238
  console.log("");
4405
- console.log(chalk4.bold(" Proposed changes:\n"));
5239
+ console.log(chalk5.bold(" Proposed changes:\n"));
4406
5240
  const getDescription = (filePath) => {
4407
5241
  return fileDescriptions?.[filePath];
4408
5242
  };
4409
5243
  if (claude) {
4410
5244
  if (claude.claudeMd) {
4411
- const icon = fs17.existsSync("CLAUDE.md") ? chalk4.yellow("~") : chalk4.green("+");
5245
+ const icon = fs20.existsSync("CLAUDE.md") ? chalk5.yellow("~") : chalk5.green("+");
4412
5246
  const desc = getDescription("CLAUDE.md");
4413
- console.log(` ${icon} ${chalk4.bold("CLAUDE.md")}`);
4414
- if (desc) console.log(chalk4.dim(` ${desc}`));
5247
+ console.log(` ${icon} ${chalk5.bold("CLAUDE.md")}`);
5248
+ if (desc) console.log(chalk5.dim(` ${desc}`));
4415
5249
  console.log("");
4416
5250
  }
4417
5251
  const skills = claude.skills;
4418
5252
  if (Array.isArray(skills) && skills.length > 0) {
4419
5253
  for (const skill of skills) {
4420
5254
  const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
4421
- const icon = fs17.existsSync(skillPath) ? chalk4.yellow("~") : chalk4.green("+");
5255
+ const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
4422
5256
  const desc = getDescription(skillPath);
4423
- console.log(` ${icon} ${chalk4.bold(skillPath)}`);
4424
- console.log(chalk4.dim(` ${desc || skill.description || skill.name}`));
5257
+ console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5258
+ console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
4425
5259
  console.log("");
4426
5260
  }
4427
5261
  }
4428
5262
  }
4429
5263
  if (cursor) {
4430
5264
  if (cursor.cursorrules) {
4431
- const icon = fs17.existsSync(".cursorrules") ? chalk4.yellow("~") : chalk4.green("+");
5265
+ const icon = fs20.existsSync(".cursorrules") ? chalk5.yellow("~") : chalk5.green("+");
4432
5266
  const desc = getDescription(".cursorrules");
4433
- console.log(` ${icon} ${chalk4.bold(".cursorrules")}`);
4434
- if (desc) console.log(chalk4.dim(` ${desc}`));
5267
+ console.log(` ${icon} ${chalk5.bold(".cursorrules")}`);
5268
+ if (desc) console.log(chalk5.dim(` ${desc}`));
4435
5269
  console.log("");
4436
5270
  }
4437
5271
  const cursorSkills = cursor.skills;
4438
5272
  if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
4439
5273
  for (const skill of cursorSkills) {
4440
5274
  const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
4441
- const icon = fs17.existsSync(skillPath) ? chalk4.yellow("~") : chalk4.green("+");
5275
+ const icon = fs20.existsSync(skillPath) ? chalk5.yellow("~") : chalk5.green("+");
4442
5276
  const desc = getDescription(skillPath);
4443
- console.log(` ${icon} ${chalk4.bold(skillPath)}`);
4444
- console.log(chalk4.dim(` ${desc || skill.description || skill.name}`));
5277
+ console.log(` ${icon} ${chalk5.bold(skillPath)}`);
5278
+ console.log(chalk5.dim(` ${desc || skill.description || skill.name}`));
4445
5279
  console.log("");
4446
5280
  }
4447
5281
  }
@@ -4449,32 +5283,32 @@ function printSetupSummary(setup) {
4449
5283
  if (Array.isArray(rules) && rules.length > 0) {
4450
5284
  for (const rule of rules) {
4451
5285
  const rulePath = `.cursor/rules/${rule.filename}`;
4452
- const icon = fs17.existsSync(rulePath) ? chalk4.yellow("~") : chalk4.green("+");
5286
+ const icon = fs20.existsSync(rulePath) ? chalk5.yellow("~") : chalk5.green("+");
4453
5287
  const desc = getDescription(rulePath);
4454
- console.log(` ${icon} ${chalk4.bold(rulePath)}`);
5288
+ console.log(` ${icon} ${chalk5.bold(rulePath)}`);
4455
5289
  if (desc) {
4456
- console.log(chalk4.dim(` ${desc}`));
5290
+ console.log(chalk5.dim(` ${desc}`));
4457
5291
  } else {
4458
5292
  const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
4459
- if (firstLine) console.log(chalk4.dim(` ${firstLine.trim().slice(0, 80)}`));
5293
+ if (firstLine) console.log(chalk5.dim(` ${firstLine.trim().slice(0, 80)}`));
4460
5294
  }
4461
5295
  console.log("");
4462
5296
  }
4463
5297
  }
4464
5298
  }
4465
- if (!fs17.existsSync("AGENTS.md")) {
4466
- console.log(` ${chalk4.green("+")} ${chalk4.bold("AGENTS.md")}`);
4467
- console.log(chalk4.dim(" Cross-agent coordination file"));
5299
+ if (!fs20.existsSync("AGENTS.md")) {
5300
+ console.log(` ${chalk5.green("+")} ${chalk5.bold("AGENTS.md")}`);
5301
+ console.log(chalk5.dim(" Cross-agent coordination file"));
4468
5302
  console.log("");
4469
5303
  }
4470
5304
  if (Array.isArray(deletions) && deletions.length > 0) {
4471
5305
  for (const del of deletions) {
4472
- console.log(` ${chalk4.red("-")} ${chalk4.bold(del.filePath)}`);
4473
- console.log(chalk4.dim(` ${del.reason}`));
5306
+ console.log(` ${chalk5.red("-")} ${chalk5.bold(del.filePath)}`);
5307
+ console.log(chalk5.dim(` ${del.reason}`));
4474
5308
  console.log("");
4475
5309
  }
4476
5310
  }
4477
- console.log(` ${chalk4.green("+")} ${chalk4.dim("new")} ${chalk4.yellow("~")} ${chalk4.dim("modified")} ${chalk4.red("-")} ${chalk4.dim("removed")}`);
5311
+ console.log(` ${chalk5.green("+")} ${chalk5.dim("new")} ${chalk5.yellow("~")} ${chalk5.dim("modified")} ${chalk5.red("-")} ${chalk5.dim("removed")}`);
4478
5312
  console.log("");
4479
5313
  }
4480
5314
  function buildSkillContent(skill) {
@@ -4490,8 +5324,8 @@ function ensurePermissions() {
4490
5324
  const settingsPath = ".claude/settings.json";
4491
5325
  let settings = {};
4492
5326
  try {
4493
- if (fs17.existsSync(settingsPath)) {
4494
- settings = JSON.parse(fs17.readFileSync(settingsPath, "utf-8"));
5327
+ if (fs20.existsSync(settingsPath)) {
5328
+ settings = JSON.parse(fs20.readFileSync(settingsPath, "utf-8"));
4495
5329
  }
4496
5330
  } catch {
4497
5331
  }
@@ -4505,8 +5339,8 @@ function ensurePermissions() {
4505
5339
  "Bash(git *)"
4506
5340
  ];
4507
5341
  settings.permissions = permissions;
4508
- if (!fs17.existsSync(".claude")) fs17.mkdirSync(".claude", { recursive: true });
4509
- fs17.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5342
+ if (!fs20.existsSync(".claude")) fs20.mkdirSync(".claude", { recursive: true });
5343
+ fs20.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
4510
5344
  }
4511
5345
  function collectSetupFiles(setup) {
4512
5346
  const files = [];
@@ -4536,7 +5370,7 @@ function collectSetupFiles(setup) {
4536
5370
  }
4537
5371
  }
4538
5372
  }
4539
- if (!fs17.existsSync("AGENTS.md")) {
5373
+ if (!fs20.existsSync("AGENTS.md")) {
4540
5374
  const agentRefs = [];
4541
5375
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
4542
5376
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
@@ -4555,10 +5389,10 @@ ${agentRefs.join(" ")}
4555
5389
  }
4556
5390
 
4557
5391
  // src/commands/undo.ts
4558
- import chalk5 from "chalk";
4559
- import ora2 from "ora";
5392
+ import chalk6 from "chalk";
5393
+ import ora3 from "ora";
4560
5394
  function undoCommand() {
4561
- const spinner = ora2("Reverting setup...").start();
5395
+ const spinner = ora3("Reverting setup...").start();
4562
5396
  try {
4563
5397
  const { restored, removed } = undoSetup();
4564
5398
  if (restored.length === 0 && removed.length === 0) {
@@ -4567,27 +5401,27 @@ function undoCommand() {
4567
5401
  }
4568
5402
  spinner.succeed("Setup reverted successfully.\n");
4569
5403
  if (restored.length > 0) {
4570
- console.log(chalk5.cyan(" Restored from backup:"));
5404
+ console.log(chalk6.cyan(" Restored from backup:"));
4571
5405
  for (const file of restored) {
4572
- console.log(` ${chalk5.green("\u21A9")} ${file}`);
5406
+ console.log(` ${chalk6.green("\u21A9")} ${file}`);
4573
5407
  }
4574
5408
  }
4575
5409
  if (removed.length > 0) {
4576
- console.log(chalk5.cyan(" Removed:"));
5410
+ console.log(chalk6.cyan(" Removed:"));
4577
5411
  for (const file of removed) {
4578
- console.log(` ${chalk5.red("\u2717")} ${file}`);
5412
+ console.log(` ${chalk6.red("\u2717")} ${file}`);
4579
5413
  }
4580
5414
  }
4581
5415
  console.log("");
4582
5416
  } catch (err) {
4583
- spinner.fail(chalk5.red(err instanceof Error ? err.message : "Undo failed"));
5417
+ spinner.fail(chalk6.red(err instanceof Error ? err.message : "Undo failed"));
4584
5418
  throw new Error("__exit__");
4585
5419
  }
4586
5420
  }
4587
5421
 
4588
5422
  // src/commands/status.ts
4589
- import chalk6 from "chalk";
4590
- import fs18 from "fs";
5423
+ import chalk7 from "chalk";
5424
+ import fs21 from "fs";
4591
5425
  async function statusCommand(options) {
4592
5426
  const config = loadConfig();
4593
5427
  const manifest = readManifest();
@@ -4600,45 +5434,45 @@ async function statusCommand(options) {
4600
5434
  }, null, 2));
4601
5435
  return;
4602
5436
  }
4603
- console.log(chalk6.bold("\nCaliber Status\n"));
5437
+ console.log(chalk7.bold("\nCaliber Status\n"));
4604
5438
  if (config) {
4605
- console.log(` LLM: ${chalk6.green(config.provider)} (${config.model})`);
5439
+ console.log(` LLM: ${chalk7.green(config.provider)} (${config.model})`);
4606
5440
  } else {
4607
- console.log(` LLM: ${chalk6.yellow("Not configured")} \u2014 run \`caliber config\``);
5441
+ console.log(` LLM: ${chalk7.yellow("Not configured")} \u2014 run ${chalk7.hex("#83D1EB")("caliber config")}`);
4608
5442
  }
4609
5443
  if (!manifest) {
4610
- console.log(` Setup: ${chalk6.dim("No setup applied")}`);
4611
- console.log(chalk6.dim("\n Run `caliber onboard` to get started.\n"));
5444
+ console.log(` Setup: ${chalk7.dim("No setup applied")}`);
5445
+ console.log(chalk7.dim("\n Run ") + chalk7.hex("#83D1EB")("caliber onboard") + chalk7.dim(" to get started.\n"));
4612
5446
  return;
4613
5447
  }
4614
- console.log(` Files managed: ${chalk6.cyan(manifest.entries.length.toString())}`);
5448
+ console.log(` Files managed: ${chalk7.cyan(manifest.entries.length.toString())}`);
4615
5449
  for (const entry of manifest.entries) {
4616
- const exists = fs18.existsSync(entry.path);
4617
- const icon = exists ? chalk6.green("\u2713") : chalk6.red("\u2717");
5450
+ const exists = fs21.existsSync(entry.path);
5451
+ const icon = exists ? chalk7.green("\u2713") : chalk7.red("\u2717");
4618
5452
  console.log(` ${icon} ${entry.path} (${entry.action})`);
4619
5453
  }
4620
5454
  console.log("");
4621
5455
  }
4622
5456
 
4623
5457
  // src/commands/regenerate.ts
4624
- import chalk7 from "chalk";
4625
- import ora3 from "ora";
5458
+ import chalk8 from "chalk";
5459
+ import ora4 from "ora";
4626
5460
  import confirm from "@inquirer/confirm";
4627
5461
  async function regenerateCommand(options) {
4628
5462
  const config = loadConfig();
4629
5463
  if (!config) {
4630
- console.log(chalk7.red("No LLM provider configured. Run `caliber config` (e.g. choose Cursor) or set ANTHROPIC_API_KEY."));
5464
+ console.log(chalk8.red("No LLM provider configured. Run ") + chalk8.hex("#83D1EB")("caliber config") + chalk8.red(" (e.g. choose Cursor) or set ANTHROPIC_API_KEY."));
4631
5465
  throw new Error("__exit__");
4632
5466
  }
4633
5467
  const manifest = readManifest();
4634
5468
  if (!manifest) {
4635
- console.log(chalk7.yellow("No existing setup found. Run `caliber onboard` first."));
5469
+ console.log(chalk8.yellow("No existing setup found. Run ") + chalk8.hex("#83D1EB")("caliber onboard") + chalk8.yellow(" first."));
4636
5470
  throw new Error("__exit__");
4637
5471
  }
4638
- const spinner = ora3("Re-analyzing project...").start();
5472
+ const spinner = ora4("Re-analyzing project...").start();
4639
5473
  const fingerprint = collectFingerprint(process.cwd());
4640
5474
  spinner.succeed("Project re-analyzed");
4641
- const genSpinner = ora3("Regenerating setup...").start();
5475
+ const genSpinner = ora4("Regenerating setup...").start();
4642
5476
  const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES);
4643
5477
  genMessages.start();
4644
5478
  let generatedSetup = null;
@@ -4675,38 +5509,38 @@ async function regenerateCommand(options) {
4675
5509
  }
4676
5510
  genSpinner.succeed("Setup regenerated");
4677
5511
  if (options.dryRun) {
4678
- console.log(chalk7.yellow("\n[Dry run] Would write:"));
5512
+ console.log(chalk8.yellow("\n[Dry run] Would write:"));
4679
5513
  console.log(JSON.stringify(generatedSetup, null, 2));
4680
5514
  return;
4681
5515
  }
4682
5516
  const shouldApply = await confirm({ message: "Apply regenerated setup?", default: true });
4683
5517
  if (!shouldApply) {
4684
- console.log(chalk7.dim("Regeneration cancelled."));
5518
+ console.log(chalk8.dim("Regeneration cancelled."));
4685
5519
  return;
4686
5520
  }
4687
- const writeSpinner = ora3("Updating config files...").start();
5521
+ const writeSpinner = ora4("Updating config files...").start();
4688
5522
  const result = writeSetup(generatedSetup);
4689
5523
  writeSpinner.succeed("Config files updated");
4690
5524
  for (const file of result.written) {
4691
- console.log(` ${chalk7.green("\u2713")} ${file}`);
5525
+ console.log(` ${chalk8.green("\u2713")} ${file}`);
4692
5526
  }
4693
5527
  console.log("");
4694
5528
  }
4695
5529
 
4696
5530
  // src/commands/recommend.ts
4697
- import chalk8 from "chalk";
4698
- import ora4 from "ora";
5531
+ import chalk9 from "chalk";
5532
+ import ora5 from "ora";
4699
5533
  import { mkdirSync, readFileSync as readFileSync7, readdirSync as readdirSync5, existsSync as existsSync9, writeFileSync } from "fs";
4700
5534
  import { join as join8, dirname as dirname2 } from "path";
4701
5535
 
4702
5536
  // src/scanner/index.ts
4703
- import fs19 from "fs";
4704
- import path16 from "path";
5537
+ import fs22 from "fs";
5538
+ import path19 from "path";
4705
5539
  import crypto2 from "crypto";
4706
5540
  function scanLocalState(dir) {
4707
5541
  const items = [];
4708
- const claudeMdPath = path16.join(dir, "CLAUDE.md");
4709
- if (fs19.existsSync(claudeMdPath)) {
5542
+ const claudeMdPath = path19.join(dir, "CLAUDE.md");
5543
+ if (fs22.existsSync(claudeMdPath)) {
4710
5544
  items.push({
4711
5545
  type: "rule",
4712
5546
  platform: "claude",
@@ -4715,10 +5549,10 @@ function scanLocalState(dir) {
4715
5549
  path: claudeMdPath
4716
5550
  });
4717
5551
  }
4718
- const skillsDir = path16.join(dir, ".claude", "skills");
4719
- if (fs19.existsSync(skillsDir)) {
4720
- for (const file of fs19.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
4721
- const filePath = path16.join(skillsDir, file);
5552
+ const skillsDir = path19.join(dir, ".claude", "skills");
5553
+ if (fs22.existsSync(skillsDir)) {
5554
+ for (const file of fs22.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))) {
5555
+ const filePath = path19.join(skillsDir, file);
4722
5556
  items.push({
4723
5557
  type: "skill",
4724
5558
  platform: "claude",
@@ -4728,10 +5562,10 @@ function scanLocalState(dir) {
4728
5562
  });
4729
5563
  }
4730
5564
  }
4731
- const mcpJsonPath = path16.join(dir, ".mcp.json");
4732
- if (fs19.existsSync(mcpJsonPath)) {
5565
+ const mcpJsonPath = path19.join(dir, ".mcp.json");
5566
+ if (fs22.existsSync(mcpJsonPath)) {
4733
5567
  try {
4734
- const mcpJson = JSON.parse(fs19.readFileSync(mcpJsonPath, "utf-8"));
5568
+ const mcpJson = JSON.parse(fs22.readFileSync(mcpJsonPath, "utf-8"));
4735
5569
  if (mcpJson.mcpServers) {
4736
5570
  for (const name of Object.keys(mcpJson.mcpServers)) {
4737
5571
  items.push({
@@ -4746,8 +5580,8 @@ function scanLocalState(dir) {
4746
5580
  } catch {
4747
5581
  }
4748
5582
  }
4749
- const cursorrulesPath = path16.join(dir, ".cursorrules");
4750
- if (fs19.existsSync(cursorrulesPath)) {
5583
+ const cursorrulesPath = path19.join(dir, ".cursorrules");
5584
+ if (fs22.existsSync(cursorrulesPath)) {
4751
5585
  items.push({
4752
5586
  type: "rule",
4753
5587
  platform: "cursor",
@@ -4756,10 +5590,10 @@ function scanLocalState(dir) {
4756
5590
  path: cursorrulesPath
4757
5591
  });
4758
5592
  }
4759
- const cursorRulesDir = path16.join(dir, ".cursor", "rules");
4760
- if (fs19.existsSync(cursorRulesDir)) {
4761
- for (const file of fs19.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
4762
- const filePath = path16.join(cursorRulesDir, file);
5593
+ const cursorRulesDir = path19.join(dir, ".cursor", "rules");
5594
+ if (fs22.existsSync(cursorRulesDir)) {
5595
+ for (const file of fs22.readdirSync(cursorRulesDir).filter((f) => f.endsWith(".mdc"))) {
5596
+ const filePath = path19.join(cursorRulesDir, file);
4763
5597
  items.push({
4764
5598
  type: "rule",
4765
5599
  platform: "cursor",
@@ -4769,12 +5603,12 @@ function scanLocalState(dir) {
4769
5603
  });
4770
5604
  }
4771
5605
  }
4772
- const cursorSkillsDir = path16.join(dir, ".cursor", "skills");
4773
- if (fs19.existsSync(cursorSkillsDir)) {
5606
+ const cursorSkillsDir = path19.join(dir, ".cursor", "skills");
5607
+ if (fs22.existsSync(cursorSkillsDir)) {
4774
5608
  try {
4775
- for (const name of fs19.readdirSync(cursorSkillsDir)) {
4776
- const skillFile = path16.join(cursorSkillsDir, name, "SKILL.md");
4777
- if (fs19.existsSync(skillFile)) {
5609
+ for (const name of fs22.readdirSync(cursorSkillsDir)) {
5610
+ const skillFile = path19.join(cursorSkillsDir, name, "SKILL.md");
5611
+ if (fs22.existsSync(skillFile)) {
4778
5612
  items.push({
4779
5613
  type: "skill",
4780
5614
  platform: "cursor",
@@ -4787,10 +5621,10 @@ function scanLocalState(dir) {
4787
5621
  } catch {
4788
5622
  }
4789
5623
  }
4790
- const cursorMcpPath = path16.join(dir, ".cursor", "mcp.json");
4791
- if (fs19.existsSync(cursorMcpPath)) {
5624
+ const cursorMcpPath = path19.join(dir, ".cursor", "mcp.json");
5625
+ if (fs22.existsSync(cursorMcpPath)) {
4792
5626
  try {
4793
- const mcpJson = JSON.parse(fs19.readFileSync(cursorMcpPath, "utf-8"));
5627
+ const mcpJson = JSON.parse(fs22.readFileSync(cursorMcpPath, "utf-8"));
4794
5628
  if (mcpJson.mcpServers) {
4795
5629
  for (const name of Object.keys(mcpJson.mcpServers)) {
4796
5630
  items.push({
@@ -4808,7 +5642,7 @@ function scanLocalState(dir) {
4808
5642
  return items;
4809
5643
  }
4810
5644
  function hashFile(filePath) {
4811
- const text = fs19.readFileSync(filePath, "utf-8");
5645
+ const text = fs22.readFileSync(filePath, "utf-8");
4812
5646
  return crypto2.createHash("sha256").update(JSON.stringify({ text })).digest("hex");
4813
5647
  }
4814
5648
  function hashJson(obj) {
@@ -4966,7 +5800,7 @@ async function searchAllProviders(technologies, platform) {
4966
5800
  }
4967
5801
  return combined;
4968
5802
  }
4969
- async function scoreWithLLM(candidates, projectContext, technologies) {
5803
+ async function scoreWithLLM2(candidates, projectContext, technologies) {
4970
5804
  const candidateList = candidates.map((c, i) => `${i}. "${c.name}" \u2014 ${c.reason || "no description"}`).join("\n");
4971
5805
  const scored = await llmJsonCall({
4972
5806
  system: `You evaluate whether AI agent skills and tools are relevant to a specific software project.
@@ -5119,11 +5953,11 @@ async function recommendCommand(options) {
5119
5953
  ...extractTopDeps()
5120
5954
  ].filter(Boolean))];
5121
5955
  if (technologies.length === 0) {
5122
- console.log(chalk8.yellow("Could not detect any languages or dependencies. Try running from a project root."));
5956
+ console.log(chalk9.yellow("Could not detect any languages or dependencies. Try running from a project root."));
5123
5957
  throw new Error("__exit__");
5124
5958
  }
5125
5959
  const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
5126
- const searchSpinner = ora4("Searching skill registries...").start();
5960
+ const searchSpinner = ora5("Searching skill registries...").start();
5127
5961
  const allCandidates = await searchAllProviders(technologies, primaryPlatform);
5128
5962
  if (!allCandidates.length) {
5129
5963
  searchSpinner.succeed("No skills found matching your tech stack.");
@@ -5136,15 +5970,15 @@ async function recommendCommand(options) {
5136
5970
  return;
5137
5971
  }
5138
5972
  searchSpinner.succeed(
5139
- `Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk8.dim(` (${filteredCount} already installed)`) : "")
5973
+ `Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk9.dim(` (${filteredCount} already installed)`) : "")
5140
5974
  );
5141
5975
  let results;
5142
5976
  const config = loadConfig();
5143
5977
  if (config) {
5144
- const scoreSpinner = ora4("Scoring relevance for your project...").start();
5978
+ const scoreSpinner = ora5("Scoring relevance for your project...").start();
5145
5979
  try {
5146
5980
  const projectContext = buildProjectContext(process.cwd());
5147
- results = await scoreWithLLM(newCandidates, projectContext, technologies);
5981
+ results = await scoreWithLLM2(newCandidates, projectContext, technologies);
5148
5982
  if (results.length === 0) {
5149
5983
  scoreSpinner.succeed("No highly relevant skills found for your specific project.");
5150
5984
  return;
@@ -5157,7 +5991,7 @@ async function recommendCommand(options) {
5157
5991
  } else {
5158
5992
  results = newCandidates.slice(0, 20);
5159
5993
  }
5160
- const fetchSpinner = ora4("Verifying skill availability...").start();
5994
+ const fetchSpinner = ora5("Verifying skill availability...").start();
5161
5995
  const contentMap = /* @__PURE__ */ new Map();
5162
5996
  await Promise.all(results.map(async (rec) => {
5163
5997
  const content = await fetchSkillContent(rec);
@@ -5170,14 +6004,14 @@ async function recommendCommand(options) {
5170
6004
  }
5171
6005
  const unavailableCount = results.length - available.length;
5172
6006
  fetchSpinner.succeed(
5173
- `${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk8.dim(` (${unavailableCount} unavailable)`) : "")
6007
+ `${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk9.dim(` (${unavailableCount} unavailable)`) : "")
5174
6008
  );
5175
- const selected = await interactiveSelect(available);
6009
+ const selected = await interactiveSelect2(available);
5176
6010
  if (selected?.length) {
5177
6011
  await installSkills(selected, platforms, contentMap);
5178
6012
  }
5179
6013
  }
5180
- async function interactiveSelect(recs) {
6014
+ async function interactiveSelect2(recs) {
5181
6015
  if (!process.stdin.isTTY) {
5182
6016
  printRecommendations(recs);
5183
6017
  return null;
@@ -5189,27 +6023,27 @@ async function interactiveSelect(recs) {
5189
6023
  const hasScores = recs.some((r) => r.score > 0);
5190
6024
  function render() {
5191
6025
  const lines = [];
5192
- lines.push(chalk8.bold(" Recommendations"));
6026
+ lines.push(chalk9.bold(" Recommendations"));
5193
6027
  lines.push("");
5194
6028
  if (hasScores) {
5195
- lines.push(` ${chalk8.dim("Score".padEnd(7))} ${chalk8.dim("Name".padEnd(28))} ${chalk8.dim("Why")}`);
6029
+ lines.push(` ${chalk9.dim("Score".padEnd(7))} ${chalk9.dim("Name".padEnd(28))} ${chalk9.dim("Why")}`);
5196
6030
  } else {
5197
- lines.push(` ${chalk8.dim("Name".padEnd(30))} ${chalk8.dim("Technology".padEnd(18))} ${chalk8.dim("Source")}`);
6031
+ lines.push(` ${chalk9.dim("Name".padEnd(30))} ${chalk9.dim("Technology".padEnd(18))} ${chalk9.dim("Source")}`);
5198
6032
  }
5199
- lines.push(chalk8.dim(" " + "\u2500".repeat(70)));
6033
+ lines.push(chalk9.dim(" " + "\u2500".repeat(70)));
5200
6034
  for (let i = 0; i < recs.length; i++) {
5201
6035
  const rec = recs[i];
5202
- const check = selected.has(i) ? chalk8.green("[x]") : "[ ]";
5203
- const ptr = i === cursor ? chalk8.cyan(">") : " ";
6036
+ const check = selected.has(i) ? chalk9.green("[x]") : "[ ]";
6037
+ const ptr = i === cursor ? chalk9.cyan(">") : " ";
5204
6038
  if (hasScores) {
5205
- const scoreColor = rec.score >= 90 ? chalk8.green : rec.score >= 70 ? chalk8.yellow : chalk8.dim;
5206
- lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(26)} ${chalk8.dim(rec.reason.slice(0, 40))}`);
6039
+ const scoreColor = rec.score >= 90 ? chalk9.green : rec.score >= 70 ? chalk9.yellow : chalk9.dim;
6040
+ lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(26)} ${chalk9.dim(rec.reason.slice(0, 40))}`);
5207
6041
  } else {
5208
- lines.push(` ${ptr} ${check} ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk8.dim(rec.source_url || "")}`);
6042
+ lines.push(` ${ptr} ${check} ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk9.dim(rec.source_url || "")}`);
5209
6043
  }
5210
6044
  }
5211
6045
  lines.push("");
5212
- lines.push(chalk8.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
6046
+ lines.push(chalk9.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
5213
6047
  return lines.join("\n");
5214
6048
  }
5215
6049
  function draw(initial) {
@@ -5258,7 +6092,7 @@ async function interactiveSelect(recs) {
5258
6092
  case "\n":
5259
6093
  cleanup();
5260
6094
  if (selected.size === 0) {
5261
- console.log(chalk8.dim("\n No skills selected.\n"));
6095
+ console.log(chalk9.dim("\n No skills selected.\n"));
5262
6096
  resolve2(null);
5263
6097
  } else {
5264
6098
  resolve2(Array.from(selected).sort().map((i) => recs[i]));
@@ -5268,7 +6102,7 @@ async function interactiveSelect(recs) {
5268
6102
  case "\x1B":
5269
6103
  case "":
5270
6104
  cleanup();
5271
- console.log(chalk8.dim("\n Cancelled.\n"));
6105
+ console.log(chalk9.dim("\n Cancelled.\n"));
5272
6106
  resolve2(null);
5273
6107
  break;
5274
6108
  }
@@ -5314,7 +6148,7 @@ async function fetchSkillContent(rec) {
5314
6148
  return null;
5315
6149
  }
5316
6150
  async function installSkills(recs, platforms, contentMap) {
5317
- const spinner = ora4(`Installing ${recs.length} skill${recs.length > 1 ? "s" : ""}...`).start();
6151
+ const spinner = ora5(`Installing ${recs.length} skill${recs.length > 1 ? "s" : ""}...`).start();
5318
6152
  const installed = [];
5319
6153
  for (const rec of recs) {
5320
6154
  const content = contentMap.get(rec.slug);
@@ -5330,7 +6164,7 @@ async function installSkills(recs, platforms, contentMap) {
5330
6164
  if (installed.length > 0) {
5331
6165
  spinner.succeed(`Installed ${installed.length} file${installed.length > 1 ? "s" : ""}`);
5332
6166
  for (const p of installed) {
5333
- console.log(chalk8.green(` \u2713 ${p}`));
6167
+ console.log(chalk9.green(` \u2713 ${p}`));
5334
6168
  }
5335
6169
  } else {
5336
6170
  spinner.fail("No skills were installed");
@@ -5339,25 +6173,25 @@ async function installSkills(recs, platforms, contentMap) {
5339
6173
  }
5340
6174
  function printRecommendations(recs) {
5341
6175
  const hasScores = recs.some((r) => r.score > 0);
5342
- console.log(chalk8.bold("\n Recommendations\n"));
6176
+ console.log(chalk9.bold("\n Recommendations\n"));
5343
6177
  if (hasScores) {
5344
- console.log(` ${chalk8.dim("Score".padEnd(7))} ${chalk8.dim("Name".padEnd(28))} ${chalk8.dim("Why")}`);
6178
+ console.log(` ${chalk9.dim("Score".padEnd(7))} ${chalk9.dim("Name".padEnd(28))} ${chalk9.dim("Why")}`);
5345
6179
  } else {
5346
- console.log(` ${chalk8.dim("Name".padEnd(30))} ${chalk8.dim("Technology".padEnd(18))} ${chalk8.dim("Source")}`);
6180
+ console.log(` ${chalk9.dim("Name".padEnd(30))} ${chalk9.dim("Technology".padEnd(18))} ${chalk9.dim("Source")}`);
5347
6181
  }
5348
- console.log(chalk8.dim(" " + "\u2500".repeat(70)));
6182
+ console.log(chalk9.dim(" " + "\u2500".repeat(70)));
5349
6183
  for (const rec of recs) {
5350
6184
  if (hasScores) {
5351
- console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(26)} ${chalk8.dim(rec.reason.slice(0, 50))}`);
6185
+ console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(26)} ${chalk9.dim(rec.reason.slice(0, 50))}`);
5352
6186
  } else {
5353
- console.log(` ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk8.dim(rec.source_url || "")}`);
6187
+ console.log(` ${rec.name.padEnd(28)} ${rec.detected_technology.padEnd(16)} ${chalk9.dim(rec.source_url || "")}`);
5354
6188
  }
5355
6189
  }
5356
6190
  console.log("");
5357
6191
  }
5358
6192
 
5359
6193
  // src/commands/score.ts
5360
- import chalk9 from "chalk";
6194
+ import chalk10 from "chalk";
5361
6195
  async function scoreCommand(options) {
5362
6196
  const dir = process.cwd();
5363
6197
  const target = options.agent ?? readState()?.targetAgent;
@@ -5371,23 +6205,23 @@ async function scoreCommand(options) {
5371
6205
  return;
5372
6206
  }
5373
6207
  displayScore(result);
5374
- const separator = chalk9.gray(" " + "\u2500".repeat(53));
6208
+ const separator = chalk10.gray(" " + "\u2500".repeat(53));
5375
6209
  console.log(separator);
5376
6210
  if (result.score < 40) {
5377
- console.log(chalk9.gray(" Run ") + chalk9.hex("#f97316")("caliber onboard") + chalk9.gray(" to generate a complete, optimized setup."));
6211
+ console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to generate a complete, optimized setup."));
5378
6212
  } else if (result.score < 70) {
5379
- console.log(chalk9.gray(" Run ") + chalk9.hex("#f97316")("caliber onboard") + chalk9.gray(" to improve your setup."));
6213
+ console.log(chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber onboard") + chalk10.gray(" to improve your setup."));
5380
6214
  } else {
5381
- console.log(chalk9.green(" Looking good!") + chalk9.gray(" Run ") + chalk9.hex("#f97316")("caliber update") + chalk9.gray(" to keep it fresh."));
6215
+ console.log(chalk10.green(" Looking good!") + chalk10.gray(" Run ") + chalk10.hex("#83D1EB")("caliber update") + chalk10.gray(" to keep it fresh."));
5382
6216
  }
5383
6217
  console.log("");
5384
6218
  }
5385
6219
 
5386
6220
  // src/commands/refresh.ts
5387
- import fs21 from "fs";
5388
- import path18 from "path";
5389
- import chalk10 from "chalk";
5390
- import ora5 from "ora";
6221
+ import fs24 from "fs";
6222
+ import path21 from "path";
6223
+ import chalk11 from "chalk";
6224
+ import ora6 from "ora";
5391
6225
 
5392
6226
  // src/lib/git-diff.ts
5393
6227
  import { execSync as execSync8 } from "child_process";
@@ -5462,37 +6296,37 @@ function collectDiff(lastSha) {
5462
6296
  }
5463
6297
 
5464
6298
  // src/writers/refresh.ts
5465
- import fs20 from "fs";
5466
- import path17 from "path";
6299
+ import fs23 from "fs";
6300
+ import path20 from "path";
5467
6301
  function writeRefreshDocs(docs) {
5468
6302
  const written = [];
5469
6303
  if (docs.claudeMd) {
5470
- fs20.writeFileSync("CLAUDE.md", docs.claudeMd);
6304
+ fs23.writeFileSync("CLAUDE.md", docs.claudeMd);
5471
6305
  written.push("CLAUDE.md");
5472
6306
  }
5473
6307
  if (docs.readmeMd) {
5474
- fs20.writeFileSync("README.md", docs.readmeMd);
6308
+ fs23.writeFileSync("README.md", docs.readmeMd);
5475
6309
  written.push("README.md");
5476
6310
  }
5477
6311
  if (docs.cursorrules) {
5478
- fs20.writeFileSync(".cursorrules", docs.cursorrules);
6312
+ fs23.writeFileSync(".cursorrules", docs.cursorrules);
5479
6313
  written.push(".cursorrules");
5480
6314
  }
5481
6315
  if (docs.cursorRules) {
5482
- const rulesDir = path17.join(".cursor", "rules");
5483
- if (!fs20.existsSync(rulesDir)) fs20.mkdirSync(rulesDir, { recursive: true });
6316
+ const rulesDir = path20.join(".cursor", "rules");
6317
+ if (!fs23.existsSync(rulesDir)) fs23.mkdirSync(rulesDir, { recursive: true });
5484
6318
  for (const rule of docs.cursorRules) {
5485
- const filePath = path17.join(rulesDir, rule.filename);
5486
- fs20.writeFileSync(filePath, rule.content);
6319
+ const filePath = path20.join(rulesDir, rule.filename);
6320
+ fs23.writeFileSync(filePath, rule.content);
5487
6321
  written.push(filePath);
5488
6322
  }
5489
6323
  }
5490
6324
  if (docs.claudeSkills) {
5491
- const skillsDir = path17.join(".claude", "skills");
5492
- if (!fs20.existsSync(skillsDir)) fs20.mkdirSync(skillsDir, { recursive: true });
6325
+ const skillsDir = path20.join(".claude", "skills");
6326
+ if (!fs23.existsSync(skillsDir)) fs23.mkdirSync(skillsDir, { recursive: true });
5493
6327
  for (const skill of docs.claudeSkills) {
5494
- const filePath = path17.join(skillsDir, skill.filename);
5495
- fs20.writeFileSync(filePath, skill.content);
6328
+ const filePath = path20.join(skillsDir, skill.filename);
6329
+ fs23.writeFileSync(filePath, skill.content);
5496
6330
  written.push(filePath);
5497
6331
  }
5498
6332
  }
@@ -5567,11 +6401,11 @@ function log(quiet, ...args) {
5567
6401
  function discoverGitRepos(parentDir) {
5568
6402
  const repos = [];
5569
6403
  try {
5570
- const entries = fs21.readdirSync(parentDir, { withFileTypes: true });
6404
+ const entries = fs24.readdirSync(parentDir, { withFileTypes: true });
5571
6405
  for (const entry of entries) {
5572
6406
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
5573
- const childPath = path18.join(parentDir, entry.name);
5574
- if (fs21.existsSync(path18.join(childPath, ".git"))) {
6407
+ const childPath = path21.join(parentDir, entry.name);
6408
+ if (fs24.existsSync(path21.join(childPath, ".git"))) {
5575
6409
  repos.push(childPath);
5576
6410
  }
5577
6411
  }
@@ -5581,7 +6415,7 @@ function discoverGitRepos(parentDir) {
5581
6415
  }
5582
6416
  async function refreshSingleRepo(repoDir, options) {
5583
6417
  const quiet = !!options.quiet;
5584
- const prefix = options.label ? `${chalk10.bold(options.label)} ` : "";
6418
+ const prefix = options.label ? `${chalk11.bold(options.label)} ` : "";
5585
6419
  const state = readState();
5586
6420
  const lastSha = state?.lastRefreshSha ?? null;
5587
6421
  const diff = collectDiff(lastSha);
@@ -5590,10 +6424,10 @@ async function refreshSingleRepo(repoDir, options) {
5590
6424
  if (currentSha) {
5591
6425
  writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
5592
6426
  }
5593
- log(quiet, chalk10.dim(`${prefix}No changes since last refresh.`));
6427
+ log(quiet, chalk11.dim(`${prefix}No changes since last refresh.`));
5594
6428
  return;
5595
6429
  }
5596
- const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
6430
+ const spinner = quiet ? null : ora6(`${prefix}Analyzing changes...`).start();
5597
6431
  const existingDocs = readExistingConfigs(repoDir);
5598
6432
  const fingerprint = collectFingerprint(repoDir);
5599
6433
  const projectContext = {
@@ -5622,10 +6456,10 @@ async function refreshSingleRepo(repoDir, options) {
5622
6456
  if (options.dryRun) {
5623
6457
  spinner?.info(`${prefix}Dry run \u2014 would update:`);
5624
6458
  for (const doc of response.docsUpdated) {
5625
- console.log(` ${chalk10.yellow("~")} ${doc}`);
6459
+ console.log(` ${chalk11.yellow("~")} ${doc}`);
5626
6460
  }
5627
6461
  if (response.changesSummary) {
5628
- console.log(chalk10.dim(`
6462
+ console.log(chalk11.dim(`
5629
6463
  ${response.changesSummary}`));
5630
6464
  }
5631
6465
  return;
@@ -5633,10 +6467,10 @@ async function refreshSingleRepo(repoDir, options) {
5633
6467
  const written = writeRefreshDocs(response.updatedDocs);
5634
6468
  spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
5635
6469
  for (const file of written) {
5636
- log(quiet, ` ${chalk10.green("\u2713")} ${file}`);
6470
+ log(quiet, ` ${chalk11.green("\u2713")} ${file}`);
5637
6471
  }
5638
6472
  if (response.changesSummary) {
5639
- log(quiet, chalk10.dim(`
6473
+ log(quiet, chalk11.dim(`
5640
6474
  ${response.changesSummary}`));
5641
6475
  }
5642
6476
  if (currentSha) {
@@ -5649,7 +6483,7 @@ async function refreshCommand(options) {
5649
6483
  const config = loadConfig();
5650
6484
  if (!config) {
5651
6485
  if (quiet) return;
5652
- console.log(chalk10.red("No LLM provider configured. Run `caliber config` (e.g. choose Cursor) or set an API key."));
6486
+ 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."));
5653
6487
  throw new Error("__exit__");
5654
6488
  }
5655
6489
  if (isGitRepo()) {
@@ -5659,20 +6493,20 @@ async function refreshCommand(options) {
5659
6493
  const repos = discoverGitRepos(process.cwd());
5660
6494
  if (repos.length === 0) {
5661
6495
  if (quiet) return;
5662
- console.log(chalk10.red("Not inside a git repository and no git repos found in child directories."));
6496
+ console.log(chalk11.red("Not inside a git repository and no git repos found in child directories."));
5663
6497
  throw new Error("__exit__");
5664
6498
  }
5665
- log(quiet, chalk10.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
6499
+ log(quiet, chalk11.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
5666
6500
  `));
5667
6501
  const originalDir = process.cwd();
5668
6502
  for (const repo of repos) {
5669
- const repoName = path18.basename(repo);
6503
+ const repoName = path21.basename(repo);
5670
6504
  try {
5671
6505
  process.chdir(repo);
5672
6506
  await refreshSingleRepo(repo, { ...options, label: repoName });
5673
6507
  } catch (err) {
5674
6508
  if (err instanceof Error && err.message === "__exit__") continue;
5675
- log(quiet, chalk10.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
6509
+ log(quiet, chalk11.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
5676
6510
  }
5677
6511
  }
5678
6512
  process.chdir(originalDir);
@@ -5680,13 +6514,13 @@ async function refreshCommand(options) {
5680
6514
  if (err instanceof Error && err.message === "__exit__") throw err;
5681
6515
  if (quiet) return;
5682
6516
  const msg = err instanceof Error ? err.message : "Unknown error";
5683
- console.log(chalk10.red(`Refresh failed: ${msg}`));
6517
+ console.log(chalk11.red(`Refresh failed: ${msg}`));
5684
6518
  throw new Error("__exit__");
5685
6519
  }
5686
6520
  }
5687
6521
 
5688
6522
  // src/commands/hooks.ts
5689
- import chalk11 from "chalk";
6523
+ import chalk12 from "chalk";
5690
6524
  var HOOKS = [
5691
6525
  {
5692
6526
  id: "session-end",
@@ -5706,13 +6540,13 @@ var HOOKS = [
5706
6540
  }
5707
6541
  ];
5708
6542
  function printStatus() {
5709
- console.log(chalk11.bold("\n Hooks\n"));
6543
+ console.log(chalk12.bold("\n Hooks\n"));
5710
6544
  for (const hook of HOOKS) {
5711
6545
  const installed = hook.isInstalled();
5712
- const icon = installed ? chalk11.green("\u2713") : chalk11.dim("\u2717");
5713
- const state = installed ? chalk11.green("enabled") : chalk11.dim("disabled");
6546
+ const icon = installed ? chalk12.green("\u2713") : chalk12.dim("\u2717");
6547
+ const state = installed ? chalk12.green("enabled") : chalk12.dim("disabled");
5714
6548
  console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
5715
- console.log(chalk11.dim(` ${hook.description}`));
6549
+ console.log(chalk12.dim(` ${hook.description}`));
5716
6550
  }
5717
6551
  console.log("");
5718
6552
  }
@@ -5721,9 +6555,9 @@ async function hooksCommand(options) {
5721
6555
  for (const hook of HOOKS) {
5722
6556
  const result = hook.install();
5723
6557
  if (result.alreadyInstalled) {
5724
- console.log(chalk11.dim(` ${hook.label} already enabled.`));
6558
+ console.log(chalk12.dim(` ${hook.label} already enabled.`));
5725
6559
  } else {
5726
- console.log(chalk11.green(" \u2713") + ` ${hook.label} enabled`);
6560
+ console.log(chalk12.green(" \u2713") + ` ${hook.label} enabled`);
5727
6561
  }
5728
6562
  }
5729
6563
  return;
@@ -5732,9 +6566,9 @@ async function hooksCommand(options) {
5732
6566
  for (const hook of HOOKS) {
5733
6567
  const result = hook.remove();
5734
6568
  if (result.notFound) {
5735
- console.log(chalk11.dim(` ${hook.label} already disabled.`));
6569
+ console.log(chalk12.dim(` ${hook.label} already disabled.`));
5736
6570
  } else {
5737
- console.log(chalk11.green(" \u2713") + ` ${hook.label} removed`);
6571
+ console.log(chalk12.green(" \u2713") + ` ${hook.label} removed`);
5738
6572
  }
5739
6573
  }
5740
6574
  return;
@@ -5749,18 +6583,18 @@ async function hooksCommand(options) {
5749
6583
  const states = HOOKS.map((h) => h.isInstalled());
5750
6584
  function render() {
5751
6585
  const lines = [];
5752
- lines.push(chalk11.bold(" Hooks"));
6586
+ lines.push(chalk12.bold(" Hooks"));
5753
6587
  lines.push("");
5754
6588
  for (let i = 0; i < HOOKS.length; i++) {
5755
6589
  const hook = HOOKS[i];
5756
6590
  const enabled = states[i];
5757
- const toggle = enabled ? chalk11.green("[on] ") : chalk11.dim("[off]");
5758
- const ptr = i === cursor ? chalk11.cyan(">") : " ";
6591
+ const toggle = enabled ? chalk12.green("[on] ") : chalk12.dim("[off]");
6592
+ const ptr = i === cursor ? chalk12.cyan(">") : " ";
5759
6593
  lines.push(` ${ptr} ${toggle} ${hook.label}`);
5760
- lines.push(chalk11.dim(` ${hook.description}`));
6594
+ lines.push(chalk12.dim(` ${hook.description}`));
5761
6595
  }
5762
6596
  lines.push("");
5763
- lines.push(chalk11.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
6597
+ lines.push(chalk12.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
5764
6598
  return lines.join("\n");
5765
6599
  }
5766
6600
  function draw(initial) {
@@ -5791,16 +6625,16 @@ async function hooksCommand(options) {
5791
6625
  const wantEnabled = states[i];
5792
6626
  if (wantEnabled && !wasInstalled) {
5793
6627
  hook.install();
5794
- console.log(chalk11.green(" \u2713") + ` ${hook.label} enabled`);
6628
+ console.log(chalk12.green(" \u2713") + ` ${hook.label} enabled`);
5795
6629
  changed++;
5796
6630
  } else if (!wantEnabled && wasInstalled) {
5797
6631
  hook.remove();
5798
- console.log(chalk11.green(" \u2713") + ` ${hook.label} disabled`);
6632
+ console.log(chalk12.green(" \u2713") + ` ${hook.label} disabled`);
5799
6633
  changed++;
5800
6634
  }
5801
6635
  }
5802
6636
  if (changed === 0) {
5803
- console.log(chalk11.dim(" No changes."));
6637
+ console.log(chalk12.dim(" No changes."));
5804
6638
  }
5805
6639
  console.log("");
5806
6640
  }
@@ -5836,7 +6670,7 @@ async function hooksCommand(options) {
5836
6670
  case "\x1B":
5837
6671
  case "":
5838
6672
  cleanup();
5839
- console.log(chalk11.dim("\n Cancelled.\n"));
6673
+ console.log(chalk12.dim("\n Cancelled.\n"));
5840
6674
  resolve2();
5841
6675
  break;
5842
6676
  }
@@ -5846,43 +6680,43 @@ async function hooksCommand(options) {
5846
6680
  }
5847
6681
 
5848
6682
  // src/commands/config.ts
5849
- import chalk12 from "chalk";
6683
+ import chalk13 from "chalk";
5850
6684
  async function configCommand() {
5851
6685
  const existing = loadConfig();
5852
6686
  if (existing) {
5853
- console.log(chalk12.bold("\nCurrent Configuration\n"));
5854
- console.log(` Provider: ${chalk12.cyan(existing.provider)}`);
5855
- console.log(` Model: ${chalk12.cyan(existing.model)}`);
6687
+ console.log(chalk13.bold("\nCurrent Configuration\n"));
6688
+ console.log(` Provider: ${chalk13.cyan(existing.provider)}`);
6689
+ console.log(` Model: ${chalk13.cyan(existing.model)}`);
5856
6690
  if (existing.apiKey) {
5857
6691
  const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
5858
- console.log(` API Key: ${chalk12.dim(masked)}`);
6692
+ console.log(` API Key: ${chalk13.dim(masked)}`);
5859
6693
  }
5860
6694
  if (existing.provider === "cursor") {
5861
- console.log(` Seat: ${chalk12.dim("Cursor (agent acp)")}`);
6695
+ console.log(` Seat: ${chalk13.dim("Cursor (agent acp)")}`);
5862
6696
  }
5863
6697
  if (existing.provider === "claude-cli") {
5864
- console.log(` Seat: ${chalk12.dim("Claude Code (claude -p)")}`);
6698
+ console.log(` Seat: ${chalk13.dim("Claude Code (claude -p)")}`);
5865
6699
  }
5866
6700
  if (existing.baseUrl) {
5867
- console.log(` Base URL: ${chalk12.dim(existing.baseUrl)}`);
6701
+ console.log(` Base URL: ${chalk13.dim(existing.baseUrl)}`);
5868
6702
  }
5869
6703
  if (existing.vertexProjectId) {
5870
- console.log(` Vertex Project: ${chalk12.dim(existing.vertexProjectId)}`);
5871
- console.log(` Vertex Region: ${chalk12.dim(existing.vertexRegion || "us-east5")}`);
6704
+ console.log(` Vertex Project: ${chalk13.dim(existing.vertexProjectId)}`);
6705
+ console.log(` Vertex Region: ${chalk13.dim(existing.vertexRegion || "us-east5")}`);
5872
6706
  }
5873
- 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())}`);
6707
+ 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())}`);
5874
6708
  console.log("");
5875
6709
  }
5876
6710
  await runInteractiveProviderSetup();
5877
- console.log(chalk12.green("\n\u2713 Configuration saved"));
5878
- console.log(chalk12.dim(` ${getConfigFilePath()}
6711
+ console.log(chalk13.green("\n\u2713 Configuration saved"));
6712
+ console.log(chalk13.dim(` ${getConfigFilePath()}
5879
6713
  `));
5880
- console.log(chalk12.dim(" You can also set environment variables instead:"));
5881
- 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"));
6714
+ console.log(chalk13.dim(" You can also set environment variables instead:"));
6715
+ 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"));
5882
6716
  }
5883
6717
 
5884
6718
  // src/commands/learn.ts
5885
- import chalk13 from "chalk";
6719
+ import chalk14 from "chalk";
5886
6720
 
5887
6721
  // src/learner/stdin.ts
5888
6722
  var STDIN_TIMEOUT_MS = 5e3;
@@ -5913,8 +6747,8 @@ function readStdin() {
5913
6747
 
5914
6748
  // src/learner/storage.ts
5915
6749
  init_constants();
5916
- import fs22 from "fs";
5917
- import path19 from "path";
6750
+ import fs25 from "fs";
6751
+ import path22 from "path";
5918
6752
  var MAX_RESPONSE_LENGTH = 2e3;
5919
6753
  var DEFAULT_STATE = {
5920
6754
  sessionId: null,
@@ -5922,15 +6756,15 @@ var DEFAULT_STATE = {
5922
6756
  lastAnalysisTimestamp: null
5923
6757
  };
5924
6758
  function ensureLearningDir() {
5925
- if (!fs22.existsSync(LEARNING_DIR)) {
5926
- fs22.mkdirSync(LEARNING_DIR, { recursive: true });
6759
+ if (!fs25.existsSync(LEARNING_DIR)) {
6760
+ fs25.mkdirSync(LEARNING_DIR, { recursive: true });
5927
6761
  }
5928
6762
  }
5929
6763
  function sessionFilePath() {
5930
- return path19.join(LEARNING_DIR, LEARNING_SESSION_FILE);
6764
+ return path22.join(LEARNING_DIR, LEARNING_SESSION_FILE);
5931
6765
  }
5932
6766
  function stateFilePath() {
5933
- return path19.join(LEARNING_DIR, LEARNING_STATE_FILE);
6767
+ return path22.join(LEARNING_DIR, LEARNING_STATE_FILE);
5934
6768
  }
5935
6769
  function truncateResponse(response) {
5936
6770
  const str = JSON.stringify(response);
@@ -5941,50 +6775,50 @@ function appendEvent(event) {
5941
6775
  ensureLearningDir();
5942
6776
  const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
5943
6777
  const filePath = sessionFilePath();
5944
- fs22.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
6778
+ fs25.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
5945
6779
  const count = getEventCount();
5946
6780
  if (count > LEARNING_MAX_EVENTS) {
5947
- const lines = fs22.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6781
+ const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
5948
6782
  const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
5949
- fs22.writeFileSync(filePath, kept.join("\n") + "\n");
6783
+ fs25.writeFileSync(filePath, kept.join("\n") + "\n");
5950
6784
  }
5951
6785
  }
5952
6786
  function readAllEvents() {
5953
6787
  const filePath = sessionFilePath();
5954
- if (!fs22.existsSync(filePath)) return [];
5955
- const lines = fs22.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
6788
+ if (!fs25.existsSync(filePath)) return [];
6789
+ const lines = fs25.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
5956
6790
  return lines.map((line) => JSON.parse(line));
5957
6791
  }
5958
6792
  function getEventCount() {
5959
6793
  const filePath = sessionFilePath();
5960
- if (!fs22.existsSync(filePath)) return 0;
5961
- const content = fs22.readFileSync(filePath, "utf-8");
6794
+ if (!fs25.existsSync(filePath)) return 0;
6795
+ const content = fs25.readFileSync(filePath, "utf-8");
5962
6796
  return content.split("\n").filter(Boolean).length;
5963
6797
  }
5964
6798
  function clearSession() {
5965
6799
  const filePath = sessionFilePath();
5966
- if (fs22.existsSync(filePath)) fs22.unlinkSync(filePath);
6800
+ if (fs25.existsSync(filePath)) fs25.unlinkSync(filePath);
5967
6801
  }
5968
6802
  function readState2() {
5969
6803
  const filePath = stateFilePath();
5970
- if (!fs22.existsSync(filePath)) return { ...DEFAULT_STATE };
6804
+ if (!fs25.existsSync(filePath)) return { ...DEFAULT_STATE };
5971
6805
  try {
5972
- return JSON.parse(fs22.readFileSync(filePath, "utf-8"));
6806
+ return JSON.parse(fs25.readFileSync(filePath, "utf-8"));
5973
6807
  } catch {
5974
6808
  return { ...DEFAULT_STATE };
5975
6809
  }
5976
6810
  }
5977
6811
  function writeState2(state) {
5978
6812
  ensureLearningDir();
5979
- fs22.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
6813
+ fs25.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
5980
6814
  }
5981
6815
  function resetState() {
5982
6816
  writeState2({ ...DEFAULT_STATE });
5983
6817
  }
5984
6818
 
5985
6819
  // src/learner/writer.ts
5986
- import fs23 from "fs";
5987
- import path20 from "path";
6820
+ import fs26 from "fs";
6821
+ import path23 from "path";
5988
6822
  var LEARNED_START = "<!-- caliber:learned -->";
5989
6823
  var LEARNED_END = "<!-- /caliber:learned -->";
5990
6824
  function writeLearnedContent(update) {
@@ -6004,8 +6838,8 @@ function writeLearnedContent(update) {
6004
6838
  function writeLearnedSection(content) {
6005
6839
  const claudeMdPath = "CLAUDE.md";
6006
6840
  let existing = "";
6007
- if (fs23.existsSync(claudeMdPath)) {
6008
- existing = fs23.readFileSync(claudeMdPath, "utf-8");
6841
+ if (fs26.existsSync(claudeMdPath)) {
6842
+ existing = fs26.readFileSync(claudeMdPath, "utf-8");
6009
6843
  }
6010
6844
  const section = `${LEARNED_START}
6011
6845
  ${content}
@@ -6019,15 +6853,15 @@ ${LEARNED_END}`;
6019
6853
  const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
6020
6854
  updated = existing + separator + "\n" + section + "\n";
6021
6855
  }
6022
- fs23.writeFileSync(claudeMdPath, updated);
6856
+ fs26.writeFileSync(claudeMdPath, updated);
6023
6857
  }
6024
6858
  function writeLearnedSkill(skill) {
6025
- const skillDir = path20.join(".claude", "skills", skill.name);
6026
- if (!fs23.existsSync(skillDir)) fs23.mkdirSync(skillDir, { recursive: true });
6027
- const skillPath = path20.join(skillDir, "SKILL.md");
6028
- if (!skill.isNew && fs23.existsSync(skillPath)) {
6029
- const existing = fs23.readFileSync(skillPath, "utf-8");
6030
- fs23.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6859
+ const skillDir = path23.join(".claude", "skills", skill.name);
6860
+ if (!fs26.existsSync(skillDir)) fs26.mkdirSync(skillDir, { recursive: true });
6861
+ const skillPath = path23.join(skillDir, "SKILL.md");
6862
+ if (!skill.isNew && fs26.existsSync(skillPath)) {
6863
+ const existing = fs26.readFileSync(skillPath, "utf-8");
6864
+ fs26.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
6031
6865
  } else {
6032
6866
  const frontmatter = [
6033
6867
  "---",
@@ -6036,14 +6870,14 @@ function writeLearnedSkill(skill) {
6036
6870
  "---",
6037
6871
  ""
6038
6872
  ].join("\n");
6039
- fs23.writeFileSync(skillPath, frontmatter + skill.content);
6873
+ fs26.writeFileSync(skillPath, frontmatter + skill.content);
6040
6874
  }
6041
6875
  return skillPath;
6042
6876
  }
6043
6877
  function readLearnedSection() {
6044
6878
  const claudeMdPath = "CLAUDE.md";
6045
- if (!fs23.existsSync(claudeMdPath)) return null;
6046
- const content = fs23.readFileSync(claudeMdPath, "utf-8");
6879
+ if (!fs26.existsSync(claudeMdPath)) return null;
6880
+ const content = fs26.readFileSync(claudeMdPath, "utf-8");
6047
6881
  const startIdx = content.indexOf(LEARNED_START);
6048
6882
  const endIdx = content.indexOf(LEARNED_END);
6049
6883
  if (startIdx === -1 || endIdx === -1) return null;
@@ -6183,53 +7017,53 @@ async function learnFinalizeCommand() {
6183
7017
  async function learnInstallCommand() {
6184
7018
  const result = installLearningHooks();
6185
7019
  if (result.alreadyInstalled) {
6186
- console.log(chalk13.dim("Learning hooks already installed."));
7020
+ console.log(chalk14.dim("Learning hooks already installed."));
6187
7021
  return;
6188
7022
  }
6189
- console.log(chalk13.green("\u2713") + " Learning hooks installed in .claude/settings.json");
6190
- console.log(chalk13.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
6191
- console.log(chalk13.dim(" Session learnings will be written to CLAUDE.md and skills."));
7023
+ console.log(chalk14.green("\u2713") + " Learning hooks installed in .claude/settings.json");
7024
+ console.log(chalk14.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
7025
+ console.log(chalk14.dim(" Session learnings will be written to CLAUDE.md and skills."));
6192
7026
  }
6193
7027
  async function learnRemoveCommand() {
6194
7028
  const result = removeLearningHooks();
6195
7029
  if (result.notFound) {
6196
- console.log(chalk13.dim("Learning hooks not found."));
7030
+ console.log(chalk14.dim("Learning hooks not found."));
6197
7031
  return;
6198
7032
  }
6199
- console.log(chalk13.green("\u2713") + " Learning hooks removed from .claude/settings.json");
7033
+ console.log(chalk14.green("\u2713") + " Learning hooks removed from .claude/settings.json");
6200
7034
  }
6201
7035
  async function learnStatusCommand() {
6202
7036
  const installed = areLearningHooksInstalled();
6203
7037
  const state = readState2();
6204
7038
  const eventCount = getEventCount();
6205
- console.log(chalk13.bold("Session Learning Status"));
7039
+ console.log(chalk14.bold("Session Learning Status"));
6206
7040
  console.log();
6207
7041
  if (installed) {
6208
- console.log(chalk13.green("\u2713") + " Learning hooks are " + chalk13.green("installed"));
7042
+ console.log(chalk14.green("\u2713") + " Learning hooks are " + chalk14.green("installed"));
6209
7043
  } else {
6210
- console.log(chalk13.dim("\u2717") + " Learning hooks are " + chalk13.yellow("not installed"));
6211
- console.log(chalk13.dim(" Run `caliber learn install` to enable session learning."));
7044
+ console.log(chalk14.dim("\u2717") + " Learning hooks are " + chalk14.yellow("not installed"));
7045
+ console.log(chalk14.dim(" Run `caliber learn install` to enable session learning."));
6212
7046
  }
6213
7047
  console.log();
6214
- console.log(`Events recorded: ${chalk13.cyan(String(eventCount))}`);
6215
- console.log(`Total this session: ${chalk13.cyan(String(state.eventCount))}`);
7048
+ console.log(`Events recorded: ${chalk14.cyan(String(eventCount))}`);
7049
+ console.log(`Total this session: ${chalk14.cyan(String(state.eventCount))}`);
6216
7050
  if (state.lastAnalysisTimestamp) {
6217
- console.log(`Last analysis: ${chalk13.cyan(state.lastAnalysisTimestamp)}`);
7051
+ console.log(`Last analysis: ${chalk14.cyan(state.lastAnalysisTimestamp)}`);
6218
7052
  } else {
6219
- console.log(`Last analysis: ${chalk13.dim("none")}`);
7053
+ console.log(`Last analysis: ${chalk14.dim("none")}`);
6220
7054
  }
6221
7055
  const learnedSection = readLearnedSection();
6222
7056
  if (learnedSection) {
6223
7057
  const lineCount = learnedSection.split("\n").filter(Boolean).length;
6224
7058
  console.log(`
6225
- Learned items in CLAUDE.md: ${chalk13.cyan(String(lineCount))}`);
7059
+ Learned items in CLAUDE.md: ${chalk14.cyan(String(lineCount))}`);
6226
7060
  }
6227
7061
  }
6228
7062
 
6229
7063
  // src/cli.ts
6230
- var __dirname = path21.dirname(fileURLToPath(import.meta.url));
7064
+ var __dirname = path24.dirname(fileURLToPath(import.meta.url));
6231
7065
  var pkg = JSON.parse(
6232
- fs24.readFileSync(path21.resolve(__dirname, "..", "package.json"), "utf-8")
7066
+ fs27.readFileSync(path24.resolve(__dirname, "..", "package.json"), "utf-8")
6233
7067
  );
6234
7068
  var program = new Command();
6235
7069
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -6251,22 +7085,22 @@ learn.command("remove").description("Remove learning hooks from .claude/settings
6251
7085
  learn.command("status").description("Show learning system status").action(learnStatusCommand);
6252
7086
 
6253
7087
  // src/utils/version-check.ts
6254
- import fs25 from "fs";
6255
- import path22 from "path";
7088
+ import fs28 from "fs";
7089
+ import path25 from "path";
6256
7090
  import { fileURLToPath as fileURLToPath2 } from "url";
6257
7091
  import { execSync as execSync9 } from "child_process";
6258
- import chalk14 from "chalk";
6259
- import ora6 from "ora";
7092
+ import chalk15 from "chalk";
7093
+ import ora7 from "ora";
6260
7094
  import confirm2 from "@inquirer/confirm";
6261
- var __dirname_vc = path22.dirname(fileURLToPath2(import.meta.url));
7095
+ var __dirname_vc = path25.dirname(fileURLToPath2(import.meta.url));
6262
7096
  var pkg2 = JSON.parse(
6263
- fs25.readFileSync(path22.resolve(__dirname_vc, "..", "package.json"), "utf-8")
7097
+ fs28.readFileSync(path25.resolve(__dirname_vc, "..", "package.json"), "utf-8")
6264
7098
  );
6265
7099
  function getInstalledVersion() {
6266
7100
  try {
6267
7101
  const globalRoot = execSync9("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
6268
- const pkgPath = path22.join(globalRoot, "@rely-ai", "caliber", "package.json");
6269
- return JSON.parse(fs25.readFileSync(pkgPath, "utf-8")).version;
7102
+ const pkgPath = path25.join(globalRoot, "@rely-ai", "caliber", "package.json");
7103
+ return JSON.parse(fs28.readFileSync(pkgPath, "utf-8")).version;
6270
7104
  } catch {
6271
7105
  return null;
6272
7106
  }
@@ -6289,17 +7123,17 @@ async function checkForUpdates() {
6289
7123
  const isInteractive = process.stdin.isTTY === true;
6290
7124
  if (!isInteractive) {
6291
7125
  console.log(
6292
- chalk14.yellow(
7126
+ chalk15.yellow(
6293
7127
  `
6294
7128
  Update available: ${current} -> ${latest}
6295
- Run ${chalk14.bold("npm install -g @rely-ai/caliber")} to upgrade.
7129
+ Run ${chalk15.bold("npm install -g @rely-ai/caliber")} to upgrade.
6296
7130
  `
6297
7131
  )
6298
7132
  );
6299
7133
  return;
6300
7134
  }
6301
7135
  console.log(
6302
- chalk14.yellow(`
7136
+ chalk15.yellow(`
6303
7137
  Update available: ${current} -> ${latest}`)
6304
7138
  );
6305
7139
  const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
@@ -6307,7 +7141,7 @@ Update available: ${current} -> ${latest}`)
6307
7141
  console.log();
6308
7142
  return;
6309
7143
  }
6310
- const spinner = ora6("Updating caliber...").start();
7144
+ const spinner = ora7("Updating caliber...").start();
6311
7145
  try {
6312
7146
  execSync9(`npm install -g @rely-ai/caliber@${latest}`, {
6313
7147
  stdio: "pipe",
@@ -6317,13 +7151,13 @@ Update available: ${current} -> ${latest}`)
6317
7151
  const installed = getInstalledVersion();
6318
7152
  if (installed !== latest) {
6319
7153
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
6320
- console.log(chalk14.yellow(`Run ${chalk14.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
7154
+ console.log(chalk15.yellow(`Run ${chalk15.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
6321
7155
  `));
6322
7156
  return;
6323
7157
  }
6324
- spinner.succeed(chalk14.green(`Updated to ${latest}`));
7158
+ spinner.succeed(chalk15.green(`Updated to ${latest}`));
6325
7159
  const args = process.argv.slice(2);
6326
- console.log(chalk14.dim(`
7160
+ console.log(chalk15.dim(`
6327
7161
  Restarting: caliber ${args.join(" ")}
6328
7162
  `));
6329
7163
  execSync9(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
@@ -6336,11 +7170,11 @@ Restarting: caliber ${args.join(" ")}
6336
7170
  if (err instanceof Error) {
6337
7171
  const stderr = err.stderr;
6338
7172
  const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
6339
- if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk14.dim(` ${errMsg}`));
7173
+ if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk15.dim(` ${errMsg}`));
6340
7174
  }
6341
7175
  console.log(
6342
- chalk14.yellow(
6343
- `Run ${chalk14.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
7176
+ chalk15.yellow(
7177
+ `Run ${chalk15.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
6344
7178
  `
6345
7179
  )
6346
7180
  );