@onebrain-ai/cli 2.0.5 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/onebrain +108 -199
- package/package.json +1 -1
package/dist/onebrain
CHANGED
|
@@ -10218,6 +10218,10 @@ var init_register_hooks = __esm(() => {
|
|
|
10218
10218
|
NPM_GLOBAL_BIN = join4(homedir2(), ".npm-global", "bin");
|
|
10219
10219
|
});
|
|
10220
10220
|
|
|
10221
|
+
// src/index.ts
|
|
10222
|
+
import { existsSync } from "fs";
|
|
10223
|
+
import { dirname as dirname6, join as join13 } from "path";
|
|
10224
|
+
|
|
10221
10225
|
// ../../node_modules/commander/esm.mjs
|
|
10222
10226
|
var import__ = __toESM(require_commander(), 1);
|
|
10223
10227
|
var {
|
|
@@ -10743,7 +10747,7 @@ init_dist();
|
|
|
10743
10747
|
import { mkdir as mkdir3, readFile as readFile3, rename as rename3, stat as stat3, writeFile as writeFile3 } from "node:fs/promises";
|
|
10744
10748
|
import { homedir as homedir3 } from "node:os";
|
|
10745
10749
|
import { dirname as dirname3, join as join5 } from "node:path";
|
|
10746
|
-
var binaryVersion = "2.0.
|
|
10750
|
+
var binaryVersion = "2.0.7";
|
|
10747
10751
|
var STANDARD_FOLDERS = [
|
|
10748
10752
|
"00-inbox",
|
|
10749
10753
|
"01-projects",
|
|
@@ -11024,7 +11028,7 @@ async function initCommand(opts = {}) {
|
|
|
11024
11028
|
// src/commands/update.ts
|
|
11025
11029
|
init_dist3();
|
|
11026
11030
|
init_dist();
|
|
11027
|
-
import { readFile as readFile4, rename as rename4, writeFile as writeFile4 } from "node:fs/promises";
|
|
11031
|
+
import { access, readFile as readFile4, rename as rename4, writeFile as writeFile4 } from "node:fs/promises";
|
|
11028
11032
|
import { join as join6 } from "node:path";
|
|
11029
11033
|
var GITHUB_RELEASES_URL = "https://api.github.com/repos/kengio/onebrain/releases/latest";
|
|
11030
11034
|
function resolveBranch2(channel) {
|
|
@@ -11093,7 +11097,7 @@ async function defaultValidateBinary() {
|
|
|
11093
11097
|
if (exitCode !== 0)
|
|
11094
11098
|
return false;
|
|
11095
11099
|
const stdout = await new Response(proc.stdout).text();
|
|
11096
|
-
return
|
|
11100
|
+
return /v\d+\.\d+/.test(stdout.trim());
|
|
11097
11101
|
} catch {
|
|
11098
11102
|
return false;
|
|
11099
11103
|
}
|
|
@@ -11135,6 +11139,19 @@ async function runUpdate(opts = {}) {
|
|
|
11135
11139
|
} else {
|
|
11136
11140
|
writeLine("OneBrain Update");
|
|
11137
11141
|
}
|
|
11142
|
+
try {
|
|
11143
|
+
await access(join6(vaultDir, "vault.yml"));
|
|
11144
|
+
} catch {
|
|
11145
|
+
const msg = `vault.yml not found in ${vaultDir}. Run 'onebrain update' from inside an OneBrain vault.`;
|
|
11146
|
+
if (isTTY) {
|
|
11147
|
+
v2.error(msg);
|
|
11148
|
+
} else {
|
|
11149
|
+
writeLine(`error: ${msg}`);
|
|
11150
|
+
}
|
|
11151
|
+
result.error = msg;
|
|
11152
|
+
result.exitCode = 1;
|
|
11153
|
+
return result;
|
|
11154
|
+
}
|
|
11138
11155
|
let latestVersion;
|
|
11139
11156
|
try {
|
|
11140
11157
|
latestVersion = await fetchLatestVersion(fetchFn);
|
|
@@ -11165,30 +11182,47 @@ async function runUpdate(opts = {}) {
|
|
|
11165
11182
|
}
|
|
11166
11183
|
let filesAdded = 0;
|
|
11167
11184
|
let filesRemoved = 0;
|
|
11185
|
+
const syncSpinner = isTTY ? L2() : null;
|
|
11186
|
+
syncSpinner?.start("Syncing plugin files…");
|
|
11168
11187
|
try {
|
|
11169
11188
|
const syncResult = await vaultSyncFn(vaultDir, { branch });
|
|
11170
11189
|
filesAdded = syncResult.filesAdded;
|
|
11171
11190
|
filesRemoved = syncResult.filesRemoved;
|
|
11191
|
+
syncSpinner?.stop(`Synced — ${filesAdded} added, ${filesRemoved} removed`);
|
|
11192
|
+
if (!isTTY) {
|
|
11193
|
+
writeLine(`syncing: ${filesAdded} files synced, ${filesRemoved} removed`);
|
|
11194
|
+
}
|
|
11172
11195
|
} catch (err) {
|
|
11173
11196
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11197
|
+
syncSpinner?.stop("Sync failed");
|
|
11174
11198
|
result.error = `vault-sync failed: ${msg}`;
|
|
11175
11199
|
result.exitCode = 1;
|
|
11176
11200
|
process.stderr.write(`update: ${result.error}
|
|
11177
11201
|
`);
|
|
11178
11202
|
return result;
|
|
11179
11203
|
}
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11204
|
+
const needsBinaryUpdate = latestVersion !== currentVersion;
|
|
11205
|
+
if (needsBinaryUpdate) {
|
|
11206
|
+
const installSpinner = isTTY ? L2() : null;
|
|
11207
|
+
installSpinner?.start(`Installing @onebrain-ai/cli ${latestVersion}…`);
|
|
11208
|
+
try {
|
|
11209
|
+
await installBinaryFn(latestVersion);
|
|
11210
|
+
installSpinner?.stop(`Installed @onebrain-ai/cli ${latestVersion}`);
|
|
11211
|
+
if (!isTTY) {
|
|
11212
|
+
writeLine(`upgrading: @onebrain-ai/cli ${latestVersion} installed`);
|
|
11213
|
+
}
|
|
11214
|
+
} catch (err) {
|
|
11215
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11216
|
+
installSpinner?.stop("Install failed");
|
|
11217
|
+
result.error = `Binary install failed: ${msg}`;
|
|
11218
|
+
result.exitCode = 1;
|
|
11219
|
+
process.stderr.write(`update: ${result.error}
|
|
11188
11220
|
`);
|
|
11189
|
-
|
|
11221
|
+
return result;
|
|
11222
|
+
}
|
|
11223
|
+
} else {
|
|
11224
|
+
noteStep("binary", `@onebrain-ai/cli ${latestVersion} already up to date`);
|
|
11190
11225
|
}
|
|
11191
|
-
noteStep("upgrading", `@onebrain-ai/cli ${latestVersion} installed`);
|
|
11192
11226
|
const binaryValid = await validateBinaryFn();
|
|
11193
11227
|
if (!binaryValid) {
|
|
11194
11228
|
result.error = "Binary validation failed. Check PATH. register-hooks NOT called.";
|
|
@@ -11245,7 +11279,6 @@ async function updateCommand(opts = {}) {
|
|
|
11245
11279
|
|
|
11246
11280
|
// src/internal/checkpoint.ts
|
|
11247
11281
|
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
11248
|
-
import { mkdir as mkdir4, readdir as readdir2, writeFile as writeFile5 } from "node:fs/promises";
|
|
11249
11282
|
import { tmpdir as osTmpdir } from "node:os";
|
|
11250
11283
|
import { join as join7 } from "node:path";
|
|
11251
11284
|
var SKIP_WINDOW = 60;
|
|
@@ -11267,15 +11300,13 @@ function readState(token, tmpDir = osTmpdir()) {
|
|
|
11267
11300
|
const count = Number(parts[0]);
|
|
11268
11301
|
const last_ts = Number(parts[1]);
|
|
11269
11302
|
const last_stop_nn = parts[2] ?? "00";
|
|
11270
|
-
const pending_stub = parts[3] && parts[3].length > 0 ? parts[3] : undefined;
|
|
11271
11303
|
if (!Number.isInteger(count) || !Number.isInteger(last_ts) || !/^\d{2}$/.test(last_stop_nn)) {
|
|
11272
11304
|
throw new Error("malformed state");
|
|
11273
11305
|
}
|
|
11274
|
-
return { count, last_ts, last_stop_nn
|
|
11306
|
+
return { count, last_ts, last_stop_nn };
|
|
11275
11307
|
} catch {
|
|
11276
|
-
const now = Math.floor(Date.now() / 1000);
|
|
11277
11308
|
try {
|
|
11278
|
-
writeFileSync(stateFilePath(token, tmpDir),
|
|
11309
|
+
writeFileSync(stateFilePath(token, tmpDir), "0:0:00", "utf8");
|
|
11279
11310
|
} catch (writeErr) {
|
|
11280
11311
|
process.stderr.write(`checkpoint: failed to rewrite state file for token ${token}: ${writeErr}
|
|
11281
11312
|
`);
|
|
@@ -11289,8 +11320,7 @@ function readState(token, tmpDir = osTmpdir()) {
|
|
|
11289
11320
|
}
|
|
11290
11321
|
function writeState(token, state, tmpDir = osTmpdir()) {
|
|
11291
11322
|
const path = stateFilePath(token, tmpDir);
|
|
11292
|
-
const
|
|
11293
|
-
const content = state.pending_stub !== undefined ? `${base}:${state.pending_stub}` : base;
|
|
11323
|
+
const content = `${state.count}:${state.last_ts}:${state.last_stop_nn}`;
|
|
11294
11324
|
try {
|
|
11295
11325
|
writeFileSync(path, content, "utf8");
|
|
11296
11326
|
} catch (err) {
|
|
@@ -11357,12 +11387,6 @@ function formatDate(epochSeconds) {
|
|
|
11357
11387
|
const dd = String(d2.getDate()).padStart(2, "0");
|
|
11358
11388
|
return `${yyyy}-${mm}-${dd}`;
|
|
11359
11389
|
}
|
|
11360
|
-
function formatYYYY(epochSeconds) {
|
|
11361
|
-
return new Date(epochSeconds * 1000).getFullYear().toString();
|
|
11362
|
-
}
|
|
11363
|
-
function formatMM(epochSeconds) {
|
|
11364
|
-
return String(new Date(epochSeconds * 1000).getMonth() + 1).padStart(2, "0");
|
|
11365
|
-
}
|
|
11366
11390
|
function emitBlock(reason) {
|
|
11367
11391
|
process.stdout.write(`${JSON.stringify({ decision: "block", reason })}
|
|
11368
11392
|
`);
|
|
@@ -11394,156 +11418,26 @@ function handleStop(token, vaultRoot, now = Math.floor(Date.now() / 1000), tmpDi
|
|
|
11394
11418
|
const since = maxNn === 0 ? " since start" : ` since checkpoint-${String(maxNn).padStart(2, "0")}`;
|
|
11395
11419
|
const filename = `${date}-${token}-checkpoint-${nextNn}.md`;
|
|
11396
11420
|
emitBlock(`${filename}${since}`);
|
|
11397
|
-
writeState(token, { count: 0, last_ts: now, last_stop_nn: nextNn
|
|
11421
|
+
writeState(token, { count: 0, last_ts: now, last_stop_nn: nextNn }, tmpDir);
|
|
11398
11422
|
}
|
|
11399
|
-
|
|
11400
|
-
tags: [checkpoint, session-log]
|
|
11401
|
-
date: ${date}
|
|
11402
|
-
checkpoint: ${nn}
|
|
11403
|
-
trigger: precompact
|
|
11404
|
-
merged: false
|
|
11405
|
-
---
|
|
11406
|
-
|
|
11407
|
-
## What We Worked On
|
|
11408
|
-
|
|
11409
|
-
<!-- stub: written automatically before compact — fill in via postcompact -->
|
|
11410
|
-
|
|
11411
|
-
## Key Decisions
|
|
11412
|
-
|
|
11413
|
-
-
|
|
11414
|
-
|
|
11415
|
-
## Insights & Learnings
|
|
11416
|
-
|
|
11417
|
-
-
|
|
11418
|
-
|
|
11419
|
-
## What Worked / Didn't Work
|
|
11420
|
-
|
|
11421
|
-
-
|
|
11422
|
-
|
|
11423
|
-
## Action Items
|
|
11424
|
-
|
|
11425
|
-
-
|
|
11426
|
-
|
|
11427
|
-
## Open Questions
|
|
11428
|
-
|
|
11429
|
-
-
|
|
11430
|
-
`;
|
|
11431
|
-
async function handlePrecompact(token, vaultRoot, now = Math.floor(Date.now() / 1000), tmpDir = osTmpdir()) {
|
|
11423
|
+
function handlePrecompact(token, _vaultRoot, now = Math.floor(Date.now() / 1000), tmpDir = osTmpdir()) {
|
|
11432
11424
|
const state = readState(token, tmpDir);
|
|
11433
11425
|
if (state.last_ts > 0 && now - state.last_ts < PRECOMPACT_RECENCY) {
|
|
11434
11426
|
return;
|
|
11435
11427
|
}
|
|
11436
|
-
|
|
11437
|
-
return;
|
|
11438
|
-
}
|
|
11439
|
-
const date = formatDate(now);
|
|
11440
|
-
let logsFolder = DEFAULT_LOGS_FOLDER;
|
|
11441
|
-
try {
|
|
11442
|
-
const config = await loadVaultConfig(vaultRoot);
|
|
11443
|
-
logsFolder = config.folders.logs;
|
|
11444
|
-
} catch {}
|
|
11445
|
-
const yyyy = formatYYYY(now);
|
|
11446
|
-
const mm = formatMM(now);
|
|
11447
|
-
const stubDir = join7(vaultRoot, logsFolder, yyyy, mm);
|
|
11448
|
-
const existingFiles = await readdir2(stubDir).catch(() => []);
|
|
11449
|
-
const prefix = `${date}-${token}-checkpoint-`;
|
|
11450
|
-
const maxNn = existingFiles.reduce((max, f2) => {
|
|
11451
|
-
if (!f2.startsWith(prefix) || !f2.endsWith(".md"))
|
|
11452
|
-
return max;
|
|
11453
|
-
const m3 = f2.match(/-checkpoint-(\d{2})\.md$/);
|
|
11454
|
-
return m3 ? Math.max(max, Number(m3[1])) : max;
|
|
11455
|
-
}, 0);
|
|
11456
|
-
const stubNn = String(maxNn + 1).padStart(2, "0");
|
|
11457
|
-
const stubFilename = `${date}-${token}-checkpoint-${stubNn}.md`;
|
|
11458
|
-
const stubPath = join7(stubDir, stubFilename);
|
|
11459
|
-
try {
|
|
11460
|
-
await mkdir4(stubDir, { recursive: true });
|
|
11461
|
-
await writeFile5(stubPath, PRECOMPACT_STUB_TEMPLATE(date, stubNn), "utf8");
|
|
11462
|
-
} catch (err) {
|
|
11463
|
-
process.stderr.write(`checkpoint: failed to write stub file ${stubPath}: ${err}
|
|
11464
|
-
`);
|
|
11465
|
-
return;
|
|
11466
|
-
}
|
|
11467
|
-
writeState(token, {
|
|
11468
|
-
count: 0,
|
|
11469
|
-
last_ts: state.last_ts,
|
|
11470
|
-
last_stop_nn: state.last_stop_nn,
|
|
11471
|
-
pending_stub: stubFilename
|
|
11472
|
-
}, tmpDir);
|
|
11428
|
+
writeState(token, { count: 0, last_ts: state.last_ts, last_stop_nn: state.last_stop_nn }, tmpDir);
|
|
11473
11429
|
}
|
|
11474
|
-
function handlePostcompact(token,
|
|
11430
|
+
function handlePostcompact(token, _vaultRoot, now = Math.floor(Date.now() / 1000), tmpDir = osTmpdir()) {
|
|
11475
11431
|
const state = readState(token, tmpDir);
|
|
11476
|
-
if (
|
|
11432
|
+
if (state.last_ts > 0 && now - state.last_ts < PRECOMPACT_RECENCY) {
|
|
11477
11433
|
writeState(token, { count: 0, last_ts: state.last_ts, last_stop_nn: state.last_stop_nn }, tmpDir);
|
|
11478
11434
|
return;
|
|
11479
11435
|
}
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
const stubNnNum = Number(stubNn);
|
|
11483
|
-
const { logsFolder } = loadVaultSettings(vaultRoot);
|
|
11484
|
-
const date = state.pending_stub.slice(0, 10);
|
|
11485
|
-
const yyyy = date.slice(0, 4);
|
|
11486
|
-
const mm = date.slice(5, 7);
|
|
11487
|
-
const dir = join7(vaultRoot, logsFolder, yyyy, mm);
|
|
11488
|
-
const prefix = `${date}-${token}-checkpoint-`;
|
|
11489
|
-
let predecessorNn = 0;
|
|
11490
|
-
try {
|
|
11491
|
-
for (const f2 of readdirSync(dir)) {
|
|
11492
|
-
if (!f2.startsWith(prefix) || !f2.endsWith(".md"))
|
|
11493
|
-
continue;
|
|
11494
|
-
const m3 = f2.match(/-checkpoint-(\d{2})\.md$/);
|
|
11495
|
-
if (m3) {
|
|
11496
|
-
const nn = Number(m3[1]);
|
|
11497
|
-
if (nn < stubNnNum)
|
|
11498
|
-
predecessorNn = Math.max(predecessorNn, nn);
|
|
11499
|
-
}
|
|
11500
|
-
}
|
|
11501
|
-
} catch {}
|
|
11502
|
-
const since = predecessorNn === 0 ? " since start" : ` since checkpoint-${String(predecessorNn).padStart(2, "0")}`;
|
|
11503
|
-
emitBlock(`fill-checkpoint: ${state.pending_stub}${since}`);
|
|
11504
|
-
writeState(token, { count: 0, last_ts: now, last_stop_nn: stubNn }, tmpDir);
|
|
11436
|
+
emitBlock(`auto-wrapup: ${token}`);
|
|
11437
|
+
writeState(token, { count: 0, last_ts: now, last_stop_nn: state.last_stop_nn }, tmpDir);
|
|
11505
11438
|
}
|
|
11506
11439
|
function postcompactFallback(token, vaultRoot, now = Math.floor(Date.now() / 1000), tmpDir = osTmpdir()) {
|
|
11507
|
-
|
|
11508
|
-
if (state.pending_stub) {
|
|
11509
|
-
handlePostcompact(token, vaultRoot, now, tmpDir);
|
|
11510
|
-
return;
|
|
11511
|
-
}
|
|
11512
|
-
const { logsFolder } = loadVaultSettings(vaultRoot);
|
|
11513
|
-
const date = formatDate(now);
|
|
11514
|
-
const yyyy = date.slice(0, 4);
|
|
11515
|
-
const mm = date.slice(5, 7);
|
|
11516
|
-
const dir = join7(vaultRoot, logsFolder, yyyy, mm);
|
|
11517
|
-
const prefix = `${date}-${token}-checkpoint-`;
|
|
11518
|
-
const stubs = [];
|
|
11519
|
-
const allNns = [];
|
|
11520
|
-
try {
|
|
11521
|
-
for (const f2 of readdirSync(dir)) {
|
|
11522
|
-
if (!f2.startsWith(prefix) || !f2.endsWith(".md"))
|
|
11523
|
-
continue;
|
|
11524
|
-
const m3 = f2.match(/-checkpoint-(\d{2})\.md$/);
|
|
11525
|
-
if (!m3)
|
|
11526
|
-
continue;
|
|
11527
|
-
allNns.push(Number(m3[1]));
|
|
11528
|
-
const content = readFileSync(join7(dir, f2), "utf8");
|
|
11529
|
-
if (/^trigger:\s*precompact/m.test(content) && !/^merged:\s*true/m.test(content)) {
|
|
11530
|
-
stubs.push(f2);
|
|
11531
|
-
}
|
|
11532
|
-
}
|
|
11533
|
-
} catch {}
|
|
11534
|
-
if (stubs.length === 0) {
|
|
11535
|
-
writeState(token, { count: 0, last_ts: state.last_ts, last_stop_nn: state.last_stop_nn }, tmpDir);
|
|
11536
|
-
return;
|
|
11537
|
-
}
|
|
11538
|
-
stubs.sort();
|
|
11539
|
-
const stubFilename = stubs[stubs.length - 1];
|
|
11540
|
-
const stubNnMatch = stubFilename.match(/-checkpoint-(\d{2})\.md$/);
|
|
11541
|
-
const stubNn = stubNnMatch?.[1] ?? "01";
|
|
11542
|
-
const stubNnNum = Number(stubNn);
|
|
11543
|
-
const predecessorNn = allNns.filter((n) => n < stubNnNum).reduce((max, n) => Math.max(max, n), 0);
|
|
11544
|
-
const since = predecessorNn === 0 ? " since start" : ` since checkpoint-${String(predecessorNn).padStart(2, "0")}`;
|
|
11545
|
-
emitBlock(`fill-checkpoint: ${stubFilename}${since}`);
|
|
11546
|
-
writeState(token, { count: 0, last_ts: now, last_stop_nn: stubNn }, tmpDir);
|
|
11440
|
+
handlePostcompact(token, vaultRoot, now, tmpDir);
|
|
11547
11441
|
}
|
|
11548
11442
|
async function checkpointCommand(mode, token, vaultRoot) {
|
|
11549
11443
|
try {
|
|
@@ -11552,7 +11446,7 @@ async function checkpointCommand(mode, token, vaultRoot) {
|
|
|
11552
11446
|
handleStop(token, vaultRoot);
|
|
11553
11447
|
break;
|
|
11554
11448
|
case "precompact":
|
|
11555
|
-
|
|
11449
|
+
handlePrecompact(token, vaultRoot);
|
|
11556
11450
|
break;
|
|
11557
11451
|
case "postcompact":
|
|
11558
11452
|
postcompactFallback(token, vaultRoot);
|
|
@@ -11571,7 +11465,7 @@ async function checkpointCommand(mode, token, vaultRoot) {
|
|
|
11571
11465
|
}
|
|
11572
11466
|
|
|
11573
11467
|
// src/internal/migrate.ts
|
|
11574
|
-
import { readFile as readFile5, readdir as
|
|
11468
|
+
import { readFile as readFile5, readdir as readdir2, writeFile as writeFile5 } from "node:fs/promises";
|
|
11575
11469
|
import { join as join8 } from "node:path";
|
|
11576
11470
|
init_dist();
|
|
11577
11471
|
function parseFrontmatterWithRest(rawText) {
|
|
@@ -11600,7 +11494,7 @@ function parseFrontmatterWithRest(rawText) {
|
|
|
11600
11494
|
}
|
|
11601
11495
|
async function listMdFiles(dir) {
|
|
11602
11496
|
try {
|
|
11603
|
-
const entries = await
|
|
11497
|
+
const entries = await readdir2(dir);
|
|
11604
11498
|
return entries.filter((e2) => e2.endsWith(".md"));
|
|
11605
11499
|
} catch {
|
|
11606
11500
|
return [];
|
|
@@ -11612,7 +11506,7 @@ async function runBackfillRecapped(logsFolder) {
|
|
|
11612
11506
|
let skipped = 0;
|
|
11613
11507
|
let yearDirs = [];
|
|
11614
11508
|
try {
|
|
11615
|
-
yearDirs = await
|
|
11509
|
+
yearDirs = await readdir2(logsFolder);
|
|
11616
11510
|
} catch {
|
|
11617
11511
|
return { backfilled: 0, skipped: 0 };
|
|
11618
11512
|
}
|
|
@@ -11620,7 +11514,7 @@ async function runBackfillRecapped(logsFolder) {
|
|
|
11620
11514
|
const yearPath = join8(logsFolder, yearDir);
|
|
11621
11515
|
let monthDirs = [];
|
|
11622
11516
|
try {
|
|
11623
|
-
monthDirs = await
|
|
11517
|
+
monthDirs = await readdir2(yearPath);
|
|
11624
11518
|
} catch {
|
|
11625
11519
|
continue;
|
|
11626
11520
|
}
|
|
@@ -11650,7 +11544,7 @@ async function runBackfillRecapped(logsFolder) {
|
|
|
11650
11544
|
const updatedContent = `---
|
|
11651
11545
|
${updatedFm}---
|
|
11652
11546
|
${rest}`;
|
|
11653
|
-
await
|
|
11547
|
+
await writeFile5(fpath, updatedContent, "utf8");
|
|
11654
11548
|
backfilled++;
|
|
11655
11549
|
} catch (error) {
|
|
11656
11550
|
process.stderr.write(`migrate: error processing ${fname}: ${error}
|
|
@@ -11683,7 +11577,7 @@ async function migrateCommand(migrationName) {
|
|
|
11683
11577
|
|
|
11684
11578
|
// src/internal/orphan-scan.ts
|
|
11685
11579
|
init_dist();
|
|
11686
|
-
import { readFile as readFile6, readdir as
|
|
11580
|
+
import { readFile as readFile6, readdir as readdir3 } from "node:fs/promises";
|
|
11687
11581
|
import { join as join9 } from "node:path";
|
|
11688
11582
|
function parseFrontmatter(rawText) {
|
|
11689
11583
|
const text = rawText.replace(/\r\n/g, `
|
|
@@ -11712,7 +11606,7 @@ function getMonthParts(now = new Date) {
|
|
|
11712
11606
|
}
|
|
11713
11607
|
async function listMdFiles2(dir) {
|
|
11714
11608
|
try {
|
|
11715
|
-
const entries = await
|
|
11609
|
+
const entries = await readdir3(dir);
|
|
11716
11610
|
return entries.filter((e2) => e2.endsWith(".md"));
|
|
11717
11611
|
} catch {
|
|
11718
11612
|
return [];
|
|
@@ -11820,7 +11714,7 @@ async function qmdReindexCommand(vaultRoot) {
|
|
|
11820
11714
|
// src/internal/register-hooks.ts
|
|
11821
11715
|
init_dist3();
|
|
11822
11716
|
init_dist();
|
|
11823
|
-
import { mkdir as
|
|
11717
|
+
import { mkdir as mkdir4, readFile as readFile7, rename as rename5, writeFile as writeFile6 } from "node:fs/promises";
|
|
11824
11718
|
import { homedir as homedir4 } from "node:os";
|
|
11825
11719
|
import { dirname as dirname4, join as join10 } from "node:path";
|
|
11826
11720
|
var HOOK_COMMANDS2 = {
|
|
@@ -11850,9 +11744,9 @@ async function readSettings2(settingsPath) {
|
|
|
11850
11744
|
}
|
|
11851
11745
|
}
|
|
11852
11746
|
async function writeSettings2(settingsPath, settings) {
|
|
11853
|
-
await
|
|
11747
|
+
await mkdir4(dirname4(settingsPath), { recursive: true });
|
|
11854
11748
|
const tmpPath = `${settingsPath}.tmp`;
|
|
11855
|
-
await
|
|
11749
|
+
await writeFile6(tmpPath, JSON.stringify(settings, null, 4), "utf8");
|
|
11856
11750
|
await rename5(tmpPath, settingsPath);
|
|
11857
11751
|
}
|
|
11858
11752
|
function checkHookPresence2(groups, targetCmd) {
|
|
@@ -11981,7 +11875,7 @@ ${ONEBRAIN_MARKER2}
|
|
|
11981
11875
|
${PATH_EXPORT2}
|
|
11982
11876
|
`;
|
|
11983
11877
|
const tmpPath = `${profilePath}.tmp`;
|
|
11984
|
-
await
|
|
11878
|
+
await writeFile6(tmpPath, updated, "utf8");
|
|
11985
11879
|
await rename5(tmpPath, profilePath);
|
|
11986
11880
|
}
|
|
11987
11881
|
async function runRegisterHooks2(opts = {}) {
|
|
@@ -12240,15 +12134,15 @@ async function sessionInitCommand(vaultRoot) {
|
|
|
12240
12134
|
init_dist3();
|
|
12241
12135
|
init_dist();
|
|
12242
12136
|
import {
|
|
12243
|
-
mkdir as
|
|
12137
|
+
mkdir as mkdir5,
|
|
12244
12138
|
mkdtemp as mkdtemp2,
|
|
12245
12139
|
readFile as readFile8,
|
|
12246
|
-
readdir as
|
|
12140
|
+
readdir as readdir4,
|
|
12247
12141
|
rename as rename6,
|
|
12248
12142
|
rm as rm2,
|
|
12249
12143
|
stat as stat4,
|
|
12250
12144
|
unlink as unlink3,
|
|
12251
|
-
writeFile as
|
|
12145
|
+
writeFile as writeFile7
|
|
12252
12146
|
} from "node:fs/promises";
|
|
12253
12147
|
import { homedir as homedir5, tmpdir as tmpdir2 } from "node:os";
|
|
12254
12148
|
import { dirname as dirname5, join as join12, relative as relative2 } from "node:path";
|
|
@@ -12273,7 +12167,7 @@ async function downloadTarball2(branch, fetchFn) {
|
|
|
12273
12167
|
}
|
|
12274
12168
|
async function extractTarball2(tarball, destDir) {
|
|
12275
12169
|
const tarPath = join12(destDir, "bundle.tar.gz");
|
|
12276
|
-
await
|
|
12170
|
+
await writeFile7(tarPath, Buffer.from(tarball));
|
|
12277
12171
|
const proc = Bun.spawn(["tar", "-xzf", tarPath, "-C", destDir], {
|
|
12278
12172
|
stdout: "pipe",
|
|
12279
12173
|
stderr: "pipe"
|
|
@@ -12284,7 +12178,7 @@ async function extractTarball2(tarball, destDir) {
|
|
|
12284
12178
|
throw new Error(`tar extraction failed (exit ${exitCode}): ${errText.trim()}`);
|
|
12285
12179
|
}
|
|
12286
12180
|
await unlink3(tarPath);
|
|
12287
|
-
const entries = await
|
|
12181
|
+
const entries = await readdir4(destDir);
|
|
12288
12182
|
const topLevel = entries.find((e2) => e2 !== "bundle.tar.gz");
|
|
12289
12183
|
if (!topLevel) {
|
|
12290
12184
|
throw new Error("Extracted tarball contains no top-level directory");
|
|
@@ -12298,7 +12192,7 @@ async function listFilesRecursive2(dir) {
|
|
|
12298
12192
|
const current = queue.pop();
|
|
12299
12193
|
let entries;
|
|
12300
12194
|
try {
|
|
12301
|
-
entries = await
|
|
12195
|
+
entries = await readdir4(current);
|
|
12302
12196
|
} catch {
|
|
12303
12197
|
continue;
|
|
12304
12198
|
}
|
|
@@ -12322,7 +12216,7 @@ async function listFilesRecursive2(dir) {
|
|
|
12322
12216
|
async function syncPluginFiles2(extractedDir, vaultRoot, unlinkFn = unlink3) {
|
|
12323
12217
|
const sourcePlugin = join12(extractedDir, ".claude", "plugins", "onebrain");
|
|
12324
12218
|
const destPlugin = join12(vaultRoot, ".claude", "plugins", "onebrain");
|
|
12325
|
-
await
|
|
12219
|
+
await mkdir5(destPlugin, { recursive: true });
|
|
12326
12220
|
const sourceFiles = await listFilesRecursive2(sourcePlugin);
|
|
12327
12221
|
const sourceRelSet = new Set(sourceFiles.map((f2) => relative2(sourcePlugin, f2)));
|
|
12328
12222
|
const destFiles = await listFilesRecursive2(destPlugin);
|
|
@@ -12337,9 +12231,9 @@ async function syncPluginFiles2(extractedDir, vaultRoot, unlinkFn = unlink3) {
|
|
|
12337
12231
|
for (const srcPath of sourceFiles) {
|
|
12338
12232
|
const rel = relative2(sourcePlugin, srcPath);
|
|
12339
12233
|
const destPath = join12(destPlugin, rel);
|
|
12340
|
-
await
|
|
12234
|
+
await mkdir5(dirname5(destPath), { recursive: true });
|
|
12341
12235
|
const content = await readFile8(srcPath);
|
|
12342
|
-
await
|
|
12236
|
+
await writeFile7(destPath, content);
|
|
12343
12237
|
filesAdded++;
|
|
12344
12238
|
}
|
|
12345
12239
|
let filesRemoved = 0;
|
|
@@ -12359,7 +12253,7 @@ async function copyRootDocs2(extractedDir, vaultRoot) {
|
|
|
12359
12253
|
const destPath = join12(vaultRoot, doc);
|
|
12360
12254
|
try {
|
|
12361
12255
|
const content = await readFile8(srcPath);
|
|
12362
|
-
await
|
|
12256
|
+
await writeFile7(destPath, content);
|
|
12363
12257
|
} catch {}
|
|
12364
12258
|
}
|
|
12365
12259
|
}
|
|
@@ -12376,7 +12270,7 @@ async function mergeHarnessFile2(extractedDir, vaultRoot, filename) {
|
|
|
12376
12270
|
try {
|
|
12377
12271
|
vaultText = await readFile8(destPath, "utf8");
|
|
12378
12272
|
} catch {
|
|
12379
|
-
await
|
|
12273
|
+
await writeFile7(destPath, repoText, "utf8");
|
|
12380
12274
|
return repoText.split(`
|
|
12381
12275
|
`).filter((l2) => l2.startsWith("@")).length;
|
|
12382
12276
|
}
|
|
@@ -12397,7 +12291,7 @@ async function mergeHarnessFile2(extractedDir, vaultRoot, filename) {
|
|
|
12397
12291
|
}
|
|
12398
12292
|
const merged = vaultLines.join(`
|
|
12399
12293
|
`);
|
|
12400
|
-
await
|
|
12294
|
+
await writeFile7(destPath, merged, "utf8");
|
|
12401
12295
|
return newImports.length;
|
|
12402
12296
|
}
|
|
12403
12297
|
async function mergeHarnessFiles2(extractedDir, vaultRoot) {
|
|
@@ -12422,7 +12316,7 @@ async function updateVaultYml2(vaultRoot, version, updateChannel) {
|
|
|
12422
12316
|
raw.update_channel = updateChannel;
|
|
12423
12317
|
const updated = $stringify(raw, { lineWidth: 0 });
|
|
12424
12318
|
const tmpPath = `${vaultYmlPath}.tmp`;
|
|
12425
|
-
await
|
|
12319
|
+
await writeFile7(tmpPath, updated, "utf8");
|
|
12426
12320
|
await rename6(tmpPath, vaultYmlPath);
|
|
12427
12321
|
}
|
|
12428
12322
|
async function readPluginVersion2(vaultRoot) {
|
|
@@ -12492,7 +12386,7 @@ async function pinToVault2(vaultRoot, installedPluginsPath, installedPluginsCach
|
|
|
12492
12386
|
return { skipped: false };
|
|
12493
12387
|
}
|
|
12494
12388
|
const tmpPath = `${installedPluginsPath}.tmp`;
|
|
12495
|
-
await
|
|
12389
|
+
await writeFile7(tmpPath, JSON.stringify(data, null, 4), "utf8");
|
|
12496
12390
|
await rename6(tmpPath, installedPluginsPath);
|
|
12497
12391
|
return { skipped: false };
|
|
12498
12392
|
}
|
|
@@ -12523,7 +12417,7 @@ async function cleanPluginCache2(installedPluginsPath, installedPluginsCacheDir)
|
|
|
12523
12417
|
} catch {}
|
|
12524
12418
|
if (onebrainDirs.length === 0) {
|
|
12525
12419
|
try {
|
|
12526
|
-
const marketplaceDirs = await
|
|
12420
|
+
const marketplaceDirs = await readdir4(cacheDir);
|
|
12527
12421
|
for (const mp of marketplaceDirs) {
|
|
12528
12422
|
const candidate = join12(cacheDir, mp, "onebrain");
|
|
12529
12423
|
try {
|
|
@@ -12539,7 +12433,7 @@ async function cleanPluginCache2(installedPluginsPath, installedPluginsCacheDir)
|
|
|
12539
12433
|
for (const pluginDir of onebrainDirs) {
|
|
12540
12434
|
let versionDirs;
|
|
12541
12435
|
try {
|
|
12542
|
-
versionDirs = await
|
|
12436
|
+
versionDirs = await readdir4(pluginDir);
|
|
12543
12437
|
} catch {
|
|
12544
12438
|
continue;
|
|
12545
12439
|
}
|
|
@@ -12726,7 +12620,7 @@ async function vaultSyncCommand2(vaultRoot, opts = {}) {
|
|
|
12726
12620
|
}
|
|
12727
12621
|
|
|
12728
12622
|
// src/index.ts
|
|
12729
|
-
var VERSION = "2.0.
|
|
12623
|
+
var VERSION = "2.0.7";
|
|
12730
12624
|
var RELEASE_DATE = "2026-04-26";
|
|
12731
12625
|
if (process.platform === "win32") {
|
|
12732
12626
|
process.stdout.setDefaultEncoding("utf8");
|
|
@@ -12738,6 +12632,19 @@ if (process.argv.slice(2).length === 0) {
|
|
|
12738
12632
|
console.log("Run `onebrain help` for available commands.");
|
|
12739
12633
|
process.exit(0);
|
|
12740
12634
|
}
|
|
12635
|
+
function findVaultRoot(startDir) {
|
|
12636
|
+
if (!startDir)
|
|
12637
|
+
return process.cwd();
|
|
12638
|
+
let dir = startDir;
|
|
12639
|
+
while (true) {
|
|
12640
|
+
if (existsSync(join13(dir, "vault.yml")))
|
|
12641
|
+
return dir;
|
|
12642
|
+
const parent = dirname6(dir);
|
|
12643
|
+
if (parent === dir)
|
|
12644
|
+
return startDir;
|
|
12645
|
+
dir = parent;
|
|
12646
|
+
}
|
|
12647
|
+
}
|
|
12741
12648
|
var program2 = new Command;
|
|
12742
12649
|
program2.name("onebrain").description("OneBrain CLI \u2014 personal AI OS for Obsidian").version(VERSION_STRING, "-v, --version");
|
|
12743
12650
|
program2.command("init").description("Initialize a new OneBrain vault").option("--vault-dir <path>", "vault root directory (default: cwd)").option("--harness <harness>", "harness type: claude-code | gemini | direct").option("--force", "overwrite existing vault.yml without prompting").action(async (opts) => {
|
|
@@ -12747,29 +12654,31 @@ program2.command("init").description("Initialize a new OneBrain vault").option("
|
|
|
12747
12654
|
force: opts.force
|
|
12748
12655
|
});
|
|
12749
12656
|
});
|
|
12750
|
-
program2.command("update").description("Update OneBrain plugin files from GitHub").option("--check", "show what would change and exit without making changes").option("--channel <channel>", "update channel: stable | next").action(async (opts) => {
|
|
12657
|
+
program2.command("update").description("Update OneBrain plugin files from GitHub").option("--check", "show what would change and exit without making changes").option("--channel <channel>", "update channel: stable | next").option("--vault-dir <path>", "vault root directory (default: auto-detect from cwd)").action(async (opts) => {
|
|
12751
12658
|
await updateCommand({
|
|
12659
|
+
vaultDir: opts.vaultDir ?? findVaultRoot(process.cwd()),
|
|
12752
12660
|
check: opts.check,
|
|
12753
12661
|
channel: opts.channel
|
|
12754
12662
|
});
|
|
12755
12663
|
});
|
|
12756
12664
|
program2.command("doctor").description("Run vault health checks and report issues").action(async () => {
|
|
12757
|
-
const vaultRoot = process.cwd();
|
|
12665
|
+
const vaultRoot = findVaultRoot(process.cwd());
|
|
12758
12666
|
await doctorCommand({ vaultDir: vaultRoot, binaryVersion: VERSION });
|
|
12759
12667
|
});
|
|
12760
12668
|
program2.command("help").description("Show this help message").action(() => {
|
|
12761
12669
|
program2.help();
|
|
12762
12670
|
});
|
|
12763
|
-
program2.command("session-init", { hidden: true }).description("Emit session token and datetime (called by Claude Code hook)").action(async () => {
|
|
12764
|
-
const vaultRoot = process.cwd();
|
|
12671
|
+
program2.command("session-init", { hidden: true }).description("Emit session token and datetime (called by Claude Code hook)").option("--vault-dir <path>", "vault root directory (default: auto-detect from cwd)").action(async (opts) => {
|
|
12672
|
+
const vaultRoot = opts.vaultDir ?? findVaultRoot(process.cwd());
|
|
12765
12673
|
await sessionInitCommand(vaultRoot);
|
|
12766
12674
|
});
|
|
12767
12675
|
program2.command("orphan-scan", { hidden: true }).description("Scan for orphaned checkpoint files in logs folder").argument("<logs_folder>", "path to logs folder").argument("<session_token>", "current session token to exclude").action(async (logsFolder, sessionToken) => {
|
|
12768
12676
|
await orphanScanCommand(logsFolder, sessionToken);
|
|
12769
12677
|
});
|
|
12770
|
-
program2.command("checkpoint", { hidden: true }).description("Handle checkpoint lifecycle (stop/precompact/postcompact/reset)").argument("<mode>", "stop | precompact | postcompact | reset").action(async (mode) => {
|
|
12678
|
+
program2.command("checkpoint", { hidden: true }).description("Handle checkpoint lifecycle (stop/precompact/postcompact/reset)").argument("<mode>", "stop | precompact | postcompact | reset").option("--vault-dir <path>", "vault root directory (default: auto-detect from cwd)").action(async (mode, opts) => {
|
|
12771
12679
|
const token = await resolveSessionToken();
|
|
12772
|
-
|
|
12680
|
+
const vaultRoot = opts.vaultDir ?? findVaultRoot(process.cwd());
|
|
12681
|
+
await checkpointCommand(mode, token, vaultRoot);
|
|
12773
12682
|
});
|
|
12774
12683
|
program2.command("qmd-reindex", { hidden: true }).description("Trigger qmd index rebuild").action(async () => {
|
|
12775
12684
|
const vaultRoot = process.cwd();
|