@rely-ai/caliber 1.31.0-dev.1774743306 → 1.31.0-dev.1774815271

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 +429 -187
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -71,6 +71,7 @@ __export(builtin_skills_exports, {
71
71
  BUILTIN_SKILLS: () => BUILTIN_SKILLS,
72
72
  BUILTIN_SKILL_NAMES: () => BUILTIN_SKILL_NAMES,
73
73
  FIND_SKILLS_SKILL: () => FIND_SKILLS_SKILL,
74
+ PLATFORM_CONFIGS: () => PLATFORM_CONFIGS,
74
75
  SAVE_LEARNING_SKILL: () => SAVE_LEARNING_SKILL,
75
76
  SETUP_CALIBER_SKILL: () => SETUP_CALIBER_SKILL,
76
77
  buildSkillContent: () => buildSkillContent,
@@ -217,18 +218,19 @@ then only act if something is missing.
217
218
  command -v caliber >/dev/null 2>&1 && caliber --version || echo "NOT_INSTALLED"
218
219
  \`\`\`
219
220
 
220
- - If a version prints \u2192 Caliber is installed. Move to Step 2.
221
- - If NOT_INSTALLED \u2192 Tell the user: "Caliber isn't installed yet. I'll install it now."
222
- Then run:
221
+ - If a version prints \u2192 Caliber is installed globally. Set \`CALIBER="caliber"\` and move to Step 2.
222
+ - If NOT_INSTALLED \u2192 Install it globally (faster for daily use since the pre-commit hook runs on every commit):
223
223
  \`\`\`bash
224
224
  npm install -g @rely-ai/caliber
225
225
  \`\`\`
226
- If npm fails (permissions, no Node, etc.), try:
226
+ Set \`CALIBER="caliber"\`.
227
+
228
+ If npm fails (permissions, no sudo, etc.), fall back to npx:
227
229
  \`\`\`bash
228
- npx @rely-ai/caliber --version
230
+ npx @rely-ai/caliber --version 2>/dev/null || echo "NO_NODE"
229
231
  \`\`\`
230
- If npx works, use \`npx @rely-ai/caliber\` as the command prefix for all subsequent steps.
231
- If both fail, tell the user: "Caliber requires Node.js >= 20. Install Node first, then run /setup-caliber again."
232
+ - If npx works \u2192 Set \`CALIBER="npx @rely-ai/caliber"\`. This works but adds ~500ms per invocation.
233
+ - If NO_NODE \u2192 Tell the user: "Caliber requires Node.js >= 20. Install Node first, then run /setup-caliber again." Stop here.
232
234
 
233
235
  ### Step 2: Check if pre-commit hook is installed
234
236
 
@@ -239,7 +241,7 @@ grep -q "caliber" .git/hooks/pre-commit 2>/dev/null && echo "HOOK_ACTIVE" || ech
239
241
  - If HOOK_ACTIVE \u2192 Tell the user: "Pre-commit hook is active \u2014 configs sync on every commit." Move to Step 3.
240
242
  - If NO_HOOK \u2192 Tell the user: "I'll install the pre-commit hook so your agent configs sync automatically on every commit."
241
243
  \`\`\`bash
242
- caliber hooks --install
244
+ $CALIBER hooks --install
243
245
  \`\`\`
244
246
 
245
247
  ### Step 3: Detect agents and check if configs exist
@@ -269,22 +271,22 @@ echo "COPILOT=$([ -f .github/copilot-instructions.md ] && echo exists || echo mi
269
271
  - If configs are missing \u2192 Tell the user: "No agent configs found. I'll generate them now."
270
272
  Use the detected or user-selected agent list:
271
273
  \`\`\`bash
272
- caliber init --auto-approve --agent <comma-separated-agents>
274
+ $CALIBER init --auto-approve --agent <comma-separated-agents>
273
275
  \`\`\`
274
- For example: \`caliber init --auto-approve --agent claude,cursor\`
276
+ For example: \`$CALIBER init --auto-approve --agent claude,cursor\`
275
277
  This generates CLAUDE.md, Cursor rules, AGENTS.md, skills, and sync infrastructure for the specified agents.
276
278
 
277
279
  ### Step 4: Check if configs are fresh
278
280
 
279
281
  \`\`\`bash
280
- caliber score --json --quiet 2>/dev/null | head -1
282
+ $CALIBER score --json --quiet 2>/dev/null | head -1
281
283
  \`\`\`
282
284
 
283
285
  - If score is 80+ \u2192 Tell the user: "Your configs are in good shape (score: X/100)."
284
286
  - If score is below 80 \u2192 Tell the user: "Your configs could be improved (score: X/100). Want me to run a refresh?"
285
287
  If yes:
286
288
  \`\`\`bash
287
- caliber refresh
289
+ $CALIBER refresh
288
290
  \`\`\`
289
291
 
290
292
  ### Step 5: Ask about team setup
@@ -295,20 +297,20 @@ Ask the user: "Are you setting up for yourself only, or for your team too?"
295
297
 
296
298
  Check if session learning is enabled:
297
299
  \`\`\`bash
298
- caliber learn status 2>/dev/null | head -3
300
+ $CALIBER learn status 2>/dev/null | head -3
299
301
  \`\`\`
300
302
  - If learning is already enabled \u2192 note it in the summary.
301
303
  - If not enabled \u2192 ask the user: "Caliber can learn from your coding sessions \u2014 when you correct a mistake or fix a pattern, it remembers for next time. Enable session learning?"
302
304
  If yes:
303
305
  \`\`\`bash
304
- caliber learn install
306
+ $CALIBER learn install
305
307
  \`\`\`
306
308
 
307
309
  Then tell the user:
308
310
  "You're all set! Here's what happens next:
309
311
  - Every time you commit, Caliber syncs your agent configs automatically
310
312
  - Your CLAUDE.md, Cursor rules, and AGENTS.md stay current with your code
311
- - Run \`caliber skills\` anytime to discover community skills for your stack"
313
+ - Run \`$CALIBER skills\` anytime to discover community skills for your stack"
312
314
 
313
315
  Then show the summary (see below) and stop.
314
316
 
@@ -343,7 +345,7 @@ Ask the user: "Are you setting up for yourself only, or for your team too?"
343
345
  \`\`\`
344
346
  Now determine which LLM provider the team uses. Check the local Caliber config:
345
347
  \`\`\`bash
346
- caliber config --show 2>/dev/null || echo "NO_CONFIG"
348
+ $CALIBER config --show 2>/dev/null || echo "NO_CONFIG"
347
349
  \`\`\`
348
350
 
349
351
  Based on the provider, the GitHub Action needs the corresponding secret:
@@ -468,7 +470,8 @@ __export(pre_commit_block_exports, {
468
470
  getCursorSyncRule: () => getCursorSyncRule,
469
471
  hasLearningsBlock: () => hasLearningsBlock,
470
472
  hasPreCommitBlock: () => hasPreCommitBlock,
471
- hasSyncBlock: () => hasSyncBlock
473
+ hasSyncBlock: () => hasSyncBlock,
474
+ stripManagedBlocks: () => stripManagedBlocks
472
475
  });
473
476
  function getCaliberNotFoundFallback(platform, bin) {
474
477
  switch (platform) {
@@ -477,7 +480,11 @@ function getCaliberNotFoundFallback(platform, bin) {
477
480
  case "codex":
478
481
  return `If \`${bin}\` is not found, read \`.agents/skills/setup-caliber/SKILL.md\` and follow its instructions to install Caliber.`;
479
482
  case "copilot":
480
- return `If \`${bin}\` is not found, install it by running \`npm install -g @rely-ai/caliber\`, then run \`caliber hooks --install\` and \`caliber refresh\`.`;
483
+ return `If \`${bin}\` is not found, tell the developer to set up Caliber by running \`/setup-caliber\` in Claude Code or Cursor. Alternatively, they can run these commands in their terminal:
484
+ \`\`\`
485
+ npx @rely-ai/caliber hooks --install
486
+ npx @rely-ai/caliber refresh
487
+ \`\`\``;
481
488
  }
482
489
  }
