@rely-ai/caliber 1.12.18 → 1.13.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 +124 -41
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -446,9 +446,9 @@ var CONFIG_FILE_NAMES = /* @__PURE__ */ new Set([
446
446
  var CONFIG_GLOBS_DIRS = [
447
447
  { dir: ".github/workflows", pattern: /\.ya?ml$/ }
448
448
  ];
449
- var TOTAL_BUDGET = 5e4;
450
- var CONFIG_BUDGET = Math.floor(TOTAL_BUDGET * 0.3);
451
- var SOURCE_BUDGET = Math.floor(TOTAL_BUDGET * 0.7);
449
+ var TOTAL_BUDGET = 4e5;
450
+ var CONFIG_BUDGET = Math.floor(TOTAL_BUDGET * 0.15);
451
+ var SOURCE_BUDGET = Math.floor(TOTAL_BUDGET * 0.85);
452
452
  function analyzeCode(dir) {
453
453
  const sourceFiles = [];
454
454
  const configFiles = [];
@@ -465,27 +465,56 @@ function analyzeCode(dir) {
465
465
  let sourceChars = 0;
466
466
  let truncated = false;
467
467
  const fileSummaries = [];
468
+ const MAX_CONTENT_LINE_COUNT = 300;
469
+ const CONTENT_BUDGET = Math.floor(SOURCE_BUDGET * 0.75);
470
+ const SUMMARY_BUDGET = SOURCE_BUDGET - CONTENT_BUDGET;
468
471
  for (const relPath of sourceFiles) {
469
472
  const fullPath = path3.join(dir, relPath);
470
- let content;
473
+ let fileContent;
471
474
  try {
472
- content = fs3.readFileSync(fullPath, "utf-8");
475
+ fileContent = fs3.readFileSync(fullPath, "utf-8");
473
476
  } catch {
474
477
  continue;
475
478
  }
476
- const lineCount = content.split("\n").length;
477
- if (lineCount > 500) continue;
479
+ const lineCount = fileContent.split("\n").length;
480
+ if (lineCount > MAX_CONTENT_LINE_COUNT) continue;
478
481
  const ext = path3.extname(relPath);
479
482
  const language = resolveLanguage(ext);
480
483
  if (!language) continue;
481
- const summary = language === "py" ? extractPython(relPath, content) : extractTypeScriptJavaScript(relPath, content, language);
484
+ const summary = language === "py" ? extractPython(relPath, fileContent) : extractTypeScriptJavaScript(relPath, fileContent, language);
485
+ summary.content = fileContent;
486
+ const entrySize = estimateSummarySize(summary) + fileContent.length;
487
+ if (sourceChars + entrySize > CONTENT_BUDGET) {
488
+ truncated = true;
489
+ break;
490
+ }
491
+ fileSummaries.push(summary);
492
+ sourceChars += entrySize;
493
+ }
494
+ const processedPaths = new Set(fileSummaries.map((f) => f.path));
495
+ let summaryChars = 0;
496
+ for (const relPath of sourceFiles) {
497
+ if (processedPaths.has(relPath)) continue;
498
+ const fullPath = path3.join(dir, relPath);
499
+ let fileContent;
500
+ try {
501
+ fileContent = fs3.readFileSync(fullPath, "utf-8");
502
+ } catch {
503
+ continue;
504
+ }
505
+ const lineCount = fileContent.split("\n").length;
506
+ if (lineCount > 1e3) continue;
507
+ const ext = path3.extname(relPath);
508
+ const language = resolveLanguage(ext);
509
+ if (!language) continue;
510
+ const summary = language === "py" ? extractPython(relPath, fileContent) : extractTypeScriptJavaScript(relPath, fileContent, language);
482
511
  const summarySize = estimateSummarySize(summary);
483
- if (sourceChars + summarySize > SOURCE_BUDGET) {
512
+ if (summaryChars + summarySize > SUMMARY_BUDGET) {
484
513
  truncated = true;
485
514
  break;
486
515
  }
487
516
  fileSummaries.push(summary);
488
- sourceChars += summarySize;
517
+ summaryChars += summarySize;
489
518
  }
490
519
  return { fileSummaries, configFiles: trimmedConfigs, truncated };
491
520
  }
@@ -2436,15 +2465,16 @@ async function generateMonolithic(fingerprint, targetAgent, prompt, callbacks, f
2436
2465
  return attemptGeneration();
2437
2466
  }
2438
2467
  var LIMITS = {
2439
- FILE_TREE_ENTRIES: 200,
2468
+ FILE_TREE_ENTRIES: 500,
2440
2469
  EXISTING_CONFIG_CHARS: 8e3,
2441
2470
  SKILLS_MAX: 10,
2442
2471
  SKILL_CHARS: 3e3,
2443
2472
  RULES_MAX: 10,
2444
- CONFIG_FILES_MAX: 15,
2445
- CONFIG_FILE_CHARS: 3e3,
2446
- ROUTES_MAX: 50,
2447
- FILE_SUMMARIES_MAX: 60
2473
+ CONFIG_FILES_MAX: 20,
2474
+ CONFIG_FILE_CHARS: 5e3,
2475
+ ROUTES_MAX: 100,
2476
+ FILE_SUMMARIES_MAX: 200,
2477
+ FILE_CONTENT_CHARS: 8e3
2448
2478
  };
2449
2479
  function truncate(text, maxChars) {
2450
2480
  if (text.length <= maxChars) return text;
@@ -2575,9 +2605,19 @@ ${truncate(cfg.content, LIMITS.CONFIG_FILE_CHARS)}`);
2575
2605
  parts.push(`(${allRoutes.length - LIMITS.ROUTES_MAX} more routes omitted)`);
2576
2606
  }
2577
2607
  }
2578
- if (ca.fileSummaries.length > 0) {
2608
+ const filesWithContent = ca.fileSummaries.filter((f) => f.content);
2609
+ const filesWithoutContent = ca.fileSummaries.filter((f) => !f.content);
2610
+ if (filesWithContent.length > 0) {
2611
+ parts.push("\n--- Source Files (full content \u2014 use these to extract patterns for skills) ---");
2612
+ for (const f of filesWithContent.slice(0, LIMITS.FILE_SUMMARIES_MAX)) {
2613
+ parts.push(`
2614
+ [${f.path}] (${f.language})`);
2615
+ parts.push(truncate(f.content, LIMITS.FILE_CONTENT_CHARS));
2616
+ }
2617
+ }
2618
+ if (filesWithoutContent.length > 0) {
2579
2619
  parts.push("\n--- Source File Summaries ---");
2580
- for (const f of ca.fileSummaries.slice(0, LIMITS.FILE_SUMMARIES_MAX)) {
2620
+ for (const f of filesWithoutContent.slice(0, LIMITS.FILE_SUMMARIES_MAX)) {
2581
2621
  const sections = [`[${f.path}] (${f.language})`];
2582
2622
  if (f.imports.length > 0) sections.push(` imports: ${f.imports.slice(0, 10).join("; ")}`);
2583
2623
  if (f.exports.length > 0) sections.push(` exports: ${f.exports.slice(0, 10).join(", ")}`);
@@ -2586,9 +2626,9 @@ ${truncate(cfg.content, LIMITS.CONFIG_FILE_CHARS)}`);
2586
2626
  if (f.types.length > 0) sections.push(` types: ${f.types.slice(0, 10).join(", ")}`);
2587
2627
  parts.push(sections.join("\n"));
2588
2628
  }
2589
- if (ca.fileSummaries.length > LIMITS.FILE_SUMMARIES_MAX) {
2629
+ if (filesWithoutContent.length > LIMITS.FILE_SUMMARIES_MAX) {
2590
2630
  parts.push(`
2591
- (${ca.fileSummaries.length - LIMITS.FILE_SUMMARIES_MAX} more files omitted)`);
2631
+ (${filesWithoutContent.length - LIMITS.FILE_SUMMARIES_MAX} more files omitted)`);
2592
2632
  }
2593
2633
  }
2594
2634
  if (ca.truncated) {
@@ -2598,7 +2638,7 @@ ${truncate(cfg.content, LIMITS.CONFIG_FILE_CHARS)}`);
2598
2638
  const allDeps = extractAllDeps(process.cwd());
2599
2639
  if (allDeps.length > 0) {
2600
2640
  parts.push(`
2601
- DEPENDENCY COVERAGE \u2014 mention at least 85% of these ${allDeps.length} packages by name in CLAUDE.md or skills for full coverage points:`);
2641
+ Project dependencies (${allDeps.length}):`);
2602
2642
  parts.push(allDeps.join(", "));
2603
2643
  }
2604
2644
  if (prompt) parts.push(`
@@ -3755,7 +3795,7 @@ async function runInteractiveProviderSetup(options) {
3755
3795
  }
3756
3796
 
3757
3797
  // src/scoring/index.ts
3758
- import { existsSync as existsSync6 } from "fs";
3798
+ import { existsSync as existsSync7 } from "fs";
3759
3799
  import { join as join8 } from "path";
3760
3800
 
3761
3801
  // src/scoring/checks/existence.ts
@@ -4104,12 +4144,25 @@ function collectProjectStructure(dir, maxDepth = 2) {
4104
4144
  walk(dir, 0);
4105
4145
  return { dirs, files };
4106
4146
  }
4107
- function collectAllConfigContent(dir) {
4147
+ function collectPrimaryConfigContent(dir) {
4108
4148
  const parts = [];
4109
4149
  for (const file of ["CLAUDE.md", ".cursorrules", "AGENTS.md"]) {
4110
4150
  const content = readFileOrNull2(join3(dir, file));
4111
4151
  if (content) parts.push(content);
4112
4152
  }
4153
+ try {
4154
+ const rulesDir = join3(dir, ".cursor", "rules");
4155
+ const mdcFiles = readdirSync2(rulesDir).filter((f) => f.endsWith(".mdc"));
4156
+ for (const f of mdcFiles) {
4157
+ const content = readFileOrNull2(join3(rulesDir, f));
4158
+ if (content) parts.push(content);
4159
+ }
4160
+ } catch {
4161
+ }
4162
+ return parts.join("\n");
4163
+ }
4164
+ function collectAllConfigContent(dir) {
4165
+ const parts = [collectPrimaryConfigContent(dir)];
4113
4166
  for (const skillsDir of [join3(dir, ".claude", "skills"), join3(dir, ".agents", "skills")]) {
4114
4167
  try {
4115
4168
  const entries = readdirSync2(skillsDir, { withFileTypes: true });
@@ -4125,15 +4178,6 @@ function collectAllConfigContent(dir) {
4125
4178
  } catch {
4126
4179
  }
4127
4180
  }
4128
- try {
4129
- const rulesDir = join3(dir, ".cursor", "rules");
4130
- const mdcFiles = readdirSync2(rulesDir).filter((f) => f.endsWith(".mdc"));
4131
- for (const f of mdcFiles) {
4132
- const content = readFileOrNull2(join3(rulesDir, f));
4133
- if (content) parts.push(content);
4134
- }
4135
- } catch {
4136
- }
4137
4181
  return parts.join("\n");
4138
4182
  }
4139
4183
  function estimateTokens2(text) {
@@ -4249,7 +4293,7 @@ function checkQuality(dir) {
4249
4293
  instruction: `Add code blocks with executable commands. Currently ${codeBlockCount}, need at least 3 for full points.`
4250
4294
  } : void 0
4251
4295
  });
4252
- const totalContent = collectAllConfigContent(dir);
4296
+ const totalContent = collectPrimaryConfigContent(dir);
4253
4297
  const totalTokens = estimateTokens2(totalContent);
4254
4298
  const tokenThreshold = TOKEN_BUDGET_THRESHOLDS.find((t) => totalTokens <= t.maxTokens);
4255
4299
  const tokenPoints = totalContent.length === 0 ? POINTS_CONCISE_CONFIG : tokenThreshold?.points ?? 0;
@@ -4481,11 +4525,11 @@ function checkGrounding(dir) {
4481
4525
  }
4482
4526
 
4483
4527
  // src/scoring/checks/accuracy.ts
4484
- import { existsSync as existsSync4 } from "fs";
4528
+ import { existsSync as existsSync4, statSync as statSync2 } from "fs";
4485
4529
  import { execSync as execSync8 } from "child_process";
4486
4530
  import { join as join5 } from "path";
4487
4531
  function validateReferences(dir) {
4488
- const configContent = collectAllConfigContent(dir);
4532
+ const configContent = collectPrimaryConfigContent(dir);
4489
4533
  if (!configContent) return { valid: [], invalid: [], total: 0 };
4490
4534
  const refs = extractReferences(configContent);
4491
4535
  const valid = [];
@@ -4519,6 +4563,25 @@ function detectGitDrift(dir) {
4519
4563
  return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: false };
4520
4564
  }
4521
4565
  const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules", ".cursor/rules"];
4566
+ try {
4567
+ const headTimestamp = execSync8(
4568
+ "git log -1 --format=%ct HEAD",
4569
+ { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4570
+ ).trim();
4571
+ const headTime = parseInt(headTimestamp, 10) * 1e3;
4572
+ for (const file of configFiles) {
4573
+ const filePath = join5(dir, file);
4574
+ if (!existsSync4(filePath)) continue;
4575
+ try {
4576
+ const mtime = statSync2(filePath).mtime.getTime();
4577
+ if (mtime > headTime) {
4578
+ return { commitsSinceConfigUpdate: 0, lastConfigCommit: "uncommitted (recently modified)", isGitRepo: true };
4579
+ }
4580
+ } catch {
4581
+ }
4582
+ }
4583
+ } catch {
4584
+ }
4522
4585
  let latestConfigCommitHash = null;
4523
4586
  for (const file of configFiles) {
4524
4587
  try {
@@ -4622,10 +4685,30 @@ function checkAccuracy(dir) {
4622
4685
  }
4623
4686
 
4624
4687
  // src/scoring/checks/freshness.ts
4688
+ import { existsSync as existsSync5, statSync as statSync3 } from "fs";
4625
4689
  import { execSync as execSync9 } from "child_process";
4626
4690
  import { join as join6 } from "path";
4627
4691
  function getCommitsSinceConfigUpdate(dir) {
4628
4692
  const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules"];
4693
+ try {
4694
+ const headTimestamp = execSync9(
4695
+ "git log -1 --format=%ct HEAD",
4696
+ { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4697
+ ).trim();
4698
+ const headTime = parseInt(headTimestamp, 10) * 1e3;
4699
+ for (const file of configFiles) {
4700
+ const filePath = join6(dir, file);
4701
+ if (!existsSync5(filePath)) continue;
4702
+ try {
4703
+ const mtime = statSync3(filePath).mtime.getTime();
4704
+ if (mtime > headTime) {
4705
+ return 0;
4706
+ }
4707
+ } catch {
4708
+ }
4709
+ }
4710
+ } catch {
4711
+ }
4629
4712
  for (const file of configFiles) {
4630
4713
  try {
4631
4714
  const hash = execSync9(
@@ -4750,7 +4833,7 @@ function checkFreshness(dir) {
4750
4833
  }
4751
4834
 
4752
4835
  // src/scoring/checks/bonus.ts
4753
- import { existsSync as existsSync5, readdirSync as readdirSync3 } from "fs";
4836
+ import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
4754
4837
  import { execSync as execSync10 } from "child_process";
4755
4838
  import { join as join7 } from "path";
4756
4839
  function hasPreCommitHook(dir) {
@@ -4800,7 +4883,7 @@ function checkBonus(dir) {
4800
4883
  instruction: "Install caliber hooks for automatic config refresh on commits."
4801
4884
  }
4802
4885
  });
4803
- const agentsMdExists = existsSync5(join7(dir, "AGENTS.md"));
4886
+ const agentsMdExists = existsSync6(join7(dir, "AGENTS.md"));
4804
4887
  checks.push({
4805
4888
  id: "agents_md_exists",
4806
4889
  name: "AGENTS.md exists",
@@ -4898,9 +4981,9 @@ function filterChecksForTarget(checks, target) {
4898
4981
  }
4899
4982
  function detectTargetAgent(dir) {
4900
4983
  const agents = [];
4901
- if (existsSync6(join8(dir, "CLAUDE.md")) || existsSync6(join8(dir, ".claude", "skills"))) agents.push("claude");
4902
- if (existsSync6(join8(dir, ".cursorrules")) || existsSync6(join8(dir, ".cursor", "rules"))) agents.push("cursor");
4903
- if (existsSync6(join8(dir, ".codex")) || existsSync6(join8(dir, ".agents", "skills"))) agents.push("codex");
4984
+ if (existsSync7(join8(dir, "CLAUDE.md")) || existsSync7(join8(dir, ".claude", "skills"))) agents.push("claude");
4985
+ if (existsSync7(join8(dir, ".cursorrules")) || existsSync7(join8(dir, ".cursor", "rules"))) agents.push("cursor");
4986
+ if (existsSync7(join8(dir, ".codex")) || existsSync7(join8(dir, ".agents", "skills"))) agents.push("codex");
4904
4987
  return agents.length > 0 ? agents : ["claude"];
4905
4988
  }
4906
4989
  function computeLocalScore(dir, targetAgent) {
@@ -5064,7 +5147,7 @@ function displayScoreDelta(before, after) {
5064
5147
  import chalk7 from "chalk";
5065
5148
  import ora from "ora";
5066
5149
  import select4 from "@inquirer/select";
5067
- import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4, existsSync as existsSync7, writeFileSync } from "fs";
5150
+ import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4, existsSync as existsSync8, writeFileSync } from "fs";
5068
5151
  import { join as join9, dirname as dirname2 } from "path";
5069
5152
 
5070
5153
  // src/scanner/index.ts
@@ -5565,7 +5648,7 @@ Already installed skills: ${Array.from(installed).join(", ")}`);
5565
5648
  }
5566
5649
  function extractTopDeps() {
5567
5650
  const pkgPath = join9(process.cwd(), "package.json");
5568
- if (!existsSync7(pkgPath)) return [];
5651
+ if (!existsSync8(pkgPath)) return [];
5569
5652
  try {
5570
5653
  const pkg3 = JSON.parse(readFileSync4(pkgPath, "utf-8"));
5571
5654
  const deps = Object.keys(pkg3.dependencies ?? {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.12.18",
3
+ "version": "1.13.1",
4
4
  "description": "Analyze your codebase and generate optimized AI agent configs (CLAUDE.md, .cursorrules, skills) — no API key needed",
5
5
  "type": "module",
6
6
  "bin": {