@rely-ai/caliber 1.37.0-dev.1774891449 → 1.37.0-dev.1774893636

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 +11 -6
  2. package/dist/bin.js +51 -31
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Caliber
2
2
 
3
- **Hand-written `CLAUDE.md` files go stale the moment you refactor.** Your AI agent hallucinates paths that no longer exist, misses new dependencies, and gives advice based on yesterday's architecture. Caliber generates and maintains your AI context files (`CLAUDE.md`, `.cursor/rules/`, `AGENTS.md`) so they stay accurate as your code evolves — and keeps every agent on your team in sync, whether they use Claude Code, Cursor, Codex, or OpenCode.
3
+ **Hand-written `CLAUDE.md` files go stale the moment you refactor.** Your AI agent hallucinates paths that no longer exist, misses new dependencies, and gives advice based on yesterday's architecture. Caliber generates and maintains your AI context files (`CLAUDE.md`, `.cursor/rules/`, `AGENTS.md`, `copilot-instructions.md`) so they stay accurate as your code evolves — and keeps every agent on your team in sync, whether they use Claude Code, Cursor, Codex, OpenCode, or GitHub Copilot.
4
4
 
5
5
  <p align="center">
6
6
  <img src="assets/demo-header.gif" alt="Caliber product demo" width="900">
@@ -15,6 +15,7 @@
15
15
  <img src="https://img.shields.io/badge/Cursor-supported-blue" alt="Cursor">
16
16
  <img src="https://img.shields.io/badge/Codex-supported-blue" alt="Codex">
17
17
  <img src="https://img.shields.io/badge/OpenCode-supported-blue" alt="OpenCode">
18
+ <img src="https://img.shields.io/badge/GitHub_Copilot-supported-blue" alt="GitHub Copilot">
18
19
  </p>
19
20
 
20
21
  ## Before / After
@@ -119,6 +120,9 @@ Pre-commit hooks run the refresh loop automatically. New team members get nudged
119
120
  - `AGENTS.md` — Project context (shared with Codex when both are targeted)
120
121
  - `.opencode/skills/*/SKILL.md` — Skills for OpenCode
121
122
 
123
+ **GitHub Copilot**
124
+ - `.github/copilot-instructions.md` — Project context for Copilot
125
+
122
126
  ## Key Features
123
127
 
124
128
  <details>
@@ -136,9 +140,10 @@ TypeScript, Python, Go, Rust, Java, Ruby, Terraform, and more. Language and fram
136
140
  caliber init --agent claude # Claude Code only
137
141
  caliber init --agent cursor # Cursor only
138
142
  caliber init --agent codex # Codex only
