@rely-ai/caliber 1.15.2 → 1.16.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 +143 -10
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -503,40 +503,173 @@ var SKIP_PATTERNS = [
503
503
  /\.generated\./,
504
504
  /\.snap$/
505
505
  ];
506
+ var COMMENT_LINE_PATTERNS = {
507
+ "c-style": /^\s*\/\//,
508
+ // ts, js, go, rs, java, etc.
509
+ "hash": /^\s*#/,
510
+ // py, sh, yaml, tf, etc.
511
+ "html": /^\s*<!--.*-->\s*$/
512
+ };
513
+ var EXT_TO_COMMENT_STYLE = {
514
+ ".ts": "c-style",
515
+ ".tsx": "c-style",
516
+ ".js": "c-style",
517
+ ".jsx": "c-style",
518
+ ".mjs": "c-style",
519
+ ".cjs": "c-style",
520
+ ".go": "c-style",
521
+ ".rs": "c-style",
522
+ ".java": "c-style",
523
+ ".kt": "c-style",
524
+ ".scala": "c-style",
525
+ ".cs": "c-style",
526
+ ".c": "c-style",
527
+ ".cpp": "c-style",
528
+ ".h": "c-style",
529
+ ".hpp": "c-style",
530
+ ".swift": "c-style",
531
+ ".php": "c-style",
532
+ ".py": "hash",
533
+ ".pyw": "hash",
534
+ ".rb": "hash",
535
+ ".sh": "hash",
536
+ ".bash": "hash",
537
+ ".zsh": "hash",
538
+ ".fish": "hash",
539
+ ".r": "hash",
540
+ ".tf": "hash",
541
+ ".hcl": "hash",
542
+ ".yaml": "hash",
543
+ ".yml": "hash",
544
+ ".toml": "hash",
545
+ ".ini": "hash",
546
+ ".cfg": "hash",
547
+ ".env": "hash",
548
+ ".html": "html",
549
+ ".xml": "html",
550
+ ".svg": "html",
551
+ ".vue": "html",
552
+ ".svelte": "html"
553
+ };
506
554
  var TOKEN_BUDGET = 18e4;
507
555
  var CHAR_BUDGET = TOKEN_BUDGET * 4;
