@rely-ai/caliber 1.13.1 → 1.14.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 +169 -298
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -408,117 +408,145 @@ var IGNORE_DIRS2 = /* @__PURE__ */ new Set([
408
408
  ".caliber",
409
409
  "__pycache__",
410
410
  ".venv",
411
+ "venv",
412
+ "env",
411
413
  "vendor",
412
- "target"
414
+ "target",
415
+ ".parcel-cache",
416
+ ".nyc_output",
417
+ ".claude",
418
+ ".cursor",
419
+ ".agents",
420
+ ".codex"
413
421
  ]);
414
- var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".py"]);
415
- var CONFIG_FILE_NAMES = /* @__PURE__ */ new Set([
416
- "package.json",
417
- "Dockerfile",
418
- "docker-compose.yml",
419
- "docker-compose.yaml",
420
- "Makefile",
421
- "tsconfig.json",
422
- "pyproject.toml",
423
- "turbo.json",
424
- "requirements.txt",
425
- "go.mod",
426
- "Cargo.toml",
427
- "Gemfile",
428
- "next.config.js",
429
- "next.config.mjs",
430
- "next.config.ts",
431
- "vite.config.ts",
432
- "vite.config.js",
433
- "vite.config.mjs",
434
- "drizzle.config.ts",
435
- "drizzle.config.js",
436
- "jest.config.ts",
437
- "jest.config.js",
438
- "jest.config.mjs",
439
- "vitest.config.ts",
440
- "vitest.config.js",
441
- "vitest.config.mts",
442
- "alembic.ini",
443
- "setup.cfg",
444
- "tox.ini"
422
+ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
423
+ ".ts",
424
+ ".tsx",
425
+ ".js",
426
+ ".jsx",
427
+ ".mjs",
428
+ ".cjs",
429
+ ".py",
430
+ ".pyw",
431
+ ".go",
432
+ ".rs",
433
+ ".rb",
434
+ ".java",
435
+ ".kt",
436
+ ".scala",
437
+ ".cs",
438
+ ".c",
439
+ ".cpp",
440
+ ".h",
441
+ ".hpp",
442
+ ".swift",
443
+ ".m",
444
+ ".php",
445
+ ".lua",
446
+ ".r",
447
+ ".jl",
448
+ ".ex",
449
+ ".exs",
450
+ ".erl",
451
+ ".hs",
452
+ ".sh",
453
+ ".bash",
454
+ ".zsh",
455
+ ".fish",
456
+ ".sql",
457
+ ".graphql",
458
+ ".gql",
459
+ ".prisma",
460
+ ".html",
461
+ ".css",
462
+ ".scss",
463
+ ".sass",
464
+ ".less",
465
+ ".svelte",
466
+ ".vue",
467
+ ".astro",
468
+ ".json",
469
+ ".yaml",
470
+ ".yml",
471
+ ".toml",
472
+ ".ini",
473
+ ".cfg",
474
+ ".env",
475
+ ".xml",
476
+ ".plist",
477
+ ".md",
478
+ ".mdx",
479
+ ".txt",
480
+ ".rst",
481
+ ".tf",
482
+ ".hcl",
483
+ ".proto",
484
+ ".mdc"
445
485
  ]);
