@rely-ai/caliber 1.36.0 → 1.36.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 (3) hide show
  1. package/README.md +2 -2
  2. package/dist/bin.js +226 -78
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -285,9 +285,9 @@ No API key? No problem. Caliber works with your existing AI tool subscription:
285
285
  | **Claude Code** (your seat) | `caliber config` → Claude Code | Inherited from Claude Code |
286
286
  | **Cursor** (your seat) | `caliber config` → Cursor | Inherited from Cursor |
287
287
  | **Anthropic** | `export ANTHROPIC_API_KEY=sk-ant-...` | `claude-sonnet-4-6` |
288
- | **OpenAI** | `export OPENAI_API_KEY=sk-...` | `gpt-4.1` |
288
+ | **OpenAI** | `export OPENAI_API_KEY=sk-...` | `gpt-5.4-mini` |
289
289
  | **Vertex AI** | `export VERTEX_PROJECT_ID=my-project` | `claude-sonnet-4-6` |
290
- | **Custom endpoint** | `OPENAI_API_KEY` + `OPENAI_BASE_URL` | `gpt-4.1` |
290
+ | **Custom endpoint** | `OPENAI_API_KEY` + `OPENAI_BASE_URL` | `gpt-5.4-mini` |
291
291
 
292
292
  Override the model for any provider: `export CALIBER_MODEL=<model-name>` or use `caliber config`.
293
293
 
package/dist/bin.js CHANGED
@@ -35,9 +35,9 @@ function getMaxPromptTokens() {
35
35
  return Math.max(MIN_PROMPT_TOKENS, Math.min(budget, MAX_PROMPT_TOKENS_CAP));
36
36
  }
37
37
  function loadConfig() {
38
- const envConfig = resolveFromEnv();
39
- if (envConfig) return envConfig;
40
- return readConfigFile();
38
+ const fileConfig = readConfigFile();
39
+ if (fileConfig) return fileConfig;
40
+ return resolveFromEnv();
41
41
  }
