@rely-ai/caliber 1.22.0 → 1.22.1-dev.1773778672

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 +109 -30
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -285,9 +285,26 @@ var IGNORE_DIRS = /* @__PURE__ */ new Set([
285
285
  "target"
286
286
  ]);
287
287
  function getFileTree(dir, maxDepth = 3) {
288
+ const entries = [];
289
+ scan(dir, "", 0, maxDepth, entries);
290
+ const dirs = [];
288
291
  const files = [];
289
- scan(dir, "", 0, maxDepth, files);
290
- return files;
292
+ for (const e of entries) {
293
+ (e.isDir ? dirs : files).push(e);
294
+ }
295
+ for (const d of dirs) {
296
+ const prefix = d.relPath;
297
+ let maxChildMtime = d.mtime;
298
+ for (const f of files) {
299
+ if (f.relPath.startsWith(prefix) && f.mtime > maxChildMtime) {
300
+ maxChildMtime = f.mtime;
301
+ }
302
+ }
303
+ d.mtime = maxChildMtime;
304
+ }
305
+ dirs.sort((a, b) => b.mtime - a.mtime);
306
+ files.sort((a, b) => b.mtime - a.mtime);
307
+ return [...dirs.map((e) => e.relPath), ...files.map((e) => e.relPath)];
291
308
  }
292
309
  function scan(base, rel, depth, maxDepth, result) {
293
310
  if (depth > maxDepth) return;
@@ -302,11 +319,17 @@ function scan(base, rel, depth, maxDepth, result) {
302
319
  if (entry.name.startsWith(".") && depth === 0 && entry.isDirectory()) continue;
303
320
  if (IGNORE_DIRS.has(entry.name)) continue;
304
321
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
322
+ const entryPath = path.join(base, relPath);
323
+ let mtime = 0;
324
+ try {
325
+ mtime = fs.statSync(entryPath).mtimeMs;
326
+ } catch {
327
+ }
305
328
  if (entry.isDirectory()) {
306
- result.push(`${relPath}/`);
329
+ result.push({ relPath: `${relPath}/`, isDir: true, mtime });
307
330
  scan(base, relPath, depth + 1, maxDepth, result);
308
331
  } else {
309
- result.push(relPath);
332
+ result.push({ relPath, isDir: false, mtime });
310
333
  }
311
334
  }
312
335
  }
@@ -584,7 +607,7 @@ var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
584
607
  ".swift",
585
608
  ".php"
586
609
  ]);
587
- var TOKEN_BUDGET = 18e4;
610
+ var TOKEN_BUDGET = 8e4;
588
611
  var CHAR_BUDGET = TOKEN_BUDGET * 4;