556
+ function compressContent(content, ext) {
557
+ const commentStyle = EXT_TO_COMMENT_STYLE[ext];
558
+ const commentPattern = commentStyle ? COMMENT_LINE_PATTERNS[commentStyle] : null;
559
+ const lines = content.split("\n");
560
+ const result = [];
561
+ let prevBlank = false;
562
+ let inBlockComment = false;
563
+ for (const line of lines) {
564
+ const trimmed = line.trimEnd();
565
+ if (!inBlockComment && /^\s*\/\*/.test(trimmed) && !trimmed.includes("*/")) {
566
+ inBlockComment = true;
567
+ continue;
568
+ }
569
+ if (inBlockComment) {
570
+ if (trimmed.includes("*/")) inBlockComment = false;
571
+ continue;
572
+ }
573
+ if (/^\s*\/\*.*\*\/\s*$/.test(trimmed)) continue;
574
+ if (trimmed.length === 0) {
575
+ if (!prevBlank) result.push("");
576
+ prevBlank = true;
577
+ continue;
578
+ }
579
+ prevBlank = false;
580
+ if (commentPattern && commentPattern.test(trimmed)) continue;
581
+ const leadingMatch = line.match(/^(\s*)/);
582
+ if (leadingMatch) {
583
+ const spaces = leadingMatch[1].replace(/\t/g, " ").length;
584
+ const normalizedIndent = " ".repeat(Math.floor(spaces / 2) * 2);
585
+ result.push(normalizedIndent + line.trimStart().trimEnd());
586
+ } else {
587
+ result.push(trimmed);
588
+ }
589
+ }
590
+ while (result.length > 0 && result[result.length - 1] === "") result.pop();
591
+ return result.join("\n");
592
+ }
593
+ function structuralFingerprint(content, ext) {
594
+ const lines = content.split("\n").filter((l) => l.trim().length > 0);
595
+ const lineCount = lines.length;
596
+ const sizeBucket = Math.floor(lineCount / 10) * 10;
597
+ const firstLine = lines[0]?.trim().slice(0, 60) || "";
598
+ const imports = lines.filter((l) => /^\s*(import |from |require\(|use )/.test(l)).length;
599
+ const exports = lines.filter((l) => /^\s*export /.test(l)).length;
600
+ const functions = lines.filter((l) => /^\s*(function |def |func |fn |pub fn )/.test(l)).length;
601
+ return `${ext}:${sizeBucket}:${imports}:${exports}:${functions}:${firstLine}`;
602
+ }
603
+ function deduplicateFiles(files) {
604
+ const groups = /* @__PURE__ */ new Map();
605
+ for (const f of files) {
606
+ const fp = structuralFingerprint(f.content, f.ext);
607
+ const group = groups.get(fp) || [];
608
+ group.push({ path: f.path, content: f.content });
609
+ groups.set(fp, group);
610
+ }
611
+ const result = [];
612
+ for (const [, group] of groups) {
613
+ const representative = group[0];
614
+ result.push({
615
+ path: representative.path,
616
+ content: representative.content,
617
+ size: representative.content.length
618
+ });
619
+ if (group.length > 1) {
620
+ const similarPaths = group.slice(1).map((f) => f.path);
621
+ const summary = `(${similarPaths.length} similar file${similarPaths.length === 1 ? "" : "s"}: ${similarPaths.join(", ")})`;
622
+ result.push({
623
+ path: `[similar to ${representative.path}]`,
624
+ content: summary,
625
+ size: summary.length
626
+ });
627
+ }
628
+ }
629
+ return result;
630
+ }
508
631
  function analyzeCode(dir) {
509
632
  const allFiles = [];
510
633
  walkDir(dir, "", 0, 10, allFiles);
511
634
  sortByPriority(allFiles);
512
635
  let totalChars = 0;
513
- let includedChars = 0;
514
- let truncated = false;
515
- const files = [];
516
- const fileSizes = /* @__PURE__ */ new Map();
517
636
  for (const relPath of allFiles) {
518
637
  try {
519
638
  const stat = fs3.statSync(path3.join(dir, relPath));
520
- fileSizes.set(relPath, stat.size);
521
639
  totalChars += stat.size;
522
640
  } catch {
523
641
  }
524
642
  }
643
+ const readFiles = [];
525
644
  for (const relPath of allFiles) {
526
645
  const fullPath = path3.join(dir, relPath);
527
- let content;
646
+ let rawContent;
528
647
  try {
529
- content = fs3.readFileSync(fullPath, "utf-8");
648
+ rawContent = fs3.readFileSync(fullPath, "utf-8");
530
649
  } catch {
531
650
  continue;
532
651
  }
533
- if (content.split("\n").length > 500) continue;
534
- const entrySize = relPath.length + content.length + 10;
652
+ if (rawContent.split("\n").length > 500) continue;
653
+ const ext = path3.extname(relPath).toLowerCase();
654
+ const compressed = compressContent(rawContent, ext);
655
+ readFiles.push({
656
+ path: relPath,
657
+ content: compressed,
658
+ ext,
659
+ rawSize: rawContent.length
660
+ });
661
+ }
662
+ const deduped = deduplicateFiles(readFiles);
663
+ let includedChars = 0;
664
+ let truncated = false;
665
+ const files = [];
666
+ for (const file of deduped) {
667
+ const entrySize = file.path.length + file.content.length + 10;
535
668
  if (includedChars + entrySize > CHAR_BUDGET) {
536
669
  truncated = true;
537
670
  continue;
538
671
  }
539
- files.push({ path: relPath, content, size: content.length });
672
+ files.push(file);
540
673
  includedChars += entrySize;
541
674
  }
542
675
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.15.2",
3
+ "version": "1.16.0",
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": {