@onebrain-ai/cli 2.1.0 → 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/README.md +6 -3
- package/dist/onebrain +534 -1262
- package/dist/postinstall.js +138 -0
- package/package.json +5 -3
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 =
|
|
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
|
|
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("
|
|
612
|
-
var childProcess = __require("
|
|
613
|
-
var path = __require("
|
|
614
|
-
var fs = __require("
|
|
615
|
-
var process2 = __require("
|
|
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 = "
|
|
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 "
|
|
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 "
|
|
8977
|
-
import { join as join2 } from "
|
|
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);
|
|
@@ -9015,7 +9014,7 @@ async function checkVaultYml(vaultRoot) {
|
|
|
9015
9014
|
check: "vault.yml",
|
|
9016
9015
|
status: "ok",
|
|
9017
9016
|
message: "valid",
|
|
9018
|
-
details
|
|
9017
|
+
...details.length > 0 ? { details } : {}
|
|
9019
9018
|
};
|
|
9020
9019
|
}
|
|
9021
9020
|
async function checkFolders(vaultRoot, config) {
|
|
@@ -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
|
|
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
|
|
9269
|
+
details: [`${skillCount} skills \xB7 ${agentCount} agents \xB7 INSTRUCTIONS.md \u2713`]
|
|
9271
9270
|
};
|
|
9272
9271
|
}
|
|
9273
9272
|
async function checkVaultYmlKeys(vaultRoot) {
|
|
@@ -9338,7 +9337,7 @@ async function checkVaultYmlKeys(vaultRoot) {
|
|
|
9338
9337
|
check: "vault.yml-keys",
|
|
9339
9338
|
status: "error",
|
|
9340
9339
|
message: `${errors.length} error(s)`,
|
|
9341
|
-
hint,
|
|
9340
|
+
...hint !== undefined ? { hint } : {},
|
|
9342
9341
|
details: hint ? [...errors, hint] : errors
|
|
9343
9342
|
};
|
|
9344
9343
|
}
|
|
@@ -9349,7 +9348,7 @@ async function checkVaultYmlKeys(vaultRoot) {
|
|
|
9349
9348
|
check: "vault.yml-keys",
|
|
9350
9349
|
status: "warn",
|
|
9351
9350
|
message: `${warnings.length} issue(s)`,
|
|
9352
|
-
hint,
|
|
9351
|
+
...hint !== undefined ? { hint } : {},
|
|
9353
9352
|
details: hint ? [...warnings, hint] : warnings
|
|
9354
9353
|
};
|
|
9355
9354
|
}
|
|
@@ -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,12 +9437,12 @@ 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",
|
|
9445
9444
|
message: "hooks ok",
|
|
9446
|
-
|
|
9445
|
+
...okDetails.length > 0 ? { details: okDetails } : {}
|
|
9447
9446
|
};
|
|
9448
9447
|
}
|
|
9449
9448
|
var import_yaml2, STANDARD_FOLDER_KEYS, REQUIRED_PLUGIN_FILES, REQUIRED_PLUGIN_DIRS, STALE_BASH_FILES, REQUIRED_VAULT_YML_KEYS, REQUIRED_FOLDER_KEYS, REQUIRED_HOOKS, QMD_HOOK_SUBSTRING = "onebrain qmd-reindex", PRECOMPACT_ONEBRAIN_SUBSTRING = "onebrain", REQUIRED_PERMISSION = "Bash(onebrain *)", STALE_HOOK_SUBSTRINGS;
|
|
@@ -9498,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.
|
|
9502
|
-
description: "CLI for OneBrain
|
|
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
|
-
build: "bun build src/index.ts --outfile dist/onebrain --target
|
|
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
|
},
|
|
@@ -9545,6 +9546,129 @@ var require_package = __commonJS((exports, module) => {
|
|
|
9545
9546
|
};
|
|
9546
9547
|
});
|
|
9547
9548
|
|
|
9549
|
+
// src/commands/internal/cli-ui.ts
|
|
9550
|
+
function out(str) {
|
|
9551
|
+
process.stdout.write(Buffer.from(str, "utf8"));
|
|
9552
|
+
}
|
|
9553
|
+
function writeLine(msg) {
|
|
9554
|
+
out(`${msg}
|
|
9555
|
+
`);
|
|
9556
|
+
}
|
|
9557
|
+
function barLine(msg) {
|
|
9558
|
+
out(`${bar} ${msg}
|
|
9559
|
+
`);
|
|
9560
|
+
}
|
|
9561
|
+
function barBlank() {
|
|
9562
|
+
out(`${bar}
|
|
9563
|
+
`);
|
|
9564
|
+
}
|
|
9565
|
+
function close(msg, isError = false, isWarning = false) {
|
|
9566
|
+
if (isError) {
|
|
9567
|
+
out(`${import_picocolors2.default.cyan("\u2514")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
|
|
9568
|
+
`);
|
|
9569
|
+
} else if (isWarning) {
|
|
9570
|
+
out(`${import_picocolors2.default.cyan("\u2514")} ${import_picocolors2.default.yellow(msg)}
|
|
9571
|
+
`);
|
|
9572
|
+
} else {
|
|
9573
|
+
out(`${import_picocolors2.default.cyan("\u2514")} ${msg}
|
|
9574
|
+
`);
|
|
9575
|
+
}
|
|
9576
|
+
}
|
|
9577
|
+
function dotLine(emoji, label) {
|
|
9578
|
+
out(`${dot} ${emoji} ${label}
|
|
9579
|
+
`);
|
|
9580
|
+
}
|
|
9581
|
+
function makeStepFn(isTTY) {
|
|
9582
|
+
return function createStep(emoji, label) {
|
|
9583
|
+
if (!isTTY)
|
|
9584
|
+
return null;
|
|
9585
|
+
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
9586
|
+
let i = 0;
|
|
9587
|
+
out(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}\u2026
|
|
9588
|
+
`);
|
|
9589
|
+
const timer = setInterval(() => {
|
|
9590
|
+
i = (i + 1) % frames.length;
|
|
9591
|
+
out(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}\u2026
|
|
9592
|
+
`);
|
|
9593
|
+
}, 80);
|
|
9594
|
+
return {
|
|
9595
|
+
stop(result, details) {
|
|
9596
|
+
clearInterval(timer);
|
|
9597
|
+
process.stdout.write(Buffer.from("\x1B[1A\x1B[2K", "utf8"));
|
|
9598
|
+
out(`${dot} ${emoji} ${label}
|
|
9599
|
+
`);
|
|
9600
|
+
if (result !== undefined)
|
|
9601
|
+
barLine(result);
|
|
9602
|
+
if (details)
|
|
9603
|
+
for (const d of details)
|
|
9604
|
+
barLine(` \xB7 ${d}`);
|
|
9605
|
+
barBlank();
|
|
9606
|
+
}
|
|
9607
|
+
};
|
|
9608
|
+
};
|
|
9609
|
+
}
|
|
9610
|
+
async function askYesNo(question) {
|
|
9611
|
+
out(`${import_picocolors2.default.cyan("\u25C6")} ${question}
|
|
9612
|
+
`);
|
|
9613
|
+
process.stdout.write(Buffer.from("\x1B[?25l", "utf8"));
|
|
9614
|
+
function renderOptions(yes) {
|
|
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`;
|
|
9617
|
+
out(`\x1B[2K${bar} ${yesLabel} / ${noLabel}\r`);
|
|
9618
|
+
}
|
|
9619
|
+
const answer = await new Promise((resolve) => {
|
|
9620
|
+
let selected = true;
|
|
9621
|
+
renderOptions(selected);
|
|
9622
|
+
const { stdin } = process;
|
|
9623
|
+
const wasRaw = stdin.isTTY ? stdin.isRaw : false;
|
|
9624
|
+
if (stdin.isTTY)
|
|
9625
|
+
stdin.setRawMode(true);
|
|
9626
|
+
stdin.resume();
|
|
9627
|
+
function onData(buf) {
|
|
9628
|
+
const key = buf.toString();
|
|
9629
|
+
if (key === "\x03") {
|
|
9630
|
+
stdin.removeListener("data", onData);
|
|
9631
|
+
if (stdin.isTTY)
|
|
9632
|
+
stdin.setRawMode(wasRaw);
|
|
9633
|
+
stdin.pause();
|
|
9634
|
+
resolve(null);
|
|
9635
|
+
} else if (key === "\r" || key === `
|
|
9636
|
+
`) {
|
|
9637
|
+
stdin.removeListener("data", onData);
|
|
9638
|
+
if (stdin.isTTY)
|
|
9639
|
+
stdin.setRawMode(wasRaw);
|
|
9640
|
+
stdin.pause();
|
|
9641
|
+
resolve(selected);
|
|
9642
|
+
} else if (key === "y" || key === "Y") {
|
|
9643
|
+
stdin.removeListener("data", onData);
|
|
9644
|
+
if (stdin.isTTY)
|
|
9645
|
+
stdin.setRawMode(wasRaw);
|
|
9646
|
+
stdin.pause();
|
|
9647
|
+
resolve(true);
|
|
9648
|
+
} else if (key === "n" || key === "N") {
|
|
9649
|
+
stdin.removeListener("data", onData);
|
|
9650
|
+
if (stdin.isTTY)
|
|
9651
|
+
stdin.setRawMode(wasRaw);
|
|
9652
|
+
stdin.pause();
|
|
9653
|
+
resolve(false);
|
|
9654
|
+
} else if (key === "\x1B[C" || key === "\x1B[D" || key === "\t") {
|
|
9655
|
+
selected = !selected;
|
|
9656
|
+
renderOptions(selected);
|
|
9657
|
+
}
|
|
9658
|
+
}
|
|
9659
|
+
stdin.on("data", onData);
|
|
9660
|
+
});
|
|
9661
|
+
process.stdout.write(Buffer.from(`
|
|
9662
|
+
\x1B[?25h\x1B[1A\x1B[2K`, "utf8"));
|
|
9663
|
+
return answer;
|
|
9664
|
+
}
|
|
9665
|
+
var import_picocolors2, bar, dot;
|
|
9666
|
+
var init_cli_ui = __esm(() => {
|
|
9667
|
+
import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
9668
|
+
bar = import_picocolors2.default.cyan("\u2502");
|
|
9669
|
+
dot = import_picocolors2.default.green("\u25CF");
|
|
9670
|
+
});
|
|
9671
|
+
|
|
9548
9672
|
// node_modules/sisteransi/src/index.js
|
|
9549
9673
|
var require_src = __commonJS((exports, module) => {
|
|
9550
9674
|
var ESC = "\x1B";
|
|
@@ -9604,8 +9728,8 @@ var require_src = __commonJS((exports, module) => {
|
|
|
9604
9728
|
});
|
|
9605
9729
|
|
|
9606
9730
|
// node_modules/@clack/core/dist/index.mjs
|
|
9607
|
-
import { stdin as $, stdout as j } from "
|
|
9608
|
-
import * as f from "
|
|
9731
|
+
import { stdin as $, stdout as j } from "process";
|
|
9732
|
+
import * as f from "readline";
|
|
9609
9733
|
function J({ onlyFirst: t = false } = {}) {
|
|
9610
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("|");
|
|
9611
9735
|
return new RegExp(F, t ? undefined : "g");
|
|
@@ -9724,7 +9848,7 @@ var init_dist = __esm(() => {
|
|
|
9724
9848
|
eD = Object.keys(r.bgColor);
|
|
9725
9849
|
[...tD, ...eD];
|
|
9726
9850
|
iD = sD();
|
|
9727
|
-
v = new Set(["\x1B", "
|
|
9851
|
+
v = new Set(["\x1B", "\x9B"]);
|
|
9728
9852
|
y = `${rD}8;;`;
|
|
9729
9853
|
aD = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
9730
9854
|
c = { actions: new Set(aD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
|
|
@@ -9733,7 +9857,7 @@ var init_dist = __esm(() => {
|
|
|
9733
9857
|
});
|
|
9734
9858
|
|
|
9735
9859
|
// node_modules/@clack/prompts/dist/index.mjs
|
|
9736
|
-
import p from "
|
|
9860
|
+
import p from "process";
|
|
9737
9861
|
function X2() {
|
|
9738
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";
|
|
9739
9863
|
}
|
|
@@ -9746,7 +9870,7 @@ ${import_picocolors3.default.gray(m2)} ${s}
|
|
|
9746
9870
|
|
|
9747
9871
|
`);
|
|
9748
9872
|
}, L2 = () => {
|
|
9749
|
-
const s = E ? ["
|
|
9873
|
+
const s = E ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], n = E ? 80 : 120, t = process.env.CI === "true";
|
|
9750
9874
|
let i, r2, c2 = false, o = "", l2;
|
|
9751
9875
|
const $2 = (h) => {
|
|
9752
9876
|
const g = h > 1 ? "Something went wrong" : "Canceled";
|
|
@@ -9790,32 +9914,32 @@ var init_dist2 = __esm(() => {
|
|
|
9790
9914
|
import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
9791
9915
|
import_sisteransi2 = __toESM(require_src(), 1);
|
|
9792
9916
|
E = X2();
|
|
9793
|
-
ee = u("
|
|
9794
|
-
A = u("
|
|
9795
|
-
B = u("
|
|
9796
|
-
S2 = u("
|
|
9797
|
-
te = u("
|
|
9798
|
-
a = u("
|
|
9799
|
-
m2 = u("
|
|
9800
|
-
j2 = u("
|
|
9801
|
-
R = u("
|
|
9802
|
-
V = u("
|
|
9803
|
-
M = u("
|
|
9804
|
-
G = u("
|
|
9805
|
-
se = u("
|
|
9806
|
-
N2 = u("
|
|
9807
|
-
re = u("
|
|
9808
|
-
ie = u("
|
|
9809
|
-
ne = u("
|
|
9810
|
-
ae = u("
|
|
9811
|
-
oe = u("
|
|
9812
|
-
ce = u("
|
|
9813
|
-
le = u("
|
|
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");
|
|
9814
9938
|
});
|
|
9815
9939
|
|
|
9816
9940
|
// src/commands/internal/harness.ts
|
|
9817
|
-
import { stat as stat2 } from "
|
|
9818
|
-
import { join as join3 } from "
|
|
9941
|
+
import { stat as stat2 } from "fs/promises";
|
|
9942
|
+
import { join as join3 } from "path";
|
|
9819
9943
|
async function pathExists(p2) {
|
|
9820
9944
|
try {
|
|
9821
9945
|
await stat2(p2);
|
|
@@ -9833,7 +9957,7 @@ async function detectHarness(vaultRoot) {
|
|
|
9833
9957
|
return "gemini";
|
|
9834
9958
|
if (env === "direct")
|
|
9835
9959
|
return "direct";
|
|
9836
|
-
process.stderr.write(`harness: unknown ONEBRAIN_HARNESS value "${env}"
|
|
9960
|
+
process.stderr.write(`harness: unknown ONEBRAIN_HARNESS value "${env}" \u2014 ignoring, falling back to directory detection
|
|
9837
9961
|
`);
|
|
9838
9962
|
}
|
|
9839
9963
|
if (await pathExists(join3(vaultRoot, ".gemini")))
|
|
@@ -9850,9 +9974,9 @@ __export(exports_register_hooks, {
|
|
|
9850
9974
|
runRegisterHooks: () => runRegisterHooks,
|
|
9851
9975
|
registerHooksCommand: () => registerHooksCommand
|
|
9852
9976
|
});
|
|
9853
|
-
import { mkdir, readFile, rename, writeFile } from "
|
|
9854
|
-
import { homedir } from "
|
|
9855
|
-
import { dirname, join as join4 } from "
|
|
9977
|
+
import { mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
9978
|
+
import { homedir } from "os";
|
|
9979
|
+
import { dirname, join as join4 } from "path";
|
|
9856
9980
|
async function readSettings(settingsPath) {
|
|
9857
9981
|
try {
|
|
9858
9982
|
const text = await readFile(settingsPath, "utf8");
|
|
@@ -10029,11 +10153,11 @@ async function runRegisterHooks(opts = {}) {
|
|
|
10029
10153
|
if (isTTY) {
|
|
10030
10154
|
const parts = HOOK_EVENTS.map((e2) => {
|
|
10031
10155
|
const status = result.hooks[e2];
|
|
10032
|
-
const icon = import_picocolors4.default.green(status === "ok" ? "
|
|
10156
|
+
const icon = import_picocolors4.default.green(status === "ok" ? "\u2713" : status === "migrated" ? "\u2191" : "+");
|
|
10033
10157
|
return `${import_picocolors4.default.dim(e2)} ${icon}`;
|
|
10034
10158
|
});
|
|
10035
10159
|
if (qmdStatus)
|
|
10036
|
-
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" : "+")}`);
|
|
10037
10161
|
hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
|
|
10038
10162
|
} else {
|
|
10039
10163
|
const hookLine = HOOK_EVENTS.map((e2) => {
|
|
@@ -10129,9 +10253,9 @@ import {
|
|
|
10129
10253
|
stat as stat3,
|
|
10130
10254
|
unlink,
|
|
10131
10255
|
writeFile as writeFile2
|
|
10132
|
-
} from "
|
|
10133
|
-
import { homedir as homedir2, tmpdir } from "
|
|
10134
|
-
import { dirname as dirname2, join as join5, relative } from "
|
|
10256
|
+
} from "fs/promises";
|
|
10257
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
10258
|
+
import { dirname as dirname2, join as join5, relative } from "path";
|
|
10135
10259
|
function resolveBranch(updateChannel) {
|
|
10136
10260
|
return updateChannel === "stable" ? "main" : "next";
|
|
10137
10261
|
}
|
|
@@ -10140,9 +10264,9 @@ async function downloadTarball(branch, fetchFn) {
|
|
|
10140
10264
|
const response = await fetchFn(url);
|
|
10141
10265
|
if (!response.ok) {
|
|
10142
10266
|
const hints = {
|
|
10143
|
-
403: "
|
|
10144
|
-
404: "
|
|
10145
|
-
429: "
|
|
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"
|
|
10146
10270
|
};
|
|
10147
10271
|
const hint = hints[response.status] ?? "";
|
|
10148
10272
|
throw new Error(`HTTP ${response.status} downloading tarball from ${url}${hint}`);
|
|
@@ -10461,35 +10585,47 @@ async function runVaultSync(vaultRoot, opts = {}) {
|
|
|
10461
10585
|
pinSkipped: true,
|
|
10462
10586
|
cacheRemoved: 0
|
|
10463
10587
|
};
|
|
10588
|
+
const embedded = opts.embedded ?? false;
|
|
10589
|
+
const createEmbeddedStep = embedded ? makeStepFn(true) : null;
|
|
10464
10590
|
let s = null;
|
|
10465
|
-
|
|
10591
|
+
let currentStep = null;
|
|
10592
|
+
function startSpinner(emoji, label) {
|
|
10466
10593
|
if (isTTY) {
|
|
10467
|
-
|
|
10468
|
-
|
|
10594
|
+
if (embedded) {
|
|
10595
|
+
currentStep = createEmbeddedStep(emoji, label);
|
|
10596
|
+
} else {
|
|
10597
|
+
s = L2();
|
|
10598
|
+
s.start(label);
|
|
10599
|
+
}
|
|
10469
10600
|
} else {
|
|
10470
|
-
process.stdout.write(`vault-sync: ${
|
|
10601
|
+
process.stdout.write(`vault-sync: ${label}
|
|
10471
10602
|
`);
|
|
10472
10603
|
}
|
|
10473
10604
|
}
|
|
10474
|
-
function stopSpinner(
|
|
10475
|
-
if (isTTY
|
|
10476
|
-
|
|
10477
|
-
|
|
10605
|
+
function stopSpinner(result2, details) {
|
|
10606
|
+
if (isTTY) {
|
|
10607
|
+
if (embedded) {
|
|
10608
|
+
currentStep?.stop(import_picocolors6.default.dim(result2), details);
|
|
10609
|
+
currentStep = null;
|
|
10610
|
+
} else if (s) {
|
|
10611
|
+
s.stop(result2);
|
|
10612
|
+
s = null;
|
|
10613
|
+
}
|
|
10478
10614
|
}
|
|
10479
10615
|
}
|
|
10480
|
-
if (isTTY) {
|
|
10616
|
+
if (isTTY && !embedded) {
|
|
10481
10617
|
we("OneBrain Vault Sync");
|
|
10482
10618
|
}
|
|
10483
10619
|
let tmpDir = null;
|
|
10484
10620
|
try {
|
|
10485
|
-
startSpinner("
|
|
10621
|
+
startSpinner("\uD83D\uDCE5", "Downloading");
|
|
10486
10622
|
let extractedDir;
|
|
10487
10623
|
try {
|
|
10488
10624
|
const dl = await downloadTarball(branch, fetchFn);
|
|
10489
10625
|
tmpDir = dl.tmpDir;
|
|
10490
10626
|
extractedDir = await extractTarball(dl.tarball, tmpDir);
|
|
10491
10627
|
} catch (err) {
|
|
10492
|
-
stopSpinner("
|
|
10628
|
+
stopSpinner("download failed");
|
|
10493
10629
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10494
10630
|
result.error = msg;
|
|
10495
10631
|
process.stderr.write(`vault-sync: download failed: ${msg}
|
|
@@ -10504,13 +10640,13 @@ async function runVaultSync(vaultRoot, opts = {}) {
|
|
|
10504
10640
|
}
|
|
10505
10641
|
} catch {}
|
|
10506
10642
|
stopSpinner(`kengio/onebrain@${branch} (v${result.version})`);
|
|
10507
|
-
startSpinner("Syncing
|
|
10643
|
+
startSpinner("\uD83D\uDCC2", "Syncing files");
|
|
10508
10644
|
try {
|
|
10509
10645
|
const { filesAdded, filesRemoved } = await syncPluginFiles(extractedDir, vaultRoot, unlinkFn);
|
|
10510
10646
|
result.filesAdded = filesAdded;
|
|
10511
10647
|
result.filesRemoved = filesRemoved;
|
|
10512
10648
|
} catch (err) {
|
|
10513
|
-
stopSpinner("
|
|
10649
|
+
stopSpinner("plugin sync failed");
|
|
10514
10650
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10515
10651
|
result.error = msg;
|
|
10516
10652
|
process.stderr.write(`vault-sync: plugin sync failed: ${msg}
|
|
@@ -10533,13 +10669,13 @@ async function runVaultSync(vaultRoot, opts = {}) {
|
|
|
10533
10669
|
} catch {}
|
|
10534
10670
|
}
|
|
10535
10671
|
await copyRootDocs(extractedDir, vaultRoot);
|
|
10536
|
-
startSpinner("Updating harness
|
|
10672
|
+
startSpinner("\uD83D\uDD27", "Updating harness");
|
|
10537
10673
|
let importsAdded = 0;
|
|
10538
10674
|
try {
|
|
10539
10675
|
importsAdded = await mergeHarnessFiles(extractedDir, vaultRoot);
|
|
10540
10676
|
result.importsAdded = importsAdded;
|
|
10541
10677
|
} catch (err) {
|
|
10542
|
-
stopSpinner("
|
|
10678
|
+
stopSpinner("harness merge failed");
|
|
10543
10679
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10544
10680
|
result.error = msg;
|
|
10545
10681
|
process.stderr.write(`vault-sync: harness merge failed: ${msg}
|
|
@@ -10561,23 +10697,23 @@ async function runVaultSync(vaultRoot, opts = {}) {
|
|
|
10561
10697
|
return result;
|
|
10562
10698
|
}
|
|
10563
10699
|
if (harness === "claude") {
|
|
10564
|
-
startSpinner("Pinning to vault
|
|
10700
|
+
startSpinner("\uD83D\uDCCC", "Pinning to vault");
|
|
10565
10701
|
try {
|
|
10566
10702
|
const pinResult = await pinToVault(vaultRoot, installedPluginsPath, installedPluginsCacheDir);
|
|
10567
10703
|
result.pinSkipped = pinResult.skipped;
|
|
10568
10704
|
if (pinResult.skipped) {
|
|
10569
10705
|
stopSpinner("pin skipped (not found or marketplace)");
|
|
10570
10706
|
} else {
|
|
10571
|
-
stopSpinner("installPath
|
|
10707
|
+
stopSpinner("installPath \u2192 .claude/plugins/onebrain");
|
|
10572
10708
|
}
|
|
10573
10709
|
} catch (err) {
|
|
10574
10710
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10575
10711
|
process.stderr.write(`vault-sync: pin warning: ${msg}
|
|
10576
10712
|
`);
|
|
10577
10713
|
result.pinSkipped = true;
|
|
10578
|
-
stopSpinner("pin skipped (error
|
|
10714
|
+
stopSpinner("pin skipped (error \u2014 non-fatal)");
|
|
10579
10715
|
}
|
|
10580
|
-
startSpinner("Cleaning cache
|
|
10716
|
+
startSpinner("\uD83E\uDDF9", "Cleaning cache");
|
|
10581
10717
|
try {
|
|
10582
10718
|
const cacheRemoved = await cleanPluginCache(installedPluginsPath, installedPluginsCacheDir);
|
|
10583
10719
|
result.cacheRemoved = cacheRemoved;
|
|
@@ -10590,12 +10726,14 @@ async function runVaultSync(vaultRoot, opts = {}) {
|
|
|
10590
10726
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10591
10727
|
process.stderr.write(`vault-sync: cache clean warning: ${msg}
|
|
10592
10728
|
`);
|
|
10593
|
-
stopSpinner("cache clean skipped (error
|
|
10729
|
+
stopSpinner("cache clean skipped (error \u2014 non-fatal)");
|
|
10594
10730
|
}
|
|
10595
10731
|
}
|
|
10596
10732
|
result.ok = true;
|
|
10597
10733
|
if (isTTY) {
|
|
10598
|
-
|
|
10734
|
+
if (!embedded) {
|
|
10735
|
+
fe(`Done \u2014 v${result.version} synced`);
|
|
10736
|
+
}
|
|
10599
10737
|
} else {
|
|
10600
10738
|
process.stdout.write(`vault-sync: done
|
|
10601
10739
|
`);
|
|
@@ -10613,16 +10751,18 @@ async function vaultSyncCommand(vaultRoot, opts = {}) {
|
|
|
10613
10751
|
process.exit(1);
|
|
10614
10752
|
}
|
|
10615
10753
|
}
|
|
10616
|
-
var import_yaml3;
|
|
10754
|
+
var import_picocolors6, import_yaml3;
|
|
10617
10755
|
var init_vault_sync = __esm(() => {
|
|
10618
10756
|
init_dist2();
|
|
10757
|
+
init_cli_ui();
|
|
10619
10758
|
init_harness();
|
|
10759
|
+
import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
10620
10760
|
import_yaml3 = __toESM(require_dist(), 1);
|
|
10621
10761
|
});
|
|
10622
10762
|
|
|
10623
10763
|
// src/index.ts
|
|
10624
10764
|
import { existsSync } from "fs";
|
|
10625
|
-
import { dirname as
|
|
10765
|
+
import { dirname as dirname4, join as join11 } from "path";
|
|
10626
10766
|
|
|
10627
10767
|
// node_modules/commander/esm.mjs
|
|
10628
10768
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -10648,7 +10788,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
|
10648
10788
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
10649
10789
|
function resolveBinaryVersion() {
|
|
10650
10790
|
if (true)
|
|
10651
|
-
return "2.1.
|
|
10791
|
+
return "2.1.4";
|
|
10652
10792
|
try {
|
|
10653
10793
|
const pkg = require_package();
|
|
10654
10794
|
return pkg.version ?? "dev";
|
|
@@ -10657,11 +10797,11 @@ function resolveBinaryVersion() {
|
|
|
10657
10797
|
}
|
|
10658
10798
|
}
|
|
10659
10799
|
var ART_LINES = [
|
|
10660
|
-
`
|
|
10661
|
-
"
|
|
10662
|
-
"
|
|
10663
|
-
"
|
|
10664
|
-
`
|
|
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`
|
|
10665
10805
|
];
|
|
10666
10806
|
var TAGLINE = "Your AI Thinking Partner";
|
|
10667
10807
|
var BANNER_LINE_COUNT = 1 + ART_LINES.length + 3;
|
|
@@ -10713,39 +10853,42 @@ function scanLine(line) {
|
|
|
10713
10853
|
function dimLine(line) {
|
|
10714
10854
|
return line.split("").map((ch) => ch === " " ? ch : `\x1B[2;38;2;50;50;70m${ch}\x1B[0m`).join("");
|
|
10715
10855
|
}
|
|
10856
|
+
function outb(str) {
|
|
10857
|
+
process.stdout.write(Buffer.from(str, "utf8"));
|
|
10858
|
+
}
|
|
10716
10859
|
function printFrame(artLines, tagline) {
|
|
10717
|
-
|
|
10860
|
+
outb(`
|
|
10718
10861
|
`);
|
|
10719
10862
|
for (const l of artLines)
|
|
10720
|
-
|
|
10863
|
+
outb(`${l}
|
|
10721
10864
|
`);
|
|
10722
|
-
|
|
10865
|
+
outb(`
|
|
10723
10866
|
`);
|
|
10724
|
-
|
|
10867
|
+
outb(`${tagline}
|
|
10725
10868
|
`);
|
|
10726
|
-
|
|
10869
|
+
outb(`
|
|
10727
10870
|
`);
|
|
10728
10871
|
}
|
|
10729
10872
|
async function printBanner() {
|
|
10730
10873
|
if (!process.stdout.isTTY)
|
|
10731
10874
|
return;
|
|
10732
10875
|
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
10733
|
-
const up = (n) =>
|
|
10876
|
+
const up = (n) => outb(`\x1B[${n}F`);
|
|
10734
10877
|
if (!supportsRgb()) {
|
|
10735
|
-
|
|
10878
|
+
outb(`
|
|
10736
10879
|
`);
|
|
10737
10880
|
for (const l of ART_LINES)
|
|
10738
|
-
|
|
10881
|
+
outb(`${import_picocolors.default.bold(import_picocolors.default.cyan(l))}
|
|
10739
10882
|
`);
|
|
10740
|
-
|
|
10883
|
+
outb(`
|
|
10741
10884
|
`);
|
|
10742
|
-
|
|
10885
|
+
outb(` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}
|
|
10743
10886
|
`);
|
|
10744
|
-
|
|
10887
|
+
outb(`
|
|
10745
10888
|
`);
|
|
10746
10889
|
return;
|
|
10747
10890
|
}
|
|
10748
|
-
|
|
10891
|
+
outb("\x1B[?25l");
|
|
10749
10892
|
try {
|
|
10750
10893
|
let diagFrame = function(highlight) {
|
|
10751
10894
|
return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
|
|
@@ -10797,7 +10940,7 @@ async function printBanner() {
|
|
|
10797
10940
|
up(BANNER_LINE_COUNT);
|
|
10798
10941
|
printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${" ".repeat(TAGLINE.length)}`);
|
|
10799
10942
|
await delay(200);
|
|
10800
|
-
const cursor =
|
|
10943
|
+
const cursor = "\x1B[1;38;2;140;255;255m\u258C\x1B[0m";
|
|
10801
10944
|
for (let len = 1;len <= TAGLINE.length; len++) {
|
|
10802
10945
|
await delay(32);
|
|
10803
10946
|
up(BANNER_LINE_COUNT);
|
|
@@ -10818,126 +10961,12 @@ async function printBanner() {
|
|
|
10818
10961
|
up(BANNER_LINE_COUNT);
|
|
10819
10962
|
printFrame(ART_LINES.map((l, i) => neonLine(l, i)), ` ${import_picocolors.default.bold(import_picocolors.default.magenta(TAGLINE))}\x1B[K`);
|
|
10820
10963
|
} finally {
|
|
10821
|
-
|
|
10822
|
-
}
|
|
10823
|
-
}
|
|
10824
|
-
|
|
10825
|
-
// src/commands/internal/cli-ui.ts
|
|
10826
|
-
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
10827
|
-
var bar = import_picocolors2.default.cyan("│");
|
|
10828
|
-
var dot = import_picocolors2.default.green("●");
|
|
10829
|
-
function writeLine(msg) {
|
|
10830
|
-
process.stdout.write(`${msg}
|
|
10831
|
-
`);
|
|
10832
|
-
}
|
|
10833
|
-
function barLine(msg) {
|
|
10834
|
-
process.stdout.write(`${bar} ${msg}
|
|
10835
|
-
`);
|
|
10836
|
-
}
|
|
10837
|
-
function barBlank() {
|
|
10838
|
-
process.stdout.write(`${bar}
|
|
10839
|
-
`);
|
|
10840
|
-
}
|
|
10841
|
-
function close(msg, isError = false, isWarning = false) {
|
|
10842
|
-
if (isError) {
|
|
10843
|
-
process.stdout.write(`${import_picocolors2.default.cyan("└")} ${import_picocolors2.default.bold(import_picocolors2.default.red(msg))}
|
|
10844
|
-
`);
|
|
10845
|
-
} else if (isWarning) {
|
|
10846
|
-
process.stdout.write(`${import_picocolors2.default.cyan("└")} ${import_picocolors2.default.yellow(msg)}
|
|
10847
|
-
`);
|
|
10848
|
-
} else {
|
|
10849
|
-
process.stdout.write(`${import_picocolors2.default.cyan("└")} ${msg}
|
|
10850
|
-
`);
|
|
10851
|
-
}
|
|
10852
|
-
}
|
|
10853
|
-
function makeStepFn(isTTY) {
|
|
10854
|
-
return function createStep(emoji, label) {
|
|
10855
|
-
if (!isTTY)
|
|
10856
|
-
return null;
|
|
10857
|
-
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
10858
|
-
let i = 0;
|
|
10859
|
-
process.stdout.write(`${import_picocolors2.default.green(frames[0])} ${emoji} ${label}…
|
|
10860
|
-
`);
|
|
10861
|
-
const timer = setInterval(() => {
|
|
10862
|
-
i = (i + 1) % frames.length;
|
|
10863
|
-
process.stdout.write(`\x1B[1A\x1B[2K${import_picocolors2.default.green(frames[i])} ${emoji} ${label}…
|
|
10864
|
-
`);
|
|
10865
|
-
}, 80);
|
|
10866
|
-
return {
|
|
10867
|
-
stop(result, details) {
|
|
10868
|
-
clearInterval(timer);
|
|
10869
|
-
process.stdout.write("\x1B[1A\x1B[2K");
|
|
10870
|
-
process.stdout.write(`${dot} ${emoji} ${label}
|
|
10871
|
-
`);
|
|
10872
|
-
if (result !== undefined)
|
|
10873
|
-
barLine(result);
|
|
10874
|
-
if (details)
|
|
10875
|
-
for (const d of details)
|
|
10876
|
-
barLine(` · ${d}`);
|
|
10877
|
-
barBlank();
|
|
10878
|
-
}
|
|
10879
|
-
};
|
|
10880
|
-
};
|
|
10881
|
-
}
|
|
10882
|
-
async function askYesNo(question) {
|
|
10883
|
-
process.stdout.write(`${import_picocolors2.default.cyan("◆")} ${question}
|
|
10884
|
-
`);
|
|
10885
|
-
process.stdout.write("\x1B[?25l");
|
|
10886
|
-
function renderOptions(yes) {
|
|
10887
|
-
const yesLabel = yes ? `${import_picocolors2.default.bold(import_picocolors2.default.green("●"))} Yes` : `${import_picocolors2.default.dim("○")} Yes`;
|
|
10888
|
-
const noLabel = yes ? `${import_picocolors2.default.dim("○")} No` : `${import_picocolors2.default.bold(import_picocolors2.default.green("●"))} No`;
|
|
10889
|
-
process.stdout.write(`\x1B[2K${bar} ${yesLabel} / ${noLabel}\r`);
|
|
10964
|
+
outb("\x1B[?25h");
|
|
10890
10965
|
}
|
|
10891
|
-
const answer = await new Promise((resolve) => {
|
|
10892
|
-
let selected = true;
|
|
10893
|
-
renderOptions(selected);
|
|
10894
|
-
const { stdin } = process;
|
|
10895
|
-
const wasRaw = stdin.isTTY ? stdin.isRaw : false;
|
|
10896
|
-
if (stdin.isTTY)
|
|
10897
|
-
stdin.setRawMode(true);
|
|
10898
|
-
stdin.resume();
|
|
10899
|
-
function onData(buf) {
|
|
10900
|
-
const key = buf.toString();
|
|
10901
|
-
if (key === "\x03") {
|
|
10902
|
-
stdin.removeListener("data", onData);
|
|
10903
|
-
if (stdin.isTTY)
|
|
10904
|
-
stdin.setRawMode(wasRaw);
|
|
10905
|
-
stdin.pause();
|
|
10906
|
-
resolve(null);
|
|
10907
|
-
} else if (key === "\r" || key === `
|
|
10908
|
-
`) {
|
|
10909
|
-
stdin.removeListener("data", onData);
|
|
10910
|
-
if (stdin.isTTY)
|
|
10911
|
-
stdin.setRawMode(wasRaw);
|
|
10912
|
-
stdin.pause();
|
|
10913
|
-
resolve(selected);
|
|
10914
|
-
} else if (key === "y" || key === "Y") {
|
|
10915
|
-
stdin.removeListener("data", onData);
|
|
10916
|
-
if (stdin.isTTY)
|
|
10917
|
-
stdin.setRawMode(wasRaw);
|
|
10918
|
-
stdin.pause();
|
|
10919
|
-
resolve(true);
|
|
10920
|
-
} else if (key === "n" || key === "N") {
|
|
10921
|
-
stdin.removeListener("data", onData);
|
|
10922
|
-
if (stdin.isTTY)
|
|
10923
|
-
stdin.setRawMode(wasRaw);
|
|
10924
|
-
stdin.pause();
|
|
10925
|
-
resolve(false);
|
|
10926
|
-
} else if (key === "\x1B[C" || key === "\x1B[D" || key === "\t") {
|
|
10927
|
-
selected = !selected;
|
|
10928
|
-
renderOptions(selected);
|
|
10929
|
-
}
|
|
10930
|
-
}
|
|
10931
|
-
stdin.on("data", onData);
|
|
10932
|
-
});
|
|
10933
|
-
process.stdout.write(`
|
|
10934
|
-
`);
|
|
10935
|
-
process.stdout.write("\x1B[?25h");
|
|
10936
|
-
process.stdout.write("\x1B[1A\x1B[2K");
|
|
10937
|
-
return answer;
|
|
10938
10966
|
}
|
|
10939
10967
|
|
|
10940
10968
|
// src/commands/doctor.ts
|
|
10969
|
+
init_cli_ui();
|
|
10941
10970
|
async function runDoctor(opts = {}) {
|
|
10942
10971
|
const vaultDir = opts.vaultDir ?? process.cwd();
|
|
10943
10972
|
const isTTY = opts.isTTY ?? process.stdout.isTTY ?? false;
|
|
@@ -10990,7 +11019,7 @@ async function runDoctor(opts = {}) {
|
|
|
10990
11019
|
let vaultYmlKeysResult;
|
|
10991
11020
|
let settingsHooksResult;
|
|
10992
11021
|
if (isTTY) {
|
|
10993
|
-
const sp2 = createStep("
|
|
11022
|
+
const sp2 = createStep("\u2699\uFE0F", "Config schema");
|
|
10994
11023
|
vaultYmlKeysResult = await checkVaultYmlKeysFn(vaultDir);
|
|
10995
11024
|
await randDelay();
|
|
10996
11025
|
sp2.stop(fmtResult(vaultYmlKeysResult), vaultYmlKeysResult.details);
|
|
@@ -11054,15 +11083,15 @@ async function runDoctor(opts = {}) {
|
|
|
11054
11083
|
printNonTtyOutput(results, totalChecks, errorCount, warningCount, showFixHint, fixableCount);
|
|
11055
11084
|
} else {
|
|
11056
11085
|
if (errorCount > 0) {
|
|
11057
|
-
close(`${summaryParts.join("
|
|
11086
|
+
close(`${summaryParts.join(" \xB7 ")} \u2014 fix before using`, true);
|
|
11058
11087
|
} else if (warningCount > 0) {
|
|
11059
|
-
close(`${summaryParts.join("
|
|
11088
|
+
close(`${summaryParts.join(" \xB7 ")} \u2014 advisory only, safe to run`, false, true);
|
|
11060
11089
|
} else {
|
|
11061
|
-
close(import_picocolors5.default.green(`${summaryParts.join("
|
|
11090
|
+
close(import_picocolors5.default.green(`${summaryParts.join(" \xB7 ")} \u2014 all passed`));
|
|
11062
11091
|
}
|
|
11063
11092
|
if (showFixHint) {
|
|
11064
11093
|
process.stdout.write(`
|
|
11065
|
-
|
|
11094
|
+
\u2192 Run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to auto-fix ${fixableCount} issue(s)
|
|
11066
11095
|
`);
|
|
11067
11096
|
}
|
|
11068
11097
|
}
|
|
@@ -11083,21 +11112,21 @@ async function doctorCommand(opts = {}) {
|
|
|
11083
11112
|
function printNonTtyOutput(results, totalChecks, errorCount, warningCount, showFixHint, fixableCount) {
|
|
11084
11113
|
const lines = ["OneBrain Doctor", ""];
|
|
11085
11114
|
for (const result of results) {
|
|
11086
|
-
const icon = result.status === "ok" ? "[
|
|
11115
|
+
const icon = result.status === "ok" ? "[\u2713]" : result.status === "warn" ? "[!]" : "[\u2717]";
|
|
11087
11116
|
lines.push(` ${icon} ${result.check.padEnd(20)} ${result.message}`);
|
|
11088
11117
|
if (result.hint)
|
|
11089
|
-
lines.push(`
|
|
11118
|
+
lines.push(` \u2192 ${result.hint}`);
|
|
11090
11119
|
if (result.details)
|
|
11091
11120
|
for (const d of result.details)
|
|
11092
|
-
lines.push(`
|
|
11121
|
+
lines.push(` \xB7 ${d}`);
|
|
11093
11122
|
}
|
|
11094
11123
|
lines.push("");
|
|
11095
11124
|
if (errorCount > 0) {
|
|
11096
|
-
lines.push(`Summary: ${totalChecks} checks
|
|
11125
|
+
lines.push(`Summary: ${totalChecks} checks \xB7 ${errorCount} error(s) \xB7 ${warningCount} warning(s) \u2014 fix before using`);
|
|
11097
11126
|
} else if (warningCount > 0) {
|
|
11098
|
-
lines.push(`Summary: ${totalChecks} checks
|
|
11127
|
+
lines.push(`Summary: ${totalChecks} checks \xB7 ${warningCount} warning(s) \u2014 ok to run`);
|
|
11099
11128
|
} else {
|
|
11100
|
-
lines.push(`Summary: ${totalChecks} checks
|
|
11129
|
+
lines.push(`Summary: ${totalChecks} checks \u2014 all passed`);
|
|
11101
11130
|
}
|
|
11102
11131
|
if (showFixHint)
|
|
11103
11132
|
lines.push(`hint: run onebrain doctor --fix to auto-fix ${fixableCount} issue(s)`);
|
|
@@ -11126,8 +11155,8 @@ function getFix(r2) {
|
|
|
11126
11155
|
const description = deprecated.length > 0 ? `Remove deprecated keys from vault.yml: ${deprecated.join(", ")}` : "Remove deprecated keys from vault.yml";
|
|
11127
11156
|
return {
|
|
11128
11157
|
fn: async (vaultDir) => {
|
|
11129
|
-
const { readFile: readFile2, writeFile: writeFile2, rename: rename2 } = await import("
|
|
11130
|
-
const { join: join5 } = await import("
|
|
11158
|
+
const { readFile: readFile2, writeFile: writeFile2, rename: rename2 } = await import("fs/promises");
|
|
11159
|
+
const { join: join5 } = await import("path");
|
|
11131
11160
|
const { parse: parse3, stringify } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
11132
11161
|
const vaultYmlPath = join5(vaultDir, "vault.yml");
|
|
11133
11162
|
const text = await readFile2(vaultYmlPath, "utf8");
|
|
@@ -11159,9 +11188,9 @@ function getFix(r2) {
|
|
|
11159
11188
|
const count = pendingMatch?.[1] ?? "some";
|
|
11160
11189
|
return {
|
|
11161
11190
|
fn: async (vaultDir) => {
|
|
11162
|
-
const { join: join5 } = await import("
|
|
11191
|
+
const { join: join5 } = await import("path");
|
|
11163
11192
|
const { parse: parseYaml } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
11164
|
-
const { readFile: readFile2 } = await import("
|
|
11193
|
+
const { readFile: readFile2 } = await import("fs/promises");
|
|
11165
11194
|
const raw = parseYaml(await readFile2(join5(vaultDir, "vault.yml"), "utf8"));
|
|
11166
11195
|
const collection = raw["qmd_collection"];
|
|
11167
11196
|
if (!collection)
|
|
@@ -11187,8 +11216,8 @@ function getFix(r2) {
|
|
|
11187
11216
|
const missingStr = r2.hint.replace("Missing: ", "");
|
|
11188
11217
|
return {
|
|
11189
11218
|
fn: async (vaultDir) => {
|
|
11190
|
-
const { mkdir: mkdir2 } = await import("
|
|
11191
|
-
const { join: join5 } = await import("
|
|
11219
|
+
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
11220
|
+
const { join: join5 } = await import("path");
|
|
11192
11221
|
const missing = missingStr.split(", ").map((f2) => f2.trim()).filter(Boolean);
|
|
11193
11222
|
for (const folder of missing) {
|
|
11194
11223
|
await mkdir2(join5(vaultDir, folder), { recursive: true });
|
|
@@ -11203,7 +11232,7 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
|
|
|
11203
11232
|
const fixable = results.filter((r2) => r2.status !== "ok" && getFix(r2) !== null);
|
|
11204
11233
|
if (fixable.length === 0) {
|
|
11205
11234
|
if (isTTY)
|
|
11206
|
-
barLine(`${import_picocolors5.default.green("
|
|
11235
|
+
barLine(`${import_picocolors5.default.green("\u25C6")} Nothing to fix`);
|
|
11207
11236
|
else
|
|
11208
11237
|
writeLine("nothing to fix");
|
|
11209
11238
|
return;
|
|
@@ -11213,14 +11242,14 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
|
|
|
11213
11242
|
barLine(import_picocolors5.default.bold(`${fixable.length} fix(es) to apply:`));
|
|
11214
11243
|
barBlank();
|
|
11215
11244
|
for (const r2 of fixable) {
|
|
11216
|
-
barLine(` ${import_picocolors5.default.cyan("
|
|
11245
|
+
barLine(` ${import_picocolors5.default.cyan("\u25C6")} ${getFix(r2).description}`);
|
|
11217
11246
|
}
|
|
11218
11247
|
barBlank();
|
|
11219
11248
|
const answer = await askYesNo("Apply all?");
|
|
11220
11249
|
if (answer === null || answer === false) {
|
|
11221
11250
|
barLine(import_picocolors5.default.dim("No"));
|
|
11222
11251
|
barBlank();
|
|
11223
|
-
close(`No changes made
|
|
11252
|
+
close(`No changes made \u2014 run ${import_picocolors5.default.cyan("onebrain doctor --fix")} to apply`);
|
|
11224
11253
|
return;
|
|
11225
11254
|
}
|
|
11226
11255
|
barLine("Yes");
|
|
@@ -11240,11 +11269,11 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
|
|
|
11240
11269
|
await fix.fn(vaultDir, registerHooksFn);
|
|
11241
11270
|
fixed++;
|
|
11242
11271
|
if (isTTY)
|
|
11243
|
-
barLine(`${import_picocolors5.default.green("
|
|
11272
|
+
barLine(`${import_picocolors5.default.green("\u25C6")} ${fix.description}`);
|
|
11244
11273
|
} catch (err) {
|
|
11245
11274
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
11246
11275
|
if (isTTY) {
|
|
11247
|
-
barLine(`${import_picocolors5.default.yellow("
|
|
11276
|
+
barLine(`${import_picocolors5.default.yellow("\u25B2")} Could not fix ${r2.check}: ${errMsg}`);
|
|
11248
11277
|
} else {
|
|
11249
11278
|
process.stderr.write(`doctor: fix failed for ${r2.check}: ${errMsg}
|
|
11250
11279
|
`);
|
|
@@ -11254,9 +11283,9 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
|
|
|
11254
11283
|
if (isTTY) {
|
|
11255
11284
|
barBlank();
|
|
11256
11285
|
if (fixed > 0)
|
|
11257
|
-
barLine(`${import_picocolors5.default.green("
|
|
11286
|
+
barLine(`${import_picocolors5.default.green("\u25C6")} Fixed ${fixed} issue(s)`);
|
|
11258
11287
|
if (unfixable.length > 0) {
|
|
11259
|
-
barLine(`${import_picocolors5.default.yellow("
|
|
11288
|
+
barLine(`${import_picocolors5.default.yellow("\u25B2")} ${unfixable.length} issue(s) require manual action:`);
|
|
11260
11289
|
for (const r2 of unfixable) {
|
|
11261
11290
|
barLine(` ${r2.check}: ${r2.hint ?? "no auto-fix available"}`);
|
|
11262
11291
|
}
|
|
@@ -11274,11 +11303,12 @@ async function applyFixes(vaultDir, results, isTTY, registerHooksFn) {
|
|
|
11274
11303
|
}
|
|
11275
11304
|
|
|
11276
11305
|
// src/commands/init.ts
|
|
11277
|
-
var
|
|
11306
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
11278
11307
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
11279
|
-
import { mkdir as mkdir3, readFile as readFile3, readdir as readdir2, rename as rename3, stat as stat4, writeFile as writeFile3 } from "
|
|
11280
|
-
import { homedir as homedir3 } from "
|
|
11281
|
-
import { dirname as dirname3, join as join6 } from "
|
|
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";
|
|
11311
|
+
init_cli_ui();
|
|
11282
11312
|
var binaryVersion = resolveBinaryVersion();
|
|
11283
11313
|
var STANDARD_FOLDERS = [
|
|
11284
11314
|
"00-inbox",
|
|
@@ -11343,12 +11373,12 @@ async function downloadPluginFiles(vaultDir, vaultSyncFn) {
|
|
|
11343
11373
|
} catch {}
|
|
11344
11374
|
let driftWarning;
|
|
11345
11375
|
if (pluginVersion && binaryVersion !== "dev" && pluginVersion !== binaryVersion) {
|
|
11346
|
-
driftWarning = `Plugin files v${pluginVersion}, binary v${binaryVersion}
|
|
11376
|
+
driftWarning = `Plugin files v${pluginVersion}, binary v${binaryVersion} \u2014 run onebrain update to sync.`;
|
|
11347
11377
|
}
|
|
11348
11378
|
return driftWarning !== undefined ? { skipped: true, driftWarning } : { skipped: true };
|
|
11349
11379
|
}
|
|
11350
11380
|
try {
|
|
11351
|
-
await vaultSyncFn(vaultDir, { includeObsidian: true });
|
|
11381
|
+
await vaultSyncFn(vaultDir, { includeObsidian: true, embedded: true });
|
|
11352
11382
|
} catch (err) {
|
|
11353
11383
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11354
11384
|
process.stderr.write(`init: vault-sync warning: ${msg}
|
|
@@ -11544,7 +11574,7 @@ async function installObsidianPlugins(vaultDir, opts) {
|
|
|
11544
11574
|
}
|
|
11545
11575
|
if (pluginFailed) {
|
|
11546
11576
|
try {
|
|
11547
|
-
const { rm: rm2 } = await import("
|
|
11577
|
+
const { rm: rm2 } = await import("fs/promises");
|
|
11548
11578
|
await rm2(pluginDir, { recursive: true, force: true });
|
|
11549
11579
|
} catch {}
|
|
11550
11580
|
} else {
|
|
@@ -11578,22 +11608,17 @@ async function runInit(opts = {}) {
|
|
|
11578
11608
|
const createStep = makeStepFn(isTTY);
|
|
11579
11609
|
const delay = opts.delayFn ?? ((ms) => new Promise((r2) => setTimeout(r2, ms)));
|
|
11580
11610
|
const randDelay = () => isTTY ? delay(Math.floor(Math.random() * 1000) + 1000) : Promise.resolve();
|
|
11611
|
+
const _confirmFn = opts.confirmFn ?? askYesNo;
|
|
11581
11612
|
const vaultYmlPath = join6(vaultDir, "vault.yml");
|
|
11582
11613
|
const vaultYmlExists = await pathExists2(vaultYmlPath);
|
|
11583
|
-
if (
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
}
|
|
11592
|
-
if (isTTY) {
|
|
11593
|
-
await printBanner();
|
|
11594
|
-
const answer = await askYesNo("vault.yml already exists. Overwrite?");
|
|
11595
|
-
if (answer === null || answer === false) {
|
|
11596
|
-
barLine(import_picocolors6.default.dim("No"));
|
|
11614
|
+
if (isTTY) {
|
|
11615
|
+
await printBanner();
|
|
11616
|
+
if (!force) {
|
|
11617
|
+
barLine(`${import_picocolors7.default.dim("vault root")} ${import_picocolors7.default.cyan(vaultDir)}`);
|
|
11618
|
+
barBlank();
|
|
11619
|
+
const proceed = await _confirmFn("Initialize OneBrain vault here?");
|
|
11620
|
+
if (proceed === null || proceed === false) {
|
|
11621
|
+
barLine(import_picocolors7.default.dim("No"));
|
|
11597
11622
|
barBlank();
|
|
11598
11623
|
close("Aborted");
|
|
11599
11624
|
result.ok = true;
|
|
@@ -11602,18 +11627,36 @@ async function runInit(opts = {}) {
|
|
|
11602
11627
|
}
|
|
11603
11628
|
barLine("Yes");
|
|
11604
11629
|
barBlank();
|
|
11630
|
+
if (vaultYmlExists) {
|
|
11631
|
+
const overwrite = await _confirmFn("vault.yml already exists. Overwrite?");
|
|
11632
|
+
if (overwrite === null || overwrite === false) {
|
|
11633
|
+
barLine(import_picocolors7.default.dim("No"));
|
|
11634
|
+
barBlank();
|
|
11635
|
+
close("Aborted");
|
|
11636
|
+
result.ok = true;
|
|
11637
|
+
result.exitCode = 0;
|
|
11638
|
+
return result;
|
|
11639
|
+
}
|
|
11640
|
+
barLine("Yes");
|
|
11641
|
+
barBlank();
|
|
11642
|
+
}
|
|
11643
|
+
}
|
|
11644
|
+
} else {
|
|
11645
|
+
if (vaultYmlExists && !force) {
|
|
11646
|
+
const msg = "vault.yml exists. Re-run with --force to overwrite.";
|
|
11647
|
+
process.stdout.write(`${msg}
|
|
11648
|
+
`);
|
|
11649
|
+
result.message = msg;
|
|
11650
|
+
result.exitCode = 1;
|
|
11651
|
+
return result;
|
|
11605
11652
|
}
|
|
11606
|
-
} else if (isTTY) {
|
|
11607
|
-
await printBanner();
|
|
11608
|
-
}
|
|
11609
|
-
if (!isTTY) {
|
|
11610
11653
|
writeLine("OneBrain Init");
|
|
11611
11654
|
}
|
|
11612
11655
|
const sp2 = createStep("\uD83D\uDCCB", "vault.yml");
|
|
11613
11656
|
await writeVaultYml(vaultDir);
|
|
11614
11657
|
if (sp2) {
|
|
11615
11658
|
await randDelay();
|
|
11616
|
-
sp2.stop(
|
|
11659
|
+
sp2.stop(import_picocolors7.default.dim("written"), ["update_channel: stable", "checkpoint: 15 msgs \xB7 30 min"]);
|
|
11617
11660
|
} else {
|
|
11618
11661
|
writeLine("vault.yml: written");
|
|
11619
11662
|
}
|
|
@@ -11626,18 +11669,25 @@ async function runInit(opts = {}) {
|
|
|
11626
11669
|
} else {
|
|
11627
11670
|
writeLine(`folders: ${foldersCreated} created`);
|
|
11628
11671
|
}
|
|
11629
|
-
const
|
|
11630
|
-
const
|
|
11631
|
-
|
|
11632
|
-
|
|
11633
|
-
} = await downloadPluginFiles(vaultDir, vaultSyncFn);
|
|
11672
|
+
const pluginJsonPath = join6(vaultDir, ".claude", "plugins", "onebrain", ".claude-plugin", "plugin.json");
|
|
11673
|
+
const pluginFilesExist = await pathExists2(pluginJsonPath);
|
|
11674
|
+
const sp4 = pluginFilesExist ? createStep("\uD83D\uDCE6", "Plugin files") : null;
|
|
11675
|
+
const { skipped: pluginSkipped, failed: pluginDownloadFailed } = await downloadPluginFiles(vaultDir, vaultSyncFn);
|
|
11634
11676
|
result.pluginSkipped = pluginSkipped;
|
|
11635
11677
|
if (sp4) {
|
|
11636
11678
|
if (pluginDownloadFailed) {
|
|
11637
11679
|
sp4.stop("download failed");
|
|
11638
11680
|
} else {
|
|
11639
11681
|
const { skills, agents } = await countPluginContents(vaultDir);
|
|
11640
|
-
sp4.stop(
|
|
11682
|
+
sp4.stop(import_picocolors7.default.dim("already installed"), [`${skills} skills \xB7 ${agents} agents`]);
|
|
11683
|
+
}
|
|
11684
|
+
} else if (isTTY) {
|
|
11685
|
+
if (!pluginDownloadFailed) {
|
|
11686
|
+
const { skills, agents } = await countPluginContents(vaultDir);
|
|
11687
|
+
dotLine("\uD83D\uDCE6", "Plugin files");
|
|
11688
|
+
barLine(import_picocolors7.default.dim("downloaded"));
|
|
11689
|
+
barLine(` \xB7 ${skills} skills \xB7 ${agents} agents`);
|
|
11690
|
+
barBlank();
|
|
11641
11691
|
}
|
|
11642
11692
|
} else {
|
|
11643
11693
|
if (pluginSkipped)
|
|
@@ -11650,7 +11700,7 @@ async function runInit(opts = {}) {
|
|
|
11650
11700
|
if (isTTY) {
|
|
11651
11701
|
close("Could not download plugin files. Check your internet connection and try again.", true);
|
|
11652
11702
|
} else {
|
|
11653
|
-
writeLine("error: vault-sync failed
|
|
11703
|
+
writeLine("error: vault-sync failed \u2014 run onebrain update to download plugin files");
|
|
11654
11704
|
}
|
|
11655
11705
|
return result;
|
|
11656
11706
|
}
|
|
@@ -11669,7 +11719,7 @@ async function runInit(opts = {}) {
|
|
|
11669
11719
|
...pluginResult.installed,
|
|
11670
11720
|
...pluginResult.failed.map((f2) => `${f2.id} (skipped)`)
|
|
11671
11721
|
];
|
|
11672
|
-
sp4b.stop(
|
|
11722
|
+
sp4b.stop(import_picocolors7.default.dim(n > 0 ? `${n} installed` : "none"), details.length > 0 ? details : undefined);
|
|
11673
11723
|
} else {
|
|
11674
11724
|
if (pluginResult.installed.length > 0)
|
|
11675
11725
|
writeLine(`plugins: ${pluginResult.installed.join(", ")} installed`);
|
|
@@ -11681,7 +11731,9 @@ async function runInit(opts = {}) {
|
|
|
11681
11731
|
result.pluginRegistrationSkipped = pluginRegistrationSkipped;
|
|
11682
11732
|
if (sp5) {
|
|
11683
11733
|
await randDelay();
|
|
11684
|
-
sp5.stop(
|
|
11734
|
+
sp5.stop(import_picocolors7.default.dim(pluginRegistrationSkipped ? "skipped" : "registered"), [
|
|
11735
|
+
`source: ${pluginRegistrationSkipped ? "marketplace" : "local"}`
|
|
11736
|
+
]);
|
|
11685
11737
|
} else {
|
|
11686
11738
|
writeLine(`plugin: ${pluginRegistrationSkipped ? "skipped (marketplace)" : "registered"}`);
|
|
11687
11739
|
}
|
|
@@ -11697,20 +11749,20 @@ async function runInit(opts = {}) {
|
|
|
11697
11749
|
}
|
|
11698
11750
|
if (sp6) {
|
|
11699
11751
|
await randDelay();
|
|
11700
|
-
sp6.stop(hooksOk ? undefined : "not registered
|
|
11752
|
+
sp6.stop(hooksOk ? undefined : "not registered \u2014 run onebrain update", hooksOk ? ["Stop \u2713 PostCompact \u2713", "Bash(onebrain *) \u2713"] : undefined);
|
|
11701
11753
|
} else {
|
|
11702
|
-
writeLine(`hooks: ${hooksOk ? "ok" : "warning
|
|
11754
|
+
writeLine(`hooks: ${hooksOk ? "ok" : "warning \u2014 hooks not registered; run onebrain update"}`);
|
|
11703
11755
|
}
|
|
11704
11756
|
result.ok = true;
|
|
11705
11757
|
result.exitCode = 0;
|
|
11706
11758
|
if (isTTY) {
|
|
11707
|
-
barLine(
|
|
11759
|
+
barLine(import_picocolors7.default.dim(`\u2500\u2500\u2500 Next steps ${"\u2500".repeat(25)}`));
|
|
11708
11760
|
barBlank();
|
|
11709
|
-
barLine(` ${
|
|
11710
|
-
barLine(` ${
|
|
11711
|
-
barLine(` ${
|
|
11761
|
+
barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("1"))} \uD83D\uDCC1 Open Obsidian \u2192 open this folder as vault`);
|
|
11762
|
+
barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("2"))} \uD83E\uDD16 Run ${import_picocolors7.default.cyan("claude")}`);
|
|
11763
|
+
barLine(` ${import_picocolors7.default.bold(import_picocolors7.default.cyan("3"))} \uD83E\uDDE0 Type ${import_picocolors7.default.cyan("/onboarding")} to personalize`);
|
|
11712
11764
|
barBlank();
|
|
11713
|
-
close(
|
|
11765
|
+
close(`\u2728 ${import_picocolors7.default.bold("Ready")} \u2014 ${import_picocolors7.default.cyan("/onboarding")}`);
|
|
11714
11766
|
} else {
|
|
11715
11767
|
writeLine("done: run /onboarding in Claude to finish setup");
|
|
11716
11768
|
}
|
|
@@ -11724,9 +11776,9 @@ async function initCommand(opts = {}) {
|
|
|
11724
11776
|
}
|
|
11725
11777
|
|
|
11726
11778
|
// src/commands/internal/checkpoint.ts
|
|
11727
|
-
import { readFileSync, readdirSync, writeFileSync } from "
|
|
11728
|
-
import { tmpdir as osTmpdir } from "
|
|
11729
|
-
import { join as join7 } from "
|
|
11779
|
+
import { readFileSync, readdirSync, writeFileSync } from "fs";
|
|
11780
|
+
import { tmpdir as osTmpdir } from "os";
|
|
11781
|
+
import { join as join7 } from "path";
|
|
11730
11782
|
var SKIP_WINDOW = 60;
|
|
11731
11783
|
var MIN_ACTIVITY = 2;
|
|
11732
11784
|
var PRECOMPACT_RECENCY = 300;
|
|
@@ -11902,8 +11954,8 @@ async function checkpointCommand(mode, token, vaultRoot) {
|
|
|
11902
11954
|
// src/commands/internal/migrate.ts
|
|
11903
11955
|
init_lib();
|
|
11904
11956
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
11905
|
-
import { readFile as readFile4, readdir as readdir3, writeFile as writeFile4 } from "
|
|
11906
|
-
import { join as join8 } from "
|
|
11957
|
+
import { readFile as readFile4, readdir as readdir3, writeFile as writeFile4 } from "fs/promises";
|
|
11958
|
+
import { join as join8 } from "path";
|
|
11907
11959
|
function parseFrontmatterWithRest(rawText) {
|
|
11908
11960
|
const text = rawText.replace(/\r\n/g, `
|
|
11909
11961
|
`);
|
|
@@ -11972,7 +12024,7 @@ async function runBackfillRecapped(logsFolder, cutoffDate) {
|
|
|
11972
12024
|
const content = await readFile4(fpath, "utf8");
|
|
11973
12025
|
const parsed = parseFrontmatterWithRest(content);
|
|
11974
12026
|
if (!parsed) {
|
|
11975
|
-
process.stderr.write(`migrate: ${fname}
|
|
12027
|
+
process.stderr.write(`migrate: ${fname} \u2014 malformed frontmatter
|
|
11976
12028
|
`);
|
|
11977
12029
|
skipped++;
|
|
11978
12030
|
continue;
|
|
@@ -12019,8 +12071,8 @@ async function migrateCommand(migrationName, cutoffDate, vaultDir) {
|
|
|
12019
12071
|
|
|
12020
12072
|
// src/commands/internal/orphan-scan.ts
|
|
12021
12073
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
12022
|
-
import { readFile as readFile5, readdir as readdir4 } from "
|
|
12023
|
-
import { join as join9 } from "
|
|
12074
|
+
import { readFile as readFile5, readdir as readdir4 } from "fs/promises";
|
|
12075
|
+
import { join as join9 } from "path";
|
|
12024
12076
|
function parseFrontmatter(rawText) {
|
|
12025
12077
|
const text = rawText.replace(/\r\n/g, `
|
|
12026
12078
|
`);
|
|
@@ -12154,290 +12206,28 @@ async function qmdReindexCommand(vaultRoot) {
|
|
|
12154
12206
|
}
|
|
12155
12207
|
}
|
|
12156
12208
|
|
|
12157
|
-
// src/
|
|
12158
|
-
|
|
12209
|
+
// src/index.ts
|
|
12210
|
+
init_register_hooks();
|
|
12211
|
+
|
|
12212
|
+
// src/commands/internal/session-init.ts
|
|
12159
12213
|
init_lib();
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
import {
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
"
|
|
12175
|
-
"
|
|
12176
|
-
"
|
|
12177
|
-
"Glob",
|
|
12178
|
-
"Grep",
|
|
12179
|
-
"Bash(git *)",
|
|
12180
|
-
"Bash(bun *)",
|
|
12181
|
-
"Bash(gh *)",
|
|
12182
|
-
"Bash(node *)",
|
|
12183
|
-
"Bash(onebrain *)",
|
|
12184
|
-
"Bash(bun install -g @onebrain-ai/cli*)",
|
|
12185
|
-
"Bash(npm install -g @onebrain-ai/cli*)",
|
|
12186
|
-
"WebFetch",
|
|
12187
|
-
"WebSearch"
|
|
12188
|
-
];
|
|
12189
|
-
var ONEBRAIN_MARKER2 = "# onebrain";
|
|
12190
|
-
var PATH_EXPORT2 = 'export PATH="$HOME/.bun/bin:$HOME/.npm-global/bin:$PATH"';
|
|
12191
|
-
async function readSettings2(settingsPath) {
|
|
12192
|
-
try {
|
|
12193
|
-
const text = await readFile6(settingsPath, "utf8");
|
|
12194
|
-
return JSON.parse(text);
|
|
12195
|
-
} catch (err) {
|
|
12196
|
-
if (err.code === "ENOENT")
|
|
12197
|
-
return {};
|
|
12198
|
-
throw err;
|
|
12199
|
-
}
|
|
12200
|
-
}
|
|
12201
|
-
async function writeSettings2(settingsPath, settings) {
|
|
12202
|
-
await mkdir4(dirname4(settingsPath), { recursive: true });
|
|
12203
|
-
const tmpPath = `${settingsPath}.tmp`;
|
|
12204
|
-
await writeFile5(tmpPath, JSON.stringify(settings, null, 4), "utf8");
|
|
12205
|
-
await rename4(tmpPath, settingsPath);
|
|
12206
|
-
}
|
|
12207
|
-
function checkHookPresence2(groups, targetCmd) {
|
|
12208
|
-
let foundMigrate = false;
|
|
12209
|
-
for (const group of groups) {
|
|
12210
|
-
for (const entry of group.hooks ?? []) {
|
|
12211
|
-
const cmd = entry.command ?? "";
|
|
12212
|
-
if (cmd === targetCmd)
|
|
12213
|
-
return "found";
|
|
12214
|
-
if (cmd.includes("checkpoint-hook.sh"))
|
|
12215
|
-
foundMigrate = true;
|
|
12216
|
-
}
|
|
12217
|
-
}
|
|
12218
|
-
return foundMigrate ? "migrate" : "missing";
|
|
12219
|
-
}
|
|
12220
|
-
function applyHooks2(settings) {
|
|
12221
|
-
if (!settings.hooks)
|
|
12222
|
-
settings.hooks = {};
|
|
12223
|
-
const hooks = settings.hooks;
|
|
12224
|
-
const result = {};
|
|
12225
|
-
for (const [event, staleCmd] of Object.entries(STALE_HOOK_COMMANDS2)) {
|
|
12226
|
-
if (!hooks[event])
|
|
12227
|
-
continue;
|
|
12228
|
-
hooks[event] = hooks[event].filter((group) => !group.hooks?.some((entry) => entry.command === staleCmd));
|
|
12229
|
-
if (hooks[event].length === 0)
|
|
12230
|
-
delete hooks[event];
|
|
12231
|
-
}
|
|
12232
|
-
for (const event of HOOK_EVENTS2) {
|
|
12233
|
-
const cmd = HOOK_COMMANDS2[event];
|
|
12234
|
-
if (!cmd)
|
|
12235
|
-
continue;
|
|
12236
|
-
if (!hooks[event])
|
|
12237
|
-
hooks[event] = [];
|
|
12238
|
-
const groups = hooks[event];
|
|
12239
|
-
const presence = checkHookPresence2(groups, cmd);
|
|
12240
|
-
if (presence === "found") {
|
|
12241
|
-
result[event] = "ok";
|
|
12242
|
-
} else if (presence === "migrate") {
|
|
12243
|
-
for (const group of groups) {
|
|
12244
|
-
if (group.matcher === undefined)
|
|
12245
|
-
group.matcher = "";
|
|
12246
|
-
for (const entry of group.hooks ?? []) {
|
|
12247
|
-
if ((entry.command ?? "").includes("checkpoint-hook.sh")) {
|
|
12248
|
-
entry.command = cmd;
|
|
12249
|
-
if (!entry.type)
|
|
12250
|
-
entry.type = "command";
|
|
12251
|
-
}
|
|
12252
|
-
}
|
|
12253
|
-
}
|
|
12254
|
-
result[event] = "migrated";
|
|
12255
|
-
} else {
|
|
12256
|
-
groups.push({ matcher: "", hooks: [{ type: "command", command: cmd }] });
|
|
12257
|
-
result[event] = "added";
|
|
12258
|
-
}
|
|
12259
|
-
}
|
|
12260
|
-
return result;
|
|
12261
|
-
}
|
|
12262
|
-
var QMD_CMD2 = "onebrain qmd-reindex";
|
|
12263
|
-
var QMD_MATCHER2 = "Write|Edit";
|
|
12264
|
-
function applyQmdHook2(settings) {
|
|
12265
|
-
if (!settings.hooks)
|
|
12266
|
-
settings.hooks = {};
|
|
12267
|
-
if (!settings.hooks["PostToolUse"])
|
|
12268
|
-
settings.hooks["PostToolUse"] = [];
|
|
12269
|
-
const groups = settings.hooks["PostToolUse"];
|
|
12270
|
-
const already = groups.some((g) => g.hooks?.some((h) => h.command === QMD_CMD2));
|
|
12271
|
-
if (already)
|
|
12272
|
-
return "ok";
|
|
12273
|
-
groups.push({ matcher: QMD_MATCHER2, hooks: [{ type: "command", command: QMD_CMD2 }] });
|
|
12274
|
-
return "added";
|
|
12275
|
-
}
|
|
12276
|
-
function applyPermissions2(settings) {
|
|
12277
|
-
if (!settings.permissions)
|
|
12278
|
-
settings.permissions = {};
|
|
12279
|
-
if (!settings.permissions.allow)
|
|
12280
|
-
settings.permissions.allow = [];
|
|
12281
|
-
const allow = settings.permissions.allow;
|
|
12282
|
-
const added = [];
|
|
12283
|
-
for (const perm of PERMISSIONS_TO_ADD2) {
|
|
12284
|
-
if (!allow.includes(perm)) {
|
|
12285
|
-
allow.push(perm);
|
|
12286
|
-
added.push(perm);
|
|
12287
|
-
}
|
|
12288
|
-
}
|
|
12289
|
-
return added;
|
|
12290
|
-
}
|
|
12291
|
-
async function registerGeminiHooks2(vaultRoot) {
|
|
12292
|
-
const geminiSettingsPath = join10(vaultRoot, ".gemini", "settings.json");
|
|
12293
|
-
try {
|
|
12294
|
-
const text = await readFile6(geminiSettingsPath, "utf8");
|
|
12295
|
-
const settings = JSON.parse(text);
|
|
12296
|
-
applyHooks2(settings);
|
|
12297
|
-
await writeSettings2(geminiSettingsPath, settings);
|
|
12298
|
-
} catch (err) {
|
|
12299
|
-
if (err.code !== "ENOENT") {
|
|
12300
|
-
process.stderr.write(`register-hooks: gemini warning: ${err instanceof Error ? err.message : String(err)}
|
|
12301
|
-
`);
|
|
12302
|
-
}
|
|
12303
|
-
}
|
|
12304
|
-
}
|
|
12305
|
-
async function registerDirectPath2() {
|
|
12306
|
-
const home = homedir4();
|
|
12307
|
-
const candidates = [join10(home, ".zshrc"), join10(home, ".bashrc"), join10(home, ".profile")];
|
|
12308
|
-
let profilePath;
|
|
12309
|
-
for (const candidate of candidates) {
|
|
12310
|
-
try {
|
|
12311
|
-
await readFile6(candidate, "utf8");
|
|
12312
|
-
profilePath = candidate;
|
|
12313
|
-
break;
|
|
12314
|
-
} catch {}
|
|
12315
|
-
}
|
|
12316
|
-
if (!profilePath)
|
|
12317
|
-
return;
|
|
12318
|
-
const content = await readFile6(profilePath, "utf8");
|
|
12319
|
-
if (content.includes(ONEBRAIN_MARKER2))
|
|
12320
|
-
return;
|
|
12321
|
-
const updated = `${content}
|
|
12322
|
-
${ONEBRAIN_MARKER2}
|
|
12323
|
-
${PATH_EXPORT2}
|
|
12324
|
-
`;
|
|
12325
|
-
const tmpPath = `${profilePath}.tmp`;
|
|
12326
|
-
await writeFile5(tmpPath, updated, "utf8");
|
|
12327
|
-
await rename4(tmpPath, profilePath);
|
|
12328
|
-
}
|
|
12329
|
-
async function runRegisterHooks2(opts = {}) {
|
|
12330
|
-
const vaultRoot = opts.vaultDir ?? process.cwd();
|
|
12331
|
-
const isTTY = opts.isTTY ?? process.stdout.isTTY ?? false;
|
|
12332
|
-
const harness = await detectHarness(vaultRoot);
|
|
12333
|
-
let qmdCollection;
|
|
12334
|
-
try {
|
|
12335
|
-
const vaultConfig = await loadVaultConfig(vaultRoot);
|
|
12336
|
-
qmdCollection = vaultConfig.qmd_collection;
|
|
12337
|
-
} catch (err) {
|
|
12338
|
-
if (err.code !== "ENOENT") {
|
|
12339
|
-
process.stderr.write(`register-hooks: warning: could not read vault.yml: ${err instanceof Error ? err.message : String(err)}
|
|
12340
|
-
`);
|
|
12341
|
-
}
|
|
12342
|
-
}
|
|
12343
|
-
const result = {
|
|
12344
|
-
ok: false,
|
|
12345
|
-
hooks: {},
|
|
12346
|
-
permissionsAdded: []
|
|
12347
|
-
};
|
|
12348
|
-
const settingsPath = join10(vaultRoot, ".claude", "settings.json");
|
|
12349
|
-
const note = (msg) => {
|
|
12350
|
-
if (opts.silent)
|
|
12351
|
-
return;
|
|
12352
|
-
process.stdout.write(`register-hooks: ${msg}
|
|
12353
|
-
`);
|
|
12354
|
-
};
|
|
12355
|
-
let hooksSpinner = null;
|
|
12356
|
-
let permSpinner = null;
|
|
12357
|
-
try {
|
|
12358
|
-
if (harness === "claude") {
|
|
12359
|
-
hooksSpinner = isTTY ? L2() : null;
|
|
12360
|
-
hooksSpinner?.start("Registering hooks...");
|
|
12361
|
-
const settings = await readSettings2(settingsPath);
|
|
12362
|
-
result.hooks = applyHooks2(settings);
|
|
12363
|
-
let qmdStatus;
|
|
12364
|
-
if (qmdCollection)
|
|
12365
|
-
qmdStatus = applyQmdHook2(settings);
|
|
12366
|
-
if (isTTY) {
|
|
12367
|
-
const parts = HOOK_EVENTS2.map((e2) => {
|
|
12368
|
-
const status = result.hooks[e2];
|
|
12369
|
-
const icon = import_picocolors7.default.green(status === "ok" ? "✓" : status === "migrated" ? "↑" : "+");
|
|
12370
|
-
return `${import_picocolors7.default.dim(e2)} ${icon}`;
|
|
12371
|
-
});
|
|
12372
|
-
if (qmdStatus)
|
|
12373
|
-
parts.push(`${import_picocolors7.default.dim("PostToolUse")} ${import_picocolors7.default.green(qmdStatus === "ok" ? "✓" : "+")}`);
|
|
12374
|
-
hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
|
|
12375
|
-
} else {
|
|
12376
|
-
const hookLine = HOOK_EVENTS2.map((e2) => {
|
|
12377
|
-
const status = result.hooks[e2];
|
|
12378
|
-
const label = status === "ok" || status === "added" || status === "migrated" ? "ok" : status ?? "ok";
|
|
12379
|
-
return `${e2} ${label}`;
|
|
12380
|
-
}).join(" ");
|
|
12381
|
-
note(hookLine);
|
|
12382
|
-
if (qmdStatus)
|
|
12383
|
-
note(`PostToolUse ${qmdStatus === "added" ? "added" : "ok"}`);
|
|
12384
|
-
}
|
|
12385
|
-
permSpinner = isTTY ? L2() : null;
|
|
12386
|
-
permSpinner?.start("Updating permissions...");
|
|
12387
|
-
result.permissionsAdded = applyPermissions2(settings);
|
|
12388
|
-
await writeSettings2(settingsPath, settings);
|
|
12389
|
-
permSpinner?.stop("Permissions ok");
|
|
12390
|
-
if (!isTTY)
|
|
12391
|
-
note("permissions ok");
|
|
12392
|
-
}
|
|
12393
|
-
if (harness === "gemini") {
|
|
12394
|
-
await registerGeminiHooks2(vaultRoot);
|
|
12395
|
-
}
|
|
12396
|
-
if (harness === "direct") {
|
|
12397
|
-
await registerDirectPath2();
|
|
12398
|
-
}
|
|
12399
|
-
result.ok = true;
|
|
12400
|
-
if (!isTTY) {
|
|
12401
|
-
note("done");
|
|
12402
|
-
}
|
|
12403
|
-
} catch (err) {
|
|
12404
|
-
hooksSpinner?.stop("Registration failed");
|
|
12405
|
-
permSpinner?.stop("Permissions failed");
|
|
12406
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
12407
|
-
result.error = msg;
|
|
12408
|
-
process.stderr.write(`register-hooks: error: ${msg}
|
|
12409
|
-
`);
|
|
12410
|
-
}
|
|
12411
|
-
return result;
|
|
12412
|
-
}
|
|
12413
|
-
async function registerHooksCommand2(vaultDir) {
|
|
12414
|
-
const result = await runRegisterHooks2({
|
|
12415
|
-
...vaultDir !== undefined ? { vaultDir } : {}
|
|
12416
|
-
});
|
|
12417
|
-
if (!result.ok) {
|
|
12418
|
-
process.exit(1);
|
|
12419
|
-
}
|
|
12420
|
-
}
|
|
12421
|
-
|
|
12422
|
-
// src/commands/internal/session-init.ts
|
|
12423
|
-
init_lib();
|
|
12424
|
-
import { unlink as unlink2 } from "node:fs/promises";
|
|
12425
|
-
import { tmpdir as osTmpdir2 } from "node:os";
|
|
12426
|
-
import { join as join11 } from "node:path";
|
|
12427
|
-
var DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
12428
|
-
var MONTH_NAMES = [
|
|
12429
|
-
"Jan",
|
|
12430
|
-
"Feb",
|
|
12431
|
-
"Mar",
|
|
12432
|
-
"Apr",
|
|
12433
|
-
"May",
|
|
12434
|
-
"Jun",
|
|
12435
|
-
"Jul",
|
|
12436
|
-
"Aug",
|
|
12437
|
-
"Sep",
|
|
12438
|
-
"Oct",
|
|
12439
|
-
"Nov",
|
|
12440
|
-
"Dec"
|
|
12214
|
+
import { unlink as unlink2 } from "fs/promises";
|
|
12215
|
+
import { tmpdir as osTmpdir2 } from "os";
|
|
12216
|
+
import { join as join10 } from "path";
|
|
12217
|
+
var DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
12218
|
+
var MONTH_NAMES = [
|
|
12219
|
+
"Jan",
|
|
12220
|
+
"Feb",
|
|
12221
|
+
"Mar",
|
|
12222
|
+
"Apr",
|
|
12223
|
+
"May",
|
|
12224
|
+
"Jun",
|
|
12225
|
+
"Jul",
|
|
12226
|
+
"Aug",
|
|
12227
|
+
"Sep",
|
|
12228
|
+
"Oct",
|
|
12229
|
+
"Nov",
|
|
12230
|
+
"Dec"
|
|
12441
12231
|
];
|
|
12442
12232
|
function formatDatetime(date) {
|
|
12443
12233
|
const dow = DAY_NAMES[date.getDay()];
|
|
@@ -12446,7 +12236,7 @@ function formatDatetime(date) {
|
|
|
12446
12236
|
const year = date.getFullYear();
|
|
12447
12237
|
const hh = String(date.getHours()).padStart(2, "0");
|
|
12448
12238
|
const mm = String(date.getMinutes()).padStart(2, "0");
|
|
12449
|
-
return `${dow}
|
|
12239
|
+
return `${dow} \xB7 ${day} ${mon} ${year} \xB7 ${hh}:${mm}`;
|
|
12450
12240
|
}
|
|
12451
12241
|
async function resolveSessionToken(tmpDir = osTmpdir2()) {
|
|
12452
12242
|
const wtSession = process.env["WT_SESSION"];
|
|
@@ -12455,644 +12245,147 @@ async function resolveSessionToken(tmpDir = osTmpdir2()) {
|
|
|
12455
12245
|
if (stripped.length > 0)
|
|
12456
12246
|
return stripped;
|
|
12457
12247
|
}
|
|
12458
|
-
const tmuxPane = process.env["TMUX_PANE"];
|
|
12459
|
-
if (tmuxPane) {
|
|
12460
|
-
const stripped = tmuxPane.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
|
|
12461
|
-
if (stripped.length > 0)
|
|
12462
|
-
return stripped;
|
|
12463
|
-
}
|
|
12464
|
-
const termSessionId = process.env["TERM_SESSION_ID"];
|
|
12465
|
-
if (termSessionId) {
|
|
12466
|
-
const stripped = termSessionId.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
|
|
12467
|
-
if (stripped.length > 0)
|
|
12468
|
-
return stripped;
|
|
12469
|
-
}
|
|
12470
|
-
const today = new Date;
|
|
12471
|
-
const yyyymmdd = [
|
|
12472
|
-
today.getFullYear(),
|
|
12473
|
-
String(today.getMonth() + 1).padStart(2, "0"),
|
|
12474
|
-
String(today.getDate()).padStart(2, "0")
|
|
12475
|
-
].join("");
|
|
12476
|
-
const cacheFile = join11(tmpDir, `onebrain-day-${yyyymmdd}.token`);
|
|
12477
|
-
const cacheExists = await Bun.file(cacheFile).exists();
|
|
12478
|
-
if (cacheExists) {
|
|
12479
|
-
const cached = (await Bun.file(cacheFile).text()).trim();
|
|
12480
|
-
const n = Number(cached);
|
|
12481
|
-
if (!Number.isNaN(n) && n > 1)
|
|
12482
|
-
return cached;
|
|
12483
|
-
}
|
|
12484
|
-
const ppid = process.ppid;
|
|
12485
|
-
if (ppid !== undefined && ppid > 1) {
|
|
12486
|
-
const token2 = String(ppid);
|
|
12487
|
-
await Bun.write(cacheFile, token2);
|
|
12488
|
-
return token2;
|
|
12489
|
-
}
|
|
12490
|
-
try {
|
|
12491
|
-
const ps = Bun.spawn([
|
|
12492
|
-
"powershell.exe",
|
|
12493
|
-
"-NoProfile",
|
|
12494
|
-
"-NonInteractive",
|
|
12495
|
-
"-Command",
|
|
12496
|
-
"(Get-Process -Id $PID).Parent.Id"
|
|
12497
|
-
], {
|
|
12498
|
-
stdout: "pipe",
|
|
12499
|
-
stderr: "pipe"
|
|
12500
|
-
});
|
|
12501
|
-
const timeoutMs = 3000;
|
|
12502
|
-
let timerId;
|
|
12503
|
-
const race = await Promise.race([
|
|
12504
|
-
ps.exited,
|
|
12505
|
-
new Promise((resolve) => {
|
|
12506
|
-
timerId = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
12507
|
-
})
|
|
12508
|
-
]);
|
|
12509
|
-
if (timerId !== undefined)
|
|
12510
|
-
clearTimeout(timerId);
|
|
12511
|
-
if (race !== "timeout") {
|
|
12512
|
-
const out = (await new Response(ps.stdout).text()).replace(/\D/g, "").trim();
|
|
12513
|
-
if (out && Number(out) > 1) {
|
|
12514
|
-
await Bun.write(cacheFile, out);
|
|
12515
|
-
return out;
|
|
12516
|
-
}
|
|
12517
|
-
} else {
|
|
12518
|
-
ps.kill();
|
|
12519
|
-
}
|
|
12520
|
-
} catch {}
|
|
12521
|
-
const token = String(Math.floor(Math.random() * 90000) + 1e4);
|
|
12522
|
-
await Bun.write(cacheFile, token);
|
|
12523
|
-
return token;
|
|
12524
|
-
}
|
|
12525
|
-
async function cleanStaleStateFile(token, tmpDir) {
|
|
12526
|
-
try {
|
|
12527
|
-
const processStartMs = Date.now() - performance.now();
|
|
12528
|
-
const stateFile = join11(tmpDir, `onebrain-${token}.state`);
|
|
12529
|
-
const f2 = Bun.file(stateFile);
|
|
12530
|
-
const exists = await f2.exists();
|
|
12531
|
-
if (!exists)
|
|
12532
|
-
return;
|
|
12533
|
-
const { mtime } = await f2.stat();
|
|
12534
|
-
const mtimeMs = mtime instanceof Date ? mtime.getTime() : Number(mtime) * 1000;
|
|
12535
|
-
if (mtimeMs < processStartMs) {
|
|
12536
|
-
try {
|
|
12537
|
-
await unlink2(stateFile);
|
|
12538
|
-
} catch {}
|
|
12539
|
-
}
|
|
12540
|
-
} catch {}
|
|
12541
|
-
}
|
|
12542
|
-
async function queryQmdUnembedded() {
|
|
12543
|
-
try {
|
|
12544
|
-
const qmdArgs = process.platform === "win32" ? ["powershell.exe", "-NoProfile", "-Command", "qmd status --json"] : ["qmd", "status", "--json"];
|
|
12545
|
-
const proc = Bun.spawn(qmdArgs, {
|
|
12546
|
-
stdout: "pipe",
|
|
12547
|
-
stderr: "pipe"
|
|
12548
|
-
});
|
|
12549
|
-
const timeoutMs = 2000;
|
|
12550
|
-
let timerId;
|
|
12551
|
-
const race = await Promise.race([
|
|
12552
|
-
proc.exited,
|
|
12553
|
-
new Promise((resolve) => {
|
|
12554
|
-
timerId = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
12555
|
-
})
|
|
12556
|
-
]);
|
|
12557
|
-
if (timerId !== undefined)
|
|
12558
|
-
clearTimeout(timerId);
|
|
12559
|
-
if (race === "timeout") {
|
|
12560
|
-
proc.kill();
|
|
12561
|
-
return 0;
|
|
12562
|
-
}
|
|
12563
|
-
const stdout = await new Response(proc.stdout).text();
|
|
12564
|
-
const parsed = JSON.parse(stdout);
|
|
12565
|
-
const unembedded = parsed["unembedded"];
|
|
12566
|
-
return typeof unembedded === "number" ? unembedded : 0;
|
|
12567
|
-
} catch {
|
|
12568
|
-
return 0;
|
|
12569
|
-
}
|
|
12570
|
-
}
|
|
12571
|
-
async function runSessionInit(vaultRoot, tmpDir = osTmpdir2()) {
|
|
12572
|
-
try {
|
|
12573
|
-
await loadVaultConfig(vaultRoot);
|
|
12574
|
-
} catch {
|
|
12575
|
-
return { decision: "block", reason: "onebrain-init-required" };
|
|
12576
|
-
}
|
|
12577
|
-
const sessionToken = await resolveSessionToken(tmpDir);
|
|
12578
|
-
await cleanStaleStateFile(sessionToken, tmpDir);
|
|
12579
|
-
const datetime = formatDatetime(new Date);
|
|
12580
|
-
const qmdUnembedded = await queryQmdUnembedded();
|
|
12581
|
-
return {
|
|
12582
|
-
datetime,
|
|
12583
|
-
session_token: sessionToken,
|
|
12584
|
-
qmd_unembedded: qmdUnembedded
|
|
12585
|
-
};
|
|
12586
|
-
}
|
|
12587
|
-
async function sessionInitCommand(vaultRoot) {
|
|
12588
|
-
const result = await runSessionInit(vaultRoot);
|
|
12589
|
-
process.stdout.write(`${JSON.stringify(result)}
|
|
12590
|
-
`);
|
|
12591
|
-
}
|
|
12592
|
-
|
|
12593
|
-
// src/commands/internal/vault-sync.ts
|
|
12594
|
-
init_dist2();
|
|
12595
|
-
init_harness();
|
|
12596
|
-
var import_yaml7 = __toESM(require_dist(), 1);
|
|
12597
|
-
import {
|
|
12598
|
-
mkdir as mkdir5,
|
|
12599
|
-
mkdtemp as mkdtemp2,
|
|
12600
|
-
readFile as readFile7,
|
|
12601
|
-
readdir as readdir5,
|
|
12602
|
-
rename as rename5,
|
|
12603
|
-
rm as rm2,
|
|
12604
|
-
stat as stat5,
|
|
12605
|
-
unlink as unlink3,
|
|
12606
|
-
writeFile as writeFile6
|
|
12607
|
-
} from "node:fs/promises";
|
|
12608
|
-
import { homedir as homedir5, tmpdir as tmpdir2 } from "node:os";
|
|
12609
|
-
import { dirname as dirname5, join as join12, relative as relative2 } from "node:path";
|
|
12610
|
-
function resolveBranch2(updateChannel) {
|
|
12611
|
-
return updateChannel === "stable" ? "main" : "next";
|
|
12612
|
-
}
|
|
12613
|
-
async function downloadTarball2(branch, fetchFn) {
|
|
12614
|
-
const url = `https://api.github.com/repos/kengio/onebrain/tarball/${branch}`;
|
|
12615
|
-
const response = await fetchFn(url);
|
|
12616
|
-
if (!response.ok) {
|
|
12617
|
-
const hints = {
|
|
12618
|
-
403: " — check repo permissions or GITHUB_TOKEN",
|
|
12619
|
-
404: " — repo or branch not found",
|
|
12620
|
-
429: " — rate limited, wait and retry"
|
|
12621
|
-
};
|
|
12622
|
-
const hint = hints[response.status] ?? "";
|
|
12623
|
-
throw new Error(`HTTP ${response.status} downloading tarball from ${url}${hint}`);
|
|
12624
|
-
}
|
|
12625
|
-
const tarball = await response.arrayBuffer();
|
|
12626
|
-
const tmpDir = await mkdtemp2(join12(tmpdir2(), "onebrain-sync-"));
|
|
12627
|
-
return { tarball, tmpDir };
|
|
12628
|
-
}
|
|
12629
|
-
async function extractTarball2(tarball, destDir) {
|
|
12630
|
-
const tarPath = join12(destDir, "bundle.tar.gz");
|
|
12631
|
-
await writeFile6(tarPath, Buffer.from(tarball));
|
|
12632
|
-
const proc = Bun.spawn(["tar", "-xzf", tarPath, "-C", destDir], {
|
|
12633
|
-
stdout: "pipe",
|
|
12634
|
-
stderr: "pipe"
|
|
12635
|
-
});
|
|
12636
|
-
const exitCode = await proc.exited;
|
|
12637
|
-
if (exitCode !== 0) {
|
|
12638
|
-
const errText = await new Response(proc.stderr).text();
|
|
12639
|
-
throw new Error(`tar extraction failed (exit ${exitCode}): ${errText.trim()}`);
|
|
12640
|
-
}
|
|
12641
|
-
await unlink3(tarPath);
|
|
12642
|
-
const entries = await readdir5(destDir);
|
|
12643
|
-
const topLevel = entries.find((e2) => e2 !== "bundle.tar.gz");
|
|
12644
|
-
if (!topLevel) {
|
|
12645
|
-
throw new Error("Extracted tarball contains no top-level directory");
|
|
12646
|
-
}
|
|
12647
|
-
return join12(destDir, topLevel);
|
|
12648
|
-
}
|
|
12649
|
-
async function listFilesRecursive2(dir) {
|
|
12650
|
-
const results = [];
|
|
12651
|
-
const queue = [dir];
|
|
12652
|
-
while (queue.length > 0) {
|
|
12653
|
-
const current = queue.pop();
|
|
12654
|
-
let entries;
|
|
12655
|
-
try {
|
|
12656
|
-
entries = await readdir5(current);
|
|
12657
|
-
} catch {
|
|
12658
|
-
continue;
|
|
12659
|
-
}
|
|
12660
|
-
for (const entry of entries) {
|
|
12661
|
-
const fullPath = join12(current, entry);
|
|
12662
|
-
let s;
|
|
12663
|
-
try {
|
|
12664
|
-
s = await stat5(fullPath);
|
|
12665
|
-
} catch {
|
|
12666
|
-
continue;
|
|
12667
|
-
}
|
|
12668
|
-
if (s.isDirectory()) {
|
|
12669
|
-
queue.push(fullPath);
|
|
12670
|
-
} else {
|
|
12671
|
-
results.push(fullPath);
|
|
12672
|
-
}
|
|
12673
|
-
}
|
|
12674
|
-
}
|
|
12675
|
-
return results;
|
|
12676
|
-
}
|
|
12677
|
-
async function syncPluginFiles2(extractedDir, vaultRoot, unlinkFn = unlink3) {
|
|
12678
|
-
const sourcePlugin = join12(extractedDir, ".claude", "plugins", "onebrain");
|
|
12679
|
-
const destPlugin = join12(vaultRoot, ".claude", "plugins", "onebrain");
|
|
12680
|
-
await mkdir5(destPlugin, { recursive: true });
|
|
12681
|
-
const sourceFiles = await listFilesRecursive2(sourcePlugin);
|
|
12682
|
-
const sourceRelSet = new Set(sourceFiles.map((f2) => relative2(sourcePlugin, f2)));
|
|
12683
|
-
const destFiles = await listFilesRecursive2(destPlugin);
|
|
12684
|
-
const destRelSet = new Set(destFiles.map((f2) => relative2(destPlugin, f2)));
|
|
12685
|
-
const staleRels = [];
|
|
12686
|
-
for (const rel of destRelSet) {
|
|
12687
|
-
if (!sourceRelSet.has(rel)) {
|
|
12688
|
-
staleRels.push(rel);
|
|
12689
|
-
}
|
|
12690
|
-
}
|
|
12691
|
-
let filesAdded = 0;
|
|
12692
|
-
for (const srcPath of sourceFiles) {
|
|
12693
|
-
const rel = relative2(sourcePlugin, srcPath);
|
|
12694
|
-
const destPath = join12(destPlugin, rel);
|
|
12695
|
-
await mkdir5(dirname5(destPath), { recursive: true });
|
|
12696
|
-
const content = await readFile7(srcPath);
|
|
12697
|
-
await writeFile6(destPath, content);
|
|
12698
|
-
filesAdded++;
|
|
12699
|
-
}
|
|
12700
|
-
let filesRemoved = 0;
|
|
12701
|
-
for (const rel of staleRels) {
|
|
12702
|
-
const destPath = join12(destPlugin, rel);
|
|
12703
|
-
try {
|
|
12704
|
-
await unlinkFn(destPath);
|
|
12705
|
-
filesRemoved++;
|
|
12706
|
-
} catch {}
|
|
12707
|
-
}
|
|
12708
|
-
return { filesAdded, filesRemoved };
|
|
12709
|
-
}
|
|
12710
|
-
async function copyRootDocs2(extractedDir, vaultRoot) {
|
|
12711
|
-
const docs = ["CONTRIBUTING.md", "CHANGELOG.md", "PLUGIN-CHANGELOG.md"];
|
|
12712
|
-
for (const doc of docs) {
|
|
12713
|
-
const srcPath = join12(extractedDir, doc);
|
|
12714
|
-
const destPath = join12(vaultRoot, doc);
|
|
12715
|
-
try {
|
|
12716
|
-
const content = await readFile7(srcPath);
|
|
12717
|
-
await writeFile6(destPath, content);
|
|
12718
|
-
} catch {}
|
|
12719
|
-
}
|
|
12720
|
-
}
|
|
12721
|
-
async function mergeHarnessFile2(extractedDir, vaultRoot, filename) {
|
|
12722
|
-
const srcPath = join12(extractedDir, filename);
|
|
12723
|
-
const destPath = join12(vaultRoot, filename);
|
|
12724
|
-
let repoText;
|
|
12725
|
-
try {
|
|
12726
|
-
repoText = await readFile7(srcPath, "utf8");
|
|
12727
|
-
} catch {
|
|
12728
|
-
return 0;
|
|
12729
|
-
}
|
|
12730
|
-
let vaultText;
|
|
12731
|
-
try {
|
|
12732
|
-
vaultText = await readFile7(destPath, "utf8");
|
|
12733
|
-
} catch {
|
|
12734
|
-
await writeFile6(destPath, repoText, "utf8");
|
|
12735
|
-
return repoText.split(`
|
|
12736
|
-
`).filter((l2) => l2.startsWith("@")).length;
|
|
12737
|
-
}
|
|
12738
|
-
const vaultAtSet = new Set(vaultText.split(`
|
|
12739
|
-
`).filter((l2) => l2.startsWith("@")).map((l2) => l2.trim()));
|
|
12740
|
-
const newImports = repoText.split(`
|
|
12741
|
-
`).filter((l2) => l2.startsWith("@") && !vaultAtSet.has(l2.trim())).map((l2) => l2.trimEnd());
|
|
12742
|
-
if (newImports.length === 0) {
|
|
12743
|
-
return 0;
|
|
12744
|
-
}
|
|
12745
|
-
const vaultLines = vaultText.split(`
|
|
12746
|
-
`);
|
|
12747
|
-
const lastAtIdx = vaultLines.reduce((acc, l2, i) => l2.startsWith("@") ? i : acc, -1);
|
|
12748
|
-
if (lastAtIdx >= 0) {
|
|
12749
|
-
vaultLines.splice(lastAtIdx, 0, ...newImports);
|
|
12750
|
-
} else {
|
|
12751
|
-
vaultLines.push("", ...newImports);
|
|
12752
|
-
}
|
|
12753
|
-
const merged = vaultLines.join(`
|
|
12754
|
-
`);
|
|
12755
|
-
await writeFile6(destPath, merged, "utf8");
|
|
12756
|
-
return newImports.length;
|
|
12757
|
-
}
|
|
12758
|
-
async function mergeHarnessFiles2(extractedDir, vaultRoot) {
|
|
12759
|
-
const harnessFiles = ["CLAUDE.md", "GEMINI.md", "AGENTS.md"];
|
|
12760
|
-
let totalImportsAdded = 0;
|
|
12761
|
-
const results = await Promise.all(harnessFiles.map((f2) => mergeHarnessFile2(extractedDir, vaultRoot, f2)));
|
|
12762
|
-
for (const n of results) {
|
|
12763
|
-
totalImportsAdded += n;
|
|
12764
|
-
}
|
|
12765
|
-
return totalImportsAdded;
|
|
12766
|
-
}
|
|
12767
|
-
async function updateVaultYml2(vaultRoot, updateChannel) {
|
|
12768
|
-
const vaultYmlPath = join12(vaultRoot, "vault.yml");
|
|
12769
|
-
let text;
|
|
12770
|
-
try {
|
|
12771
|
-
text = await readFile7(vaultYmlPath, "utf8");
|
|
12772
|
-
} catch {
|
|
12773
|
-
text = "";
|
|
12774
|
-
}
|
|
12775
|
-
const raw = import_yaml7.parse(text) ?? {};
|
|
12776
|
-
raw["update_channel"] = updateChannel;
|
|
12777
|
-
const updated = import_yaml7.stringify(raw, { lineWidth: 0 });
|
|
12778
|
-
const tmpPath = `${vaultYmlPath}.tmp`;
|
|
12779
|
-
await writeFile6(tmpPath, updated, "utf8");
|
|
12780
|
-
await rename5(tmpPath, vaultYmlPath);
|
|
12781
|
-
}
|
|
12782
|
-
async function readPluginVersion2(vaultRoot) {
|
|
12783
|
-
const pluginJsonPath = join12(vaultRoot, ".claude", "plugins", "onebrain", ".claude-plugin", "plugin.json");
|
|
12784
|
-
try {
|
|
12785
|
-
const text = await readFile7(pluginJsonPath, "utf8");
|
|
12786
|
-
const parsed = JSON.parse(text);
|
|
12787
|
-
return typeof parsed["version"] === "string" ? parsed["version"] : "unknown";
|
|
12788
|
-
} catch {
|
|
12789
|
-
return "unknown";
|
|
12790
|
-
}
|
|
12791
|
-
}
|
|
12792
|
-
async function pinToVault2(vaultRoot, installedPluginsPath, installedPluginsCacheDir) {
|
|
12793
|
-
let text;
|
|
12794
|
-
try {
|
|
12795
|
-
text = await readFile7(installedPluginsPath, "utf8");
|
|
12796
|
-
} catch {
|
|
12797
|
-
return { skipped: true };
|
|
12798
|
-
}
|
|
12799
|
-
let data;
|
|
12800
|
-
try {
|
|
12801
|
-
data = JSON.parse(text);
|
|
12802
|
-
} catch {
|
|
12803
|
-
throw new Error(`installed_plugins.json is not valid JSON: ${installedPluginsPath}`);
|
|
12804
|
-
}
|
|
12805
|
-
const plugins = data["plugins"];
|
|
12806
|
-
if (!plugins) {
|
|
12807
|
-
return { skipped: true };
|
|
12808
|
-
}
|
|
12809
|
-
const onebrainKeys = Object.keys(plugins).filter((k2) => k2.startsWith("onebrain@"));
|
|
12810
|
-
if (onebrainKeys.length === 0) {
|
|
12811
|
-
return { skipped: true };
|
|
12812
|
-
}
|
|
12813
|
-
const vaultPluginDir = join12(vaultRoot, ".claude", "plugins", "onebrain");
|
|
12814
|
-
const pluginVersion = await readPluginVersion2(vaultRoot);
|
|
12815
|
-
const cacheDir = installedPluginsCacheDir ?? join12(dirname5(installedPluginsPath), "cache");
|
|
12816
|
-
const hasMarketplace = onebrainKeys.some((k2) => {
|
|
12817
|
-
const entries = plugins[k2];
|
|
12818
|
-
return entries.some((e2) => e2["source"] === "marketplace");
|
|
12819
|
-
});
|
|
12820
|
-
if (hasMarketplace) {
|
|
12821
|
-
return { skipped: true };
|
|
12822
|
-
}
|
|
12823
|
-
let changed = false;
|
|
12824
|
-
for (const key of onebrainKeys) {
|
|
12825
|
-
const entries = plugins[key];
|
|
12826
|
-
for (const entry of entries) {
|
|
12827
|
-
const installPath = entry["installPath"];
|
|
12828
|
-
if (typeof installPath !== "string") {
|
|
12829
|
-
continue;
|
|
12830
|
-
}
|
|
12831
|
-
let inCache = false;
|
|
12832
|
-
try {
|
|
12833
|
-
inCache = installPath.startsWith(`${cacheDir}/`) || installPath === cacheDir;
|
|
12834
|
-
} catch {
|
|
12835
|
-
inCache = false;
|
|
12836
|
-
}
|
|
12837
|
-
if (!inCache) {
|
|
12838
|
-
continue;
|
|
12839
|
-
}
|
|
12840
|
-
entry["installPath"] = vaultPluginDir;
|
|
12841
|
-
entry["version"] = pluginVersion;
|
|
12842
|
-
changed = true;
|
|
12843
|
-
}
|
|
12844
|
-
}
|
|
12845
|
-
if (!changed) {
|
|
12846
|
-
return { skipped: false };
|
|
12847
|
-
}
|
|
12848
|
-
const tmpPath = `${installedPluginsPath}.tmp`;
|
|
12849
|
-
await writeFile6(tmpPath, JSON.stringify(data, null, 4), "utf8");
|
|
12850
|
-
await rename5(tmpPath, installedPluginsPath);
|
|
12851
|
-
return { skipped: false };
|
|
12852
|
-
}
|
|
12853
|
-
async function cleanPluginCache2(installedPluginsPath, installedPluginsCacheDir) {
|
|
12854
|
-
const cacheDir = installedPluginsCacheDir ?? join12(dirname5(installedPluginsPath), "cache");
|
|
12855
|
-
try {
|
|
12856
|
-
await stat5(cacheDir);
|
|
12857
|
-
} catch {
|
|
12858
|
-
return 0;
|
|
12859
|
-
}
|
|
12860
|
-
const onebrainDirs = [];
|
|
12861
|
-
try {
|
|
12862
|
-
const text = await readFile7(installedPluginsPath, "utf8");
|
|
12863
|
-
const data = JSON.parse(text);
|
|
12864
|
-
const plugins = data["plugins"];
|
|
12865
|
-
if (plugins) {
|
|
12866
|
-
for (const key of Object.keys(plugins)) {
|
|
12867
|
-
if (!key.startsWith("onebrain@"))
|
|
12868
|
-
continue;
|
|
12869
|
-
const marketplace = key.split("@")[1];
|
|
12870
|
-
const candidate = join12(cacheDir, marketplace, "onebrain");
|
|
12871
|
-
try {
|
|
12872
|
-
await stat5(candidate);
|
|
12873
|
-
onebrainDirs.push(candidate);
|
|
12874
|
-
} catch {}
|
|
12875
|
-
}
|
|
12876
|
-
}
|
|
12877
|
-
} catch {}
|
|
12878
|
-
if (onebrainDirs.length === 0) {
|
|
12879
|
-
try {
|
|
12880
|
-
const marketplaceDirs = await readdir5(cacheDir);
|
|
12881
|
-
for (const mp of marketplaceDirs) {
|
|
12882
|
-
const candidate = join12(cacheDir, mp, "onebrain");
|
|
12883
|
-
try {
|
|
12884
|
-
await stat5(candidate);
|
|
12885
|
-
onebrainDirs.push(candidate);
|
|
12886
|
-
} catch {}
|
|
12887
|
-
}
|
|
12888
|
-
} catch {
|
|
12889
|
-
return 0;
|
|
12890
|
-
}
|
|
12891
|
-
}
|
|
12892
|
-
let removed = 0;
|
|
12893
|
-
for (const pluginDir of onebrainDirs) {
|
|
12894
|
-
let versionDirs;
|
|
12895
|
-
try {
|
|
12896
|
-
versionDirs = await readdir5(pluginDir);
|
|
12897
|
-
} catch {
|
|
12898
|
-
continue;
|
|
12899
|
-
}
|
|
12900
|
-
for (const versionDir of versionDirs) {
|
|
12901
|
-
const fullPath = join12(pluginDir, versionDir);
|
|
12902
|
-
try {
|
|
12903
|
-
const s = await stat5(fullPath);
|
|
12904
|
-
if (s.isDirectory()) {
|
|
12905
|
-
await rm2(fullPath, { recursive: true, force: true });
|
|
12906
|
-
removed++;
|
|
12907
|
-
}
|
|
12908
|
-
} catch {}
|
|
12909
|
-
}
|
|
12910
|
-
}
|
|
12911
|
-
return removed;
|
|
12912
|
-
}
|
|
12913
|
-
async function runVaultSync2(vaultRoot, opts = {}) {
|
|
12914
|
-
const fetchFn = opts.fetchFn ?? globalThis.fetch;
|
|
12915
|
-
const isTTY = opts.isTTY ?? process.stdout.isTTY;
|
|
12916
|
-
const unlinkFn = opts.unlinkFn ?? unlink3;
|
|
12917
|
-
let updateChannel = "stable";
|
|
12918
|
-
try {
|
|
12919
|
-
const vaultYmlText = await readFile7(join12(vaultRoot, "vault.yml"), "utf8");
|
|
12920
|
-
const vaultYml = import_yaml7.parse(vaultYmlText) ?? {};
|
|
12921
|
-
if (typeof vaultYml["update_channel"] === "string") {
|
|
12922
|
-
updateChannel = vaultYml["update_channel"];
|
|
12923
|
-
}
|
|
12924
|
-
} catch {}
|
|
12925
|
-
const harness = await detectHarness(vaultRoot);
|
|
12926
|
-
const branch = opts.branch ?? resolveBranch2(updateChannel);
|
|
12927
|
-
const installedPluginsPath = opts.installedPluginsPath ?? join12(homedir5(), ".claude", "plugins", "installed_plugins.json");
|
|
12928
|
-
const installedPluginsCacheDir = opts.installedPluginsCacheDir;
|
|
12929
|
-
const result = {
|
|
12930
|
-
ok: false,
|
|
12931
|
-
version: "unknown",
|
|
12932
|
-
branch,
|
|
12933
|
-
filesAdded: 0,
|
|
12934
|
-
filesRemoved: 0,
|
|
12935
|
-
importsAdded: 0,
|
|
12936
|
-
pinSkipped: true,
|
|
12937
|
-
cacheRemoved: 0
|
|
12938
|
-
};
|
|
12939
|
-
let s = null;
|
|
12940
|
-
function startSpinner(msg) {
|
|
12941
|
-
if (isTTY) {
|
|
12942
|
-
s = L2();
|
|
12943
|
-
s.start(msg);
|
|
12944
|
-
} else {
|
|
12945
|
-
process.stdout.write(`vault-sync: ${msg}
|
|
12946
|
-
`);
|
|
12947
|
-
}
|
|
12248
|
+
const tmuxPane = process.env["TMUX_PANE"];
|
|
12249
|
+
if (tmuxPane) {
|
|
12250
|
+
const stripped = tmuxPane.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
|
|
12251
|
+
if (stripped.length > 0)
|
|
12252
|
+
return stripped;
|
|
12948
12253
|
}
|
|
12949
|
-
|
|
12950
|
-
|
|
12951
|
-
|
|
12952
|
-
|
|
12953
|
-
|
|
12254
|
+
const termSessionId = process.env["TERM_SESSION_ID"];
|
|
12255
|
+
if (termSessionId) {
|
|
12256
|
+
const stripped = termSessionId.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
|
|
12257
|
+
if (stripped.length > 0)
|
|
12258
|
+
return stripped;
|
|
12954
12259
|
}
|
|
12955
|
-
|
|
12956
|
-
|
|
12260
|
+
const today = new Date;
|
|
12261
|
+
const yyyymmdd = [
|
|
12262
|
+
today.getFullYear(),
|
|
12263
|
+
String(today.getMonth() + 1).padStart(2, "0"),
|
|
12264
|
+
String(today.getDate()).padStart(2, "0")
|
|
12265
|
+
].join("");
|
|
12266
|
+
const cacheFile = join10(tmpDir, `onebrain-day-${yyyymmdd}.token`);
|
|
12267
|
+
const cacheExists = await Bun.file(cacheFile).exists();
|
|
12268
|
+
if (cacheExists) {
|
|
12269
|
+
const cached = (await Bun.file(cacheFile).text()).trim();
|
|
12270
|
+
const n = Number(cached);
|
|
12271
|
+
if (!Number.isNaN(n) && n > 1)
|
|
12272
|
+
return cached;
|
|
12273
|
+
}
|
|
12274
|
+
const ppid = process.ppid;
|
|
12275
|
+
if (ppid !== undefined && ppid > 1) {
|
|
12276
|
+
const token2 = String(ppid);
|
|
12277
|
+
await Bun.write(cacheFile, token2);
|
|
12278
|
+
return token2;
|
|
12957
12279
|
}
|
|
12958
|
-
let tmpDir = null;
|
|
12959
12280
|
try {
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
12971
|
-
|
|
12972
|
-
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
12978
|
-
|
|
12281
|
+
const ps = Bun.spawn([
|
|
12282
|
+
"powershell.exe",
|
|
12283
|
+
"-NoProfile",
|
|
12284
|
+
"-NonInteractive",
|
|
12285
|
+
"-Command",
|
|
12286
|
+
"(Get-Process -Id $PID).Parent.Id"
|
|
12287
|
+
], {
|
|
12288
|
+
stdout: "pipe",
|
|
12289
|
+
stderr: "pipe"
|
|
12290
|
+
});
|
|
12291
|
+
const timeoutMs = 3000;
|
|
12292
|
+
let timerId;
|
|
12293
|
+
const race = await Promise.race([
|
|
12294
|
+
ps.exited,
|
|
12295
|
+
new Promise((resolve) => {
|
|
12296
|
+
timerId = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
12297
|
+
})
|
|
12298
|
+
]);
|
|
12299
|
+
if (timerId !== undefined)
|
|
12300
|
+
clearTimeout(timerId);
|
|
12301
|
+
if (race !== "timeout") {
|
|
12302
|
+
const out2 = (await new Response(ps.stdout).text()).replace(/\D/g, "").trim();
|
|
12303
|
+
if (out2 && Number(out2) > 1) {
|
|
12304
|
+
await Bun.write(cacheFile, out2);
|
|
12305
|
+
return out2;
|
|
12979
12306
|
}
|
|
12980
|
-
} catch {}
|
|
12981
|
-
stopSpinner(`kengio/onebrain@${branch} (v${result.version})`);
|
|
12982
|
-
startSpinner("Syncing plugin files...");
|
|
12983
|
-
try {
|
|
12984
|
-
const { filesAdded, filesRemoved } = await syncPluginFiles2(extractedDir, vaultRoot, unlinkFn);
|
|
12985
|
-
result.filesAdded = filesAdded;
|
|
12986
|
-
result.filesRemoved = filesRemoved;
|
|
12987
|
-
} catch (err) {
|
|
12988
|
-
stopSpinner("Plugin sync failed");
|
|
12989
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
12990
|
-
result.error = msg;
|
|
12991
|
-
process.stderr.write(`vault-sync: plugin sync failed: ${msg}
|
|
12992
|
-
`);
|
|
12993
|
-
return result;
|
|
12994
|
-
}
|
|
12995
|
-
stopSpinner(`${result.filesAdded} file${result.filesAdded !== 1 ? "s" : ""} synced, ${result.filesRemoved} removed`);
|
|
12996
|
-
if (opts.includeObsidian) {
|
|
12997
|
-
const sourceObsidian = join12(extractedDir, ".obsidian");
|
|
12998
|
-
const destObsidian = join12(vaultRoot, ".obsidian");
|
|
12999
|
-
try {
|
|
13000
|
-
const obsidianFiles = await listFilesRecursive2(sourceObsidian);
|
|
13001
|
-
for (const srcPath of obsidianFiles) {
|
|
13002
|
-
const rel = relative2(sourceObsidian, srcPath);
|
|
13003
|
-
const destPath = join12(destObsidian, rel);
|
|
13004
|
-
await mkdir5(dirname5(destPath), { recursive: true });
|
|
13005
|
-
const content = await readFile7(srcPath);
|
|
13006
|
-
await writeFile6(destPath, content);
|
|
13007
|
-
}
|
|
13008
|
-
} catch {}
|
|
13009
|
-
}
|
|
13010
|
-
await copyRootDocs2(extractedDir, vaultRoot);
|
|
13011
|
-
startSpinner("Updating harness files...");
|
|
13012
|
-
let importsAdded = 0;
|
|
13013
|
-
try {
|
|
13014
|
-
importsAdded = await mergeHarnessFiles2(extractedDir, vaultRoot);
|
|
13015
|
-
result.importsAdded = importsAdded;
|
|
13016
|
-
} catch (err) {
|
|
13017
|
-
stopSpinner("Harness merge failed");
|
|
13018
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
13019
|
-
result.error = msg;
|
|
13020
|
-
process.stderr.write(`vault-sync: harness merge failed: ${msg}
|
|
13021
|
-
`);
|
|
13022
|
-
return result;
|
|
13023
|
-
}
|
|
13024
|
-
if (importsAdded > 0) {
|
|
13025
|
-
stopSpinner(`${importsAdded} import${importsAdded !== 1 ? "s" : ""} added`);
|
|
13026
12307
|
} else {
|
|
13027
|
-
|
|
13028
|
-
}
|
|
13029
|
-
try {
|
|
13030
|
-
await updateVaultYml2(vaultRoot, updateChannel);
|
|
13031
|
-
} catch (err) {
|
|
13032
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
13033
|
-
result.error = msg;
|
|
13034
|
-
process.stderr.write(`vault-sync: vault.yml update failed: ${msg}
|
|
13035
|
-
`);
|
|
13036
|
-
return result;
|
|
12308
|
+
ps.kill();
|
|
13037
12309
|
}
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
}
|
|
13055
|
-
startSpinner("Cleaning cache...");
|
|
12310
|
+
} catch {}
|
|
12311
|
+
const token = String(Math.floor(Math.random() * 90000) + 1e4);
|
|
12312
|
+
await Bun.write(cacheFile, token);
|
|
12313
|
+
return token;
|
|
12314
|
+
}
|
|
12315
|
+
async function cleanStaleStateFile(token, tmpDir) {
|
|
12316
|
+
try {
|
|
12317
|
+
const processStartMs = Date.now() - performance.now();
|
|
12318
|
+
const stateFile = join10(tmpDir, `onebrain-${token}.state`);
|
|
12319
|
+
const f2 = Bun.file(stateFile);
|
|
12320
|
+
const exists = await f2.exists();
|
|
12321
|
+
if (!exists)
|
|
12322
|
+
return;
|
|
12323
|
+
const { mtime } = await f2.stat();
|
|
12324
|
+
const mtimeMs = mtime instanceof Date ? mtime.getTime() : Number(mtime) * 1000;
|
|
12325
|
+
if (mtimeMs < processStartMs) {
|
|
13056
12326
|
try {
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
if (cacheRemoved > 0) {
|
|
13060
|
-
stopSpinner(`${cacheRemoved} cached version${cacheRemoved !== 1 ? "s" : ""} removed`);
|
|
13061
|
-
} else {
|
|
13062
|
-
stopSpinner("no cache to clean");
|
|
13063
|
-
}
|
|
13064
|
-
} catch (err) {
|
|
13065
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
13066
|
-
process.stderr.write(`vault-sync: cache clean warning: ${msg}
|
|
13067
|
-
`);
|
|
13068
|
-
stopSpinner("cache clean skipped (error — non-fatal)");
|
|
13069
|
-
}
|
|
13070
|
-
}
|
|
13071
|
-
result.ok = true;
|
|
13072
|
-
if (isTTY) {
|
|
13073
|
-
fe(`Done — v${result.version} synced`);
|
|
13074
|
-
} else {
|
|
13075
|
-
process.stdout.write(`vault-sync: done
|
|
13076
|
-
`);
|
|
12327
|
+
await unlink2(stateFile);
|
|
12328
|
+
} catch {}
|
|
13077
12329
|
}
|
|
13078
|
-
}
|
|
13079
|
-
|
|
13080
|
-
|
|
12330
|
+
} catch {}
|
|
12331
|
+
}
|
|
12332
|
+
async function queryQmdUnembedded() {
|
|
12333
|
+
try {
|
|
12334
|
+
const qmdArgs = process.platform === "win32" ? ["powershell.exe", "-NoProfile", "-Command", "qmd status --json"] : ["qmd", "status", "--json"];
|
|
12335
|
+
const proc = Bun.spawn(qmdArgs, {
|
|
12336
|
+
stdout: "pipe",
|
|
12337
|
+
stderr: "pipe"
|
|
12338
|
+
});
|
|
12339
|
+
const timeoutMs = 2000;
|
|
12340
|
+
let timerId;
|
|
12341
|
+
const race = await Promise.race([
|
|
12342
|
+
proc.exited,
|
|
12343
|
+
new Promise((resolve) => {
|
|
12344
|
+
timerId = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
12345
|
+
})
|
|
12346
|
+
]);
|
|
12347
|
+
if (timerId !== undefined)
|
|
12348
|
+
clearTimeout(timerId);
|
|
12349
|
+
if (race === "timeout") {
|
|
12350
|
+
proc.kill();
|
|
12351
|
+
return 0;
|
|
13081
12352
|
}
|
|
12353
|
+
const stdout = await new Response(proc.stdout).text();
|
|
12354
|
+
const parsed = JSON.parse(stdout);
|
|
12355
|
+
const unembedded = parsed["unembedded"];
|
|
12356
|
+
return typeof unembedded === "number" ? unembedded : 0;
|
|
12357
|
+
} catch {
|
|
12358
|
+
return 0;
|
|
13082
12359
|
}
|
|
13083
|
-
return result;
|
|
13084
12360
|
}
|
|
13085
|
-
async function
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
12361
|
+
async function runSessionInit(vaultRoot, tmpDir = osTmpdir2()) {
|
|
12362
|
+
try {
|
|
12363
|
+
await loadVaultConfig(vaultRoot);
|
|
12364
|
+
} catch {
|
|
12365
|
+
return { decision: "block", reason: "onebrain-init-required" };
|
|
13089
12366
|
}
|
|
12367
|
+
const sessionToken = await resolveSessionToken(tmpDir);
|
|
12368
|
+
await cleanStaleStateFile(sessionToken, tmpDir);
|
|
12369
|
+
const datetime = formatDatetime(new Date);
|
|
12370
|
+
const qmdUnembedded = await queryQmdUnembedded();
|
|
12371
|
+
return {
|
|
12372
|
+
datetime,
|
|
12373
|
+
session_token: sessionToken,
|
|
12374
|
+
qmd_unembedded: qmdUnembedded
|
|
12375
|
+
};
|
|
12376
|
+
}
|
|
12377
|
+
async function sessionInitCommand(vaultRoot) {
|
|
12378
|
+
const result = await runSessionInit(vaultRoot);
|
|
12379
|
+
process.stdout.write(`${JSON.stringify(result)}
|
|
12380
|
+
`);
|
|
13090
12381
|
}
|
|
13091
12382
|
|
|
12383
|
+
// src/index.ts
|
|
12384
|
+
init_vault_sync();
|
|
12385
|
+
|
|
13092
12386
|
// src/commands/update.ts
|
|
13093
12387
|
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
13094
|
-
|
|
13095
|
-
import { join as join13 } from "node:path";
|
|
12388
|
+
init_cli_ui();
|
|
13096
12389
|
var GITHUB_REPO = "https://api.github.com/repos/kengio/onebrain";
|
|
13097
12390
|
var GITHUB_RELEASES_URL = `${GITHUB_REPO}/releases/latest`;
|
|
13098
12391
|
async function fetchLatestRelease(fetchFn) {
|
|
@@ -13113,14 +12406,6 @@ async function fetchLatestRelease(fetchFn) {
|
|
|
13113
12406
|
function formatReleaseDate(date) {
|
|
13114
12407
|
return date.toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" });
|
|
13115
12408
|
}
|
|
13116
|
-
function daysBehind(date) {
|
|
13117
|
-
const days = Math.floor((Date.now() - date.getTime()) / (1000 * 60 * 60 * 24));
|
|
13118
|
-
if (days <= 0)
|
|
13119
|
-
return "just released";
|
|
13120
|
-
if (days === 1)
|
|
13121
|
-
return "1 day behind";
|
|
13122
|
-
return `${days} days behind`;
|
|
13123
|
-
}
|
|
13124
12409
|
var _windowsShell;
|
|
13125
12410
|
function windowsShell() {
|
|
13126
12411
|
if (_windowsShell !== undefined)
|
|
@@ -13178,7 +12463,6 @@ async function defaultCurrentVersion() {
|
|
|
13178
12463
|
}
|
|
13179
12464
|
}
|
|
13180
12465
|
async function runUpdate(opts = {}) {
|
|
13181
|
-
const vaultDir = opts.vaultDir ?? process.cwd();
|
|
13182
12466
|
const isTTY = opts.isTTY ?? process.stdout.isTTY ?? false;
|
|
13183
12467
|
const check = opts.check ?? false;
|
|
13184
12468
|
const fetchFn = opts.fetchFn ?? globalThis.fetch;
|
|
@@ -13187,35 +12471,19 @@ async function runUpdate(opts = {}) {
|
|
|
13187
12471
|
const currentVersionFn = opts.currentVersionFn ?? defaultCurrentVersion;
|
|
13188
12472
|
const result = { ok: false, exitCode: 0 };
|
|
13189
12473
|
const createStep = makeStepFn(isTTY);
|
|
13190
|
-
const delay = opts.delayFn ?? ((ms) => new Promise((r2) => setTimeout(r2, ms)));
|
|
13191
|
-
const randDelay = () => isTTY ? delay(Math.floor(Math.random() * 1000) + 1000) : Promise.resolve();
|
|
13192
12474
|
if (isTTY) {
|
|
13193
12475
|
await printBanner();
|
|
13194
12476
|
} else {
|
|
13195
12477
|
writeLine("OneBrain Update");
|
|
13196
12478
|
}
|
|
13197
|
-
try {
|
|
13198
|
-
await access(join13(vaultDir, "vault.yml"));
|
|
13199
|
-
} catch {
|
|
13200
|
-
const msg = `vault.yml not found in ${vaultDir}. Run 'onebrain update' from inside an OneBrain vault.`;
|
|
13201
|
-
if (isTTY) {
|
|
13202
|
-
close(msg, true);
|
|
13203
|
-
} else {
|
|
13204
|
-
writeLine(`error: ${msg}`);
|
|
13205
|
-
}
|
|
13206
|
-
result.error = msg;
|
|
13207
|
-
result.exitCode = 1;
|
|
13208
|
-
return result;
|
|
13209
|
-
}
|
|
13210
12479
|
const sp1 = createStep("\uD83D\uDD0D", "Local version");
|
|
13211
12480
|
const { version: currentVersion, publishedAt: localPublishedAt } = await currentVersionFn();
|
|
13212
12481
|
result.currentVersion = currentVersion;
|
|
13213
|
-
|
|
13214
|
-
const localVersionLabel = localPublishedAt ? `${import_picocolors8.default.dim(currentVersion)} ${import_picocolors8.default.dim("·")} ${import_picocolors8.default.dim(formatReleaseDate(localPublishedAt))}` : import_picocolors8.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);
|
|
13215
12483
|
if (sp1)
|
|
13216
12484
|
sp1.stop(localVersionLabel);
|
|
13217
12485
|
else
|
|
13218
|
-
writeLine(`current: ${currentVersion}
|
|
12486
|
+
writeLine(`current: ${currentVersion}`);
|
|
13219
12487
|
const sp2 = createStep("\uD83C\uDF10", "Remote version");
|
|
13220
12488
|
let latestVersion;
|
|
13221
12489
|
let publishedAt = null;
|
|
@@ -13223,14 +12491,11 @@ async function runUpdate(opts = {}) {
|
|
|
13223
12491
|
const release = await fetchLatestRelease(fetchFn);
|
|
13224
12492
|
latestVersion = release.version;
|
|
13225
12493
|
publishedAt = release.publishedAt;
|
|
13226
|
-
|
|
13227
|
-
const isOutdated = latestVersion !== currentVersion;
|
|
13228
|
-
const behindSuffix = isOutdated && publishedAt ? ` ${import_picocolors8.default.dim("·")} ${import_picocolors8.default.dim(daysBehind(publishedAt))}` : "";
|
|
13229
|
-
const dateSuffix = publishedAt ? ` ${import_picocolors8.default.dim("·")} ${import_picocolors8.default.dim(formatReleaseDate(publishedAt))}${behindSuffix}` : "";
|
|
12494
|
+
const dateSuffix = publishedAt ? ` ${import_picocolors8.default.dim("\xB7")} ${import_picocolors8.default.dim(formatReleaseDate(publishedAt))}` : "";
|
|
13230
12495
|
if (sp2)
|
|
13231
12496
|
sp2.stop(`${import_picocolors8.default.green(latestVersion)}${dateSuffix}`);
|
|
13232
12497
|
else
|
|
13233
|
-
writeLine(`latest: ${latestVersion}
|
|
12498
|
+
writeLine(`latest: ${latestVersion}`);
|
|
13234
12499
|
} catch (err) {
|
|
13235
12500
|
const msg = err instanceof Error ? err.message : String(err);
|
|
13236
12501
|
if (sp2)
|
|
@@ -13249,12 +12514,12 @@ async function runUpdate(opts = {}) {
|
|
|
13249
12514
|
if (check) {
|
|
13250
12515
|
if (isTTY) {
|
|
13251
12516
|
if (currentVersion !== latestVersion) {
|
|
13252
|
-
barLine(
|
|
12517
|
+
barLine(`\u2B06\uFE0F ${import_picocolors8.default.dim(currentVersion)} \u2192 ${import_picocolors8.default.green(latestVersion)} \xB7 binary would upgrade`);
|
|
13253
12518
|
barBlank();
|
|
13254
12519
|
}
|
|
13255
|
-
close("Dry run complete
|
|
12520
|
+
close("Dry run complete \u2014 no changes made");
|
|
13256
12521
|
} else {
|
|
13257
|
-
writeLine("done: dry run complete
|
|
12522
|
+
writeLine("done: dry run complete \u2014 no changes made");
|
|
13258
12523
|
}
|
|
13259
12524
|
result.ok = true;
|
|
13260
12525
|
result.exitCode = 0;
|
|
@@ -13262,11 +12527,9 @@ async function runUpdate(opts = {}) {
|
|
|
13262
12527
|
}
|
|
13263
12528
|
if (latestVersion === currentVersion) {
|
|
13264
12529
|
if (isTTY) {
|
|
13265
|
-
|
|
13266
|
-
close(`Already up to date — @onebrain-ai/cli ${import_picocolors8.default.dim(latestVersion)}${import_picocolors8.default.dim(dateSuffix)}`);
|
|
12530
|
+
close(`Already up to date \u2014 @onebrain-ai/cli ${import_picocolors8.default.dim(latestVersion)}`);
|
|
13267
12531
|
} else {
|
|
13268
|
-
|
|
13269
|
-
writeLine(`already up to date: @onebrain-ai/cli ${latestVersion}${dateSuffix}`);
|
|
12532
|
+
writeLine(`already up to date: @onebrain-ai/cli ${latestVersion}`);
|
|
13270
12533
|
writeLine("done: nothing to do");
|
|
13271
12534
|
}
|
|
13272
12535
|
result.ok = true;
|
|
@@ -13274,13 +12537,12 @@ async function runUpdate(opts = {}) {
|
|
|
13274
12537
|
return result;
|
|
13275
12538
|
}
|
|
13276
12539
|
if (isTTY) {
|
|
13277
|
-
barLine(
|
|
12540
|
+
barLine(`\u2B06\uFE0F ${import_picocolors8.default.dim(currentVersion)} \u2192 ${import_picocolors8.default.green(latestVersion)}`);
|
|
13278
12541
|
barBlank();
|
|
13279
12542
|
}
|
|
13280
12543
|
const sp3 = createStep("\uD83D\uDCE6", "Installing @onebrain-ai/cli");
|
|
13281
12544
|
try {
|
|
13282
12545
|
await installBinaryFn(latestVersion);
|
|
13283
|
-
await randDelay();
|
|
13284
12546
|
if (sp3)
|
|
13285
12547
|
sp3.stop(import_picocolors8.default.green(latestVersion));
|
|
13286
12548
|
else
|
|
@@ -13299,9 +12561,8 @@ async function runUpdate(opts = {}) {
|
|
|
13299
12561
|
}
|
|
13300
12562
|
return result;
|
|
13301
12563
|
}
|
|
13302
|
-
const sp4 = createStep("
|
|
12564
|
+
const sp4 = createStep("\u2705", "Validating binary");
|
|
13303
12565
|
const binaryValid = await validateBinaryFn();
|
|
13304
|
-
await randDelay();
|
|
13305
12566
|
if (!binaryValid) {
|
|
13306
12567
|
if (sp4)
|
|
13307
12568
|
sp4.stop("failed");
|
|
@@ -13320,7 +12581,7 @@ async function runUpdate(opts = {}) {
|
|
|
13320
12581
|
result.ok = true;
|
|
13321
12582
|
result.exitCode = 0;
|
|
13322
12583
|
if (isTTY) {
|
|
13323
|
-
close(`Done
|
|
12584
|
+
close(`Done \u2014 run ${import_picocolors8.default.cyan("/update")} in Claude to sync vault files`);
|
|
13324
12585
|
} else {
|
|
13325
12586
|
writeLine("done: run /update in Claude to sync vault files");
|
|
13326
12587
|
}
|
|
@@ -13333,11 +12594,24 @@ async function updateCommand(opts = {}) {
|
|
|
13333
12594
|
}
|
|
13334
12595
|
}
|
|
13335
12596
|
|
|
12597
|
+
// src/lib/patch-utf8.ts
|
|
12598
|
+
function patchUtf8(stream) {
|
|
12599
|
+
const orig = stream.write.bind(stream);
|
|
12600
|
+
stream.write = (chunk, encodingOrCb, cb) => {
|
|
12601
|
+
const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
12602
|
+
if (typeof encodingOrCb === "function")
|
|
12603
|
+
return orig(buf, encodingOrCb);
|
|
12604
|
+
if (cb !== undefined)
|
|
12605
|
+
return orig(buf, cb);
|
|
12606
|
+
return orig(buf);
|
|
12607
|
+
};
|
|
12608
|
+
}
|
|
12609
|
+
|
|
13336
12610
|
// src/index.ts
|
|
13337
|
-
var VERSION = "2.1.
|
|
12611
|
+
var VERSION = "2.1.4";
|
|
13338
12612
|
var RELEASE_DATE = "2026-04-28";
|
|
13339
|
-
process.stdout
|
|
13340
|
-
process.stderr
|
|
12613
|
+
patchUtf8(process.stdout);
|
|
12614
|
+
patchUtf8(process.stderr);
|
|
13341
12615
|
var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
|
|
13342
12616
|
if (process.argv.slice(2).length === 0) {
|
|
13343
12617
|
console.log(VERSION_STRING);
|
|
@@ -13349,9 +12623,9 @@ function findVaultRoot(startDir) {
|
|
|
13349
12623
|
return process.cwd();
|
|
13350
12624
|
let dir = startDir;
|
|
13351
12625
|
while (true) {
|
|
13352
|
-
if (existsSync(
|
|
12626
|
+
if (existsSync(join11(dir, "vault.yml")))
|
|
13353
12627
|
return dir;
|
|
13354
|
-
const parent =
|
|
12628
|
+
const parent = dirname4(dir);
|
|
13355
12629
|
if (parent === dir)
|
|
13356
12630
|
return startDir;
|
|
13357
12631
|
dir = parent;
|
|
@@ -13365,11 +12639,9 @@ program2.command("init").description("Initialize a new OneBrain vault").option("
|
|
|
13365
12639
|
...opts.force !== undefined ? { force: opts.force } : {}
|
|
13366
12640
|
});
|
|
13367
12641
|
});
|
|
13368
|
-
program2.command("update").description("Update
|
|
12642
|
+
program2.command("update").description("Update @onebrain-ai/cli to the latest version").option("--check", "show what would change and exit without making changes").action(async (opts) => {
|
|
13369
12643
|
await updateCommand({
|
|
13370
|
-
|
|
13371
|
-
...opts.check !== undefined ? { check: opts.check } : {},
|
|
13372
|
-
...opts.channel !== undefined ? { channel: opts.channel } : {}
|
|
12644
|
+
...opts.check !== undefined ? { check: opts.check } : {}
|
|
13373
12645
|
});
|
|
13374
12646
|
});
|
|
13375
12647
|
program2.command("doctor").description("Run vault health checks and report issues").option("--fix", "auto-fix detected issues").action(async (opts) => {
|
|
@@ -13400,10 +12672,10 @@ program2.command("qmd-reindex", { hidden: true }).description("Trigger qmd index
|
|
|
13400
12672
|
});
|
|
13401
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) => {
|
|
13402
12674
|
const root = vaultRoot ?? process.cwd();
|
|
13403
|
-
await
|
|
12675
|
+
await vaultSyncCommand(root, opts.branch !== undefined ? { branch: opts.branch } : {});
|
|
13404
12676
|
});
|
|
13405
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) => {
|
|
13406
|
-
await
|
|
12678
|
+
await registerHooksCommand(opts.vaultDir);
|
|
13407
12679
|
});
|
|
13408
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) => {
|
|
13409
12681
|
await migrateCommand(name, cutoffDate);
|