589
612
  function compressContent(content, ext) {
590
613
  const cp = EXT_COMMENT[ext] ? COMMENT_LINE[EXT_COMMENT[ext]] : null;
@@ -829,7 +852,7 @@ function analyzeCode(dir) {
829
852
  const repFP = structuralFingerprint(rep.compressed, rep.ext);
830
853
  const similar = group.slice(1).filter((f) => structuralFingerprint(f.compressed, f.ext) === repFP);
831
854
  const unique = group.slice(1).filter((f) => structuralFingerprint(f.compressed, f.ext) !== repFP);
832
- const repEntry = { path: rep.path, content: rep.compressed, size: rep.compressed.length };
855
+ const repEntry = { path: rep.path, content: rep.compressed, size: rep.compressed.length, priority: rep.score };
833
856
  const repSize = rep.path.length + rep.compressed.length + 10;
834
857
  if (includedChars + repSize <= CHAR_BUDGET) {
835
858
  result.push(repEntry);
@@ -841,14 +864,14 @@ function analyzeCode(dir) {
841
864
  const summary = `(${similar.length} similar file${similar.length === 1 ? "" : "s"} in ${dirPath}/: ${names.join(", ")})`;
842
865
  const summarySize = summary.length + 30;
843
866
  if (includedChars + summarySize <= CHAR_BUDGET) {
844
- result.push({ path: `[similar to ${rep.path}]`, content: summary, size: summary.length });
867
+ result.push({ path: `[similar to ${rep.path}]`, content: summary, size: summary.length, priority: rep.score });
845
868
  includedChars += summarySize;
846
869
  }
847
870
  }
848
871
  for (const f of unique) {
849
872
  const skeletonSize = f.path.length + f.skeleton.length + 10;
850
873
  if (includedChars + skeletonSize <= CHAR_BUDGET) {
851
- result.push({ path: f.path, content: f.skeleton, size: f.skeleton.length });
874
+ result.push({ path: f.path, content: f.skeleton, size: f.skeleton.length, priority: f.score });
852
875
  includedChars += skeletonSize;
853
876
  }
854
877
  }
@@ -858,7 +881,7 @@ function analyzeCode(dir) {
858
881
  if (includedPaths.has(f.path)) continue;
859
882
  const skeletonSize = f.path.length + f.skeleton.length + 10;
860
883
  if (includedChars + skeletonSize > CHAR_BUDGET) continue;
861
- result.push({ path: f.path, content: f.skeleton, size: f.skeleton.length });
884
+ result.push({ path: f.path, content: f.skeleton, size: f.skeleton.length, priority: f.score });
862
885
  includedChars += skeletonSize;
863
886
  }
864
887
  return {
@@ -2700,6 +2723,7 @@ async function generateSkillsForSetup(setup, fingerprint, targetAgent, onStatus)
2700
2723
  if (failed > 0) onStatus?.(`${succeeded} generated, ${failed} failed`);
2701
2724
  return succeeded;
2702
2725
  }
2726
+ var MAX_PROMPT_TOKENS = 12e4;
2703
2727
  var LIMITS = {
2704
2728
  FILE_TREE_ENTRIES: 500,
2705
2729
  EXISTING_CONFIG_CHARS: 8e3,
@@ -2712,6 +2736,41 @@ function truncate(text, maxChars) {
2712
2736
  return text.slice(0, maxChars) + `
2713
2737
  ... (truncated at ${maxChars} chars)`;
2714
2738
  }
2739
+ function sampleFileTree(fileTree, codeAnalysisPaths, limit) {
2740
+ if (fileTree.length <= limit) return fileTree;
2741
+ const dirs = [];
2742
+ const rootFiles = [];
2743
+ const nestedFiles = [];
2744
+ for (const entry of fileTree) {
2745
+ if (entry.endsWith("/")) {
2746
+ dirs.push(entry);
2747
+ } else if (!entry.includes("/")) {
2748
+ rootFiles.push(entry);
2749
+ } else {
2750
+ nestedFiles.push(entry);
2751
+ }
2752
+ }
2753
+ const result = [];
2754
+ const included = /* @__PURE__ */ new Set();
2755
+ function add(entry) {
2756
+ if (!included.has(entry)) {
2757
+ included.add(entry);
2758
+ result.push(entry);
2759
+ }
2760
+ }
2761
+ const dirBudget = Math.min(dirs.length, Math.floor(limit * 0.4));
2762
+ for (let i = 0; i < dirBudget; i++) add(dirs[i]);
2763
+ for (const f of rootFiles.slice(0, 50)) add(f);
2764
+ for (const p of codeAnalysisPaths) {
2765
+ if (result.length >= limit) break;
2766
+ if (fileTree.includes(p)) add(p);
2767
+ }
2768
+ for (const f of nestedFiles) {
2769
+ if (result.length >= limit) break;
2770
+ add(f);
2771
+ }
2772
+ return result.slice(0, limit);
2773
+ }
2715
2774
  function buildGeneratePrompt(fingerprint, targetAgent, prompt, failingChecks, currentScore, passingChecks) {
2716
2775
  const parts = [];
2717
2776
  const existing = fingerprint.existingConfigs;
@@ -2763,9 +2822,10 @@ Git remote: ${fingerprint.gitRemoteUrl}`);
2763
2822
  if (fingerprint.frameworks.length > 0) parts.push(`Frameworks: ${fingerprint.frameworks.join(", ")}`);
2764
2823
  if (fingerprint.description) parts.push(`Project description: ${fingerprint.description}`);
2765
2824
  if (fingerprint.fileTree.length > 0) {
2766
- const tree = fingerprint.fileTree.slice(0, LIMITS.FILE_TREE_ENTRIES);
2825
+ const caPaths = fingerprint.codeAnalysis?.files.map((f) => f.path) ?? [];
2826
+ const tree = sampleFileTree(fingerprint.fileTree, caPaths, LIMITS.FILE_TREE_ENTRIES);
2767
2827
  parts.push(`
2768
- File tree (top-level, ${tree.length}/${fingerprint.fileTree.length}):
2828
+ File tree (${tree.length}/${fingerprint.fileTree.length}):
2769
2829
  ${tree.join("\n")}`);
2770
2830
  }
2771
2831
  if (existing.claudeMd) parts.push(`
@@ -2816,23 +2876,6 @@ ${truncate(skill.content, LIMITS.SKILL_CHARS)}`);
2816
2876
  (${existing.cursorSkills.length - LIMITS.SKILLS_MAX} more skills omitted)`);
2817
2877
  }
2818
2878
  }
2819
- if (fingerprint.codeAnalysis) {
2820
- const ca = fingerprint.codeAnalysis;
2821
- if (ca.truncated) {
2822
- const pct = ca.totalProjectTokens > 0 ? Math.round(ca.includedTokens / ca.totalProjectTokens * 100) : 100;
2823
- parts.push(`
2824
- --- Project Files (trimmed to ~${ca.includedTokens.toLocaleString()}/${ca.totalProjectTokens.toLocaleString()} tokens, ${pct}% of total) ---`);
2825
- } else {
2826
- parts.push(`
2827
- --- Project Files (${ca.files.length} files, ~${ca.includedTokens.toLocaleString()} tokens) ---`);
2828
- }
2829
- parts.push("Study these files to extract patterns for skills. Use the exact code patterns you see here.\n");
2830
- for (const f of ca.files) {
2831
- parts.push(`[${f.path}]`);
2832
- parts.push(f.content);
2833
- parts.push("");
2834
- }
2835
- }
2836
2879
  const allDeps = extractAllDeps(process.cwd());
2837
2880
  if (allDeps.length > 0) {
2838
2881
  parts.push(`
@@ -2841,6 +2884,42 @@ Project dependencies (${allDeps.length}):`);
2841
2884
  }
2842
2885
  if (prompt) parts.push(`
2843
2886
  User instructions: ${prompt}`);
2887
+ if (fingerprint.codeAnalysis) {
2888
+ const ca = fingerprint.codeAnalysis;
2889
+ const basePrompt = parts.join("\n");
2890
+ const baseTokens = estimateTokens(basePrompt);
2891
+ const tokenBudgetForCode = Math.max(0, MAX_PROMPT_TOKENS - baseTokens);
2892
+ const codeLines = [];
2893
+ let codeChars = 0;
2894
+ codeLines.push("Study these files to extract patterns for skills. Use the exact code patterns you see here.\n");
2895
+ const sortedFiles = [...ca.files].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
2896
+ let includedFiles = 0;
2897
+ for (const f of sortedFiles) {
2898
+ const entry = `[${f.path}]
2899
+ ${f.content}
2900
+ `;
2901
+ if (estimateTokens(codeLines.join("\n") + entry) > tokenBudgetForCode && includedFiles > 0) break;
2902
+ codeLines.push(entry);
2903
+ codeChars += f.content.length;
2904
+ includedFiles++;
2905
+ }
2906
+ const includedTokens = Math.ceil(codeChars / 4);
2907
+ let header;
2908
+ if (includedFiles < ca.files.length) {
2909
+ const pct = ca.totalProjectTokens > 0 ? Math.round(includedTokens / ca.totalProjectTokens * 100) : 100;
2910
+ header = `
2911
+ --- Project Files (trimmed to ~${includedTokens.toLocaleString()}/${ca.totalProjectTokens.toLocaleString()} tokens, ${pct}% of total) ---`;
2912
+ } else if (ca.truncated) {
2913
+ const pct = ca.totalProjectTokens > 0 ? Math.round(ca.includedTokens / ca.totalProjectTokens * 100) : 100;
2914
+ header = `
2915
+ --- Project Files (trimmed to ~${ca.includedTokens.toLocaleString()}/${ca.totalProjectTokens.toLocaleString()} tokens, ${pct}% of total) ---`;
2916
+ } else {
2917
+ header = `
2918
+ --- Project Files (${ca.files.length} files, ~${ca.includedTokens.toLocaleString()} tokens) ---`;
2919
+ }
2920
+ parts.push(header);
2921
+ parts.push(codeLines.join("\n"));
2922
+ }
2844
2923
  return parts.join("\n");
2845
2924
  }
2846
2925
 
@@ -9162,7 +9241,7 @@ function sanitizeSecrets(text) {
9162
9241
 
9163
9242
  // src/ai/learn.ts
9164
9243
  init_config();
9165
- var MAX_PROMPT_TOKENS = 1e5;
9244
+ var MAX_PROMPT_TOKENS2 = 1e5;
9166
9245
  function formatEventsForPrompt(events) {
9167
9246
  return events.map((e, i) => {
9168
9247
  if (e.hook_event_name === "UserPromptSubmit") {
@@ -9210,7 +9289,7 @@ function parseAnalysisResponse(raw) {
9210
9289
  }
9211
9290
  }
9212
9291
  async function analyzeEvents(events, existingClaudeMd, existingLearnedSection, existingSkills) {
9213
- const fittedEvents = trimEventsToFit(events, MAX_PROMPT_TOKENS - 1e4);
9292
+ const fittedEvents = trimEventsToFit(events, MAX_PROMPT_TOKENS2 - 1e4);
9214
9293
  const eventsText = formatEventsForPrompt(fittedEvents);
9215
9294
  const contextParts = [];
9216
9295
  if (existingClaudeMd) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.22.0",
3
+ "version": "1.22.1-dev.1773778672",
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": {