@onebrain-ai/cli 2.1.0 → 2.1.2

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/onebrain +311 -265
  2. package/package.json +2 -2
package/dist/onebrain CHANGED
@@ -9015,7 +9015,7 @@ async function checkVaultYml(vaultRoot) {
9015
9015
  check: "vault.yml",
9016
9016
  status: "ok",
9017
9017
  message: "valid",
9018
- details: details.length > 0 ? details : undefined
9018
+ ...details.length > 0 ? { details } : {}
9019
9019
  };
9020
9020
  }
9021
9021
  async function checkFolders(vaultRoot, config) {
@@ -9338,7 +9338,7 @@ async function checkVaultYmlKeys(vaultRoot) {
9338
9338
  check: "vault.yml-keys",
9339
9339
  status: "error",
9340
9340
  message: `${errors.length} error(s)`,
9341
- hint,
9341
+ ...hint !== undefined ? { hint } : {},
9342
9342
  details: hint ? [...errors, hint] : errors
9343
9343
  };
9344
9344
  }
@@ -9349,7 +9349,7 @@ async function checkVaultYmlKeys(vaultRoot) {
9349
9349
  check: "vault.yml-keys",
9350
9350
  status: "warn",
9351
9351
  message: `${warnings.length} issue(s)`,
9352
- hint,
9352
+ ...hint !== undefined ? { hint } : {},
9353
9353
  details: hint ? [...warnings, hint] : warnings
9354
9354
  };
9355
9355
  }
@@ -9443,7 +9443,7 @@ async function checkSettingsHooks(vaultRoot, config) {
9443
9443
  check: "settings-hooks",
9444
9444
  status: "ok",
9445
9445
  message: "hooks ok",
9446
- details: okDetails.length > 0 ? okDetails : undefined
9446
+ ...okDetails.length > 0 ? { details: okDetails } : {}
9447
9447
  };
9448
9448
  }
9449
9449
  var import_yaml2, STANDARD_FOLDER_KEYS, REQUIRED_PLUGIN_FILES, REQUIRED_PLUGIN_DIRS, STALE_BASH_FILES, REQUIRED_VAULT_YML_KEYS, REQUIRED_FOLDER_KEYS, REQUIRED_HOOKS, QMD_HOOK_SUBSTRING = "onebrain qmd-reindex", PRECOMPACT_ONEBRAIN_SUBSTRING = "onebrain", REQUIRED_PERMISSION = "Bash(onebrain *)", STALE_HOOK_SUBSTRINGS;