446
- var CONFIG_GLOBS_DIRS = [
447
- { dir: ".github/workflows", pattern: /\.ya?ml$/ }
486
+ var SKIP_FILES = /* @__PURE__ */ new Set([
487
+ "package-lock.json",
488
+ "yarn.lock",
489
+ "pnpm-lock.yaml",
490
+ "bun.lockb",
491
+ "Cargo.lock",
492
+ "Gemfile.lock",
493
+ "poetry.lock",
494
+ "composer.lock",
495
+ ".DS_Store",
496
+ "Thumbs.db"
497
+ ]);
498
+ var SKIP_PATTERNS = [
499
+ /\.min\.(js|css)$/,
500
+ /\.bundle\.(js|css)$/,
501
+ /\.map$/,
502
+ /\.d\.ts$/,
503
+ /\.generated\./,
504
+ /\.snap$/
448
505
  ];
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);
506
+ var TOKEN_BUDGET = 18e4;
507
+ var CHAR_BUDGET = TOKEN_BUDGET * 4;
452
508
  function analyzeCode(dir) {
453
- const sourceFiles = [];
454
- const configFiles = [];
455
- walkDir(dir, "", 0, 10, sourceFiles, configFiles, dir);
456
- sortByPriority(sourceFiles);
457
- let configChars = 0;
458
- const trimmedConfigs = [];
459
- for (const cfg of configFiles) {
460
- const size = cfg.path.length + cfg.content.length;
461
- if (configChars + size > CONFIG_BUDGET) break;
462
- trimmedConfigs.push(cfg);
463
- configChars += size;
464
- }
465
- let sourceChars = 0;
509
+ const allFiles = [];
510
+ walkDir(dir, "", 0, 10, allFiles);
511
+ sortByPriority(allFiles);
512
+ let totalChars = 0;
513
+ let includedChars = 0;
466
514
  let truncated = false;
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;
471
- for (const relPath of sourceFiles) {
472
- const fullPath = path3.join(dir, relPath);
473
- let fileContent;
515
+ const files = [];
516
+ const fileSizes = /* @__PURE__ */ new Map();
517
+ for (const relPath of allFiles) {
474
518
  try {
475
- fileContent = fs3.readFileSync(fullPath, "utf-8");
519
+ const stat = fs3.statSync(path3.join(dir, relPath));
520
+ fileSizes.set(relPath, stat.size);
521
+ totalChars += stat.size;
476
522
  } catch {
477
- continue;
478
- }
479
- const lineCount = fileContent.split("\n").length;
480
- if (lineCount > MAX_CONTENT_LINE_COUNT) continue;
481
- const ext = path3.extname(relPath);
482
- const language = resolveLanguage(ext);
483
- if (!language) continue;
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
523
  }
491
- fileSummaries.push(summary);
492
- sourceChars += entrySize;
493
524
  }
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;
525
+ for (const relPath of allFiles) {
498
526
  const fullPath = path3.join(dir, relPath);
499
- let fileContent;
527
+ let content;
500
528
  try {
501
- fileContent = fs3.readFileSync(fullPath, "utf-8");
529
+ content = fs3.readFileSync(fullPath, "utf-8");
502
530
  } catch {
503
531
  continue;
504
532
  }
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);
511
- const summarySize = estimateSummarySize(summary);
512
- if (summaryChars + summarySize > SUMMARY_BUDGET) {
533
+ if (content.split("\n").length > 500) continue;
534
+ const entrySize = relPath.length + content.length + 10;
535
+ if (includedChars + entrySize > CHAR_BUDGET) {
513
536
  truncated = true;
514
- break;
537
+ continue;
515
538
  }
516
- fileSummaries.push(summary);
517
- summaryChars += summarySize;
539
+ files.push({ path: relPath, content, size: content.length });
540
+ includedChars += entrySize;
518
541
  }
519
- return { fileSummaries, configFiles: trimmedConfigs, truncated };
542
+ return {
543
+ files,
544
+ truncated,
545
+ totalProjectTokens: Math.ceil(totalChars / 4),
546
+ includedTokens: Math.ceil(includedChars / 4)
547
+ };
520
548
  }
