@onebrain-ai/cli 2.1.4 → 2.1.5

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 +345 -156
  2. package/package.json +1 -1
package/dist/onebrain CHANGED
@@ -9105,10 +9105,10 @@ async function checkQmdEmbeddings(config) {
9105
9105
  check: "qmd-embeddings",
9106
9106
  status: "warn",
9107
9107
  message: summary,
9108
- hint: "Run onebrain doctor --fix to reindex and embed",
9108
+ hint: "Advisory: run /qmd embed when ready (or onebrain doctor --fix)",
9109
9109
  details: [
9110
9110
  `collection: ${config.qmd_collection}`,
9111
- "Run onebrain doctor --fix to reindex and embed"
9111
+ "Advisory: run /qmd embed when ready (or onebrain doctor --fix)"
9112
9112
  ]
9113
9113
  };
9114
9114
  }
@@ -9140,20 +9140,7 @@ async function checkOrphanCheckpoints(vaultRoot, config) {
9140
9140
  message: "0 orphans"
9141
9141
  };
9142
9142
  }
9143
- if (checkpointFiles.length === 0) {
9144
- return {
9145
- check: "orphan-checkpoints",
9146
- status: "ok",
9147
- message: "0 orphans"
9148
- };
9149
- }
9150
- let orphanCount = 0;
9151
- for (const filePath of checkpointFiles) {
9152
- const merged = await readMergedField(filePath);
9153
- if (merged !== true) {
9154
- orphanCount++;
9155
- }
9156
- }
9143
+ const orphanCount = checkpointFiles.length;
9157
9144
  if (orphanCount === 0) {
9158
9145
  return {
9159
9146
  check: "orphan-checkpoints",
@@ -9169,30 +9156,6 @@ async function checkOrphanCheckpoints(vaultRoot, config) {
9169
9156
  details: ["Run /wrapup to synthesize and merge them"]
9170
9157
  };
9171
9158
  }
9172
- async function readMergedField(filePath) {
9173
- try {
9174
- const file = Bun.file(filePath);
9175
- const text = await file.text();
9176
- if (!text.startsWith("---"))
9177
- return;
9178
- const endIdx = text.indexOf(`
9179
- ---`, 3);
9180
- if (endIdx === -1)
9181
- return;
9182
- const frontmatter = text.slice(3, endIdx).trim();
9183
- const parsed = import_yaml2.parse(frontmatter);
9184
- if (!parsed)
9185
- return;
9186
- const merged = parsed["merged"];
9187
- if (merged === true || merged === "true")
9188
- return true;
9189
- if (merged === false || merged === "false")
9190
- return false;
9191
- return;
9192
- } catch {
9193
- return;
9194
- }
9195
- }
9196
9159
  async function checkPluginFiles(vaultRoot) {
9197
9160
  const pluginBase = join2(vaultRoot, ".claude", "plugins", "onebrain");
9198
9161
  const missingFiles = [];
@@ -9497,7 +9460,7 @@ var init_lib = __esm(() => {
9497
9460
  var require_package = __commonJS((exports, module) => {
9498
9461
  module.exports = {
9499
9462
  name: "@onebrain-ai/cli",
9500
- version: "2.1.4",
9463
+ version: "2.1.5",
9501
9464
  description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
9502
9465
  keywords: [
9503
9466
  "onebrain",
@@ -9562,6 +9525,10 @@ function barBlank() {
9562
9525
  out(`${bar}
9563
9526
  `);
9564
9527
  }
9528
+ function barOpen(msg) {
9529
+ out(`${import_picocolors2.default.cyan("\u250C")} ${msg}
9530
+ `);
9531
+ }
9565
9532
  function close(msg, isError = false, isWarning = false) {
9566
9533
  if (isError) {
9567
9534
  out(`${import_picocolors2.default.cyan("\u2514")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
@@ -10788,7 +10755,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
10788
10755
  var import_picocolors = __toESM(require_picocolors(), 1);
10789
10756
  function resolveBinaryVersion() {
10790
10757
  if (true)
10791
- return "2.1.4";
10758
+ return "2.1.5";
10792
10759
  try {
10793
10760
  const pkg = require_package();
10794
10761
  return pkg.version ?? "dev";
@@ -10797,43 +10764,52 @@ function resolveBinaryVersion() {
10797
10764
  }
10798
10765
  }
10799
10766
  var ART_LINES = [
10800
- ` \u25C6${"\u2500".repeat(25)}\u25C6`,
10801
- " \u250C\u2500\u2510\u250C\u2510\u2577\u250C\u2500\u2574\u250C\u2510 \u250C\u2500\u2510\u250C\u2500\u2510\u2577\u250C\u2510\u2577",
10802
- " \u2502 \u2502\u2502\u2514\u2524\u251C\u2574 \u251C\u2534\u2510\u251C\u252C\u2518\u251C\u2500\u2524\u2502\u2502\u2514\u2524",
10803
- " \u2514\u2500\u2518\u2575 \u2575\u2514\u2500\u2574\u2514\u2500\u2518\u2575\u2514\u2574\u2575 \u2575\u2575\u2575 \u2575",
10804
- ` \u25C6${"\u2500".repeat(25)}\u25C6`
10767
+ ` \u25C6${"\u2500".repeat(26)}\u25C6`,
10768
+ " \u250C\u2500\u2510\u250C\u2510\u2577\u250C\u2500\u2574\u250C\u2510 \u250C\u2500\u2510\u250C\u2500\u2510\u2577\u250C\u2510\u2577",
10769
+ " \u2502 \u2502\u2502\u2514\u2524\u251C\u2574 \u251C\u2534\u2510\u251C\u252C\u2518\u251C\u2500\u2524\u2502\u2502\u2514\u2524",
10770
+ " \u2514\u2500\u2518\u2575 \u2575\u2514\u2500\u2574\u2514\u2500\u2518\u2575\u2514\u2574\u2575 \u2575\u2575\u2575 \u2575",
10771
+ ` \u25C6${"\u2500".repeat(26)}\u25C6`
10805
10772
  ];
10806
- var TAGLINE = "Your AI Thinking Partner";
10773
+ var PREFIX = "Your AI ";
10774
+ var TAGLINE_LEAD = " ";
10775
+ var TAGLINE_FALLBACK = `${PREFIX}Thinking Partner`;
10807
10776
  var BANNER_LINE_COUNT = 1 + ART_LINES.length + 3;
10777
+ var PREFIX_COLOR = [120, 230, 255];
10778
+ var TRAILING_COLOR = [255, 80, 255];
10779
+ var FINAL_COLOR = [120, 230, 255];
10780
+ var SENTENCES = [
10781
+ { trailing: "Remembers You", trailingWords: ["Remembers", "You"], wordTicks: [24, 32] },
10782
+ { trailing: "Catches Insights", trailingWords: ["Catches", "Insights"], wordTicks: [27, 26] },
10783
+ { trailing: "Thinking Partner", trailingWords: ["Thinking", "Partner"], wordTicks: [26, 31] }
10784
+ ];
10808
10785
  function supportsRgb() {
10809
10786
  const c = process.env["COLORTERM"] ?? "";
10810
10787
  return c === "truecolor" || c === "24bit";
10811
10788
  }
10789
+ function rgb(r, g, b, ch) {
10790
+ return `\x1B[1;38;2;${r};${g};${b}m${ch}\x1B[0m`;
10791
+ }
10792
+ function rgbStr(c, ch) {
10793
+ return rgb(c[0], c[1], c[2], ch);
10794
+ }
10812
10795
  function hsvToRgb(h, floor = 80) {
10813
10796
  const c = 255;
10814
10797
  const x = Math.round(c * (1 - Math.abs(h / 60 % 2 - 1)));
10815
10798
  let r = 0;
10816
10799
  let g = 0;
10817
10800
  let b = 0;
10818
- if (h < 60) {
10819
- r = c;
10820
- g = x;
10821
- } else if (h < 120) {
10822
- r = x;
10823
- g = c;
10824
- } else if (h < 180) {
10825
- g = c;
10826
- b = x;
10827
- } else if (h < 240) {
10828
- g = x;
10829
- b = c;
10830
- } else if (h < 300) {
10831
- r = x;
10832
- b = c;
10833
- } else {
10834
- r = c;
10835
- b = x;
10836
- }
10801
+ if (h < 60)
10802
+ [r, g, b] = [c, x, 0];
10803
+ else if (h < 120)
10804
+ [r, g, b] = [x, c, 0];
10805
+ else if (h < 180)
10806
+ [r, g, b] = [0, c, x];
10807
+ else if (h < 240)
10808
+ [r, g, b] = [0, x, c];
10809
+ else if (h < 300)
10810
+ [r, g, b] = [x, 0, c];
10811
+ else
10812
+ [r, g, b] = [c, 0, x];
10837
10813
  return [Math.min(255, r + floor), Math.min(255, g + floor), Math.min(255, b + floor)];
10838
10814
  }
10839
10815
  var HUE_PER_CHAR = 10;
@@ -10844,15 +10820,25 @@ function neonLine(line, lineIndex = 0, floor = 80) {
10844
10820
  return ch;
10845
10821
  const hue = ((i * HUE_PER_CHAR - lineIndex * HUE_PER_ROW) % 360 + 360) % 360;
10846
10822
  const [r, g, b] = hsvToRgb(hue, floor);
10847
- return `\x1B[1;38;2;${r};${g};${b}m${ch}\x1B[0m`;
10823
+ return rgb(r, g, b, ch);
10848
10824
  }).join("");
10849
10825
  }
10850
- function scanLine(line) {
10851
- return line.split("").map((ch) => ch === " " ? ch : `\x1B[1;38;2;140;255;255m${ch}\x1B[0m`).join("");
10826
+ function whiteLine(line) {
10827
+ return line.split("").map((ch) => ch === " " ? ch : `\x1B[1;97m${ch}\x1B[0m`).join("");
10828
+ }
10829
+ function whiteGlowLine(line, alpha) {
10830
+ return line.split("").map((ch) => ch === " " ? ch : `\x1B[1;38;2;${alpha};${alpha};${alpha}m${ch}\x1B[0m`).join("");
10852
10831
  }
10853
10832
  function dimLine(line) {
10854
10833
  return line.split("").map((ch) => ch === " " ? ch : `\x1B[2;38;2;50;50;70m${ch}\x1B[0m`).join("");
10855
10834
  }
10835
+ function scanLineCh(line) {
10836
+ return line.split("").map((ch) => ch === " " ? ch : rgb(140, 255, 255, ch)).join("");
10837
+ }
10838
+ var CURSOR = rgb(140, 255, 255, "\u258C");
10839
+ var GLYPHS = "\u2593\u2591\u2592\u2588\u2502\u2524\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u256A\u256B\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u2518\u250C\u2551\u258C\u2580\u2584\u2590\u2206\u0192\u03A9\xA7\xB6\xB1\xF7\xD7\xF8\xA5\u20AC";
10840
+ var randGlyph = () => GLYPHS[Math.floor(Math.random() * GLYPHS.length)] ?? "?";
10841
+ var glitchWhite = (g) => `\x1B[1;97m${g}\x1B[0m`;
10856
10842
  function outb(str) {
10857
10843
  process.stdout.write(Buffer.from(str, "utf8"));
10858
10844
  }
@@ -10869,11 +10855,274 @@ function printFrame(artLines, tagline) {
10869
10855
  outb(`
10870
10856
  `);
10871
10857
  }
10858
+ function blankTagline() {
10859
+ return `${TAGLINE_LEAD}${" ".repeat(TAGLINE_FALLBACK.length)}`;
10860
+ }
10861
+ function buildTaglineLine(prefixLockedChars, trailingPart) {
10862
+ let s = TAGLINE_LEAD;
10863
+ for (let i = 0;i < PREFIX.length; i++) {
10864
+ if (i < prefixLockedChars) {
10865
+ s += PREFIX[i] === " " ? " " : rgbStr(PREFIX_COLOR, PREFIX[i]);
10866
+ } else {
10867
+ s += " ";
10868
+ }
10869
+ }
10870
+ s += trailingPart;
10871
+ return `${s}\x1B[K`;
10872
+ }
10873
+ var LOCK_LATENCY = 4;
10874
+ var PREFIX_TICK_MS = [27, 27];
10875
+ var INTER_WORD_PAUSE_MS = 65;
10876
+ var SENTENCE_HOLD_MS = 500;
10877
+ var WIPE_TICK_MS = 22;
10878
+ var WIPE_TRAIL = 3;
10879
+ var WIPE_PAUSE_MS = 80;
10880
+ async function playBannerIntro(rainbowArt, whiteArt) {
10881
+ const delay = (ms) => new Promise((r) => setTimeout(r, ms));
10882
+ const up = (n) => outb(`\x1B[${n}F`);
10883
+ printFrame(ART_LINES.map(dimLine), blankTagline());
10884
+ for (let scan = 0;scan < ART_LINES.length; scan++) {
10885
+ await delay(55);
10886
+ up(BANNER_LINE_COUNT);
10887
+ printFrame(ART_LINES.map((l, i) => {
10888
+ if (i < scan - 2)
10889
+ return whiteLine(l);
10890
+ if (i === scan - 2)
10891
+ return whiteGlowLine(l, 200);
10892
+ if (i === scan - 1)
10893
+ return whiteGlowLine(l, 230);
10894
+ if (i === scan)
10895
+ return scanLineCh(l);
10896
+ return dimLine(l);
10897
+ }), blankTagline());
10898
+ }
10899
+ await delay(40);
10900
+ up(BANNER_LINE_COUNT);
10901
+ printFrame(whiteArt, blankTagline());
10902
+ await delay(600);
10903
+ let minD = 0;
10904
+ let maxD = 0;
10905
+ for (let row = 0;row < ART_LINES.length; row++) {
10906
+ minD = Math.min(minD, -row * 3);
10907
+ maxD = Math.max(maxD, ART_LINES[row].length - 1 - row * 3);
10908
+ }
10909
+ function flowFrame(frontD) {
10910
+ return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
10911
+ if (ch === " ")
10912
+ return ch;
10913
+ const d = col - 3 * row;
10914
+ if (d <= frontD) {
10915
+ const hue = ((col * HUE_PER_CHAR - row * HUE_PER_ROW) % 360 + 360) % 360;
10916
+ const [r, g, b] = hsvToRgb(hue);
10917
+ return rgb(r, g, b, ch);
10918
+ }
10919
+ return `\x1B[1;97m${ch}\x1B[0m`;
10920
+ }).join(""));
10921
+ }
10922
+ for (let d = minD;d <= maxD; d++) {
10923
+ await delay(9);
10924
+ up(BANNER_LINE_COUNT);
10925
+ printFrame(flowFrame(d), blankTagline());
10926
+ }
10927
+ up(BANNER_LINE_COUNT);
10928
+ printFrame(rainbowArt, blankTagline());
10929
+ await delay(180);
10930
+ function shimmerArtFrame(highlight) {
10931
+ return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
10932
+ if (ch === " ")
10933
+ return ch;
10934
+ const d = col - 3 * row;
10935
+ if (Math.abs(d - highlight) <= 1)
10936
+ return `\x1B[1;97m${ch}\x1B[0m`;
10937
+ const hue = ((col * HUE_PER_CHAR - row * HUE_PER_ROW) % 360 + 360) % 360;
10938
+ const [r, g, b] = hsvToRgb(hue);
10939
+ return rgb(r, g, b, ch);
10940
+ }).join(""));
10941
+ }
10942
+ for (let d = minD;d <= maxD; d++) {
10943
+ await delay(9);
10944
+ up(BANNER_LINE_COUNT);
10945
+ printFrame(shimmerArtFrame(d), blankTagline());
10946
+ }
10947
+ up(BANNER_LINE_COUNT);
10948
+ printFrame(rainbowArt, blankTagline());
10949
+ await delay(80);
10950
+ }
10951
+ async function decodeFirstSentence(rainbowArt, s) {
10952
+ const delay = (ms) => new Promise((r) => setTimeout(r, ms));
10953
+ const up = (n) => outb(`\x1B[${n}F`);
10954
+ const prefixWords = ["Your", "AI"];
10955
+ for (let wi = 0;wi < prefixWords.length; wi++) {
10956
+ const w = prefixWords[wi];
10957
+ const tickMs = PREFIX_TICK_MS[wi];
10958
+ const totalTicks = w.length + LOCK_LATENCY;
10959
+ const baseIdx = prefixWords.slice(0, wi).reduce((a, x) => a + x.length + 1, 0);
10960
+ for (let t = 1;t <= totalTicks; t++) {
10961
+ await delay(tickMs);
10962
+ up(BANNER_LINE_COUNT);
10963
+ let prefixPart = TAGLINE_LEAD;
10964
+ for (let i = 0;i < PREFIX.length; i++) {
10965
+ if (i < baseIdx) {
10966
+ prefixPart += PREFIX[i] === " " ? " " : rgbStr(PREFIX_COLOR, PREFIX[i]);
10967
+ } else if (i >= baseIdx + w.length) {
10968
+ prefixPart += " ";
10969
+ } else {
10970
+ const localIdx = i - baseIdx;
10971
+ const age = t - localIdx;
10972
+ if (age > LOCK_LATENCY)
10973
+ prefixPart += rgbStr(PREFIX_COLOR, PREFIX[i]);
10974
+ else if (age > 0)
10975
+ prefixPart += glitchWhite(randGlyph());
10976
+ else if (age === 0 && t < w.length)
10977
+ prefixPart += CURSOR;
10978
+ else
10979
+ prefixPart += " ";
10980
+ }
10981
+ }
10982
+ const trailingBlank = " ".repeat(s.trailing.length);
10983
+ printFrame(rainbowArt, `${prefixPart}${trailingBlank}\x1B[K`);
10984
+ }
10985
+ if (wi < prefixWords.length - 1) {
10986
+ await delay(INTER_WORD_PAUSE_MS);
10987
+ }
10988
+ }
10989
+ await delay(INTER_WORD_PAUSE_MS);
10990
+ await decodeTrailing(rainbowArt, s, PREFIX.length);
10991
+ }
10992
+ async function decodeTrailing(rainbowArt, s, lockedPrefixChars) {
10993
+ const delay = (ms) => new Promise((r) => setTimeout(r, ms));
10994
+ const up = (n) => outb(`\x1B[${n}F`);
10995
+ const words = s.trailingWords;
10996
+ const ticks = s.wordTicks;
10997
+ const offsets = [];
10998
+ let off = 0;
10999
+ for (const w of words) {
11000
+ offsets.push(off);
11001
+ off += w.length + 1;
11002
+ }
11003
+ for (let wi = 0;wi < words.length; wi++) {
11004
+ const w = words[wi];
11005
+ const tickMs = ticks[wi];
11006
+ const totalTicks = w.length + LOCK_LATENCY;
11007
+ for (let t = 1;t <= totalTicks; t++) {
11008
+ await delay(tickMs);
11009
+ up(BANNER_LINE_COUNT);
11010
+ let trailing = "";
11011
+ for (let j = 0;j < s.trailing.length; j++) {
11012
+ const ch = s.trailing[j];
11013
+ if (ch === " ") {
11014
+ trailing += " ";
11015
+ continue;
11016
+ }
11017
+ let owningWi = -1;
11018
+ let localIdx = -1;
11019
+ for (let k = 0;k < words.length; k++) {
11020
+ const start = offsets[k];
11021
+ const end = start + words[k].length;
11022
+ if (j >= start && j < end) {
11023
+ owningWi = k;
11024
+ localIdx = j - start;
11025
+ break;
11026
+ }
11027
+ }
11028
+ if (owningWi < wi) {
11029
+ trailing += rgbStr(TRAILING_COLOR, ch);
11030
+ } else if (owningWi > wi) {
11031
+ trailing += " ";
11032
+ } else {
11033
+ const age = t - localIdx;
11034
+ if (age > LOCK_LATENCY)
11035
+ trailing += rgbStr(TRAILING_COLOR, ch);
11036
+ else if (age > 0)
11037
+ trailing += glitchWhite(randGlyph());
11038
+ else if (age === 0 && t < w.length)
11039
+ trailing += CURSOR;
11040
+ else
11041
+ trailing += " ";
11042
+ }
11043
+ }
11044
+ printFrame(rainbowArt, buildTaglineLine(lockedPrefixChars, trailing));
11045
+ }
11046
+ if (wi < words.length - 1) {
11047
+ await delay(INTER_WORD_PAUSE_MS);
11048
+ }
11049
+ }
11050
+ }
11051
+ async function wipeSwapTransition(rainbowArt, from, to) {
11052
+ const delay = (ms) => new Promise((r) => setTimeout(r, ms));
11053
+ const up = (n) => outb(`\x1B[${n}F`);
11054
+ for (let pos = from.trailing.length - 1;pos >= -WIPE_TRAIL; pos--) {
11055
+ await delay(WIPE_TICK_MS);
11056
+ up(BANNER_LINE_COUNT);
11057
+ let trailing = "";
11058
+ for (let j = 0;j < from.trailing.length; j++) {
11059
+ const ch = from.trailing[j];
11060
+ if (ch === " ") {
11061
+ trailing += " ";
11062
+ continue;
11063
+ }
11064
+ const offset = j - pos;
11065
+ if (offset >= 0 && offset <= WIPE_TRAIL) {
11066
+ trailing += rgb(140, 255, 255, randGlyph());
11067
+ } else if (j > pos) {
11068
+ trailing += " ";
11069
+ } else {
11070
+ trailing += rgbStr(TRAILING_COLOR, ch);
11071
+ }
11072
+ }
11073
+ printFrame(rainbowArt, buildTaglineLine(PREFIX.length, trailing));
11074
+ }
11075
+ await delay(WIPE_PAUSE_MS);
11076
+ await decodeTrailing(rainbowArt, to, PREFIX.length);
11077
+ }
11078
+ async function lockShimmer(rainbowArt, s) {
11079
+ const delay = (ms) => new Promise((r) => setTimeout(r, ms));
11080
+ const up = (n) => outb(`\x1B[${n}F`);
11081
+ const SHIMMER_TICK_MS = 22;
11082
+ const TRAIL = 3;
11083
+ const STOPS = [
11084
+ [255, 255, 255],
11085
+ [200, 245, 255],
11086
+ [150, 235, 255]
11087
+ ];
11088
+ const fullText = PREFIX + s.trailing;
11089
+ const N = fullText.length;
11090
+ for (let pos = 0;pos <= N + TRAIL; pos++) {
11091
+ await delay(SHIMMER_TICK_MS);
11092
+ up(BANNER_LINE_COUNT);
11093
+ let line = TAGLINE_LEAD;
11094
+ for (let j = 0;j < N; j++) {
11095
+ const ch = fullText[j];
11096
+ if (ch === " ") {
11097
+ line += " ";
11098
+ continue;
11099
+ }
11100
+ const offset = pos - j;
11101
+ if (offset >= 0 && offset < TRAIL) {
11102
+ line += rgbStr(STOPS[offset], ch);
11103
+ } else if (offset >= TRAIL) {
11104
+ line += rgbStr(FINAL_COLOR, ch);
11105
+ } else {
11106
+ const baseColor = j < PREFIX.length ? PREFIX_COLOR : TRAILING_COLOR;
11107
+ line += rgbStr(baseColor, ch);
11108
+ }
11109
+ }
11110
+ line += "\x1B[K";
11111
+ printFrame(rainbowArt, line);
11112
+ }
11113
+ up(BANNER_LINE_COUNT);
11114
+ let finalLine = TAGLINE_LEAD;
11115
+ for (let j = 0;j < N; j++) {
11116
+ const ch = fullText[j];
11117
+ finalLine += ch === " " ? " " : rgbStr(FINAL_COLOR, ch);
11118
+ }
11119
+ finalLine += "\x1B[K";
11120
+ printFrame(rainbowArt, finalLine);
11121
+ await delay(150);
11122
+ }
10872
11123
  async function printBanner() {
10873
11124
  if (!process.stdout.isTTY)
10874
11125
  return;
10875
- const delay = (ms) => new Promise((r) => setTimeout(r, ms));
10876
- const up = (n) => outb(`\x1B[${n}F`);
10877
11126
  if (!supportsRgb()) {
10878
11127
  outb(`
10879
11128
  `);
@@ -10882,84 +11131,24 @@ async function printBanner() {
10882
11131
  `);
10883
11132
  outb(`
10884
11133
  `);
10885
- outb(` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}
11134
+ outb(`${TAGLINE_LEAD}${import_picocolors.default.bold(import_picocolors.default.cyan(TAGLINE_FALLBACK))}
10886
11135
  `);
10887
11136
  outb(`
10888
11137
  `);
10889
11138
  return;
10890
11139
  }
10891
- outb("\x1B[?25l");
11140
+ const rainbowArt = ART_LINES.map((l, i) => neonLine(l, i));
11141
+ const whiteArt = ART_LINES.map((l) => whiteLine(l));
10892
11142
  try {
10893
- let diagFrame = function(highlight) {
10894
- return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
10895
- if (ch === " ")
10896
- return ch;
10897
- const d = col - 3 * row;
10898
- if (Math.abs(d - highlight) <= 1)
10899
- return `\x1B[1;97m${ch}\x1B[0m`;
10900
- const hue = ((col * HUE_PER_CHAR - row * HUE_PER_ROW) % 360 + 360) % 360;
10901
- const [r, g, b] = hsvToRgb(hue);
10902
- return `\x1B[1;38;2;${r};${g};${b}m${ch}\x1B[0m`;
10903
- }).join(""));
10904
- };
10905
- printFrame(ART_LINES.map(dimLine), ` ${" ".repeat(TAGLINE.length)}`);
10906
- for (let scan = 0;scan < ART_LINES.length; scan++) {
10907
- await delay(65);
10908
- up(BANNER_LINE_COUNT);
10909
- printFrame(ART_LINES.map((l, i) => {
10910
- if (i < scan - 2)
10911
- return neonLine(l, i);
10912
- if (i === scan - 2)
10913
- return neonLine(l, i, 120);
10914
- if (i === scan - 1)
10915
- return neonLine(l, i, 200);
10916
- if (i === scan)
10917
- return scanLine(l);
10918
- return dimLine(l);
10919
- }), ` ${" ".repeat(TAGLINE.length)}`);
10920
- }
10921
- await delay(60);
10922
- up(BANNER_LINE_COUNT);
10923
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${" ".repeat(TAGLINE.length)}`);
10924
- let minD = 0;
10925
- let maxD = 0;
10926
- for (let row = 0;row < ART_LINES.length; row++) {
10927
- minD = Math.min(minD, -row * 3);
10928
- maxD = Math.max(maxD, ART_LINES[row].length - 1 - row * 3);
10929
- }
10930
- for (let d = minD;d <= maxD; d++) {
10931
- await delay(16);
10932
- up(BANNER_LINE_COUNT);
10933
- printFrame(diagFrame(d), ` ${" ".repeat(TAGLINE.length)}`);
10934
- }
10935
- for (let d = maxD;d >= minD; d--) {
10936
- await delay(16);
10937
- up(BANNER_LINE_COUNT);
10938
- printFrame(diagFrame(d), ` ${" ".repeat(TAGLINE.length)}`);
10939
- }
10940
- up(BANNER_LINE_COUNT);
10941
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${" ".repeat(TAGLINE.length)}`);
10942
- await delay(200);
10943
- const cursor = "\x1B[1;38;2;140;255;255m\u258C\x1B[0m";
10944
- for (let len = 1;len <= TAGLINE.length; len++) {
10945
- await delay(32);
10946
- up(BANNER_LINE_COUNT);
10947
- const hasCursor = len < TAGLINE.length;
10948
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` \x1B[1;97m${TAGLINE.slice(0, len)}\x1B[0m${hasCursor ? cursor : ""}${" ".repeat(Math.max(0, TAGLINE.length - len - 1))}`);
10949
- }
10950
- const tagWithCursor = ` \x1B[1;97m${TAGLINE}\x1B[0m${cursor}`;
10951
- const tagWhite = ` \x1B[1;97m${TAGLINE}\x1B[0m\x1B[K`;
10952
- for (let b = 0;b < 2; b++) {
10953
- await delay(600);
10954
- up(BANNER_LINE_COUNT);
10955
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), tagWhite);
10956
- await delay(600);
10957
- up(BANNER_LINE_COUNT);
10958
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), tagWithCursor);
10959
- }
10960
- await delay(600);
10961
- up(BANNER_LINE_COUNT);
10962
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}\x1B[K`);
11143
+ outb("\x1B[?25l");
11144
+ await playBannerIntro(rainbowArt, whiteArt);
11145
+ await decodeFirstSentence(rainbowArt, SENTENCES[0]);
11146
+ await new Promise((r) => setTimeout(r, SENTENCE_HOLD_MS));
11147
+ await wipeSwapTransition(rainbowArt, SENTENCES[0], SENTENCES[1]);
11148
+ await new Promise((r) => setTimeout(r, SENTENCE_HOLD_MS));
11149
+ await wipeSwapTransition(rainbowArt, SENTENCES[1], SENTENCES[2]);
11150
+ await new Promise((r) => setTimeout(r, SENTENCE_HOLD_MS));
11151
+ await lockShimmer(rainbowArt, SENTENCES[2]);
10963
11152
  } finally {
10964
11153
  outb("\x1B[?25h");
10965
11154
  }
@@ -11072,7 +11261,12 @@ async function runDoctor(opts = {}) {
11072
11261
  const totalChecks = results.length;
11073
11262
  const errorCount = results.filter((r2) => r2.status === "error").length;
11074
11263
  const warningCount = results.filter((r2) => r2.status === "warn").length;
11075
- const fixableCount = results.filter((r2) => r2.status !== "ok" && getFix(r2) !== null).length;
11264
+ const fixableCount = results.filter((r2) => {
11265
+ if (r2.status === "ok")
11266
+ return false;
11267
+ const fix = getFix(r2);
11268
+ return fix !== null && !fix.advisory;
11269
+ }).length;
11076
11270
  const showFixHint = !opts.fix && fixableCount > 0;
11077
11271
  const summaryParts = [`${totalChecks} checks`];
11078
11272
  if (errorCount > 0)
@@ -11187,6 +11381,7 @@ function getFix(r2) {
11187
11381
  const pendingMatch = r2.message.match(/(\d+) unembedded/);
11188
11382
  const count = pendingMatch?.[1] ?? "some";
11189
11383
  return {
11384
+ advisory: true,
11190
11385
  fn: async (vaultDir) => {
11191
11386
  const { join: join5 } = await import("path");
11192
11387
  const { parse: parseYaml } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
@@ -11232,14 +11427,14 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11232
11427
  const fixable = results.filter((r2) => r2.status !== "ok" && getFix(r2) !== null);
11233
11428
  if (fixable.length === 0) {
11234
11429
  if (isTTY)
11235
- barLine(`${import_picocolors5.default.green("\u25C6")} Nothing to fix`);
11430
+ writeLine(`${import_picocolors5.default.green("\u25C6")} Nothing to fix`);
11236
11431
  else
11237
11432
  writeLine("nothing to fix");
11238
11433
  return;
11239
11434
  }
11240
11435
  if (isTTY) {
11241
- barBlank();
11242
- barLine(import_picocolors5.default.bold(`${fixable.length} fix(es) to apply:`));
11436
+ writeLine("");
11437
+ barOpen(import_picocolors5.default.bold(`${fixable.length} fix(es) to apply:`));
11243
11438
  barBlank();
11244
11439
  for (const r2 of fixable) {
11245
11440
  barLine(` ${import_picocolors5.default.cyan("\u25C6")} ${getFix(r2).description}`);
@@ -12142,12 +12337,6 @@ async function scanMonthDir(monthDir, currentToken, today, seenTokens) {
12142
12337
  continue;
12143
12338
  if (seenTokens.has(ftoken))
12144
12339
  continue;
12145
- try {
12146
- const content = await readFile5(join9(monthDir, fname), "utf8");
12147
- const fm = parseFrontmatter(content);
12148
- if (fm && (fm["merged"] === true || fm["merged"] === "true"))
12149
- continue;
12150
- } catch {}
12151
12340
  if (await hasManualSessionLog(monthDir, fdate))
12152
12341
  continue;
12153
12342
  seenTokens.add(ftoken);
@@ -12608,8 +12797,8 @@ function patchUtf8(stream) {
12608
12797
  }
12609
12798
 
12610
12799
  // src/index.ts
12611
- var VERSION = "2.1.4";
12612
- var RELEASE_DATE = "2026-04-28";
12800
+ var VERSION = "2.1.5";
12801
+ var RELEASE_DATE = "2026-04-29";
12613
12802
  patchUtf8(process.stdout);
12614
12803
  patchUtf8(process.stderr);
12615
12804
  var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onebrain-ai/cli",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
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",