@@ -9498,7 +9498,7 @@ var init_lib = __esm(() => {
9498
9498
  var require_package = __commonJS((exports, module) => {
9499
9499
  module.exports = {
9500
9500
  name: "@onebrain-ai/cli",
9501
- version: "2.1.0",
9501
+ version: "2.1.2",
9502
9502
  description: "CLI for OneBrain — personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
9503
9503
  keywords: [
9504
9504
  "onebrain",
@@ -9526,7 +9526,7 @@ var require_package = __commonJS((exports, module) => {
9526
9526
  },
9527
9527
  files: ["dist/onebrain"],
9528
9528
  scripts: {
9529
- build: "bun build src/index.ts --outfile dist/onebrain --target node",
9529
+ build: "bun build src/index.ts --outfile dist/onebrain --target bun",
9530
9530
  test: "bun test --pass-with-no-tests src/",
9531
9531
  typecheck: "tsc --noEmit"
9532
9532
  },
@@ -9545,6 +9545,129 @@ var require_package = __commonJS((exports, module) => {
9545
9545
  };
9546
9546
  });
9547
9547
 
9548
+ // src/commands/internal/cli-ui.ts
9549
+ function out(str) {
9550
+ process.stdout.write(Buffer.from(str, "utf8"));
9551
+ }
9552
+ function writeLine(msg) {
9553
+ out(`${msg}
9554
+ `);
9555
+ }
9556
+ function barLine(msg) {
9557
+ out(`${bar} ${msg}
9558
+ `);
9559
+ }
9560
+ function barBlank() {
9561
+ out(`${bar}
9562
+ `);
9563
+ }
9564
+ function close(msg, isError = false, isWarning = false) {
9565
+ if (isError) {
9566
+ out(`${import_picocolors2.default.cyan("└")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
9567
+ `);
9568
+ } else if (isWarning) {
9569
+ out(`${import_picocolors2.default.cyan("└")} ${import_picocolors2.default.yellow(msg)}
9570
+ `);
9571
+ } else {
9572
+ out(`${import_picocolors2.default.cyan("└")} ${msg}
9573
+ `);
9574
+ }
9575
+ }
9576
+ function dotLine(emoji, label) {
9577
+ out(`${dot} ${emoji} ${label}
9578
+ `);
9579
+ }
9580
+ function makeStepFn(isTTY) {
9581
+ return function createStep(emoji, label) {
9582
+ if (!isTTY)
9583
+ return null;
9584
+ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
9585
+ let i = 0;
9586
+ out(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}…
9587
+ `);
9588
+ const timer = setInterval(() => {
9589
+ i = (i + 1) % frames.length;
9590
+ out(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}…
9591
+ `);
9592
+ }, 80);
9593
+ return {
9594
+ stop(result, details) {
9595
+ clearInterval(timer);
9596
+ process.stdout.write(Buffer.from("\x1B[1A\x1B[2K", "utf8"));
9597
+ out(`${dot} ${emoji} ${label}
9598
+ `);
9599
+ if (result !== undefined)
9600
+ barLine(result);
9601
+ if (details)
9602
+ for (const d of details)
9603
+ barLine(` · ${d}`);
9604
+ barBlank();
9605
+ }
9606
+ };
9607
+ };
9608
+ }
9609
+ async function askYesNo(question) {
9610
+ out(`${import_picocolors2.default.cyan("◆")} ${question}
9611
+ `);
9612
+ process.stdout.write(Buffer.from("\x1B[?25l", "utf8"));
9613
+ function renderOptions(yes) {
9614
+ const yesLabel = yes ? `${import_picocolors2.default.bold(import_picocolors2.default.green("●"))} Yes` : `${import_picocolors2.default.dim("○")} Yes`;
9615
+ const noLabel = yes ? `${import_picocolors2.default.dim("○")} No` : `${import_picocolors2.default.bold(import_picocolors2.default.green("●"))} No`;
9616
+ out(`\x1B[2K${bar} ${yesLabel} / ${noLabel}\r`);
9617
+ }
9618
+ const answer = await new Promise((resolve) => {
9619
+ let selected = true;
9620
+ renderOptions(selected);
9621
+ const { stdin } = process;
9622
+ const wasRaw = stdin.isTTY ? stdin.isRaw : false;
9623
+ if (stdin.isTTY)
9624
+ stdin.setRawMode(true);
9625
+ stdin.resume();
9626
+ function onData(buf) {
9627
+ const key = buf.toString();
9628
+ if (key === "\x03") {
9629
+ stdin.removeListener("data", onData);
9630
+ if (stdin.isTTY)
9631
+ stdin.setRawMode(wasRaw);
9632
+ stdin.pause();
9633
+ resolve(null);
9634
+ } else if (key === "\r" || key === `
9635
+ `) {
9636
+ stdin.removeListener("data", onData);
9637
+ if (stdin.isTTY)
9638
+ stdin.setRawMode(wasRaw);
9639
+ stdin.pause();
9640
+ resolve(selected);
9641
+ } else if (key === "y" || key === "Y") {
9642
+ stdin.removeListener("data", onData);
9643
+ if (stdin.isTTY)
9644
+ stdin.setRawMode(wasRaw);
9645
+ stdin.pause();
9646
+ resolve(true);
9647
+ } else if (key === "n" || key === "N") {
9648
+ stdin.removeListener("data", onData);
9649
+ if (stdin.isTTY)
9650
+ stdin.setRawMode(wasRaw);
9651
+ stdin.pause();
9652
+ resolve(false);
9653
+ } else if (key === "\x1B[C" || key === "\x1B[D" || key === "\t") {
9654
+ selected = !selected;
9655
+ renderOptions(selected);
9656
+ }
9657
+ }
9658
+ stdin.on("data", onData);
9659
+ });
9660
+ process.stdout.write(Buffer.from(`
9661
+ \x1B[?25h\x1B[1A\x1B[2K`, "utf8"));
9662
+ return answer;
9663
+ }
9664
+ var import_picocolors2, bar, dot;
9665
+ var init_cli_ui = __esm(() => {
9666
+ import_picocolors2 = __toESM(require_picocolors(), 1);
9667
+ bar = import_picocolors2.default.cyan("│");
9668
+ dot = import_picocolors2.default.green("●");
9669
+ });
9670
+
9548
9671
  // node_modules/sisteransi/src/index.js
9549
9672
  var require_src = __commonJS((exports, module) => {
9550
9673
  var ESC = "\x1B";
@@ -10461,35 +10584,47 @@ async function runVaultSync(vaultRoot, opts = {}) {
10461
10584
  pinSkipped: true,
10462
10585
  cacheRemoved: 0
10463
10586
  };
10587
+ const embedded = opts.embedded ?? false;
10588
+ const createEmbeddedStep = embedded ? makeStepFn(true) : null;
10464
10589
  let s = null;
10465
- function startSpinner(msg) {
10590
+ let currentStep = null;
10591
+ function startSpinner(emoji, label) {
10466
10592
  if (isTTY) {
10467
- s = L2();
10468
- s.start(msg);
10593
+ if (embedded) {
10594
+ currentStep = createEmbeddedStep(emoji, label);
10595
+ } else {
10596
+ s = L2();
10597
+ s.start(label);
10598
+ }
10469
10599
  } else {
10470
- process.stdout.write(`vault-sync: ${msg}
10600
+ process.stdout.write(`vault-sync: ${label}
10471
10601
  `);
10472
10602
  }
10473
10603
  }
10474
- function stopSpinner(msg) {
10475
- if (isTTY && s) {
10476
- s.stop(msg);
10477
- s = null;
10604
+ function stopSpinner(result2, details) {
10605
+ if (isTTY) {
10606
+ if (embedded) {
10607
+ currentStep?.stop(import_picocolors6.default.dim(result2), details);
10608
+ currentStep = null;
10609
+ } else if (s) {
10610
+ s.stop(result2);
10611
+ s = null;
10612
+ }
10478
10613
  }
10479
10614
  }
10480
- if (isTTY) {
10615
+ if (isTTY && !embedded) {
10481
10616
  we("OneBrain Vault Sync");
10482
10617
  }
10483
10618
  let tmpDir = null;
10484
10619
  try {
10485
- startSpinner("Downloading tarball...");
10620
+ startSpinner("\uD83D\uDCE5", "Downloading");
10486
10621
  let extractedDir;
10487
10622
  try {
10488
10623
  const dl = await downloadTarball(branch, fetchFn);
10489
10624
  tmpDir = dl.tmpDir;
10490
10625
  extractedDir = await extractTarball(dl.tarball, tmpDir);
10491
10626
  } catch (err) {
10492
- stopSpinner("Download failed");
10627
+ stopSpinner("download failed");
10493
10628
  const msg = err instanceof Error ? err.message : String(err);
10494
10629
  result.error = msg;
10495
10630
  process.stderr.write(`vault-sync: download failed: ${msg}
@@ -10504,13 +10639,13 @@ async function runVaultSync(vaultRoot, opts = {}) {
10504
10639
  }
10505
10640
  } catch {}
10506
10641
  stopSpinner(`kengio/onebrain@${branch} (v${result.version})`);
10507
- startSpinner("Syncing plugin files...");
10642
+ startSpinner("\uD83D\uDCC2", "Syncing files");
10508
10643
  try {
10509
10644
  const { filesAdded, filesRemoved } = await syncPluginFiles(extractedDir, vaultRoot, unlinkFn);
10510
10645
  result.filesAdded = filesAdded;
10511
10646
  result.filesRemoved = filesRemoved;
10512
10647
  } catch (err) {
10513
- stopSpinner("Plugin sync failed");
10648
+ stopSpinner("plugin sync failed");
10514
10649
  const msg = err instanceof Error ? err.message : String(err);
10515
10650
  result.error = msg;
10516
10651
  process.stderr.write(`vault-sync: plugin sync failed: ${msg}
@@ -10533,13 +10668,13 @@ async function runVaultSync(vaultRoot, opts = {}) {
10533
10668
  } catch {}
10534
10669
  }
10535
10670
  await copyRootDocs(extractedDir, vaultRoot);
10536
- startSpinner("Updating harness files...");
10671
+ startSpinner("\uD83D\uDD27", "Updating harness");
10537
10672
  let importsAdded = 0;
10538
10673
  try {
10539
10674
  importsAdded = await mergeHarnessFiles(extractedDir, vaultRoot);
10540
10675
  result.importsAdded = importsAdded;
10541
10676
  } catch (err) {
10542
- stopSpinner("Harness merge failed");
10677
+ stopSpinner("harness merge failed");
10543
10678
  const msg = err instanceof Error ? err.message : String(err);
10544
10679
  result.error = msg;
10545
10680
  process.stderr.write(`vault-sync: harness merge failed: ${msg}
@@ -10561,7 +10696,7 @@ async function runVaultSync(vaultRoot, opts = {}) {
10561
10696
  return result;
10562
10697
  }
10563
10698
  if (harness === "claude") {
10564
- startSpinner("Pinning to vault...");
10699
+ startSpinner("\uD83D\uDCCC", "Pinning to vault");
10565
10700
  try {
10566
10701
  const pinResult = await pinToVault(vaultRoot, installedPluginsPath, installedPluginsCacheDir);
10567
10702
  result.pinSkipped = pinResult.skipped;
@@ -10577,7 +10712,7 @@ async function runVaultSync(vaultRoot, opts = {}) {
10577
10712
  result.pinSkipped = true;
10578
10713
  stopSpinner("pin skipped (error — non-fatal)");
10579
10714
  }
10580
- startSpinner("Cleaning cache...");
10715
+ startSpinner("\uD83E\uDDF9", "Cleaning cache");
10581
10716
  try {
10582
10717
  const cacheRemoved = await cleanPluginCache(installedPluginsPath, installedPluginsCacheDir);
10583
10718
  result.cacheRemoved = cacheRemoved;
@@ -10595,7 +10730,9 @@ async function runVaultSync(vaultRoot, opts = {}) {
10595
10730
  }
10596
10731
  result.ok = true;
10597
10732
  if (isTTY) {
10598
- fe(`Done — v${result.version} synced`);
10733
+ if (!embedded) {
10734
+ fe(`Done — v${result.version} synced`);
10735
+ }
10599
10736
  } else {
10600
10737
  process.stdout.write(`vault-sync: done
10601
10738
  `);
@@ -10613,16 +10750,18 @@ async function vaultSyncCommand(vaultRoot, opts = {}) {
10613
10750
  process.exit(1);
10614
10751
  }
10615
10752
  }
10616
- var import_yaml3;
10753
+ var import_picocolors6, import_yaml3;
10617
10754
  var init_vault_sync = __esm(() => {
10618
10755
  init_dist2();
10756
+ init_cli_ui();
10619
10757
  init_harness();
10758
+ import_picocolors6 = __toESM(require_picocolors(), 1);
10620
10759
  import_yaml3 = __toESM(require_dist(), 1);
10621
10760
  });
10622
10761
 
10623
10762
  // src/index.ts
10624
10763
  import { existsSync } from "fs";
10625
- import { dirname as dirname6, join as join14 } from "path";
10764
+ import { dirname as dirname6, join as join13 } from "path";
10626
10765
 
10627
10766
  // node_modules/commander/esm.mjs
10628
10767
  var import__ = __toESM(require_commander(), 1);
@@ -10648,7 +10787,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
10648
10787
  var import_picocolors = __toESM(require_picocolors(), 1);
10649
10788
  function resolveBinaryVersion() {
10650
10789
  if (true)
10651
- return "2.1.0";
10790
+ return "2.1.2";
10652
10791
  try {
10653
10792
  const pkg = require_package();
10654
10793
  return pkg.version ?? "dev";
@@ -10713,39 +10852,42 @@ function scanLine(line) {
10713
10852
  function dimLine(line) {
10714
10853
  return line.split("").map((ch) => ch === " " ? ch : `\x1B[2;38;2;50;50;70m${ch}\x1B[0m`).join("");
10715
10854
  }
10855
+ function outb(str) {
10856
+ process.stdout.write(Buffer.from(str, "utf8"));
10857
+ }
10716
10858
  function printFrame(artLines, tagline) {
10717
- process.stdout.write(`
10859
+ outb(`
10718
10860
  `);
10719
10861
  for (const l of artLines)
10720
- process.stdout.write(`${l}
10862
+ outb(`${l}
10721
10863
  `);
10722
- process.stdout.write(`
10864
+ outb(`
10723
10865
  `);
10724
- process.stdout.write(`${tagline}
10866
+ outb(`${tagline}
10725
10867
  `);
10726
- process.stdout.write(`
10868
+ outb(`
10727
10869
  `);
10728
10870
  }
10729
10871
  async function printBanner() {
10730
10872
  if (!process.stdout.isTTY)
10731
10873
  return;
10732
10874
  const delay = (ms) => new Promise((r) => setTimeout(r, ms));
10733
- const up = (n) => process.stdout.write(`\x1B[${n}F`);
10875
+ const up = (n) => outb(`\x1B[${n}F`);
10734
10876
  if (!supportsRgb()) {
10735
- process.stdout.write(`
10877
+ outb(`
10736
10878
  `);
10737
10879
  for (const l of ART_LINES)
10738
- process.stdout.write(`${import_picocolors.default.bold(import_picocolors.default.cyan(l))}
10880
+ outb(`${import_picocolors.default.bold(import_picocolors.default.cyan(l))}
10739
10881
  `);
10740
- process.stdout.write(`
10882
+ outb(`
10741
10883
  `);
10742
- process.stdout.write(` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}
10884
+ outb(` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}
10743
10885
  `);
10744
- process.stdout.write(`
10886
+ outb(`
10745
10887
  `);
10746
10888
  return;
10747
10889
  }
10748
- process.stdout.write("\x1B[?25l");
10890
+ outb("\x1B[?25l");
10749
10891
  try {
10750
10892
  let diagFrame = function(highlight) {
10751
10893
  return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
@@ -10818,126 +10960,12 @@ async function printBanner() {
10818
10960
  up(BANNER_LINE_COUNT);
10819
10961
  printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}\x1B[K`);
10820
10962
  } finally {
10821
- process.stdout.write("\x1B[?25h");
10963
+ outb("\x1B[?25h");
10822
10964
  }
10823
10965
  }
10824
10966
 
10825
- // src/commands/internal/cli-ui.ts
10826
- var import_picocolors2 = __toESM(require_picocolors(), 1);
10827
- var bar = import_picocolors2.default.cyan("│");
10828
- var dot = import_picocolors2.default.green("●");
10829
- function writeLine(msg) {
10830
- process.stdout.write(`${msg}
10831
- `);
10832
- }
10833
- function barLine(msg) {
10834
- process.stdout.write(`${bar} ${msg}
10835
- `);
10836
- }
10837
- function barBlank() {
10838
- process.stdout.write(`${bar}
10839
- `);
10840
- }
10841
- function close(msg, isError = false, isWarning = false) {
10842
- if (isError) {
10843
- process.stdout.write(`${import_picocolors2.default.cyan("└")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
10844
- `);
10845
- } else if (isWarning) {
10846
- process.stdout.write(`${import_picocolors2.default.cyan("└")} ${import_picocolors2.default.yellow(msg)}
10847
- `);
10848
- } else {
10849
- process.stdout.write(`${import_picocolors2.default.cyan("└")} ${msg}
10850
- `);
10851
- }
10852
- }
10853
- function makeStepFn(isTTY) {
10854
- return function createStep(emoji, label) {
10855
- if (!isTTY)
10856
- return null;
10857
- const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
10858
- let i = 0;
10859
- process.stdout.write(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}…
10860
- `);
10861
- const timer = setInterval(() => {
10862
- i = (i + 1) % frames.length;
10863
- process.stdout.write(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}…
10864
- `);
10865
- }, 80);
10866
- return {
10867
- stop(result, details) {
10868
- clearInterval(timer);
10869
- process.stdout.write("\x1B[1A\x1B[2K");
10870
- process.stdout.write(`${dot} ${emoji} ${label}
10871
- `);
10872
- if (result !== undefined)
10873
- barLine(result);
10874
- if (details)
10875
- for (const d of details)
10876
- barLine(` · ${d}`);
10877
- barBlank();
10878
- }
10879
- };
10880
- };
10881
- }
10882
- async function askYesNo(question) {
10883
- process.stdout.write(`${import_picocolors2.default.cyan("◆")} ${question}
10884
- `);
10885
- process.stdout.write("\x1B[?25l");
10886
- function renderOptions(yes) {
10887
- const yesLabel = yes ? `${import_picocolors2.default.bold(import_picocolors2.default.green("●"))} Yes` : `${import_picocolors2.default.dim("○")} Yes`;
10888
- const noLabel = yes ? `${import_picocolors2.default.dim("○")} No` : `${import_picocolors2.default.bold(import_picocolors2.default.green("●"))} No`;
10889
- process.stdout.write(`\x1B[2K${bar} ${yesLabel} / ${noLabel}\r`);
10890
- }
10891
- const answer = await new Promise((resolve) => {
10892
- let selected = true;
10893
- renderOptions(selected);
10894
- const { stdin } = process;
10895
- const wasRaw = stdin.isTTY ? stdin.isRaw : false;
10896
- if (stdin.isTTY)
10897
- stdin.setRawMode(true);
10898
- stdin.resume();
10899
- function onData(buf) {
10900
- const key = buf.toString();
10901
- if (key === "\x03") {
10902
- stdin.removeListener("data", onData);
10903
- if (stdin.isTTY)
10904
- stdin.setRawMode(wasRaw);
10905
- stdin.pause();
10906
- resolve(null);
10907
- } else if (key === "\r" || key === `
10908
- `) {
10909
- stdin.removeListener("data", onData);
10910
- if (stdin.isTTY)
10911
- stdin.setRawMode(wasRaw);
10912
- stdin.pause();
10913
- resolve(selected);
10914
- } else if (key === "y" || key === "Y") {
10915
- stdin.removeListener("data", onData);
10916
- if (stdin.isTTY)
10917
- stdin.setRawMode(wasRaw);
10918
- stdin.pause();
10919
- resolve(true);
10920
- } else if (key === "n" || key === "N") {
10921
- stdin.removeListener("data", onData);
10922
- if (stdin.isTTY)
10923
- stdin.setRawMode(wasRaw);
10924
- stdin.pause();
10925
- resolve(false);
10926
- } else if (key === "\x1B[C" || key === "\x1B[D" || key === "\t") {
10927
- selected = !selected;
10928
- renderOptions(selected);
10929
- }
10930
- }
10931
- stdin.on("data", onData);
10932
- });
10933
- process.stdout.write(`
10934
- `);
10935
- process.stdout.write("\x1B[?25h");
10936
- process.stdout.write("\x1B[1A\x1B[2K");
10937
- return answer;
10938
- }
10939
-
10940
10967
  // src/commands/doctor.ts
10968
+ init_cli_ui();
10941
10969
  async function runDoctor(opts = {}) {
10942
10970
  const vaultDir = opts.vaultDir ?? process.cwd();
10943
10971
  const isTTY = opts.isTTY ?? process.stdout.isTTY ?? false;
@@ -11274,11 +11302,12 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11274
11302
  }
11275
11303
 
11276
11304
  // src/commands/init.ts
11277
- var import_picocolors6 = __toESM(require_picocolors(), 1);
11305
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
11278
11306
  var import_yaml4 = __toESM(require_dist(), 1);
11279
11307
  import { mkdir as mkdir3, readFile as readFile3, readdir as readdir2, rename as rename3, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
11280
11308
  import { homedir as homedir3 } from "node:os";
11281
11309
  import { dirname as dirname3, join as join6 } from "node:path";
11310
+ init_cli_ui();
11282
11311
  var binaryVersion = resolveBinaryVersion();
11283
11312
  var STANDARD_FOLDERS = [
11284
11313
  "00-inbox",
@@ -11348,7 +11377,7 @@ async function downloadPluginFiles(vaultDir, vaultSyncFn) {
11348
11377
  return driftWarning !== undefined ? { skipped: true, driftWarning } : { skipped: true };
11349
11378
  }
11350
11379
  try {
11351
- await vaultSyncFn(vaultDir, { includeObsidian: true });
11380
+ await vaultSyncFn(vaultDir, { includeObsidian: true, embedded: true });
11352
11381
  } catch (err) {
11353
11382
  const msg = err instanceof Error ? err.message : String(err);
11354
11383
  process.stderr.write(`init: vault-sync warning: ${msg}
@@ -11578,22 +11607,17 @@ async function runInit(opts = {}) {
11578
11607
  const createStep = makeStepFn(isTTY);
11579
11608
  const delay = opts.delayFn ?? ((ms) => new Promise((r2) => setTimeout(r2, ms)));
11580
11609
  const randDelay = () => isTTY ? delay(Math.floor(Math.random() * 1000) + 1000) : Promise.resolve();
11610
+ const _confirmFn = opts.confirmFn ?? askYesNo;
11581
11611
  const vaultYmlPath = join6(vaultDir, "vault.yml");
11582
11612
  const vaultYmlExists = await pathExists2(vaultYmlPath);
11583
- if (vaultYmlExists && !force) {
11584
- if (!isTTY) {
11585
- const msg = "vault.yml exists. Re-run with --force to overwrite.";
11586
- process.stdout.write(`${msg}
11587
- `);
11588
- result.message = msg;
11589
- result.exitCode = 1;
11590
- return result;
11591
- }
11592
- if (isTTY) {
11593
- await printBanner();
11594
- const answer = await askYesNo("vault.yml already exists. Overwrite?");
11595
- if (answer === null || answer === false) {
11596
- barLine(import_picocolors6.default.dim("No"));
11613
+ if (isTTY) {
11614
+ await printBanner();
11615
+ if (!force) {
11616
+ barLine(`${import_picocolors7.default.dim("vault root")} ${import_picocolors7.default.cyan(vaultDir)}`);
11617
+ barBlank();
11618
+ const proceed = await _confirmFn("Initialize OneBrain vault here?");
11619
+ if (proceed === null || proceed === false) {
11620
+ barLine(import_picocolors7.default.dim("No"));
11597
11621
  barBlank();
11598
11622
  close("Aborted");
11599
11623
  result.ok = true;
@@ -11602,18 +11626,36 @@ async function runInit(opts = {}) {
11602
11626
  }
11603
11627
  barLine("Yes");
11604
11628
  barBlank();
11629
+ if (vaultYmlExists) {
11630
+ const overwrite = await _confirmFn("vault.yml already exists. Overwrite?");
11631
+ if (overwrite === null || overwrite === false) {
11632
+ barLine(import_picocolors7.default.dim("No"));
11633
+ barBlank();
11634
+ close("Aborted");
11635
+ result.ok = true;
11636
+ result.exitCode = 0;
11637
+ return result;
11638
+ }
11639
+ barLine("Yes");
11640
+ barBlank();
11641
+ }
11642
+ }
11643
+ } else {
11644
+ if (vaultYmlExists && !force) {
11645
+ const msg = "vault.yml exists. Re-run with --force to overwrite.";
11646
+ process.stdout.write(`${msg}
11647
+ `);
11648
+ result.message = msg;
11649
+ result.exitCode = 1;
11650
+ return result;
11605
11651
  }
11606
- } else if (isTTY) {
11607
- await printBanner();
11608
- }
11609
- if (!isTTY) {
11610
11652
  writeLine("OneBrain Init");
11611
11653
  }
11612
11654
  const sp2 = createStep("\uD83D\uDCCB", "vault.yml");
11613
11655
  await writeVaultYml(vaultDir);
11614
11656
  if (sp2) {
11615
11657
  await randDelay();
11616
- sp2.stop(import_picocolors6.default.dim("written"), ["update_channel: stable", "checkpoint: 15 msgs · 30 min"]);
11658
+ sp2.stop(import_picocolors7.default.dim("written"), ["update_channel: stable", "checkpoint: 15 msgs · 30 min"]);
11617
11659
  } else {
11618
11660
  writeLine("vault.yml: written");
11619
11661
  }
@@ -11626,7 +11668,9 @@ async function runInit(opts = {}) {
11626
11668
  } else {
11627
11669
  writeLine(`folders: ${foldersCreated} created`);
11628
11670
  }
11629
- const sp4 = createStep("\uD83D\uDCE6", "Plugin files");
11671
+ const pluginJsonPath = join6(vaultDir, ".claude", "plugins", "onebrain", ".claude-plugin", "plugin.json");
11672
+ const pluginFilesExist = await pathExists2(pluginJsonPath);
11673
+ const sp4 = pluginFilesExist ? createStep("\uD83D\uDCE6", "Plugin files") : null;
11630
11674
  const {
11631
11675
  skipped: pluginSkipped,
11632
11676
  failed: pluginDownloadFailed
@@ -11637,7 +11681,15 @@ async function runInit(opts = {}) {
11637
11681
  sp4.stop("download failed");
11638
11682
  } else {
11639
11683
  const { skills, agents } = await countPluginContents(vaultDir);
11640
- sp4.stop(import_picocolors6.default.dim(pluginSkipped ? "already installed" : "downloaded"), [`${skills} skills · ${agents} agents`]);
11684
+ sp4.stop(import_picocolors7.default.dim("already installed"), [`${skills} skills · ${agents} agents`]);
11685
+ }
11686
+ } else if (isTTY) {
11687
+ if (!pluginDownloadFailed) {
11688
+ const { skills, agents } = await countPluginContents(vaultDir);
11689
+ dotLine("\uD83D\uDCE6", "Plugin files");
11690
+ barLine(import_picocolors7.default.dim("downloaded"));
11691
+ barLine(` · ${skills} skills · ${agents} agents`);
11692
+ barBlank();
11641
11693
  }
11642
11694
  } else {
11643
11695
  if (pluginSkipped)
@@ -11669,7 +11721,7 @@ async function runInit(opts = {}) {
11669
11721
  ...pluginResult.installed,
11670
11722
  ...pluginResult.failed.map((f2) => `${f2.id} (skipped)`)
11671
11723
  ];
11672
- sp4b.stop(import_picocolors6.default.dim(n > 0 ? `${n} installed` : "none"), details.length > 0 ? details : undefined);
11724
+ sp4b.stop(import_picocolors7.default.dim(n > 0 ? `${n} installed` : "none"), details.length > 0 ? details : undefined);
11673
11725
  } else {
11674
11726
  if (pluginResult.installed.length > 0)
11675
11727
  writeLine(`plugins: ${pluginResult.installed.join(", ")} installed`);
@@ -11681,7 +11733,7 @@ async function runInit(opts = {}) {
11681
11733
  result.pluginRegistrationSkipped = pluginRegistrationSkipped;
11682
11734
  if (sp5) {
11683
11735
  await randDelay();
11684
- sp5.stop(import_picocolors6.default.dim(pluginRegistrationSkipped ? "skipped" : "registered"), [`source: ${pluginRegistrationSkipped ? "marketplace" : "local"}`]);
11736
+ sp5.stop(import_picocolors7.default.dim(pluginRegistrationSkipped ? "skipped" : "registered"), [`source: ${pluginRegistrationSkipped ? "marketplace" : "local"}`]);
11685
11737
  } else {
11686
11738
  writeLine(`plugin: ${pluginRegistrationSkipped ? "skipped (marketplace)" : "registered"}`);
11687
11739
  }
@@ -11704,13 +11756,13 @@ async function runInit(opts = {}) {
11704
11756
  result.ok = true;
11705
11757
  result.exitCode = 0;
11706
11758
  if (isTTY) {
11707
- barLine(import_picocolors6.default.dim(`─── Next steps ${"─".repeat(25)}`));
11759
+ barLine(import_picocolors7.default.dim(`─── Next steps ${"─".repeat(25)}`));
11708
11760
  barBlank();
11709
- barLine(` ${import_picocolors6.default.bold(import_picocolors6.default.cyan("1"))} \uD83D\uDCC1 Open Obsidian → open this folder as vault`);
11710
- barLine(` ${import_picocolors6.default.bold(import_picocolors6.default.cyan("2"))} \uD83E\uDD16 Run ${import_picocolors6.default.cyan("claude")}`);
11711
- barLine(` ${import_picocolors6.default.bold(import_picocolors6.default.cyan("3"))} \uD83E\uDDE0 Type ${import_picocolors6.default.cyan("/onboarding")} to personalize`);
11761
+ barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("1"))} \uD83D\uDCC1 Open Obsidian → open this folder as vault`);
11762
+ barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("2"))} \uD83E\uDD16 Run ${import_picocolors7.default.cyan("claude")}`);
11763
+ barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("3"))} \uD83E\uDDE0 Type ${import_picocolors7.default.cyan("/onboarding")} to personalize`);
11712
11764
  barBlank();
11713
- close(`✨ ${import_picocolors6.default.bold("Ready")} — ${import_picocolors6.default.cyan("/onboarding")}`);
11765
+ close(`✨ ${import_picocolors7.default.bold("Ready")} — ${import_picocolors7.default.cyan("/onboarding")}`);
11714
11766
  } else {
11715
11767
  writeLine("done: run /onboarding in Claude to finish setup");
11716
11768
  }
@@ -12158,7 +12210,7 @@ async function qmdReindexCommand(vaultRoot) {
12158
12210
  init_dist2();
12159
12211
  init_lib();
12160
12212
  init_harness();
12161
- var import_picocolors7 = __toESM(require_picocolors(), 1);
12213
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
12162
12214
  import { mkdir as mkdir4, readFile as readFile6, rename as rename4, writeFile as writeFile5 } from "node:fs/promises";
12163
12215
  import { homedir as homedir4 } from "node:os";
12164
12216
  import { dirname as dirname4, join as join10 } from "node:path";
@@ -12366,11 +12418,11 @@ async function runRegisterHooks2(opts = {}) {
12366
12418
  if (isTTY) {
12367
12419
  const parts = HOOK_EVENTS2.map((e2) => {
12368
12420
  const status = result.hooks[e2];
12369
- const icon = import_picocolors7.default.green(status === "ok" ? "✓" : status === "migrated" ? "↑" : "+");
12370
- return `${import_picocolors7.default.dim(e2)} ${icon}`;
12421
+ const icon = import_picocolors8.default.green(status === "ok" ? "✓" : status === "migrated" ? "↑" : "+");
12422
+ return `${import_picocolors8.default.dim(e2)} ${icon}`;
12371
12423
  });
12372
12424
  if (qmdStatus)
12373
- parts.push(`${import_picocolors7.default.dim("PostToolUse")} ${import_picocolors7.default.green(qmdStatus === "ok" ? "✓" : "+")}`);
12425
+ parts.push(`${import_picocolors8.default.dim("PostToolUse")} ${import_picocolors8.default.green(qmdStatus === "ok" ? "✓" : "+")}`);
12374
12426
  hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
12375
12427
  } else {
12376
12428
  const hookLine = HOOK_EVENTS2.map((e2) => {
@@ -12509,10 +12561,10 @@ async function resolveSessionToken(tmpDir = osTmpdir2()) {
12509
12561
  if (timerId !== undefined)
12510
12562
  clearTimeout(timerId);
12511
12563
  if (race !== "timeout") {
12512
- const out = (await new Response(ps.stdout).text()).replace(/\D/g, "").trim();
12513
- if (out && Number(out) > 1) {
12514
- await Bun.write(cacheFile, out);
12515
- return out;
12564
+ const out2 = (await new Response(ps.stdout).text()).replace(/\D/g, "").trim();
12565
+ if (out2 && Number(out2) > 1) {
12566
+ await Bun.write(cacheFile, out2);
12567
+ return out2;
12516
12568
  }
12517
12569
  } else {
12518
12570
  ps.kill();
@@ -12592,7 +12644,9 @@ async function sessionInitCommand(vaultRoot) {
12592
12644
 
12593
12645
  // src/commands/internal/vault-sync.ts
12594
12646
  init_dist2();
12647
+ init_cli_ui();
12595
12648
  init_harness();
12649
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
12596
12650
  var import_yaml7 = __toESM(require_dist(), 1);
12597
12651
  import {
12598
12652
  mkdir as mkdir5,
@@ -12936,35 +12990,47 @@ async function runVaultSync2(vaultRoot, opts = {}) {
12936
12990
  pinSkipped: true,
12937
12991
  cacheRemoved: 0
12938
12992
  };
12993
+ const embedded = opts.embedded ?? false;
12994
+ const createEmbeddedStep = embedded ? makeStepFn(true) : null;
12939
12995
  let s = null;
12940
- function startSpinner(msg) {
12996
+ let currentStep = null;
12997
+ function startSpinner(emoji, label) {
12941
12998
  if (isTTY) {
12942
- s = L2();
12943
- s.start(msg);
12999
+ if (embedded) {
13000
+ currentStep = createEmbeddedStep(emoji, label);
13001
+ } else {
13002
+ s = L2();
13003
+ s.start(label);
13004
+ }
12944
13005
  } else {
12945
- process.stdout.write(`vault-sync: ${msg}
13006
+ process.stdout.write(`vault-sync: ${label}
12946
13007
  `);
12947
13008
  }
12948
13009
  }
12949
- function stopSpinner(msg) {
12950
- if (isTTY && s) {
12951
- s.stop(msg);
12952
- s = null;
13010
+ function stopSpinner(result2, details) {
13011
+ if (isTTY) {
13012
+ if (embedded) {
13013
+ currentStep?.stop(import_picocolors9.default.dim(result2), details);
13014
+ currentStep = null;
13015
+ } else if (s) {
13016
+ s.stop(result2);
13017
+ s = null;
13018
+ }
12953
13019
  }
12954
13020
  }
12955
- if (isTTY) {
13021
+ if (isTTY && !embedded) {
12956
13022
  we("OneBrain Vault Sync");
12957
13023
  }
12958
13024
  let tmpDir = null;
12959
13025
  try {
12960
- startSpinner("Downloading tarball...");
13026
+ startSpinner("\uD83D\uDCE5", "Downloading");
12961
13027
  let extractedDir;
12962
13028
  try {
12963
13029
  const dl = await downloadTarball2(branch, fetchFn);
12964
13030
  tmpDir = dl.tmpDir;
12965
13031
  extractedDir = await extractTarball2(dl.tarball, tmpDir);
12966
13032
  } catch (err) {
12967
- stopSpinner("Download failed");
13033
+ stopSpinner("download failed");
12968
13034
  const msg = err instanceof Error ? err.message : String(err);
12969
13035
  result.error = msg;
12970
13036
  process.stderr.write(`vault-sync: download failed: ${msg}
@@ -12979,13 +13045,13 @@ async function runVaultSync2(vaultRoot, opts = {}) {
12979
13045
  }
12980
13046
  } catch {}
12981
13047
  stopSpinner(`kengio/onebrain@${branch} (v${result.version})`);
12982
- startSpinner("Syncing plugin files...");
13048
+ startSpinner("\uD83D\uDCC2", "Syncing files");
12983
13049
  try {
12984
13050
  const { filesAdded, filesRemoved } = await syncPluginFiles2(extractedDir, vaultRoot, unlinkFn);
12985
13051
  result.filesAdded = filesAdded;
12986
13052
  result.filesRemoved = filesRemoved;
12987
13053
  } catch (err) {
12988
- stopSpinner("Plugin sync failed");
13054
+ stopSpinner("plugin sync failed");
12989
13055
  const msg = err instanceof Error ? err.message : String(err);
12990
13056
  result.error = msg;
12991
13057
  process.stderr.write(`vault-sync: plugin sync failed: ${msg}
@@ -13008,13 +13074,13 @@ async function runVaultSync2(vaultRoot, opts = {}) {
13008
13074
  } catch {}
13009
13075
  }
13010
13076
  await copyRootDocs2(extractedDir, vaultRoot);
13011
- startSpinner("Updating harness files...");
13077
+ startSpinner("\uD83D\uDD27", "Updating harness");
13012
13078
  let importsAdded = 0;
13013
13079
  try {
13014
13080
  importsAdded = await mergeHarnessFiles2(extractedDir, vaultRoot);
13015
13081
  result.importsAdded = importsAdded;
13016
13082
  } catch (err) {
13017
- stopSpinner("Harness merge failed");
13083
+ stopSpinner("harness merge failed");
13018
13084
  const msg = err instanceof Error ? err.message : String(err);
13019
13085
  result.error = msg;
13020
13086
  process.stderr.write(`vault-sync: harness merge failed: ${msg}
@@ -13036,7 +13102,7 @@ async function runVaultSync2(vaultRoot, opts = {}) {
13036
13102
  return result;
13037
13103
  }
13038
13104
  if (harness === "claude") {
13039
- startSpinner("Pinning to vault...");
13105
+ startSpinner("\uD83D\uDCCC", "Pinning to vault");
13040
13106
  try {
13041
13107
  const pinResult = await pinToVault2(vaultRoot, installedPluginsPath, installedPluginsCacheDir);
13042
13108
  result.pinSkipped = pinResult.skipped;
@@ -13052,7 +13118,7 @@ async function runVaultSync2(vaultRoot, opts = {}) {
13052
13118
  result.pinSkipped = true;
13053
13119
  stopSpinner("pin skipped (error — non-fatal)");
13054
13120
  }
13055
- startSpinner("Cleaning cache...");
13121
+ startSpinner("\uD83E\uDDF9", "Cleaning cache");
13056
13122
  try {
13057
13123
  const cacheRemoved = await cleanPluginCache2(installedPluginsPath, installedPluginsCacheDir);
13058
13124
  result.cacheRemoved = cacheRemoved;
@@ -13070,7 +13136,9 @@ async function runVaultSync2(vaultRoot, opts = {}) {
13070
13136
  }
13071
13137
  result.ok = true;
13072
13138
  if (isTTY) {
13073
- fe(`Done — v${result.version} synced`);
13139
+ if (!embedded) {
13140
+ fe(`Done — v${result.version} synced`);
13141
+ }
13074
13142
  } else {
13075
13143
  process.stdout.write(`vault-sync: done
13076
13144
  `);
@@ -13090,9 +13158,8 @@ async function vaultSyncCommand2(vaultRoot, opts = {}) {
13090
13158
  }
13091
13159
 
13092
13160
  // src/commands/update.ts
13093
- var import_picocolors8 = __toESM(require_picocolors(), 1);
13094
- import { access } from "node:fs/promises";
13095
- import { join as join13 } from "node:path";
13161
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
13162
+ init_cli_ui();
13096
13163
  var GITHUB_REPO = "https://api.github.com/repos/kengio/onebrain";
13097
13164
  var GITHUB_RELEASES_URL = `${GITHUB_REPO}/releases/latest`;
13098
13165
  async function fetchLatestRelease(fetchFn) {
@@ -13113,14 +13180,6 @@ async function fetchLatestRelease(fetchFn) {
13113
13180
  function formatReleaseDate(date) {
13114
13181
  return date.toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" });
13115
13182
  }
13116
- function daysBehind(date) {
13117
- const days = Math.floor((Date.now() - date.getTime()) / (1000 * 60 * 60 * 24));
13118
- if (days <= 0)
13119
- return "just released";
13120
- if (days === 1)
13121
- return "1 day behind";
13122
- return `${days} days behind`;
13123
- }
13124
13183
  var _windowsShell;
13125
13184
  function windowsShell() {
13126
13185
  if (_windowsShell !== undefined)
@@ -13178,7 +13237,6 @@ async function defaultCurrentVersion() {
13178
13237
  }
13179
13238
  }
13180
13239
  async function runUpdate(opts = {}) {
13181
- const vaultDir = opts.vaultDir ?? process.cwd();
13182
13240
  const isTTY = opts.isTTY ?? process.stdout.isTTY ?? false;
13183
13241
  const check = opts.check ?? false;
13184
13242
  const fetchFn = opts.fetchFn ?? globalThis.fetch;
@@ -13187,35 +13245,19 @@ async function runUpdate(opts = {}) {
13187
13245
  const currentVersionFn = opts.currentVersionFn ?? defaultCurrentVersion;
13188
13246
  const result = { ok: false, exitCode: 0 };
13189
13247
  const createStep = makeStepFn(isTTY);
13190
- const delay = opts.delayFn ?? ((ms) => new Promise((r2) => setTimeout(r2, ms)));
13191
- const randDelay = () => isTTY ? delay(Math.floor(Math.random() * 1000) + 1000) : Promise.resolve();
13192
13248
  if (isTTY) {
13193
13249
  await printBanner();
13194
13250
  } else {
13195
13251
  writeLine("OneBrain Update");
13196
13252
  }
13197
- try {
13198
- await access(join13(vaultDir, "vault.yml"));
13199
- } catch {
13200
- const msg = `vault.yml not found in ${vaultDir}. Run 'onebrain update' from inside an OneBrain vault.`;
13201
- if (isTTY) {
13202
- close(msg, true);
13203
- } else {
13204
- writeLine(`error: ${msg}`);
13205
- }
13206
- result.error = msg;
13207
- result.exitCode = 1;
13208
- return result;
13209
- }
13210
13253
  const sp1 = createStep("\uD83D\uDD0D", "Local version");
13211
13254
  const { version: currentVersion, publishedAt: localPublishedAt } = await currentVersionFn();
13212
13255
  result.currentVersion = currentVersion;
13213
- await randDelay();
13214
- const localVersionLabel = localPublishedAt ? `${import_picocolors8.default.dim(currentVersion)} ${import_picocolors8.default.dim("·")} ${import_picocolors8.default.dim(formatReleaseDate(localPublishedAt))}` : import_picocolors8.default.dim(currentVersion);
13256
+ const localVersionLabel = localPublishedAt ? `${import_picocolors10.default.dim(currentVersion)} ${import_picocolors10.default.dim("·")} ${import_picocolors10.default.dim(formatReleaseDate(localPublishedAt))}` : import_picocolors10.default.dim(currentVersion);
13215
13257
  if (sp1)
13216
13258
  sp1.stop(localVersionLabel);
13217
13259
  else
13218
- writeLine(`current: ${currentVersion}${localPublishedAt ? ` (${formatReleaseDate(localPublishedAt)})` : ""}`);
13260
+ writeLine(`current: ${currentVersion}`);
13219
13261
  const sp2 = createStep("\uD83C\uDF10", "Remote version");
13220
13262
  let latestVersion;
13221
13263
  let publishedAt = null;
@@ -13223,14 +13265,11 @@ async function runUpdate(opts = {}) {
13223
13265
  const release = await fetchLatestRelease(fetchFn);
13224
13266
  latestVersion = release.version;
13225
13267
  publishedAt = release.publishedAt;
13226
- await randDelay();
13227
- const isOutdated = latestVersion !== currentVersion;
13228
- const behindSuffix = isOutdated && publishedAt ? ` ${import_picocolors8.default.dim("·")} ${import_picocolors8.default.dim(daysBehind(publishedAt))}` : "";
13229
- const dateSuffix = publishedAt ? ` ${import_picocolors8.default.dim("·")} ${import_picocolors8.default.dim(formatReleaseDate(publishedAt))}${behindSuffix}` : "";
13268
+ const dateSuffix = publishedAt ? ` ${import_picocolors10.default.dim("·")} ${import_picocolors10.default.dim(formatReleaseDate(publishedAt))}` : "";
13230
13269
  if (sp2)
13231
- sp2.stop(`${import_picocolors8.default.green(latestVersion)}${dateSuffix}`);
13270
+ sp2.stop(`${import_picocolors10.default.green(latestVersion)}${dateSuffix}`);
13232
13271
  else
13233
- writeLine(`latest: ${latestVersion}${isOutdated && publishedAt ? ` (${daysBehind(publishedAt)})` : ""}`);
13272
+ writeLine(`latest: ${latestVersion}`);
13234
13273
  } catch (err) {
13235
13274
  const msg = err instanceof Error ? err.message : String(err);
13236
13275
  if (sp2)
@@ -13249,7 +13288,7 @@ async function runUpdate(opts = {}) {
13249
13288
  if (check) {
13250
13289
  if (isTTY) {
13251
13290
  if (currentVersion !== latestVersion) {
13252
- barLine(`⬆️ ${import_picocolors8.default.dim(currentVersion)} → ${import_picocolors8.default.green(latestVersion)} · binary would upgrade`);
13291
+ barLine(`⬆️ ${import_picocolors10.default.dim(currentVersion)} → ${import_picocolors10.default.green(latestVersion)} · binary would upgrade`);
13253
13292
  barBlank();
13254
13293
  }
13255
13294
  close("Dry run complete — no changes made");
@@ -13262,11 +13301,9 @@ async function runUpdate(opts = {}) {
13262
13301
  }
13263
13302
  if (latestVersion === currentVersion) {
13264
13303
  if (isTTY) {
13265
- const dateSuffix = publishedAt ? ` · ${formatReleaseDate(publishedAt)}` : "";
13266
- close(`Already up to date — @onebrain-ai/cli ${import_picocolors8.default.dim(latestVersion)}${import_picocolors8.default.dim(dateSuffix)}`);
13304
+ close(`Already up to date @onebrain-ai/cli ${import_picocolors10.default.dim(latestVersion)}`);
13267
13305
  } else {
13268
- const dateSuffix = publishedAt ? ` (${formatReleaseDate(publishedAt)})` : "";
13269
- writeLine(`already up to date: @onebrain-ai/cli ${latestVersion}${dateSuffix}`);
13306
+ writeLine(`already up to date: @onebrain-ai/cli ${latestVersion}`);
13270
13307
  writeLine("done: nothing to do");
13271
13308
  }
13272
13309
  result.ok = true;
@@ -13274,15 +13311,14 @@ async function runUpdate(opts = {}) {
13274
13311
  return result;
13275
13312
  }
13276
13313
  if (isTTY) {
13277
- barLine(`⬆️ ${import_picocolors8.default.dim(currentVersion)} → ${import_picocolors8.default.green(latestVersion)}`);
13314
+ barLine(`⬆️ ${import_picocolors10.default.dim(currentVersion)} → ${import_picocolors10.default.green(latestVersion)}`);
13278
13315
  barBlank();
13279
13316
  }
13280
13317
  const sp3 = createStep("\uD83D\uDCE6", "Installing @onebrain-ai/cli");
13281
13318
  try {
13282
13319
  await installBinaryFn(latestVersion);
13283
- await randDelay();
13284
13320
  if (sp3)
13285
- sp3.stop(import_picocolors8.default.green(latestVersion));
13321
+ sp3.stop(import_picocolors10.default.green(latestVersion));
13286
13322
  else
13287
13323
  writeLine(`upgrading: @onebrain-ai/cli ${latestVersion} installed`);
13288
13324
  } catch (err) {
@@ -13301,7 +13337,6 @@ async function runUpdate(opts = {}) {
13301
13337
  }
13302
13338
  const sp4 = createStep("✅", "Validating binary");
13303
13339
  const binaryValid = await validateBinaryFn();
13304
- await randDelay();
13305
13340
  if (!binaryValid) {
13306
13341
  if (sp4)
13307
13342
  sp4.stop("failed");
@@ -13320,7 +13355,7 @@ async function runUpdate(opts = {}) {
13320
13355
  result.ok = true;
13321
13356
  result.exitCode = 0;
13322
13357
  if (isTTY) {
13323
- close(`Done — run ${import_picocolors8.default.cyan("/update")} in Claude to sync vault files`);
13358
+ close(`Done — run ${import_picocolors10.default.cyan("/update")} in Claude to sync vault files`);
13324
13359
  } else {
13325
13360
  writeLine("done: run /update in Claude to sync vault files");
13326
13361
  }
@@ -13333,11 +13368,24 @@ async function updateCommand(opts = {}) {
13333
13368
  }
13334
13369
  }
13335
13370
 
13371
+ // src/lib/patch-utf8.ts
13372
+ function patchUtf8(stream) {
13373
+ const orig = stream.write.bind(stream);
13374
+ stream.write = (chunk, encodingOrCb, cb) => {
13375
+ const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
13376
+ if (typeof encodingOrCb === "function")
13377
+ return orig(buf, encodingOrCb);
13378
+ if (cb !== undefined)
13379
+ return orig(buf, cb);
13380
+ return orig(buf);
13381
+ };
13382
+ }
13383
+
13336
13384
  // src/index.ts
13337
- var VERSION = "2.1.0";
13385
+ var VERSION = "2.1.2";
13338
13386
  var RELEASE_DATE = "2026-04-28";
13339
- process.stdout.setDefaultEncoding("utf8");
13340
- process.stderr.setDefaultEncoding("utf8");
13387
+ patchUtf8(process.stdout);
13388
+ patchUtf8(process.stderr);
13341
13389
  var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
13342
13390
  if (process.argv.slice(2).length === 0) {
13343
13391
  console.log(VERSION_STRING);
@@ -13349,7 +13397,7 @@ function findVaultRoot(startDir) {
13349
13397
  return process.cwd();
13350
13398
  let dir = startDir;
13351
13399
  while (true) {
13352
- if (existsSync(join14(dir, "vault.yml")))
13400
+ if (existsSync(join13(dir, "vault.yml")))
13353
13401
  return dir;
13354
13402
  const parent = dirname6(dir);
13355
13403
  if (parent === dir)
@@ -13365,11 +13413,9 @@ program2.command("init").description("Initialize a new OneBrain vault").option("
13365
13413
  ...opts.force !== undefined ? { force: opts.force } : {}
13366
13414
  });
13367
13415
  });
13368
- program2.command("update").description("Update OneBrain plugin files from GitHub").option("--check", "show what would change and exit without making changes").option("--channel <channel>", "update channel: stable | next").option("--vault-dir <path>", "vault root directory (default: auto-detect from cwd)").action(async (opts) => {
13416
+ program2.command("update").description("Update @onebrain-ai/cli to the latest version").option("--check", "show what would change and exit without making changes").action(async (opts) => {
13369
13417
  await updateCommand({
13370
- vaultDir: opts.vaultDir ?? findVaultRoot(process.cwd()),
13371
- ...opts.check !== undefined ? { check: opts.check } : {},
13372
- ...opts.channel !== undefined ? { channel: opts.channel } : {}
13418
+ ...opts.check !== undefined ? { check: opts.check } : {}
13373
13419
  });
13374
13420
  });
13375
13421
  program2.command("doctor").description("Run vault health checks and report issues").option("--fix", "auto-fix detected issues").action(async (opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onebrain-ai/cli",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "CLI for OneBrain — personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
5
5
  "keywords": [
6
6
  "onebrain",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "files": ["dist/onebrain"],
30
30
  "scripts": {
31
- "build": "bun build src/index.ts --outfile dist/onebrain --target node",
31
+ "build": "bun build src/index.ts --outfile dist/onebrain --target bun",
32
32
  "test": "bun test --pass-with-no-tests src/",
33
33
  "typecheck": "tsc --noEmit"
34
34
  },