42
42
  function resolveFromEnv() {
43
43
  if (process.env.ANTHROPIC_API_KEY) {
@@ -130,7 +130,7 @@ var init_config = __esm({
130
130
  DEFAULT_MODELS = {
131
131
  anthropic: "claude-sonnet-4-6",
132
132
  vertex: "claude-sonnet-4-6",
133
- openai: "gpt-4.1",
133
+ openai: "gpt-5.4-mini",
134
134
  cursor: "sonnet-4.6",
135
135
  "claude-cli": "default"
136
136
  };
@@ -139,8 +139,7 @@ var init_config = __esm({
139
139
  "claude-opus-4-6": 2e5,
140
140
  "claude-haiku-4-5-20251001": 2e5,
141
141
  "claude-sonnet-4-5-20250514": 2e5,
142
- "gpt-4.1": 1e6,
143
- "gpt-4.1-mini": 1e6,
142
+ "gpt-5.4-mini": 1e6,
144
143
  "gpt-4o": 128e3,
145
144
  "gpt-4o-mini": 128e3,
146
145
  "sonnet-4.6": 2e5
@@ -152,7 +151,7 @@ var init_config = __esm({
152
151
  DEFAULT_FAST_MODELS = {
153
152
  anthropic: "claude-haiku-4-5-20251001",
154
153
  vertex: "claude-haiku-4-5-20251001",
155
- openai: "gpt-4.1-mini",
154
+ openai: "gpt-5.4-mini",
156
155
  cursor: "gpt-5.3-codex-fast"
157
156
  };
158
157
  }
@@ -2836,13 +2835,7 @@ var KNOWN_MODELS = {
2836
2835
  "claude-opus-4-6@20250605",
2837
2836
  "claude-opus-4-1-20250620"
2838
2837
  ],
2839
- openai: [
2840
- "gpt-4.1",
2841
- "gpt-4.1-mini",
2842
- "gpt-4o",
2843
- "gpt-4o-mini",
2844
- "o3-mini"
2845
- ],
2838
+ openai: ["gpt-5.4-mini", "gpt-4o", "gpt-4o-mini", "o3-mini"],
2846
2839
  cursor: ["auto", "composer-1.5"],
2847
2840
  "claude-cli": []
2848
2841
  };
@@ -2850,7 +2843,8 @@ function isModelNotAvailableError(error) {
2850
2843
  const msg = error.message.toLowerCase();
2851
2844
  const status = error.status;
2852
2845
  if (status === 404 && msg.includes("model")) return true;
2853
- if (msg.includes("model") && (msg.includes("not found") || msg.includes("not_found"))) return true;
2846
+ if (msg.includes("model") && (msg.includes("not found") || msg.includes("not_found")))
2847
+ return true;
2854
2848
  if (msg.includes("model") && msg.includes("not available")) return true;
2855
2849
  if (msg.includes("model") && msg.includes("does not exist")) return true;
2856
2850
  if (msg.includes("publisher model")) return true;
@@ -2876,12 +2870,18 @@ function filterRelevantModels(models, provider) {
2876
2870
  async function handleModelNotAvailable(failedModel, provider, config) {
2877
2871
  if (!process.stdin.isTTY) {
2878
2872
  console.error(
2879
- chalk.red(`Model "${failedModel}" is not available. Run \`${resolveCaliber()} config\` to select a different model.`)
2873
+ chalk.red(
2874
+ `Model "${failedModel}" is not available. Run \`${resolveCaliber()} config\` to select a different model.`
2875
+ )
2880
2876
  );
2881
2877
  return null;
2882
2878
  }
2883
- console.log(chalk.yellow(`
2884
- \u26A0 Model "${failedModel}" is not available on your ${config.provider} deployment.`));
2879
+ console.log(
2880
+ chalk.yellow(
2881
+ `
2882
+ \u26A0 Model "${failedModel}" is not available on your ${config.provider} deployment.`
2883
+ )
2884
+ );
2885
2885
  let models = [];
2886
2886
  if (provider.listModels) {
2887
2887
  try {
@@ -2895,7 +2895,11 @@ async function handleModelNotAvailable(failedModel, provider, config) {
2895
2895
  }
2896
2896
  models = models.filter((m) => m !== failedModel);
2897
2897
  if (models.length === 0) {
2898
- console.log(chalk.red(` No alternative models found. Run \`${resolveCaliber()} config\` to configure manually.`));
2898
+ console.log(
2899
+ chalk.red(
2900
+ ` No alternative models found. Run \`${resolveCaliber()} config\` to configure manually.`
2901
+ )
2902
+ );
2899
2903
  return null;
2900
2904
  }
2901
2905
  console.log("");
@@ -6288,14 +6292,17 @@ function checkExistence(dir) {
6288
6292
  const opencodeSkills = countFiles(join3(dir, ".opencode", "skills"), /SKILL\.md$/);
6289
6293
  const skillCount = claudeSkills.length + codexSkills.length + opencodeSkills.length;
6290
6294
  const skillBase = skillCount >= 1 ? POINTS_SKILLS_EXIST : 0;
6291
- const skillBonus = Math.min((skillCount - 1) * POINTS_SKILLS_BONUS_PER_EXTRA, POINTS_SKILLS_BONUS_CAP);
6295
+ const skillBonus = Math.min(
6296
+ (skillCount - 1) * POINTS_SKILLS_BONUS_PER_EXTRA,
6297
+ POINTS_SKILLS_BONUS_CAP
6298
+ );
6292
6299
  const skillPoints = skillCount >= 1 ? skillBase + Math.max(0, skillBonus) : 0;
6293
6300
  const maxSkillPoints = POINTS_SKILLS_EXIST + POINTS_SKILLS_BONUS_CAP;
6294
6301
  checks.push({
6295
6302
  id: "skills_exist",
6296
6303
  name: "Skills configured",
6297
6304
  category: "existence",
6298
- maxPoints: maxSkillPoints,
6305
+ maxPoints: skillCount >= 1 ? maxSkillPoints : 0,
6299
6306
  earnedPoints: Math.min(skillPoints, maxSkillPoints),
6300
6307
  passed: skillCount >= 1,
6301
6308
  detail: skillCount === 0 ? "No skills found" : `${skillCount} skill${skillCount === 1 ? "" : "s"} found`,
@@ -6328,7 +6335,7 @@ function checkExistence(dir) {
6328
6335
  id: "mcp_servers",
6329
6336
  name: "MCP servers configured",
6330
6337
  category: "existence",
6331
- maxPoints: POINTS_MCP_SERVERS,
6338
+ maxPoints: mcp.count >= 1 ? POINTS_MCP_SERVERS : 0,
6332
6339
  earnedPoints: mcp.count >= 1 ? POINTS_MCP_SERVERS : 0,
6333
6340
  passed: mcp.count >= 1,
6334
6341
  detail: mcp.count > 0 ? `${mcp.count} server${mcp.count === 1 ? "" : "s"} in ${mcp.sources.join(", ")}` : "No MCP servers configured",
@@ -6863,7 +6870,11 @@ init_resolve_caliber();
6863
6870
  init_pre_commit_block();
6864
6871
  function hasPreCommitHook(dir) {
6865
6872
  try {
6866
- const gitDir = execSync12("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
6873
+ const gitDir = execSync12("git rev-parse --git-dir", {
6874
+ cwd: dir,
6875
+ encoding: "utf-8",
6876
+ stdio: ["pipe", "pipe", "pipe"]
6877
+ }).trim();
6867
6878
  const hookPath = join7(gitDir, "hooks", "pre-commit");
6868
6879
  const content = readFileOrNull(hookPath);
6869
6880
  return content ? content.includes("caliber") : false;
@@ -6954,9 +6965,9 @@ function checkBonus(dir) {
6954
6965
  id: "open_skills_format",
6955
6966
  name: "Skills use OpenSkills format",
6956
6967
  category: "bonus",
6957
- maxPoints: POINTS_OPEN_SKILLS_FORMAT,
6968
+ maxPoints: totalSkillFiles > 0 ? POINTS_OPEN_SKILLS_FORMAT : 0,
6958
6969
  earnedPoints: allOpenSkills ? POINTS_OPEN_SKILLS_FORMAT : 0,
6959
- passed: allOpenSkills,
6970
+ passed: allOpenSkills || totalSkillFiles === 0,
6960
6971
  detail: totalSkillFiles === 0 ? "No skills to check" : allOpenSkills ? `All ${totalSkillFiles} skill${totalSkillFiles === 1 ? "" : "s"} use SKILL.md with frontmatter` : `${openSkillsCount}/${totalSkillFiles} use OpenSkills format`,
6961
6972
  suggestion: totalSkillFiles > 0 && !allOpenSkills ? "Migrate skills to .claude/skills/{name}/SKILL.md with YAML frontmatter" : void 0,
6962
6973
  fix: totalSkillFiles > 0 && !allOpenSkills ? {
@@ -9750,27 +9761,47 @@ async function initCommand(options) {
9750
9761
  const bin = resolveCaliber();
9751
9762
  const firstRun = isFirstRun(process.cwd());
9752
9763
  if (firstRun) {
9753
- console.log(brand.bold(`
9764
+ console.log(
9765
+ brand.bold(`
9754
9766
  \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
9755
9767
  \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
9756
9768
  \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
9757
9769
  \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
9758
9770
  \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
9759
9771
  \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
9760
- `));
9772
+ `)
9773
+ );
9761
9774
  console.log(chalk14.dim(" Keep your AI agent configs in sync \u2014 automatically."));
9762
9775
  console.log(chalk14.dim(" Works across Claude Code, Cursor, Codex, and GitHub Copilot.\n"));
9763
- console.log(title.bold(" How it works:\n"));
9764
- console.log(chalk14.dim(" 1. Connect Auto-detect your LLM provider and agents"));
9765
- console.log(chalk14.dim(" 2. Build Install sync, scan your project, generate configs"));
9766
- console.log(chalk14.dim(" 3. Done Review score and start syncing\n"));
9776
+ console.log(title.bold(" What this does:\n"));
9777
+ console.log(
9778
+ chalk14.dim(" Caliber reads your project structure (file tree, package.json, etc.)")
9779
+ );
9780
+ console.log(chalk14.dim(" and generates agent config files (CLAUDE.md, .cursor/rules/, etc.)."));
9781
+ console.log(chalk14.dim(" You review all changes before anything is written to disk.\n"));
9782
+ console.log(title.bold(" Steps:\n"));
9783
+ console.log(
9784
+ chalk14.dim(" 1. Connect Pick your LLM provider (or use your existing subscription)")
9785
+ );
9786
+ console.log(
9787
+ chalk14.dim(" 2. Build Scan project, generate configs, install pre-commit sync")
9788
+ );
9789
+ console.log(
9790
+ chalk14.dim(" 3. Review See exactly what changed \u2014 accept, refine, or decline\n")
9791
+ );
9767
9792
  } else {
9768
9793
  console.log(brand.bold("\n CALIBER") + chalk14.dim(" \u2014 setting up continuous sync\n"));
9769
9794
  }
9770
9795
  const platforms = detectPlatforms();
9771
9796
  if (!platforms.claude && !platforms.cursor && !platforms.codex && !platforms.opencode) {
9772
- console.log(chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex, OpenCode)."));
9773
- console.log(chalk14.yellow(" Caliber will still generate config files, but they won't be auto-installed.\n"));
9797
+ console.log(
9798
+ chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex, OpenCode).")
9799
+ );
9800
+ console.log(
9801
+ chalk14.yellow(
9802
+ " Caliber will still generate config files, but they won't be auto-installed.\n"
9803
+ )
9804
+ );
9774
9805
  }
9775
9806
  const report = options.debugReport ? new DebugReport() : null;
9776
9807
  console.log(title.bold(" Step 1/3 \u2014 Connect\n"));
@@ -9825,9 +9856,12 @@ async function initCommand(options) {
9825
9856
  console.log(chalk14.dim(modelLine + "\n"));
9826
9857
  if (report) {
9827
9858
  report.markStep("Provider connection");
9828
- report.addSection("LLM Provider", `- **Provider**: ${config.provider}
9859
+ report.addSection(
9860
+ "LLM Provider",
9861
+ `- **Provider**: ${config.provider}
9829
9862
  - **Model**: ${displayModel}
9830
- - **Fast model**: ${fastModel || "none"}`);
9863
+ - **Fast model**: ${fastModel || "none"}`
9864
+ );
9831
9865
  }
9832
9866
  await validateModel({ fast: true });
9833
9867
  let targetAgent;
@@ -9863,9 +9897,12 @@ async function initCommand(options) {
9863
9897
  console.log(` ${chalk14.green("\u2713")} Onboarding hook \u2014 nudges new team members to set up`);
9864
9898
  const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
9865
9899
  for (const agent of targetAgent) {
9866
- if (agent === "claude" && !fs34.existsSync(".claude")) fs34.mkdirSync(".claude", { recursive: true });
9867
- if (agent === "cursor" && !fs34.existsSync(".cursor")) fs34.mkdirSync(".cursor", { recursive: true });
9868
- if (agent === "codex" && !fs34.existsSync(".agents")) fs34.mkdirSync(".agents", { recursive: true });
9900
+ if (agent === "claude" && !fs34.existsSync(".claude"))
9901
+ fs34.mkdirSync(".claude", { recursive: true });
9902
+ if (agent === "cursor" && !fs34.existsSync(".cursor"))
9903
+ fs34.mkdirSync(".cursor", { recursive: true });
9904
+ if (agent === "codex" && !fs34.existsSync(".agents"))
9905
+ fs34.mkdirSync(".agents", { recursive: true });
9869
9906
  }
9870
9907
  const skillsWritten = ensureBuiltinSkills2();
9871
9908
  if (skillsWritten.length > 0) {
@@ -9883,11 +9920,16 @@ async function initCommand(options) {
9883
9920
  log(options.verbose, `Baseline score: ${baselineScore.score}/100`);
9884
9921
  if (report) {
9885
9922
  report.markStep("Baseline scoring");
9886
- report.addSection("Scoring: Baseline", `**Score**: ${baselineScore.score}/100
9923
+ report.addSection(
9924
+ "Scoring: Baseline",
9925
+ `**Score**: ${baselineScore.score}/100
9887
9926
 
9888
9927
  | Check | Passed | Points | Max |
9889
9928
  |-------|--------|--------|-----|
9890
- ` + baselineScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
9929
+ ` + baselineScore.checks.map(
9930
+ (c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`
9931
+ ).join("\n")
9932
+ );
9891
9933
  report.addSection("Generation: Target Agents", targetAgent.join(", "));
9892
9934
  }
9893
9935
  const hasExistingConfig = !!(baselineScore.checks.some((c) => c.id === "claude_md_exists" && c.passed) || baselineScore.checks.some((c) => c.id === "cursorrules_exists" && c.passed));
@@ -9906,8 +9948,19 @@ async function initCommand(options) {
9906
9948
  if (hasExistingConfig && baselineScore.score === 100 && !options.force) {
9907
9949
  skipGeneration = true;
9908
9950
  } else if (hasExistingConfig && !options.force && !options.autoApprove) {
9909
- console.log(chalk14.dim(` Config score: ${baselineScore.score}/100 \u2014 Caliber can improve this.
9951
+ const topGains = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0).sort((a, b) => b.maxPoints - b.earnedPoints - (a.maxPoints - a.earnedPoints)).slice(0, 3);
9952
+ console.log(chalk14.dim(` Config score: ${baselineScore.score}/100
9910
9953
  `));
9954
+ if (topGains.length > 0) {
9955
+ console.log(chalk14.dim(" Top improvements Caliber can make:"));
9956
+ for (const c of topGains) {
9957
+ const pts = c.maxPoints - c.earnedPoints;
9958
+ console.log(
9959
+ chalk14.dim(` +${pts} pts`) + chalk14.white(` ${c.name}`) + (c.suggestion ? chalk14.gray(` \u2014 ${c.suggestion}`) : "")
9960
+ );
9961
+ }
9962
+ console.log("");
9963
+ }
9911
9964
  const improveAnswer = await confirm2({ message: "Improve your existing configs?" });
9912
9965
  skipGeneration = !improveAnswer;
9913
9966
  }
@@ -9937,7 +9990,12 @@ async function initCommand(options) {
9937
9990
  if (targetAgent.includes("cursor")) {
9938
9991
  const rulesDir = path28.join(".cursor", "rules");
9939
9992
  if (!fs34.existsSync(rulesDir)) fs34.mkdirSync(rulesDir, { recursive: true });
9940
- for (const rule of [getCursorPreCommitRule2(), getCursorLearningsRule2(), getCursorSyncRule2(), getCursorSetupRule2()]) {
9993
+ for (const rule of [
9994
+ getCursorPreCommitRule2(),
9995
+ getCursorLearningsRule2(),
9996
+ getCursorSyncRule2(),
9997
+ getCursorSetupRule2()
9998
+ ]) {
9941
9999
  fs34.writeFileSync(path28.join(rulesDir, rule.filename), rule.content);
9942
10000
  }
9943
10001
  console.log(` ${chalk14.green("\u2713")} Cursor rules \u2014 added Caliber sync rules`);
@@ -9969,7 +10027,9 @@ async function initCommand(options) {
9969
10027
  trackInitCompleted("sync-only", baselineScore.score);
9970
10028
  console.log(chalk14.bold.green("\n Caliber sync is set up!\n"));
9971
10029
  console.log(chalk14.dim(" Your agent configs will sync automatically on every commit."));
9972
- console.log(chalk14.dim(" Run ") + title(`${bin} init --force`) + chalk14.dim(" anytime to generate or improve configs.\n"));
10030
+ console.log(
10031
+ chalk14.dim(" Run ") + title(`${bin} init --force`) + chalk14.dim(" anytime to generate or improve configs.\n")
10032
+ );
9973
10033
  return;
9974
10034
  }
9975
10035
  const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
@@ -9987,8 +10047,14 @@ async function initCommand(options) {
9987
10047
  const TASK_STACK = display.add("Detecting project stack", { pipelineLabel: "Scan" });
9988
10048
  const TASK_CONFIG = display.add("Generating configs", { depth: 1, pipelineLabel: "Generate" });
9989
10049
  const TASK_SKILLS_GEN = display.add("Generating skills", { depth: 2, pipelineLabel: "Skills" });
9990
- const TASK_SKILLS_SEARCH = display.add("Searching community skills", { depth: 1, pipelineLabel: "Search", pipelineRow: 1 });
9991
- const TASK_SCORE_REFINE = display.add("Validating & refining config", { pipelineLabel: "Validate" });
10050
+ const TASK_SKILLS_SEARCH = display.add("Searching community skills", {
10051
+ depth: 1,
10052
+ pipelineLabel: "Search",
10053
+ pipelineRow: 1
10054
+ });
10055
+ const TASK_SCORE_REFINE = display.add("Validating & refining config", {
10056
+ pipelineLabel: "Validate"
10057
+ });
9992
10058
  display.start();
9993
10059
  display.enableWaitingContent();
9994
10060
  try {
@@ -9998,21 +10064,39 @@ async function initCommand(options) {
9998
10064
  const stackSummary = stackParts.join(", ") || "no languages";
9999
10065
  const largeRepoNote = fingerprint.fileTree.length > 5e3 ? ` (${fingerprint.fileTree.length.toLocaleString()} files, smart sampling active)` : "";
10000
10066
  display.update(TASK_STACK, "done", stackSummary + largeRepoNote);
10001
- trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
10002
- log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
10067
+ trackInitProjectDiscovered(
10068
+ fingerprint.languages.length,
10069
+ fingerprint.frameworks.length,
10070
+ fingerprint.fileTree.length
10071
+ );
10072
+ log(
10073
+ options.verbose,
10074
+ `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`
10075
+ );
10003
10076
  const cliSources = options.source || [];
10004
10077
  const workspaces = getDetectedWorkspaces(process.cwd());
10005
10078
  const sources2 = resolveAllSources(process.cwd(), cliSources, workspaces);
10006
10079
  if (sources2.length > 0) {
10007
10080
  fingerprint.sources = sources2;
10008
- log(options.verbose, `Sources: ${sources2.length} resolved (${sources2.map((s) => s.name).join(", ")})`);
10081
+ log(
10082
+ options.verbose,
10083
+ `Sources: ${sources2.length} resolved (${sources2.map((s) => s.name).join(", ")})`
10084
+ );
10009
10085
  }
10010
10086
  if (report) {
10011
- report.addJson("Fingerprint: Git", { remote: fingerprint.gitRemoteUrl, packageName: fingerprint.packageName });
10087
+ report.addJson("Fingerprint: Git", {
10088
+ remote: fingerprint.gitRemoteUrl,
10089
+ packageName: fingerprint.packageName
10090
+ });
10012
10091
  report.addCodeBlock("Fingerprint: File Tree", fingerprint.fileTree.join("\n"));
10013
- report.addJson("Fingerprint: Detected Stack", { languages: fingerprint.languages, frameworks: fingerprint.frameworks, tools: fingerprint.tools });
10092
+ report.addJson("Fingerprint: Detected Stack", {
10093
+ languages: fingerprint.languages,
10094
+ frameworks: fingerprint.frameworks,
10095
+ tools: fingerprint.tools
10096
+ });
10014
10097
  report.addJson("Fingerprint: Existing Configs", fingerprint.existingConfigs);
10015
- if (fingerprint.codeAnalysis) report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
10098
+ if (fingerprint.codeAnalysis)
10099
+ report.addJson("Fingerprint: Code Analysis", fingerprint.codeAnalysis);
10016
10100
  }
10017
10101
  const isEmpty = fingerprint.fileTree.length < 3;
10018
10102
  if (isEmpty) {
@@ -10043,13 +10127,26 @@ async function initCommand(options) {
10043
10127
  let passingChecks;
10044
10128
  let currentScore;
10045
10129
  if (hasExistingConfig && localBaseline.score >= 95 && !options.force) {
10046
- const currentLlmFixable = localBaseline.checks.filter((c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id));
10047
- failingChecks = currentLlmFixable.map((c) => ({ name: c.name, suggestion: c.suggestion, fix: c.fix }));
10130
+ const currentLlmFixable = localBaseline.checks.filter(
10131
+ (c) => !c.passed && c.maxPoints > 0 && !NON_LLM_CHECKS.has(c.id)
10132
+ );
10133
+ failingChecks = currentLlmFixable.map((c) => ({
10134
+ name: c.name,
10135
+ suggestion: c.suggestion,
10136
+ fix: c.fix
10137
+ }));
10048
10138
  passingChecks = localBaseline.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
10049
10139
  currentScore = localBaseline.score;
10050
10140
  }
10051
10141
  if (report) {
10052
- const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
10142
+ const fullPrompt = buildGeneratePrompt(
10143
+ fingerprint,
10144
+ targetAgent,
10145
+ fingerprint.description,
10146
+ failingChecks,
10147
+ currentScore,
10148
+ passingChecks
10149
+ );
10053
10150
  report.addCodeBlock("Generation: Full LLM Prompt", fullPrompt);
10054
10151
  }
10055
10152
  const result = await generateSetup(
@@ -10169,7 +10266,10 @@ async function initCommand(options) {
10169
10266
  if (rawOutput) report.addCodeBlock("Generation: Raw LLM Response", rawOutput);
10170
10267
  report.addJson("Generation: Parsed Config", generatedSetup);
10171
10268
  }
10172
- log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
10269
+ log(
10270
+ options.verbose,
10271
+ `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`
10272
+ );
10173
10273
  console.log(title.bold(" Step 3/3 \u2014 Done\n"));
10174
10274
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
10175
10275
  const staged = stageFiles(setupFiles, process.cwd());
@@ -10181,10 +10281,18 @@ async function initCommand(options) {
10181
10281
  }
10182
10282
  console.log("");
10183
10283
  }
10184
- console.log(chalk14.dim(` ${chalk14.green(`${staged.newFiles} new`)} / ${chalk14.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`));
10284
+ console.log(
10285
+ chalk14.dim(
10286
+ ` ${chalk14.green(`${staged.newFiles} new`)} / ${chalk14.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}`
10287
+ )
10288
+ );
10185
10289
  if (skillSearchResult.results.length > 0) {
10186
- console.log(chalk14.dim(` ${chalk14.cyan(`${skillSearchResult.results.length}`)} community skills available to install
10187
- `));
10290
+ console.log(
10291
+ chalk14.dim(
10292
+ ` ${chalk14.cyan(`${skillSearchResult.results.length}`)} community skills available to install
10293
+ `
10294
+ )
10295
+ );
10188
10296
  } else {
10189
10297
  console.log("");
10190
10298
  }
@@ -10220,8 +10328,12 @@ async function initCommand(options) {
10220
10328
  }
10221
10329
  const updatedFiles = collectSetupFiles(generatedSetup, targetAgent);
10222
10330
  const restaged = stageFiles(updatedFiles, process.cwd());
10223
- console.log(chalk14.dim(` ${chalk14.green(`${restaged.newFiles} new`)} / ${chalk14.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
10224
- `));
10331
+ console.log(
10332
+ chalk14.dim(
10333
+ ` ${chalk14.green(`${restaged.newFiles} new`)} / ${chalk14.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
10334
+ `
10335
+ )
10336
+ );
10225
10337
  printSetupSummary(generatedSetup);
10226
10338
  const { openReview: openRev } = await Promise.resolve().then(() => (init_review(), review_exports));
10227
10339
  await openRev("terminal", restaged.stagedFiles);
@@ -10247,7 +10359,8 @@ async function initCommand(options) {
10247
10359
  const agentRefs = [];
10248
10360
  if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
10249
10361
  if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
10250
- if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
10362
+ if (agentRefs.length === 0)
10363
+ agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
10251
10364
  const stubContent = `# AGENTS.md
10252
10365
 
10253
10366
  This project uses AI coding agents configured by [Caliber](https://github.com/caliber-ai-org/ai-setup).
@@ -10294,24 +10407,39 @@ ${agentRefs.join(" ")}
10294
10407
  if (afterScore.score < baselineScore.score) {
10295
10408
  trackInitScoreRegression(baselineScore.score, afterScore.score);
10296
10409
  console.log("");
10297
- console.log(chalk14.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
10410
+ console.log(
10411
+ chalk14.yellow(
10412
+ ` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`
10413
+ )
10414
+ );
10298
10415
  try {
10299
10416
  const { restored, removed } = undoSetup();
10300
10417
  if (restored.length > 0 || removed.length > 0) {
10301
- console.log(chalk14.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
10418
+ console.log(
10419
+ chalk14.dim(
10420
+ ` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`
10421
+ )
10422
+ );
10302
10423
  }
10303
10424
  } catch {
10304
10425
  }
10305
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n"));
10426
+ console.log(
10427
+ chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} init --force`) + chalk14.dim(" to override.\n")
10428
+ );
10306
10429
  return;
10307
10430
  }
10308
10431
  if (report) {
10309
10432
  report.markStep("Post-write scoring");
10310
- report.addSection("Scoring: Post-Write", `**Score**: ${afterScore.score}/100 (delta: ${afterScore.score - baselineScore.score >= 0 ? "+" : ""}${afterScore.score - baselineScore.score})
10433
+ report.addSection(
10434
+ "Scoring: Post-Write",
10435
+ `**Score**: ${afterScore.score}/100 (delta: ${afterScore.score - baselineScore.score >= 0 ? "+" : ""}${afterScore.score - baselineScore.score})
10311
10436
 
10312
10437
  | Check | Passed | Points | Max |
10313
10438
  |-------|--------|--------|-----|
10314
- ` + afterScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
10439
+ ` + afterScore.checks.map(
10440
+ (c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`
10441
+ ).join("\n")
10442
+ );
10315
10443
  }
10316
10444
  recordScore(afterScore, "init");
10317
10445
  trackInitCompleted("full-generation", afterScore.score);
@@ -10319,7 +10447,10 @@ ${agentRefs.join(" ")}
10319
10447
  if (options.verbose) {
10320
10448
  log(options.verbose, `Final score: ${afterScore.score}/100`);
10321
10449
  for (const c of afterScore.checks.filter((ch) => !ch.passed)) {
10322
- log(options.verbose, ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
10450
+ log(
10451
+ options.verbose,
10452
+ ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`
10453
+ );
10323
10454
  }
10324
10455
  }
10325
10456
  let communitySkillsInstalled = 0;
@@ -10336,14 +10467,20 @@ ${agentRefs.join(" ")}
10336
10467
  const done = chalk14.green("\u2713");
10337
10468
  console.log(chalk14.bold.green("\n Caliber is set up!\n"));
10338
10469
  console.log(chalk14.bold(" What's configured:\n"));
10339
- console.log(` ${done} Continuous sync ${chalk14.dim("pre-commit hook keeps all agent configs in sync")}`);
10470
+ console.log(
10471
+ ` ${done} Continuous sync ${chalk14.dim("pre-commit hook keeps all agent configs in sync")}`
10472
+ );
10340
10473
  console.log(` ${done} Config generated ${chalk14.dim(`score: ${afterScore.score}/100`)}`);
10341
- console.log(` ${done} Agent skills ${chalk14.dim("/setup-caliber for new team members")}`);
10474
+ console.log(
10475
+ ` ${done} Agent skills ${chalk14.dim("/setup-caliber for new team members")}`
10476
+ );
10342
10477
  if (hasLearnableAgent) {
10343
10478
  console.log(` ${done} Session learning ${chalk14.dim("learns from your corrections")}`);
10344
10479
  }
10345
10480
  if (communitySkillsInstalled > 0) {
10346
- console.log(` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} installed for your stack`)}`);
10481
+ console.log(
10482
+ ` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} installed for your stack`)}`
10483
+ );
10347
10484
  }
10348
10485
  console.log(chalk14.bold("\n What happens next:\n"));
10349
10486
  console.log(chalk14.dim(" Every commit syncs your agent configs automatically."));
@@ -10360,8 +10497,10 @@ ${agentRefs.join(" ")}
10360
10497
  report.markStep("Finished");
10361
10498
  const reportPath = path28.join(process.cwd(), ".caliber", "debug-report.md");
10362
10499
  report.write(reportPath);
10363
- console.log(chalk14.dim(` Debug report written to ${path28.relative(process.cwd(), reportPath)}
10364
- `));
10500
+ console.log(
10501
+ chalk14.dim(` Debug report written to ${path28.relative(process.cwd(), reportPath)}
10502
+ `)
10503
+ );
10365
10504
  }
10366
10505
  }
10367
10506
 
@@ -10697,18 +10836,27 @@ async function scoreCommand(options) {
10697
10836
  const separator = chalk18.gray(" " + "\u2500".repeat(53));
10698
10837
  console.log(separator);
10699
10838
  const bin = resolveCaliber();
10700
- if (result.score < 40) {
10839
+ const failing = result.checks.filter((c) => !c.passed && c.maxPoints > 0).sort((a, b) => b.maxPoints - b.earnedPoints - (a.maxPoints - a.earnedPoints));
10840
+ if (result.score < 70 && failing.length > 0) {
10841
+ const topFix = failing[0];
10842
+ const pts = topFix.maxPoints - topFix.earnedPoints;
10701
10843
  console.log(
10702
- chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate a complete, optimized config.")
10844
+ chalk18.gray(" Biggest gain: ") + chalk18.yellow(`+${pts} pts`) + chalk18.gray(` from "${topFix.name}"`) + (topFix.suggestion ? chalk18.gray(` \u2014 ${topFix.suggestion}`) : "")
10703
10845
  );
10704
- } else if (result.score < 70) {
10705
10846
  console.log(
10706
- chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve your config.")
10847
+ chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to auto-fix these.")
10707
10848
  );
10708
- } else {
10849
+ } else if (failing.length > 0) {
10709
10850
  console.log(
10710
- chalk18.green(" Looking good!") + chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch.")
10851
+ chalk18.green(" Looking good!") + chalk18.gray(
10852
+ ` ${failing.length} check${failing.length === 1 ? "" : "s"} can still be improved.`
10853
+ )
10711
10854
  );
10855
+ console.log(
10856
+ chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve, or ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch.")
10857
+ );
10858
+ } else {
10859
+ console.log(chalk18.green(" Perfect score! Your agent configs are fully optimized."));
10712
10860
  }
10713
10861
  console.log("");
10714
10862
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.36.0",
3
+ "version": "1.36.1",
4
4
  "description": "AI context infrastructure for coding agents — keeps CLAUDE.md, Cursor rules, and skills in sync as your codebase evolves",
5
5
  "type": "module",
6
6
  "bin": {