@rely-ai/caliber 1.39.0 → 1.40.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 +13 -1
  2. package/dist/bin.js +35 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -51,7 +51,7 @@ Requires **Node.js >= 20**.
51
51
  npx @rely-ai/caliber bootstrap
52
52
  ```
53
53
 
54
- Then, in your next Claude Code or Cursor chat session, type:
54
+ Then, in your terminal (not the IDE chat), start a Claude Code or Cursor CLI session and type:
55
55
 
56
56
  > **/setup-caliber**
57
57
 
@@ -61,6 +61,18 @@ Your agent detects your stack, generates tailored configs for every platform you
61
61
 
62
62
  > **Your code stays on your machine.** Bootstrap is 100% local — no LLM calls, no code sent anywhere. Generation uses your own AI subscription or API key. Caliber never sees your code.
63
63
 
64
+ <details>
65
+ <summary><strong>Windows Users</strong></summary>
66
+
67
+ Caliber works on Windows with a few notes:
68
+
69
+ - **Run from your terminal** (PowerShell, CMD, or Git Bash) — not from inside an IDE chat window. Open a terminal, `cd` into your project folder, then run `npx @rely-ai/caliber bootstrap`.
70
+ - **Git Bash is recommended.** Caliber's pre-commit hooks and auto-sync scripts use shell syntax. Git for Windows includes Git Bash, which handles this automatically. If you only use PowerShell, hooks may be skipped silently.
71
+ - **Cursor Agent CLI:** If prompted to install it, download from [cursor.com/downloads](https://www.cursor.com/downloads) instead of the `curl | bash` command shown on macOS/Linux. Then run `agent login` in your terminal to authenticate.
72
+ - **One terminal at a time.** Avoid running Caliber from multiple terminals simultaneously — this can cause conflicting state and unexpected provider detection.
73
+
74
+ </details>
75
+
64
76
  ## Audits first, writes second
65
77
 
66
78
  Caliber never overwrites your existing configs without asking. The workflow mirrors code review:
package/dist/bin.js CHANGED
@@ -858,7 +858,7 @@ function openDiffsInEditor(editor, files) {
858
858
  for (const file of files) {
859
859
  try {
860
860
  const leftPath = file.originalPath ?? getEmptyFilePath(file.proposedPath);
861
- if (IS_WINDOWS3) {
861
+ if (IS_WINDOWS4) {
862
862
  const quote = (s) => `"${s}"`;
863
863
  spawn3([cmd, "--diff", quote(leftPath), quote(file.proposedPath)].join(" "), { shell: true, stdio: "ignore", detached: true }).unref();
864
864
  } else {
@@ -869,11 +869,11 @@ function openDiffsInEditor(editor, files) {
869
869
  }
870
870
  }
871
871
  }
872
- var IS_WINDOWS3, DIFF_TEMP_DIR;
872
+ var IS_WINDOWS4, DIFF_TEMP_DIR;
873
873
  var init_editor = __esm({
874
874
  "src/utils/editor.ts"() {
875
875
  "use strict";
876
- IS_WINDOWS3 = process.platform === "win32";
876
+ IS_WINDOWS4 = process.platform === "win32";
877
877
  DIFF_TEMP_DIR = path25.join(os6.tmpdir(), "caliber-diff");
878
878
  }
879
879
  });
@@ -3078,6 +3078,10 @@ async function llmCall(options) {
3078
3078
  await new Promise((r) => setTimeout(r, 1e3 * Math.pow(2, attempt - 1)));
3079
3079
  continue;
3080
3080
  }
3081
+ if (isRateLimitError(error.message) && attempt < MAX_RETRIES) {
3082
+ await new Promise((r) => setTimeout(r, 2e3 * Math.pow(2, attempt - 1)));
3083
+ continue;
3084
+ }
3081
3085
  if (isTransientError(error) && attempt < MAX_RETRIES) {
3082
3086
  await new Promise((r) => setTimeout(r, 1e3 * Math.pow(2, attempt - 1)));
3083
3087
  continue;
@@ -6274,6 +6278,7 @@ init_config();
6274
6278
  import chalk3 from "chalk";
6275
6279
  import select2 from "@inquirer/select";
6276
6280
  import confirm from "@inquirer/confirm";
6281
+ var IS_WINDOWS3 = process.platform === "win32";
6277
6282
  var PROVIDER_CHOICES = [
6278
6283
  { name: "Claude Code \u2014 use your existing subscription (no API key)", value: "claude-cli" },
6279
6284
  { name: "Cursor \u2014 use your existing subscription (no API key)", value: "cursor" },
@@ -6305,8 +6310,13 @@ async function runInteractiveProviderSetup(options) {
6305
6310
  case "cursor": {
6306
6311
  if (!isCursorAgentAvailable()) {
6307
6312
  console.log(chalk3.yellow("\n Cursor Agent CLI not found."));
6308
- console.log(chalk3.dim(" Install it: ") + chalk3.hex("#83D1EB")("curl https://cursor.com/install -fsS | bash"));
6309
- console.log(chalk3.dim(" Then run ") + chalk3.hex("#83D1EB")("agent login") + chalk3.dim(" to authenticate.\n"));
6313
+ if (IS_WINDOWS3) {
6314
+ console.log(chalk3.dim(" Install it from: ") + chalk3.hex("#83D1EB")("https://www.cursor.com/downloads"));
6315
+ console.log(chalk3.dim(" Then run ") + chalk3.hex("#83D1EB")("agent login") + chalk3.dim(" in PowerShell to authenticate.\n"));
6316
+ } else {
6317
+ console.log(chalk3.dim(" Install it: ") + chalk3.hex("#83D1EB")("curl https://cursor.com/install -fsS | bash"));
6318
+ console.log(chalk3.dim(" Then run ") + chalk3.hex("#83D1EB")("agent login") + chalk3.dim(" to authenticate.\n"));
6319
+ }
6310
6320
  const proceed = await confirm({ message: "Continue anyway?" });
6311
6321
  if (!proceed) throw new Error("__exit__");
6312
6322
  } else if (!isCursorLoggedIn()) {
@@ -6611,7 +6621,7 @@ function checkExistence(dir) {
6611
6621
  earnedPoints: Math.min(skillPoints, maxSkillPoints),
6612
6622
  passed: skillCount >= 1,
6613
6623
  detail: skillCount === 0 ? "No skills found" : `${skillCount} skill${skillCount === 1 ? "" : "s"} found`,
6614
- suggestion: skillCount === 0 ? "Add .claude/skills/ with project-specific workflows" : skillCount < 3 ? "Optimal is 2-3 focused skills" : void 0,
6624
+ suggestion: skillCount === 0 ? "Skills are reusable agent workflows (e.g., deploy, test, review). Add 2-3 for your most common tasks" : skillCount < 3 ? "Optimal is 2-3 focused skills" : void 0,
6615
6625
  fix: skillCount === 0 ? {
6616
6626
  action: "create_skills",
6617
6627
  data: { currentCount: 0 },
@@ -6628,7 +6638,7 @@ function checkExistence(dir) {
6628
6638
  earnedPoints: mdcCount >= 1 ? POINTS_CURSOR_MDC_RULES : 0,
6629
6639
  passed: mdcCount >= 1,
6630
6640
  detail: mdcCount === 0 ? "No .mdc rule files" : `${mdcCount} .mdc rule${mdcCount === 1 ? "" : "s"} found`,
6631
- suggestion: mdcCount === 0 ? "Add .cursor/rules/*.mdc with frontmatter for Cursor" : void 0,
6641
+ suggestion: mdcCount === 0 ? "Cursor .mdc rules use frontmatter to scope rules to specific files/paths. Add them for more targeted Cursor behavior" : void 0,
6632
6642
  fix: mdcCount === 0 ? {
6633
6643
  action: "create_mdc_rules",
6634
6644
  data: {},
@@ -6644,7 +6654,7 @@ function checkExistence(dir) {
6644
6654
  earnedPoints: mcp.count >= 1 ? POINTS_MCP_SERVERS : 0,
6645
6655
  passed: mcp.count >= 1,
6646
6656
  detail: mcp.count > 0 ? `${mcp.count} server${mcp.count === 1 ? "" : "s"} in ${mcp.sources.join(", ")}` : "No MCP servers configured",
6647
- suggestion: mcp.count === 0 ? "Configure MCP servers in .mcp.json for external service access" : void 0,
6657
+ suggestion: mcp.count === 0 ? "MCP servers connect your agent to external tools (databases, Slack, Linear, etc). Add if your team uses external services" : void 0,
6648
6658
  fix: mcp.count === 0 ? {
6649
6659
  action: "configure_mcp",
6650
6660
  data: {},
@@ -6713,7 +6723,7 @@ function checkQuality(dir) {
6713
6723
  earnedPoints: tokenPoints,
6714
6724
  passed: tokenPoints >= 4,
6715
6725
  detail: totalContent.length === 0 ? "No config files to measure" : `~${totalTokens} tokens total across all config files`,
6716
- suggestion: tokenPoints < 4 && totalContent.length > 0 ? `Total config is ~${totalTokens} tokens \u2014 reduce to under 5000 for better agent performance` : void 0,
6726
+ suggestion: tokenPoints < 4 && totalContent.length > 0 ? `Config is ~${totalTokens} tokens. Agents work best under ~5000 tokens (~4 pages of text) \u2014 trim verbose sections` : void 0,
6717
6727
  fix: tokenPoints < 4 && totalContent.length > 0 ? {
6718
6728
  action: "reduce_size",
6719
6729
  data: { currentTokens: totalTokens, targetTokens: 5e3 },
@@ -7157,7 +7167,7 @@ function checkFreshness(dir) {
7157
7167
  earnedPoints: hasPermissions ? POINTS_PERMISSIONS : 0,
7158
7168
  passed: hasPermissions,
7159
7169
  detail: permissionDetail,
7160
- suggestion: hasPermissions ? void 0 : "Add permissions.allow to .claude/settings.json for safer agent execution",
7170
+ suggestion: hasPermissions ? void 0 : "Permissions control which shell commands the agent can run without asking. Adds a safety layer for your team",
7161
7171
  fix: hasPermissions ? void 0 : {
7162
7172
  action: "add_permissions",
7163
7173
  data: {},
@@ -7222,7 +7232,7 @@ function checkBonus(dir) {
7222
7232
  earnedPoints: hasHooks ? POINTS_HOOKS : 0,
7223
7233
  passed: hasHooks,
7224
7234
  detail: hasHooks ? hookSources.join(", ") : "No hooks configured",
7225
- suggestion: hasHooks ? void 0 : `Run \`${resolveCaliber()} init\` to add pre-commit instructions`,
7235
+ suggestion: hasHooks ? void 0 : `Hooks auto-sync your agent config on every commit so it stays fresh. Run \`${resolveCaliber()} init\` to set up`,
7226
7236
  fix: hasHooks ? void 0 : {
7227
7237
  action: "install_hooks",
7228
7238
  data: {},
@@ -7238,7 +7248,7 @@ function checkBonus(dir) {
7238
7248
  earnedPoints: agentsMdExists ? POINTS_AGENTS_MD : 0,
7239
7249
  passed: agentsMdExists,
7240
7250
  detail: agentsMdExists ? "Found at project root" : "Not found",
7241
- suggestion: agentsMdExists ? void 0 : "Add AGENTS.md \u2014 the emerging cross-agent standard",
7251
+ suggestion: agentsMdExists ? void 0 : "AGENTS.md provides project context to Codex, Copilot, and other agents. Works alongside CLAUDE.md",
7242
7252
  fix: agentsMdExists ? void 0 : {
7243
7253
  action: "create_file",
7244
7254
  data: { file: "AGENTS.md" },
@@ -7274,7 +7284,7 @@ function checkBonus(dir) {
7274
7284
  earnedPoints: allOpenSkills ? POINTS_OPEN_SKILLS_FORMAT : 0,
7275
7285
  passed: allOpenSkills || totalSkillFiles === 0,
7276
7286
  detail: totalSkillFiles === 0 ? "No skills to check" : allOpenSkills ? `All ${totalSkillFiles} skill${totalSkillFiles === 1 ? "" : "s"} use SKILL.md with frontmatter` : `${openSkillsCount}/${totalSkillFiles} use OpenSkills format`,
7277
- suggestion: totalSkillFiles > 0 && !allOpenSkills ? "Migrate skills to .claude/skills/{name}/SKILL.md with YAML frontmatter" : void 0,
7287
+ suggestion: totalSkillFiles > 0 && !allOpenSkills ? "OpenSkills format (SKILL.md with YAML header) makes skills portable across agents. Migrate for cross-tool compatibility" : void 0,
7278
7288
  fix: totalSkillFiles > 0 && !allOpenSkills ? {
7279
7289
  action: "migrate_skills",
7280
7290
  data: { openSkills: openSkillsCount, total: totalSkillFiles },
@@ -7291,7 +7301,7 @@ function checkBonus(dir) {
7291
7301
  earnedPoints: hasLearned ? POINTS_LEARNED_CONTENT : 0,
7292
7302
  passed: hasLearned,
7293
7303
  detail: hasLearned ? "Session learnings found in CALIBER_LEARNINGS.md" : "No learned content",
7294
- suggestion: hasLearned ? void 0 : `Install learning hooks: \`${resolveCaliber()} learn install\``
7304
+ suggestion: hasLearned ? void 0 : `Session learnings capture patterns from your coding sessions so the agent improves over time. Run \`${resolveCaliber()} learn install\``
7295
7305
  });
7296
7306
  return checks;
7297
7307
  }
@@ -7532,7 +7542,7 @@ function displayScore(result) {
7532
7542
  formatTopImprovements(result.checks);
7533
7543
  }
7534
7544
  function formatTopImprovements(checks) {
7535
- const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({ name: c.name, potential: c.maxPoints - c.earnedPoints })).sort((a, b) => b.potential - a.potential).slice(0, 5);
7545
+ const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({ name: c.name, potential: c.maxPoints - c.earnedPoints, suggestion: c.suggestion })).sort((a, b) => b.potential - a.potential).slice(0, 5);
7536
7546
  if (improvable.length === 0) return;
7537
7547
  console.log(chalk4.gray(" \u2500 TOP IMPROVEMENTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
7538
7548
  console.log("");
@@ -7542,6 +7552,9 @@ function formatTopImprovements(checks) {
7542
7552
  const label = chalk4.white(item.name.padEnd(42));
7543
7553
  const pts = chalk4.yellow(`+${item.potential} pts`);
7544
7554
  console.log(` ${num} ${label}${pts}`);
7555
+ if (item.suggestion) {
7556
+ console.log(chalk4.gray(` ${item.suggestion}`));
7557
+ }
7545
7558
  }
7546
7559
  console.log("");
7547
7560
  }
@@ -10097,6 +10110,7 @@ function getScoreTrend(entries) {
10097
10110
  }
10098
10111
 
10099
10112
  // src/commands/init.ts
10113
+ var IS_WINDOWS5 = process.platform === "win32";
10100
10114
  function log(verbose, ...args) {
10101
10115
  if (verbose) console.log(chalk14.dim(` [verbose] ${args.map(String).join(" ")}`));
10102
10116
  }
@@ -10232,6 +10246,10 @@ async function initCommand(options) {
10232
10246
  console.log(` ${chalk14.green("\u2713")} Onboarding hook \u2014 nudges new team members to set up`);
10233
10247
  installSessionStartHook();
10234
10248
  console.log(` ${chalk14.green("\u2713")} Freshness hook \u2014 warns when configs are stale`);
10249
+ if (IS_WINDOWS5) {
10250
+ console.log(chalk14.yellow("\n Note: hooks use shell syntax and require Git Bash (included with Git for Windows)."));
10251
+ console.log(chalk14.dim(" If hooks don't run, ensure Git for Windows is installed and git is using its bundled sh."));
10252
+ }
10235
10253
  const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
10236
10254
  for (const agent of targetAgent) {
10237
10255
  if (agent === "claude" && !fs34.existsSync(".claude"))
@@ -11209,12 +11227,12 @@ async function scoreCommand(options) {
11209
11227
  chalk18.gray(" Biggest gain: ") + chalk18.yellow(`+${pts} pts`) + chalk18.gray(` from "${topFix.name}"`) + (topFix.suggestion ? chalk18.gray(` \u2014 ${topFix.suggestion}`) : "")
11210
11228
  );
11211
11229
  console.log(
11212
- chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to auto-fix these.")
11230
+ chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate or update your agent config files.")
11213
11231
  );
11214
11232
  } else if (failing.length > 0) {
11215
11233
  console.log(
11216
11234
  chalk18.green(" Looking good!") + chalk18.gray(
11217
- ` ${failing.length} check${failing.length === 1 ? "" : "s"} can still be improved.`
11235
+ ` ${failing.length} optional improvement${failing.length === 1 ? "" : "s"} available.`
11218
11236
  )
11219
11237
  );
11220
11238
  console.log(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.39.0",
3
+ "version": "1.40.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": {