@caliber-ai/cli 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -30,11 +30,15 @@ __export(constants_exports, {
30
30
  CALIBER_DIR: () => CALIBER_DIR,
31
31
  CLI_CALLBACK_PORT: () => CLI_CALLBACK_PORT,
32
32
  FRONTEND_URL: () => FRONTEND_URL,
33
+ LEARNING_DIR: () => LEARNING_DIR,
34
+ LEARNING_MAX_EVENTS: () => LEARNING_MAX_EVENTS,
35
+ LEARNING_SESSION_FILE: () => LEARNING_SESSION_FILE,
36
+ LEARNING_STATE_FILE: () => LEARNING_STATE_FILE,
33
37
  MANIFEST_FILE: () => MANIFEST_FILE
34
38
  });
35
39
  import path2 from "path";
36
40
  import os2 from "os";
37
- var API_URL, FRONTEND_URL, CLI_CALLBACK_PORT, AUTH_DIR, AUTH_FILE, CALIBER_DIR, MANIFEST_FILE, BACKUPS_DIR;
41
+ var API_URL, FRONTEND_URL, CLI_CALLBACK_PORT, AUTH_DIR, AUTH_FILE, CALIBER_DIR, MANIFEST_FILE, BACKUPS_DIR, LEARNING_DIR, LEARNING_SESSION_FILE, LEARNING_STATE_FILE, LEARNING_MAX_EVENTS;
38
42
  var init_constants = __esm({
39
43
  "src/constants.ts"() {
40
44
  "use strict";
@@ -46,6 +50,10 @@ var init_constants = __esm({
46
50
  CALIBER_DIR = ".caliber";
47
51
  MANIFEST_FILE = path2.join(CALIBER_DIR, "manifest.json");
48
52
  BACKUPS_DIR = path2.join(CALIBER_DIR, "backups");
53
+ LEARNING_DIR = path2.join(CALIBER_DIR, "learning");
54
+ LEARNING_SESSION_FILE = "current-session.jsonl";
55
+ LEARNING_STATE_FILE = "state.json";
56
+ LEARNING_MAX_EVENTS = 500;
49
57
  }
50
58
  });
51
59
 
@@ -75,8 +83,8 @@ if (dsn) {
75
83
 
76
84
  // src/cli.ts
77
85
  import { Command } from "commander";
78
- import fs22 from "fs";
79
- import path19 from "path";
86
+ import fs25 from "fs";
87
+ import path22 from "path";
80
88
  import { fileURLToPath as fileURLToPath3 } from "url";
81
89
 
82
90
  // src/commands/init.ts
@@ -957,9 +965,9 @@ async function getValidToken() {
957
965
  }
958
966
  return refreshed;
959
967
  }
960
- async function apiRequest(path21, options = {}) {
968
+ async function apiRequest(path24, options = {}) {
961
969
  let token = await getValidToken();
962
- let resp = await fetch(`${API_URL}${path21}`, {
970
+ let resp = await fetch(`${API_URL}${path24}`, {
963
971
  method: options.method || "GET",
964
972
  headers: {
965
973
  "Content-Type": "application/json",
@@ -973,7 +981,7 @@ async function apiRequest(path21, options = {}) {
973
981
  throw new Error("Session expired. Run `caliber login` to re-authenticate.");
974
982
  }
975
983
  token = refreshed;
976
- resp = await fetch(`${API_URL}${path21}`, {
984
+ resp = await fetch(`${API_URL}${path24}`, {
977
985
  method: options.method || "GET",
978
986
  headers: {
979
987
  "Content-Type": "application/json",
@@ -989,9 +997,9 @@ async function apiRequest(path21, options = {}) {
989
997
  const json = await resp.json();
990
998
  return json.data;
991
999
  }
992
- async function apiStream(path21, body, onChunk, onComplete, onError, onStatus) {
1000
+ async function apiStream(path24, body, onChunk, onComplete, onError, onStatus) {
993
1001
  let token = await getValidToken();
994
- let resp = await fetch(`${API_URL}${path21}`, {
1002
+ let resp = await fetch(`${API_URL}${path24}`, {
995
1003
  method: "POST",
996
1004
  headers: {
997
1005
  "Content-Type": "application/json",
@@ -1005,7 +1013,7 @@ async function apiStream(path21, body, onChunk, onComplete, onError, onStatus) {
1005
1013
  throw new Error("Session expired. Run `caliber login` to re-authenticate.");
1006
1014
  }
1007
1015
  token = refreshed;
1008
- resp = await fetch(`${API_URL}${path21}`, {
1016
+ resp = await fetch(`${API_URL}${path24}`, {
1009
1017
  method: "POST",
1010
1018
  headers: {
1011
1019
  "Content-Type": "application/json",
@@ -3371,10 +3379,374 @@ async function reviewCommand(message, options) {
3371
3379
  await submitReview({ rating, bestPart, biggestGap, wouldRecommend });
3372
3380
  }
3373
3381
 
3382
+ // src/commands/learn.ts
3383
+ import chalk14 from "chalk";
3384
+
3385
+ // src/learner/stdin.ts
3386
+ var STDIN_TIMEOUT_MS = 5e3;
3387
+ function readStdin() {
3388
+ return new Promise((resolve2, reject) => {
3389
+ if (process.stdin.isTTY) {
3390
+ resolve2("");
3391
+ return;
3392
+ }
3393
+ const chunks = [];
3394
+ const timer = setTimeout(() => {
3395
+ process.stdin.removeAllListeners();
3396
+ process.stdin.destroy();
3397
+ resolve2(Buffer.concat(chunks).toString("utf-8"));
3398
+ }, STDIN_TIMEOUT_MS);
3399
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
3400
+ process.stdin.on("end", () => {
3401
+ clearTimeout(timer);
3402
+ resolve2(Buffer.concat(chunks).toString("utf-8"));
3403
+ });
3404
+ process.stdin.on("error", (err) => {
3405
+ clearTimeout(timer);
3406
+ reject(err);
3407
+ });
3408
+ process.stdin.resume();
3409
+ });
3410
+ }
3411
+
3412
+ // src/learner/storage.ts
3413
+ init_constants();
3414
+ import fs22 from "fs";
3415
+ import path19 from "path";
3416
+ var MAX_RESPONSE_LENGTH = 2e3;
3417
+ var DEFAULT_STATE = {
3418
+ sessionId: null,
3419
+ eventCount: 0,
3420
+ lastAnalysisTimestamp: null
3421
+ };
3422
+ function ensureLearningDir() {
3423
+ if (!fs22.existsSync(LEARNING_DIR)) {
3424
+ fs22.mkdirSync(LEARNING_DIR, { recursive: true });
3425
+ }
3426
+ }
3427
+ function sessionFilePath() {
3428
+ return path19.join(LEARNING_DIR, LEARNING_SESSION_FILE);
3429
+ }
3430
+ function stateFilePath() {
3431
+ return path19.join(LEARNING_DIR, LEARNING_STATE_FILE);
3432
+ }
3433
+ function truncateResponse(response) {
3434
+ const str = JSON.stringify(response);
3435
+ if (str.length <= MAX_RESPONSE_LENGTH) return response;
3436
+ return { _truncated: str.slice(0, MAX_RESPONSE_LENGTH) };
3437
+ }
3438
+ function appendEvent(event) {
3439
+ ensureLearningDir();
3440
+ const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
3441
+ const filePath = sessionFilePath();
3442
+ fs22.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
3443
+ const count = getEventCount();
3444
+ if (count > LEARNING_MAX_EVENTS) {
3445
+ const lines = fs22.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
3446
+ const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
3447
+ fs22.writeFileSync(filePath, kept.join("\n") + "\n");
3448
+ }
3449
+ }
3450
+ function readAllEvents() {
3451
+ const filePath = sessionFilePath();
3452
+ if (!fs22.existsSync(filePath)) return [];
3453
+ const lines = fs22.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
3454
+ return lines.map((line) => JSON.parse(line));
3455
+ }
3456
+ function getEventCount() {
3457
+ const filePath = sessionFilePath();
3458
+ if (!fs22.existsSync(filePath)) return 0;
3459
+ const content = fs22.readFileSync(filePath, "utf-8");
3460
+ return content.split("\n").filter(Boolean).length;
3461
+ }
3462
+ function clearSession() {
3463
+ const filePath = sessionFilePath();
3464
+ if (fs22.existsSync(filePath)) fs22.unlinkSync(filePath);
3465
+ }
3466
+ function readState2() {
3467
+ const filePath = stateFilePath();
3468
+ if (!fs22.existsSync(filePath)) return { ...DEFAULT_STATE };
3469
+ try {
3470
+ return JSON.parse(fs22.readFileSync(filePath, "utf-8"));
3471
+ } catch {
3472
+ return { ...DEFAULT_STATE };
3473
+ }
3474
+ }
3475
+ function writeState2(state) {
3476
+ ensureLearningDir();
3477
+ fs22.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
3478
+ }
3479
+ function resetState() {
3480
+ writeState2({ ...DEFAULT_STATE });
3481
+ }
3482
+
3483
+ // src/learner/writer.ts
3484
+ import fs23 from "fs";
3485
+ import path20 from "path";
3486
+ var LEARNED_START = "<!-- caliber:learned -->";
3487
+ var LEARNED_END = "<!-- /caliber:learned -->";
3488
+ function writeLearnedContent(update) {
3489
+ const written = [];
3490
+ if (update.claudeMdLearnedSection) {
3491
+ writeLearnedSection(update.claudeMdLearnedSection);
3492
+ written.push("CLAUDE.md");
3493
+ }
3494
+ if (update.skills?.length) {
3495
+ for (const skill of update.skills) {
3496
+ const skillPath = writeLearnedSkill(skill);
3497
+ written.push(skillPath);
3498
+ }
3499
+ }
3500
+ return written;
3501
+ }
3502
+ function writeLearnedSection(content) {
3503
+ const claudeMdPath = "CLAUDE.md";
3504
+ let existing = "";
3505
+ if (fs23.existsSync(claudeMdPath)) {
3506
+ existing = fs23.readFileSync(claudeMdPath, "utf-8");
3507
+ }
3508
+ const section = `${LEARNED_START}
3509
+ ${content}
3510
+ ${LEARNED_END}`;
3511
+ const startIdx = existing.indexOf(LEARNED_START);
3512
+ const endIdx = existing.indexOf(LEARNED_END);
3513
+ let updated;
3514
+ if (startIdx !== -1 && endIdx !== -1) {
3515
+ updated = existing.slice(0, startIdx) + section + existing.slice(endIdx + LEARNED_END.length);
3516
+ } else {
3517
+ const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
3518
+ updated = existing + separator + "\n" + section + "\n";
3519
+ }
3520
+ fs23.writeFileSync(claudeMdPath, updated);
3521
+ }
3522
+ function writeLearnedSkill(skill) {
3523
+ const skillDir = path20.join(".claude", "skills", skill.name);
3524
+ if (!fs23.existsSync(skillDir)) fs23.mkdirSync(skillDir, { recursive: true });
3525
+ const skillPath = path20.join(skillDir, "SKILL.md");
3526
+ if (!skill.isNew && fs23.existsSync(skillPath)) {
3527
+ const existing = fs23.readFileSync(skillPath, "utf-8");
3528
+ fs23.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
3529
+ } else {
3530
+ const frontmatter = [
3531
+ "---",
3532
+ `name: ${skill.name}`,
3533
+ `description: ${skill.description}`,
3534
+ "---",
3535
+ ""
3536
+ ].join("\n");
3537
+ fs23.writeFileSync(skillPath, frontmatter + skill.content);
3538
+ }
3539
+ return skillPath;
3540
+ }
3541
+ function readLearnedSection() {
3542
+ const claudeMdPath = "CLAUDE.md";
3543
+ if (!fs23.existsSync(claudeMdPath)) return null;
3544
+ const content = fs23.readFileSync(claudeMdPath, "utf-8");
3545
+ const startIdx = content.indexOf(LEARNED_START);
3546
+ const endIdx = content.indexOf(LEARNED_END);
3547
+ if (startIdx === -1 || endIdx === -1) return null;
3548
+ return content.slice(startIdx + LEARNED_START.length, endIdx).trim();
3549
+ }
3550
+
3551
+ // src/lib/learning-hooks.ts
3552
+ import fs24 from "fs";
3553
+ import path21 from "path";
3554
+ var SETTINGS_PATH2 = path21.join(".claude", "settings.json");
3555
+ var HOOK_CONFIGS = [
3556
+ {
3557
+ event: "PostToolUse",
3558
+ command: "caliber learn observe",
3559
+ description: "Caliber: recording tool usage for session learning"
3560
+ },
3561
+ {
3562
+ event: "PostToolUseFailure",
3563
+ command: "caliber learn observe --failure",
3564
+ description: "Caliber: recording tool failure for session learning"
3565
+ },
3566
+ {
3567
+ event: "SessionEnd",
3568
+ command: "caliber learn finalize",
3569
+ description: "Caliber: finalizing session learnings"
3570
+ }
3571
+ ];
3572
+ function readSettings2() {
3573
+ if (!fs24.existsSync(SETTINGS_PATH2)) return {};
3574
+ try {
3575
+ return JSON.parse(fs24.readFileSync(SETTINGS_PATH2, "utf-8"));
3576
+ } catch {
3577
+ return {};
3578
+ }
3579
+ }
3580
+ function writeSettings2(settings) {
3581
+ const dir = path21.dirname(SETTINGS_PATH2);
3582
+ if (!fs24.existsSync(dir)) fs24.mkdirSync(dir, { recursive: true });
3583
+ fs24.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
3584
+ }
3585
+ function hasLearningHook(matchers, command) {
3586
+ return matchers.some((entry) => entry.hooks?.some((h) => h.command === command));
3587
+ }
3588
+ function areLearningHooksInstalled() {
3589
+ const settings = readSettings2();
3590
+ if (!settings.hooks) return false;
3591
+ return HOOK_CONFIGS.every((cfg) => {
3592
+ const matchers = settings.hooks[cfg.event];
3593
+ return Array.isArray(matchers) && hasLearningHook(matchers, cfg.command);
3594
+ });
3595
+ }
3596
+ function installLearningHooks() {
3597
+ if (areLearningHooksInstalled()) {
3598
+ return { installed: false, alreadyInstalled: true };
3599
+ }
3600
+ const settings = readSettings2();
3601
+ if (!settings.hooks) settings.hooks = {};
3602
+ for (const cfg of HOOK_CONFIGS) {
3603
+ if (!Array.isArray(settings.hooks[cfg.event])) {
3604
+ settings.hooks[cfg.event] = [];
3605
+ }
3606
+ if (!hasLearningHook(settings.hooks[cfg.event], cfg.command)) {
3607
+ settings.hooks[cfg.event].push({
3608
+ matcher: "",
3609
+ hooks: [{ type: "command", command: cfg.command, description: cfg.description }]
3610
+ });
3611
+ }
3612
+ }
3613
+ writeSettings2(settings);
3614
+ return { installed: true, alreadyInstalled: false };
3615
+ }
3616
+ function removeLearningHooks() {
3617
+ const settings = readSettings2();
3618
+ if (!settings.hooks) return { removed: false, notFound: true };
3619
+ let removedAny = false;
3620
+ for (const cfg of HOOK_CONFIGS) {
3621
+ const matchers = settings.hooks[cfg.event];
3622
+ if (!Array.isArray(matchers)) continue;
3623
+ const idx = matchers.findIndex((entry) => entry.hooks?.some((h) => h.command === cfg.command));
3624
+ if (idx !== -1) {
3625
+ matchers.splice(idx, 1);
3626
+ removedAny = true;
3627
+ if (matchers.length === 0) delete settings.hooks[cfg.event];
3628
+ }
3629
+ }
3630
+ if (settings.hooks && Object.keys(settings.hooks).length === 0) {
3631
+ delete settings.hooks;
3632
+ }
3633
+ if (!removedAny) return { removed: false, notFound: true };
3634
+ writeSettings2(settings);
3635
+ return { removed: true, notFound: false };
3636
+ }
3637
+
3638
+ // src/commands/learn.ts
3639
+ async function learnObserveCommand(options) {
3640
+ try {
3641
+ const raw = await readStdin();
3642
+ if (!raw.trim()) return;
3643
+ const hookData = JSON.parse(raw);
3644
+ const event = {
3645
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3646
+ session_id: hookData.session_id || "unknown",
3647
+ hook_event_name: options.failure ? "PostToolUseFailure" : "PostToolUse",
3648
+ tool_name: hookData.tool_name || "unknown",
3649
+ tool_input: hookData.tool_input || {},
3650
+ tool_response: hookData.tool_response || {},
3651
+ tool_use_id: hookData.tool_use_id || "",
3652
+ cwd: hookData.cwd || process.cwd()
3653
+ };
3654
+ appendEvent(event);
3655
+ const state = readState2();
3656
+ state.eventCount++;
3657
+ if (!state.sessionId) state.sessionId = event.session_id;
3658
+ writeState2(state);
3659
+ } catch {
3660
+ }
3661
+ }
3662
+ async function learnFinalizeCommand() {
3663
+ try {
3664
+ const auth2 = getStoredAuth();
3665
+ if (!auth2) {
3666
+ clearSession();
3667
+ resetState();
3668
+ return;
3669
+ }
3670
+ const events = readAllEvents();
3671
+ if (!events.length) {
3672
+ clearSession();
3673
+ resetState();
3674
+ return;
3675
+ }
3676
+ const existingConfigs = readExistingConfigs(process.cwd());
3677
+ const existingLearnedSection = readLearnedSection();
3678
+ const existingSkills = existingConfigs.claudeSkills || [];
3679
+ const response = await apiRequest("/api/learn/analyze", {
3680
+ method: "POST",
3681
+ body: {
3682
+ events,
3683
+ existingClaudeMd: existingConfigs.claudeMd || "",
3684
+ existingLearnedSection,
3685
+ existingSkills
3686
+ }
3687
+ });
3688
+ if (response.claudeMdLearnedSection || response.skills?.length) {
3689
+ writeLearnedContent({
3690
+ claudeMdLearnedSection: response.claudeMdLearnedSection,
3691
+ skills: response.skills
3692
+ });
3693
+ }
3694
+ } catch {
3695
+ } finally {
3696
+ clearSession();
3697
+ resetState();
3698
+ }
3699
+ }
3700
+ async function learnInstallCommand() {
3701
+ const result = installLearningHooks();
3702
+ if (result.alreadyInstalled) {
3703
+ console.log(chalk14.dim("Learning hooks already installed."));
3704
+ return;
3705
+ }
3706
+ console.log(chalk14.green("\u2713") + " Learning hooks installed in .claude/settings.json");
3707
+ console.log(chalk14.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
3708
+ console.log(chalk14.dim(" Session learnings will be written to CLAUDE.md and skills."));
3709
+ }
3710
+ async function learnRemoveCommand() {
3711
+ const result = removeLearningHooks();
3712
+ if (result.notFound) {
3713
+ console.log(chalk14.dim("Learning hooks not found."));
3714
+ return;
3715
+ }
3716
+ console.log(chalk14.green("\u2713") + " Learning hooks removed from .claude/settings.json");
3717
+ }
3718
+ async function learnStatusCommand() {
3719
+ const installed = areLearningHooksInstalled();
3720
+ const state = readState2();
3721
+ const eventCount = getEventCount();
3722
+ console.log(chalk14.bold("Session Learning Status"));
3723
+ console.log();
3724
+ if (installed) {
3725
+ console.log(chalk14.green("\u2713") + " Learning hooks are " + chalk14.green("installed"));
3726
+ } else {
3727
+ console.log(chalk14.dim("\u2717") + " Learning hooks are " + chalk14.yellow("not installed"));
3728
+ console.log(chalk14.dim(" Run `caliber learn install` to enable session learning."));
3729
+ }
3730
+ console.log();
3731
+ console.log(`Events recorded: ${chalk14.cyan(String(eventCount))}`);
3732
+ console.log(`Total this session: ${chalk14.cyan(String(state.eventCount))}`);
3733
+ if (state.lastAnalysisTimestamp) {
3734
+ console.log(`Last analysis: ${chalk14.cyan(state.lastAnalysisTimestamp)}`);
3735
+ } else {
3736
+ console.log(`Last analysis: ${chalk14.dim("none")}`);
3737
+ }
3738
+ const learnedSection = readLearnedSection();
3739
+ if (learnedSection) {
3740
+ const lineCount = learnedSection.split("\n").filter(Boolean).length;
3741
+ console.log(`
3742
+ Learned items in CLAUDE.md: ${chalk14.cyan(String(lineCount))}`);
3743
+ }
3744
+ }
3745
+
3374
3746
  // src/cli.ts
3375
- var __dirname2 = path19.dirname(fileURLToPath3(import.meta.url));
3747
+ var __dirname2 = path22.dirname(fileURLToPath3(import.meta.url));
3376
3748
  var pkg3 = JSON.parse(
3377
- fs22.readFileSync(path19.resolve(__dirname2, "..", "package.json"), "utf-8")
3749
+ fs25.readFileSync(path22.resolve(__dirname2, "..", "package.json"), "utf-8")
3378
3750
  );
3379
3751
  var program = new Command();
3380
3752
  var displayVersion = process.env.CALIBER_LOCAL ? `${pkg3.version}-local` : pkg3.version;
@@ -3394,24 +3766,30 @@ var hooks = program.command("hooks").description("Manage Claude Code session hoo
3394
3766
  hooks.command("install").description("Install auto-refresh SessionEnd hook").action(hooksInstallCommand);
3395
3767
  hooks.command("remove").description("Remove auto-refresh SessionEnd hook").action(hooksRemoveCommand);
3396
3768
  hooks.command("status").description("Check if auto-refresh hook is installed").action(hooksStatusCommand);
3769
+ var learn = program.command("learn").description("Session learning \u2014 observe tool usage and extract reusable instructions");
3770
+ learn.command("observe").description("Record a tool event from stdin (called by hooks)").option("--failure", "Mark event as a tool failure").action(learnObserveCommand);
3771
+ learn.command("finalize").description("Analyze session events and update CLAUDE.md (called on SessionEnd)").action(learnFinalizeCommand);
3772
+ learn.command("install").description("Install learning hooks into .claude/settings.json").action(learnInstallCommand);
3773
+ learn.command("remove").description("Remove learning hooks from .claude/settings.json").action(learnRemoveCommand);
3774
+ learn.command("status").description("Show learning system status").action(learnStatusCommand);
3397
3775
 
3398
3776
  // src/utils/version-check.ts
3399
- import fs23 from "fs";
3400
- import path20 from "path";
3777
+ import fs26 from "fs";
3778
+ import path23 from "path";
3401
3779
  import { fileURLToPath as fileURLToPath4 } from "url";
3402
3780
  import { execSync as execSync5 } from "child_process";
3403
- import chalk14 from "chalk";
3781
+ import chalk15 from "chalk";
3404
3782
  import ora10 from "ora";
3405
3783
  import confirm3 from "@inquirer/confirm";
3406
- var __dirname_vc = path20.dirname(fileURLToPath4(import.meta.url));
3784
+ var __dirname_vc = path23.dirname(fileURLToPath4(import.meta.url));
3407
3785
  var pkg4 = JSON.parse(
3408
- fs23.readFileSync(path20.resolve(__dirname_vc, "..", "package.json"), "utf-8")
3786
+ fs26.readFileSync(path23.resolve(__dirname_vc, "..", "package.json"), "utf-8")
3409
3787
  );
3410
3788
  function getInstalledVersion() {
3411
3789
  try {
3412
3790
  const globalRoot = execSync5("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3413
- const pkgPath = path20.join(globalRoot, "@caliber-ai", "cli", "package.json");
3414
- return JSON.parse(fs23.readFileSync(pkgPath, "utf-8")).version;
3791
+ const pkgPath = path23.join(globalRoot, "@caliber-ai", "cli", "package.json");
3792
+ return JSON.parse(fs26.readFileSync(pkgPath, "utf-8")).version;
3415
3793
  } catch {
3416
3794
  return null;
3417
3795
  }
@@ -3434,17 +3812,17 @@ async function checkForUpdates() {
3434
3812
  const isInteractive = process.stdin.isTTY === true;
3435
3813
  if (!isInteractive) {
3436
3814
  console.log(
3437
- chalk14.yellow(
3815
+ chalk15.yellow(
3438
3816
  `
3439
3817
  Update available: ${current} -> ${latest}
3440
- Run ${chalk14.bold("npm install -g @caliber-ai/cli")} to upgrade.
3818
+ Run ${chalk15.bold("npm install -g @caliber-ai/cli")} to upgrade.
3441
3819
  `
3442
3820
  )
3443
3821
  );
3444
3822
  return;
3445
3823
  }
3446
3824
  console.log(
3447
- chalk14.yellow(`
3825
+ chalk15.yellow(`
3448
3826
  Update available: ${current} -> ${latest}`)
3449
3827
  );
3450
3828
  const shouldUpdate = await confirm3({ message: "Would you like to update now? (Y/n)", default: true });
@@ -3458,13 +3836,13 @@ Update available: ${current} -> ${latest}`)
3458
3836
  const installed = getInstalledVersion();
3459
3837
  if (installed !== latest) {
3460
3838
  spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
3461
- console.log(chalk14.yellow(`Run ${chalk14.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually.
3839
+ console.log(chalk15.yellow(`Run ${chalk15.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually.
3462
3840
  `));
3463
3841
  return;
3464
3842
  }
3465
- spinner.succeed(chalk14.green(`Updated to ${latest}`));
3843
+ spinner.succeed(chalk15.green(`Updated to ${latest}`));
3466
3844
  const args = process.argv.slice(2);
3467
- console.log(chalk14.dim(`
3845
+ console.log(chalk15.dim(`
3468
3846
  Restarting: caliber ${args.join(" ")}
3469
3847
  `));
3470
3848
  execSync5(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
@@ -3475,10 +3853,10 @@ Restarting: caliber ${args.join(" ")}
3475
3853
  } catch (err) {
3476
3854
  spinner.fail("Update failed");
3477
3855
  const msg = err instanceof Error ? err.message : "";
3478
- if (msg && !msg.includes("SIGTERM")) console.log(chalk14.dim(` ${msg.split("\n")[0]}`));
3856
+ if (msg && !msg.includes("SIGTERM")) console.log(chalk15.dim(` ${msg.split("\n")[0]}`));
3479
3857
  console.log(
3480
- chalk14.yellow(
3481
- `Run ${chalk14.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually to upgrade.
3858
+ chalk15.yellow(
3859
+ `Run ${chalk15.bold(`npm install -g @caliber-ai/cli@${latest}`)} manually to upgrade.
3482
3860
  `
3483
3861
  )
3484
3862
  );