@onebrain-ai/cli 2.1.2 → 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.
package/dist/onebrain CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- import { createRequire } from "node:module";
4
3
  var __create = Object.create;
5
4
  var __getProtoOf = Object.getPrototypeOf;
6
5
  var __defProp = Object.defineProperty;
@@ -28,7 +27,7 @@ var __export = (target, all) => {
28
27
  });
29
28
  };
30
29
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
31
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
30
+ var __require = import.meta.require;
32
31
 
33
32
  // node_modules/commander/lib/error.js
34
33
  var require_error = __commonJS((exports) => {
@@ -353,7 +352,7 @@ var require_help = __commonJS((exports) => {
353
352
  return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
354
353
  }
355
354
  wrap(str, width, indent, minColumnWidth = 40) {
356
- const indents = " \\f\\t\\v   -    \uFEFF";
355
+ const indents = " \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF";
357
356
  const manualIndent = new RegExp(`[\\n][${indents}]+`);
358
357
  if (str.match(manualIndent))
359
358
  return str;
@@ -365,7 +364,7 @@ var require_help = __commonJS((exports) => {
365
364
  `, `
366
365
  `);
367
366
  const indentString = " ".repeat(indent);
368
- const zeroWidthSpace = "";
367
+ const zeroWidthSpace = "\u200B";
369
368
  const breaks = `\\s${zeroWidthSpace}`;
370
369
  const regex = new RegExp(`
371
370
  |.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`, "g");
@@ -608,11 +607,11 @@ var require_suggestSimilar = __commonJS((exports) => {
608
607
 
609
608
  // node_modules/commander/lib/command.js
610
609
  var require_command = __commonJS((exports) => {
611
- var EventEmitter = __require("node:events").EventEmitter;
612
- var childProcess = __require("node:child_process");
613
- var path = __require("node:path");
614
- var fs = __require("node:fs");
615
- var process2 = __require("node:process");
610
+ var EventEmitter = __require("events").EventEmitter;
611
+ var childProcess = __require("child_process");
612
+ var path = __require("path");
613
+ var fs = __require("fs");
614
+ var process2 = __require("process");
616
615
  var { Argument, humanReadableArgName } = require_argument();
617
616
  var { CommanderError } = require_error();
618
617
  var { Help } = require_help();
@@ -5365,15 +5364,15 @@ var require_errors = __commonJS((exports) => {
5365
5364
  let lineStr = src.substring(lc.lineStarts[line - 1], lc.lineStarts[line]).replace(/[\n\r]+$/, "");
5366
5365
  if (ci >= 60 && lineStr.length > 80) {
5367
5366
  const trimStart = Math.min(ci - 39, lineStr.length - 79);
5368
- lineStr = "" + lineStr.substring(trimStart);
5367
+ lineStr = "\u2026" + lineStr.substring(trimStart);
5369
5368
  ci -= trimStart - 1;
5370
5369
  }
5371
5370
  if (lineStr.length > 80)
5372
- lineStr = lineStr.substring(0, 79) + "";
5371
+ lineStr = lineStr.substring(0, 79) + "\u2026";
5373
5372
  if (line > 1 && /^ *$/.test(lineStr.substring(0, ci))) {
5374
5373
  let prev = src.substring(lc.lineStarts[line - 2], lc.lineStarts[line - 1]);
5375
5374
  if (prev.length > 80)
5376
- prev = prev.substring(0, 79) + `…
5375
+ prev = prev.substring(0, 79) + `\u2026
5377
5376
  `;
5378
5377
  lineStr = prev + lineStr;
5379
5378
  }
@@ -6428,8 +6427,8 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
6428
6427
  r: "\r",
6429
6428
  t: "\t",
6430
6429
  v: "\v",
6431
- N: "…",
6432
- _: " ",
6430
+ N: "\x85",
6431
+ _: "\xA0",
6433
6432
  L: "\u2028",
6434
6433
  P: "\u2029",
6435
6434
  " ": " ",
@@ -8904,7 +8903,7 @@ var require_dist = __commonJS((exports) => {
8904
8903
  });
8905
8904
 
8906
8905
  // src/lib/parser.ts
8907
- import { join } from "node:path";
8906
+ import { join } from "path";
8908
8907
  async function loadVaultConfig(vaultRoot) {
8909
8908
  const vaultYmlPath = join(vaultRoot, "vault.yml");
8910
8909
  const file = Bun.file(vaultYmlPath);
@@ -8973,8 +8972,8 @@ var init_parser = __esm(() => {
8973
8972
  });
8974
8973
 
8975
8974
  // src/lib/validator.ts
8976
- import { stat } from "node:fs/promises";
8977
- import { join as join2 } from "node:path";
8975
+ import { stat } from "fs/promises";
8976
+ import { join as join2 } from "path";
8978
8977
  async function checkVaultYml(vaultRoot) {
8979
8978
  const vaultYmlPath = join2(vaultRoot, "vault.yml");
8980
8979
  const file = Bun.file(vaultYmlPath);
@@ -9100,16 +9099,16 @@ async function checkQmdEmbeddings(config) {
9100
9099
  if (total === null) {
9101
9100
  return { check: "qmd-embeddings", status: "ok", message: "qmd status unavailable" };
9102
9101
  }
9103
- const summary = `${total} indexed · ${pending} unembedded`;
9102
+ const summary = `${total} indexed \xB7 ${pending} unembedded`;
9104
9103
  if (pending > 0) {
9105
9104
  return {
9106
9105
  check: "qmd-embeddings",
9107
9106
  status: "warn",
9108
9107
  message: summary,
9109
- hint: "Run onebrain doctor --fix to reindex and embed",
9108
+ hint: "Advisory: run /qmd embed when ready (or onebrain doctor --fix)",
9110
9109
  details: [
9111
9110
  `collection: ${config.qmd_collection}`,
9112
- "Run onebrain doctor --fix to reindex and embed"
9111
+ "Advisory: run /qmd embed when ready (or onebrain doctor --fix)"
9113
9112
  ]
9114
9113
  };
9115
9114
  }
@@ -9141,20 +9140,7 @@ async function checkOrphanCheckpoints(vaultRoot, config) {
9141
9140
  message: "0 orphans"
9142
9141
  };
9143
9142
  }
9144
- if (checkpointFiles.length === 0) {
9145
- return {
9146
- check: "orphan-checkpoints",
9147
- status: "ok",
9148
- message: "0 orphans"
9149
- };
9150
- }
9151
- let orphanCount = 0;
9152
- for (const filePath of checkpointFiles) {
9153
- const merged = await readMergedField(filePath);
9154
- if (merged !== true) {
9155
- orphanCount++;
9156
- }
9157
- }
9143
+ const orphanCount = checkpointFiles.length;
9158
9144
  if (orphanCount === 0) {
9159
9145
  return {
9160
9146
  check: "orphan-checkpoints",
@@ -9170,30 +9156,6 @@ async function checkOrphanCheckpoints(vaultRoot, config) {
9170
9156
  details: ["Run /wrapup to synthesize and merge them"]
9171
9157
  };
9172
9158
  }
9173
- async function readMergedField(filePath) {
9174
- try {
9175
- const file = Bun.file(filePath);
9176
- const text = await file.text();
9177
- if (!text.startsWith("---"))
9178
- return;
9179
- const endIdx = text.indexOf(`
9180
- ---`, 3);
9181
- if (endIdx === -1)
9182
- return;
9183
- const frontmatter = text.slice(3, endIdx).trim();
9184
- const parsed = import_yaml2.parse(frontmatter);
9185
- if (!parsed)
9186
- return;
9187
- const merged = parsed["merged"];
9188
- if (merged === true || merged === "true")
9189
- return true;
9190
- if (merged === false || merged === "false")
9191
- return false;
9192
- return;
9193
- } catch {
9194
- return;
9195
- }
9196
- }
9197
9159
  async function checkPluginFiles(vaultRoot) {
9198
9160
  const pluginBase = join2(vaultRoot, ".claude", "plugins", "onebrain");
9199
9161
  const missingFiles = [];
@@ -9267,7 +9229,7 @@ async function checkPluginFiles(vaultRoot) {
9267
9229
  check: "plugin-files",
9268
9230
  status: "ok",
9269
9231
  message: "all required files present",
9270
- details: [`${skillCount} skills · ${agentCount} agents · INSTRUCTIONS.md ✓`]
9232
+ details: [`${skillCount} skills \xB7 ${agentCount} agents \xB7 INSTRUCTIONS.md \u2713`]
9271
9233
  };
9272
9234
  }
9273
9235
  async function checkVaultYmlKeys(vaultRoot) {
@@ -9392,14 +9354,14 @@ async function checkSettingsHooks(vaultRoot, config) {
9392
9354
  if (!hookPresent(settings, event, cmdSubstring)) {
9393
9355
  warnings.push(`${event} hook missing`);
9394
9356
  } else {
9395
- confirmedHooks.push(`${event} ✓`);
9357
+ confirmedHooks.push(`${event} \u2713`);
9396
9358
  }
9397
9359
  }
9398
9360
  if (config.qmd_collection) {
9399
9361
  if (!hookPresent(settings, "PostToolUse", QMD_HOOK_SUBSTRING)) {
9400
9362
  warnings.push("PostToolUse (qmd) hook missing");
9401
9363
  } else {
9402
- confirmedHooks.push("PostToolUse ");
9364
+ confirmedHooks.push("PostToolUse \u2713");
9403
9365
  }
9404
9366
  }
9405
9367
  const precompactGroups = settings.hooks?.["PreCompact"] ?? [];
@@ -9438,7 +9400,7 @@ async function checkSettingsHooks(vaultRoot, config) {
9438
9400
  if (confirmedHooks.length > 0)
9439
9401
  okDetails.push(`hooks: ${confirmedHooks.join(" ")}`);
9440
9402
  if (permissionOk)
9441
- okDetails.push("permissions: Bash(onebrain *) ");
9403
+ okDetails.push("permissions: Bash(onebrain *) \u2713");
9442
9404
  return {
9443
9405
  check: "settings-hooks",
9444
9406
  status: "ok",
@@ -9498,8 +9460,8 @@ var init_lib = __esm(() => {
9498
9460
  var require_package = __commonJS((exports, module) => {
9499
9461
  module.exports = {
9500
9462
  name: "@onebrain-ai/cli",
9501
- version: "2.1.2",
9502
- description: "CLI for OneBrain personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
9463
+ version: "2.1.5",
9464
+ description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
9503
9465
  keywords: [
9504
9466
  "onebrain",
9505
9467
  "obsidian",
@@ -9524,9 +9486,11 @@ var require_package = __commonJS((exports, module) => {
9524
9486
  bin: {
9525
9487
  onebrain: "dist/onebrain"
9526
9488
  },
9527
- files: ["dist/onebrain"],
9489
+ files: ["dist/onebrain", "dist/postinstall.js"],
9528
9490
  scripts: {
9529
9491
  build: "bun build src/index.ts --outfile dist/onebrain --target bun",
9492
+ "build:postinstall": "bun build src/scripts/postinstall.ts --outfile dist/postinstall.js --target node",
9493
+ postinstall: "node dist/postinstall.js",
9530
9494
  test: "bun test --pass-with-no-tests src/",
9531
9495
  typecheck: "tsc --noEmit"
9532
9496
  },
@@ -9561,15 +9525,19 @@ function barBlank() {
9561
9525
  out(`${bar}
9562
9526
  `);
9563
9527
  }
9528
+ function barOpen(msg) {
9529
+ out(`${import_picocolors2.default.cyan("\u250C")} ${msg}
9530
+ `);
9531
+ }
9564
9532
  function close(msg, isError = false, isWarning = false) {
9565
9533
  if (isError) {
9566
- out(`${import_picocolors2.default.cyan("")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
9534
+ out(`${import_picocolors2.default.cyan("\u2514")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
9567
9535
  `);
9568
9536
  } else if (isWarning) {
9569
- out(`${import_picocolors2.default.cyan("")} ${import_picocolors2.default.yellow(msg)}
9537
+ out(`${import_picocolors2.default.cyan("\u2514")} ${import_picocolors2.default.yellow(msg)}
9570
9538
  `);
9571
9539
  } else {
9572
- out(`${import_picocolors2.default.cyan("")} ${msg}
9540
+ out(`${import_picocolors2.default.cyan("\u2514")} ${msg}
9573
9541
  `);
9574
9542
  }
9575
9543
  }
@@ -9581,13 +9549,13 @@ function makeStepFn(isTTY) {
9581
9549
  return function createStep(emoji, label) {
9582
9550
  if (!isTTY)
9583
9551
  return null;
9584
- const frames = ["", "", "", "", "", "", "", "", "", ""];
9552
+ const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9585
9553
  let i = 0;
9586
- out(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}
9554
+ out(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}\u2026
9587
9555
  `);
9588
9556
  const timer = setInterval(() => {
9589
9557
  i = (i + 1) % frames.length;
9590
- out(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}
9558
+ out(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}\u2026
9591
9559
  `);
9592
9560
  }, 80);
9593
9561
  return {
@@ -9600,19 +9568,19 @@ function makeStepFn(isTTY) {
9600
9568
  barLine(result);
9601
9569
  if (details)
9602
9570
  for (const d of details)
9603
- barLine(` · ${d}`);
9571
+ barLine(` \xB7 ${d}`);
9604
9572
  barBlank();
9605
9573
  }
9606
9574
  };
9607
9575
  };
9608
9576
  }
9609
9577
  async function askYesNo(question) {
9610
- out(`${import_picocolors2.default.cyan("")} ${question}
9578
+ out(`${import_picocolors2.default.cyan("\u25C6")} ${question}
9611
9579
  `);
9612
9580
  process.stdout.write(Buffer.from("\x1B[?25l", "utf8"));
9613
9581
  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`;
9582
+ const yesLabel = yes ? `${import_picocolors2.default.bold(import_picocolors2.default.green("\u25CF"))} Yes` : `${import_picocolors2.default.dim("\u25CB")} Yes`;
9583
+ const noLabel = yes ? `${import_picocolors2.default.dim("\u25CB")} No` : `${import_picocolors2.default.bold(import_picocolors2.default.green("\u25CF"))} No`;
9616
9584
  out(`\x1B[2K${bar} ${yesLabel} / ${noLabel}\r`);
9617
9585
  }
9618
9586
  const answer = await new Promise((resolve) => {
@@ -9664,8 +9632,8 @@ async function askYesNo(question) {
9664
9632
  var import_picocolors2, bar, dot;
9665
9633
  var init_cli_ui = __esm(() => {
9666
9634
  import_picocolors2 = __toESM(require_picocolors(), 1);
9667
- bar = import_picocolors2.default.cyan("");
9668
- dot = import_picocolors2.default.green("");
9635
+ bar = import_picocolors2.default.cyan("\u2502");
9636
+ dot = import_picocolors2.default.green("\u25CF");
9669
9637
  });
9670
9638
 
9671
9639
  // node_modules/sisteransi/src/index.js
@@ -9727,8 +9695,8 @@ var require_src = __commonJS((exports, module) => {
9727
9695
  });
9728
9696
 
9729
9697
  // node_modules/@clack/core/dist/index.mjs
9730
- import { stdin as $, stdout as j } from "node:process";
9731
- import * as f from "node:readline";
9698
+ import { stdin as $, stdout as j } from "process";
9699
+ import * as f from "readline";
9732
9700
  function J({ onlyFirst: t = false } = {}) {
9733
9701
  const F = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
9734
9702
  return new RegExp(F, t ? undefined : "g");
@@ -9847,7 +9815,7 @@ var init_dist = __esm(() => {
9847
9815
  eD = Object.keys(r.bgColor);
9848
9816
  [...tD, ...eD];
9849
9817
  iD = sD();
9850
- v = new Set(["\x1B", "›"]);
9818
+ v = new Set(["\x1B", "\x9B"]);
9851
9819
  y = `${rD}8;;`;
9852
9820
  aD = ["up", "down", "left", "right", "space", "enter", "cancel"];
9853
9821
  c = { actions: new Set(aD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
@@ -9856,7 +9824,7 @@ var init_dist = __esm(() => {
9856
9824
  });
9857
9825
 
9858
9826
  // node_modules/@clack/prompts/dist/index.mjs
9859
- import p from "node:process";
9827
+ import p from "process";
9860
9828
  function X2() {
9861
9829
  return p.platform !== "win32" ? p.env.TERM !== "linux" : !!p.env.CI || !!p.env.WT_SESSION || !!p.env.TERMINUS_SUBLIME || p.env.ConEmuTask === "{cmd::Cmder}" || p.env.TERM_PROGRAM === "Terminus-Sublime" || p.env.TERM_PROGRAM === "vscode" || p.env.TERM === "xterm-256color" || p.env.TERM === "alacritty" || p.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
9862
9830
  }
@@ -9869,7 +9837,7 @@ ${import_picocolors3.default.gray(m2)} ${s}
9869
9837
 
9870
9838
  `);
9871
9839
  }, L2 = () => {
9872
- const s = E ? ["", "", "", ""] : ["", "o", "O", "0"], n = E ? 80 : 120, t = process.env.CI === "true";
9840
+ const s = E ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], n = E ? 80 : 120, t = process.env.CI === "true";
9873
9841
  let i, r2, c2 = false, o = "", l2;
9874
9842
  const $2 = (h) => {
9875
9843
  const g = h > 1 ? "Something went wrong" : "Canceled";
@@ -9913,32 +9881,32 @@ var init_dist2 = __esm(() => {
9913
9881
  import_picocolors3 = __toESM(require_picocolors(), 1);
9914
9882
  import_sisteransi2 = __toESM(require_src(), 1);
9915
9883
  E = X2();
9916
- ee = u("", "*");
9917
- A = u("", "x");
9918
- B = u("", "x");
9919
- S2 = u("", "o");
9920
- te = u("", "T");
9921
- a = u("", "|");
9922
- m2 = u("", "");
9923
- j2 = u("", ">");
9924
- R = u("", " ");
9925
- V = u("", "[]");
9926
- M = u("", "[+]");
9927
- G = u("", "[ ]");
9928
- se = u("", "");
9929
- N2 = u("", "-");
9930
- re = u("", "+");
9931
- ie = u("", "+");
9932
- ne = u("", "+");
9933
- ae = u("", "");
9934
- oe = u("", "*");
9935
- ce = u("", "!");
9936
- le = u("", "x");
9884
+ ee = u("\u25C6", "*");
9885
+ A = u("\u25A0", "x");
9886
+ B = u("\u25B2", "x");
9887
+ S2 = u("\u25C7", "o");
9888
+ te = u("\u250C", "T");
9889
+ a = u("\u2502", "|");
9890
+ m2 = u("\u2514", "\u2014");
9891
+ j2 = u("\u25CF", ">");
9892
+ R = u("\u25CB", " ");
9893
+ V = u("\u25FB", "[\u2022]");
9894
+ M = u("\u25FC", "[+]");
9895
+ G = u("\u25FB", "[ ]");
9896
+ se = u("\u25AA", "\u2022");
9897
+ N2 = u("\u2500", "-");
9898
+ re = u("\u256E", "+");
9899
+ ie = u("\u251C", "+");
9900
+ ne = u("\u256F", "+");
9901
+ ae = u("\u25CF", "\u2022");
9902
+ oe = u("\u25C6", "*");
9903
+ ce = u("\u25B2", "!");
9904
+ le = u("\u25A0", "x");
9937
9905
  });
9938
9906
 
9939
9907
  // src/commands/internal/harness.ts
9940
- import { stat as stat2 } from "node:fs/promises";
9941
- import { join as join3 } from "node:path";
9908
+ import { stat as stat2 } from "fs/promises";
9909
+ import { join as join3 } from "path";
9942
9910
  async function pathExists(p2) {
9943
9911
  try {
9944
9912
  await stat2(p2);
@@ -9956,7 +9924,7 @@ async function detectHarness(vaultRoot) {
9956
9924
  return "gemini";
9957
9925
  if (env === "direct")
9958
9926
  return "direct";
9959
- process.stderr.write(`harness: unknown ONEBRAIN_HARNESS value "${env}" ignoring, falling back to directory detection
9927
+ process.stderr.write(`harness: unknown ONEBRAIN_HARNESS value "${env}" \u2014 ignoring, falling back to directory detection
9960
9928
  `);
9961
9929
  }
9962
9930
  if (await pathExists(join3(vaultRoot, ".gemini")))
@@ -9973,9 +9941,9 @@ __export(exports_register_hooks, {
9973
9941
  runRegisterHooks: () => runRegisterHooks,
9974
9942
  registerHooksCommand: () => registerHooksCommand
9975
9943
  });
9976
- import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
9977
- import { homedir } from "node:os";
9978
- import { dirname, join as join4 } from "node:path";
9944
+ import { mkdir, readFile, rename, writeFile } from "fs/promises";
9945
+ import { homedir } from "os";
9946
+ import { dirname, join as join4 } from "path";
9979
9947
  async function readSettings(settingsPath) {
9980
9948
  try {
9981
9949
  const text = await readFile(settingsPath, "utf8");
@@ -10152,11 +10120,11 @@ async function runRegisterHooks(opts = {}) {
10152
10120
  if (isTTY) {
10153
10121
  const parts = HOOK_EVENTS.map((e2) => {
10154
10122
  const status = result.hooks[e2];
10155
- const icon = import_picocolors4.default.green(status === "ok" ? "" : status === "migrated" ? "" : "+");
10123
+ const icon = import_picocolors4.default.green(status === "ok" ? "\u2713" : status === "migrated" ? "\u2191" : "+");
10156
10124
  return `${import_picocolors4.default.dim(e2)} ${icon}`;
10157
10125
  });
10158
10126
  if (qmdStatus)
10159
- parts.push(`${import_picocolors4.default.dim("PostToolUse")} ${import_picocolors4.default.green(qmdStatus === "ok" ? "" : "+")}`);
10127
+ parts.push(`${import_picocolors4.default.dim("PostToolUse")} ${import_picocolors4.default.green(qmdStatus === "ok" ? "\u2713" : "+")}`);
10160
10128
  hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
10161
10129
  } else {
10162
10130
  const hookLine = HOOK_EVENTS.map((e2) => {
@@ -10252,9 +10220,9 @@ import {
10252
10220
  stat as stat3,
10253
10221
  unlink,
10254
10222
  writeFile as writeFile2
10255
- } from "node:fs/promises";
10256
- import { homedir as homedir2, tmpdir } from "node:os";
10257
- import { dirname as dirname2, join as join5, relative } from "node:path";
10223
+ } from "fs/promises";
10224
+ import { homedir as homedir2, tmpdir } from "os";
10225
+ import { dirname as dirname2, join as join5, relative } from "path";
10258
10226
  function resolveBranch(updateChannel) {
10259
10227
  return updateChannel === "stable" ? "main" : "next";
10260
10228
  }
@@ -10263,9 +10231,9 @@ async function downloadTarball(branch, fetchFn) {
10263
10231
  const response = await fetchFn(url);
10264
10232
  if (!response.ok) {
10265
10233
  const hints = {
10266
- 403: " check repo permissions or GITHUB_TOKEN",
10267
- 404: " repo or branch not found",
10268
- 429: " rate limited, wait and retry"
10234
+ 403: " \u2014 check repo permissions or GITHUB_TOKEN",
10235
+ 404: " \u2014 repo or branch not found",
10236
+ 429: " \u2014 rate limited, wait and retry"
10269
10237
  };
10270
10238
  const hint = hints[response.status] ?? "";
10271
10239
  throw new Error(`HTTP ${response.status} downloading tarball from ${url}${hint}`);
@@ -10703,14 +10671,14 @@ async function runVaultSync(vaultRoot, opts = {}) {
10703
10671
  if (pinResult.skipped) {
10704
10672
  stopSpinner("pin skipped (not found or marketplace)");
10705
10673
  } else {
10706
- stopSpinner("installPath .claude/plugins/onebrain");
10674
+ stopSpinner("installPath \u2192 .claude/plugins/onebrain");
10707
10675
  }
10708
10676
  } catch (err) {
10709
10677
  const msg = err instanceof Error ? err.message : String(err);
10710
10678
  process.stderr.write(`vault-sync: pin warning: ${msg}
10711
10679
  `);
10712
10680
  result.pinSkipped = true;
10713
- stopSpinner("pin skipped (error non-fatal)");
10681
+ stopSpinner("pin skipped (error \u2014 non-fatal)");
10714
10682
  }
10715
10683
  startSpinner("\uD83E\uDDF9", "Cleaning cache");
10716
10684
  try {
@@ -10725,13 +10693,13 @@ async function runVaultSync(vaultRoot, opts = {}) {
10725
10693
  const msg = err instanceof Error ? err.message : String(err);
10726
10694
  process.stderr.write(`vault-sync: cache clean warning: ${msg}
10727
10695
  `);
10728
- stopSpinner("cache clean skipped (error non-fatal)");
10696
+ stopSpinner("cache clean skipped (error \u2014 non-fatal)");
10729
10697
  }
10730
10698
  }
10731
10699
  result.ok = true;
10732
10700
  if (isTTY) {
10733
10701
  if (!embedded) {
10734
- fe(`Done v${result.version} synced`);
10702
+ fe(`Done \u2014 v${result.version} synced`);
10735
10703
  }
10736
10704
  } else {
10737
10705
  process.stdout.write(`vault-sync: done
@@ -10761,7 +10729,7 @@ var init_vault_sync = __esm(() => {
10761
10729
 
10762
10730
  // src/index.ts
10763
10731
  import { existsSync } from "fs";
10764
- import { dirname as dirname6, join as join13 } from "path";
10732
+ import { dirname as dirname4, join as join11 } from "path";
10765
10733
 
10766
10734
  // node_modules/commander/esm.mjs
10767
10735
  var import__ = __toESM(require_commander(), 1);
@@ -10787,7 +10755,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
10787
10755
  var import_picocolors = __toESM(require_picocolors(), 1);
10788
10756
  function resolveBinaryVersion() {
10789
10757
  if (true)
10790
- return "2.1.2";
10758
+ return "2.1.5";
10791
10759
  try {
10792
10760
  const pkg = require_package();
10793
10761
  return pkg.version ?? "dev";
@@ -10796,43 +10764,52 @@ function resolveBinaryVersion() {
10796
10764
  }
10797
10765
  }
10798
10766
  var ART_LINES = [
10799
- ` ◆${"".repeat(25)}◆`,
10800
- " ┌─┐┌┐╷┌─╴┌┐ ┌─┐┌─┐╷┌┐╷",
10801
- " ││└┤├╴ ├┴┐├┬┘├─┤││└┤",
10802
- " └─┘╵ ╵└─╴└─┘╵└╴╵ ╵╵╵ ",
10803
- ` ◆${"".repeat(25)}◆`
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`
10804
10772
  ];
10805
- var TAGLINE = "Your AI Thinking Partner";
10773
+ var PREFIX = "Your AI ";
10774
+ var TAGLINE_LEAD = " ";
10775
+ var TAGLINE_FALLBACK = `${PREFIX}Thinking Partner`;
10806
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
+ ];
10807
10785
  function supportsRgb() {
10808
10786
  const c = process.env["COLORTERM"] ?? "";
10809
10787
  return c === "truecolor" || c === "24bit";
10810
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
+ }
10811
10795
  function hsvToRgb(h, floor = 80) {
10812
10796
  const c = 255;
10813
10797
  const x = Math.round(c * (1 - Math.abs(h / 60 % 2 - 1)));
10814
10798
  let r = 0;
10815
10799
  let g = 0;
10816
10800
  let b = 0;
10817
- if (h < 60) {
10818
- r = c;
10819
- g = x;
10820
- } else if (h < 120) {
10821
- r = x;
10822
- g = c;
10823
- } else if (h < 180) {
10824
- g = c;
10825
- b = x;
10826
- } else if (h < 240) {
10827
- g = x;
10828
- b = c;
10829
- } else if (h < 300) {
10830
- r = x;
10831
- b = c;
10832
- } else {
10833
- r = c;
10834
- b = x;
10835
- }
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];
10836
10813
  return [Math.min(255, r + floor), Math.min(255, g + floor), Math.min(255, b + floor)];
10837
10814
  }
10838
10815
  var HUE_PER_CHAR = 10;
@@ -10843,15 +10820,25 @@ function neonLine(line, lineIndex = 0, floor = 80) {
10843
10820
  return ch;
10844
10821
  const hue = ((i * HUE_PER_CHAR - lineIndex * HUE_PER_ROW) % 360 + 360) % 360;
10845
10822
  const [r, g, b] = hsvToRgb(hue, floor);
10846
- return `\x1B[1;38;2;${r};${g};${b}m${ch}\x1B[0m`;
10823
+ return rgb(r, g, b, ch);
10847
10824
  }).join("");
10848
10825
  }
10849
- function scanLine(line) {
10850
- 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("");
10851
10831
  }
10852
10832
  function dimLine(line) {
10853
10833
  return line.split("").map((ch) => ch === " " ? ch : `\x1B[2;38;2;50;50;70m${ch}\x1B[0m`).join("");
10854
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`;
10855
10842
  function outb(str) {
10856
10843
  process.stdout.write(Buffer.from(str, "utf8"));
10857
10844
  }
@@ -10868,11 +10855,274 @@ function printFrame(artLines, tagline) {
10868
10855
  outb(`
10869
10856
  `);
10870
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
+ }
10871
11123
  async function printBanner() {
10872
11124
  if (!process.stdout.isTTY)
10873
11125
  return;
10874
- const delay = (ms) => new Promise((r) => setTimeout(r, ms));
10875
- const up = (n) => outb(`\x1B[${n}F`);
10876
11126
  if (!supportsRgb()) {
10877
11127
  outb(`
10878
11128
  `);
@@ -10881,84 +11131,24 @@ async function printBanner() {
10881
11131
  `);
10882
11132
  outb(`
10883
11133
  `);
10884
- outb(` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}
11134
+ outb(`${TAGLINE_LEAD}${import_picocolors.default.bold(import_picocolors.default.cyan(TAGLINE_FALLBACK))}
10885
11135
  `);
10886
11136
  outb(`
10887
11137
  `);
10888
11138
  return;
10889
11139
  }
10890
- outb("\x1B[?25l");
11140
+ const rainbowArt = ART_LINES.map((l, i) => neonLine(l, i));
11141
+ const whiteArt = ART_LINES.map((l) => whiteLine(l));
10891
11142
  try {
10892
- let diagFrame = function(highlight) {
10893
- return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
10894
- if (ch === " ")
10895
- return ch;
10896
- const d = col - 3 * row;
10897
- if (Math.abs(d - highlight) <= 1)
10898
- return `\x1B[1;97m${ch}\x1B[0m`;
10899
- const hue = ((col * HUE_PER_CHAR - row * HUE_PER_ROW) % 360 + 360) % 360;
10900
- const [r, g, b] = hsvToRgb(hue);
10901
- return `\x1B[1;38;2;${r};${g};${b}m${ch}\x1B[0m`;
10902
- }).join(""));
10903
- };
10904
- printFrame(ART_LINES.map(dimLine), ` ${" ".repeat(TAGLINE.length)}`);
10905
- for (let scan = 0;scan < ART_LINES.length; scan++) {
10906
- await delay(65);
10907
- up(BANNER_LINE_COUNT);
10908
- printFrame(ART_LINES.map((l, i) => {
10909
- if (i < scan - 2)
10910
- return neonLine(l, i);
10911
- if (i === scan - 2)
10912
- return neonLine(l, i, 120);
10913
- if (i === scan - 1)
10914
- return neonLine(l, i, 200);
10915
- if (i === scan)
10916
- return scanLine(l);
10917
- return dimLine(l);
10918
- }), ` ${" ".repeat(TAGLINE.length)}`);
10919
- }
10920
- await delay(60);
10921
- up(BANNER_LINE_COUNT);
10922
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${" ".repeat(TAGLINE.length)}`);
10923
- let minD = 0;
10924
- let maxD = 0;
10925
- for (let row = 0;row < ART_LINES.length; row++) {
10926
- minD = Math.min(minD, -row * 3);
10927
- maxD = Math.max(maxD, ART_LINES[row].length - 1 - row * 3);
10928
- }
10929
- for (let d = minD;d <= maxD; d++) {
10930
- await delay(16);
10931
- up(BANNER_LINE_COUNT);
10932
- printFrame(diagFrame(d), ` ${" ".repeat(TAGLINE.length)}`);
10933
- }
10934
- for (let d = maxD;d >= minD; d--) {
10935
- await delay(16);
10936
- up(BANNER_LINE_COUNT);
10937
- printFrame(diagFrame(d), ` ${" ".repeat(TAGLINE.length)}`);
10938
- }
10939
- up(BANNER_LINE_COUNT);
10940
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${" ".repeat(TAGLINE.length)}`);
10941
- await delay(200);
10942
- const cursor = `\x1B[1;38;2;140;255;255m▌\x1B[0m`;
10943
- for (let len = 1;len <= TAGLINE.length; len++) {
10944
- await delay(32);
10945
- up(BANNER_LINE_COUNT);
10946
- const hasCursor = len < TAGLINE.length;
10947
- 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))}`);
10948
- }
10949
- const tagWithCursor = ` \x1B[1;97m${TAGLINE}\x1B[0m${cursor}`;
10950
- const tagWhite = ` \x1B[1;97m${TAGLINE}\x1B[0m\x1B[K`;
10951
- for (let b = 0;b < 2; b++) {
10952
- await delay(600);
10953
- up(BANNER_LINE_COUNT);
10954
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), tagWhite);
10955
- await delay(600);
10956
- up(BANNER_LINE_COUNT);
10957
- printFrame(ART_LINES.map((l, i) => neonLine(l, i)), tagWithCursor);
10958
- }
10959
- await delay(600);
10960
- up(BANNER_LINE_COUNT);
10961
- 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]);
10962
11152
  } finally {
10963
11153
  outb("\x1B[?25h");
10964
11154
  }
@@ -11018,7 +11208,7 @@ async function runDoctor(opts = {}) {
11018
11208
  let vaultYmlKeysResult;
11019
11209
  let settingsHooksResult;
11020
11210
  if (isTTY) {
11021
- const sp2 = createStep("⚙️", "Config schema");
11211
+ const sp2 = createStep("\u2699\uFE0F", "Config schema");
11022
11212
  vaultYmlKeysResult = await checkVaultYmlKeysFn(vaultDir);
11023
11213
  await randDelay();
11024
11214
  sp2.stop(fmtResult(vaultYmlKeysResult), vaultYmlKeysResult.details);
@@ -11071,7 +11261,12 @@ async function runDoctor(opts = {}) {
11071
11261
  const totalChecks = results.length;
11072
11262
  const errorCount = results.filter((r2) => r2.status === "error").length;
11073
11263
  const warningCount = results.filter((r2) => r2.status === "warn").length;
11074
- 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;
11075
11270
  const showFixHint = !opts.fix && fixableCount > 0;
11076
11271
  const summaryParts = [`${totalChecks} checks`];
11077
11272
  if (errorCount > 0)
@@ -11082,15 +11277,15 @@ async function runDoctor(opts = {}) {
11082
11277
  printNonTtyOutput(results, totalChecks, errorCount, warningCount, showFixHint, fixableCount);
11083
11278
  } else {
11084
11279
  if (errorCount > 0) {
11085
- close(`${summaryParts.join(" · ")} fix before using`, true);
11280
+ close(`${summaryParts.join(" \xB7 ")} \u2014 fix before using`, true);
11086
11281
  } else if (warningCount > 0) {
11087
- close(`${summaryParts.join(" · ")} advisory only, safe to run`, false, true);
11282
+ close(`${summaryParts.join(" \xB7 ")} \u2014 advisory only, safe to run`, false, true);
11088
11283
  } else {
11089
- close(import_picocolors5.default.green(`${summaryParts.join(" · ")} all passed`));
11284
+ close(import_picocolors5.default.green(`${summaryParts.join(" \xB7 ")} \u2014 all passed`));
11090
11285
  }
11091
11286
  if (showFixHint) {
11092
11287
  process.stdout.write(`
11093
- Run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to auto-fix ${fixableCount} issue(s)
11288
+ \u2192 Run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to auto-fix ${fixableCount} issue(s)
11094
11289
  `);
11095
11290
  }
11096
11291
  }
@@ -11111,21 +11306,21 @@ async function doctorCommand(opts = {}) {
11111
11306
  function printNonTtyOutput(results, totalChecks, errorCount, warningCount, showFixHint, fixableCount) {
11112
11307
  const lines = ["OneBrain Doctor", ""];
11113
11308
  for (const result of results) {
11114
- const icon = result.status === "ok" ? "[]" : result.status === "warn" ? "[!]" : "[]";
11309
+ const icon = result.status === "ok" ? "[\u2713]" : result.status === "warn" ? "[!]" : "[\u2717]";
11115
11310
  lines.push(` ${icon} ${result.check.padEnd(20)} ${result.message}`);
11116
11311
  if (result.hint)
11117
- lines.push(` ${result.hint}`);
11312
+ lines.push(` \u2192 ${result.hint}`);
11118
11313
  if (result.details)
11119
11314
  for (const d of result.details)
11120
- lines.push(` · ${d}`);
11315
+ lines.push(` \xB7 ${d}`);
11121
11316
  }
11122
11317
  lines.push("");
11123
11318
  if (errorCount > 0) {
11124
- lines.push(`Summary: ${totalChecks} checks · ${errorCount} error(s) · ${warningCount} warning(s) fix before using`);
11319
+ lines.push(`Summary: ${totalChecks} checks \xB7 ${errorCount} error(s) \xB7 ${warningCount} warning(s) \u2014 fix before using`);
11125
11320
  } else if (warningCount > 0) {
11126
- lines.push(`Summary: ${totalChecks} checks · ${warningCount} warning(s) ok to run`);
11321
+ lines.push(`Summary: ${totalChecks} checks \xB7 ${warningCount} warning(s) \u2014 ok to run`);
11127
11322
  } else {
11128
- lines.push(`Summary: ${totalChecks} checks all passed`);
11323
+ lines.push(`Summary: ${totalChecks} checks \u2014 all passed`);
11129
11324
  }
11130
11325
  if (showFixHint)
11131
11326
  lines.push(`hint: run onebrain doctor --fix to auto-fix ${fixableCount} issue(s)`);
@@ -11154,8 +11349,8 @@ function getFix(r2) {
11154
11349
  const description = deprecated.length > 0 ? `Remove deprecated keys from vault.yml: ${deprecated.join(", ")}` : "Remove deprecated keys from vault.yml";
11155
11350
  return {
11156
11351
  fn: async (vaultDir) => {
11157
- const { readFile: readFile2, writeFile: writeFile2, rename: rename2 } = await import("node:fs/promises");
11158
- const { join: join5 } = await import("node:path");
11352
+ const { readFile: readFile2, writeFile: writeFile2, rename: rename2 } = await import("fs/promises");
11353
+ const { join: join5 } = await import("path");
11159
11354
  const { parse: parse3, stringify } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
11160
11355
  const vaultYmlPath = join5(vaultDir, "vault.yml");
11161
11356
  const text = await readFile2(vaultYmlPath, "utf8");
@@ -11186,10 +11381,11 @@ function getFix(r2) {
11186
11381
  const pendingMatch = r2.message.match(/(\d+) unembedded/);
11187
11382
  const count = pendingMatch?.[1] ?? "some";
11188
11383
  return {
11384
+ advisory: true,
11189
11385
  fn: async (vaultDir) => {
11190
- const { join: join5 } = await import("node:path");
11386
+ const { join: join5 } = await import("path");
11191
11387
  const { parse: parseYaml } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
11192
- const { readFile: readFile2 } = await import("node:fs/promises");
11388
+ const { readFile: readFile2 } = await import("fs/promises");
11193
11389
  const raw = parseYaml(await readFile2(join5(vaultDir, "vault.yml"), "utf8"));
11194
11390
  const collection = raw["qmd_collection"];
11195
11391
  if (!collection)
@@ -11215,8 +11411,8 @@ function getFix(r2) {
11215
11411
  const missingStr = r2.hint.replace("Missing: ", "");
11216
11412
  return {
11217
11413
  fn: async (vaultDir) => {
11218
- const { mkdir: mkdir2 } = await import("node:fs/promises");
11219
- const { join: join5 } = await import("node:path");
11414
+ const { mkdir: mkdir2 } = await import("fs/promises");
11415
+ const { join: join5 } = await import("path");
11220
11416
  const missing = missingStr.split(", ").map((f2) => f2.trim()).filter(Boolean);
11221
11417
  for (const folder of missing) {
11222
11418
  await mkdir2(join5(vaultDir, folder), { recursive: true });
@@ -11231,24 +11427,24 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11231
11427
  const fixable = results.filter((r2) => r2.status !== "ok" && getFix(r2) !== null);
11232
11428
  if (fixable.length === 0) {
11233
11429
  if (isTTY)
11234
- barLine(`${import_picocolors5.default.green("")} Nothing to fix`);
11430
+ writeLine(`${import_picocolors5.default.green("\u25C6")} Nothing to fix`);
11235
11431
  else
11236
11432
  writeLine("nothing to fix");
11237
11433
  return;
11238
11434
  }
11239
11435
  if (isTTY) {
11240
- barBlank();
11241
- 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:`));
11242
11438
  barBlank();
11243
11439
  for (const r2 of fixable) {
11244
- barLine(` ${import_picocolors5.default.cyan("")} ${getFix(r2).description}`);
11440
+ barLine(` ${import_picocolors5.default.cyan("\u25C6")} ${getFix(r2).description}`);
11245
11441
  }
11246
11442
  barBlank();
11247
11443
  const answer = await askYesNo("Apply all?");
11248
11444
  if (answer === null || answer === false) {
11249
11445
  barLine(import_picocolors5.default.dim("No"));
11250
11446
  barBlank();
11251
- close(`No changes made run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to apply`);
11447
+ close(`No changes made \u2014 run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to apply`);
11252
11448
  return;
11253
11449
  }
11254
11450
  barLine("Yes");
@@ -11268,11 +11464,11 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11268
11464
  await fix.fn(vaultDir, registerHooksFn);
11269
11465
  fixed++;
11270
11466
  if (isTTY)
11271
- barLine(`${import_picocolors5.default.green("")} ${fix.description}`);
11467
+ barLine(`${import_picocolors5.default.green("\u25C6")} ${fix.description}`);
11272
11468
  } catch (err) {
11273
11469
  const errMsg = err instanceof Error ? err.message : String(err);
11274
11470
  if (isTTY) {
11275
- barLine(`${import_picocolors5.default.yellow("")} Could not fix ${r2.check}: ${errMsg}`);
11471
+ barLine(`${import_picocolors5.default.yellow("\u25B2")} Could not fix ${r2.check}: ${errMsg}`);
11276
11472
  } else {
11277
11473
  process.stderr.write(`doctor: fix failed for ${r2.check}: ${errMsg}
11278
11474
  `);
@@ -11282,9 +11478,9 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11282
11478
  if (isTTY) {
11283
11479
  barBlank();
11284
11480
  if (fixed > 0)
11285
- barLine(`${import_picocolors5.default.green("")} Fixed ${fixed} issue(s)`);
11481
+ barLine(`${import_picocolors5.default.green("\u25C6")} Fixed ${fixed} issue(s)`);
11286
11482
  if (unfixable.length > 0) {
11287
- barLine(`${import_picocolors5.default.yellow("")} ${unfixable.length} issue(s) require manual action:`);
11483
+ barLine(`${import_picocolors5.default.yellow("\u25B2")} ${unfixable.length} issue(s) require manual action:`);
11288
11484
  for (const r2 of unfixable) {
11289
11485
  barLine(` ${r2.check}: ${r2.hint ?? "no auto-fix available"}`);
11290
11486
  }
@@ -11304,9 +11500,9 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11304
11500
  // src/commands/init.ts
11305
11501
  var import_picocolors7 = __toESM(require_picocolors(), 1);
11306
11502
  var import_yaml4 = __toESM(require_dist(), 1);
11307
- import { mkdir as mkdir3, readFile as readFile3, readdir as readdir2, rename as rename3, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
11308
- import { homedir as homedir3 } from "node:os";
11309
- import { dirname as dirname3, join as join6 } from "node:path";
11503
+ import { mkdir as mkdir3, readFile as readFile3, readdir as readdir2, rename as rename3, stat as stat4, writeFile as writeFile3 } from "fs/promises";
11504
+ import { homedir as homedir3 } from "os";
11505
+ import { dirname as dirname3, join as join6 } from "path";
11310
11506
  init_cli_ui();
11311
11507
  var binaryVersion = resolveBinaryVersion();
11312
11508
  var STANDARD_FOLDERS = [
@@ -11372,7 +11568,7 @@ async function downloadPluginFiles(vaultDir, vaultSyncFn) {
11372
11568
  } catch {}
11373
11569
  let driftWarning;
11374
11570
  if (pluginVersion && binaryVersion !== "dev" && pluginVersion !== binaryVersion) {
11375
- driftWarning = `Plugin files v${pluginVersion}, binary v${binaryVersion} run onebrain update to sync.`;
11571
+ driftWarning = `Plugin files v${pluginVersion}, binary v${binaryVersion} \u2014 run onebrain update to sync.`;
11376
11572
  }
11377
11573
  return driftWarning !== undefined ? { skipped: true, driftWarning } : { skipped: true };
11378
11574
  }
@@ -11573,7 +11769,7 @@ async function installObsidianPlugins(vaultDir, opts) {
11573
11769
  }
11574
11770
  if (pluginFailed) {
11575
11771
  try {
11576
- const { rm: rm2 } = await import("node:fs/promises");
11772
+ const { rm: rm2 } = await import("fs/promises");
11577
11773
  await rm2(pluginDir, { recursive: true, force: true });
11578
11774
  } catch {}
11579
11775
  } else {
@@ -11655,7 +11851,7 @@ async function runInit(opts = {}) {
11655
11851
  await writeVaultYml(vaultDir);
11656
11852
  if (sp2) {
11657
11853
  await randDelay();
11658
- sp2.stop(import_picocolors7.default.dim("written"), ["update_channel: stable", "checkpoint: 15 msgs · 30 min"]);
11854
+ sp2.stop(import_picocolors7.default.dim("written"), ["update_channel: stable", "checkpoint: 15 msgs \xB7 30 min"]);
11659
11855
  } else {
11660
11856
  writeLine("vault.yml: written");
11661
11857
  }
@@ -11671,24 +11867,21 @@ async function runInit(opts = {}) {
11671
11867
  const pluginJsonPath = join6(vaultDir, ".claude", "plugins", "onebrain", ".claude-plugin", "plugin.json");
11672
11868
  const pluginFilesExist = await pathExists2(pluginJsonPath);
11673
11869
  const sp4 = pluginFilesExist ? createStep("\uD83D\uDCE6", "Plugin files") : null;
11674
- const {
11675
- skipped: pluginSkipped,
11676
- failed: pluginDownloadFailed
11677
- } = await downloadPluginFiles(vaultDir, vaultSyncFn);
11870
+ const { skipped: pluginSkipped, failed: pluginDownloadFailed } = await downloadPluginFiles(vaultDir, vaultSyncFn);
11678
11871
  result.pluginSkipped = pluginSkipped;
11679
11872
  if (sp4) {
11680
11873
  if (pluginDownloadFailed) {
11681
11874
  sp4.stop("download failed");
11682
11875
  } else {
11683
11876
  const { skills, agents } = await countPluginContents(vaultDir);
11684
- sp4.stop(import_picocolors7.default.dim("already installed"), [`${skills} skills · ${agents} agents`]);
11877
+ sp4.stop(import_picocolors7.default.dim("already installed"), [`${skills} skills \xB7 ${agents} agents`]);
11685
11878
  }
11686
11879
  } else if (isTTY) {
11687
11880
  if (!pluginDownloadFailed) {
11688
11881
  const { skills, agents } = await countPluginContents(vaultDir);
11689
11882
  dotLine("\uD83D\uDCE6", "Plugin files");
11690
11883
  barLine(import_picocolors7.default.dim("downloaded"));
11691
- barLine(` · ${skills} skills · ${agents} agents`);
11884
+ barLine(` \xB7 ${skills} skills \xB7 ${agents} agents`);
11692
11885
  barBlank();
11693
11886
  }
11694
11887
  } else {
@@ -11702,7 +11895,7 @@ async function runInit(opts = {}) {
11702
11895
  if (isTTY) {
11703
11896
  close("Could not download plugin files. Check your internet connection and try again.", true);
11704
11897
  } else {
11705
- writeLine("error: vault-sync failed run onebrain update to download plugin files");
11898
+ writeLine("error: vault-sync failed \u2014 run onebrain update to download plugin files");
11706
11899
  }
11707
11900
  return result;
11708
11901
  }
@@ -11733,7 +11926,9 @@ async function runInit(opts = {}) {
11733
11926
  result.pluginRegistrationSkipped = pluginRegistrationSkipped;
11734
11927
  if (sp5) {
11735
11928
  await randDelay();
11736
- sp5.stop(import_picocolors7.default.dim(pluginRegistrationSkipped ? "skipped" : "registered"), [`source: ${pluginRegistrationSkipped ? "marketplace" : "local"}`]);
11929
+ sp5.stop(import_picocolors7.default.dim(pluginRegistrationSkipped ? "skipped" : "registered"), [
11930
+ `source: ${pluginRegistrationSkipped ? "marketplace" : "local"}`
11931
+ ]);
11737
11932
  } else {
11738
11933
  writeLine(`plugin: ${pluginRegistrationSkipped ? "skipped (marketplace)" : "registered"}`);
11739
11934
  }
@@ -11749,20 +11944,20 @@ async function runInit(opts = {}) {
11749
11944
  }
11750
11945
  if (sp6) {
11751
11946
  await randDelay();
11752
- sp6.stop(hooksOk ? undefined : "not registered run onebrain update", hooksOk ? ["Stop PostCompact ", "Bash(onebrain *) "] : undefined);
11947
+ sp6.stop(hooksOk ? undefined : "not registered \u2014 run onebrain update", hooksOk ? ["Stop \u2713 PostCompact \u2713", "Bash(onebrain *) \u2713"] : undefined);
11753
11948
  } else {
11754
- writeLine(`hooks: ${hooksOk ? "ok" : "warning hooks not registered; run onebrain update"}`);
11949
+ writeLine(`hooks: ${hooksOk ? "ok" : "warning \u2014 hooks not registered; run onebrain update"}`);
11755
11950
  }
11756
11951
  result.ok = true;
11757
11952
  result.exitCode = 0;
11758
11953
  if (isTTY) {
11759
- barLine(import_picocolors7.default.dim(`─── Next steps ${"".repeat(25)}`));
11954
+ barLine(import_picocolors7.default.dim(`\u2500\u2500\u2500 Next steps ${"\u2500".repeat(25)}`));
11760
11955
  barBlank();
11761
- barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("1"))} \uD83D\uDCC1 Open Obsidian open this folder as vault`);
11956
+ barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("1"))} \uD83D\uDCC1 Open Obsidian \u2192 open this folder as vault`);
11762
11957
  barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("2"))} \uD83E\uDD16 Run ${import_picocolors7.default.cyan("claude")}`);
11763
11958
  barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("3"))} \uD83E\uDDE0 Type ${import_picocolors7.default.cyan("/onboarding")} to personalize`);
11764
11959
  barBlank();
11765
- close(`✨ ${import_picocolors7.default.bold("Ready")} ${import_picocolors7.default.cyan("/onboarding")}`);
11960
+ close(`\u2728 ${import_picocolors7.default.bold("Ready")} \u2014 ${import_picocolors7.default.cyan("/onboarding")}`);
11766
11961
  } else {
11767
11962
  writeLine("done: run /onboarding in Claude to finish setup");
11768
11963
  }
@@ -11776,9 +11971,9 @@ async function initCommand(opts = {}) {
11776
11971
  }
11777
11972
 
11778
11973
  // src/commands/internal/checkpoint.ts
11779
- import { readFileSync, readdirSync, writeFileSync } from "node:fs";
11780
- import { tmpdir as osTmpdir } from "node:os";
11781
- import { join as join7 } from "node:path";
11974
+ import { readFileSync, readdirSync, writeFileSync } from "fs";
11975
+ import { tmpdir as osTmpdir } from "os";
11976
+ import { join as join7 } from "path";
11782
11977
  var SKIP_WINDOW = 60;
11783
11978
  var MIN_ACTIVITY = 2;
11784
11979
  var PRECOMPACT_RECENCY = 300;
@@ -11954,8 +12149,8 @@ async function checkpointCommand(mode, token, vaultRoot) {
11954
12149
  // src/commands/internal/migrate.ts
11955
12150
  init_lib();
11956
12151
  var import_yaml5 = __toESM(require_dist(), 1);
11957
- import { readFile as readFile4, readdir as readdir3, writeFile as writeFile4 } from "node:fs/promises";
11958
- import { join as join8 } from "node:path";
12152
+ import { readFile as readFile4, readdir as readdir3, writeFile as writeFile4 } from "fs/promises";
12153
+ import { join as join8 } from "path";
11959
12154
  function parseFrontmatterWithRest(rawText) {
11960
12155
  const text = rawText.replace(/\r\n/g, `
11961
12156
  `);
@@ -12024,7 +12219,7 @@ async function runBackfillRecapped(logsFolder, cutoffDate) {
12024
12219
  const content = await readFile4(fpath, "utf8");
12025
12220
  const parsed = parseFrontmatterWithRest(content);
12026
12221
  if (!parsed) {
12027
- process.stderr.write(`migrate: ${fname} malformed frontmatter
12222
+ process.stderr.write(`migrate: ${fname} \u2014 malformed frontmatter
12028
12223
  `);
12029
12224
  skipped++;
12030
12225
  continue;
@@ -12071,8 +12266,8 @@ async function migrateCommand(migrationName, cutoffDate, vaultDir) {
12071
12266
 
12072
12267
  // src/commands/internal/orphan-scan.ts
12073
12268
  var import_yaml6 = __toESM(require_dist(), 1);
12074
- import { readFile as readFile5, readdir as readdir4 } from "node:fs/promises";
12075
- import { join as join9 } from "node:path";
12269
+ import { readFile as readFile5, readdir as readdir4 } from "fs/promises";
12270
+ import { join as join9 } from "path";
12076
12271
  function parseFrontmatter(rawText) {
12077
12272
  const text = rawText.replace(/\r\n/g, `
12078
12273
  `);
@@ -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);
@@ -12206,332 +12395,70 @@ async function qmdReindexCommand(vaultRoot) {
12206
12395
  }
12207
12396
  }
12208
12397
 
12209
- // src/commands/internal/register-hooks.ts
12210
- init_dist2();
12398
+ // src/index.ts
12399
+ init_register_hooks();
12400
+
12401
+ // src/commands/internal/session-init.ts
12211
12402
  init_lib();
12212
- init_harness();
12213
- var import_picocolors8 = __toESM(require_picocolors(), 1);
12214
- import { mkdir as mkdir4, readFile as readFile6, rename as rename4, writeFile as writeFile5 } from "node:fs/promises";
12215
- import { homedir as homedir4 } from "node:os";
12216
- import { dirname as dirname4, join as join10 } from "node:path";
12217
- var HOOK_COMMANDS2 = {
12218
- Stop: "onebrain checkpoint stop",
12219
- PostCompact: "onebrain checkpoint postcompact"
12220
- };
12221
- var HOOK_EVENTS2 = ["Stop", "PostCompact"];
12222
- var STALE_HOOK_COMMANDS2 = {
12223
- PreCompact: "onebrain checkpoint precompact"
12224
- };
12225
- var PERMISSIONS_TO_ADD2 = [
12226
- "Read",
12227
- "Write",
12228
- "Edit",
12229
- "Glob",
12230
- "Grep",
12231
- "Bash(git *)",
12232
- "Bash(bun *)",
12233
- "Bash(gh *)",
12234
- "Bash(node *)",
12235
- "Bash(onebrain *)",
12236
- "Bash(bun install -g @onebrain-ai/cli*)",
12237
- "Bash(npm install -g @onebrain-ai/cli*)",
12238
- "WebFetch",
12239
- "WebSearch"
12403
+ import { unlink as unlink2 } from "fs/promises";
12404
+ import { tmpdir as osTmpdir2 } from "os";
12405
+ import { join as join10 } from "path";
12406
+ var DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
12407
+ var MONTH_NAMES = [
12408
+ "Jan",
12409
+ "Feb",
12410
+ "Mar",
12411
+ "Apr",
12412
+ "May",
12413
+ "Jun",
12414
+ "Jul",
12415
+ "Aug",
12416
+ "Sep",
12417
+ "Oct",
12418
+ "Nov",
12419
+ "Dec"
12240
12420
  ];
12241
- var ONEBRAIN_MARKER2 = "# onebrain";
12242
- var PATH_EXPORT2 = 'export PATH="$HOME/.bun/bin:$HOME/.npm-global/bin:$PATH"';
12243
- async function readSettings2(settingsPath) {
12244
- try {
12245
- const text = await readFile6(settingsPath, "utf8");
12246
- return JSON.parse(text);
12247
- } catch (err) {
12248
- if (err.code === "ENOENT")
12249
- return {};
12250
- throw err;
12251
- }
12252
- }
12253
- async function writeSettings2(settingsPath, settings) {
12254
- await mkdir4(dirname4(settingsPath), { recursive: true });
12255
- const tmpPath = `${settingsPath}.tmp`;
12256
- await writeFile5(tmpPath, JSON.stringify(settings, null, 4), "utf8");
12257
- await rename4(tmpPath, settingsPath);
12421
+ function formatDatetime(date) {
12422
+ const dow = DAY_NAMES[date.getDay()];
12423
+ const day = String(date.getDate()).padStart(2, "0");
12424
+ const mon = MONTH_NAMES[date.getMonth()];
12425
+ const year = date.getFullYear();
12426
+ const hh = String(date.getHours()).padStart(2, "0");
12427
+ const mm = String(date.getMinutes()).padStart(2, "0");
12428
+ return `${dow} \xB7 ${day} ${mon} ${year} \xB7 ${hh}:${mm}`;
12258
12429
  }
12259
- function checkHookPresence2(groups, targetCmd) {
12260
- let foundMigrate = false;
12261
- for (const group of groups) {
12262
- for (const entry of group.hooks ?? []) {
12263
- const cmd = entry.command ?? "";
12264
- if (cmd === targetCmd)
12265
- return "found";
12266
- if (cmd.includes("checkpoint-hook.sh"))
12267
- foundMigrate = true;
12268
- }
12430
+ async function resolveSessionToken(tmpDir = osTmpdir2()) {
12431
+ const wtSession = process.env["WT_SESSION"];
12432
+ if (wtSession) {
12433
+ const stripped = wtSession.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
12434
+ if (stripped.length > 0)
12435
+ return stripped;
12269
12436
  }
12270
- return foundMigrate ? "migrate" : "missing";
12271
- }
12272
- function applyHooks2(settings) {
12273
- if (!settings.hooks)
12274
- settings.hooks = {};
12275
- const hooks = settings.hooks;
12276
- const result = {};
12277
- for (const [event, staleCmd] of Object.entries(STALE_HOOK_COMMANDS2)) {
12278
- if (!hooks[event])
12279
- continue;
12280
- hooks[event] = hooks[event].filter((group) => !group.hooks?.some((entry) => entry.command === staleCmd));
12281
- if (hooks[event].length === 0)
12282
- delete hooks[event];
12437
+ const tmuxPane = process.env["TMUX_PANE"];
12438
+ if (tmuxPane) {
12439
+ const stripped = tmuxPane.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
12440
+ if (stripped.length > 0)
12441
+ return stripped;
12283
12442
  }
12284
- for (const event of HOOK_EVENTS2) {
12285
- const cmd = HOOK_COMMANDS2[event];
12286
- if (!cmd)
12287
- continue;
12288
- if (!hooks[event])
12289
- hooks[event] = [];
12290
- const groups = hooks[event];
12291
- const presence = checkHookPresence2(groups, cmd);
12292
- if (presence === "found") {
12293
- result[event] = "ok";
12294
- } else if (presence === "migrate") {
12295
- for (const group of groups) {
12296
- if (group.matcher === undefined)
12297
- group.matcher = "";
12298
- for (const entry of group.hooks ?? []) {
12299
- if ((entry.command ?? "").includes("checkpoint-hook.sh")) {
12300
- entry.command = cmd;
12301
- if (!entry.type)
12302
- entry.type = "command";
12303
- }
12304
- }
12305
- }
12306
- result[event] = "migrated";
12307
- } else {
12308
- groups.push({ matcher: "", hooks: [{ type: "command", command: cmd }] });
12309
- result[event] = "added";
12310
- }
12443
+ const termSessionId = process.env["TERM_SESSION_ID"];
12444
+ if (termSessionId) {
12445
+ const stripped = termSessionId.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
12446
+ if (stripped.length > 0)
12447
+ return stripped;
12311
12448
  }
12312
- return result;
12313
- }
12314
- var QMD_CMD2 = "onebrain qmd-reindex";
12315
- var QMD_MATCHER2 = "Write|Edit";
12316
- function applyQmdHook2(settings) {
12317
- if (!settings.hooks)
12318
- settings.hooks = {};
12319
- if (!settings.hooks["PostToolUse"])
12320
- settings.hooks["PostToolUse"] = [];
12321
- const groups = settings.hooks["PostToolUse"];
12322
- const already = groups.some((g) => g.hooks?.some((h) => h.command === QMD_CMD2));
12323
- if (already)
12324
- return "ok";
12325
- groups.push({ matcher: QMD_MATCHER2, hooks: [{ type: "command", command: QMD_CMD2 }] });
12326
- return "added";
12327
- }
12328
- function applyPermissions2(settings) {
12329
- if (!settings.permissions)
12330
- settings.permissions = {};
12331
- if (!settings.permissions.allow)
12332
- settings.permissions.allow = [];
12333
- const allow = settings.permissions.allow;
12334
- const added = [];
12335
- for (const perm of PERMISSIONS_TO_ADD2) {
12336
- if (!allow.includes(perm)) {
12337
- allow.push(perm);
12338
- added.push(perm);
12339
- }
12340
- }
12341
- return added;
12342
- }
12343
- async function registerGeminiHooks2(vaultRoot) {
12344
- const geminiSettingsPath = join10(vaultRoot, ".gemini", "settings.json");
12345
- try {
12346
- const text = await readFile6(geminiSettingsPath, "utf8");
12347
- const settings = JSON.parse(text);
12348
- applyHooks2(settings);
12349
- await writeSettings2(geminiSettingsPath, settings);
12350
- } catch (err) {
12351
- if (err.code !== "ENOENT") {
12352
- process.stderr.write(`register-hooks: gemini warning: ${err instanceof Error ? err.message : String(err)}
12353
- `);
12354
- }
12355
- }
12356
- }
12357
- async function registerDirectPath2() {
12358
- const home = homedir4();
12359
- const candidates = [join10(home, ".zshrc"), join10(home, ".bashrc"), join10(home, ".profile")];
12360
- let profilePath;
12361
- for (const candidate of candidates) {
12362
- try {
12363
- await readFile6(candidate, "utf8");
12364
- profilePath = candidate;
12365
- break;
12366
- } catch {}
12367
- }
12368
- if (!profilePath)
12369
- return;
12370
- const content = await readFile6(profilePath, "utf8");
12371
- if (content.includes(ONEBRAIN_MARKER2))
12372
- return;
12373
- const updated = `${content}
12374
- ${ONEBRAIN_MARKER2}
12375
- ${PATH_EXPORT2}
12376
- `;
12377
- const tmpPath = `${profilePath}.tmp`;
12378
- await writeFile5(tmpPath, updated, "utf8");
12379
- await rename4(tmpPath, profilePath);
12380
- }
12381
- async function runRegisterHooks2(opts = {}) {
12382
- const vaultRoot = opts.vaultDir ?? process.cwd();
12383
- const isTTY = opts.isTTY ?? process.stdout.isTTY ?? false;
12384
- const harness = await detectHarness(vaultRoot);
12385
- let qmdCollection;
12386
- try {
12387
- const vaultConfig = await loadVaultConfig(vaultRoot);
12388
- qmdCollection = vaultConfig.qmd_collection;
12389
- } catch (err) {
12390
- if (err.code !== "ENOENT") {
12391
- process.stderr.write(`register-hooks: warning: could not read vault.yml: ${err instanceof Error ? err.message : String(err)}
12392
- `);
12393
- }
12394
- }
12395
- const result = {
12396
- ok: false,
12397
- hooks: {},
12398
- permissionsAdded: []
12399
- };
12400
- const settingsPath = join10(vaultRoot, ".claude", "settings.json");
12401
- const note = (msg) => {
12402
- if (opts.silent)
12403
- return;
12404
- process.stdout.write(`register-hooks: ${msg}
12405
- `);
12406
- };
12407
- let hooksSpinner = null;
12408
- let permSpinner = null;
12409
- try {
12410
- if (harness === "claude") {
12411
- hooksSpinner = isTTY ? L2() : null;
12412
- hooksSpinner?.start("Registering hooks...");
12413
- const settings = await readSettings2(settingsPath);
12414
- result.hooks = applyHooks2(settings);
12415
- let qmdStatus;
12416
- if (qmdCollection)
12417
- qmdStatus = applyQmdHook2(settings);
12418
- if (isTTY) {
12419
- const parts = HOOK_EVENTS2.map((e2) => {
12420
- const status = result.hooks[e2];
12421
- const icon = import_picocolors8.default.green(status === "ok" ? "✓" : status === "migrated" ? "↑" : "+");
12422
- return `${import_picocolors8.default.dim(e2)} ${icon}`;
12423
- });
12424
- if (qmdStatus)
12425
- parts.push(`${import_picocolors8.default.dim("PostToolUse")} ${import_picocolors8.default.green(qmdStatus === "ok" ? "✓" : "+")}`);
12426
- hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
12427
- } else {
12428
- const hookLine = HOOK_EVENTS2.map((e2) => {
12429
- const status = result.hooks[e2];
12430
- const label = status === "ok" || status === "added" || status === "migrated" ? "ok" : status ?? "ok";
12431
- return `${e2} ${label}`;
12432
- }).join(" ");
12433
- note(hookLine);
12434
- if (qmdStatus)
12435
- note(`PostToolUse ${qmdStatus === "added" ? "added" : "ok"}`);
12436
- }
12437
- permSpinner = isTTY ? L2() : null;
12438
- permSpinner?.start("Updating permissions...");
12439
- result.permissionsAdded = applyPermissions2(settings);
12440
- await writeSettings2(settingsPath, settings);
12441
- permSpinner?.stop("Permissions ok");
12442
- if (!isTTY)
12443
- note("permissions ok");
12444
- }
12445
- if (harness === "gemini") {
12446
- await registerGeminiHooks2(vaultRoot);
12447
- }
12448
- if (harness === "direct") {
12449
- await registerDirectPath2();
12450
- }
12451
- result.ok = true;
12452
- if (!isTTY) {
12453
- note("done");
12454
- }
12455
- } catch (err) {
12456
- hooksSpinner?.stop("Registration failed");
12457
- permSpinner?.stop("Permissions failed");
12458
- const msg = err instanceof Error ? err.message : String(err);
12459
- result.error = msg;
12460
- process.stderr.write(`register-hooks: error: ${msg}
12461
- `);
12462
- }
12463
- return result;
12464
- }
12465
- async function registerHooksCommand2(vaultDir) {
12466
- const result = await runRegisterHooks2({
12467
- ...vaultDir !== undefined ? { vaultDir } : {}
12468
- });
12469
- if (!result.ok) {
12470
- process.exit(1);
12471
- }
12472
- }
12473
-
12474
- // src/commands/internal/session-init.ts
12475
- init_lib();
12476
- import { unlink as unlink2 } from "node:fs/promises";
12477
- import { tmpdir as osTmpdir2 } from "node:os";
12478
- import { join as join11 } from "node:path";
12479
- var DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
12480
- var MONTH_NAMES = [
12481
- "Jan",
12482
- "Feb",
12483
- "Mar",
12484
- "Apr",
12485
- "May",
12486
- "Jun",
12487
- "Jul",
12488
- "Aug",
12489
- "Sep",
12490
- "Oct",
12491
- "Nov",
12492
- "Dec"
12493
- ];
12494
- function formatDatetime(date) {
12495
- const dow = DAY_NAMES[date.getDay()];
12496
- const day = String(date.getDate()).padStart(2, "0");
12497
- const mon = MONTH_NAMES[date.getMonth()];
12498
- const year = date.getFullYear();
12499
- const hh = String(date.getHours()).padStart(2, "0");
12500
- const mm = String(date.getMinutes()).padStart(2, "0");
12501
- return `${dow} · ${day} ${mon} ${year} · ${hh}:${mm}`;
12502
- }
12503
- async function resolveSessionToken(tmpDir = osTmpdir2()) {
12504
- const wtSession = process.env["WT_SESSION"];
12505
- if (wtSession) {
12506
- const stripped = wtSession.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
12507
- if (stripped.length > 0)
12508
- return stripped;
12509
- }
12510
- const tmuxPane = process.env["TMUX_PANE"];
12511
- if (tmuxPane) {
12512
- const stripped = tmuxPane.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
12513
- if (stripped.length > 0)
12514
- return stripped;
12515
- }
12516
- const termSessionId = process.env["TERM_SESSION_ID"];
12517
- if (termSessionId) {
12518
- const stripped = termSessionId.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
12519
- if (stripped.length > 0)
12520
- return stripped;
12521
- }
12522
- const today = new Date;
12523
- const yyyymmdd = [
12524
- today.getFullYear(),
12525
- String(today.getMonth() + 1).padStart(2, "0"),
12526
- String(today.getDate()).padStart(2, "0")
12527
- ].join("");
12528
- const cacheFile = join11(tmpDir, `onebrain-day-${yyyymmdd}.token`);
12529
- const cacheExists = await Bun.file(cacheFile).exists();
12530
- if (cacheExists) {
12531
- const cached = (await Bun.file(cacheFile).text()).trim();
12532
- const n = Number(cached);
12533
- if (!Number.isNaN(n) && n > 1)
12534
- return cached;
12449
+ const today = new Date;
12450
+ const yyyymmdd = [
12451
+ today.getFullYear(),
12452
+ String(today.getMonth() + 1).padStart(2, "0"),
12453
+ String(today.getDate()).padStart(2, "0")
12454
+ ].join("");
12455
+ const cacheFile = join10(tmpDir, `onebrain-day-${yyyymmdd}.token`);
12456
+ const cacheExists = await Bun.file(cacheFile).exists();
12457
+ if (cacheExists) {
12458
+ const cached = (await Bun.file(cacheFile).text()).trim();
12459
+ const n = Number(cached);
12460
+ if (!Number.isNaN(n) && n > 1)
12461
+ return cached;
12535
12462
  }
12536
12463
  const ppid = process.ppid;
12537
12464
  if (ppid !== undefined && ppid > 1) {
@@ -12577,7 +12504,7 @@ async function resolveSessionToken(tmpDir = osTmpdir2()) {
12577
12504
  async function cleanStaleStateFile(token, tmpDir) {
12578
12505
  try {
12579
12506
  const processStartMs = Date.now() - performance.now();
12580
- const stateFile = join11(tmpDir, `onebrain-${token}.state`);
12507
+ const stateFile = join10(tmpDir, `onebrain-${token}.state`);
12581
12508
  const f2 = Bun.file(stateFile);
12582
12509
  const exists = await f2.exists();
12583
12510
  if (!exists)
@@ -12642,523 +12569,11 @@ async function sessionInitCommand(vaultRoot) {
12642
12569
  `);
12643
12570
  }
12644
12571
 
12645
- // src/commands/internal/vault-sync.ts
12646
- init_dist2();
12647
- init_cli_ui();
12648
- init_harness();
12649
- var import_picocolors9 = __toESM(require_picocolors(), 1);
12650
- var import_yaml7 = __toESM(require_dist(), 1);
12651
- import {
12652
- mkdir as mkdir5,
12653
- mkdtemp as mkdtemp2,
12654
- readFile as readFile7,
12655
- readdir as readdir5,
12656
- rename as rename5,
12657
- rm as rm2,
12658
- stat as stat5,
12659
- unlink as unlink3,
12660
- writeFile as writeFile6
12661
- } from "node:fs/promises";
12662
- import { homedir as homedir5, tmpdir as tmpdir2 } from "node:os";
12663
- import { dirname as dirname5, join as join12, relative as relative2 } from "node:path";
12664
- function resolveBranch2(updateChannel) {
12665
- return updateChannel === "stable" ? "main" : "next";
12666
- }
12667
- async function downloadTarball2(branch, fetchFn) {
12668
- const url = `https://api.github.com/repos/kengio/onebrain/tarball/${branch}`;
12669
- const response = await fetchFn(url);
12670
- if (!response.ok) {
12671
- const hints = {
12672
- 403: " — check repo permissions or GITHUB_TOKEN",
12673
- 404: " — repo or branch not found",
12674
- 429: " — rate limited, wait and retry"
12675
- };
12676
- const hint = hints[response.status] ?? "";
12677
- throw new Error(`HTTP ${response.status} downloading tarball from ${url}${hint}`);
12678
- }
12679
- const tarball = await response.arrayBuffer();
12680
- const tmpDir = await mkdtemp2(join12(tmpdir2(), "onebrain-sync-"));
12681
- return { tarball, tmpDir };
12682
- }
12683
- async function extractTarball2(tarball, destDir) {
12684
- const tarPath = join12(destDir, "bundle.tar.gz");
12685
- await writeFile6(tarPath, Buffer.from(tarball));
12686
- const proc = Bun.spawn(["tar", "-xzf", tarPath, "-C", destDir], {
12687
- stdout: "pipe",
12688
- stderr: "pipe"
12689
- });
12690
- const exitCode = await proc.exited;
12691
- if (exitCode !== 0) {
12692
- const errText = await new Response(proc.stderr).text();
12693
- throw new Error(`tar extraction failed (exit ${exitCode}): ${errText.trim()}`);
12694
- }
12695
- await unlink3(tarPath);
12696
- const entries = await readdir5(destDir);
12697
- const topLevel = entries.find((e2) => e2 !== "bundle.tar.gz");
12698
- if (!topLevel) {
12699
- throw new Error("Extracted tarball contains no top-level directory");
12700
- }
12701
- return join12(destDir, topLevel);
12702
- }
12703
- async function listFilesRecursive2(dir) {
12704
- const results = [];
12705
- const queue = [dir];
12706
- while (queue.length > 0) {
12707
- const current = queue.pop();
12708
- let entries;
12709
- try {
12710
- entries = await readdir5(current);
12711
- } catch {
12712
- continue;
12713
- }
12714
- for (const entry of entries) {
12715
- const fullPath = join12(current, entry);
12716
- let s;
12717
- try {
12718
- s = await stat5(fullPath);
12719
- } catch {
12720
- continue;
12721
- }
12722
- if (s.isDirectory()) {
12723
- queue.push(fullPath);
12724
- } else {
12725
- results.push(fullPath);
12726
- }
12727
- }
12728
- }
12729
- return results;
12730
- }
12731
- async function syncPluginFiles2(extractedDir, vaultRoot, unlinkFn = unlink3) {
12732
- const sourcePlugin = join12(extractedDir, ".claude", "plugins", "onebrain");
12733
- const destPlugin = join12(vaultRoot, ".claude", "plugins", "onebrain");
12734
- await mkdir5(destPlugin, { recursive: true });
12735
- const sourceFiles = await listFilesRecursive2(sourcePlugin);
12736
- const sourceRelSet = new Set(sourceFiles.map((f2) => relative2(sourcePlugin, f2)));
12737
- const destFiles = await listFilesRecursive2(destPlugin);
12738
- const destRelSet = new Set(destFiles.map((f2) => relative2(destPlugin, f2)));
12739
- const staleRels = [];
12740
- for (const rel of destRelSet) {
12741
- if (!sourceRelSet.has(rel)) {
12742
- staleRels.push(rel);
12743
- }
12744
- }
12745
- let filesAdded = 0;
12746
- for (const srcPath of sourceFiles) {
12747
- const rel = relative2(sourcePlugin, srcPath);
12748
- const destPath = join12(destPlugin, rel);
12749
- await mkdir5(dirname5(destPath), { recursive: true });
12750
- const content = await readFile7(srcPath);
12751
- await writeFile6(destPath, content);
12752
- filesAdded++;
12753
- }
12754
- let filesRemoved = 0;
12755
- for (const rel of staleRels) {
12756
- const destPath = join12(destPlugin, rel);
12757
- try {
12758
- await unlinkFn(destPath);
12759
- filesRemoved++;
12760
- } catch {}
12761
- }
12762
- return { filesAdded, filesRemoved };
12763
- }
12764
- async function copyRootDocs2(extractedDir, vaultRoot) {
12765
- const docs = ["CONTRIBUTING.md", "CHANGELOG.md", "PLUGIN-CHANGELOG.md"];
12766
- for (const doc of docs) {
12767
- const srcPath = join12(extractedDir, doc);
12768
- const destPath = join12(vaultRoot, doc);
12769
- try {
12770
- const content = await readFile7(srcPath);
12771
- await writeFile6(destPath, content);
12772
- } catch {}
12773
- }
12774
- }
12775
- async function mergeHarnessFile2(extractedDir, vaultRoot, filename) {
12776
- const srcPath = join12(extractedDir, filename);
12777
- const destPath = join12(vaultRoot, filename);
12778
- let repoText;
12779
- try {
12780
- repoText = await readFile7(srcPath, "utf8");
12781
- } catch {
12782
- return 0;
12783
- }
12784
- let vaultText;
12785
- try {
12786
- vaultText = await readFile7(destPath, "utf8");
12787
- } catch {
12788
- await writeFile6(destPath, repoText, "utf8");
12789
- return repoText.split(`
12790
- `).filter((l2) => l2.startsWith("@")).length;
12791
- }
12792
- const vaultAtSet = new Set(vaultText.split(`
12793
- `).filter((l2) => l2.startsWith("@")).map((l2) => l2.trim()));
12794
- const newImports = repoText.split(`
12795
- `).filter((l2) => l2.startsWith("@") && !vaultAtSet.has(l2.trim())).map((l2) => l2.trimEnd());
12796
- if (newImports.length === 0) {
12797
- return 0;
12798
- }
12799
- const vaultLines = vaultText.split(`
12800
- `);
12801
- const lastAtIdx = vaultLines.reduce((acc, l2, i) => l2.startsWith("@") ? i : acc, -1);
12802
- if (lastAtIdx >= 0) {
12803
- vaultLines.splice(lastAtIdx, 0, ...newImports);
12804
- } else {
12805
- vaultLines.push("", ...newImports);
12806
- }
12807
- const merged = vaultLines.join(`
12808
- `);
12809
- await writeFile6(destPath, merged, "utf8");
12810
- return newImports.length;
12811
- }
12812
- async function mergeHarnessFiles2(extractedDir, vaultRoot) {
12813
- const harnessFiles = ["CLAUDE.md", "GEMINI.md", "AGENTS.md"];
12814
- let totalImportsAdded = 0;
12815
- const results = await Promise.all(harnessFiles.map((f2) => mergeHarnessFile2(extractedDir, vaultRoot, f2)));
12816
- for (const n of results) {
12817
- totalImportsAdded += n;
12818
- }
12819
- return totalImportsAdded;
12820
- }
12821
- async function updateVaultYml2(vaultRoot, updateChannel) {
12822
- const vaultYmlPath = join12(vaultRoot, "vault.yml");
12823
- let text;
12824
- try {
12825
- text = await readFile7(vaultYmlPath, "utf8");
12826
- } catch {
12827
- text = "";
12828
- }
12829
- const raw = import_yaml7.parse(text) ?? {};
12830
- raw["update_channel"] = updateChannel;
12831
- const updated = import_yaml7.stringify(raw, { lineWidth: 0 });
12832
- const tmpPath = `${vaultYmlPath}.tmp`;
12833
- await writeFile6(tmpPath, updated, "utf8");
12834
- await rename5(tmpPath, vaultYmlPath);
12835
- }
12836
- async function readPluginVersion2(vaultRoot) {
12837
- const pluginJsonPath = join12(vaultRoot, ".claude", "plugins", "onebrain", ".claude-plugin", "plugin.json");
12838
- try {
12839
- const text = await readFile7(pluginJsonPath, "utf8");
12840
- const parsed = JSON.parse(text);
12841
- return typeof parsed["version"] === "string" ? parsed["version"] : "unknown";
12842
- } catch {
12843
- return "unknown";
12844
- }
12845
- }
12846
- async function pinToVault2(vaultRoot, installedPluginsPath, installedPluginsCacheDir) {
12847
- let text;
12848
- try {
12849
- text = await readFile7(installedPluginsPath, "utf8");
12850
- } catch {
12851
- return { skipped: true };
12852
- }
12853
- let data;
12854
- try {
12855
- data = JSON.parse(text);
12856
- } catch {
12857
- throw new Error(`installed_plugins.json is not valid JSON: ${installedPluginsPath}`);
12858
- }
12859
- const plugins = data["plugins"];
12860
- if (!plugins) {
12861
- return { skipped: true };
12862
- }
12863
- const onebrainKeys = Object.keys(plugins).filter((k2) => k2.startsWith("onebrain@"));
12864
- if (onebrainKeys.length === 0) {
12865
- return { skipped: true };
12866
- }
12867
- const vaultPluginDir = join12(vaultRoot, ".claude", "plugins", "onebrain");
12868
- const pluginVersion = await readPluginVersion2(vaultRoot);
12869
- const cacheDir = installedPluginsCacheDir ?? join12(dirname5(installedPluginsPath), "cache");
12870
- const hasMarketplace = onebrainKeys.some((k2) => {
12871
- const entries = plugins[k2];
12872
- return entries.some((e2) => e2["source"] === "marketplace");
12873
- });
12874
- if (hasMarketplace) {
12875
- return { skipped: true };
12876
- }
12877
- let changed = false;
12878
- for (const key of onebrainKeys) {
12879
- const entries = plugins[key];
12880
- for (const entry of entries) {
12881
- const installPath = entry["installPath"];
12882
- if (typeof installPath !== "string") {
12883
- continue;
12884
- }
12885
- let inCache = false;
12886
- try {
12887
- inCache = installPath.startsWith(`${cacheDir}/`) || installPath === cacheDir;
12888
- } catch {
12889
- inCache = false;
12890
- }
12891
- if (!inCache) {
12892
- continue;
12893
- }
12894
- entry["installPath"] = vaultPluginDir;
12895
- entry["version"] = pluginVersion;
12896
- changed = true;
12897
- }
12898
- }
12899
- if (!changed) {
12900
- return { skipped: false };
12901
- }
12902
- const tmpPath = `${installedPluginsPath}.tmp`;
12903
- await writeFile6(tmpPath, JSON.stringify(data, null, 4), "utf8");
12904
- await rename5(tmpPath, installedPluginsPath);
12905
- return { skipped: false };
12906
- }
12907
- async function cleanPluginCache2(installedPluginsPath, installedPluginsCacheDir) {
12908
- const cacheDir = installedPluginsCacheDir ?? join12(dirname5(installedPluginsPath), "cache");
12909
- try {
12910
- await stat5(cacheDir);
12911
- } catch {
12912
- return 0;
12913
- }
12914
- const onebrainDirs = [];
12915
- try {
12916
- const text = await readFile7(installedPluginsPath, "utf8");
12917
- const data = JSON.parse(text);
12918
- const plugins = data["plugins"];
12919
- if (plugins) {
12920
- for (const key of Object.keys(plugins)) {
12921
- if (!key.startsWith("onebrain@"))
12922
- continue;
12923
- const marketplace = key.split("@")[1];
12924
- const candidate = join12(cacheDir, marketplace, "onebrain");
12925
- try {
12926
- await stat5(candidate);
12927
- onebrainDirs.push(candidate);
12928
- } catch {}
12929
- }
12930
- }
12931
- } catch {}
12932
- if (onebrainDirs.length === 0) {
12933
- try {
12934
- const marketplaceDirs = await readdir5(cacheDir);
12935
- for (const mp of marketplaceDirs) {
12936
- const candidate = join12(cacheDir, mp, "onebrain");
12937
- try {
12938
- await stat5(candidate);
12939
- onebrainDirs.push(candidate);
12940
- } catch {}
12941
- }
12942
- } catch {
12943
- return 0;
12944
- }
12945
- }
12946
- let removed = 0;
12947
- for (const pluginDir of onebrainDirs) {
12948
- let versionDirs;
12949
- try {
12950
- versionDirs = await readdir5(pluginDir);
12951
- } catch {
12952
- continue;
12953
- }
12954
- for (const versionDir of versionDirs) {
12955
- const fullPath = join12(pluginDir, versionDir);
12956
- try {
12957
- const s = await stat5(fullPath);
12958
- if (s.isDirectory()) {
12959
- await rm2(fullPath, { recursive: true, force: true });
12960
- removed++;
12961
- }
12962
- } catch {}
12963
- }
12964
- }
12965
- return removed;
12966
- }
12967
- async function runVaultSync2(vaultRoot, opts = {}) {
12968
- const fetchFn = opts.fetchFn ?? globalThis.fetch;
12969
- const isTTY = opts.isTTY ?? process.stdout.isTTY;
12970
- const unlinkFn = opts.unlinkFn ?? unlink3;
12971
- let updateChannel = "stable";
12972
- try {
12973
- const vaultYmlText = await readFile7(join12(vaultRoot, "vault.yml"), "utf8");
12974
- const vaultYml = import_yaml7.parse(vaultYmlText) ?? {};
12975
- if (typeof vaultYml["update_channel"] === "string") {
12976
- updateChannel = vaultYml["update_channel"];
12977
- }
12978
- } catch {}
12979
- const harness = await detectHarness(vaultRoot);
12980
- const branch = opts.branch ?? resolveBranch2(updateChannel);
12981
- const installedPluginsPath = opts.installedPluginsPath ?? join12(homedir5(), ".claude", "plugins", "installed_plugins.json");
12982
- const installedPluginsCacheDir = opts.installedPluginsCacheDir;
12983
- const result = {
12984
- ok: false,
12985
- version: "unknown",
12986
- branch,
12987
- filesAdded: 0,
12988
- filesRemoved: 0,
12989
- importsAdded: 0,
12990
- pinSkipped: true,
12991
- cacheRemoved: 0
12992
- };
12993
- const embedded = opts.embedded ?? false;
12994
- const createEmbeddedStep = embedded ? makeStepFn(true) : null;
12995
- let s = null;
12996
- let currentStep = null;
12997
- function startSpinner(emoji, label) {
12998
- if (isTTY) {
12999
- if (embedded) {
13000
- currentStep = createEmbeddedStep(emoji, label);
13001
- } else {
13002
- s = L2();
13003
- s.start(label);
13004
- }
13005
- } else {
13006
- process.stdout.write(`vault-sync: ${label}
13007
- `);
13008
- }
13009
- }
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
- }
13019
- }
13020
- }
13021
- if (isTTY && !embedded) {
13022
- we("OneBrain Vault Sync");
13023
- }
13024
- let tmpDir = null;
13025
- try {
13026
- startSpinner("\uD83D\uDCE5", "Downloading");
13027
- let extractedDir;
13028
- try {
13029
- const dl = await downloadTarball2(branch, fetchFn);
13030
- tmpDir = dl.tmpDir;
13031
- extractedDir = await extractTarball2(dl.tarball, tmpDir);
13032
- } catch (err) {
13033
- stopSpinner("download failed");
13034
- const msg = err instanceof Error ? err.message : String(err);
13035
- result.error = msg;
13036
- process.stderr.write(`vault-sync: download failed: ${msg}
13037
- `);
13038
- return result;
13039
- }
13040
- try {
13041
- const pjText = await readFile7(join12(extractedDir, ".claude", "plugins", "onebrain", ".claude-plugin", "plugin.json"), "utf8");
13042
- const pj = JSON.parse(pjText);
13043
- if (typeof pj["version"] === "string") {
13044
- result.version = pj["version"];
13045
- }
13046
- } catch {}
13047
- stopSpinner(`kengio/onebrain@${branch} (v${result.version})`);
13048
- startSpinner("\uD83D\uDCC2", "Syncing files");
13049
- try {
13050
- const { filesAdded, filesRemoved } = await syncPluginFiles2(extractedDir, vaultRoot, unlinkFn);
13051
- result.filesAdded = filesAdded;
13052
- result.filesRemoved = filesRemoved;
13053
- } catch (err) {
13054
- stopSpinner("plugin sync failed");
13055
- const msg = err instanceof Error ? err.message : String(err);
13056
- result.error = msg;
13057
- process.stderr.write(`vault-sync: plugin sync failed: ${msg}
13058
- `);
13059
- return result;
13060
- }
13061
- stopSpinner(`${result.filesAdded} file${result.filesAdded !== 1 ? "s" : ""} synced, ${result.filesRemoved} removed`);
13062
- if (opts.includeObsidian) {
13063
- const sourceObsidian = join12(extractedDir, ".obsidian");
13064
- const destObsidian = join12(vaultRoot, ".obsidian");
13065
- try {
13066
- const obsidianFiles = await listFilesRecursive2(sourceObsidian);
13067
- for (const srcPath of obsidianFiles) {
13068
- const rel = relative2(sourceObsidian, srcPath);
13069
- const destPath = join12(destObsidian, rel);
13070
- await mkdir5(dirname5(destPath), { recursive: true });
13071
- const content = await readFile7(srcPath);
13072
- await writeFile6(destPath, content);
13073
- }
13074
- } catch {}
13075
- }
13076
- await copyRootDocs2(extractedDir, vaultRoot);
13077
- startSpinner("\uD83D\uDD27", "Updating harness");
13078
- let importsAdded = 0;
13079
- try {
13080
- importsAdded = await mergeHarnessFiles2(extractedDir, vaultRoot);
13081
- result.importsAdded = importsAdded;
13082
- } catch (err) {
13083
- stopSpinner("harness merge failed");
13084
- const msg = err instanceof Error ? err.message : String(err);
13085
- result.error = msg;
13086
- process.stderr.write(`vault-sync: harness merge failed: ${msg}
13087
- `);
13088
- return result;
13089
- }
13090
- if (importsAdded > 0) {
13091
- stopSpinner(`${importsAdded} import${importsAdded !== 1 ? "s" : ""} added`);
13092
- } else {
13093
- stopSpinner("harness files up-to-date");
13094
- }
13095
- try {
13096
- await updateVaultYml2(vaultRoot, updateChannel);
13097
- } catch (err) {
13098
- const msg = err instanceof Error ? err.message : String(err);
13099
- result.error = msg;
13100
- process.stderr.write(`vault-sync: vault.yml update failed: ${msg}
13101
- `);
13102
- return result;
13103
- }
13104
- if (harness === "claude") {
13105
- startSpinner("\uD83D\uDCCC", "Pinning to vault");
13106
- try {
13107
- const pinResult = await pinToVault2(vaultRoot, installedPluginsPath, installedPluginsCacheDir);
13108
- result.pinSkipped = pinResult.skipped;
13109
- if (pinResult.skipped) {
13110
- stopSpinner("pin skipped (not found or marketplace)");
13111
- } else {
13112
- stopSpinner("installPath → .claude/plugins/onebrain");
13113
- }
13114
- } catch (err) {
13115
- const msg = err instanceof Error ? err.message : String(err);
13116
- process.stderr.write(`vault-sync: pin warning: ${msg}
13117
- `);
13118
- result.pinSkipped = true;
13119
- stopSpinner("pin skipped (error — non-fatal)");
13120
- }
13121
- startSpinner("\uD83E\uDDF9", "Cleaning cache");
13122
- try {
13123
- const cacheRemoved = await cleanPluginCache2(installedPluginsPath, installedPluginsCacheDir);
13124
- result.cacheRemoved = cacheRemoved;
13125
- if (cacheRemoved > 0) {
13126
- stopSpinner(`${cacheRemoved} cached version${cacheRemoved !== 1 ? "s" : ""} removed`);
13127
- } else {
13128
- stopSpinner("no cache to clean");
13129
- }
13130
- } catch (err) {
13131
- const msg = err instanceof Error ? err.message : String(err);
13132
- process.stderr.write(`vault-sync: cache clean warning: ${msg}
13133
- `);
13134
- stopSpinner("cache clean skipped (error — non-fatal)");
13135
- }
13136
- }
13137
- result.ok = true;
13138
- if (isTTY) {
13139
- if (!embedded) {
13140
- fe(`Done — v${result.version} synced`);
13141
- }
13142
- } else {
13143
- process.stdout.write(`vault-sync: done
13144
- `);
13145
- }
13146
- } finally {
13147
- if (tmpDir) {
13148
- rm2(tmpDir, { recursive: true, force: true }).catch(() => {});
13149
- }
13150
- }
13151
- return result;
13152
- }
13153
- async function vaultSyncCommand2(vaultRoot, opts = {}) {
13154
- const result = await runVaultSync2(vaultRoot, opts);
13155
- if (!result.ok) {
13156
- process.exit(1);
13157
- }
13158
- }
12572
+ // src/index.ts
12573
+ init_vault_sync();
13159
12574
 
13160
12575
  // src/commands/update.ts
13161
- var import_picocolors10 = __toESM(require_picocolors(), 1);
12576
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
13162
12577
  init_cli_ui();
13163
12578
  var GITHUB_REPO = "https://api.github.com/repos/kengio/onebrain";
13164
12579
  var GITHUB_RELEASES_URL = `${GITHUB_REPO}/releases/latest`;
@@ -13253,7 +12668,7 @@ async function runUpdate(opts = {}) {
13253
12668
  const sp1 = createStep("\uD83D\uDD0D", "Local version");
13254
12669
  const { version: currentVersion, publishedAt: localPublishedAt } = await currentVersionFn();
13255
12670
  result.currentVersion = 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);
12671
+ const localVersionLabel = localPublishedAt ? `${import_picocolors8.default.dim(currentVersion)} ${import_picocolors8.default.dim("\xB7")} ${import_picocolors8.default.dim(formatReleaseDate(localPublishedAt))}` : import_picocolors8.default.dim(currentVersion);
13257
12672
  if (sp1)
13258
12673
  sp1.stop(localVersionLabel);
13259
12674
  else
@@ -13265,9 +12680,9 @@ async function runUpdate(opts = {}) {
13265
12680
  const release = await fetchLatestRelease(fetchFn);
13266
12681
  latestVersion = release.version;
13267
12682
  publishedAt = release.publishedAt;
13268
- const dateSuffix = publishedAt ? ` ${import_picocolors10.default.dim("·")} ${import_picocolors10.default.dim(formatReleaseDate(publishedAt))}` : "";
12683
+ const dateSuffix = publishedAt ? ` ${import_picocolors8.default.dim("\xB7")} ${import_picocolors8.default.dim(formatReleaseDate(publishedAt))}` : "";
13269
12684
  if (sp2)
13270
- sp2.stop(`${import_picocolors10.default.green(latestVersion)}${dateSuffix}`);
12685
+ sp2.stop(`${import_picocolors8.default.green(latestVersion)}${dateSuffix}`);
13271
12686
  else
13272
12687
  writeLine(`latest: ${latestVersion}`);
13273
12688
  } catch (err) {
@@ -13288,12 +12703,12 @@ async function runUpdate(opts = {}) {
13288
12703
  if (check) {
13289
12704
  if (isTTY) {
13290
12705
  if (currentVersion !== latestVersion) {
13291
- barLine(`⬆️ ${import_picocolors10.default.dim(currentVersion)} ${import_picocolors10.default.green(latestVersion)} · binary would upgrade`);
12706
+ barLine(`\u2B06\uFE0F ${import_picocolors8.default.dim(currentVersion)} \u2192 ${import_picocolors8.default.green(latestVersion)} \xB7 binary would upgrade`);
13292
12707
  barBlank();
13293
12708
  }
13294
- close("Dry run complete no changes made");
12709
+ close("Dry run complete \u2014 no changes made");
13295
12710
  } else {
13296
- writeLine("done: dry run complete no changes made");
12711
+ writeLine("done: dry run complete \u2014 no changes made");
13297
12712
  }
13298
12713
  result.ok = true;
13299
12714
  result.exitCode = 0;
@@ -13301,7 +12716,7 @@ async function runUpdate(opts = {}) {
13301
12716
  }
13302
12717
  if (latestVersion === currentVersion) {
13303
12718
  if (isTTY) {
13304
- close(`Already up to date @onebrain-ai/cli ${import_picocolors10.default.dim(latestVersion)}`);
12719
+ close(`Already up to date \u2014 @onebrain-ai/cli ${import_picocolors8.default.dim(latestVersion)}`);
13305
12720
  } else {
13306
12721
  writeLine(`already up to date: @onebrain-ai/cli ${latestVersion}`);
13307
12722
  writeLine("done: nothing to do");
@@ -13311,14 +12726,14 @@ async function runUpdate(opts = {}) {
13311
12726
  return result;
13312
12727
  }
13313
12728
  if (isTTY) {
13314
- barLine(`⬆️ ${import_picocolors10.default.dim(currentVersion)} ${import_picocolors10.default.green(latestVersion)}`);
12729
+ barLine(`\u2B06\uFE0F ${import_picocolors8.default.dim(currentVersion)} \u2192 ${import_picocolors8.default.green(latestVersion)}`);
13315
12730
  barBlank();
13316
12731
  }
13317
12732
  const sp3 = createStep("\uD83D\uDCE6", "Installing @onebrain-ai/cli");
13318
12733
  try {
13319
12734
  await installBinaryFn(latestVersion);
13320
12735
  if (sp3)
13321
- sp3.stop(import_picocolors10.default.green(latestVersion));
12736
+ sp3.stop(import_picocolors8.default.green(latestVersion));
13322
12737
  else
13323
12738
  writeLine(`upgrading: @onebrain-ai/cli ${latestVersion} installed`);
13324
12739
  } catch (err) {
@@ -13335,7 +12750,7 @@ async function runUpdate(opts = {}) {
13335
12750
  }
13336
12751
  return result;
13337
12752
  }
13338
- const sp4 = createStep("", "Validating binary");
12753
+ const sp4 = createStep("\u2705", "Validating binary");
13339
12754
  const binaryValid = await validateBinaryFn();
13340
12755
  if (!binaryValid) {
13341
12756
  if (sp4)
@@ -13355,7 +12770,7 @@ async function runUpdate(opts = {}) {
13355
12770
  result.ok = true;
13356
12771
  result.exitCode = 0;
13357
12772
  if (isTTY) {
13358
- close(`Done run ${import_picocolors10.default.cyan("/update")} in Claude to sync vault files`);
12773
+ close(`Done \u2014 run ${import_picocolors8.default.cyan("/update")} in Claude to sync vault files`);
13359
12774
  } else {
13360
12775
  writeLine("done: run /update in Claude to sync vault files");
13361
12776
  }
@@ -13382,8 +12797,8 @@ function patchUtf8(stream) {
13382
12797
  }
13383
12798
 
13384
12799
  // src/index.ts
13385
- var VERSION = "2.1.2";
13386
- var RELEASE_DATE = "2026-04-28";
12800
+ var VERSION = "2.1.5";
12801
+ var RELEASE_DATE = "2026-04-29";
13387
12802
  patchUtf8(process.stdout);
13388
12803
  patchUtf8(process.stderr);
13389
12804
  var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
@@ -13397,9 +12812,9 @@ function findVaultRoot(startDir) {
13397
12812
  return process.cwd();
13398
12813
  let dir = startDir;
13399
12814
  while (true) {
13400
- if (existsSync(join13(dir, "vault.yml")))
12815
+ if (existsSync(join11(dir, "vault.yml")))
13401
12816
  return dir;
13402
- const parent = dirname6(dir);
12817
+ const parent = dirname4(dir);
13403
12818
  if (parent === dir)
13404
12819
  return startDir;
13405
12820
  dir = parent;
@@ -13446,10 +12861,10 @@ program2.command("qmd-reindex", { hidden: true }).description("Trigger qmd index
13446
12861
  });
13447
12862
  program2.command("vault-sync", { hidden: true }).description("Sync plugin files from GitHub to vault").argument("[vault_root]", "vault root directory (default: cwd)").option("--branch <branch>", "override branch (main | next)").action(async (vaultRoot, opts) => {
13448
12863
  const root = vaultRoot ?? process.cwd();
13449
- await vaultSyncCommand2(root, opts.branch !== undefined ? { branch: opts.branch } : {});
12864
+ await vaultSyncCommand(root, opts.branch !== undefined ? { branch: opts.branch } : {});
13450
12865
  });
13451
12866
  program2.command("register-hooks", { hidden: true }).description("Install Claude Code hooks into settings.json").option("--vault-dir <path>", "vault root directory (default: cwd)").action(async (opts) => {
13452
- await registerHooksCommand2(opts.vaultDir);
12867
+ await registerHooksCommand(opts.vaultDir);
13453
12868
  });
13454
12869
  program2.command("migrate", { hidden: true }).description("Run one-time migration scripts").argument("<name>", "migration name: backfill-recapped").argument("[cutoff_date]", "ISO date cutoff (YYYY-MM-DD) \u2014 skip logs newer than this date").action(async (name, cutoffDate) => {
13455
12870
  await migrateCommand(name, cutoffDate);