483
490
  function getPreCommitBlock(platform = "claude") {
@@ -545,11 +552,10 @@ function getSyncSetupInstruction(platform, bin) {
545
552
  case "codex":
546
553
  return `If the pre-commit hook is not set up, read \`.agents/skills/setup-caliber/SKILL.md\` and follow the setup instructions.`;
547
554
  case "copilot":
548
- return `If the pre-commit hook is not set up, install it by running:
555
+ return `If the pre-commit hook is not set up, the developer should run \`/setup-caliber\` in Claude Code or Cursor for automated setup. Alternatively, run in terminal:
549
556
  \`\`\`bash
550
- npm install -g @rely-ai/caliber
551
- caliber hooks --install
552
- caliber refresh
557
+ npx @rely-ai/caliber hooks --install
558
+ npx @rely-ai/caliber refresh
553
559
  git add ${MANAGED_DOC_PATHS} 2>/dev/null
554
560
  \`\`\``;
555
561
  }
@@ -608,7 +614,15 @@ If the user agrees, read \`.cursor/skills/setup-caliber/SKILL.md\` and follow it
608
614
  function getCursorSetupRule() {
609
615
  return { filename: CURSOR_SETUP_FILENAME, content: getCursorSetupContent() };
610
616
  }
611
- 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, SYNC_BLOCK_START, SYNC_BLOCK_END, CURSOR_SYNC_FILENAME, CURSOR_SETUP_FILENAME;
617
+ function stripManagedBlocks(content) {
618
+ let result = content;
619
+ for (const [start, end] of MANAGED_BLOCK_PAIRS) {
620
+ const regex = new RegExp(`\\n?${start.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${end.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n?`, "g");
621
+ result = result.replace(regex, "\n");
622
+ }
623
+ return result.replace(/\n{3,}/g, "\n\n").trim() + "\n";
624
+ }
625
+ 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, SYNC_BLOCK_START, SYNC_BLOCK_END, CURSOR_SYNC_FILENAME, CURSOR_SETUP_FILENAME, MANAGED_BLOCK_PAIRS;
612
626
  var init_pre_commit_block = __esm({
613
627
  "src/writers/pre-commit-block.ts"() {
614
628
  "use strict";
@@ -637,6 +651,11 @@ These are auto-extracted from real tool usage \u2014 treat them as project-speci
637
651
  SYNC_BLOCK_END = "<!-- /caliber:managed:sync -->";
638
652
  CURSOR_SYNC_FILENAME = "caliber-sync.mdc";
639
653
  CURSOR_SETUP_FILENAME = "caliber-setup.mdc";
654
+ MANAGED_BLOCK_PAIRS = [
655
+ [BLOCK_START, BLOCK_END],
656
+ [LEARNINGS_BLOCK_START, LEARNINGS_BLOCK_END],
657
+ [SYNC_BLOCK_START, SYNC_BLOCK_END]
658
+ ];
640
659
  }
641
660
  });
642
661
 
@@ -1120,8 +1139,8 @@ var init_lock = __esm({
1120
1139
 
1121
1140
  // src/cli.ts
1122
1141
  import { Command } from "commander";
1123
- import fs47 from "fs";
1124
- import path38 from "path";
1142
+ import fs49 from "fs";
1143
+ import path39 from "path";
1125
1144
  import { fileURLToPath } from "url";
1126
1145
 
1127
1146
  // src/commands/init.ts
@@ -4444,15 +4463,15 @@ init_config();
4444
4463
  // src/utils/dependencies.ts
4445
4464
  import { readFileSync as readFileSync2 } from "fs";
4446
4465
  import { join as join2 } from "path";
4447
- function readFileOrNull2(path40) {
4466
+ function readFileOrNull2(path41) {
4448
4467
  try {
4449
- return readFileSync2(path40, "utf-8");
4468
+ return readFileSync2(path41, "utf-8");
4450
4469
  } catch {
4451
4470
  return null;
4452
4471
  }
4453
4472
  }
4454
- function readJsonOrNull(path40) {
4455
- const content = readFileOrNull2(path40);
4473
+ function readJsonOrNull(path41) {
4474
+ const content = readFileOrNull2(path41);
4456
4475
  if (!content) return null;
4457
4476
  try {
4458
4477
  return JSON.parse(content);
@@ -5773,6 +5792,9 @@ async function runInteractiveProviderSetup(options) {
5773
5792
  return config;
5774
5793
  }
5775
5794
 
5795
+ // src/commands/init.ts
5796
+ import confirm2 from "@inquirer/confirm";
5797
+
5776
5798
  // src/scoring/index.ts
5777
5799
  import { existsSync as existsSync7 } from "fs";
5778
5800
  import { join as join9 } from "path";
@@ -6771,8 +6793,8 @@ function detectTargetAgent(dir) {
6771
6793
  const agents = [];
6772
6794
  if (existsSync7(join9(dir, "CLAUDE.md")) || existsSync7(join9(dir, ".claude", "skills"))) agents.push("claude");
6773
6795
  if (existsSync7(join9(dir, ".cursorrules")) || existsSync7(join9(dir, ".cursor", "rules"))) agents.push("cursor");
6774
- if (existsSync7(join9(dir, ".codex")) || existsSync7(join9(dir, ".agents", "skills"))) agents.push("codex");
6775
- if (existsSync7(join9(dir, ".github", "copilot-instructions.md"))) agents.push("github-copilot");
6796
+ if (existsSync7(join9(dir, ".codex")) || existsSync7(join9(dir, ".agents", "skills")) || existsSync7(join9(dir, "AGENTS.md"))) agents.push("codex");
6797
+ if (existsSync7(join9(dir, ".github", "copilot-instructions.md")) || existsSync7(join9(dir, ".github", "instructions"))) agents.push("github-copilot");
6776
6798
  return agents.length > 0 ? agents : ["claude"];
6777
6799
  }
6778
6800
  function computeLocalScore(dir, targetAgent) {
@@ -7026,11 +7048,57 @@ function getMachineId() {
7026
7048
  return machineId;
7027
7049
  }
7028
7050
  var EMAIL_HASH_KEY = "caliber-telemetry-v1";
7029
- function getGitEmailHash() {
7051
+ var PERSONAL_DOMAINS = /* @__PURE__ */ new Set([
7052
+ "gmail.com",
7053
+ "googlemail.com",
7054
+ "outlook.com",
7055
+ "hotmail.com",
7056
+ "live.com",
7057
+ "yahoo.com",
7058
+ "yahoo.co.uk",
7059
+ "icloud.com",
7060
+ "me.com",
7061
+ "mac.com",
7062
+ "aol.com",
7063
+ "protonmail.com",
7064
+ "proton.me",
7065
+ "pm.me",
7066
+ "mail.com",
7067
+ "zoho.com",
7068
+ "yandex.com",
7069
+ "gmx.com",
7070
+ "gmx.net",
7071
+ "fastmail.com",
7072
+ "tutanota.com",
7073
+ "tuta.io"
7074
+ ]);
7075
+ function getGitEmail() {
7030
7076
  try {
7031
7077
  const email = execSync13("git config user.email", { encoding: "utf-8" }).trim();
7032
- if (!email) return void 0;
7033
- return crypto4.createHmac("sha256", EMAIL_HASH_KEY).update(email).digest("hex");
7078
+ return email || void 0;
7079
+ } catch {
7080
+ return void 0;
7081
+ }
7082
+ }
7083
+ function getGitEmailInfo() {
7084
+ const email = getGitEmail();
7085
+ if (!email) return {};
7086
+ const hash = crypto4.createHmac("sha256", EMAIL_HASH_KEY).update(email).digest("hex");
7087
+ let domain;
7088
+ if (email.includes("@")) {
7089
+ const d = email.split("@")[1].toLowerCase();
7090
+ if (!PERSONAL_DOMAINS.has(d)) domain = d;
7091
+ }
7092
+ return { hash, domain };
7093
+ }
7094
+ function getRepoHash() {
7095
+ try {
7096
+ const remote = execSync13("git remote get-url origin || git rev-parse --show-toplevel", {
7097
+ encoding: "utf-8",
7098
+ stdio: ["pipe", "pipe", "pipe"]
7099
+ }).trim();
7100
+ if (!remote) return void 0;
7101
+ return crypto4.createHmac("sha256", EMAIL_HASH_KEY).update(remote).digest("hex").slice(0, 16);
7034
7102
  } catch {
7035
7103
  return void 0;
7036
7104
  }
@@ -7055,6 +7123,7 @@ function markNoticeShown() {
7055
7123
  var POSTHOG_KEY = "phc_XXrV0pSX4s2QVxVoOaeuyXDvtlRwPAjovt1ttMGVMPp";
7056
7124
  var client = null;
7057
7125
  var distinctId = null;
7126
+ var superProperties = {};
7058
7127
  function initTelemetry() {
7059
7128
  if (isTelemetryDisabled()) return;
7060
7129
  const machineId = getMachineId();
@@ -7070,11 +7139,17 @@ function initTelemetry() {
7070
7139
  );
7071
7140
  markNoticeShown();
7072
7141
  }
7073
- const gitEmailHash = getGitEmailHash();
7142
+ const { hash: gitEmailHash, domain: emailDomain } = getGitEmailInfo();
7143
+ const repoHash = getRepoHash();
7144
+ superProperties = {
7145
+ ...repoHash ? { repo_hash: repoHash } : {},
7146
+ ...emailDomain ? { email_domain: emailDomain } : {}
7147
+ };
7074
7148
  client.identify({
7075
7149
  distinctId: machineId,
7076
7150
  properties: {
7077
- ...gitEmailHash ? { git_email_hash: gitEmailHash } : {}
7151
+ ...gitEmailHash ? { git_email_hash: gitEmailHash } : {},
7152
+ ...emailDomain ? { email_domain: emailDomain } : {}
7078
7153
  }
7079
7154
  });
7080
7155
  }
@@ -7083,7 +7158,7 @@ function trackEvent(name, properties) {
7083
7158
  client.capture({
7084
7159
  distinctId,
7085
7160
  event: name,
7086
- properties: properties ?? {}
7161
+ properties: { ...superProperties, ...properties }
7087
7162
  });
7088
7163
  }
7089
7164
  async function flushTelemetry() {
@@ -7132,11 +7207,14 @@ function trackInitSkillsSearch(searched, installedCount) {
7132
7207
  function trackInitScoreRegression(oldScore, newScore) {
7133
7208
  trackEvent("init_score_regression", { old_score: oldScore, new_score: newScore });
7134
7209
  }
7210
+ function trackInitCompleted(path41, score) {
7211
+ trackEvent("init_completed", { path: path41, score });
7212
+ }
7135
7213
  function trackRegenerateCompleted(action, durationMs) {
7136
7214
  trackEvent("regenerate_completed", { action, duration_ms: durationMs });
7137
7215
  }
7138
- function trackRefreshCompleted(changesCount, durationMs) {
7139
- trackEvent("refresh_completed", { changes_count: changesCount, duration_ms: durationMs });
7216
+ function trackRefreshCompleted(changesCount, durationMs, trigger) {
7217
+ trackEvent("refresh_completed", { changes_count: changesCount, duration_ms: durationMs, trigger: trigger ?? "manual" });
7140
7218
  }
7141
7219
  function trackScoreComputed(score, agent) {
7142
7220
  trackEvent("score_computed", { score, agent });
@@ -7150,6 +7228,9 @@ function trackSkillsInstalled(count) {
7150
7228
  function trackUndoExecuted() {
7151
7229
  trackEvent("undo_executed");
7152
7230
  }
7231
+ function trackUninstallExecuted() {
7232
+ trackEvent("uninstall_executed");
7233
+ }
7153
7234
  function trackInitLearnEnabled(enabled) {
7154
7235
  trackEvent("init_learn_enabled", { enabled });
7155
7236
  }
@@ -8084,11 +8165,11 @@ function countIssuePoints(issues) {
8084
8165
  }
8085
8166
  async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
8086
8167
  const existsCache = /* @__PURE__ */ new Map();
8087
- const cachedExists = (path40) => {
8088
- const cached = existsCache.get(path40);
8168
+ const cachedExists = (path41) => {
8169
+ const cached = existsCache.get(path41);
8089
8170
  if (cached !== void 0) return cached;
8090
- const result = existsSync9(path40);
8091
- existsCache.set(path40, result);
8171
+ const result = existsSync9(path41);
8172
+ existsCache.set(path41, result);
8092
8173
  return result;
8093
8174
  };
8094
8175
  const projectStructure = collectProjectStructure(dir);
@@ -8868,25 +8949,6 @@ async function promptAgent(detected) {
8868
8949
  });
8869
8950
  return selected;
8870
8951
  }
8871
- async function promptLearnInstall(targetAgent) {
8872
- const hasClaude = targetAgent.includes("claude");
8873
- const hasCursor = targetAgent.includes("cursor");
8874
- const agentName = hasClaude && hasCursor ? "Claude and Cursor" : hasClaude ? "Claude" : "Cursor";
8875
- console.log(chalk11.bold(`
8876
- Session Learning
8877
- `));
8878
- console.log(chalk11.dim(` Caliber can learn from your ${agentName} sessions \u2014 when a tool fails`));
8879
- console.log(chalk11.dim(` or you correct a mistake, it captures the lesson so it won't`));
8880
- console.log(chalk11.dim(` happen again. Runs once at session end using the fast model.
8881
- `));
8882
- return select5({
8883
- message: "Enable session learning?",
8884
- choices: [
8885
- { name: "Enable session learning (recommended)", value: true },
8886
- { name: "Skip for now", value: false }
8887
- ]
8888
- });
8889
- }
8890
8952
  async function promptReviewAction(hasSkillResults, hasChanges, staged) {
8891
8953
  if (!hasChanges && !hasSkillResults) return "accept";
8892
8954
  const choices = [];
@@ -9345,10 +9407,9 @@ async function initCommand(options) {
9345
9407
  console.log(chalk14.dim(" Keep your AI agent configs in sync \u2014 automatically."));
9346
9408
  console.log(chalk14.dim(" Works across Claude Code, Cursor, Codex, and GitHub Copilot.\n"));
9347
9409
  console.log(title.bold(" How it works:\n"));
9348
- console.log(chalk14.dim(" 1. Connect Link your LLM provider and select your agents"));
9349
- console.log(chalk14.dim(" 2. Setup Detect stack, install sync hooks & skills"));
9350
- console.log(chalk14.dim(" 3. Generate Audit existing config or generate from scratch"));
9351
- console.log(chalk14.dim(" 4. Finalize Review changes and score your setup\n"));
9410
+ console.log(chalk14.dim(" 1. Connect Auto-detect your LLM provider and agents"));
9411
+ console.log(chalk14.dim(" 2. Build Install sync, scan your project, generate configs"));
9412
+ console.log(chalk14.dim(" 3. Done Review score and start syncing\n"));
9352
9413
  } else {
9353
9414
  console.log(brand.bold("\n CALIBER") + chalk14.dim(" \u2014 setting up continuous sync\n"));
9354
9415
  }
@@ -9358,19 +9419,50 @@ async function initCommand(options) {
9358
9419
  console.log(chalk14.yellow(" Caliber will still generate config files, but they won't be auto-installed.\n"));
9359
9420
  }
9360
9421
  const report = options.debugReport ? new DebugReport() : null;
9361
- console.log(title.bold(" Step 1/4 \u2014 Connect\n"));
9422
+ console.log(title.bold(" Step 1/3 \u2014 Connect\n"));
9362
9423
  let config = loadConfig();
9424
+ if (!config && !options.autoApprove) {
9425
+ if (isClaudeCliAvailable()) {
9426
+ console.log(chalk14.dim(" Detected: Claude Code CLI (uses your Pro/Max/Team subscription)\n"));
9427
+ const useIt = await confirm2({ message: "Use Claude Code as your LLM provider?" });
9428
+ if (useIt) {
9429
+ const autoConfig = { provider: "claude-cli", model: "default" };
9430
+ writeConfigFile(autoConfig);
9431
+ config = autoConfig;
9432
+ }
9433
+ } else if (isCursorAgentAvailable() && isCursorLoggedIn()) {
9434
+ console.log(chalk14.dim(" Detected: Cursor (uses your existing subscription)\n"));
9435
+ const useIt = await confirm2({ message: "Use Cursor as your LLM provider?" });
9436
+ if (useIt) {
9437
+ const autoConfig = { provider: "cursor", model: "sonnet-4.6" };
9438
+ writeConfigFile(autoConfig);
9439
+ config = autoConfig;
9440
+ }
9441
+ }
9442
+ }
9363
9443
  if (!config) {
9364
- console.log(chalk14.dim(" No LLM provider configured yet.\n"));
9365
- await runInteractiveProviderSetup({
9366
- selectMessage: "How do you want to use Caliber? (choose LLM provider)"
9367
- });
9368
- config = loadConfig();
9444
+ if (options.autoApprove) {
9445
+ if (isClaudeCliAvailable()) {
9446
+ const autoConfig = { provider: "claude-cli", model: "default" };
9447
+ writeConfigFile(autoConfig);
9448
+ config = autoConfig;
9449
+ } else if (isCursorAgentAvailable() && isCursorLoggedIn()) {
9450
+ const autoConfig = { provider: "cursor", model: "sonnet-4.6" };
9451
+ writeConfigFile(autoConfig);
9452
+ config = autoConfig;
9453
+ }
9454
+ }
9369
9455
  if (!config) {
9370
- console.log(chalk14.red(" Configuration cancelled or failed.\n"));
9371
- throw new Error("__exit__");
9456
+ console.log(chalk14.dim(" No LLM provider detected.\n"));
9457
+ await runInteractiveProviderSetup({
9458
+ selectMessage: "How do you want to use Caliber? (choose LLM provider)"
9459
+ });
9460
+ config = loadConfig();
9461
+ if (!config) {
9462
+ console.log(chalk14.red(" Configuration cancelled or failed.\n"));
9463
+ throw new Error("__exit__");
9464
+ }
9372
9465
  }
9373
- console.log(chalk14.green(" \u2713 Provider saved\n"));
9374
9466
  }
9375
9467
  trackInitProviderSelected(config.provider, config.model, firstRun);
9376
9468
  const displayModel = getDisplayModel(config);
@@ -9388,22 +9480,28 @@ async function initCommand(options) {
9388
9480
  const agentAutoDetected = !options.agent;
9389
9481
  if (options.agent) {
9390
9482
  targetAgent = options.agent;
9391
- } else if (options.autoApprove) {
9392
- const detected = detectAgents(process.cwd());
9393
- targetAgent = detected.length > 0 ? detected : ["claude"];
9394
- log(options.verbose, `Auto-approve: using ${targetAgent.join(", ")}`);
9395
9483
  } else {
9396
9484
  const detected = detectAgents(process.cwd());
9397
- targetAgent = await promptAgent(detected.length > 0 ? detected : void 0);
9485
+ if (detected.length > 0 && (options.autoApprove || firstRun)) {
9486
+ targetAgent = detected;
9487
+ console.log(chalk14.dim(` Detected agents: ${detected.join(", ")}
9488
+ `));
9489
+ } else if (detected.length > 0) {
9490
+ console.log(chalk14.dim(` Detected agents: ${detected.join(", ")}
9491
+ `));
9492
+ const useDetected = await confirm2({ message: "Use detected agents?" });
9493
+ targetAgent = useDetected ? detected : await promptAgent();
9494
+ } else {
9495
+ targetAgent = options.autoApprove ? ["claude"] : await promptAgent();
9496
+ }
9398
9497
  }
9399
9498
  console.log(chalk14.dim(` Target: ${targetAgent.join(", ")}
9400
9499
  `));
9401
9500
  trackInitAgentSelected(targetAgent, agentAutoDetected);
9402
- console.log(title.bold(" Step 2/4 \u2014 Setup\n"));
9403
- console.log(chalk14.dim(" Installing sync infrastructure...\n"));
9501
+ console.log(title.bold(" Step 2/3 \u2014 Build\n"));
9404
9502
  const hookResult = installPreCommitHook();
9405
9503
  if (hookResult.installed) {
9406
- console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed \u2014 configs sync on every commit`);
9504
+ console.log(` ${chalk14.green("\u2713")} Pre-commit hook installed`);
9407
9505
  } else if (hookResult.alreadyInstalled) {
9408
9506
  console.log(` ${chalk14.green("\u2713")} Pre-commit hook \u2014 active`);
9409
9507
  }
@@ -9415,21 +9513,18 @@ async function initCommand(options) {
9415
9513
  }
9416
9514
  const skillsWritten = ensureBuiltinSkills2();
9417
9515
  if (skillsWritten.length > 0) {
9418
- console.log(` ${chalk14.green("\u2713")} Agent skills installed \u2014 /setup-caliber, /find-skills, /save-learning`);
9419
- } else {
9420
- console.log(` ${chalk14.green("\u2713")} Agent skills \u2014 already installed`);
9516
+ console.log(` ${chalk14.green("\u2713")} Agent skills installed`);
9517
+ }
9518
+ const hasLearnableAgent = targetAgent.includes("claude") || targetAgent.includes("cursor");
9519
+ if (hasLearnableAgent) {
9520
+ if (targetAgent.includes("claude")) installLearningHooks();
9521
+ if (targetAgent.includes("cursor")) installCursorLearningHooks();
9522
+ console.log(` ${chalk14.green("\u2713")} Session learning enabled`);
9523
+ trackInitLearnEnabled(true);
9421
9524
  }
9422
9525
  console.log("");
9423
- console.log(chalk14.dim(" New team members can run /setup-caliber inside their coding agent"));
9424
- console.log(chalk14.dim(" (Claude Code or Cursor) to get set up automatically.\n"));
9425
9526
  let baselineScore = computeLocalScore(process.cwd(), targetAgent);
9426
- console.log(chalk14.dim(" Current config score:"));
9427
- displayScoreSummary(baselineScore);
9428
- if (options.verbose) {
9429
- for (const c of baselineScore.checks) {
9430
- log(options.verbose, ` ${c.passed ? "\u2713" : "\u2717"} ${c.name}: ${c.earnedPoints}/${c.maxPoints}${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
9431
- }
9432
- }
9527
+ log(options.verbose, `Baseline score: ${baselineScore.score}/100`);
9433
9528
  if (report) {
9434
9529
  report.markStep("Baseline scoring");
9435
9530
  report.addSection("Scoring: Baseline", `**Score**: ${baselineScore.score}/100
@@ -9450,25 +9545,15 @@ async function initCommand(options) {
9450
9545
  ]);
9451
9546
  const passingCount = baselineScore.checks.filter((c) => c.passed).length;
9452
9547
  const failingCount = baselineScore.checks.filter((c) => !c.passed).length;
9548
+ trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9453
9549
  let skipGeneration = false;
9454
- if (hasExistingConfig && baselineScore.score === 100) {
9455
- trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
9456
- console.log(chalk14.bold.green("\n Your config is already optimal.\n"));
9457
- skipGeneration = !options.force;
9550
+ if (hasExistingConfig && baselineScore.score === 100 && !options.force) {
9551
+ skipGeneration = true;
9458
9552
  } else if (hasExistingConfig && !options.force && !options.autoApprove) {
9459
- trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9460
- console.log(chalk14.dim("\n Sync infrastructure is ready. Caliber can also audit your existing"));
9461
- console.log(chalk14.dim(" configs and improve them using AI.\n"));
9462
- const auditAnswer = await promptInput(" Audit and improve your existing config? (Y/n) ");
9463
- skipGeneration = auditAnswer.toLowerCase() === "n";
9464
- } else if (!hasExistingConfig && !options.force && !options.autoApprove) {
9465
- trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9466
- console.log(chalk14.dim("\n Sync infrastructure is ready. Caliber can also generate tailored"));
9467
- console.log(chalk14.dim(" CLAUDE.md, Cursor rules, and Codex configs for your project.\n"));
9468
- const generateAnswer = await promptInput(" Generate agent configs? (Y/n) ");
9469
- skipGeneration = generateAnswer.toLowerCase() === "n";
9470
- } else {
9471
- trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
9553
+ console.log(chalk14.dim(` Config score: ${baselineScore.score}/100 \u2014 Caliber can improve this.
9554
+ `));
9555
+ const improveAnswer = await confirm2({ message: "Improve your existing configs?" });
9556
+ skipGeneration = !improveAnswer;
9472
9557
  }
9473
9558
  if (skipGeneration) {
9474
9559
  const {
@@ -9525,6 +9610,7 @@ async function initCommand(options) {
9525
9610
  lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
9526
9611
  targetAgent
9527
9612
  });
9613
+ trackInitCompleted("sync-only", baselineScore.score);
9528
9614
  console.log(chalk14.bold.green("\n Caliber sync is set up!\n"));
9529
9615
  console.log(chalk14.dim(" Your agent configs will sync automatically on every commit."));
9530
9616
  console.log(chalk14.dim(" Run ") + title(`${bin} init --force`) + chalk14.dim(" anytime to generate or improve configs.\n"));
@@ -9532,7 +9618,6 @@ async function initCommand(options) {
9532
9618
  }
9533
9619
  const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
9534
9620
  const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
9535
- console.log(title.bold("\n Step 3/4 \u2014 Generate\n"));
9536
9621
  const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
9537
9622
  console.log(chalk14.dim(genModelInfo + "\n"));
9538
9623
  if (report) report.markStep("Generation");
@@ -9731,7 +9816,7 @@ async function initCommand(options) {
9731
9816
  report.addJson("Generation: Parsed Config", generatedSetup);
9732
9817
  }
9733
9818
  log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
9734
- console.log(title.bold(" Step 4/4 \u2014 Finalize\n"));
9819
+ console.log(title.bold(" Step 3/3 \u2014 Done\n"));
9735
9820
  const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
9736
9821
  const staged = stageFiles(setupFiles, process.cwd());
9737
9822
  const totalChanges = staged.newFiles + staged.modifiedFiles;
@@ -9875,6 +9960,7 @@ ${agentRefs.join(" ")}
9875
9960
  ` + afterScore.checks.map((c) => `| ${c.name} | ${c.passed ? "Yes" : "No"} | ${c.earnedPoints} | ${c.maxPoints} |`).join("\n"));
9876
9961
  }
9877
9962
  recordScore(afterScore, "init");
9963
+ trackInitCompleted("full-generation", afterScore.score);
9878
9964
  displayScoreDelta(baselineScore, afterScore);
9879
9965
  if (options.verbose) {
9880
9966
  log(options.verbose, `Final score: ${afterScore.score}/100`);
@@ -9892,64 +9978,26 @@ ${agentRefs.join(" ")}
9892
9978
  communitySkillsInstalled = selected.length;
9893
9979
  }
9894
9980
  }
9895
- console.log("");
9896
- console.log(` ${chalk14.green("\u2713")} Docs auto-refresh ${chalk14.dim(`agents run ${resolveCaliber()} refresh before commits`)}`);
9897
9981
  trackInitHookSelected("config-instructions");
9898
- const hasLearnableAgent = targetAgent.includes("claude") || targetAgent.includes("cursor");
9899
- let enableLearn = false;
9900
- if (hasLearnableAgent) {
9901
- if (!options.autoApprove) {
9902
- enableLearn = await promptLearnInstall(targetAgent);
9903
- trackInitLearnEnabled(enableLearn);
9904
- if (enableLearn) {
9905
- if (targetAgent.includes("claude")) {
9906
- const r = installLearningHooks();
9907
- if (r.installed) console.log(` ${chalk14.green("\u2713")} Learning hooks installed for Claude Code`);
9908
- else if (r.alreadyInstalled) console.log(chalk14.dim(" Claude Code learning hooks already installed"));
9909
- }
9910
- if (targetAgent.includes("cursor")) {
9911
- const r = installCursorLearningHooks();
9912
- if (r.installed) console.log(` ${chalk14.green("\u2713")} Learning hooks installed for Cursor`);
9913
- else if (r.alreadyInstalled) console.log(chalk14.dim(" Cursor learning hooks already installed"));
9914
- }
9915
- console.log(chalk14.dim(" Run ") + chalk14.hex("#83D1EB")(`${bin} learn status`) + chalk14.dim(" to see insights"));
9916
- } else {
9917
- console.log(chalk14.dim(" Skipped. Run ") + chalk14.hex("#83D1EB")(`${bin} learn install`) + chalk14.dim(" later to enable."));
9918
- }
9919
- } else {
9920
- enableLearn = true;
9921
- if (targetAgent.includes("claude")) installLearningHooks();
9922
- if (targetAgent.includes("cursor")) installCursorLearningHooks();
9923
- }
9924
- }
9925
- console.log(chalk14.bold.green("\n Caliber is set up!"));
9926
- console.log(chalk14.dim(" Your AI agent configs will now stay in sync with your codebase automatically."));
9927
- console.log(chalk14.dim(" Every commit refreshes configs for all your agents. All changes are backed up.\n"));
9928
9982
  const done = chalk14.green("\u2713");
9929
- const skip = chalk14.dim("\u2013");
9930
- console.log(chalk14.bold(" What was configured:\n"));
9931
- console.log(` ${done} Continuous sync ${chalk14.dim("pre-commit hook keeps all agent configs in sync")}`);
9932
- console.log(` ${done} Config generated ${title(`${bin} score`)} ${chalk14.dim("for full breakdown")}`);
9933
- console.log(` ${done} Agent skills ${chalk14.dim("/setup-caliber for new team members")}`);
9983
+ console.log(chalk14.bold.green("\n Caliber is set up!\n"));
9984
+ console.log(chalk14.bold(" What's configured:\n"));
9985
+ console.log(` ${done} Continuous sync ${chalk14.dim("pre-commit hook keeps all agent configs in sync")}`);
9986
+ console.log(` ${done} Config generated ${chalk14.dim(`score: ${afterScore.score}/100`)}`);
9987
+ console.log(` ${done} Agent skills ${chalk14.dim("/setup-caliber for new team members")}`);
9934
9988
  if (hasLearnableAgent) {
9935
- if (enableLearn) {
9936
- console.log(` ${done} Session learning ${chalk14.dim("agent learns from your feedback")}`);
9937
- } else {
9938
- console.log(` ${skip} Session learning ${title(`${bin} learn install`)} ${chalk14.dim("to enable later")}`);
9939
- }
9989
+ console.log(` ${done} Session learning ${chalk14.dim("learns from your corrections")}`);
9940
9990
  }
9941
9991
  if (communitySkillsInstalled > 0) {
9942
- console.log(` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} skill${communitySkillsInstalled > 1 ? "s" : ""} installed for your stack`)}`);
9943
- } else if (skillSearchResult.results.length > 0) {
9944
- console.log(` ${skip} Community skills ${chalk14.dim("available but skipped")}`);
9992
+ console.log(` ${done} Community skills ${chalk14.dim(`${communitySkillsInstalled} installed for your stack`)}`);
9945
9993
  }
9946
9994
  console.log(chalk14.bold("\n What happens next:\n"));
9947
- console.log(chalk14.dim(" Every commit will automatically sync your agent configs."));
9948
- console.log(chalk14.dim(" New team members can run /setup-caliber to get set up instantly.\n"));
9949
- console.log(chalk14.bold(" Explore:\n"));
9950
- console.log(` ${title(`${bin} score`)} Full scoring breakdown with improvement tips`);
9951
- console.log(` ${title(`${bin} skills`)} Find community skills for your stack`);
9952
- console.log(` ${title(`${bin} undo`)} Revert all changes from this run`);
9995
+ console.log(chalk14.dim(" Every commit syncs your agent configs automatically."));
9996
+ console.log(chalk14.dim(" New team members run /setup-caliber to get set up instantly.\n"));
9997
+ console.log(` ${title(`${bin} score`)} Full scoring breakdown`);
9998
+ console.log(` ${title(`${bin} skills`)} Find community skills`);
9999
+ console.log(` ${title(`${bin} undo`)} Revert changes`);
10000
+ console.log(` ${title(`${bin} uninstall`)} Remove Caliber completely`);
9953
10001
  console.log("");
9954
10002
  if (options.showTokens) {
9955
10003
  displayTokenUsage();
@@ -10835,7 +10883,8 @@ async function refreshSingleRepo(repoDir, options) {
10835
10883
  }
10836
10884
  }
10837
10885
  const written = writeRefreshDocs(response.updatedDocs);
10838
- trackRefreshCompleted(written.length, Date.now());
10886
+ const trigger = quiet ? "hook" : "manual";
10887
+ trackRefreshCompleted(written.length, Date.now(), trigger);
10839
10888
  const postScore = computeLocalScore(repoDir, targetAgent);
10840
10889
  if (postScore.score < preScore.score) {
10841
10890
  for (const [filePath, content] of preRefreshContents) {
@@ -12539,10 +12588,199 @@ async function publishCommand() {
12539
12588
  }
12540
12589
  }
12541
12590
 
12591
+ // src/commands/bootstrap.ts
12592
+ init_builtin_skills();
12593
+ import fs47 from "fs";
12594
+ import chalk27 from "chalk";
12595
+ var PLATFORM_SKILL_DIRS = {
12596
+ claude: ".claude/skills",
12597
+ cursor: ".cursor/skills",
12598
+ codex: ".agents/skills"
12599
+ };
12600
+ async function bootstrapCommand() {
12601
+ const platforms = detectPlatforms();
12602
+ const detected = [];
12603
+ if (platforms.claude) detected.push("claude");
12604
+ if (platforms.cursor) detected.push("cursor");
12605
+ if (platforms.codex) detected.push("codex");
12606
+ if (detected.length === 0) detected.push("claude");
12607
+ const written = [];
12608
+ for (const platform of detected) {
12609
+ const skillsDir = PLATFORM_SKILL_DIRS[platform];
12610
+ if (!skillsDir) continue;
12611
+ for (const skill of BUILTIN_SKILLS) {
12612
+ const skillDir = `${skillsDir}/${skill.name}`;
12613
+ const skillPath = `${skillDir}/SKILL.md`;
12614
+ fs47.mkdirSync(skillDir, { recursive: true });
12615
+ fs47.writeFileSync(skillPath, buildSkillContent(skill));
12616
+ written.push(skillPath);
12617
+ }
12618
+ }
12619
+ if (written.length === 0) {
12620
+ console.log(chalk27.yellow("No skills were written."));
12621
+ return;
12622
+ }
12623
+ console.log(chalk27.bold.green("\n Caliber skills installed!\n"));
12624
+ for (const file of written) {
12625
+ console.log(` ${chalk27.green("\u2713")} ${file}`);
12626
+ }
12627
+ console.log(chalk27.dim("\n Your agent can now run /setup-caliber to complete the setup."));
12628
+ console.log(chalk27.dim(' Just tell your agent: "Run /setup-caliber"\n'));
12629
+ }
12630
+
12631
+ // src/commands/uninstall.ts
12632
+ import fs48 from "fs";
12633
+ import path38 from "path";
12634
+ import chalk28 from "chalk";
12635
+ import confirm3 from "@inquirer/confirm";
12636
+ init_pre_commit_block();
12637
+ init_builtin_skills();
12638
+ init_config();
12639
+ var MANAGED_DOC_FILES = [
12640
+ "CLAUDE.md",
12641
+ path38.join(".github", "copilot-instructions.md"),
12642
+ "AGENTS.md"
12643
+ ];
12644
+ var SKILL_DIRS = PLATFORM_CONFIGS.map((c) => c.skillsDir);
12645
+ var CURSOR_RULES_DIR = path38.join(".cursor", "rules");
12646
+ function removeCaliberCursorRules() {
12647
+ const removed = [];
12648
+ if (!fs48.existsSync(CURSOR_RULES_DIR)) return removed;
12649
+ for (const file of fs48.readdirSync(CURSOR_RULES_DIR)) {
12650
+ if (file.startsWith("caliber-") && file.endsWith(".mdc")) {
12651
+ const fullPath = path38.join(CURSOR_RULES_DIR, file);
12652
+ fs48.unlinkSync(fullPath);
12653
+ removed.push(fullPath);
12654
+ }
12655
+ }
12656
+ return removed;
12657
+ }
12658
+ function removeBuiltinSkills() {
12659
+ const removed = [];
12660
+ for (const skillsDir of SKILL_DIRS) {
12661
+ if (!fs48.existsSync(skillsDir)) continue;
12662
+ for (const name of BUILTIN_SKILL_NAMES) {
12663
+ const skillDir = path38.join(skillsDir, name);
12664
+ if (fs48.existsSync(skillDir)) {
12665
+ fs48.rmSync(skillDir, { recursive: true });
12666
+ removed.push(skillDir);
12667
+ }
12668
+ }
12669
+ }
12670
+ return removed;
12671
+ }
12672
+ function stripManagedBlocksFromFiles() {
12673
+ const modified = [];
12674
+ for (const filePath of MANAGED_DOC_FILES) {
12675
+ if (!fs48.existsSync(filePath)) continue;
12676
+ const original = fs48.readFileSync(filePath, "utf-8");
12677
+ const stripped = stripManagedBlocks(original);
12678
+ if (stripped !== original) {
12679
+ const trimmed = stripped.trim();
12680
+ if (!trimmed || /^#\s*\S*$/.test(trimmed)) {
12681
+ fs48.unlinkSync(filePath);
12682
+ } else {
12683
+ fs48.writeFileSync(filePath, stripped);
12684
+ }
12685
+ modified.push(filePath);
12686
+ }
12687
+ }
12688
+ return modified;
12689
+ }
12690
+ function removeDirectory(dir) {
12691
+ if (!fs48.existsSync(dir)) return false;
12692
+ fs48.rmSync(dir, { recursive: true });
12693
+ return true;
12694
+ }
12695
+ async function uninstallCommand(options) {
12696
+ console.log(chalk28.bold("\n Caliber Uninstall\n"));
12697
+ console.log(chalk28.dim(" This will remove all Caliber resources from this project:\n"));
12698
+ console.log(chalk28.dim(" \u2022 Pre-commit hook"));
12699
+ console.log(chalk28.dim(" \u2022 Session learning hooks"));
12700
+ console.log(chalk28.dim(" \u2022 Managed blocks in CLAUDE.md, AGENTS.md, copilot-instructions.md"));
12701
+ console.log(chalk28.dim(" \u2022 Cursor rules (caliber-*.mdc)"));
12702
+ console.log(chalk28.dim(" \u2022 Built-in skills (setup-caliber, find-skills, save-learning)"));
12703
+ console.log(chalk28.dim(" \u2022 CALIBER_LEARNINGS.md"));
12704
+ console.log(chalk28.dim(" \u2022 .caliber/ directory (backups, cache, state)\n"));
12705
+ if (!options.force) {
12706
+ const proceed = await confirm3({ message: "Continue with uninstall?" });
12707
+ if (!proceed) {
12708
+ console.log(chalk28.dim("\n Cancelled.\n"));
12709
+ return;
12710
+ }
12711
+ }
12712
+ console.log("");
12713
+ const actions = [];
12714
+ const hookResult = removePreCommitHook();
12715
+ if (hookResult.removed) {
12716
+ console.log(` ${chalk28.red("\u2717")} Pre-commit hook removed`);
12717
+ actions.push("pre-commit hook");
12718
+ }
12719
+ const learnResult = removeLearningHooks();
12720
+ if (learnResult.removed) {
12721
+ console.log(` ${chalk28.red("\u2717")} Claude Code learning hooks removed`);
12722
+ actions.push("claude learning hooks");
12723
+ }
12724
+ const cursorLearnResult = removeCursorLearningHooks();
12725
+ if (cursorLearnResult.removed) {
12726
+ console.log(` ${chalk28.red("\u2717")} Cursor learning hooks removed`);
12727
+ actions.push("cursor learning hooks");
12728
+ }
12729
+ const strippedFiles = stripManagedBlocksFromFiles();
12730
+ for (const file of strippedFiles) {
12731
+ console.log(` ${chalk28.yellow("~")} ${file} \u2014 managed blocks removed`);
12732
+ actions.push(file);
12733
+ }
12734
+ const removedRules = removeCaliberCursorRules();
12735
+ for (const rule of removedRules) {
12736
+ console.log(` ${chalk28.red("\u2717")} ${rule}`);
12737
+ }
12738
+ if (removedRules.length > 0) actions.push("cursor rules");
12739
+ const removedSkills = removeBuiltinSkills();
12740
+ for (const skill of removedSkills) {
12741
+ console.log(` ${chalk28.red("\u2717")} ${skill}/`);
12742
+ }
12743
+ if (removedSkills.length > 0) actions.push("builtin skills");
12744
+ if (fs48.existsSync("CALIBER_LEARNINGS.md")) {
12745
+ fs48.unlinkSync("CALIBER_LEARNINGS.md");
12746
+ console.log(` ${chalk28.red("\u2717")} CALIBER_LEARNINGS.md`);
12747
+ actions.push("learnings file");
12748
+ }
12749
+ if (removeDirectory(CALIBER_DIR)) {
12750
+ console.log(` ${chalk28.red("\u2717")} .caliber/ directory`);
12751
+ actions.push(".caliber directory");
12752
+ }
12753
+ if (actions.length === 0) {
12754
+ console.log(chalk28.dim(" Nothing to remove \u2014 Caliber is not installed in this project.\n"));
12755
+ return;
12756
+ }
12757
+ trackUninstallExecuted();
12758
+ const configPath = getConfigFilePath();
12759
+ if (fs48.existsSync(configPath)) {
12760
+ console.log("");
12761
+ const removeConfig = options.force || await confirm3({
12762
+ message: `Remove global config (~/.caliber/config.json)? This affects all projects.`
12763
+ });
12764
+ if (removeConfig) {
12765
+ fs48.unlinkSync(configPath);
12766
+ console.log(` ${chalk28.red("\u2717")} ${configPath}`);
12767
+ const configDir = path38.dirname(configPath);
12768
+ try {
12769
+ const remaining = fs48.readdirSync(configDir);
12770
+ if (remaining.length === 0) fs48.rmdirSync(configDir);
12771
+ } catch {
12772
+ }
12773
+ }
12774
+ }
12775
+ console.log(chalk28.bold.green(`
12776
+ Caliber has been removed from this project.`));
12777
+ console.log(chalk28.dim(" Your code is untouched \u2014 only Caliber config files were removed.\n"));
12778
+ }
12779
+
12542
12780
  // src/cli.ts
12543
- var __dirname = path38.dirname(fileURLToPath(import.meta.url));
12781
+ var __dirname = path39.dirname(fileURLToPath(import.meta.url));
12544
12782
  var pkg = JSON.parse(
12545
- fs47.readFileSync(path38.resolve(__dirname, "..", "package.json"), "utf-8")
12783
+ fs49.readFileSync(path39.resolve(__dirname, "..", "package.json"), "utf-8")
12546
12784
  );
12547
12785
  var program = new Command();
12548
12786
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
@@ -12550,9 +12788,11 @@ program.name(process.env.CALIBER_LOCAL ? "caloc" : "caliber").description("AI co
12550
12788
  function tracked(commandName, handler) {
12551
12789
  const wrapper = async (...args) => {
12552
12790
  const start = Date.now();
12791
+ const isCI = !!(process.env.CI || process.env.GITHUB_ACTIONS);
12553
12792
  trackEvent("command_started", {
12554
12793
  command: commandName,
12555
- cli_version: pkg.version
12794
+ cli_version: pkg.version,
12795
+ is_ci: isCI
12556
12796
  });
12557
12797
  try {
12558
12798
  await handler(...args);
@@ -12604,7 +12844,9 @@ function parseAgentOption(value) {
12604
12844
  return agents;
12605
12845
  }
12606
12846
  program.command("init").description("Initialize your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex, github-copilot", parseAgentOption).option("--source <paths...>", "Related source paths to include as context").option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing config without prompting").option("--debug-report", void 0, false).option("--show-tokens", "Show token usage summary at the end").option("--auto-approve", "Run without interactive prompts (auto-accept all)").option("--verbose", "Show detailed logs of each step").action(tracked("init", initCommand));
12847
+ program.command("bootstrap").description("Install agent skills (/setup-caliber, /find-skills, /save-learning) without running init").action(tracked("bootstrap", bootstrapCommand));
12607
12848
  program.command("undo").description("Revert all config changes made by Caliber").action(tracked("undo", undoCommand));
12849
+ program.command("uninstall").description("Remove all Caliber resources from this project").option("--force", "Skip confirmation prompt").action(tracked("uninstall", (options) => uninstallCommand(options)));
12608
12850
  program.command("status").description("Show current Caliber config status").option("--json", "Output as JSON").action(tracked("status", statusCommand));
12609
12851
  program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate config").option("--dry-run", "Preview changes without writing files").action(tracked("regenerate", regenerateCommand));
12610
12852
  program.command("config").description("Configure LLM provider, API key, and model").action(tracked("config", configCommand));
@@ -12629,16 +12871,16 @@ learn.command("delete <index>").description("Delete a learning by its index numb
12629
12871
  learn.command("add <content>").description("Add a learning directly (used by agent skills)").option("--personal", "Save as a personal learning instead of project-level").action(tracked("learn:add", learnAddCommand));
12630
12872
 
12631
12873
  // src/utils/version-check.ts
12632
- import fs48 from "fs";
12633
- import path39 from "path";
12874
+ import fs50 from "fs";
12875
+ import path40 from "path";
12634
12876
  import { fileURLToPath as fileURLToPath2 } from "url";
12635
12877
  import { execSync as execSync16, execFileSync as execFileSync3 } from "child_process";
12636
- import chalk27 from "chalk";
12878
+ import chalk29 from "chalk";
12637
12879
  import ora8 from "ora";
12638
- import confirm2 from "@inquirer/confirm";
12639
- var __dirname_vc = path39.dirname(fileURLToPath2(import.meta.url));
12880
+ import confirm4 from "@inquirer/confirm";
12881
+ var __dirname_vc = path40.dirname(fileURLToPath2(import.meta.url));
12640
12882
  var pkg2 = JSON.parse(
12641
- fs48.readFileSync(path39.resolve(__dirname_vc, "..", "package.json"), "utf-8")
12883
+ fs50.readFileSync(path40.resolve(__dirname_vc, "..", "package.json"), "utf-8")
12642
12884
  );
12643
12885
  function getChannel(version) {
12644
12886
  const match = version.match(/-(dev|next)\./);
@@ -12663,8 +12905,8 @@ function isNewer(registry, current) {
12663
12905
  function getInstalledVersion() {
12664
12906
  try {
12665
12907
  const globalRoot = execSync16("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
12666
- const pkgPath = path39.join(globalRoot, "@rely-ai", "caliber", "package.json");
12667
- return JSON.parse(fs48.readFileSync(pkgPath, "utf-8")).version;
12908
+ const pkgPath = path40.join(globalRoot, "@rely-ai", "caliber", "package.json");
12909
+ return JSON.parse(fs50.readFileSync(pkgPath, "utf-8")).version;
12668
12910
  } catch {
12669
12911
  return null;
12670
12912
  }
@@ -12689,20 +12931,20 @@ async function checkForUpdates() {
12689
12931
  if (!isInteractive) {
12690
12932
  const installTag = channel === "latest" ? "" : `@${channel}`;
12691
12933
  console.log(
12692
- chalk27.yellow(
12934
+ chalk29.yellow(
12693
12935
  `
12694
12936
  Update available: ${current} -> ${latest}
12695
- Run ${chalk27.bold(`npm install -g @rely-ai/caliber${installTag}`)} to upgrade.
12937
+ Run ${chalk29.bold(`npm install -g @rely-ai/caliber${installTag}`)} to upgrade.
12696
12938
  `
12697
12939
  )
12698
12940
  );
12699
12941
  return;
12700
12942
  }
12701
12943
  console.log(
12702
- chalk27.yellow(`
12944
+ chalk29.yellow(`
12703
12945
  Update available: ${current} -> ${latest}`)
12704
12946
  );
12705
- const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
12947
+ const shouldUpdate = await confirm4({ message: "Would you like to update now? (Y/n)", default: true });
12706
12948
  if (!shouldUpdate) {
12707
12949
  console.log();
12708
12950
  return;
@@ -12719,13 +12961,13 @@ Update available: ${current} -> ${latest}`)
12719
12961
  const installed = getInstalledVersion();
12720
12962
  if (installed !== latest) {
12721
12963
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
12722
- console.log(chalk27.yellow(`Run ${chalk27.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
12964
+ console.log(chalk29.yellow(`Run ${chalk29.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually.
12723
12965
  `));
12724
12966
  return;
12725
12967
  }
12726
- spinner.succeed(chalk27.green(`Updated to ${latest}`));
12968
+ spinner.succeed(chalk29.green(`Updated to ${latest}`));
12727
12969
  const args = process.argv.slice(2);
12728
- console.log(chalk27.dim(`
12970
+ console.log(chalk29.dim(`
12729
12971
  Restarting: caliber ${args.join(" ")}
12730
12972
  `));
12731
12973
  execFileSync3("caliber", args, {
@@ -12738,11 +12980,11 @@ Restarting: caliber ${args.join(" ")}
12738
12980
  if (err instanceof Error) {
12739
12981
  const stderr = err.stderr;
12740
12982
  const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
12741
- if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk27.dim(` ${errMsg}`));
12983
+ if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk29.dim(` ${errMsg}`));
12742
12984
  }
12743
12985
  console.log(
12744
- chalk27.yellow(
12745
- `Run ${chalk27.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually to upgrade.
12986
+ chalk29.yellow(
12987
+ `Run ${chalk29.bold(`npm install -g @rely-ai/caliber@${tag}`)} manually to upgrade.
12746
12988
  `
12747
12989
  )
12748
12990
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.31.0-dev.1774743306",
3
+ "version": "1.31.0-dev.1774815271",
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": {