@rely-ai/caliber 1.42.0 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.js +102 -12
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -262,6 +262,7 @@ var pre_commit_block_exports = {};
262
262
  __export(pre_commit_block_exports, {
263
263
  appendLearningsBlock: () => appendLearningsBlock,
264
264
  appendManagedBlocks: () => appendManagedBlocks,
265
+ appendModelBlock: () => appendModelBlock,
265
266
  appendPreCommitBlock: () => appendPreCommitBlock,
266
267
  appendSyncBlock: () => appendSyncBlock,
267
268
  getCursorLearningsRule: () => getCursorLearningsRule,
@@ -269,6 +270,7 @@ __export(pre_commit_block_exports, {
269
270
  getCursorSetupRule: () => getCursorSetupRule,
270
271
  getCursorSyncRule: () => getCursorSyncRule,
271
272
  hasLearningsBlock: () => hasLearningsBlock,
273
+ hasModelBlock: () => hasModelBlock,
272
274
  hasPreCommitBlock: () => hasPreCommitBlock,
273
275
  hasSyncBlock: () => hasSyncBlock,
274
276
  stripManagedBlocks: () => stripManagedBlocks
@@ -345,6 +347,25 @@ function appendLearningsBlock(content) {
345
347
  function getCursorLearningsRule() {
346
348
  return { filename: CURSOR_LEARNINGS_FILENAME, content: CURSOR_LEARNINGS_CONTENT };
347
349
  }
350
+ function buildManagedModelBlock() {
351
+ const m = DEFAULT_MODELS.anthropic;
352
+ return `${MODEL_BLOCK_START}
353
+ ## Model Configuration
354
+
355
+ Recommended default: \`${m}\` with high effort (stronger reasoning; higher cost and latency than smaller models).
356
+ Smaller/faster models trade quality for speed and cost \u2014 pick what fits the task.
357
+ Pin your choice (\`/model\` in Claude Code, or \`CALIBER_MODEL\` when using Caliber with an API provider) so upstream default changes do not silently change behavior.
358
+
359
+ ${MODEL_BLOCK_END}`;
360
+ }
361
+ function hasModelBlock(content) {
362
+ return content.includes(MODEL_BLOCK_START);
363
+ }
364
+ function appendModelBlock(content) {
365
+ if (hasModelBlock(content)) return content;
366
+ const trimmed = content.trimEnd();
367
+ return trimmed + "\n\n" + buildManagedModelBlock() + "\n";
368
+ }
348
369
  function getSyncSetupInstruction(platform) {
349
370
  switch (platform) {
350
371
  case "claude":
@@ -379,7 +400,10 @@ function appendSyncBlock(content, platform = "claude") {
379
400
  return trimmed + "\n\n" + getSyncBlock(platform) + "\n";
380
401
  }
381
402
  function appendManagedBlocks(content, platform = "claude") {
382
- return appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(content, platform)), platform);
403
+ return appendSyncBlock(
404
+ appendModelBlock(appendLearningsBlock(appendPreCommitBlock(content, platform))),
405
+ platform
406
+ );
383
407
  }
384
408
  function getCursorSyncContent() {
385
409
  const bin = resolveCaliber();
@@ -407,7 +431,7 @@ grep -q "caliber" .git/hooks/pre-commit 2>/dev/null && echo "SYNCED" || echo "NO
407
431
  \`\`\`
408
432
 
409
433
  If SYNCED: proceed normally.
410
- If NOT_SYNCED: Tell the user: "This project uses Caliber to keep agent configs in sync. It's not set up on your machine yet \u2014 want me to set it up? (~30 seconds)". If they agree, read \`.cursor/skills/setup-caliber/SKILL.md\` and follow its instructions.
434
+ If NOT_SYNCED: Tell the user: "This project uses Caliber to keep agent configs in sync \u2014 it is not set up yet. Want me to run /setup-caliber? (~30 seconds)". If they agree, read \`.cursor/skills/setup-caliber/SKILL.md\` and follow its instructions.
411
435
  `;
412
436
  }
413
437
  function getCursorSetupRule() {
@@ -424,11 +448,12 @@ function stripManagedBlocks(content) {
424
448
  }
425
449
  return result.replace(/\n{3,}/g, "\n\n").trim() + "\n";
426
450
  }
427
- var BLOCK_START, BLOCK_END, MANAGED_DOC_PATHS, CURSOR_RULE_FILENAME, LEARNINGS_BLOCK_START, LEARNINGS_BLOCK_END, LEARNINGS_BLOCK, CURSOR_LEARNINGS_FILENAME, CURSOR_LEARNINGS_CONTENT, SYNC_BLOCK_START, SYNC_BLOCK_END, CURSOR_SYNC_FILENAME, CURSOR_SETUP_FILENAME, MANAGED_BLOCK_PAIRS;
451
+ var BLOCK_START, BLOCK_END, MANAGED_DOC_PATHS, CURSOR_RULE_FILENAME, LEARNINGS_BLOCK_START, LEARNINGS_BLOCK_END, LEARNINGS_BLOCK, CURSOR_LEARNINGS_FILENAME, CURSOR_LEARNINGS_CONTENT, MODEL_BLOCK_START, MODEL_BLOCK_END, SYNC_BLOCK_START, SYNC_BLOCK_END, CURSOR_SYNC_FILENAME, CURSOR_SETUP_FILENAME, MANAGED_BLOCK_PAIRS;
428
452
  var init_pre_commit_block = __esm({
429
453
  "src/writers/pre-commit-block.ts"() {
430
454
  "use strict";
431
455
  init_resolve_caliber();
456
+ init_config();
432
457
  BLOCK_START = "<!-- caliber:managed:pre-commit -->";
433
458
  BLOCK_END = "<!-- /caliber:managed:pre-commit -->";
434
459
  MANAGED_DOC_PATHS = "CLAUDE.md .claude/ .cursor/ .cursorrules .github/copilot-instructions.md .github/instructions/ AGENTS.md CALIBER_LEARNINGS.md .agents/ .opencode/";
@@ -449,6 +474,8 @@ alwaysApply: true
449
474
  Read \`CALIBER_LEARNINGS.md\` for patterns and anti-patterns learned from previous sessions.
450
475
  These are auto-extracted from real tool usage \u2014 treat them as project-specific rules.
451
476
  `;
477
+ MODEL_BLOCK_START = "<!-- caliber:managed:model-config -->";
478
+ MODEL_BLOCK_END = "<!-- /caliber:managed:model-config -->";
452
479
  SYNC_BLOCK_START = "<!-- caliber:managed:sync -->";
453
480
  SYNC_BLOCK_END = "<!-- /caliber:managed:sync -->";
454
481
  CURSOR_SYNC_FILENAME = "caliber-sync.mdc";
@@ -456,6 +483,7 @@ These are auto-extracted from real tool usage \u2014 treat them as project-speci
456
483
  MANAGED_BLOCK_PAIRS = [
457
484
  [BLOCK_START, BLOCK_END],
458
485
  [LEARNINGS_BLOCK_START, LEARNINGS_BLOCK_END],
486
+ [MODEL_BLOCK_START, MODEL_BLOCK_END],
459
487
  [SYNC_BLOCK_START, SYNC_BLOCK_END]
460
488
  ];
461
489
  }
@@ -5504,6 +5532,13 @@ var LIMITS = {
5504
5532
  SKILL_CHARS: 3e3,
5505
5533
  RULES_MAX: 10
5506
5534
  };
5535
+ var BUILD_GENERATE_PROMPT_MAX_TOKENS = 12e4;
5536
+ var PROJECT_FILES_HEADER_RESERVE_TOKENS = 160;
5537
+ function maxCharsForCodeFileContent(runningJoinedLen, pathLine, budgetTokens) {
5538
+ const maxTotalChars = budgetTokens * 4;
5539
+ const overhead = runningJoinedLen + 1 + pathLine.length + 1;
5540
+ return Math.max(0, maxTotalChars - overhead);
5541
+ }
5507
5542
  function truncate(text, maxChars) {
5508
5543
  if (text.length <= maxChars) return text;
5509
5544
  return text.slice(0, maxChars) + `
@@ -5709,9 +5744,12 @@ User instructions: ${prompt}`);
5709
5744
  if (fingerprint.codeAnalysis) {
5710
5745
  const ca = fingerprint.codeAnalysis;
5711
5746
  const basePrompt = parts.join("\n");
5712
- const maxPromptTokens = getMaxPromptTokens();
5747
+ const effectiveMaxTokens = Math.min(getMaxPromptTokens(), BUILD_GENERATE_PROMPT_MAX_TOKENS);
5713
5748
  const baseTokens = estimateTokens(basePrompt);
5714
- const tokenBudgetForCode = Math.max(0, maxPromptTokens - baseTokens);
5749
+ const tokenBudgetForCode = Math.max(
5750
+ 0,
5751
+ effectiveMaxTokens - baseTokens - PROJECT_FILES_HEADER_RESERVE_TOKENS
5752
+ );
5715
5753
  const codeLines = [];
5716
5754
  let codeChars = 0;
5717
5755
  const introLine = "Study these files to extract patterns for skills. Use the exact code patterns you see here.\n";
@@ -5720,13 +5758,24 @@ User instructions: ${prompt}`);
5720
5758
  const sortedFiles = [...ca.files].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
5721
5759
  let includedFiles = 0;
5722
5760
  for (const f of sortedFiles) {
5723
- const entry = `[${f.path}]
5724
- ${f.content}
5761
+ const pathLine = `[${f.path}]
5762
+ `;
5763
+ const maxContent = maxCharsForCodeFileContent(runningCodeLen, pathLine, tokenBudgetForCode);
5764
+ if (maxContent < 1) {
5765
+ if (includedFiles > 0) break;
5766
+ continue;
5767
+ }
5768
+ const content = f.content.slice(0, Math.min(f.content.length, maxContent));
5769
+ const entry = `${pathLine}${content}
5725
5770
  `;
5726
5771
  const projectedLen = runningCodeLen + 1 + entry.length;
5727
- if (Math.ceil(projectedLen / 4) > tokenBudgetForCode && includedFiles > 0) break;
5772
+ const projectedTokens = Math.ceil(projectedLen / 4);
5773
+ if (projectedTokens > tokenBudgetForCode) {
5774
+ if (includedFiles > 0) break;
5775
+ continue;
5776
+ }
5728
5777
  codeLines.push(entry);
5729
- codeChars += f.content.length;
5778
+ codeChars += content.length;
5730
5779
  runningCodeLen = projectedLen;
5731
5780
  includedFiles++;
5732
5781
  }
@@ -5764,7 +5813,7 @@ function writeClaudeConfig(config) {
5764
5813
  const written = [];
5765
5814
  fs13.writeFileSync(
5766
5815
  "CLAUDE.md",
5767
- appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.claudeMd)))
5816
+ appendManagedBlocks(config.claudeMd)
5768
5817
  );
5769
5818
  written.push("CLAUDE.md");
5770
5819
  if (config.rules?.length) {
@@ -5874,7 +5923,7 @@ function writeCodexConfig(config) {
5874
5923
  const written = [];
5875
5924
  fs15.writeFileSync(
5876
5925
  "AGENTS.md",
5877
- appendLearningsBlock(appendPreCommitBlock(config.agentsMd, "codex"))
5926
+ appendManagedBlocks(config.agentsMd, "codex")
5878
5927
  );
5879
5928
  written.push("AGENTS.md");
5880
5929
  if (config.skills?.length) {
@@ -5906,7 +5955,7 @@ function writeGithubCopilotConfig(config) {
5906
5955
  fs16.mkdirSync(".github", { recursive: true });
5907
5956
  fs16.writeFileSync(
5908
5957
  path15.join(".github", "copilot-instructions.md"),
5909
- appendSyncBlock(appendLearningsBlock(appendPreCommitBlock(config.instructions, "copilot")))
5958
+ appendManagedBlocks(config.instructions, "copilot")
5910
5959
  );
5911
5960
  written.push(".github/copilot-instructions.md");
5912
5961
  }
@@ -6649,6 +6698,7 @@ var POINTS_FRESHNESS = 4;
6649
6698
  var POINTS_NO_SECRETS = 4;
6650
6699
  var POINTS_PERMISSIONS = 2;
6651
6700
  var POINTS_HOOKS = 2;
6701
+ var POINTS_MODEL_PINNED = 2;
6652
6702
  var POINTS_AGENTS_MD = 1;
6653
6703
  var POINTS_OPEN_SKILLS_FORMAT = 2;
6654
6704
  var POINTS_LEARNED_CONTENT = 2;
@@ -7433,6 +7483,19 @@ import { execSync as execSync12 } from "child_process";
7433
7483
  import { join as join7 } from "path";
7434
7484
  init_resolve_caliber();
7435
7485
  init_pre_commit_block();
7486
+
7487
+ // src/scoring/model-pinning.ts
7488
+ function configContentSuggestsPinnedModel(lower) {
7489
+ if (/\bcaliber_model\b/.test(lower) || /\bcaliber_fast_model\b/.test(lower)) return true;
7490
+ if (/(?:^|[\s`'"\n])\/model(?:[\s`'"\n]|$)/.test(lower)) return true;
7491
+ if (/claude-(sonnet|opus|haiku)([-.@\d]|\b)/.test(lower)) return true;
7492
+ if (/\bgpt-[45]([-._\d]|\b)/.test(lower)) return true;
7493
+ if (/\bsonnet-4\.[\d.]+\b/.test(lower)) return true;
7494
+ if (/\b(high|medium|low)\s+effort\b/.test(lower)) return true;
7495
+ return false;
7496
+ }
7497
+
7498
+ // src/scoring/checks/bonus.ts
7436
7499
  function hasPreCommitHook(dir) {
7437
7500
  try {
7438
7501
  const gitDir = execSync12("git rev-parse --git-dir", {
@@ -7553,6 +7616,33 @@ function checkBonus(dir) {
7553
7616
  detail: hasLearned ? "Session learnings found in CALIBER_LEARNINGS.md" : "No learned content",
7554
7617
  suggestion: hasLearned ? void 0 : `Session learnings capture patterns from your coding sessions so the agent improves over time. Run \`${resolveCaliber()} learn install\``
7555
7618
  });
7619
+ const configContent = (() => {
7620
+ const parts = [];
7621
+ for (const rel of ["CLAUDE.md", "AGENTS.md"]) {
7622
+ const c = readFileOrNull(join7(dir, rel));
7623
+ if (c) parts.push(c);
7624
+ }
7625
+ try {
7626
+ const rulesDir = join7(dir, ".cursor", "rules");
7627
+ for (const f of readdirSync3(rulesDir).filter((x) => x.endsWith(".mdc"))) {
7628
+ const content = readFileOrNull(join7(rulesDir, f));
7629
+ if (content) parts.push(content);
7630
+ }
7631
+ } catch {
7632
+ }
7633
+ return parts.join("\n").toLowerCase();
7634
+ })();
7635
+ const hasModelRef = configContentSuggestsPinnedModel(configContent);
7636
+ checks.push({
7637
+ id: "model_pinned",
7638
+ name: "Model & effort pinned",
7639
+ category: "bonus",
7640
+ maxPoints: POINTS_MODEL_PINNED,
7641
+ earnedPoints: hasModelRef ? POINTS_MODEL_PINNED : 0,
7642
+ passed: hasModelRef,
7643
+ detail: hasModelRef ? "Model or effort level explicitly set in config" : "Config doesn't pin model or effort level \u2014 behavior may change when defaults are updated",
7644
+ suggestion: hasModelRef ? void 0 : "Add model/effort to config: CALIBER_MODEL env var, or /model in Claude Code, or a Model Configuration section in CLAUDE.md"
7645
+ });
7556
7646
  return checks;
7557
7647
  }
7558
7648
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.42.0",
3
+ "version": "1.43.0",
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": {