521
- function walkDir(base, rel, depth, maxDepth, sourceFiles, configFiles, rootDir) {
549
+ function walkDir(base, rel, depth, maxDepth, files) {
522
550
  if (depth > maxDepth) return;
523
551
  const fullPath = path3.join(base, rel);
524
552
  let entries;
@@ -532,171 +560,52 @@ function walkDir(base, rel, depth, maxDepth, sourceFiles, configFiles, rootDir)
532
560
  if (entry.name.startsWith(".") && depth === 0 && entry.isDirectory()) continue;
533
561
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
534
562
  if (entry.isDirectory()) {
535
- const matchedGlobDir = CONFIG_GLOBS_DIRS.find(
536
- (g) => relPath === g.dir || relPath.endsWith(`/${g.dir}`)
537
- );
538
- if (matchedGlobDir) {
539
- collectConfigsFromDir(base, relPath, matchedGlobDir.pattern, configFiles);
540
- }
541
- walkDir(base, relPath, depth + 1, maxDepth, sourceFiles, configFiles, rootDir);
542
- } else {
543
- if (CONFIG_FILE_NAMES.has(entry.name)) {
544
- try {
545
- const content = fs3.readFileSync(path3.join(base, relPath), "utf-8");
546
- configFiles.push({ path: relPath, content });
547
- } catch {
548
- }
549
- }
550
- const ext = path3.extname(entry.name);
551
- if (SOURCE_EXTENSIONS.has(ext) && !entry.name.endsWith(".d.ts")) {
552
- sourceFiles.push(relPath);
553
- }
554
- }
555
- }
556
- }
557
- function collectConfigsFromDir(base, relDir, pattern, configFiles) {
558
- const fullDir = path3.join(base, relDir);
559
- let entries;
560
- try {
561
- entries = fs3.readdirSync(fullDir, { withFileTypes: true });
562
- } catch {
563
- return;
564
- }
565
- for (const entry of entries) {
566
- if (entry.isFile() && pattern.test(entry.name)) {
567
- const relPath = `${relDir}/${entry.name}`;
568
- try {
569
- const content = fs3.readFileSync(path3.join(base, relPath), "utf-8");
570
- configFiles.push({ path: relPath, content });
571
- } catch {
563
+ walkDir(base, relPath, depth + 1, maxDepth, files);
564
+ } else if (entry.isFile()) {
565
+ if (SKIP_FILES.has(entry.name)) continue;
566
+ if (SKIP_PATTERNS.some((p) => p.test(entry.name))) continue;
567
+ const ext = path3.extname(entry.name).toLowerCase();
568
+ if (TEXT_EXTENSIONS.has(ext) || depth === 0 && !ext && !entry.name.startsWith(".")) {
569
+ files.push(relPath);
572
570
  }
573
571
  }
574
572
  }
575
573
  }
576
574
  function sortByPriority(files) {
577
- const entryPointNames = /* @__PURE__ */ new Set(["index.ts", "index.js", "main.py", "app.ts", "app.js", "server.ts", "server.js"]);
578
- const routePattern = /(route|api|controller)/i;
579
- const schemaPattern = /(types|schema|models)/i;
580
- const servicePattern = /(service|lib|utils)/i;
581
- const testPattern = /(test|spec|__tests__)/i;
575
+ const entryPointNames = /* @__PURE__ */ new Set([
576
+ "index.ts",
577
+ "index.js",
578
+ "index.tsx",
579
+ "index.jsx",
580
+ "main.ts",
581
+ "main.py",
582
+ "main.go",
583
+ "main.rs",
584
+ "app.ts",
585
+ "app.js",
586
+ "app.py",
587
+ "server.ts",
588
+ "server.js",
589
+ "mod.rs",
590
+ "lib.rs"
591
+ ]);
592
+ const configPattern = /\.(json|ya?ml|toml|ini|cfg|env)$|config\.|Makefile|Dockerfile/i;
593
+ const routePattern = /(route|api|controller|endpoint|handler)/i;
594
+ const schemaPattern = /(types|schema|models|entities|migration)/i;
595
+ const servicePattern = /(service|lib|utils|helper|middleware)/i;
596
+ const testPattern = /(test|spec|__tests__|_test\.|\.test\.)/i;
582
597
  function priority(filePath) {
583
598
  const base = path3.basename(filePath);
584
599
  if (entryPointNames.has(base)) return 0;
585
- if (routePattern.test(filePath)) return 1;
586
- if (schemaPattern.test(filePath)) return 2;
587
- if (servicePattern.test(filePath)) return 3;
588
- if (testPattern.test(filePath)) return 5;
589
- return 4;
600
+ if (configPattern.test(filePath)) return 1;
601
+ if (routePattern.test(filePath)) return 2;
602
+ if (schemaPattern.test(filePath)) return 3;
603
+ if (servicePattern.test(filePath)) return 4;
604
+ if (testPattern.test(filePath)) return 6;
605
+ return 5;
590
606
  }
591
607
  files.sort((a, b) => priority(a) - priority(b));
592
608
  }
593
- function resolveLanguage(ext) {
594
- if (ext === ".ts" || ext === ".tsx") return "ts";
595
- if (ext === ".js" || ext === ".jsx") return "js";
596
- if (ext === ".py") return "py";
597
- return null;
598
- }
599
- function extractTypeScriptJavaScript(filePath, content, language) {
600
- const lines = content.split("\n");
601
- const imports = [];
602
- const exports = [];
603
- const functions = [];
604
- const classes = [];
605
- const types = [];
606
- const routes = [];
607
- for (const line of lines) {
608
- const trimmed = line.trim();
609
- if (/^import\s+/.test(trimmed)) {
610
- imports.push(trimmed);
611
- continue;
612
- }
613
- const exportMatch = trimmed.match(
614
- /^export\s+(?:default\s+)?(?:async\s+)?(function|const|class|interface|type|enum)\s+(\w+)/
615
- );
616
- if (exportMatch) {
617
- exports.push(`${exportMatch[1]} ${exportMatch[2]}`);
618
- if (exportMatch[1] === "class") classes.push(exportMatch[2]);
619
- if (exportMatch[1] === "interface" || exportMatch[1] === "type") types.push(exportMatch[2]);
620
- if (exportMatch[1] === "function") functions.push(exportMatch[2]);
621
- continue;
622
- }
623
- const fnMatch = trimmed.match(/^(?:async\s+)?function\s+(\w+)/);
624
- if (fnMatch && !trimmed.startsWith("export")) {
625
- functions.push(fnMatch[1]);
626
- continue;
627
- }
628
- const arrowMatch = trimmed.match(/^(?:export\s+)?const\s+(\w+)\s*=\s*(?:async\s*)?\(/);
629
- if (arrowMatch && !exports.some((e) => e.endsWith(arrowMatch[1]))) {
630
- functions.push(arrowMatch[1]);
631
- }
632
- const classMatch = trimmed.match(/^class\s+(\w+)/);
633
- if (classMatch && !trimmed.startsWith("export")) {
634
- classes.push(classMatch[1]);
635
- continue;
636
- }
637
- const ifaceMatch = trimmed.match(/^(?:interface|type)\s+(\w+)/);
638
- if (ifaceMatch && !trimmed.startsWith("export")) {
639
- types.push(ifaceMatch[1]);
640
- continue;
641
- }
642
- const routeMatch = trimmed.match(
643
- /(?:router|app|server)\.(get|post|put|patch|delete|all|use)\s*\(\s*['"`]([^'"`]+)['"`]/
644
- );
645
- if (routeMatch) {
646
- routes.push(`${routeMatch[1].toUpperCase()} ${routeMatch[2]}`);
647
- }
648
- }
649
- return { path: filePath, language, imports, exports, functions, classes, types, routes };
650
- }
651
- function extractPython(filePath, content) {
652
- const lines = content.split("\n");
653
- const imports = [];
654
- const functions = [];
655
- const classes = [];
656
- const routes = [];
657
- let prevLine = "";
658
- for (const line of lines) {
659
- const trimmed = line.trim();
660
- if (/^import\s+/.test(trimmed) || /^from\s+/.test(trimmed)) {
661
- imports.push(trimmed);
662
- continue;
663
- }
664
- const defMatch = trimmed.match(/^def\s+(\w+)\s*\(([^)]*)\)/);
665
- if (defMatch) {
666
- functions.push(`${defMatch[1]}(${defMatch[2]})`);
667
- }
668
- const classMatch = trimmed.match(/^class\s+(\w+)/);
669
- if (classMatch) {
670
- classes.push(classMatch[1]);
671
- }
672
- const decoratorRoute = prevLine.match(
673
- /@(?:app|router)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"]([^'"]+)['"]/
674
- );
675
- if (decoratorRoute && defMatch) {
676
- routes.push(`${decoratorRoute[1].toUpperCase()} ${decoratorRoute[2]}`);
677
- }
678
- const includeRouter = trimmed.match(
679
- /include_router\s*\([^,]+,\s*prefix\s*=\s*['"]([^'"]+)['"]/
680
- );
681
- if (includeRouter) {
682
- routes.push(`ROUTER ${includeRouter[1]}`);
683
- }
684
- prevLine = trimmed;
685
- }
686
- return {
687
- path: filePath,
688
- language: "py",
689
- imports,
690
- exports: [],
691
- functions,
692
- classes,
693
- types: [],
694
- routes
695
- };
696
- }
697
- function estimateSummarySize(summary) {
698
- return summary.path.length + summary.imports.reduce((s, i) => s + i.length, 0) + summary.exports.reduce((s, e) => s + e.length, 0) + summary.functions.reduce((s, f) => s + f.length, 0) + summary.classes.reduce((s, c) => s + c.length, 0) + summary.types.reduce((s, t) => s + t.length, 0) + summary.routes.reduce((s, r) => s + r.length, 0);
699
- }
700
609
 
701
610
  // src/llm/index.ts
702
611
  init_config();
@@ -2469,12 +2378,7 @@ var LIMITS = {
2469
2378
  EXISTING_CONFIG_CHARS: 8e3,
2470
2379
  SKILLS_MAX: 10,
2471
2380
  SKILL_CHARS: 3e3,
2472
- RULES_MAX: 10,
2473
- CONFIG_FILES_MAX: 20,
2474
- CONFIG_FILE_CHARS: 5e3,
2475
- ROUTES_MAX: 100,
2476
- FILE_SUMMARIES_MAX: 200,
2477
- FILE_CONTENT_CHARS: 8e3
2381
+ RULES_MAX: 10
2478
2382
  };
2479
2383
  function truncate(text, maxChars) {
2480
2384
  if (text.length <= maxChars) return text;
@@ -2587,52 +2491,19 @@ ${truncate(skill.content, LIMITS.SKILL_CHARS)}`);
2587
2491
  }
2588
2492
  if (fingerprint.codeAnalysis) {
2589
2493
  const ca = fingerprint.codeAnalysis;
2590
- if (ca.configFiles.length > 0) {
2591
- parts.push("\n--- Project Config Files ---");
2592
- for (const cfg of ca.configFiles.slice(0, LIMITS.CONFIG_FILES_MAX)) {
2593
- parts.push(`
2594
- [${cfg.path}]
2595
- ${truncate(cfg.content, LIMITS.CONFIG_FILE_CHARS)}`);
2596
- }
2597
- }
2598
- const allRoutes = ca.fileSummaries.filter((f) => f.routes.length > 0).flatMap((f) => f.routes.map((r) => `${r} (${f.path})`));
2599
- if (allRoutes.length > 0) {
2600
- parts.push("\n--- API Routes ---");
2601
- for (const route of allRoutes.slice(0, LIMITS.ROUTES_MAX)) {
2602
- parts.push(`- ${route}`);
2603
- }
2604
- if (allRoutes.length > LIMITS.ROUTES_MAX) {
2605
- parts.push(`(${allRoutes.length - LIMITS.ROUTES_MAX} more routes omitted)`);
2606
- }
2607
- }
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) {
2619
- parts.push("\n--- Source File Summaries ---");
2620
- for (const f of filesWithoutContent.slice(0, LIMITS.FILE_SUMMARIES_MAX)) {
2621
- const sections = [`[${f.path}] (${f.language})`];
2622
- if (f.imports.length > 0) sections.push(` imports: ${f.imports.slice(0, 10).join("; ")}`);
2623
- if (f.exports.length > 0) sections.push(` exports: ${f.exports.slice(0, 10).join(", ")}`);
2624
- if (f.functions.length > 0) sections.push(` functions: ${f.functions.slice(0, 10).join(", ")}`);
2625
- if (f.classes.length > 0) sections.push(` classes: ${f.classes.join(", ")}`);
2626
- if (f.types.length > 0) sections.push(` types: ${f.types.slice(0, 10).join(", ")}`);
2627
- parts.push(sections.join("\n"));
2628
- }
2629
- if (filesWithoutContent.length > LIMITS.FILE_SUMMARIES_MAX) {
2630
- parts.push(`
2631
- (${filesWithoutContent.length - LIMITS.FILE_SUMMARIES_MAX} more files omitted)`);
2632
- }
2633
- }
2634
2494
  if (ca.truncated) {
2635
- parts.push("\n(Code analysis was truncated due to size limits \u2014 not all files are shown.)");
2495
+ const pct = ca.totalProjectTokens > 0 ? Math.round(ca.includedTokens / ca.totalProjectTokens * 100) : 100;
2496
+ parts.push(`
2497
+ --- Project Files (trimmed to ~${ca.includedTokens.toLocaleString()}/${ca.totalProjectTokens.toLocaleString()} tokens, ${pct}% of total) ---`);
2498
+ } else {
2499
+ parts.push(`
2500
+ --- Project Files (${ca.files.length} files, ~${ca.includedTokens.toLocaleString()} tokens) ---`);
2501
+ }
2502
+ parts.push("Study these files to extract patterns for skills. Use the exact code patterns you see here.\n");
2503
+ for (const f of ca.files) {
2504
+ parts.push(`[${f.path}]`);
2505
+ parts.push(f.content);
2506
+ parts.push("");
2636
2507
  }
2637
2508
  }
2638
2509
  const allDeps = extractAllDeps(process.cwd());
@@ -6149,7 +6020,7 @@ async function initCommand(options) {
6149
6020
  spinner.succeed("Project analyzed");
6150
6021
  log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
6151
6022
  if (options.verbose && fingerprint.codeAnalysis) {
6152
- log(options.verbose, `Code analysis: ${fingerprint.codeAnalysis.fileSummaries.length} file summaries, ${fingerprint.codeAnalysis.configFiles.length} config files`);
6023
+ log(options.verbose, `Code analysis: ${fingerprint.codeAnalysis.files.length} files, ~${fingerprint.codeAnalysis.includedTokens.toLocaleString()} tokens${fingerprint.codeAnalysis.truncated ? ` (trimmed from ~${fingerprint.codeAnalysis.totalProjectTokens.toLocaleString()})` : ""}`);
6153
6024
  }
6154
6025
  trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
6155
6026
  console.log(chalk8.dim(` Languages: ${fingerprint.languages.join(", ") || "none detected"}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.13.1",
3
+ "version": "1.14.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": {