139
- caliber init --agent opencode # OpenCode only
140
- caliber init --agent all # All platforms
141
- caliber init --agent claude,cursor # Comma-separated
143
+ caliber init --agent opencode # OpenCode only
144
+ caliber init --agent github-copilot # GitHub Copilot only
145
+ caliber init --agent all # All platforms
146
+ caliber init --agent claude,cursor # Comma-separated
142
147
  ```
143
148
 
144
149
  </details>
@@ -302,9 +307,9 @@ No API key? No problem. Caliber works with your existing AI tool subscription:
302
307
  | **Claude Code** (your seat) | `caliber config` → Claude Code | Inherited from Claude Code |
303
308
  | **Cursor** (your seat) | `caliber config` → Cursor | Inherited from Cursor |
304
309
  | **Anthropic** | `export ANTHROPIC_API_KEY=sk-ant-...` | `claude-sonnet-4-6` |
305
- | **OpenAI** | `export OPENAI_API_KEY=sk-...` | `gpt-4.1` |
310
+ | **OpenAI** | `export OPENAI_API_KEY=sk-...` | `gpt-5.4-mini` |
306
311
  | **Vertex AI** | `export VERTEX_PROJECT_ID=my-project` | `claude-sonnet-4-6` |
307
- | **Custom endpoint** | `OPENAI_API_KEY` + `OPENAI_BASE_URL` | `gpt-4.1` |
312
+ | **Custom endpoint** | `OPENAI_API_KEY` + `OPENAI_BASE_URL` | `gpt-5.4-mini` |
308
313
 
309
314
  Override the model for any provider: `export CALIBER_MODEL=<model-name>` or use `caliber config`.
310
315
 
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("");
@@ -6294,14 +6298,17 @@ function checkExistence(dir) {
6294
6298
  const opencodeSkills = countFiles(join3(dir, ".opencode", "skills"), /SKILL\.md$/);
6295
6299
  const skillCount = claudeSkills.length + codexSkills.length + opencodeSkills.length;
6296
6300
  const skillBase = skillCount >= 1 ? POINTS_SKILLS_EXIST : 0;
6297
- const skillBonus = Math.min((skillCount - 1) * POINTS_SKILLS_BONUS_PER_EXTRA, POINTS_SKILLS_BONUS_CAP);
6301
+ const skillBonus = Math.min(
6302
+ (skillCount - 1) * POINTS_SKILLS_BONUS_PER_EXTRA,
6303
+ POINTS_SKILLS_BONUS_CAP
6304
+ );
6298
6305
  const skillPoints = skillCount >= 1 ? skillBase + Math.max(0, skillBonus) : 0;
6299
6306
  const maxSkillPoints = POINTS_SKILLS_EXIST + POINTS_SKILLS_BONUS_CAP;
6300
6307
  checks.push({
6301
6308
  id: "skills_exist",
6302
6309
  name: "Skills configured",
6303
6310
  category: "existence",
6304
- maxPoints: maxSkillPoints,
6311
+ maxPoints: skillCount >= 1 ? maxSkillPoints : 0,
6305
6312
  earnedPoints: Math.min(skillPoints, maxSkillPoints),
6306
6313
  passed: skillCount >= 1,
6307
6314
  detail: skillCount === 0 ? "No skills found" : `${skillCount} skill${skillCount === 1 ? "" : "s"} found`,
@@ -6334,7 +6341,7 @@ function checkExistence(dir) {
6334
6341
  id: "mcp_servers",
6335
6342
  name: "MCP servers configured",
6336
6343
  category: "existence",
6337
- maxPoints: POINTS_MCP_SERVERS,
6344
+ maxPoints: mcp.count >= 1 ? POINTS_MCP_SERVERS : 0,
6338
6345
  earnedPoints: mcp.count >= 1 ? POINTS_MCP_SERVERS : 0,
6339
6346
  passed: mcp.count >= 1,
6340
6347
  detail: mcp.count > 0 ? `${mcp.count} server${mcp.count === 1 ? "" : "s"} in ${mcp.sources.join(", ")}` : "No MCP servers configured",
@@ -6869,7 +6876,11 @@ init_resolve_caliber();
6869
6876
  init_pre_commit_block();
6870
6877
  function hasPreCommitHook(dir) {
6871
6878
  try {
6872
- const gitDir = execSync12("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
6879
+ const gitDir = execSync12("git rev-parse --git-dir", {
6880
+ cwd: dir,
6881
+ encoding: "utf-8",
6882
+ stdio: ["pipe", "pipe", "pipe"]
6883
+ }).trim();
6873
6884
  const hookPath = join7(gitDir, "hooks", "pre-commit");
6874
6885
  const content = readFileOrNull(hookPath);
6875
6886
  return content ? content.includes("caliber") : false;
@@ -6960,9 +6971,9 @@ function checkBonus(dir) {
6960
6971
  id: "open_skills_format",
6961
6972
  name: "Skills use OpenSkills format",
6962
6973
  category: "bonus",
6963
- maxPoints: POINTS_OPEN_SKILLS_FORMAT,
6974
+ maxPoints: totalSkillFiles > 0 ? POINTS_OPEN_SKILLS_FORMAT : 0,
6964
6975
  earnedPoints: allOpenSkills ? POINTS_OPEN_SKILLS_FORMAT : 0,
6965
- passed: allOpenSkills,
6976
+ passed: allOpenSkills || totalSkillFiles === 0,
6966
6977
  detail: totalSkillFiles === 0 ? "No skills to check" : allOpenSkills ? `All ${totalSkillFiles} skill${totalSkillFiles === 1 ? "" : "s"} use SKILL.md with frontmatter` : `${openSkillsCount}/${totalSkillFiles} use OpenSkills format`,
6967
6978
  suggestion: totalSkillFiles > 0 && !allOpenSkills ? "Migrate skills to .claude/skills/{name}/SKILL.md with YAML frontmatter" : void 0,
6968
6979
  fix: totalSkillFiles > 0 && !allOpenSkills ? {
@@ -10843,18 +10854,27 @@ async function scoreCommand(options) {
10843
10854
  const separator = chalk18.gray(" " + "\u2500".repeat(53));
10844
10855
  console.log(separator);
10845
10856
  const bin = resolveCaliber();
10846
- if (result.score < 40) {
10857
+ const failing = result.checks.filter((c) => !c.passed && c.maxPoints > 0).sort((a, b) => b.maxPoints - b.earnedPoints - (a.maxPoints - a.earnedPoints));
10858
+ if (result.score < 70 && failing.length > 0) {
10859
+ const topFix = failing[0];
10860
+ const pts = topFix.maxPoints - topFix.earnedPoints;
10847
10861
  console.log(
10848
- chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to generate a complete, optimized config.")
10862
+ chalk18.gray(" Biggest gain: ") + chalk18.yellow(`+${pts} pts`) + chalk18.gray(` from "${topFix.name}"`) + (topFix.suggestion ? chalk18.gray(` \u2014 ${topFix.suggestion}`) : "")
10849
10863
  );
10850
- } else if (result.score < 70) {
10851
10864
  console.log(
10852
- chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve your config.")
10865
+ chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to auto-fix these.")
10853
10866
  );
10854
- } else {
10867
+ } else if (failing.length > 0) {
10855
10868
  console.log(
10856
- chalk18.green(" Looking good!") + chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch.")
10869
+ chalk18.green(" Looking good!") + chalk18.gray(
10870
+ ` ${failing.length} check${failing.length === 1 ? "" : "s"} can still be improved.`
10871
+ )
10857
10872
  );
10873
+ console.log(
10874
+ chalk18.gray(" Run ") + chalk18.hex("#83D1EB")(`${bin} init`) + chalk18.gray(" to improve, or ") + chalk18.hex("#83D1EB")(`${bin} regenerate`) + chalk18.gray(" to rebuild from scratch.")
10875
+ );
10876
+ } else {
10877
+ console.log(chalk18.green(" Perfect score! Your agent configs are fully optimized."));
10858
10878
  }
10859
10879
  console.log("");
10860
10880
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.37.0-dev.1774891449",
3
+ "version": "1.37.0-dev.1774893636",
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": {