@onebrain-ai/cli 2.1.2 → 2.1.4

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,7 +9099,7 @@ 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",
@@ -9267,7 +9266,7 @@ async function checkPluginFiles(vaultRoot) {
9267
9266
  check: "plugin-files",
9268
9267
  status: "ok",
9269
9268
  message: "all required files present",
9270
- details: [`${skillCount} skills · ${agentCount} agents · INSTRUCTIONS.md ✓`]
9269
+ details: [`${skillCount} skills \xB7 ${agentCount} agents \xB7 INSTRUCTIONS.md \u2713`]
9271
9270
  };
9272
9271
  }
9273
9272
  async function checkVaultYmlKeys(vaultRoot) {
@@ -9392,14 +9391,14 @@ async function checkSettingsHooks(vaultRoot, config) {
9392
9391
  if (!hookPresent(settings, event, cmdSubstring)) {
9393
9392
  warnings.push(`${event} hook missing`);
9394
9393
  } else {
9395
- confirmedHooks.push(`${event} ✓`);
9394
+ confirmedHooks.push(`${event} \u2713`);
9396
9395
  }
9397
9396
  }
9398
9397
  if (config.qmd_collection) {
9399
9398
  if (!hookPresent(settings, "PostToolUse", QMD_HOOK_SUBSTRING)) {
9400
9399
  warnings.push("PostToolUse (qmd) hook missing");
9401
9400
  } else {
9402
- confirmedHooks.push("PostToolUse ");
9401
+ confirmedHooks.push("PostToolUse \u2713");
9403
9402
  }
9404
9403
  }
9405
9404
  const precompactGroups = settings.hooks?.["PreCompact"] ?? [];
@@ -9438,7 +9437,7 @@ async function checkSettingsHooks(vaultRoot, config) {
9438
9437
  if (confirmedHooks.length > 0)
9439
9438
  okDetails.push(`hooks: ${confirmedHooks.join(" ")}`);
9440
9439
  if (permissionOk)
9441
- okDetails.push("permissions: Bash(onebrain *) ");
9440
+ okDetails.push("permissions: Bash(onebrain *) \u2713");
9442
9441
  return {
9443
9442
  check: "settings-hooks",
9444
9443
  status: "ok",
@@ -9498,8 +9497,8 @@ var init_lib = __esm(() => {
9498
9497
  var require_package = __commonJS((exports, module) => {
9499
9498
  module.exports = {
9500
9499
  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",
9500
+ version: "2.1.4",
9501
+ description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
9503
9502
  keywords: [
9504
9503
  "onebrain",
9505
9504
  "obsidian",
@@ -9524,9 +9523,11 @@ var require_package = __commonJS((exports, module) => {
9524
9523
  bin: {
9525
9524
  onebrain: "dist/onebrain"
9526
9525
  },
9527
- files: ["dist/onebrain"],
9526
+ files: ["dist/onebrain", "dist/postinstall.js"],
9528
9527
  scripts: {
9529
9528
  build: "bun build src/index.ts --outfile dist/onebrain --target bun",
9529
+ "build:postinstall": "bun build src/scripts/postinstall.ts --outfile dist/postinstall.js --target node",
9530
+ postinstall: "node dist/postinstall.js",
9530
9531
  test: "bun test --pass-with-no-tests src/",
9531
9532
  typecheck: "tsc --noEmit"
9532
9533
  },
@@ -9563,13 +9564,13 @@ function barBlank() {
9563
9564
  }
9564
9565
  function close(msg, isError = false, isWarning = false) {
9565
9566
  if (isError) {
9566
- out(`${import_picocolors2.default.cyan("")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
9567
+ out(`${import_picocolors2.default.cyan("\u2514")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
9567
9568
  `);
9568
9569
  } else if (isWarning) {
9569
- out(`${import_picocolors2.default.cyan("")} ${import_picocolors2.default.yellow(msg)}
9570
+ out(`${import_picocolors2.default.cyan("\u2514")} ${import_picocolors2.default.yellow(msg)}
9570
9571
  `);
9571
9572
  } else {
9572
- out(`${import_picocolors2.default.cyan("")} ${msg}
9573
+ out(`${import_picocolors2.default.cyan("\u2514")} ${msg}
9573
9574
  `);
9574
9575
  }
9575
9576
  }
@@ -9581,13 +9582,13 @@ function makeStepFn(isTTY) {
9581
9582
  return function createStep(emoji, label) {
9582
9583
  if (!isTTY)
9583
9584
  return null;
9584
- const frames = ["", "", "", "", "", "", "", "", "", ""];
9585
+ const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9585
9586
  let i = 0;
9586
- out(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}
9587
+ out(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}\u2026
9587
9588
  `);
9588
9589
  const timer = setInterval(() => {
9589
9590
  i = (i + 1) % frames.length;
9590
- out(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}
9591
+ out(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}\u2026
9591
9592
  `);
9592
9593
  }, 80);
9593
9594
  return {
@@ -9600,19 +9601,19 @@ function makeStepFn(isTTY) {
9600
9601
  barLine(result);
9601
9602
  if (details)
9602
9603
  for (const d of details)
9603
- barLine(` · ${d}`);
9604
+ barLine(` \xB7 ${d}`);
9604
9605
  barBlank();
9605
9606
  }
9606
9607
  };
9607
9608
  };
9608
9609
  }
9609
9610
  async function askYesNo(question) {
9610
- out(`${import_picocolors2.default.cyan("")} ${question}
9611
+ out(`${import_picocolors2.default.cyan("\u25C6")} ${question}
9611
9612
  `);
9612
9613
  process.stdout.write(Buffer.from("\x1B[?25l", "utf8"));
9613
9614
  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`;
9615
+ const yesLabel = yes ? `${import_picocolors2.default.bold(import_picocolors2.default.green("\u25CF"))} Yes` : `${import_picocolors2.default.dim("\u25CB")} Yes`;
9616
+ const noLabel = yes ? `${import_picocolors2.default.dim("\u25CB")} No` : `${import_picocolors2.default.bold(import_picocolors2.default.green("\u25CF"))} No`;
9616
9617
  out(`\x1B[2K${bar} ${yesLabel} / ${noLabel}\r`);
9617
9618
  }
9618
9619
  const answer = await new Promise((resolve) => {
@@ -9664,8 +9665,8 @@ async function askYesNo(question) {
9664
9665
  var import_picocolors2, bar, dot;
9665
9666
  var init_cli_ui = __esm(() => {
9666
9667
  import_picocolors2 = __toESM(require_picocolors(), 1);
9667
- bar = import_picocolors2.default.cyan("");
9668
- dot = import_picocolors2.default.green("");
9668
+ bar = import_picocolors2.default.cyan("\u2502");
9669
+ dot = import_picocolors2.default.green("\u25CF");
9669
9670
  });
9670
9671
 
9671
9672
  // node_modules/sisteransi/src/index.js
@@ -9727,8 +9728,8 @@ var require_src = __commonJS((exports, module) => {
9727
9728
  });
9728
9729
 
9729
9730
  // node_modules/@clack/core/dist/index.mjs
9730
- import { stdin as $, stdout as j } from "node:process";
9731
- import * as f from "node:readline";
9731
+ import { stdin as $, stdout as j } from "process";
9732
+ import * as f from "readline";
9732
9733
  function J({ onlyFirst: t = false } = {}) {
9733
9734
  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
9735
  return new RegExp(F, t ? undefined : "g");
@@ -9847,7 +9848,7 @@ var init_dist = __esm(() => {
9847
9848
  eD = Object.keys(r.bgColor);
9848
9849
  [...tD, ...eD];
9849
9850
  iD = sD();
9850
- v = new Set(["\x1B", "›"]);
9851
+ v = new Set(["\x1B", "\x9B"]);
9851
9852
  y = `${rD}8;;`;
9852
9853
  aD = ["up", "down", "left", "right", "space", "enter", "cancel"];
9853
9854
  c = { actions: new Set(aD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
@@ -9856,7 +9857,7 @@ var init_dist = __esm(() => {
9856
9857
  });
9857
9858
 
9858
9859
  // node_modules/@clack/prompts/dist/index.mjs
9859
- import p from "node:process";
9860
+ import p from "process";
9860
9861
  function X2() {
9861
9862
  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
9863
  }
@@ -9869,7 +9870,7 @@ ${import_picocolors3.default.gray(m2)} ${s}
9869
9870
 
9870
9871
  `);
9871
9872
  }, L2 = () => {
9872
- const s = E ? ["", "", "", ""] : ["", "o", "O", "0"], n = E ? 80 : 120, t = process.env.CI === "true";
9873
+ const s = E ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], n = E ? 80 : 120, t = process.env.CI === "true";
9873
9874
  let i, r2, c2 = false, o = "", l2;
9874
9875
  const $2 = (h) => {
9875
9876
  const g = h > 1 ? "Something went wrong" : "Canceled";
@@ -9913,32 +9914,32 @@ var init_dist2 = __esm(() => {
9913
9914
  import_picocolors3 = __toESM(require_picocolors(), 1);
9914
9915
  import_sisteransi2 = __toESM(require_src(), 1);
9915
9916
  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");
9917
+ ee = u("\u25C6", "*");
9918
+ A = u("\u25A0", "x");
9919
+ B = u("\u25B2", "x");
9920
+ S2 = u("\u25C7", "o");
9921
+ te = u("\u250C", "T");
9922
+ a = u("\u2502", "|");
9923
+ m2 = u("\u2514", "\u2014");
9924
+ j2 = u("\u25CF", ">");
9925
+ R = u("\u25CB", " ");
9926
+ V = u("\u25FB", "[\u2022]");
9927
+ M = u("\u25FC", "[+]");
9928
+ G = u("\u25FB", "[ ]");
9929
+ se = u("\u25AA", "\u2022");
9930
+ N2 = u("\u2500", "-");
9931
+ re = u("\u256E", "+");
9932
+ ie = u("\u251C", "+");
9933
+ ne = u("\u256F", "+");
9934
+ ae = u("\u25CF", "\u2022");
9935
+ oe = u("\u25C6", "*");
9936
+ ce = u("\u25B2", "!");
9937
+ le = u("\u25A0", "x");
9937
9938
  });
9938
9939
 
9939
9940
  // src/commands/internal/harness.ts
9940
- import { stat as stat2 } from "node:fs/promises";
9941
- import { join as join3 } from "node:path";
9941
+ import { stat as stat2 } from "fs/promises";
9942
+ import { join as join3 } from "path";
9942
9943
  async function pathExists(p2) {
9943
9944
  try {
9944
9945
  await stat2(p2);
@@ -9956,7 +9957,7 @@ async function detectHarness(vaultRoot) {
9956
9957
  return "gemini";
9957
9958
  if (env === "direct")
9958
9959
  return "direct";
9959
- process.stderr.write(`harness: unknown ONEBRAIN_HARNESS value "${env}" ignoring, falling back to directory detection
9960
+ process.stderr.write(`harness: unknown ONEBRAIN_HARNESS value "${env}" \u2014 ignoring, falling back to directory detection
9960
9961
  `);
9961
9962
  }
9962
9963
  if (await pathExists(join3(vaultRoot, ".gemini")))
@@ -9973,9 +9974,9 @@ __export(exports_register_hooks, {
9973
9974
  runRegisterHooks: () => runRegisterHooks,
9974
9975
  registerHooksCommand: () => registerHooksCommand
9975
9976
  });
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";
9977
+ import { mkdir, readFile, rename, writeFile } from "fs/promises";
9978
+ import { homedir } from "os";
9979
+ import { dirname, join as join4 } from "path";
9979
9980
  async function readSettings(settingsPath) {
9980
9981
  try {
9981
9982
  const text = await readFile(settingsPath, "utf8");
@@ -10152,11 +10153,11 @@ async function runRegisterHooks(opts = {}) {
10152
10153
  if (isTTY) {
10153
10154
  const parts = HOOK_EVENTS.map((e2) => {
10154
10155
  const status = result.hooks[e2];
10155
- const icon = import_picocolors4.default.green(status === "ok" ? "" : status === "migrated" ? "" : "+");
10156
+ const icon = import_picocolors4.default.green(status === "ok" ? "\u2713" : status === "migrated" ? "\u2191" : "+");
10156
10157
  return `${import_picocolors4.default.dim(e2)} ${icon}`;
10157
10158
  });
10158
10159
  if (qmdStatus)
10159
- parts.push(`${import_picocolors4.default.dim("PostToolUse")} ${import_picocolors4.default.green(qmdStatus === "ok" ? "" : "+")}`);
10160
+ parts.push(`${import_picocolors4.default.dim("PostToolUse")} ${import_picocolors4.default.green(qmdStatus === "ok" ? "\u2713" : "+")}`);
10160
10161
  hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
10161
10162
  } else {
10162
10163
  const hookLine = HOOK_EVENTS.map((e2) => {
@@ -10252,9 +10253,9 @@ import {
10252
10253
  stat as stat3,
10253
10254
  unlink,
10254
10255
  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";
10256
+ } from "fs/promises";
10257
+ import { homedir as homedir2, tmpdir } from "os";
10258
+ import { dirname as dirname2, join as join5, relative } from "path";
10258
10259
  function resolveBranch(updateChannel) {
10259
10260
  return updateChannel === "stable" ? "main" : "next";
10260
10261
  }
@@ -10263,9 +10264,9 @@ async function downloadTarball(branch, fetchFn) {
10263
10264
  const response = await fetchFn(url);
10264
10265
  if (!response.ok) {
10265
10266
  const hints = {
10266
- 403: " check repo permissions or GITHUB_TOKEN",
10267
- 404: " repo or branch not found",
10268
- 429: " rate limited, wait and retry"
10267
+ 403: " \u2014 check repo permissions or GITHUB_TOKEN",
10268
+ 404: " \u2014 repo or branch not found",
10269
+ 429: " \u2014 rate limited, wait and retry"
10269
10270
  };
10270
10271
  const hint = hints[response.status] ?? "";
10271
10272
  throw new Error(`HTTP ${response.status} downloading tarball from ${url}${hint}`);
@@ -10703,14 +10704,14 @@ async function runVaultSync(vaultRoot, opts = {}) {
10703
10704
  if (pinResult.skipped) {
10704
10705
  stopSpinner("pin skipped (not found or marketplace)");
10705
10706
  } else {
10706
- stopSpinner("installPath .claude/plugins/onebrain");
10707
+ stopSpinner("installPath \u2192 .claude/plugins/onebrain");
10707
10708
  }
10708
10709
  } catch (err) {
10709
10710
  const msg = err instanceof Error ? err.message : String(err);
10710
10711
  process.stderr.write(`vault-sync: pin warning: ${msg}
10711
10712
  `);
10712
10713
  result.pinSkipped = true;
10713
- stopSpinner("pin skipped (error non-fatal)");
10714
+ stopSpinner("pin skipped (error \u2014 non-fatal)");
10714
10715
  }
10715
10716
  startSpinner("\uD83E\uDDF9", "Cleaning cache");
10716
10717
  try {
@@ -10725,13 +10726,13 @@ async function runVaultSync(vaultRoot, opts = {}) {
10725
10726
  const msg = err instanceof Error ? err.message : String(err);
10726
10727
  process.stderr.write(`vault-sync: cache clean warning: ${msg}
10727
10728
  `);
10728
- stopSpinner("cache clean skipped (error non-fatal)");
10729
+ stopSpinner("cache clean skipped (error \u2014 non-fatal)");
10729
10730
  }
10730
10731
  }
10731
10732
  result.ok = true;
10732
10733
  if (isTTY) {
10733
10734
  if (!embedded) {
10734
- fe(`Done v${result.version} synced`);
10735
+ fe(`Done \u2014 v${result.version} synced`);
10735
10736
  }
10736
10737
  } else {
10737
10738
  process.stdout.write(`vault-sync: done
@@ -10761,7 +10762,7 @@ var init_vault_sync = __esm(() => {
10761
10762
 
10762
10763
  // src/index.ts
10763
10764
  import { existsSync } from "fs";
10764
- import { dirname as dirname6, join as join13 } from "path";
10765
+ import { dirname as dirname4, join as join11 } from "path";
10765
10766
 
10766
10767
  // node_modules/commander/esm.mjs
10767
10768
  var import__ = __toESM(require_commander(), 1);
@@ -10787,7 +10788,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
10787
10788
  var import_picocolors = __toESM(require_picocolors(), 1);
10788
10789
  function resolveBinaryVersion() {
10789
10790
  if (true)
10790
- return "2.1.2";
10791
+ return "2.1.4";
10791
10792
  try {
10792
10793
  const pkg = require_package();
10793
10794
  return pkg.version ?? "dev";
@@ -10796,11 +10797,11 @@ function resolveBinaryVersion() {
10796
10797
  }
10797
10798
  }
10798
10799
  var ART_LINES = [
10799
- ` ◆${"".repeat(25)}◆`,
10800
- " ┌─┐┌┐╷┌─╴┌┐ ┌─┐┌─┐╷┌┐╷",
10801
- " ││└┤├╴ ├┴┐├┬┘├─┤││└┤",
10802
- " └─┘╵ ╵└─╴└─┘╵└╴╵ ╵╵╵ ",
10803
- ` ◆${"".repeat(25)}◆`
10800
+ ` \u25C6${"\u2500".repeat(25)}\u25C6`,
10801
+ " \u250C\u2500\u2510\u250C\u2510\u2577\u250C\u2500\u2574\u250C\u2510 \u250C\u2500\u2510\u250C\u2500\u2510\u2577\u250C\u2510\u2577",
10802
+ " \u2502 \u2502\u2502\u2514\u2524\u251C\u2574 \u251C\u2534\u2510\u251C\u252C\u2518\u251C\u2500\u2524\u2502\u2502\u2514\u2524",
10803
+ " \u2514\u2500\u2518\u2575 \u2575\u2514\u2500\u2574\u2514\u2500\u2518\u2575\u2514\u2574\u2575 \u2575\u2575\u2575 \u2575",
10804
+ ` \u25C6${"\u2500".repeat(25)}\u25C6`
10804
10805
  ];
10805
10806
  var TAGLINE = "Your AI Thinking Partner";
10806
10807
  var BANNER_LINE_COUNT = 1 + ART_LINES.length + 3;
@@ -10939,7 +10940,7 @@ async function printBanner() {
10939
10940
  up(BANNER_LINE_COUNT);
10940
10941
  printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${" ".repeat(TAGLINE.length)}`);
10941
10942
  await delay(200);
10942
- const cursor = `\x1B[1;38;2;140;255;255m▌\x1B[0m`;
10943
+ const cursor = "\x1B[1;38;2;140;255;255m\u258C\x1B[0m";
10943
10944
  for (let len = 1;len <= TAGLINE.length; len++) {
10944
10945
  await delay(32);
10945
10946
  up(BANNER_LINE_COUNT);
@@ -11018,7 +11019,7 @@ async function runDoctor(opts = {}) {
11018
11019
  let vaultYmlKeysResult;
11019
11020
  let settingsHooksResult;
11020
11021
  if (isTTY) {
11021
- const sp2 = createStep("⚙️", "Config schema");
11022
+ const sp2 = createStep("\u2699\uFE0F", "Config schema");
11022
11023
  vaultYmlKeysResult = await checkVaultYmlKeysFn(vaultDir);
11023
11024
  await randDelay();
11024
11025
  sp2.stop(fmtResult(vaultYmlKeysResult), vaultYmlKeysResult.details);
@@ -11082,15 +11083,15 @@ async function runDoctor(opts = {}) {
11082
11083
  printNonTtyOutput(results, totalChecks, errorCount, warningCount, showFixHint, fixableCount);
11083
11084
  } else {
11084
11085
  if (errorCount > 0) {
11085
- close(`${summaryParts.join(" · ")} fix before using`, true);
11086
+ close(`${summaryParts.join(" \xB7 ")} \u2014 fix before using`, true);
11086
11087
  } else if (warningCount > 0) {
11087
- close(`${summaryParts.join(" · ")} advisory only, safe to run`, false, true);
11088
+ close(`${summaryParts.join(" \xB7 ")} \u2014 advisory only, safe to run`, false, true);
11088
11089
  } else {
11089
- close(import_picocolors5.default.green(`${summaryParts.join(" · ")} all passed`));
11090
+ close(import_picocolors5.default.green(`${summaryParts.join(" \xB7 ")} \u2014 all passed`));
11090
11091
  }
11091
11092
  if (showFixHint) {
11092
11093
  process.stdout.write(`
11093
- Run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to auto-fix ${fixableCount} issue(s)
11094
+ \u2192 Run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to auto-fix ${fixableCount} issue(s)
11094
11095
  `);
11095
11096
  }
11096
11097
  }
@@ -11111,21 +11112,21 @@ async function doctorCommand(opts = {}) {
11111
11112
  function printNonTtyOutput(results, totalChecks, errorCount, warningCount, showFixHint, fixableCount) {
11112
11113
  const lines = ["OneBrain Doctor", ""];
11113
11114
  for (const result of results) {
11114
- const icon = result.status === "ok" ? "[]" : result.status === "warn" ? "[!]" : "[]";
11115
+ const icon = result.status === "ok" ? "[\u2713]" : result.status === "warn" ? "[!]" : "[\u2717]";
11115
11116
  lines.push(` ${icon} ${result.check.padEnd(20)} ${result.message}`);
11116
11117
  if (result.hint)
11117
- lines.push(` ${result.hint}`);
11118
+ lines.push(` \u2192 ${result.hint}`);
11118
11119
  if (result.details)
11119
11120
  for (const d of result.details)
11120
- lines.push(` · ${d}`);
11121
+ lines.push(` \xB7 ${d}`);
11121
11122
  }
11122
11123
  lines.push("");
11123
11124
  if (errorCount > 0) {
11124
- lines.push(`Summary: ${totalChecks} checks · ${errorCount} error(s) · ${warningCount} warning(s) fix before using`);
11125
+ lines.push(`Summary: ${totalChecks} checks \xB7 ${errorCount} error(s) \xB7 ${warningCount} warning(s) \u2014 fix before using`);
11125
11126
  } else if (warningCount > 0) {
11126
- lines.push(`Summary: ${totalChecks} checks · ${warningCount} warning(s) ok to run`);
11127
+ lines.push(`Summary: ${totalChecks} checks \xB7 ${warningCount} warning(s) \u2014 ok to run`);
11127
11128
  } else {
11128
- lines.push(`Summary: ${totalChecks} checks all passed`);
11129
+ lines.push(`Summary: ${totalChecks} checks \u2014 all passed`);
11129
11130
  }
11130
11131
  if (showFixHint)
11131
11132
  lines.push(`hint: run onebrain doctor --fix to auto-fix ${fixableCount} issue(s)`);
@@ -11154,8 +11155,8 @@ function getFix(r2) {
11154
11155
  const description = deprecated.length > 0 ? `Remove deprecated keys from vault.yml: ${deprecated.join(", ")}` : "Remove deprecated keys from vault.yml";
11155
11156
  return {
11156
11157
  fn: async (vaultDir) => {
11157
- const { readFile: readFile2, writeFile: writeFile2, rename: rename2 } = await import("node:fs/promises");
11158
- const { join: join5 } = await import("node:path");
11158
+ const { readFile: readFile2, writeFile: writeFile2, rename: rename2 } = await import("fs/promises");
11159
+ const { join: join5 } = await import("path");
11159
11160
  const { parse: parse3, stringify } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
11160
11161
  const vaultYmlPath = join5(vaultDir, "vault.yml");
11161
11162
  const text = await readFile2(vaultYmlPath, "utf8");
@@ -11187,9 +11188,9 @@ function getFix(r2) {
11187
11188
  const count = pendingMatch?.[1] ?? "some";
11188
11189
  return {
11189
11190
  fn: async (vaultDir) => {
11190
- const { join: join5 } = await import("node:path");
11191
+ const { join: join5 } = await import("path");
11191
11192
  const { parse: parseYaml } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
11192
- const { readFile: readFile2 } = await import("node:fs/promises");
11193
+ const { readFile: readFile2 } = await import("fs/promises");
11193
11194
  const raw = parseYaml(await readFile2(join5(vaultDir, "vault.yml"), "utf8"));
11194
11195
  const collection = raw["qmd_collection"];
11195
11196
  if (!collection)
@@ -11215,8 +11216,8 @@ function getFix(r2) {
11215
11216
  const missingStr = r2.hint.replace("Missing: ", "");
11216
11217
  return {
11217
11218
  fn: async (vaultDir) => {
11218
- const { mkdir: mkdir2 } = await import("node:fs/promises");
11219
- const { join: join5 } = await import("node:path");
11219
+ const { mkdir: mkdir2 } = await import("fs/promises");
11220
+ const { join: join5 } = await import("path");
11220
11221
  const missing = missingStr.split(", ").map((f2) => f2.trim()).filter(Boolean);
11221
11222
  for (const folder of missing) {
11222
11223
  await mkdir2(join5(vaultDir, folder), { recursive: true });
@@ -11231,7 +11232,7 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11231
11232
  const fixable = results.filter((r2) => r2.status !== "ok" && getFix(r2) !== null);
11232
11233
  if (fixable.length === 0) {
11233
11234
  if (isTTY)
11234
- barLine(`${import_picocolors5.default.green("")} Nothing to fix`);
11235
+ barLine(`${import_picocolors5.default.green("\u25C6")} Nothing to fix`);
11235
11236
  else
11236
11237
  writeLine("nothing to fix");
11237
11238
  return;
@@ -11241,14 +11242,14 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11241
11242
  barLine(import_picocolors5.default.bold(`${fixable.length} fix(es) to apply:`));
11242
11243
  barBlank();
11243
11244
  for (const r2 of fixable) {
11244
- barLine(` ${import_picocolors5.default.cyan("")} ${getFix(r2).description}`);
11245
+ barLine(` ${import_picocolors5.default.cyan("\u25C6")} ${getFix(r2).description}`);
11245
11246
  }
11246
11247
  barBlank();
11247
11248
  const answer = await askYesNo("Apply all?");
11248
11249
  if (answer === null || answer === false) {
11249
11250
  barLine(import_picocolors5.default.dim("No"));
11250
11251
  barBlank();
11251
- close(`No changes made run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to apply`);
11252
+ close(`No changes made \u2014 run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to apply`);
11252
11253
  return;
11253
11254
  }
11254
11255
  barLine("Yes");
@@ -11268,11 +11269,11 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11268
11269
  await fix.fn(vaultDir, registerHooksFn);
11269
11270
  fixed++;
11270
11271
  if (isTTY)
11271
- barLine(`${import_picocolors5.default.green("")} ${fix.description}`);
11272
+ barLine(`${import_picocolors5.default.green("\u25C6")} ${fix.description}`);
11272
11273
  } catch (err) {
11273
11274
  const errMsg = err instanceof Error ? err.message : String(err);
11274
11275
  if (isTTY) {
11275
- barLine(`${import_picocolors5.default.yellow("")} Could not fix ${r2.check}: ${errMsg}`);
11276
+ barLine(`${import_picocolors5.default.yellow("\u25B2")} Could not fix ${r2.check}: ${errMsg}`);
11276
11277
  } else {
11277
11278
  process.stderr.write(`doctor: fix failed for ${r2.check}: ${errMsg}
11278
11279
  `);
@@ -11282,9 +11283,9 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11282
11283
  if (isTTY) {
11283
11284
  barBlank();
11284
11285
  if (fixed > 0)
11285
- barLine(`${import_picocolors5.default.green("")} Fixed ${fixed} issue(s)`);
11286
+ barLine(`${import_picocolors5.default.green("\u25C6")} Fixed ${fixed} issue(s)`);
11286
11287
  if (unfixable.length > 0) {
11287
- barLine(`${import_picocolors5.default.yellow("")} ${unfixable.length} issue(s) require manual action:`);
11288
+ barLine(`${import_picocolors5.default.yellow("\u25B2")} ${unfixable.length} issue(s) require manual action:`);
11288
11289
  for (const r2 of unfixable) {
11289
11290
  barLine(` ${r2.check}: ${r2.hint ?? "no auto-fix available"}`);
11290
11291
  }
@@ -11304,9 +11305,9 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
11304
11305
  // src/commands/init.ts
11305
11306
  var import_picocolors7 = __toESM(require_picocolors(), 1);
11306
11307
  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";
11308
+ import { mkdir as mkdir3, readFile as readFile3, readdir as readdir2, rename as rename3, stat as stat4, writeFile as writeFile3 } from "fs/promises";
11309
+ import { homedir as homedir3 } from "os";
11310
+ import { dirname as dirname3, join as join6 } from "path";
11310
11311
  init_cli_ui();
11311
11312
  var binaryVersion = resolveBinaryVersion();
11312
11313
  var STANDARD_FOLDERS = [
@@ -11372,7 +11373,7 @@ async function downloadPluginFiles(vaultDir, vaultSyncFn) {
11372
11373
  } catch {}
11373
11374
  let driftWarning;
11374
11375
  if (pluginVersion && binaryVersion !== "dev" && pluginVersion !== binaryVersion) {
11375
- driftWarning = `Plugin files v${pluginVersion}, binary v${binaryVersion} run onebrain update to sync.`;
11376
+ driftWarning = `Plugin files v${pluginVersion}, binary v${binaryVersion} \u2014 run onebrain update to sync.`;
11376
11377
  }
11377
11378
  return driftWarning !== undefined ? { skipped: true, driftWarning } : { skipped: true };
11378
11379
  }
@@ -11573,7 +11574,7 @@ async function installObsidianPlugins(vaultDir, opts) {
11573
11574
  }
11574
11575
  if (pluginFailed) {
11575
11576
  try {
11576
- const { rm: rm2 } = await import("node:fs/promises");
11577
+ const { rm: rm2 } = await import("fs/promises");
11577
11578
  await rm2(pluginDir, { recursive: true, force: true });
11578
11579
  } catch {}
11579
11580
  } else {
@@ -11655,7 +11656,7 @@ async function runInit(opts = {}) {
11655
11656
  await writeVaultYml(vaultDir);
11656
11657
  if (sp2) {
11657
11658
  await randDelay();
11658
- sp2.stop(import_picocolors7.default.dim("written"), ["update_channel: stable", "checkpoint: 15 msgs · 30 min"]);
11659
+ sp2.stop(import_picocolors7.default.dim("written"), ["update_channel: stable", "checkpoint: 15 msgs \xB7 30 min"]);
11659
11660
  } else {
11660
11661
  writeLine("vault.yml: written");
11661
11662
  }
@@ -11671,24 +11672,21 @@ async function runInit(opts = {}) {
11671
11672
  const pluginJsonPath = join6(vaultDir, ".claude", "plugins", "onebrain", ".claude-plugin", "plugin.json");
11672
11673
  const pluginFilesExist = await pathExists2(pluginJsonPath);
11673
11674
  const sp4 = pluginFilesExist ? createStep("\uD83D\uDCE6", "Plugin files") : null;
11674
- const {
11675
- skipped: pluginSkipped,
11676
- failed: pluginDownloadFailed
11677
- } = await downloadPluginFiles(vaultDir, vaultSyncFn);
11675
+ const { skipped: pluginSkipped, failed: pluginDownloadFailed } = await downloadPluginFiles(vaultDir, vaultSyncFn);
11678
11676
  result.pluginSkipped = pluginSkipped;
11679
11677
  if (sp4) {
11680
11678
  if (pluginDownloadFailed) {
11681
11679
  sp4.stop("download failed");
11682
11680
  } else {
11683
11681
  const { skills, agents } = await countPluginContents(vaultDir);
11684
- sp4.stop(import_picocolors7.default.dim("already installed"), [`${skills} skills · ${agents} agents`]);
11682
+ sp4.stop(import_picocolors7.default.dim("already installed"), [`${skills} skills \xB7 ${agents} agents`]);
11685
11683
  }
11686
11684
  } else if (isTTY) {
11687
11685
  if (!pluginDownloadFailed) {
11688
11686
  const { skills, agents } = await countPluginContents(vaultDir);
11689
11687
  dotLine("\uD83D\uDCE6", "Plugin files");
11690
11688
  barLine(import_picocolors7.default.dim("downloaded"));
11691
- barLine(` · ${skills} skills · ${agents} agents`);
11689
+ barLine(` \xB7 ${skills} skills \xB7 ${agents} agents`);
11692
11690
  barBlank();
11693
11691
  }
11694
11692
  } else {
@@ -11702,7 +11700,7 @@ async function runInit(opts = {}) {
11702
11700
  if (isTTY) {
11703
11701
  close("Could not download plugin files. Check your internet connection and try again.", true);
11704
11702
  } else {
11705
- writeLine("error: vault-sync failed run onebrain update to download plugin files");
11703
+ writeLine("error: vault-sync failed \u2014 run onebrain update to download plugin files");
11706
11704
  }
11707
11705
  return result;
11708
11706
  }
@@ -11733,7 +11731,9 @@ async function runInit(opts = {}) {
11733
11731
  result.pluginRegistrationSkipped = pluginRegistrationSkipped;
11734
11732
  if (sp5) {
11735
11733
  await randDelay();
11736
- sp5.stop(import_picocolors7.default.dim(pluginRegistrationSkipped ? "skipped" : "registered"), [`source: ${pluginRegistrationSkipped ? "marketplace" : "local"}`]);
11734
+ sp5.stop(import_picocolors7.default.dim(pluginRegistrationSkipped ? "skipped" : "registered"), [
11735
+ `source: ${pluginRegistrationSkipped ? "marketplace" : "local"}`
11736
+ ]);
11737
11737
  } else {
11738
11738
  writeLine(`plugin: ${pluginRegistrationSkipped ? "skipped (marketplace)" : "registered"}`);
11739
11739
  }
@@ -11749,20 +11749,20 @@ async function runInit(opts = {}) {
11749
11749
  }
11750
11750
  if (sp6) {
11751
11751
  await randDelay();
11752
- sp6.stop(hooksOk ? undefined : "not registered run onebrain update", hooksOk ? ["Stop PostCompact ", "Bash(onebrain *) "] : undefined);
11752
+ sp6.stop(hooksOk ? undefined : "not registered \u2014 run onebrain update", hooksOk ? ["Stop \u2713 PostCompact \u2713", "Bash(onebrain *) \u2713"] : undefined);
11753
11753
  } else {
11754
- writeLine(`hooks: ${hooksOk ? "ok" : "warning hooks not registered; run onebrain update"}`);
11754
+ writeLine(`hooks: ${hooksOk ? "ok" : "warning \u2014 hooks not registered; run onebrain update"}`);
11755
11755
  }
11756
11756
  result.ok = true;
11757
11757
  result.exitCode = 0;
11758
11758
  if (isTTY) {
11759
- barLine(import_picocolors7.default.dim(`─── Next steps ${"".repeat(25)}`));
11759
+ barLine(import_picocolors7.default.dim(`\u2500\u2500\u2500 Next steps ${"\u2500".repeat(25)}`));
11760
11760
  barBlank();
11761
- barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("1"))} \uD83D\uDCC1 Open Obsidian open this folder as vault`);
11761
+ barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("1"))} \uD83D\uDCC1 Open Obsidian \u2192 open this folder as vault`);
11762
11762
  barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("2"))} \uD83E\uDD16 Run ${import_picocolors7.default.cyan("claude")}`);
11763
11763
  barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("3"))} \uD83E\uDDE0 Type ${import_picocolors7.default.cyan("/onboarding")} to personalize`);
11764
11764
  barBlank();
11765
- close(`✨ ${import_picocolors7.default.bold("Ready")} ${import_picocolors7.default.cyan("/onboarding")}`);
11765
+ close(`\u2728 ${import_picocolors7.default.bold("Ready")} \u2014 ${import_picocolors7.default.cyan("/onboarding")}`);
11766
11766
  } else {
11767
11767
  writeLine("done: run /onboarding in Claude to finish setup");
11768
11768
  }
@@ -11776,9 +11776,9 @@ async function initCommand(opts = {}) {
11776
11776
  }
11777
11777
 
11778
11778
  // 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";
11779
+ import { readFileSync, readdirSync, writeFileSync } from "fs";
11780
+ import { tmpdir as osTmpdir } from "os";
11781
+ import { join as join7 } from "path";
11782
11782
  var SKIP_WINDOW = 60;
11783
11783
  var MIN_ACTIVITY = 2;
11784
11784
  var PRECOMPACT_RECENCY = 300;
@@ -11954,8 +11954,8 @@ async function checkpointCommand(mode, token, vaultRoot) {
11954
11954
  // src/commands/internal/migrate.ts
11955
11955
  init_lib();
11956
11956
  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";
11957
+ import { readFile as readFile4, readdir as readdir3, writeFile as writeFile4 } from "fs/promises";
11958
+ import { join as join8 } from "path";
11959
11959
  function parseFrontmatterWithRest(rawText) {
11960
11960
  const text = rawText.replace(/\r\n/g, `
11961
11961
  `);
@@ -12024,7 +12024,7 @@ async function runBackfillRecapped(logsFolder, cutoffDate) {
12024
12024
  const content = await readFile4(fpath, "utf8");
12025
12025
  const parsed = parseFrontmatterWithRest(content);
12026
12026
  if (!parsed) {
12027
- process.stderr.write(`migrate: ${fname} malformed frontmatter
12027
+ process.stderr.write(`migrate: ${fname} \u2014 malformed frontmatter
12028
12028
  `);
12029
12029
  skipped++;
12030
12030
  continue;
@@ -12071,8 +12071,8 @@ async function migrateCommand(migrationName, cutoffDate, vaultDir) {
12071
12071
 
12072
12072
  // src/commands/internal/orphan-scan.ts
12073
12073
  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";
12074
+ import { readFile as readFile5, readdir as readdir4 } from "fs/promises";
12075
+ import { join as join9 } from "path";
12076
12076
  function parseFrontmatter(rawText) {
12077
12077
  const text = rawText.replace(/\r\n/g, `
12078
12078
  `);
@@ -12206,276 +12206,14 @@ async function qmdReindexCommand(vaultRoot) {
12206
12206
  }
12207
12207
  }
12208
12208
 
12209
- // src/commands/internal/register-hooks.ts
12210
- init_dist2();
12211
- 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"
12240
- ];
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);
12258
- }
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
- }
12269
- }
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];
12283
- }
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
- }
12311
- }
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
- }
12209
+ // src/index.ts
12210
+ init_register_hooks();
12473
12211
 
12474
12212
  // src/commands/internal/session-init.ts
12475
12213
  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";
12214
+ import { unlink as unlink2 } from "fs/promises";
12215
+ import { tmpdir as osTmpdir2 } from "os";
12216
+ import { join as join10 } from "path";
12479
12217
  var DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
12480
12218
  var MONTH_NAMES = [
12481
12219
  "Jan",
@@ -12498,7 +12236,7 @@ function formatDatetime(date) {
12498
12236
  const year = date.getFullYear();
12499
12237
  const hh = String(date.getHours()).padStart(2, "0");
12500
12238
  const mm = String(date.getMinutes()).padStart(2, "0");
12501
- return `${dow} · ${day} ${mon} ${year} · ${hh}:${mm}`;
12239
+ return `${dow} \xB7 ${day} ${mon} ${year} \xB7 ${hh}:${mm}`;
12502
12240
  }
12503
12241
  async function resolveSessionToken(tmpDir = osTmpdir2()) {
12504
12242
  const wtSession = process.env["WT_SESSION"];
@@ -12525,7 +12263,7 @@ async function resolveSessionToken(tmpDir = osTmpdir2()) {
12525
12263
  String(today.getMonth() + 1).padStart(2, "0"),
12526
12264
  String(today.getDate()).padStart(2, "0")
12527
12265
  ].join("");
12528
- const cacheFile = join11(tmpDir, `onebrain-day-${yyyymmdd}.token`);
12266
+ const cacheFile = join10(tmpDir, `onebrain-day-${yyyymmdd}.token`);
12529
12267
  const cacheExists = await Bun.file(cacheFile).exists();
12530
12268
  if (cacheExists) {
12531
12269
  const cached = (await Bun.file(cacheFile).text()).trim();
@@ -12577,7 +12315,7 @@ async function resolveSessionToken(tmpDir = osTmpdir2()) {
12577
12315
  async function cleanStaleStateFile(token, tmpDir) {
12578
12316
  try {
12579
12317
  const processStartMs = Date.now() - performance.now();
12580
- const stateFile = join11(tmpDir, `onebrain-${token}.state`);
12318
+ const stateFile = join10(tmpDir, `onebrain-${token}.state`);
12581
12319
  const f2 = Bun.file(stateFile);
12582
12320
  const exists = await f2.exists();
12583
12321
  if (!exists)
@@ -12642,523 +12380,11 @@ async function sessionInitCommand(vaultRoot) {
12642
12380
  `);
12643
12381
  }
12644
12382
 
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
- }
12383
+ // src/index.ts
12384
+ init_vault_sync();
13159
12385
 
13160
12386
  // src/commands/update.ts
13161
- var import_picocolors10 = __toESM(require_picocolors(), 1);
12387
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
13162
12388
  init_cli_ui();
13163
12389
  var GITHUB_REPO = "https://api.github.com/repos/kengio/onebrain";
13164
12390
  var GITHUB_RELEASES_URL = `${GITHUB_REPO}/releases/latest`;
@@ -13253,7 +12479,7 @@ async function runUpdate(opts = {}) {
13253
12479
  const sp1 = createStep("\uD83D\uDD0D", "Local version");
13254
12480
  const { version: currentVersion, publishedAt: localPublishedAt } = await currentVersionFn();
13255
12481
  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);
12482
+ 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
12483
  if (sp1)
13258
12484
  sp1.stop(localVersionLabel);
13259
12485
  else
@@ -13265,9 +12491,9 @@ async function runUpdate(opts = {}) {
13265
12491
  const release = await fetchLatestRelease(fetchFn);
13266
12492
  latestVersion = release.version;
13267
12493
  publishedAt = release.publishedAt;
13268
- const dateSuffix = publishedAt ? ` ${import_picocolors10.default.dim("·")} ${import_picocolors10.default.dim(formatReleaseDate(publishedAt))}` : "";
12494
+ const dateSuffix = publishedAt ? ` ${import_picocolors8.default.dim("\xB7")} ${import_picocolors8.default.dim(formatReleaseDate(publishedAt))}` : "";
13269
12495
  if (sp2)
13270
- sp2.stop(`${import_picocolors10.default.green(latestVersion)}${dateSuffix}`);
12496
+ sp2.stop(`${import_picocolors8.default.green(latestVersion)}${dateSuffix}`);
13271
12497
  else
13272
12498
  writeLine(`latest: ${latestVersion}`);
13273
12499
  } catch (err) {
@@ -13288,12 +12514,12 @@ async function runUpdate(opts = {}) {
13288
12514
  if (check) {
13289
12515
  if (isTTY) {
13290
12516
  if (currentVersion !== latestVersion) {
13291
- barLine(`⬆️ ${import_picocolors10.default.dim(currentVersion)} ${import_picocolors10.default.green(latestVersion)} · binary would upgrade`);
12517
+ barLine(`\u2B06\uFE0F ${import_picocolors8.default.dim(currentVersion)} \u2192 ${import_picocolors8.default.green(latestVersion)} \xB7 binary would upgrade`);
13292
12518
  barBlank();
13293
12519
  }
13294
- close("Dry run complete no changes made");
12520
+ close("Dry run complete \u2014 no changes made");
13295
12521
  } else {
13296
- writeLine("done: dry run complete no changes made");
12522
+ writeLine("done: dry run complete \u2014 no changes made");
13297
12523
  }
13298
12524
  result.ok = true;
13299
12525
  result.exitCode = 0;
@@ -13301,7 +12527,7 @@ async function runUpdate(opts = {}) {
13301
12527
  }
13302
12528
  if (latestVersion === currentVersion) {
13303
12529
  if (isTTY) {
13304
- close(`Already up to date @onebrain-ai/cli ${import_picocolors10.default.dim(latestVersion)}`);
12530
+ close(`Already up to date \u2014 @onebrain-ai/cli ${import_picocolors8.default.dim(latestVersion)}`);
13305
12531
  } else {
13306
12532
  writeLine(`already up to date: @onebrain-ai/cli ${latestVersion}`);
13307
12533
  writeLine("done: nothing to do");
@@ -13311,14 +12537,14 @@ async function runUpdate(opts = {}) {
13311
12537
  return result;
13312
12538
  }
13313
12539
  if (isTTY) {
13314
- barLine(`⬆️ ${import_picocolors10.default.dim(currentVersion)} ${import_picocolors10.default.green(latestVersion)}`);
12540
+ barLine(`\u2B06\uFE0F ${import_picocolors8.default.dim(currentVersion)} \u2192 ${import_picocolors8.default.green(latestVersion)}`);
13315
12541
  barBlank();
13316
12542
  }
13317
12543
  const sp3 = createStep("\uD83D\uDCE6", "Installing @onebrain-ai/cli");
13318
12544
  try {
13319
12545
  await installBinaryFn(latestVersion);
13320
12546
  if (sp3)
13321
- sp3.stop(import_picocolors10.default.green(latestVersion));
12547
+ sp3.stop(import_picocolors8.default.green(latestVersion));
13322
12548
  else
13323
12549
  writeLine(`upgrading: @onebrain-ai/cli ${latestVersion} installed`);
13324
12550
  } catch (err) {
@@ -13335,7 +12561,7 @@ async function runUpdate(opts = {}) {
13335
12561
  }
13336
12562
  return result;
13337
12563
  }
13338
- const sp4 = createStep("", "Validating binary");
12564
+ const sp4 = createStep("\u2705", "Validating binary");
13339
12565
  const binaryValid = await validateBinaryFn();
13340
12566
  if (!binaryValid) {
13341
12567
  if (sp4)
@@ -13355,7 +12581,7 @@ async function runUpdate(opts = {}) {
13355
12581
  result.ok = true;
13356
12582
  result.exitCode = 0;
13357
12583
  if (isTTY) {
13358
- close(`Done run ${import_picocolors10.default.cyan("/update")} in Claude to sync vault files`);
12584
+ close(`Done \u2014 run ${import_picocolors8.default.cyan("/update")} in Claude to sync vault files`);
13359
12585
  } else {
13360
12586
  writeLine("done: run /update in Claude to sync vault files");
13361
12587
  }
@@ -13382,7 +12608,7 @@ function patchUtf8(stream) {
13382
12608
  }
13383
12609
 
13384
12610
  // src/index.ts
13385
- var VERSION = "2.1.2";
12611
+ var VERSION = "2.1.4";
13386
12612
  var RELEASE_DATE = "2026-04-28";
13387
12613
  patchUtf8(process.stdout);
13388
12614
  patchUtf8(process.stderr);
@@ -13397,9 +12623,9 @@ function findVaultRoot(startDir) {
13397
12623
  return process.cwd();
13398
12624
  let dir = startDir;
13399
12625
  while (true) {
13400
- if (existsSync(join13(dir, "vault.yml")))
12626
+ if (existsSync(join11(dir, "vault.yml")))
13401
12627
  return dir;
13402
- const parent = dirname6(dir);
12628
+ const parent = dirname4(dir);
13403
12629
  if (parent === dir)
13404
12630
  return startDir;
13405
12631
  dir = parent;
@@ -13446,10 +12672,10 @@ program2.command("qmd-reindex", { hidden: true }).description("Trigger qmd index
13446
12672
  });
13447
12673
  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
12674
  const root = vaultRoot ?? process.cwd();
13449
- await vaultSyncCommand2(root, opts.branch !== undefined ? { branch: opts.branch } : {});
12675
+ await vaultSyncCommand(root, opts.branch !== undefined ? { branch: opts.branch } : {});
13450
12676
  });
13451
12677
  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);
12678
+ await registerHooksCommand(opts.vaultDir);
13453
12679
  });
13454
12680
  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
12681
  await migrateCommand(name, cutoffDate);