@rely-ai/caliber 1.48.2 → 1.49.3

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 +370 -168
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -184,6 +184,7 @@ var init_config = __esm({
184
184
  // src/lib/resolve-caliber.ts
185
185
  var resolve_caliber_exports = {};
186
186
  __export(resolve_caliber_exports, {
187
+ displayCaliberName: () => displayCaliberName,
187
188
  isCaliberCommand: () => isCaliberCommand,
188
189
  isNpxResolution: () => isNpxResolution,
189
190
  pickExecutable: () => pickExecutable,
@@ -254,6 +255,9 @@ function isNpxResolution() {
254
255
  if (r === "npx --yes @rely-ai/caliber") return true;
255
256
  return NPX_RESOLUTION_RE.test(r);
256
257
  }
258
+ function displayCaliberName() {
259
+ return isNpxResolution() ? "npx @rely-ai/caliber" : "caliber";
260
+ }
257
261
  function resetResolvedCaliber() {
258
262
  _resolved = null;
259
263
  }
@@ -344,7 +348,7 @@ npx @rely-ai/caliber refresh
344
348
  }
345
349
  }
346
350
  function getPreCommitBlock(platform = "claude") {
347
- const bin = resolveCaliber();
351
+ const bin = displayCaliberName();
348
352
  return `${BLOCK_START}
349
353
  ## Before Committing
350
354
 
@@ -369,7 +373,7 @@ ${getCaliberNotFoundFallback(platform, bin)}
369
373
  ${BLOCK_END}`;
370
374
  }
371
375
  function getCursorRuleContent() {
372
- const bin = resolveCaliber();
376
+ const bin = displayCaliberName();
373
377
  return `---
374
378
  description: Run Caliber sync before git commits to keep agent configs up to date
375
379
  alwaysApply: true
@@ -386,8 +390,20 @@ Valid \`${bin} refresh\` options: \`--quiet\` and \`--dry-run\` only. Do not pas
386
390
  If \`${bin}\` is not found, read the setup-caliber skill from .cursor/skills/setup-caliber/SKILL.md and follow its instructions to install Caliber.
387
391
  `;
388
392
  }
393
+ function getSectionBody(content, headingRe) {
394
+ const match = content.match(headingRe);
395
+ if (!match || match.index === void 0) return null;
396
+ const start = match.index + match[0].length;
397
+ const tail = content.slice(start);
398
+ const nextHeadingMatch = tail.match(/^##\s/m);
399
+ const end = nextHeadingMatch?.index ?? tail.length;
400
+ return tail.slice(0, end);
401
+ }
389
402
  function hasPreCommitBlock(content) {
390
- return content.includes(BLOCK_START);
403
+ if (content.includes(BLOCK_START)) return true;
404
+ const body = getSectionBody(content, PRECOMMIT_HEADING_RE);
405
+ if (body && /caliber/i.test(body)) return true;
406
+ return false;
391
407
  }
392
408
  function appendPreCommitBlock(content, platform = "claude") {
393
409
  if (hasPreCommitBlock(content)) return content;
@@ -398,7 +414,10 @@ function getCursorPreCommitRule() {
398
414
  return { filename: CURSOR_RULE_FILENAME, content: getCursorRuleContent() };
399
415
  }
400
416
  function hasLearningsBlock(content) {
401
- return content.includes(LEARNINGS_BLOCK_START);
417
+ if (content.includes(LEARNINGS_BLOCK_START)) return true;
418
+ const body = getSectionBody(content, LEARNINGS_HEADING_RE);
419
+ if (body && /CALIBER_LEARNINGS/.test(body)) return true;
420
+ return false;
402
421
  }
403
422
  function appendLearningsBlock(content) {
404
423
  if (hasLearningsBlock(content)) return content;
@@ -420,7 +439,10 @@ Pin your choice (\`/model\` in Claude Code, or \`CALIBER_MODEL\` when using Cali
420
439
  ${MODEL_BLOCK_END}`;
421
440
  }
422
441
  function hasModelBlock(content) {
423
- return content.includes(MODEL_BLOCK_START);
442
+ if (content.includes(MODEL_BLOCK_START)) return true;
443
+ const body = getSectionBody(content, MODEL_HEADING_RE);
444
+ if (body && /CALIBER_MODEL/.test(body)) return true;
445
+ return false;
424
446
  }
425
447
  function appendModelBlock(content) {
426
448
  if (hasModelBlock(content)) return content;
@@ -443,7 +465,7 @@ git add ${MANAGED_DOC_PATHS} 2>/dev/null
443
465
  }
444
466
  }
445
467
  function getSyncBlock(platform = "claude") {
446
- const bin = resolveCaliber();
468
+ const bin = displayCaliberName();
447
469
  return `${SYNC_BLOCK_START}
448
470
  ## Context Sync
449
471
 
@@ -453,7 +475,10 @@ ${getSyncSetupInstruction(platform)}
453
475
  ${SYNC_BLOCK_END}`;
454
476
  }
455
477
  function hasSyncBlock(content) {
456
- return content.includes(SYNC_BLOCK_START);
478
+ if (content.includes(SYNC_BLOCK_START)) return true;
479
+ const body = getSectionBody(content, SYNC_HEADING_RE);
480
+ if (body && /caliber-ai-org\/ai-setup/.test(body)) return true;
481
+ return false;
457
482
  }
458
483
  function appendSyncBlock(content, platform = "claude") {
459
484
  if (hasSyncBlock(content)) return content;
@@ -467,7 +492,7 @@ function appendManagedBlocks(content, platform = "claude") {
467
492
  );
468
493
  }
469
494
  function getCursorSyncContent() {
470
- const bin = resolveCaliber();
495
+ const bin = displayCaliberName();
471
496
  return `---
472
497
  description: This project uses Caliber for automatic AI agent context sync
473
498
  alwaysApply: true
@@ -509,7 +534,7 @@ function stripManagedBlocks(content) {
509
534
  }
510
535
  return result.replace(/\n{3,}/g, "\n\n").trim() + "\n";
511
536
  }
512
- var BLOCK_START, BLOCK_END, MANAGED_DOC_PATHS, CURSOR_RULE_FILENAME, LEARNINGS_BLOCK_START, LEARNINGS_BLOCK_END, LEARNINGS_BLOCK, CURSOR_LEARNINGS_FILENAME, CURSOR_LEARNINGS_CONTENT, MODEL_BLOCK_START, MODEL_BLOCK_END, SYNC_BLOCK_START, SYNC_BLOCK_END, CURSOR_SYNC_FILENAME, CURSOR_SETUP_FILENAME, MANAGED_BLOCK_PAIRS;
537
+ var BLOCK_START, BLOCK_END, MANAGED_DOC_PATHS, CURSOR_RULE_FILENAME, PRECOMMIT_HEADING_RE, LEARNINGS_BLOCK_START, LEARNINGS_BLOCK_END, LEARNINGS_BLOCK, CURSOR_LEARNINGS_FILENAME, CURSOR_LEARNINGS_CONTENT, LEARNINGS_HEADING_RE, MODEL_BLOCK_START, MODEL_BLOCK_END, MODEL_HEADING_RE, SYNC_BLOCK_START, SYNC_BLOCK_END, SYNC_HEADING_RE, CURSOR_SYNC_FILENAME, CURSOR_SETUP_FILENAME, MANAGED_BLOCK_PAIRS;
513
538
  var init_pre_commit_block = __esm({
514
539
  "src/writers/pre-commit-block.ts"() {
515
540
  "use strict";
@@ -519,6 +544,7 @@ var init_pre_commit_block = __esm({
519
544
  BLOCK_END = "<!-- /caliber:managed:pre-commit -->";
520
545
  MANAGED_DOC_PATHS = "CLAUDE.md .claude/ .cursor/ .cursorrules .github/copilot-instructions.md .github/instructions/ AGENTS.md CALIBER_LEARNINGS.md .agents/ .opencode/";
521
546
  CURSOR_RULE_FILENAME = "caliber-pre-commit.mdc";
547
+ PRECOMMIT_HEADING_RE = /^##\s+Before Committing\s*$/m;
522
548
  LEARNINGS_BLOCK_START = "<!-- caliber:managed:learnings -->";
523
549
  LEARNINGS_BLOCK_END = "<!-- /caliber:managed:learnings -->";
524
550
  LEARNINGS_BLOCK = `${LEARNINGS_BLOCK_START}
@@ -535,10 +561,13 @@ alwaysApply: true
535
561
  Read \`CALIBER_LEARNINGS.md\` for patterns and anti-patterns learned from previous sessions.
536
562
  These are auto-extracted from real tool usage \u2014 treat them as project-specific rules.
537
563
  `;
564
+ LEARNINGS_HEADING_RE = /^##\s+Session Learnings\s*$/m;
538
565
  MODEL_BLOCK_START = "<!-- caliber:managed:model-config -->";
539
566
  MODEL_BLOCK_END = "<!-- /caliber:managed:model-config -->";
567
+ MODEL_HEADING_RE = /^##\s+Model Configuration\s*$/m;
540
568
  SYNC_BLOCK_START = "<!-- caliber:managed:sync -->";
541
569
  SYNC_BLOCK_END = "<!-- /caliber:managed:sync -->";
570
+ SYNC_HEADING_RE = /^##\s+Context Sync\s*$/m;
542
571
  CURSOR_SYNC_FILENAME = "caliber-sync.mdc";
543
572
  CURSOR_SETUP_FILENAME = "caliber-setup.mdc";
544
573
  MANAGED_BLOCK_PAIRS = [
@@ -574,7 +603,7 @@ description: ${skill.description}
574
603
  return frontmatter + skill.content;
575
604
  }
576
605
  function getFindSkillsContent() {
577
- const bin = resolveCaliber();
606
+ const bin = displayCaliberName();
578
607
  return `# Find Skills
579
608
 
580
609
  Search the public skill registry for community-contributed skills
@@ -627,7 +656,7 @@ User: "I need to write tests for this Python ML pipeline"
627
656
  `;
628
657
  }
629
658
  function getSaveLearningContent() {
630
- const bin = resolveCaliber();
659
+ const bin = displayCaliberName();
631
660
  return `# Save Learning
632
661
 
633
662
  Save a user's instruction or preference as a persistent learning that
@@ -2583,10 +2612,19 @@ import os3 from "os";
2583
2612
  // src/llm/seat-based-errors.ts
2584
2613
  init_resolve_caliber();
2585
2614
  var ERROR_PATTERNS = [
2586
- { pattern: /not logged in|not authenticated|login required|unauthorized/i, message: "Not logged in. Run the login command for your provider to re-authenticate." },
2615
+ {
2616
+ pattern: /not logged in|not authenticated|login required|unauthorized/i,
2617
+ message: "Not logged in. Run the login command for your provider to re-authenticate."
2618
+ },
2587
2619
  { pattern: /rate limit|too many requests|429/i, message: "Rate limit exceeded. Retrying..." },
2588
- { pattern: /usage limit|out of usage|budget.*limit|limit.*reached/i, message: () => `Usage limit reached. Run \`${resolveCaliber()} config\` to switch models (e.g. auto or composer-1.5).` },
2589
- { pattern: /model.*not found|invalid model|model.*unavailable/i, message: () => `The requested model is not available. Run \`${resolveCaliber()} config\` to select a different model.` }
2620
+ {
2621
+ pattern: /usage limit|out of usage|budget.*limit|limit.*reached/i,
2622
+ message: () => `Usage limit reached. Run \`${displayCaliberName()} config\` to switch models (e.g. auto or composer-1.5).`
2623
+ },
2624
+ {
2625
+ pattern: /model.*not found|invalid model|model.*unavailable/i,
2626
+ message: () => `The requested model is not available. Run \`${displayCaliberName()} config\` to select a different model.`
2627
+ }
2590
2628
  ];
2591
2629
  function parseSeatBasedError(stderr, exitCode) {
2592
2630
  if (!stderr && exitCode === 0) return null;
@@ -2664,6 +2702,12 @@ function withCaliberSubprocessEnv(env) {
2664
2702
  [CALIBER_SUBPROCESS_LEGACY_ENV]: "1"
2665
2703
  };
2666
2704
  }
2705
+ function isHookCascadeFromUserClaudeSession() {
2706
+ const inClaudeSession = process.env.CLAUDECODE === "1";
2707
+ const isCaliberSpawned = process.env[CALIBER_SUBPROCESS_ENV] === "1";
2708
+ const isInteractiveTty = process.stdin.isTTY === true;
2709
+ return inClaudeSession && !isCaliberSpawned && !isInteractiveTty;
2710
+ }
2667
2711
 
2668
2712
  // src/llm/cursor-acp.ts
2669
2713
  var IS_WINDOWS = process.platform === "win32";
@@ -3038,12 +3082,17 @@ function resolveClaudeBin() {
3038
3082
  _claudeBin = "claude";
3039
3083
  return _claudeBin;
3040
3084
  }
3085
+ var ANTI_RECURSION_ENV_VARS = /* @__PURE__ */ new Set([
3086
+ "CLAUDECODE",
3087
+ "CLAUDE_CODE_SIMPLE",
3088
+ "CLAUDE_CODE_SESSION_ID",
3089
+ "CLAUDE_CODE_ENTRYPOINT",
3090
+ "CLAUDE_CODE_EXECPATH"
3091
+ ]);
3041
3092
  function cleanClaudeEnv() {
3042
3093
  const env = { ...process.env };
3043
- for (const key of Object.keys(env)) {
3044
- if (key === "CLAUDE_CODE_SIMPLE" || key === "CLAUDECODE" || key.startsWith("CLAUDE_CODE_")) {
3045
- delete env[key];
3046
- }
3094
+ for (const key of ANTI_RECURSION_ENV_VARS) {
3095
+ delete env[key];
3047
3096
  }
3048
3097
  return env;
3049
3098
  }
@@ -3505,7 +3554,7 @@ async function handleModelNotAvailable(failedModel, provider, config) {
3505
3554
  if (!process.stdin.isTTY) {
3506
3555
  console.error(
3507
3556
  chalk.red(
3508
- `Model "${failedModel}" is not available. Run \`${resolveCaliber()} config\` to select a different model.`
3557
+ `Model "${failedModel}" is not available. Run \`${displayCaliberName()} config\` to select a different model.`
3509
3558
  )
3510
3559
  );
3511
3560
  return null;
@@ -3531,7 +3580,7 @@ async function handleModelNotAvailable(failedModel, provider, config) {
3531
3580
  if (models.length === 0) {
3532
3581
  console.log(
3533
3582
  chalk.red(
3534
- ` No alternative models found. Run \`${resolveCaliber()} config\` to configure manually.`
3583
+ ` No alternative models found. Run \`${displayCaliberName()} config\` to configure manually.`
3535
3584
  )
3536
3585
  );
3537
3586
  return null;
@@ -3623,7 +3672,7 @@ function getProvider() {
3623
3672
  const config = loadConfig();
3624
3673
  if (!config) {
3625
3674
  throw new Error(
3626
- `No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, MINIMAX_API_KEY, or VERTEX_PROJECT_ID; or run \`${resolveCaliber()} config\` and choose Cursor, Claude Code, or OpenCode; or set CALIBER_USE_CURSOR_SEAT=1 / CALIBER_USE_CLAUDE_CLI=1 / CALIBER_USE_OPENCODE=1.`
3675
+ `No LLM provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, MINIMAX_API_KEY, or VERTEX_PROJECT_ID; or run \`${displayCaliberName()} config\` and choose Cursor, Claude Code, or OpenCode; or set CALIBER_USE_CURSOR_SEAT=1 / CALIBER_USE_CLAUDE_CLI=1 / CALIBER_USE_OPENCODE=1.`
3627
3676
  );
3628
3677
  }
3629
3678
  cachedConfig = config;
@@ -4816,8 +4865,11 @@ var notificationHook = createScriptHook({
4816
4865
  var isNotificationHookInstalled = notificationHook.isInstalled;
4817
4866
  var installNotificationHook = notificationHook.install;
4818
4867
  var removeNotificationHook = notificationHook.remove;
4819
- var PRECOMMIT_START = "# caliber:pre-commit:start";
4820
- var PRECOMMIT_END = "# caliber:pre-commit:end";
4868
+ var HOOK_BLOCK_VERSION = "v2";
4869
+ var PRECOMMIT_START = `# caliber:pre-commit:${HOOK_BLOCK_VERSION}:start`;
4870
+ var PRECOMMIT_END = `# caliber:pre-commit:${HOOK_BLOCK_VERSION}:end`;
4871
+ var PRECOMMIT_ANY_VERSION_START_RE = /^#\s*caliber:pre-commit:(?:[a-zA-Z0-9_.-]+:)?start\s*$/m;
4872
+ var PRECOMMIT_ANY_VERSION_BLOCK_RE = /\n?#\s*caliber:pre-commit:(?:[a-zA-Z0-9_.-]+:)?start[\s\S]*?#\s*caliber:pre-commit:(?:[a-zA-Z0-9_.-]+:)?end\n?/g;
4821
4873
  function tryWindowsDirectNodeInvocation(cmd) {
4822
4874
  if (process.platform !== "win32") return null;
4823
4875
  if (!/\.cmd$/i.test(cmd)) return null;
@@ -4875,7 +4927,7 @@ function getPrecommitBlock() {
4875
4927
  if ${guard}; then
4876
4928
  mkdir -p .caliber
4877
4929
  echo "\\033[2mcaliber: refreshing docs...\\033[0m"
4878
- ${invoke} refresh --quiet 2>.caliber/refresh-hook.log || true
4930
+ ${invoke} refresh --quiet 2>.caliber/refresh-hook.log || echo "\\033[33mcaliber: refresh skipped \u2014 see .caliber/refresh-hook.log\\033[0m" >&2
4879
4931
  ${invoke} learn finalize 2>>.caliber/refresh-hook.log || true
4880
4932
  git diff --name-only -- CLAUDE.md .claude/ .cursor/ AGENTS.md CALIBER_LEARNINGS.md .github/ .agents/ .opencode/ 2>/dev/null | xargs git add 2>/dev/null || true
4881
4933
  fi
@@ -4900,19 +4952,29 @@ function isPreCommitHookInstalled() {
4900
4952
  const hookPath = getPreCommitPath();
4901
4953
  if (!hookPath || !fs11.existsSync(hookPath)) return false;
4902
4954
  const content = fs11.readFileSync(hookPath, "utf-8");
4903
- return content.includes(PRECOMMIT_START);
4955
+ return PRECOMMIT_ANY_VERSION_START_RE.test(content);
4904
4956
  }
4905
4957
  function installPreCommitHook() {
4906
- if (isPreCommitHookInstalled()) {
4907
- return { installed: false, alreadyInstalled: true };
4908
- }
4909
4958
  const hookPath = getPreCommitPath();
4910
- if (!hookPath) return { installed: false, alreadyInstalled: false };
4959
+ if (!hookPath) {
4960
+ return { installed: false, alreadyInstalled: false, upgraded: false };
4961
+ }
4911
4962
  const hooksDir = path10.dirname(hookPath);
4912
4963
  if (!fs11.existsSync(hooksDir)) fs11.mkdirSync(hooksDir, { recursive: true });
4913
- let content = "";
4914
- if (fs11.existsSync(hookPath)) {
4915
- content = fs11.readFileSync(hookPath, "utf-8");
4964
+ const exists = fs11.existsSync(hookPath);
4965
+ let content = exists ? fs11.readFileSync(hookPath, "utf-8") : "";
4966
+ if (PRECOMMIT_ANY_VERSION_START_RE.test(content)) {
4967
+ if (content.includes(PRECOMMIT_START)) {
4968
+ return { installed: false, alreadyInstalled: true, upgraded: false };
4969
+ }
4970
+ content = content.replace(PRECOMMIT_ANY_VERSION_BLOCK_RE, "\n").replace(/\n{3,}/g, "\n\n");
4971
+ if (!content.endsWith("\n")) content += "\n";
4972
+ content += "\n" + getPrecommitBlock() + "\n";
4973
+ fs11.writeFileSync(hookPath, content);
4974
+ fs11.chmodSync(hookPath, 493);
4975
+ return { installed: false, alreadyInstalled: false, upgraded: true };
4976
+ }
4977
+ if (exists) {
4916
4978
  if (!content.endsWith("\n")) content += "\n";
4917
4979
  content += "\n" + getPrecommitBlock() + "\n";
4918
4980
  } else {
@@ -4920,7 +4982,7 @@ function installPreCommitHook() {
4920
4982
  }
4921
4983
  fs11.writeFileSync(hookPath, content);
4922
4984
  fs11.chmodSync(hookPath, 493);
4923
- return { installed: true, alreadyInstalled: false };
4985
+ return { installed: true, alreadyInstalled: false, upgraded: false };
4924
4986
  }
4925
4987
  function removePreCommitHook() {
4926
4988
  const hookPath = getPreCommitPath();
@@ -4928,11 +4990,10 @@ function removePreCommitHook() {
4928
4990
  return { removed: false, notFound: true };
4929
4991
  }
4930
4992
  let content = fs11.readFileSync(hookPath, "utf-8");
4931
- if (!content.includes(PRECOMMIT_START)) {
4993
+ if (!PRECOMMIT_ANY_VERSION_START_RE.test(content)) {
4932
4994
  return { removed: false, notFound: true };
4933
4995
  }
4934
- const regex = new RegExp(`\\n?${PRECOMMIT_START}[\\s\\S]*?${PRECOMMIT_END}\\n?`);
4935
- content = content.replace(regex, "\n");
4996
+ content = content.replace(PRECOMMIT_ANY_VERSION_BLOCK_RE, "\n").replace(/\n{3,}/g, "\n\n");
4936
4997
  if (content.trim() === "#!/bin/sh" || content.trim() === "") {
4937
4998
  fs11.unlinkSync(hookPath);
4938
4999
  } else {
@@ -5570,7 +5631,8 @@ var CORE_MAX_TOKENS = 16e3;
5570
5631
  var GENERATION_MAX_TOKENS = 64e3;
5571
5632
  var MODEL_MAX_OUTPUT_TOKENS = 128e3;
5572
5633
  var MAX_RETRIES2 = 5;
5573
- var DEFAULT_INACTIVITY_TIMEOUT_MS = 12e4;
5634
+ var DEFAULT_INACTIVITY_TIMEOUT_MS = 3e5;
5635
+ var SOFT_INACTIVITY_WARN_MS = 6e4;
5574
5636
  var DEFAULT_TOTAL_TIMEOUT_MS = 6e5;
5575
5637
  function parseEnvTimeout(envVar, defaultMs, minMs = 5e3) {
5576
5638
  const val = process.env[envVar];
@@ -5823,14 +5885,30 @@ async function streamGeneration(config) {
5823
5885
  let charsReceived = 0;
5824
5886
  let settled = false;
5825
5887
  let inactivityTimer = null;
5888
+ let softWarnTimer = null;
5889
+ let softWarnFired = false;
5826
5890
  function clearInactivityTimer() {
5827
5891
  if (inactivityTimer) {
5828
5892
  clearTimeout(inactivityTimer);
5829
5893
  inactivityTimer = null;
5830
5894
  }
5895
+ if (softWarnTimer) {
5896
+ clearTimeout(softWarnTimer);
5897
+ softWarnTimer = null;
5898
+ }
5831
5899
  }
5832
5900
  function resetInactivityTimer() {
5833
5901
  if (inactivityTimer) clearTimeout(inactivityTimer);
5902
+ if (softWarnTimer) clearTimeout(softWarnTimer);
5903
+ if (config.callbacks && !softWarnFired && SOFT_INACTIVITY_WARN_MS < inactivityTimeoutMs) {
5904
+ softWarnTimer = setTimeout(() => {
5905
+ if (settled) return;
5906
+ softWarnFired = true;
5907
+ config.callbacks?.onStatus(
5908
+ "Model is taking longer than usual on this prompt \u2014 large repos may need more time. Set CALIBER_STREAM_INACTIVITY_TIMEOUT_MS to override."
5909
+ );
5910
+ }, SOFT_INACTIVITY_WARN_MS);
5911
+ }
5834
5912
  inactivityTimer = setTimeout(() => {
5835
5913
  if (settled) return;
5836
5914
  settled = true;
@@ -7745,10 +7823,11 @@ function detectGitDrift(dir) {
7745
7823
  }
7746
7824
  const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules", ".cursor/rules"];
7747
7825
  try {
7748
- const headTimestamp = execSync12(
7749
- "git log -1 --format=%ct HEAD",
7750
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
7751
- ).trim();
7826
+ const headTimestamp = execSync12("git log -1 --format=%ct HEAD", {
7827
+ cwd: dir,
7828
+ encoding: "utf-8",
7829
+ stdio: ["pipe", "pipe", "pipe"]
7830
+ }).trim();
7752
7831
  const headTime = parseInt(headTimestamp, 10) * 1e3;
7753
7832
  for (const file of configFiles) {
7754
7833
  const filePath = join5(dir, file);
@@ -7756,7 +7835,11 @@ function detectGitDrift(dir) {
7756
7835
  try {
7757
7836
  const mtime = statSync(filePath).mtime.getTime();
7758
7837
  if (mtime > headTime) {
7759
- return { commitsSinceConfigUpdate: 0, lastConfigCommit: "uncommitted (recently modified)", isGitRepo: true };
7838
+ return {
7839
+ commitsSinceConfigUpdate: 0,
7840
+ lastConfigCommit: "uncommitted (recently modified)",
7841
+ isGitRepo: true
7842
+ };
7760
7843
  }
7761
7844
  } catch {
7762
7845
  }
@@ -7766,19 +7849,20 @@ function detectGitDrift(dir) {
7766
7849
  let latestConfigCommitHash = null;
7767
7850
  for (const file of configFiles) {
7768
7851
  try {
7769
- const hash = execSync12(
7770
- `git log -1 --format=%H -- "${file}"`,
7771
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
7772
- ).trim();
7852
+ const hash = execSync12(`git log -1 --format=%H -- "${file}"`, {
7853
+ cwd: dir,
7854
+ encoding: "utf-8",
7855
+ stdio: ["pipe", "pipe", "pipe"]
7856
+ }).trim();
7773
7857
  if (!hash) continue;
7774
7858
  if (!latestConfigCommitHash) {
7775
7859
  latestConfigCommitHash = hash;
7776
7860
  } else {
7777
7861
  try {
7778
- execSync12(
7779
- `git merge-base --is-ancestor ${latestConfigCommitHash} ${hash}`,
7780
- { cwd: dir, stdio: ["pipe", "pipe", "pipe"] }
7781
- );
7862
+ execSync12(`git merge-base --is-ancestor ${latestConfigCommitHash} ${hash}`, {
7863
+ cwd: dir,
7864
+ stdio: ["pipe", "pipe", "pipe"]
7865
+ });
7782
7866
  latestConfigCommitHash = hash;
7783
7867
  } catch {
7784
7868
  }
@@ -7790,22 +7874,28 @@ function detectGitDrift(dir) {
7790
7874
  return { commitsSinceConfigUpdate: 0, lastConfigCommit: null, isGitRepo: true };
7791
7875
  }
7792
7876
  try {
7793
- const countStr = execSync12(
7794
- `git rev-list --count ${latestConfigCommitHash}..HEAD`,
7795
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
7796
- ).trim();
7877
+ const countStr = execSync12(`git rev-list --count ${latestConfigCommitHash}..HEAD`, {
7878
+ cwd: dir,
7879
+ encoding: "utf-8",
7880
+ stdio: ["pipe", "pipe", "pipe"]
7881
+ }).trim();
7797
7882
  const commitsSince = parseInt(countStr, 10) || 0;
7798
- const lastDate = execSync12(
7799
- `git log -1 --format=%ci ${latestConfigCommitHash}`,
7800
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
7801
- ).trim();
7883
+ const lastDate = execSync12(`git log -1 --format=%ci ${latestConfigCommitHash}`, {
7884
+ cwd: dir,
7885
+ encoding: "utf-8",
7886
+ stdio: ["pipe", "pipe", "pipe"]
7887
+ }).trim();
7802
7888
  return {
7803
7889
  commitsSinceConfigUpdate: commitsSince,
7804
7890
  lastConfigCommit: lastDate,
7805
7891
  isGitRepo: true
7806
7892
  };
7807
7893
  } catch {
7808
- return { commitsSinceConfigUpdate: 0, lastConfigCommit: latestConfigCommitHash, isGitRepo: true };
7894
+ return {
7895
+ commitsSinceConfigUpdate: 0,
7896
+ lastConfigCommit: latestConfigCommitHash,
7897
+ isGitRepo: true
7898
+ };
7809
7899
  }
7810
7900
  }
7811
7901
  function checkAccuracy(dir) {
@@ -7855,10 +7945,13 @@ function checkAccuracy(dir) {
7855
7945
  earnedPoints: driftPoints,
7856
7946
  passed: drift.commitsSinceConfigUpdate <= 15 || !drift.isGitRepo,
7857
7947
  detail: !drift.isGitRepo ? "Not a git repository \u2014 skipping drift check" : !drift.lastConfigCommit ? "Config files not tracked in git" : drift.commitsSinceConfigUpdate === 0 ? "Config is up to date with latest commits" : `${drift.commitsSinceConfigUpdate} commit${drift.commitsSinceConfigUpdate === 1 ? "" : "s"} since last config update`,
7858
- suggestion: drift.commitsSinceConfigUpdate > 15 ? `Code has had ${drift.commitsSinceConfigUpdate} commits since last config update \u2014 run \`${resolveCaliber()} refresh\` to sync` : void 0,
7948
+ suggestion: drift.commitsSinceConfigUpdate > 15 ? `Code has had ${drift.commitsSinceConfigUpdate} commits since last config update \u2014 run \`${displayCaliberName()} refresh\` to sync` : void 0,
7859
7949
  fix: drift.commitsSinceConfigUpdate > 15 ? {
7860
7950
  action: "refresh_config",
7861
- data: { commitsSince: drift.commitsSinceConfigUpdate, lastConfigCommit: drift.lastConfigCommit },
7951
+ data: {
7952
+ commitsSince: drift.commitsSinceConfigUpdate,
7953
+ lastConfigCommit: drift.lastConfigCommit
7954
+ },
7862
7955
  instruction: `Config is ${drift.commitsSinceConfigUpdate} commits behind. Review recent changes and update config accordingly.`
7863
7956
  } : void 0
7864
7957
  });
@@ -7873,10 +7966,11 @@ import { join as join6 } from "path";
7873
7966
  function getCommitsSinceConfigUpdate(dir) {
7874
7967
  const configFiles = ["CLAUDE.md", "AGENTS.md", ".cursorrules"];
7875
7968
  try {
7876
- const headTimestamp = execSync13(
7877
- "git log -1 --format=%ct HEAD",
7878
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
7879
- ).trim();
7969
+ const headTimestamp = execSync13("git log -1 --format=%ct HEAD", {
7970
+ cwd: dir,
7971
+ encoding: "utf-8",
7972
+ stdio: ["pipe", "pipe", "pipe"]
7973
+ }).trim();
7880
7974
  const headTime = parseInt(headTimestamp, 10) * 1e3;
7881
7975
  for (const file of configFiles) {
7882
7976
  const filePath = join6(dir, file);
@@ -7893,15 +7987,17 @@ function getCommitsSinceConfigUpdate(dir) {
7893
7987
  }
7894
7988
  for (const file of configFiles) {
7895
7989
  try {
7896
- const hash = execSync13(
7897
- `git log -1 --format=%H -- "${file}"`,
7898
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
7899
- ).trim();
7990
+ const hash = execSync13(`git log -1 --format=%H -- "${file}"`, {
7991
+ cwd: dir,
7992
+ encoding: "utf-8",
7993
+ stdio: ["pipe", "pipe", "pipe"]
7994
+ }).trim();
7900
7995
  if (hash) {
7901
- const countStr = execSync13(
7902
- `git rev-list --count ${hash}..HEAD`,
7903
- { cwd: dir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
7904
- ).trim();
7996
+ const countStr = execSync13(`git rev-list --count ${hash}..HEAD`, {
7997
+ cwd: dir,
7998
+ encoding: "utf-8",
7999
+ stdio: ["pipe", "pipe", "pipe"]
8000
+ }).trim();
7905
8001
  return parseInt(countStr, 10) || 0;
7906
8002
  }
7907
8003
  } catch {
@@ -7930,7 +8026,7 @@ function checkFreshness(dir) {
7930
8026
  earnedPoints: freshnessPoints,
7931
8027
  passed: freshnessPoints >= 3,
7932
8028
  detail: freshnessDetail,
7933
- suggestion: commitsSince !== null && freshnessPoints < 3 ? `Config is ${commitsSince} commits behind \u2014 run \`${resolveCaliber()} refresh\` to update it` : void 0,
8029
+ suggestion: commitsSince !== null && freshnessPoints < 3 ? `Config is ${commitsSince} commits behind \u2014 run \`${displayCaliberName()} refresh\` to update it` : void 0,
7934
8030
  fix: commitsSince !== null && freshnessPoints < 3 ? {
7935
8031
  action: "refresh_config",
7936
8032
  data: { commitsSince },
@@ -8082,11 +8178,11 @@ function checkBonus(dir) {
8082
8178
  earnedPoints: hasHooks ? POINTS_HOOKS : 0,
8083
8179
  passed: hasHooks,
8084
8180
  detail: hasHooks ? hookSources.join(", ") : "No hooks configured",
8085
- suggestion: hasHooks ? void 0 : `Hooks auto-sync your agent config on every commit so it stays fresh. Run \`${resolveCaliber()} init\` to set up`,
8181
+ suggestion: hasHooks ? void 0 : `Hooks auto-sync your agent config on every commit so it stays fresh. Run \`${displayCaliberName()} init\` to set up`,
8086
8182
  fix: hasHooks ? void 0 : {
8087
8183
  action: "install_hooks",
8088
8184
  data: {},
8089
- instruction: `Run ${resolveCaliber()} init to add pre-commit refresh instructions to config files.`
8185
+ instruction: `Run ${displayCaliberName()} init to add pre-commit refresh instructions to config files.`
8090
8186
  }
8091
8187
  });
8092
8188
  const agentsMdExists = existsSync6(join7(dir, "AGENTS.md"));
@@ -8151,7 +8247,7 @@ function checkBonus(dir) {
8151
8247
  earnedPoints: hasLearned ? POINTS_LEARNED_CONTENT : 0,
8152
8248
  passed: hasLearned,
8153
8249
  detail: hasLearned ? "Session learnings found in CALIBER_LEARNINGS.md" : "No learned content",
8154
- suggestion: hasLearned ? void 0 : `Session learnings capture patterns from your coding sessions so the agent improves over time. Run \`${resolveCaliber()} learn install\``
8250
+ suggestion: hasLearned ? void 0 : `Session learnings capture patterns from your coding sessions so the agent improves over time. Run \`${displayCaliberName()} learn install\``
8155
8251
  });
8156
8252
  const configContent = (() => {
8157
8253
  const parts = [];
@@ -8198,7 +8294,7 @@ function checkSources(dir) {
8198
8294
  earnedPoints: hasSources ? POINTS_SOURCES_CONFIGURED : 0,
8199
8295
  passed: hasSources,
8200
8296
  detail: hasSources ? `${configSources.length} source${configSources.length === 1 ? "" : "s"} configured` : "No external sources configured",
8201
- suggestion: hasSources ? void 0 : `Run \`${resolveCaliber()} sources add <path>\` to add related repos or docs`
8297
+ suggestion: hasSources ? void 0 : `Run \`${displayCaliberName()} sources add <path>\` to add related repos or docs`
8202
8298
  });
8203
8299
  if (hasSources) {
8204
8300
  const claudeMd = readFileOrNull(join8(dir, "CLAUDE.md"));
@@ -8216,7 +8312,7 @@ function checkSources(dir) {
8216
8312
  earnedPoints: referenced ? POINTS_SOURCES_REFERENCED : 0,
8217
8313
  passed: referenced,
8218
8314
  detail: referenced ? "At least one source is referenced in CLAUDE.md" : "No configured sources are mentioned in CLAUDE.md",
8219
- suggestion: referenced ? void 0 : `Regenerate with \`${resolveCaliber()} init\` to include source context in your config`
8315
+ suggestion: referenced ? void 0 : `Regenerate with \`${displayCaliberName()} init\` to include source context in your config`
8220
8316
  });
8221
8317
  }
8222
8318
  return checks;
@@ -8327,7 +8423,14 @@ var CATEGORY_LABELS = {
8327
8423
  freshness: { icon: "\u{1F6E1}\uFE0F", label: "FRESHNESS & SAFETY" },
8328
8424
  bonus: { icon: "\u2B50", label: "BONUS" }
8329
8425
  };
8330
- var CATEGORY_ORDER = ["existence", "quality", "grounding", "accuracy", "freshness", "bonus"];
8426
+ var CATEGORY_ORDER = [
8427
+ "existence",
8428
+ "quality",
8429
+ "grounding",
8430
+ "accuracy",
8431
+ "freshness",
8432
+ "bonus"
8433
+ ];
8331
8434
  function gradeColor(grade) {
8332
8435
  switch (grade) {
8333
8436
  case "A":
@@ -8396,7 +8499,9 @@ function displayScore(result) {
8396
8499
  console.log("");
8397
8500
  console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8398
8501
  console.log("");
8399
- console.log(` ${chalk3.bold("Agent Config Score")} ${gc(chalk3.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk3.bold(result.grade))}`);
8502
+ console.log(
8503
+ ` ${chalk3.bold("Agent Config Score")} ${gc(chalk3.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk3.bold(result.grade))}`
8504
+ );
8400
8505
  console.log(` ${progressBar(result.score, result.maxScore)}`);
8401
8506
  console.log(chalk3.dim(` Target: ${agentLabel}`));
8402
8507
  console.log("");
@@ -8419,7 +8524,11 @@ function displayScore(result) {
8419
8524
  formatTopImprovements(result.checks);
8420
8525
  }
8421
8526
  function formatTopImprovements(checks) {
8422
- const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({ name: c.name, potential: c.maxPoints - c.earnedPoints, suggestion: c.suggestion })).sort((a, b) => b.potential - a.potential).slice(0, 5);
8527
+ const improvable = checks.filter((c) => c.earnedPoints < c.maxPoints).map((c) => ({
8528
+ name: c.name,
8529
+ potential: c.maxPoints - c.earnedPoints,
8530
+ suggestion: c.suggestion
8531
+ })).sort((a, b) => b.potential - a.potential).slice(0, 5);
8423
8532
  if (improvable.length === 0) return;
8424
8533
  console.log(chalk3.gray(" \u2500 TOP IMPROVEMENTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8425
8534
  console.log("");
@@ -8450,8 +8559,12 @@ function displayScoreSummary(result) {
8450
8559
  }
8451
8560
  const remaining = failing.length - shown.length;
8452
8561
  const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
8453
- console.log(chalk3.dim(`
8454
- Run ${chalk3.hex("#83D1EB")(`${resolveCaliber()} score`)} for details.${moreText}`));
8562
+ console.log(
8563
+ chalk3.dim(
8564
+ `
8565
+ Run ${chalk3.hex("#83D1EB")(`${displayCaliberName()} score`)} for details.${moreText}`
8566
+ )
8567
+ );
8455
8568
  }
8456
8569
  console.log("");
8457
8570
  }
@@ -8467,7 +8580,9 @@ function displayScoreDelta(before, after) {
8467
8580
  console.log(
8468
8581
  ` Score: ${beforeGc(`${before.score}`)} ${chalk3.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk3.gray("\u2192")} ${afterGc(after.grade)}`
8469
8582
  );
8470
- console.log(` ${progressBar(before.score, before.maxScore, 19)} ${chalk3.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`);
8583
+ console.log(
8584
+ ` ${progressBar(before.score, before.maxScore, 19)} ${chalk3.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`
8585
+ );
8471
8586
  console.log("");
8472
8587
  console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8473
8588
  console.log("");
@@ -9149,7 +9264,7 @@ async function querySkills(query) {
9149
9264
  console.log("");
9150
9265
  console.log(
9151
9266
  chalk5.dim(
9152
- ` Install with: ${resolveCaliber()} skills --install ${available.map((r) => r.slug).join(",")}`
9267
+ ` Install with: ${displayCaliberName()} skills --install ${available.map((r) => r.slug).join(",")}`
9153
9268
  )
9154
9269
  );
9155
9270
  console.log("");
@@ -11137,7 +11252,7 @@ function log(verbose, ...args) {
11137
11252
  async function initCommand(options) {
11138
11253
  const brand = chalk14.hex("#EB9D83");
11139
11254
  const title = chalk14.hex("#83D1EB");
11140
- const bin = resolveCaliber();
11255
+ const bin = displayCaliberName();
11141
11256
  const firstRun = isFirstRun(process.cwd());
11142
11257
  if (firstRun) {
11143
11258
  console.log(
@@ -11278,6 +11393,8 @@ async function initCommand(options) {
11278
11393
  const hookResult = installPreCommitHook();
11279
11394
  if (hookResult.installed) {
11280
11395
  console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed \u2014 configs sync on every commit`);
11396
+ } else if (hookResult.upgraded) {
11397
+ console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 upgraded to latest version`);
11281
11398
  } else if (hookResult.alreadyInstalled) {
11282
11399
  console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 active`);
11283
11400
  }
@@ -11977,24 +12094,34 @@ async function statusCommand(options) {
11977
12094
  const config = loadConfig();
11978
12095
  const manifest = readManifest();
11979
12096
  if (options.json) {
11980
- console.log(JSON.stringify({
11981
- configured: !!config,
11982
- provider: config?.provider,
11983
- model: config?.model,
11984
- manifest
11985
- }, null, 2));
12097
+ console.log(
12098
+ JSON.stringify(
12099
+ {
12100
+ configured: !!config,
12101
+ provider: config?.provider,
12102
+ model: config?.model,
12103
+ manifest
12104
+ },
12105
+ null,
12106
+ 2
12107
+ )
12108
+ );
11986
12109
  return;
11987
12110
  }
11988
12111
  console.log(chalk16.bold("\nCaliber Status\n"));
11989
12112
  if (config) {
11990
12113
  console.log(` LLM: ${chalk16.green(config.provider)} (${config.model})`);
11991
12114
  } else {
11992
- const bin = resolveCaliber();
11993
- console.log(` LLM: ${chalk16.yellow("Not configured")} \u2014 run ${chalk16.hex("#83D1EB")(`${bin} config`)}`);
12115
+ const bin = displayCaliberName();
12116
+ console.log(
12117
+ ` LLM: ${chalk16.yellow("Not configured")} \u2014 run ${chalk16.hex("#83D1EB")(`${bin} config`)}`
12118
+ );
11994
12119
  }
11995
12120
  if (!manifest) {
11996
12121
  console.log(` Config: ${chalk16.dim("No config applied")}`);
11997
- console.log(chalk16.dim("\n Run ") + chalk16.hex("#83D1EB")(`${resolveCaliber()} init`) + chalk16.dim(" to get started.\n"));
12122
+ console.log(
12123
+ chalk16.dim("\n Run ") + chalk16.hex("#83D1EB")(`${displayCaliberName()} init`) + chalk16.dim(" to get started.\n")
12124
+ );
11998
12125
  return;
11999
12126
  }
12000
12127
  console.log(` Files managed: ${chalk16.cyan(manifest.entries.length.toString())}`);
@@ -12014,15 +12141,19 @@ init_review();
12014
12141
  init_config();
12015
12142
  init_resolve_caliber();
12016
12143
  async function regenerateCommand(options) {
12017
- const bin = resolveCaliber();
12144
+ const bin = displayCaliberName();
12018
12145
  const config = loadConfig();
12019
12146
  if (!config) {
12020
- console.log(chalk17.red("No LLM provider configured. Run ") + chalk17.hex("#83D1EB")(`${bin} config`) + chalk17.red(" first."));
12147
+ console.log(
12148
+ chalk17.red("No LLM provider configured. Run ") + chalk17.hex("#83D1EB")(`${bin} config`) + chalk17.red(" first.")
12149
+ );
12021
12150
  throw new Error("__exit__");
12022
12151
  }
12023
12152
  const manifest = readManifest();
12024
12153
  if (!manifest) {
12025
- console.log(chalk17.yellow("No existing config found. Run ") + chalk17.hex("#83D1EB")(`${bin} init`) + chalk17.yellow(" first."));
12154
+ console.log(
12155
+ chalk17.yellow("No existing config found. Run ") + chalk17.hex("#83D1EB")(`${bin} init`) + chalk17.yellow(" first.")
12156
+ );
12026
12157
  throw new Error("__exit__");
12027
12158
  }
12028
12159
  const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
@@ -12037,27 +12168,24 @@ async function regenerateCommand(options) {
12037
12168
  return;
12038
12169
  }
12039
12170
  const genSpinner = ora5("Regenerating config...").start();
12040
- const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, { showElapsedTime: true });
12171
+ const genMessages = new SpinnerMessages(genSpinner, GENERATION_MESSAGES, {
12172
+ showElapsedTime: true
12173
+ });
12041
12174
  genMessages.start();
12042
12175
  let generatedSetup = null;
12043
12176
  try {
12044
- const result = await generateSetup(
12045
- fingerprint,
12046
- targetAgent,
12047
- void 0,
12048
- {
12049
- onStatus: (status) => {
12050
- genMessages.handleServerStatus(status);
12051
- },
12052
- onComplete: (setup) => {
12053
- generatedSetup = setup;
12054
- },
12055
- onError: (error) => {
12056
- genMessages.stop();
12057
- genSpinner.fail(`Generation error: ${error}`);
12058
- }
12177
+ const result = await generateSetup(fingerprint, targetAgent, void 0, {
12178
+ onStatus: (status) => {
12179
+ genMessages.handleServerStatus(status);
12180
+ },
12181
+ onComplete: (setup) => {
12182
+ generatedSetup = setup;
12183
+ },
12184
+ onError: (error) => {
12185
+ genMessages.stop();
12186
+ genSpinner.fail(`Generation error: ${error}`);
12059
12187
  }
12060
- );
12188
+ });
12061
12189
  if (!generatedSetup) generatedSetup = result.setup;
12062
12190
  } catch (err) {
12063
12191
  genMessages.stop();
@@ -12075,9 +12203,13 @@ async function regenerateCommand(options) {
12075
12203
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
12076
12204
  const staged = stageFiles(setupFiles, process.cwd());
12077
12205
  const totalChanges = staged.newFiles + staged.modifiedFiles;
12078
- console.log(chalk17.dim(`
12206
+ console.log(
12207
+ chalk17.dim(
12208
+ `
12079
12209
  ${chalk17.green(`${staged.newFiles} new`)} / ${chalk17.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
12080
- `));
12210
+ `
12211
+ )
12212
+ );
12081
12213
  if (totalChanges === 0) {
12082
12214
  console.log(chalk17.dim(" No changes needed \u2014 your configs are already up to date.\n"));
12083
12215
  cleanupStaging();
@@ -12138,21 +12270,33 @@ async function regenerateCommand(options) {
12138
12270
  const afterScore = computeLocalScore(process.cwd(), targetAgent);
12139
12271
  if (afterScore.score < baselineScore.score) {
12140
12272
  console.log("");
12141
- console.log(chalk17.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
12273
+ console.log(
12274
+ chalk17.yellow(
12275
+ ` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`
12276
+ )
12277
+ );
12142
12278
  try {
12143
12279
  const { restored, removed } = undoSetup();
12144
12280
  if (restored.length > 0 || removed.length > 0) {
12145
- console.log(chalk17.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
12281
+ console.log(
12282
+ chalk17.dim(
12283
+ ` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`
12284
+ )
12285
+ );
12146
12286
  }
12147
12287
  } catch {
12148
12288
  }
12149
- console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} init --force`) + chalk17.dim(" to override.\n"));
12289
+ console.log(
12290
+ chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} init --force`) + chalk17.dim(" to override.\n")
12291
+ );
12150
12292
  return;
12151
12293
  }
12152
12294
  displayScoreDelta(baselineScore, afterScore);
12153
12295
  trackRegenerateCompleted(action, Date.now());
12154
12296
  console.log(chalk17.bold.green(" Regeneration complete!"));
12155
- console.log(chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} undo`) + chalk17.dim(" to revert changes.\n"));
12297
+ console.log(
12298
+ chalk17.dim(" Run ") + chalk17.hex("#83D1EB")(`${bin} undo`) + chalk17.dim(" to revert changes.\n")
12299
+ );
12156
12300
  }
12157
12301
 
12158
12302
  // src/commands/score.ts
@@ -12267,7 +12411,7 @@ async function scoreCommand(options) {
12267
12411
  displayScore(result);
12268
12412
  const separator = chalk18.gray(" " + "\u2500".repeat(53));
12269
12413
  console.log(separator);
12270
- const bin = resolveCaliber();
12414
+ const bin = displayCaliberName();
12271
12415
  const failing = result.checks.filter((c) => !c.passed && c.maxPoints > 0).sort((a, b) => b.maxPoints - b.earnedPoints - (a.maxPoints - a.earnedPoints));
12272
12416
  if (result.score < 70 && failing.length > 0) {
12273
12417
  const topFix = failing[0];
@@ -13204,6 +13348,7 @@ async function refreshSingleRepo(repoDir, options) {
13204
13348
  async function refreshCommand(options) {
13205
13349
  const quiet = !!options.quiet;
13206
13350
  if (quiet && isCaliberSubprocess()) return;
13351
+ if (quiet && isHookCascadeFromUserClaudeSession()) return;
13207
13352
  if (quiet) {
13208
13353
  const { isCaliberRunning: isCaliberRunning2 } = await Promise.resolve().then(() => (init_lock(), lock_exports));
13209
13354
  if (isCaliberRunning2()) return;
@@ -13228,7 +13373,7 @@ async function refreshCommand(options) {
13228
13373
  if (!config) {
13229
13374
  if (quiet) return;
13230
13375
  console.log(
13231
- chalk19.red("No LLM provider configured. Run ") + chalk19.hex("#83D1EB")(`${resolveCaliber()} config`) + chalk19.red(" (e.g. choose Cursor) or set an API key.")
13376
+ chalk19.red("No LLM provider configured. Run ") + chalk19.hex("#83D1EB")(`${displayCaliberName()} config`) + chalk19.red(" (e.g. choose Cursor) or set an API key.")
13232
13377
  );
13233
13378
  throw new Error("__exit__");
13234
13379
  }
@@ -13336,7 +13481,9 @@ async function hooksCommand(options) {
13336
13481
  if (options.install) {
13337
13482
  for (const hook of HOOKS) {
13338
13483
  const result = hook.install();
13339
- if (result.alreadyInstalled) {
13484
+ if (result.upgraded) {
13485
+ console.log(chalk20.green(" \u2713") + ` ${hook.label} upgraded to latest version`);
13486
+ } else if (result.alreadyInstalled) {
13340
13487
  console.log(chalk20.dim(` ${hook.label} already enabled.`));
13341
13488
  } else {
13342
13489
  console.log(chalk20.green(" \u2713") + ` ${hook.label} enabled`);
@@ -14253,6 +14400,7 @@ async function learnFinalizeCommand(options) {
14253
14400
  const isAuto = options?.auto === true;
14254
14401
  const isIncremental = options?.incremental === true;
14255
14402
  if (isAuto && isCaliberSubprocess()) return;
14403
+ if (isAuto && isHookCascadeFromUserClaudeSession()) return;
14256
14404
  if (!options?.force && !isAuto) {
14257
14405
  const { isCaliberRunning: isCaliberRunning2 } = await Promise.resolve().then(() => (init_lock(), lock_exports));
14258
14406
  if (isCaliberRunning2()) {
@@ -14276,7 +14424,7 @@ async function learnFinalizeCommand(options) {
14276
14424
  if (isAuto) return;
14277
14425
  console.log(
14278
14426
  chalk23.yellow(
14279
- `caliber: no LLM provider configured \u2014 run \`${resolveCaliber()} config\` first`
14427
+ `caliber: no LLM provider configured \u2014 run \`${displayCaliberName()} config\` first`
14280
14428
  )
14281
14429
  );
14282
14430
  clearSession();
@@ -14442,7 +14590,7 @@ async function learnFinalizeCommand(options) {
14442
14590
  if (staleLearnings.length > 0 && !isAuto) {
14443
14591
  console.log(
14444
14592
  chalk23.yellow(
14445
- `caliber: ${staleLearnings.length} learning${staleLearnings.length === 1 ? "" : "s"} never activated \u2014 run \`${resolveCaliber()} learn list --verbose\` to review`
14593
+ `caliber: ${staleLearnings.length} learning${staleLearnings.length === 1 ? "" : "s"} never activated \u2014 run \`${displayCaliberName()} learn list --verbose\` to review`
14446
14594
  )
14447
14595
  );
14448
14596
  }
@@ -14499,7 +14647,7 @@ async function learnInstallCommand() {
14499
14647
  if (!fs48.existsSync(".claude") && !fs48.existsSync(".cursor")) {
14500
14648
  console.log(chalk23.yellow("No .claude/ or .cursor/ directory found."));
14501
14649
  console.log(
14502
- chalk23.dim(` Run \`${resolveCaliber()} init\` first, or create the directory manually.`)
14650
+ chalk23.dim(` Run \`${displayCaliberName()} init\` first, or create the directory manually.`)
14503
14651
  );
14504
14652
  return;
14505
14653
  }
@@ -14547,7 +14695,7 @@ async function learnStatusCommand() {
14547
14695
  }
14548
14696
  if (!claudeInstalled && !cursorInstalled) {
14549
14697
  console.log(
14550
- chalk23.dim(` Run \`${resolveCaliber()} learn install\` to enable session learning.`)
14698
+ chalk23.dim(` Run \`${displayCaliberName()} learn install\` to enable session learning.`)
14551
14699
  );
14552
14700
  }
14553
14701
  console.log();
@@ -14603,7 +14751,9 @@ function getAllLearnings() {
14603
14751
  async function learnListCommand(options) {
14604
14752
  const items = getAllLearnings();
14605
14753
  if (items.length === 0) {
14606
- console.log(chalk23.dim(`No learnings yet. Run \`${resolveCaliber()} learn install\` to start.`));
14754
+ console.log(
14755
+ chalk23.dim(`No learnings yet. Run \`${displayCaliberName()} learn install\` to start.`)
14756
+ );
14607
14757
  return;
14608
14758
  }
14609
14759
  const roiStats = options?.verbose ? readROIStats() : null;
@@ -14634,7 +14784,7 @@ async function learnDeleteCommand(indexStr) {
14634
14784
  if (isNaN(index) || index < 1) {
14635
14785
  console.log(
14636
14786
  chalk23.red(
14637
- `Invalid index: "${indexStr}". Use a number from \`${resolveCaliber()} learn list\`.`
14787
+ `Invalid index: "${indexStr}". Use a number from \`${displayCaliberName()} learn list\`.`
14638
14788
  )
14639
14789
  );
14640
14790
  return;
@@ -14745,13 +14895,23 @@ function displayColdStart(score) {
14745
14895
  const hooksInstalled = areLearningHooksInstalled() || areCursorLearningHooksInstalled();
14746
14896
  if (!hooksInstalled) {
14747
14897
  console.log(chalk24.yellow(" Learning hooks not installed."));
14748
- console.log(chalk24.dim(" Session learning captures patterns from your AI coding sessions \u2014 what"));
14749
- console.log(chalk24.dim(" fails, what works, corrections you make \u2014 so your agents improve over time.\n"));
14750
- console.log(chalk24.dim(" Run ") + chalk24.cyan(`${resolveCaliber()} learn install`) + chalk24.dim(" to enable."));
14898
+ console.log(
14899
+ chalk24.dim(" Session learning captures patterns from your AI coding sessions \u2014 what")
14900
+ );
14901
+ console.log(
14902
+ chalk24.dim(" fails, what works, corrections you make \u2014 so your agents improve over time.\n")
14903
+ );
14904
+ console.log(
14905
+ chalk24.dim(" Run ") + chalk24.cyan(`${displayCaliberName()} learn install`) + chalk24.dim(" to enable.")
14906
+ );
14751
14907
  } else {
14752
14908
  console.log(chalk24.dim(" Learning hooks are active. Use your AI agent and insights"));
14753
14909
  console.log(chalk24.dim(" will appear automatically after each session.\n"));
14754
- console.log(chalk24.dim(` Progress: 0/${MIN_SESSIONS_FULL} sessions \u2014 full insights unlock at ${MIN_SESSIONS_FULL}`));
14910
+ console.log(
14911
+ chalk24.dim(
14912
+ ` Progress: 0/${MIN_SESSIONS_FULL} sessions \u2014 full insights unlock at ${MIN_SESSIONS_FULL}`
14913
+ )
14914
+ );
14755
14915
  }
14756
14916
  console.log(chalk24.dim(`
14757
14917
  Config score: ${score.score}/100 (${score.grade})`));
@@ -14760,20 +14920,32 @@ function displayColdStart(score) {
14760
14920
  function displayEarlyData(data, score) {
14761
14921
  console.log(chalk24.bold("\n Agent Insights") + chalk24.yellow(" (early data)\n"));
14762
14922
  const remaining = MIN_SESSIONS_FULL - data.totalSessions;
14763
- console.log(chalk24.dim(` ${data.totalSessions}/${MIN_SESSIONS_FULL} sessions tracked \u2014 ${remaining} more for full insights.
14764
- `));
14923
+ console.log(
14924
+ chalk24.dim(
14925
+ ` ${data.totalSessions}/${MIN_SESSIONS_FULL} sessions tracked \u2014 ${remaining} more for full insights.
14926
+ `
14927
+ )
14928
+ );
14765
14929
  console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
14766
14930
  console.log(` Learnings accumulated: ${chalk24.cyan(String(data.learningCount))}`);
14767
14931
  if (data.totalWasteTokens > 0) {
14768
- console.log(` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`);
14932
+ console.log(
14933
+ ` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`
14934
+ );
14769
14935
  }
14770
14936
  if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
14771
- console.log(` Failure rate trend: ${chalk24.green(`${data.failureRateImprovement}% fewer`)} failures with learnings ${chalk24.dim("(early signal)")}`);
14937
+ console.log(
14938
+ ` Failure rate trend: ${chalk24.green(`${data.failureRateImprovement}% fewer`)} failures with learnings ${chalk24.dim("(early signal)")}`
14939
+ );
14772
14940
  } else if (data.totalSessions > 0 && data.failureRateImprovement === null) {
14773
- console.log(` Failure rate trend: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`);
14941
+ console.log(
14942
+ ` Failure rate trend: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`
14943
+ );
14774
14944
  }
14775
14945
  if (data.taskSuccessRate !== null) {
14776
- console.log(` Task success rate: ${chalk24.cyan(`${data.taskSuccessRate}%`)} ${chalk24.dim(`(${data.taskCount} tasks)`)}`);
14946
+ console.log(
14947
+ ` Task success rate: ${chalk24.cyan(`${data.taskSuccessRate}%`)} ${chalk24.dim(`(${data.taskCount} tasks)`)}`
14948
+ );
14777
14949
  }
14778
14950
  console.log(` Config score: ${chalk24.cyan(`${score.score}/100`)} (${score.grade})`);
14779
14951
  console.log("");
@@ -14783,32 +14955,48 @@ function displayFullInsights(data, score) {
14783
14955
  console.log(chalk24.bold(" Agent Health"));
14784
14956
  if (data.taskSuccessRate !== null) {
14785
14957
  const color = data.taskSuccessRate >= 80 ? chalk24.green : data.taskSuccessRate >= 60 ? chalk24.yellow : chalk24.red;
14786
- console.log(` Task success rate: ${color(`${data.taskSuccessRate}%`)} across ${data.taskCount} tasks`);
14958
+ console.log(
14959
+ ` Task success rate: ${color(`${data.taskSuccessRate}%`)} across ${data.taskCount} tasks`
14960
+ );
14787
14961
  if (data.taskCorrectionCount > 0) {
14788
- console.log(` Corrections needed: ${chalk24.yellow(String(data.taskCorrectionCount))} tasks required user correction`);
14962
+ console.log(
14963
+ ` Corrections needed: ${chalk24.yellow(String(data.taskCorrectionCount))} tasks required user correction`
14964
+ );
14789
14965
  }
14790
14966
  }
14791
14967
  console.log(` Sessions tracked: ${chalk24.cyan(String(data.totalSessions))}`);
14792
14968
  console.log(chalk24.bold("\n Learning Impact"));
14793
14969
  console.log(` Learnings active: ${chalk24.cyan(String(data.learningCount))}`);
14794
14970
  if (data.failureRateWith !== null && data.failureRateWithout !== null) {
14795
- console.log(` Failure rate: ${chalk24.red(data.failureRateWithout.toFixed(1))}/session ${chalk24.dim("\u2192")} ${chalk24.green(data.failureRateWith.toFixed(1))}/session with learnings`);
14971
+ console.log(
14972
+ ` Failure rate: ${chalk24.red(data.failureRateWithout.toFixed(1))}/session ${chalk24.dim("\u2192")} ${chalk24.green(data.failureRateWith.toFixed(1))}/session with learnings`
14973
+ );
14796
14974
  if (data.failureRateImprovement !== null && data.failureRateImprovement > 0) {
14797
- console.log(` Improvement: ${chalk24.green(`${data.failureRateImprovement}%`)} fewer failures`);
14975
+ console.log(
14976
+ ` Improvement: ${chalk24.green(`${data.failureRateImprovement}%`)} fewer failures`
14977
+ );
14798
14978
  } else if (data.failureRateImprovement === null) {
14799
- console.log(` Improvement: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`);
14979
+ console.log(
14980
+ ` Improvement: ${chalk24.dim("collecting data (need 3+ sessions in each group)")}`
14981
+ );
14800
14982
  }
14801
14983
  }
14802
14984
  if (data.totalWasteTokens > 0 || data.estimatedSavingsTokens > 0) {
14803
14985
  console.log(chalk24.bold("\n Efficiency"));
14804
14986
  if (data.totalWasteTokens > 0) {
14805
- console.log(` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`);
14987
+ console.log(
14988
+ ` Waste captured: ${chalk24.cyan(data.totalWasteTokens.toLocaleString())} tokens`
14989
+ );
14806
14990
  }
14807
14991
  if (data.estimatedSavingsTokens > 0) {
14808
- console.log(` Estimated savings: ~${chalk24.green(data.estimatedSavingsTokens.toLocaleString())} tokens`);
14992
+ console.log(
14993
+ ` Estimated savings: ~${chalk24.green(data.estimatedSavingsTokens.toLocaleString())} tokens`
14994
+ );
14809
14995
  }
14810
14996
  if (data.estimatedSavingsSeconds > 0) {
14811
- console.log(` Time saved: ~${chalk24.green(formatDuration(data.estimatedSavingsSeconds))}`);
14997
+ console.log(
14998
+ ` Time saved: ~${chalk24.green(formatDuration(data.estimatedSavingsSeconds))}`
14999
+ );
14812
15000
  }
14813
15001
  }
14814
15002
  console.log(chalk24.bold("\n Config Quality"));
@@ -14819,7 +15007,9 @@ function displayFullInsights(data, score) {
14819
15007
  const trendColor = trend.direction === "up" ? chalk24.green : trend.direction === "down" ? chalk24.red : chalk24.gray;
14820
15008
  const arrow = trend.direction === "up" ? "\u2191" : trend.direction === "down" ? "\u2193" : "\u2192";
14821
15009
  const sign = trend.delta > 0 ? "+" : "";
14822
- console.log(` Trend: ${trendColor(`${arrow} ${sign}${trend.delta} pts`)} ${chalk24.dim(`over ${trend.entries} checks`)}`);
15010
+ console.log(
15011
+ ` Trend: ${trendColor(`${arrow} ${sign}${trend.delta} pts`)} ${chalk24.dim(`over ${trend.entries} checks`)}`
15012
+ );
14823
15013
  }
14824
15014
  console.log("");
14825
15015
  }
@@ -14829,12 +15019,18 @@ async function insightsCommand(options) {
14829
15019
  const score = computeLocalScore(process.cwd(), readState()?.targetAgent);
14830
15020
  trackInsightsViewed(data.totalSessions, data.learningCount);
14831
15021
  if (options.json) {
14832
- console.log(JSON.stringify({
14833
- ...data,
14834
- tier: data.totalSessions === 0 ? "cold-start" : data.totalSessions < MIN_SESSIONS_FULL ? "early" : "full",
14835
- configScore: score.score,
14836
- configGrade: score.grade
14837
- }, null, 2));
15022
+ console.log(
15023
+ JSON.stringify(
15024
+ {
15025
+ ...data,
15026
+ tier: data.totalSessions === 0 ? "cold-start" : data.totalSessions < MIN_SESSIONS_FULL ? "early" : "full",
15027
+ configScore: score.score,
15028
+ configGrade: score.grade
15029
+ },
15030
+ null,
15031
+ 2
15032
+ )
15033
+ );
14838
15034
  return;
14839
15035
  }
14840
15036
  if (data.totalSessions === 0) {
@@ -14857,7 +15053,9 @@ async function sourcesListCommand() {
14857
15053
  const workspaces = getDetectedWorkspaces(dir);
14858
15054
  if (configSources.length === 0 && workspaces.length === 0) {
14859
15055
  console.log(chalk25.dim("\n No sources configured.\n"));
14860
- console.log(chalk25.dim(" Add a source: ") + chalk25.hex("#83D1EB")(`${resolveCaliber()} sources add <path>`));
15056
+ console.log(
15057
+ chalk25.dim(" Add a source: ") + chalk25.hex("#83D1EB")(`${displayCaliberName()} sources add <path>`)
15058
+ );
14861
15059
  console.log(chalk25.dim(" Or add to .caliber/sources.json manually.\n"));
14862
15060
  return;
14863
15061
  }
@@ -14869,7 +15067,9 @@ async function sourcesListCommand() {
14869
15067
  const status = exists ? chalk25.green("reachable") : chalk25.red("not found");
14870
15068
  const hasSummary = source.path && fs49.existsSync(path40.join(path40.resolve(dir, source.path), ".caliber", "summary.json"));
14871
15069
  console.log(` ${chalk25.bold(source.role || source.type)} ${chalk25.dim(sourcePath)}`);
14872
- console.log(` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`);
15070
+ console.log(
15071
+ ` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`
15072
+ );
14873
15073
  if (source.description) console.log(` ${chalk25.dim(source.description)}`);
14874
15074
  console.log("");
14875
15075
  }
@@ -14900,9 +15100,7 @@ async function sourcesAddCommand(sourcePath) {
14900
15100
  throw new Error("__exit__");
14901
15101
  }
14902
15102
  const existing = loadSourcesConfig(dir);
14903
- const alreadyConfigured = existing.some(
14904
- (s) => s.path && path40.resolve(dir, s.path) === absPath
14905
- );
15103
+ const alreadyConfigured = existing.some((s) => s.path && path40.resolve(dir, s.path) === absPath);
14906
15104
  if (alreadyConfigured) {
14907
15105
  console.log(chalk25.yellow(`
14908
15106
  Already configured: ${sourcePath}
@@ -14928,9 +15126,7 @@ async function sourcesAddCommand(sourcePath) {
14928
15126
  async function sourcesRemoveCommand(name) {
14929
15127
  const dir = process.cwd();
14930
15128
  const existing = loadSourcesConfig(dir);
14931
- const idx = existing.findIndex(
14932
- (s) => s.path?.includes(name) || s.role === name
14933
- );
15129
+ const idx = existing.findIndex((s) => s.path?.includes(name) || s.role === name);
14934
15130
  if (idx === -1) {
14935
15131
  console.log(chalk25.red(`
14936
15132
  Source not found: ${name}
@@ -14943,9 +15139,11 @@ async function sourcesRemoveCommand(name) {
14943
15139
  }
14944
15140
  const removed = existing.splice(idx, 1)[0];
14945
15141
  writeSourcesConfig(dir, existing);
14946
- console.log(chalk25.green(`
15142
+ console.log(
15143
+ chalk25.green(`
14947
15144
  \u2713 Removed ${removed.path || removed.url} (${removed.role || removed.type})
14948
- `));
15145
+ `)
15146
+ );
14949
15147
  }
14950
15148
 
14951
15149
  // src/commands/publish.ts
@@ -14959,7 +15157,9 @@ async function publishCommand() {
14959
15157
  const dir = process.cwd();
14960
15158
  const config = loadConfig();
14961
15159
  if (!config) {
14962
- console.log(chalk26.red("No LLM provider configured. Run ") + chalk26.hex("#83D1EB")(`${resolveCaliber()} config`) + chalk26.red(" first."));
15160
+ console.log(
15161
+ chalk26.red("No LLM provider configured. Run ") + chalk26.hex("#83D1EB")(`${displayCaliberName()} config`) + chalk26.red(" first.")
15162
+ );
14963
15163
  throw new Error("__exit__");
14964
15164
  }
14965
15165
  const spinner = ora7("Generating project summary...").start();
@@ -15002,7 +15202,9 @@ async function publishCommand() {
15002
15202
  spinner.succeed("Project summary published");
15003
15203
  console.log(` ${chalk26.green("\u2713")} ${path41.relative(dir, outputPath)}`);
15004
15204
  console.log(chalk26.dim("\n Other projects can now reference this repo as a source."));
15005
- console.log(chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n"));
15205
+ console.log(
15206
+ chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n")
15207
+ );
15006
15208
  } catch (err) {
15007
15209
  spinner.fail("Failed to generate summary");
15008
15210
  if (err instanceof Error && err.message === "__exit__") throw err;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.48.2",
3
+ "version": "1.49.3",
4
4
  "description": "AI context infrastructure for coding agents — keeps CLAUDE.md, Cursor rules, and skills in sync as your codebase evolves",
5
5
  "type": "module",
6
6
  "bin": {