@rely-ai/caliber 1.16.0 → 1.18.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.
- package/dist/bin.js +357 -174
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -396,6 +396,7 @@ function readExistingConfigs(dir) {
|
|
|
396
396
|
// src/fingerprint/code-analysis.ts
|
|
397
397
|
import fs3 from "fs";
|
|
398
398
|
import path3 from "path";
|
|
399
|
+
import { execSync as execSync2 } from "child_process";
|
|
399
400
|
var IGNORE_DIRS2 = /* @__PURE__ */ new Set([
|
|
400
401
|
"node_modules",
|
|
401
402
|
".git",
|
|
@@ -503,59 +504,78 @@ var SKIP_PATTERNS = [
|
|
|
503
504
|
/\.generated\./,
|
|
504
505
|
/\.snap$/
|
|
505
506
|
];
|
|
506
|
-
var
|
|
507
|
-
"c
|
|
508
|
-
|
|
509
|
-
"
|
|
510
|
-
// py, sh, yaml, tf, etc.
|
|
511
|
-
"html": /^\s*<!--.*-->\s*$/
|
|
507
|
+
var COMMENT_LINE = {
|
|
508
|
+
"c": /^\s*\/\//,
|
|
509
|
+
"h": /^\s*#/,
|
|
510
|
+
"x": /^\s*<!--.*-->\s*$/
|
|
512
511
|
};
|
|
513
|
-
var
|
|
514
|
-
".ts": "c
|
|
515
|
-
".tsx": "c
|
|
516
|
-
".js": "c
|
|
517
|
-
".jsx": "c
|
|
518
|
-
".mjs": "c
|
|
519
|
-
".cjs": "c
|
|
520
|
-
".go": "c
|
|
521
|
-
".rs": "c
|
|
522
|
-
".java": "c
|
|
523
|
-
".kt": "c
|
|
524
|
-
".scala": "c
|
|
525
|
-
".cs": "c
|
|
526
|
-
".c": "c
|
|
527
|
-
".cpp": "c
|
|
528
|
-
".h": "c
|
|
529
|
-
".hpp": "c
|
|
530
|
-
".swift": "c
|
|
531
|
-
".php": "c
|
|
532
|
-
".py": "
|
|
533
|
-
".pyw": "
|
|
534
|
-
".rb": "
|
|
535
|
-
".sh": "
|
|
536
|
-
".bash": "
|
|
537
|
-
".zsh": "
|
|
538
|
-
".fish": "
|
|
539
|
-
".r": "
|
|
540
|
-
".tf": "
|
|
541
|
-
".hcl": "
|
|
542
|
-
".yaml": "
|
|
543
|
-
".yml": "
|
|
544
|
-
".toml": "
|
|
545
|
-
".ini": "
|
|
546
|
-
".cfg": "
|
|
547
|
-
".env": "
|
|
548
|
-
".html": "
|
|
549
|
-
".xml": "
|
|
550
|
-
".
|
|
551
|
-
".
|
|
552
|
-
".svelte": "html"
|
|
512
|
+
var EXT_COMMENT = {
|
|
513
|
+
".ts": "c",
|
|
514
|
+
".tsx": "c",
|
|
515
|
+
".js": "c",
|
|
516
|
+
".jsx": "c",
|
|
517
|
+
".mjs": "c",
|
|
518
|
+
".cjs": "c",
|
|
519
|
+
".go": "c",
|
|
520
|
+
".rs": "c",
|
|
521
|
+
".java": "c",
|
|
522
|
+
".kt": "c",
|
|
523
|
+
".scala": "c",
|
|
524
|
+
".cs": "c",
|
|
525
|
+
".c": "c",
|
|
526
|
+
".cpp": "c",
|
|
527
|
+
".h": "c",
|
|
528
|
+
".hpp": "c",
|
|
529
|
+
".swift": "c",
|
|
530
|
+
".php": "c",
|
|
531
|
+
".py": "h",
|
|
532
|
+
".pyw": "h",
|
|
533
|
+
".rb": "h",
|
|
534
|
+
".sh": "h",
|
|
535
|
+
".bash": "h",
|
|
536
|
+
".zsh": "h",
|
|
537
|
+
".fish": "h",
|
|
538
|
+
".r": "h",
|
|
539
|
+
".tf": "h",
|
|
540
|
+
".hcl": "h",
|
|
541
|
+
".yaml": "h",
|
|
542
|
+
".yml": "h",
|
|
543
|
+
".toml": "h",
|
|
544
|
+
".ini": "h",
|
|
545
|
+
".cfg": "h",
|
|
546
|
+
".env": "h",
|
|
547
|
+
".html": "x",
|
|
548
|
+
".xml": "x",
|
|
549
|
+
".vue": "x",
|
|
550
|
+
".svelte": "x"
|
|
553
551
|
};
|
|
552
|
+
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
553
|
+
".ts",
|
|
554
|
+
".tsx",
|
|
555
|
+
".js",
|
|
556
|
+
".jsx",
|
|
557
|
+
".mjs",
|
|
558
|
+
".cjs",
|
|
559
|
+
".py",
|
|
560
|
+
".pyw",
|
|
561
|
+
".go",
|
|
562
|
+
".rs",
|
|
563
|
+
".rb",
|
|
564
|
+
".java",
|
|
565
|
+
".kt",
|
|
566
|
+
".scala",
|
|
567
|
+
".cs",
|
|
568
|
+
".c",
|
|
569
|
+
".cpp",
|
|
570
|
+
".h",
|
|
571
|
+
".hpp",
|
|
572
|
+
".swift",
|
|
573
|
+
".php"
|
|
574
|
+
]);
|
|
554
575
|
var TOKEN_BUDGET = 18e4;
|
|
555
576
|
var CHAR_BUDGET = TOKEN_BUDGET * 4;
|
|
556
577
|
function compressContent(content, ext) {
|
|
557
|
-
const
|
|
558
|
-
const commentPattern = commentStyle ? COMMENT_LINE_PATTERNS[commentStyle] : null;
|
|
578
|
+
const cp = EXT_COMMENT[ext] ? COMMENT_LINE[EXT_COMMENT[ext]] : null;
|
|
559
579
|
const lines = content.split("\n");
|
|
560
580
|
const result = [];
|
|
561
581
|
let prevBlank = false;
|
|
@@ -577,12 +597,11 @@ function compressContent(content, ext) {
|
|
|
577
597
|
continue;
|
|
578
598
|
}
|
|
579
599
|
prevBlank = false;
|
|
580
|
-
if (
|
|
581
|
-
const
|
|
582
|
-
if (
|
|
583
|
-
const spaces =
|
|
584
|
-
|
|
585
|
-
result.push(normalizedIndent + line.trimStart().trimEnd());
|
|
600
|
+
if (cp && cp.test(trimmed)) continue;
|
|
601
|
+
const leading = line.match(/^(\s*)/);
|
|
602
|
+
if (leading) {
|
|
603
|
+
const spaces = leading[1].replace(/\t/g, " ").length;
|
|
604
|
+
result.push(" ".repeat(Math.floor(spaces / 2) * 2) + line.trimStart().trimEnd());
|
|
586
605
|
} else {
|
|
587
606
|
result.push(trimmed);
|
|
588
607
|
}
|
|
@@ -590,93 +609,255 @@ function compressContent(content, ext) {
|
|
|
590
609
|
while (result.length > 0 && result[result.length - 1] === "") result.pop();
|
|
591
610
|
return result.join("\n");
|
|
592
611
|
}
|
|
593
|
-
function
|
|
594
|
-
|
|
595
|
-
const
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
612
|
+
function extractSkeleton(content, ext) {
|
|
613
|
+
if (!SOURCE_EXTENSIONS.has(ext)) return content;
|
|
614
|
+
const lines = content.split("\n");
|
|
615
|
+
const result = [];
|
|
616
|
+
let braceDepth = 0;
|
|
617
|
+
let inSignature = false;
|
|
618
|
+
let skipBody = false;
|
|
619
|
+
if ([".py", ".pyw", ".rb"].includes(ext)) {
|
|
620
|
+
return extractSkeletonIndentBased(lines, ext);
|
|
621
|
+
}
|
|
622
|
+
for (let i = 0; i < lines.length; i++) {
|
|
623
|
+
const line = lines[i];
|
|
624
|
+
const trimmed = line.trim();
|
|
625
|
+
if (/^\s*(import |from |require\(|use |package |module )/.test(line)) {
|
|
626
|
+
result.push(line);
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
if (/^\s*(export\s+)?(interface|type|enum)\s/.test(trimmed)) {
|
|
630
|
+
result.push(line);
|
|
631
|
+
let depth = 0;
|
|
632
|
+
for (let j = i; j < lines.length; j++) {
|
|
633
|
+
if (j > i) result.push(lines[j]);
|
|
634
|
+
depth += (lines[j].match(/{/g) || []).length;
|
|
635
|
+
depth -= (lines[j].match(/}/g) || []).length;
|
|
636
|
+
if (depth <= 0 && j > i) {
|
|
637
|
+
i = j;
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
const isFnOrClass = /^\s*(export\s+)?(default\s+)?(async\s+)?(function|class|const\s+\w+\s*=\s*(async\s*)?\(|pub\s+fn|fn|func)\s/.test(trimmed) || /^\s*(def|func|fn|pub fn|pub async fn)\s/.test(trimmed);
|
|
644
|
+
if (isFnOrClass && braceDepth === 0) {
|
|
645
|
+
result.push(line);
|
|
646
|
+
const opens = (line.match(/{/g) || []).length;
|
|
647
|
+
const closes = (line.match(/}/g) || []).length;
|
|
648
|
+
if (opens > closes) {
|
|
649
|
+
skipBody = true;
|
|
650
|
+
braceDepth = opens - closes;
|
|
651
|
+
result.push(" ".repeat(line.search(/\S/)) + " // ...");
|
|
652
|
+
}
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
if (skipBody) {
|
|
656
|
+
braceDepth += (line.match(/{/g) || []).length;
|
|
657
|
+
braceDepth -= (line.match(/}/g) || []).length;
|
|
658
|
+
if (braceDepth <= 0) {
|
|
659
|
+
result.push(line);
|
|
660
|
+
skipBody = false;
|
|
661
|
+
braceDepth = 0;
|
|
662
|
+
}
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
if (braceDepth === 0) {
|
|
666
|
+
result.push(line);
|
|
667
|
+
}
|
|
610
668
|
}
|
|
669
|
+
return result.join("\n");
|
|
670
|
+
}
|
|
671
|
+
function extractSkeletonIndentBased(lines, ext) {
|
|
611
672
|
const result = [];
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
673
|
+
let skipIndent = -1;
|
|
674
|
+
for (const line of lines) {
|
|
675
|
+
const trimmed = line.trim();
|
|
676
|
+
if (trimmed.length === 0) continue;
|
|
677
|
+
const indent = line.search(/\S/);
|
|
678
|
+
if (/^(import |from )/.test(trimmed)) {
|
|
679
|
+
result.push(line);
|
|
680
|
+
skipIndent = -1;
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (/^(class |def |async def )/.test(trimmed)) {
|
|
684
|
+
result.push(line);
|
|
685
|
+
skipIndent = indent;
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
if (trimmed.startsWith("@")) {
|
|
689
|
+
result.push(line);
|
|
690
|
+
skipIndent = -1;
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (skipIndent >= 0 && indent > skipIndent) {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
skipIndent = -1;
|
|
697
|
+
result.push(line);
|
|
698
|
+
}
|
|
699
|
+
return result.join("\n");
|
|
700
|
+
}
|
|
701
|
+
function extractImports(content, filePath) {
|
|
702
|
+
const imports = [];
|
|
703
|
+
const dir = path3.dirname(filePath);
|
|
704
|
+
for (const line of content.split("\n")) {
|
|
705
|
+
const trimmed = line.trim();
|
|
706
|
+
const jsMatch = trimmed.match(/(?:from|require\()\s*['"]([^'"]+)['"]/);
|
|
707
|
+
if (jsMatch && jsMatch[1].startsWith(".")) {
|
|
708
|
+
imports.push(path3.normalize(path3.join(dir, jsMatch[1])));
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
const pyMatch = trimmed.match(/^from\s+(\.[.\w]*)\s+import/);
|
|
712
|
+
if (pyMatch) {
|
|
713
|
+
const modulePath = pyMatch[1].replace(/\./g, "/");
|
|
714
|
+
imports.push(path3.normalize(path3.join(dir, modulePath)));
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
const goMatch = trimmed.match(/^\s*"([^"]+)"/);
|
|
718
|
+
if (goMatch && !goMatch[1].includes(".")) {
|
|
719
|
+
imports.push(goMatch[1]);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return imports;
|
|
723
|
+
}
|
|
724
|
+
function buildImportCounts(files) {
|
|
725
|
+
const counts = /* @__PURE__ */ new Map();
|
|
726
|
+
for (const [filePath, content] of files) {
|
|
727
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
728
|
+
if (!SOURCE_EXTENSIONS.has(ext)) continue;
|
|
729
|
+
const imports = extractImports(content, filePath);
|
|
730
|
+
for (const imp of imports) {
|
|
731
|
+
const candidates = [imp, imp + ".ts", imp + ".js", imp + ".tsx", imp + ".jsx", imp + "/index.ts", imp + "/index.js", imp + ".py"];
|
|
732
|
+
for (const candidate of candidates) {
|
|
733
|
+
const normalized = candidate.replace(/\\/g, "/");
|
|
734
|
+
if (files.has(normalized)) {
|
|
735
|
+
counts.set(normalized, (counts.get(normalized) || 0) + 1);
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return counts;
|
|
742
|
+
}
|
|
743
|
+
function getGitFrequency(dir) {
|
|
744
|
+
const freq = /* @__PURE__ */ new Map();
|
|
745
|
+
try {
|
|
746
|
+
const output = execSync2(
|
|
747
|
+
'git log --since="6 months ago" --format="" --name-only --diff-filter=ACMR 2>/dev/null | head -10000',
|
|
748
|
+
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }
|
|
749
|
+
);
|
|
750
|
+
for (const line of output.split("\n")) {
|
|
751
|
+
const trimmed = line.trim();
|
|
752
|
+
if (trimmed) freq.set(trimmed, (freq.get(trimmed) || 0) + 1);
|
|
627
753
|
}
|
|
754
|
+
} catch {
|
|
755
|
+
}
|
|
756
|
+
return freq;
|
|
757
|
+
}
|
|
758
|
+
function groupByDirectory(files) {
|
|
759
|
+
const groups = /* @__PURE__ */ new Map();
|
|
760
|
+
for (const f of files) {
|
|
761
|
+
const dir = path3.dirname(f.path);
|
|
762
|
+
const group = groups.get(dir) || [];
|
|
763
|
+
group.push(f);
|
|
764
|
+
groups.set(dir, group);
|
|
628
765
|
}
|
|
629
|
-
return
|
|
766
|
+
return groups;
|
|
767
|
+
}
|
|
768
|
+
function structuralFingerprint(content, ext) {
|
|
769
|
+
const lines = content.split("\n").filter((l) => l.trim().length > 0);
|
|
770
|
+
const bucket = Math.floor(lines.length / 10) * 10;
|
|
771
|
+
const first = (lines[0] || "").trim().slice(0, 50);
|
|
772
|
+
const imports = lines.filter((l) => /^\s*(import |from |require\(|use )/.test(l)).length;
|
|
773
|
+
const fns = lines.filter((l) => /^\s*(export\s+)?(async\s+)?(function |def |func |fn |pub fn |class )/.test(l)).length;
|
|
774
|
+
return `${ext}:${bucket}:${imports}:${fns}:${first}`;
|
|
630
775
|
}
|
|
631
776
|
function analyzeCode(dir) {
|
|
632
|
-
const
|
|
633
|
-
walkDir(dir, "", 0, 10,
|
|
634
|
-
sortByPriority(allFiles);
|
|
777
|
+
const allPaths = [];
|
|
778
|
+
walkDir(dir, "", 0, 10, allPaths);
|
|
635
779
|
let totalChars = 0;
|
|
636
|
-
for (const relPath of
|
|
780
|
+
for (const relPath of allPaths) {
|
|
637
781
|
try {
|
|
638
|
-
|
|
639
|
-
totalChars += stat.size;
|
|
782
|
+
totalChars += fs3.statSync(path3.join(dir, relPath)).size;
|
|
640
783
|
} catch {
|
|
641
784
|
}
|
|
642
785
|
}
|
|
643
|
-
const
|
|
644
|
-
for (const relPath of
|
|
645
|
-
const fullPath = path3.join(dir, relPath);
|
|
646
|
-
let rawContent;
|
|
786
|
+
const fileContents = /* @__PURE__ */ new Map();
|
|
787
|
+
for (const relPath of allPaths) {
|
|
647
788
|
try {
|
|
648
|
-
|
|
789
|
+
const content = fs3.readFileSync(path3.join(dir, relPath), "utf-8");
|
|
790
|
+
if (content.split("\n").length <= 500) fileContents.set(relPath, content);
|
|
649
791
|
} catch {
|
|
650
|
-
continue;
|
|
651
792
|
}
|
|
652
|
-
|
|
793
|
+
}
|
|
794
|
+
const importCounts = buildImportCounts(fileContents);
|
|
795
|
+
const gitFreq = getGitFrequency(dir);
|
|
796
|
+
const scored = [];
|
|
797
|
+
let compressedChars = 0;
|
|
798
|
+
for (const [relPath, rawContent] of fileContents) {
|
|
653
799
|
const ext = path3.extname(relPath).toLowerCase();
|
|
654
800
|
const compressed = compressContent(rawContent, ext);
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
801
|
+
const skeleton = extractSkeleton(compressed, ext);
|
|
802
|
+
compressedChars += compressed.length;
|
|
803
|
+
const priorityScore = filePriority(relPath);
|
|
804
|
+
const importScore = Math.min(importCounts.get(relPath) || 0, 20) * 2;
|
|
805
|
+
const gitScore = Math.min(gitFreq.get(relPath) || 0, 10) * 3;
|
|
806
|
+
const score = priorityScore + importScore + gitScore;
|
|
807
|
+
scored.push({ path: relPath, rawContent, compressed, skeleton, ext, score });
|
|
808
|
+
}
|
|
809
|
+
scored.sort((a, b) => b.score - a.score);
|
|
810
|
+
const dirGroups = groupByDirectory(scored);
|
|
811
|
+
const result = [];
|
|
663
812
|
let includedChars = 0;
|
|
664
|
-
let
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
813
|
+
let dupGroups = 0;
|
|
814
|
+
for (const [dirPath, group] of dirGroups) {
|
|
815
|
+
if (group.length === 0) continue;
|
|
816
|
+
const rep = group[0];
|
|
817
|
+
const repFP = structuralFingerprint(rep.compressed, rep.ext);
|
|
818
|
+
const similar = group.slice(1).filter((f) => structuralFingerprint(f.compressed, f.ext) === repFP);
|
|
819
|
+
const unique = group.slice(1).filter((f) => structuralFingerprint(f.compressed, f.ext) !== repFP);
|
|
820
|
+
const repEntry = { path: rep.path, content: rep.compressed, size: rep.compressed.length };
|
|
821
|
+
const repSize = rep.path.length + rep.compressed.length + 10;
|
|
822
|
+
if (includedChars + repSize <= CHAR_BUDGET) {
|
|
823
|
+
result.push(repEntry);
|
|
824
|
+
includedChars += repSize;
|
|
825
|
+
}
|
|
826
|
+
if (similar.length > 0) {
|
|
827
|
+
dupGroups++;
|
|
828
|
+
const names = similar.map((f) => path3.basename(f.path));
|
|
829
|
+
const summary = `(${similar.length} similar file${similar.length === 1 ? "" : "s"} in ${dirPath}/: ${names.join(", ")})`;
|
|
830
|
+
const summarySize = summary.length + 30;
|
|
831
|
+
if (includedChars + summarySize <= CHAR_BUDGET) {
|
|
832
|
+
result.push({ path: `[similar to ${rep.path}]`, content: summary, size: summary.length });
|
|
833
|
+
includedChars += summarySize;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
for (const f of unique) {
|
|
837
|
+
const skeletonSize = f.path.length + f.skeleton.length + 10;
|
|
838
|
+
if (includedChars + skeletonSize <= CHAR_BUDGET) {
|
|
839
|
+
result.push({ path: f.path, content: f.skeleton, size: f.skeleton.length });
|
|
840
|
+
includedChars += skeletonSize;
|
|
841
|
+
}
|
|
671
842
|
}
|
|
672
|
-
|
|
673
|
-
|
|
843
|
+
}
|
|
844
|
+
const includedPaths = new Set(result.map((f) => f.path));
|
|
845
|
+
for (const f of scored) {
|
|
846
|
+
if (includedPaths.has(f.path)) continue;
|
|
847
|
+
const skeletonSize = f.path.length + f.skeleton.length + 10;
|
|
848
|
+
if (includedChars + skeletonSize > CHAR_BUDGET) continue;
|
|
849
|
+
result.push({ path: f.path, content: f.skeleton, size: f.skeleton.length });
|
|
850
|
+
includedChars += skeletonSize;
|
|
674
851
|
}
|
|
675
852
|
return {
|
|
676
|
-
files,
|
|
677
|
-
truncated,
|
|
853
|
+
files: result,
|
|
854
|
+
truncated: includedChars >= CHAR_BUDGET * 0.95,
|
|
678
855
|
totalProjectTokens: Math.ceil(totalChars / 4),
|
|
679
|
-
|
|
856
|
+
compressedTokens: Math.ceil(compressedChars / 4),
|
|
857
|
+
includedTokens: Math.ceil(includedChars / 4),
|
|
858
|
+
filesAnalyzed: fileContents.size,
|
|
859
|
+
filesIncluded: result.length,
|
|
860
|
+
duplicateGroups: dupGroups
|
|
680
861
|
};
|
|
681
862
|
}
|
|
682
863
|
function walkDir(base, rel, depth, maxDepth, files) {
|
|
@@ -704,8 +885,9 @@ function walkDir(base, rel, depth, maxDepth, files) {
|
|
|
704
885
|
}
|
|
705
886
|
}
|
|
706
887
|
}
|
|
707
|
-
function
|
|
708
|
-
const
|
|
888
|
+
function filePriority(filePath) {
|
|
889
|
+
const base = path3.basename(filePath);
|
|
890
|
+
const entryPoints = /* @__PURE__ */ new Set([
|
|
709
891
|
"index.ts",
|
|
710
892
|
"index.js",
|
|
711
893
|
"index.tsx",
|
|
@@ -722,22 +904,13 @@ function sortByPriority(files) {
|
|
|
722
904
|
"mod.rs",
|
|
723
905
|
"lib.rs"
|
|
724
906
|
]);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
if (entryPointNames.has(base)) return 0;
|
|
733
|
-
if (configPattern.test(filePath)) return 1;
|
|
734
|
-
if (routePattern.test(filePath)) return 2;
|
|
735
|
-
if (schemaPattern.test(filePath)) return 3;
|
|
736
|
-
if (servicePattern.test(filePath)) return 4;
|
|
737
|
-
if (testPattern.test(filePath)) return 6;
|
|
738
|
-
return 5;
|
|
739
|
-
}
|
|
740
|
-
files.sort((a, b) => priority(a) - priority(b));
|
|
907
|
+
if (entryPoints.has(base)) return 40;
|
|
908
|
+
if (/\.(json|ya?ml|toml|ini|cfg|env)$|config\.|Makefile|Dockerfile/i.test(filePath)) return 35;
|
|
909
|
+
if (/(route|api|controller|endpoint|handler)/i.test(filePath)) return 30;
|
|
910
|
+
if (/(types|schema|models|entities|migration)/i.test(filePath)) return 25;
|
|
911
|
+
if (/(service|lib|utils|helper|middleware)/i.test(filePath)) return 20;
|
|
912
|
+
if (/(test|spec|__tests__|_test\.|\.test\.)/i.test(filePath)) return 5;
|
|
913
|
+
return 15;
|
|
741
914
|
}
|
|
742
915
|
|
|
743
916
|
// src/llm/index.ts
|
|
@@ -1019,7 +1192,7 @@ var OpenAICompatProvider = class {
|
|
|
1019
1192
|
};
|
|
1020
1193
|
|
|
1021
1194
|
// src/llm/cursor-acp.ts
|
|
1022
|
-
import { spawn, execSync as
|
|
1195
|
+
import { spawn, execSync as execSync3 } from "child_process";
|
|
1023
1196
|
import readline from "readline";
|
|
1024
1197
|
var ACP_AGENT_BIN = "agent";
|
|
1025
1198
|
var CursorAcpProvider = class {
|
|
@@ -1169,7 +1342,7 @@ ${msg.content}
|
|
|
1169
1342
|
};
|
|
1170
1343
|
function isCursorAgentAvailable() {
|
|
1171
1344
|
try {
|
|
1172
|
-
|
|
1345
|
+
execSync3(`which ${ACP_AGENT_BIN}`, { stdio: "ignore" });
|
|
1173
1346
|
return true;
|
|
1174
1347
|
} catch {
|
|
1175
1348
|
return false;
|
|
@@ -1177,7 +1350,7 @@ function isCursorAgentAvailable() {
|
|
|
1177
1350
|
}
|
|
1178
1351
|
|
|
1179
1352
|
// src/llm/claude-cli.ts
|
|
1180
|
-
import { spawn as spawn2, execSync as
|
|
1353
|
+
import { spawn as spawn2, execSync as execSync4 } from "child_process";
|
|
1181
1354
|
var CLAUDE_CLI_BIN = "claude";
|
|
1182
1355
|
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
1183
1356
|
var ClaudeCliProvider = class {
|
|
@@ -1296,7 +1469,7 @@ ${msg.content}
|
|
|
1296
1469
|
function isClaudeCliAvailable() {
|
|
1297
1470
|
try {
|
|
1298
1471
|
const cmd = process.platform === "win32" ? `where ${CLAUDE_CLI_BIN}` : `which ${CLAUDE_CLI_BIN}`;
|
|
1299
|
-
|
|
1472
|
+
execSync4(cmd, { stdio: "ignore" });
|
|
1300
1473
|
return true;
|
|
1301
1474
|
} catch {
|
|
1302
1475
|
return false;
|
|
@@ -3030,10 +3203,10 @@ import select2 from "@inquirer/select";
|
|
|
3030
3203
|
import { createTwoFilesPatch } from "diff";
|
|
3031
3204
|
|
|
3032
3205
|
// src/utils/editor.ts
|
|
3033
|
-
import { execSync as
|
|
3206
|
+
import { execSync as execSync5, spawn as spawn3 } from "child_process";
|
|
3034
3207
|
function commandExists(cmd) {
|
|
3035
3208
|
try {
|
|
3036
|
-
|
|
3209
|
+
execSync5(`which ${cmd}`, { stdio: "ignore" });
|
|
3037
3210
|
return true;
|
|
3038
3211
|
} catch {
|
|
3039
3212
|
return false;
|
|
@@ -3333,11 +3506,11 @@ ${agentRefs.join(" ")}
|
|
|
3333
3506
|
// src/lib/hooks.ts
|
|
3334
3507
|
import fs17 from "fs";
|
|
3335
3508
|
import path12 from "path";
|
|
3336
|
-
import { execSync as
|
|
3509
|
+
import { execSync as execSync7 } from "child_process";
|
|
3337
3510
|
|
|
3338
3511
|
// src/lib/resolve-caliber.ts
|
|
3339
3512
|
import fs16 from "fs";
|
|
3340
|
-
import { execSync as
|
|
3513
|
+
import { execSync as execSync6 } from "child_process";
|
|
3341
3514
|
var _resolved = null;
|
|
3342
3515
|
function resolveCaliber() {
|
|
3343
3516
|
if (_resolved) return _resolved;
|
|
@@ -3347,7 +3520,7 @@ function resolveCaliber() {
|
|
|
3347
3520
|
return _resolved;
|
|
3348
3521
|
}
|
|
3349
3522
|
try {
|
|
3350
|
-
const found =
|
|
3523
|
+
const found = execSync6("which caliber", {
|
|
3351
3524
|
encoding: "utf-8",
|
|
3352
3525
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3353
3526
|
}).trim();
|
|
@@ -3452,7 +3625,7 @@ ${PRECOMMIT_END}`;
|
|
|
3452
3625
|
}
|
|
3453
3626
|
function getGitHooksDir() {
|
|
3454
3627
|
try {
|
|
3455
|
-
const gitDir =
|
|
3628
|
+
const gitDir = execSync7("git rev-parse --git-dir", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3456
3629
|
return path12.join(gitDir, "hooks");
|
|
3457
3630
|
} catch {
|
|
3458
3631
|
return null;
|
|
@@ -3596,7 +3769,7 @@ function removeLearningHooks() {
|
|
|
3596
3769
|
init_constants();
|
|
3597
3770
|
import fs19 from "fs";
|
|
3598
3771
|
import path14 from "path";
|
|
3599
|
-
import { execSync as
|
|
3772
|
+
import { execSync as execSync8 } from "child_process";
|
|
3600
3773
|
var STATE_FILE = path14.join(CALIBER_DIR, ".caliber-state.json");
|
|
3601
3774
|
function normalizeTargetAgent(value) {
|
|
3602
3775
|
if (Array.isArray(value)) return value;
|
|
@@ -3624,7 +3797,7 @@ function writeState(state) {
|
|
|
3624
3797
|
}
|
|
3625
3798
|
function getCurrentHeadSha() {
|
|
3626
3799
|
try {
|
|
3627
|
-
return
|
|
3800
|
+
return execSync8("git rev-parse HEAD", {
|
|
3628
3801
|
encoding: "utf-8",
|
|
3629
3802
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3630
3803
|
}).trim();
|
|
@@ -4547,7 +4720,7 @@ function checkGrounding(dir) {
|
|
|
4547
4720
|
|
|
4548
4721
|
// src/scoring/checks/accuracy.ts
|
|
4549
4722
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
4550
|
-
import { execSync as
|
|
4723
|
+
import { execSync as execSync9 } from "child_process";
|
|
4551
4724
|
import { join as join5 } from "path";
|
|
4552
4725
|
function validateReferences(dir) {
|
|
4553
4726
|
const configContent = collectPrimaryConfigContent(dir);
|
|
@@ -4579,13 +4752,13 @@ function validateReferences(dir) {
|
|
|
4579
4752
|
}
|
|
4580
4753
|
function detectGitDrift(dir) {
|
|
4581
4754
|
try {
|
|
4582
|
-
|
|
4755
|
+
execSync9("git rev-parse --git-dir", { cwd: dir, stdio: ["pipe", "pipe", "pipe"] });
|
|
4583
4756
|
} catch {
|
|
4584
4757
|
return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: false };
|
|
4585
4758
|
}
|
|
4586
4759
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules", ".cursor/rules"];
|
|
4587
4760
|
try {
|
|
4588
|
-
const headTimestamp =
|
|
4761
|
+
const headTimestamp = execSync9(
|
|
4589
4762
|
"git log -1 --format=%ct HEAD",
|
|
4590
4763
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4591
4764
|
).trim();
|
|
@@ -4606,7 +4779,7 @@ function detectGitDrift(dir) {
|
|
|
4606
4779
|
let latestConfigCommitHash = null;
|
|
4607
4780
|
for (const file of configFiles) {
|
|
4608
4781
|
try {
|
|
4609
|
-
const hash =
|
|
4782
|
+
const hash = execSync9(
|
|
4610
4783
|
`git log -1 --format=%H -- "${file}"`,
|
|
4611
4784
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4612
4785
|
).trim();
|
|
@@ -4615,7 +4788,7 @@ function detectGitDrift(dir) {
|
|
|
4615
4788
|
latestConfigCommitHash = hash;
|
|
4616
4789
|
} else {
|
|
4617
4790
|
try {
|
|
4618
|
-
|
|
4791
|
+
execSync9(
|
|
4619
4792
|
`git merge-base --is-ancestor ${latestConfigCommitHash} ${hash}`,
|
|
4620
4793
|
{ cwd: dir, stdio: ["pipe", "pipe", "pipe"] }
|
|
4621
4794
|
);
|
|
@@ -4630,12 +4803,12 @@ function detectGitDrift(dir) {
|
|
|
4630
4803
|
return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: true };
|
|
4631
4804
|
}
|
|
4632
4805
|
try {
|
|
4633
|
-
const countStr =
|
|
4806
|
+
const countStr = execSync9(
|
|
4634
4807
|
`git rev-list --count ${latestConfigCommitHash}..HEAD`,
|
|
4635
4808
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4636
4809
|
).trim();
|
|
4637
4810
|
const commitsSince = parseInt(countStr, 10) || 0;
|
|
4638
|
-
const lastDate =
|
|
4811
|
+
const lastDate = execSync9(
|
|
4639
4812
|
`git log -1 --format=%ci ${latestConfigCommitHash}`,
|
|
4640
4813
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4641
4814
|
).trim();
|
|
@@ -4707,12 +4880,12 @@ function checkAccuracy(dir) {
|
|
|
4707
4880
|
|
|
4708
4881
|
// src/scoring/checks/freshness.ts
|
|
4709
4882
|
import { existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
4710
|
-
import { execSync as
|
|
4883
|
+
import { execSync as execSync10 } from "child_process";
|
|
4711
4884
|
import { join as join6 } from "path";
|
|
4712
4885
|
function getCommitsSinceConfigUpdate(dir) {
|
|
4713
4886
|
const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules"];
|
|
4714
4887
|
try {
|
|
4715
|
-
const headTimestamp =
|
|
4888
|
+
const headTimestamp = execSync10(
|
|
4716
4889
|
"git log -1 --format=%ct HEAD",
|
|
4717
4890
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4718
4891
|
).trim();
|
|
@@ -4732,12 +4905,12 @@ function getCommitsSinceConfigUpdate(dir) {
|
|
|
4732
4905
|
}
|
|
4733
4906
|
for (const file of configFiles) {
|
|
4734
4907
|
try {
|
|
4735
|
-
const hash =
|
|
4908
|
+
const hash = execSync10(
|
|
4736
4909
|
`git log -1 --format=%H -- "${file}"`,
|
|
4737
4910
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4738
4911
|
).trim();
|
|
4739
4912
|
if (hash) {
|
|
4740
|
-
const countStr =
|
|
4913
|
+
const countStr = execSync10(
|
|
4741
4914
|
`git rev-list --count ${hash}..HEAD`,
|
|
4742
4915
|
{ cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4743
4916
|
).trim();
|
|
@@ -4855,11 +5028,11 @@ function checkFreshness(dir) {
|
|
|
4855
5028
|
|
|
4856
5029
|
// src/scoring/checks/bonus.ts
|
|
4857
5030
|
import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
|
|
4858
|
-
import { execSync as
|
|
5031
|
+
import { execSync as execSync11 } from "child_process";
|
|
4859
5032
|
import { join as join7 } from "path";
|
|
4860
5033
|
function hasPreCommitHook(dir) {
|
|
4861
5034
|
try {
|
|
4862
|
-
const gitDir =
|
|
5035
|
+
const gitDir = execSync11("git rev-parse --git-dir", { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
4863
5036
|
const hookPath = join7(gitDir, "hooks", "pre-commit");
|
|
4864
5037
|
const content = readFileOrNull2(hookPath);
|
|
4865
5038
|
return content ? content.includes("caliber") : false;
|
|
@@ -5327,7 +5500,7 @@ import fs22 from "fs";
|
|
|
5327
5500
|
import path17 from "path";
|
|
5328
5501
|
import os3 from "os";
|
|
5329
5502
|
import crypto3 from "crypto";
|
|
5330
|
-
import { execSync as
|
|
5503
|
+
import { execSync as execSync12 } from "child_process";
|
|
5331
5504
|
var CONFIG_DIR2 = path17.join(os3.homedir(), ".caliber");
|
|
5332
5505
|
var CONFIG_FILE2 = path17.join(CONFIG_DIR2, "config.json");
|
|
5333
5506
|
var runtimeDisabled = false;
|
|
@@ -5354,7 +5527,7 @@ function getMachineId() {
|
|
|
5354
5527
|
}
|
|
5355
5528
|
function getGitEmailHash() {
|
|
5356
5529
|
try {
|
|
5357
|
-
const email =
|
|
5530
|
+
const email = execSync12("git config user.email", { encoding: "utf-8" }).trim();
|
|
5358
5531
|
if (!email) return void 0;
|
|
5359
5532
|
return crypto3.createHash("sha256").update(email).digest("hex");
|
|
5360
5533
|
} catch {
|
|
@@ -6169,15 +6342,25 @@ async function initCommand(options) {
|
|
|
6169
6342
|
spinner.succeed("Project analyzed");
|
|
6170
6343
|
log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
|
|
6171
6344
|
if (options.verbose && fingerprint.codeAnalysis) {
|
|
6172
|
-
log(options.verbose, `Code analysis: ${fingerprint.codeAnalysis.
|
|
6345
|
+
log(options.verbose, `Code analysis: ${fingerprint.codeAnalysis.filesIncluded}/${fingerprint.codeAnalysis.filesAnalyzed} files, ~${fingerprint.codeAnalysis.includedTokens.toLocaleString()} tokens, ${fingerprint.codeAnalysis.duplicateGroups} dedup groups`);
|
|
6173
6346
|
}
|
|
6174
6347
|
trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
|
|
6175
6348
|
console.log(chalk8.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
|
|
6176
6349
|
console.log(chalk8.dim(` Files: ${fingerprint.fileTree.length} found`));
|
|
6177
6350
|
if (fingerprint.codeAnalysis) {
|
|
6178
6351
|
const ca = fingerprint.codeAnalysis;
|
|
6179
|
-
const
|
|
6180
|
-
|
|
6352
|
+
const compressionPct = ca.totalProjectTokens > 0 ? Math.round((1 - ca.compressedTokens / ca.totalProjectTokens) * 100) : 0;
|
|
6353
|
+
const parts = [`Context: ~${ca.includedTokens.toLocaleString()} tokens sent`];
|
|
6354
|
+
if (ca.truncated) {
|
|
6355
|
+
parts.push(`(${Math.round(ca.includedTokens / ca.totalProjectTokens * 100)}% of ${ca.totalProjectTokens.toLocaleString()} total)`);
|
|
6356
|
+
}
|
|
6357
|
+
if (compressionPct > 5) {
|
|
6358
|
+
parts.push(`compressed ${compressionPct}%`);
|
|
6359
|
+
}
|
|
6360
|
+
if (ca.duplicateGroups > 0) {
|
|
6361
|
+
parts.push(`${ca.duplicateGroups} duplicate group${ca.duplicateGroups === 1 ? "" : "s"} merged`);
|
|
6362
|
+
}
|
|
6363
|
+
console.log(chalk8.dim(` ${parts.join(" \xB7 ")}`));
|
|
6181
6364
|
}
|
|
6182
6365
|
console.log("");
|
|
6183
6366
|
if (report) {
|
|
@@ -7152,7 +7335,7 @@ import chalk13 from "chalk";
|
|
|
7152
7335
|
import ora5 from "ora";
|
|
7153
7336
|
|
|
7154
7337
|
// src/lib/git-diff.ts
|
|
7155
|
-
import { execSync as
|
|
7338
|
+
import { execSync as execSync13 } from "child_process";
|
|
7156
7339
|
var MAX_DIFF_BYTES = 1e5;
|
|
7157
7340
|
var DOC_PATTERNS = [
|
|
7158
7341
|
"CLAUDE.md",
|
|
@@ -7166,7 +7349,7 @@ function excludeArgs() {
|
|
|
7166
7349
|
}
|
|
7167
7350
|
function safeExec(cmd) {
|
|
7168
7351
|
try {
|
|
7169
|
-
return
|
|
7352
|
+
return execSync13(cmd, {
|
|
7170
7353
|
encoding: "utf-8",
|
|
7171
7354
|
stdio: ["pipe", "pipe", "pipe"],
|
|
7172
7355
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -8093,7 +8276,7 @@ learn.command("status").description("Show learning system status").action(tracke
|
|
|
8093
8276
|
import fs32 from "fs";
|
|
8094
8277
|
import path26 from "path";
|
|
8095
8278
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8096
|
-
import { execSync as
|
|
8279
|
+
import { execSync as execSync14 } from "child_process";
|
|
8097
8280
|
import chalk17 from "chalk";
|
|
8098
8281
|
import ora6 from "ora";
|
|
8099
8282
|
import confirm2 from "@inquirer/confirm";
|
|
@@ -8103,7 +8286,7 @@ var pkg2 = JSON.parse(
|
|
|
8103
8286
|
);
|
|
8104
8287
|
function getInstalledVersion() {
|
|
8105
8288
|
try {
|
|
8106
|
-
const globalRoot =
|
|
8289
|
+
const globalRoot = execSync14("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
8107
8290
|
const pkgPath = path26.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
8108
8291
|
return JSON.parse(fs32.readFileSync(pkgPath, "utf-8")).version;
|
|
8109
8292
|
} catch {
|
|
@@ -8148,7 +8331,7 @@ Update available: ${current} -> ${latest}`)
|
|
|
8148
8331
|
}
|
|
8149
8332
|
const spinner = ora6("Updating caliber...").start();
|
|
8150
8333
|
try {
|
|
8151
|
-
|
|
8334
|
+
execSync14(`npm install -g @rely-ai/caliber@${latest}`, {
|
|
8152
8335
|
stdio: "pipe",
|
|
8153
8336
|
timeout: 12e4,
|
|
8154
8337
|
env: { ...process.env, npm_config_fund: "false", npm_config_audit: "false" }
|
|
@@ -8165,7 +8348,7 @@ Update available: ${current} -> ${latest}`)
|
|
|
8165
8348
|
console.log(chalk17.dim(`
|
|
8166
8349
|
Restarting: caliber ${args.join(" ")}
|
|
8167
8350
|
`));
|
|
8168
|
-
|
|
8351
|
+
execSync14(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
8169
8352
|
stdio: "inherit",
|
|
8170
8353
|
env: { ...process.env, CALIBER_SKIP_UPDATE_CHECK: "1" }
|
|
8171
8354
|
});
|
package/package.json
CHANGED