@onebrain-ai/cli 2.2.0 → 2.2.1
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 +110 -21
- package/package.json +1 -1
package/dist/onebrain
CHANGED
|
@@ -8909,7 +8909,7 @@ async function loadVaultConfig(vaultRoot) {
|
|
|
8909
8909
|
const file = Bun.file(vaultYmlPath);
|
|
8910
8910
|
const exists = await file.exists();
|
|
8911
8911
|
if (!exists) {
|
|
8912
|
-
throw new Error(
|
|
8912
|
+
throw new Error(`${VAULT_YML_NOT_FOUND_PREFIX}${vaultYmlPath}. Run onebrain init to set up this vault.`);
|
|
8913
8913
|
}
|
|
8914
8914
|
const text = await file.text();
|
|
8915
8915
|
const parsed = import_yaml.parse(text) ?? {};
|
|
@@ -8952,7 +8952,7 @@ async function loadVaultConfig(vaultRoot) {
|
|
|
8952
8952
|
}
|
|
8953
8953
|
return config;
|
|
8954
8954
|
}
|
|
8955
|
-
var import_yaml, DEFAULT_FOLDERS, DEFAULT_CHECKPOINT;
|
|
8955
|
+
var import_yaml, DEFAULT_FOLDERS, DEFAULT_CHECKPOINT, VAULT_YML_NOT_FOUND_PREFIX = "vault.yml not found at ";
|
|
8956
8956
|
var init_parser = __esm(() => {
|
|
8957
8957
|
import_yaml = __toESM(require_dist(), 1);
|
|
8958
8958
|
DEFAULT_FOLDERS = {
|
|
@@ -9545,7 +9545,9 @@ __export(exports_lib, {
|
|
|
9545
9545
|
checkOrphanCheckpoints: () => checkOrphanCheckpoints,
|
|
9546
9546
|
checkFolders: () => checkFolders,
|
|
9547
9547
|
checkClaudeSettings: () => checkClaudeSettings,
|
|
9548
|
-
atomicWrite: () => atomicWrite
|
|
9548
|
+
atomicWrite: () => atomicWrite,
|
|
9549
|
+
VAULT_YML_NOT_FOUND_PREFIX: () => VAULT_YML_NOT_FOUND_PREFIX,
|
|
9550
|
+
DEFAULT_CHECKPOINT: () => DEFAULT_CHECKPOINT
|
|
9549
9551
|
});
|
|
9550
9552
|
var init_lib = __esm(() => {
|
|
9551
9553
|
init_parser();
|
|
@@ -9558,7 +9560,7 @@ var init_lib = __esm(() => {
|
|
|
9558
9560
|
var require_package = __commonJS((exports, module) => {
|
|
9559
9561
|
module.exports = {
|
|
9560
9562
|
name: "@onebrain-ai/cli",
|
|
9561
|
-
version: "2.2.
|
|
9563
|
+
version: "2.2.1",
|
|
9562
9564
|
description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
|
|
9563
9565
|
keywords: [
|
|
9564
9566
|
"onebrain",
|
|
@@ -10989,7 +10991,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
|
10989
10991
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
10990
10992
|
function resolveBinaryVersion() {
|
|
10991
10993
|
if (true)
|
|
10992
|
-
return "2.2.
|
|
10994
|
+
return "2.2.1";
|
|
10993
10995
|
try {
|
|
10994
10996
|
const pkg = require_package();
|
|
10995
10997
|
return pkg.version ?? "dev";
|
|
@@ -11481,7 +11483,8 @@ async function runDoctor(opts = {}) {
|
|
|
11481
11483
|
agent: "05-agent",
|
|
11482
11484
|
archive: "06-archive",
|
|
11483
11485
|
logs: "07-logs"
|
|
11484
|
-
}
|
|
11486
|
+
},
|
|
11487
|
+
checkpoint: { ...DEFAULT_CHECKPOINT }
|
|
11485
11488
|
};
|
|
11486
11489
|
const sp1 = createStep("\uD83D\uDCCB", "vault.yml");
|
|
11487
11490
|
const vaultYmlResult = await checkVaultYmlFn(vaultDir);
|
|
@@ -12603,9 +12606,12 @@ async function migrateCommand(migrationName, cutoffDate, vaultDir) {
|
|
|
12603
12606
|
}
|
|
12604
12607
|
|
|
12605
12608
|
// src/commands/internal/orphan-scan.ts
|
|
12609
|
+
init_parser();
|
|
12606
12610
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
12607
|
-
import { readFile as readFile5, readdir as readdir4 } from "fs/promises";
|
|
12611
|
+
import { readFile as readFile5, readdir as readdir4, stat as stat6 } from "fs/promises";
|
|
12608
12612
|
import { join as join9 } from "path";
|
|
12613
|
+
var MIN_GUARD_MINUTES = 60;
|
|
12614
|
+
var DEFAULT_ACTIVE_SESSION_GUARD_MS = 60 * 60 * 1000;
|
|
12609
12615
|
function parseFrontmatter(rawText) {
|
|
12610
12616
|
const text = rawText.replace(/\r\n/g, `
|
|
12611
12617
|
`);
|
|
@@ -12639,6 +12645,61 @@ async function listMdFiles2(dir) {
|
|
|
12639
12645
|
return [];
|
|
12640
12646
|
}
|
|
12641
12647
|
}
|
|
12648
|
+
async function getActiveSessionGuardMs(vaultRoot) {
|
|
12649
|
+
try {
|
|
12650
|
+
const config = await loadVaultConfig(vaultRoot);
|
|
12651
|
+
const cpMinutes = config.checkpoint.minutes;
|
|
12652
|
+
if (typeof cpMinutes !== "number" || !Number.isFinite(cpMinutes) || cpMinutes <= 0) {
|
|
12653
|
+
return DEFAULT_ACTIVE_SESSION_GUARD_MS;
|
|
12654
|
+
}
|
|
12655
|
+
const minutes = Math.max(MIN_GUARD_MINUTES, 2 * cpMinutes);
|
|
12656
|
+
return minutes * 60 * 1000;
|
|
12657
|
+
} catch (err) {
|
|
12658
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12659
|
+
const isExpectedAbsence = msg.startsWith(VAULT_YML_NOT_FOUND_PREFIX);
|
|
12660
|
+
if (!isExpectedAbsence) {
|
|
12661
|
+
try {
|
|
12662
|
+
process.stderr.write(`onebrain orphan-scan: vault.yml unreadable, using ${MIN_GUARD_MINUTES}-min Active-Session Guard default (${msg})
|
|
12663
|
+
`);
|
|
12664
|
+
} catch {}
|
|
12665
|
+
}
|
|
12666
|
+
return DEFAULT_ACTIVE_SESSION_GUARD_MS;
|
|
12667
|
+
}
|
|
12668
|
+
}
|
|
12669
|
+
async function getMtimeMs(path) {
|
|
12670
|
+
try {
|
|
12671
|
+
const s = await stat6(path);
|
|
12672
|
+
if (typeof s.mtimeMs !== "number" || !Number.isFinite(s.mtimeMs))
|
|
12673
|
+
return null;
|
|
12674
|
+
return s.mtimeMs;
|
|
12675
|
+
} catch {
|
|
12676
|
+
return null;
|
|
12677
|
+
}
|
|
12678
|
+
}
|
|
12679
|
+
async function getNewestMtimeMs(filePaths) {
|
|
12680
|
+
if (filePaths.length === 0)
|
|
12681
|
+
return null;
|
|
12682
|
+
let newest = Number.NEGATIVE_INFINITY;
|
|
12683
|
+
for (const p2 of filePaths) {
|
|
12684
|
+
const m3 = await getMtimeMs(p2);
|
|
12685
|
+
if (m3 === null)
|
|
12686
|
+
return null;
|
|
12687
|
+
if (m3 > newest)
|
|
12688
|
+
newest = m3;
|
|
12689
|
+
}
|
|
12690
|
+
return Number.isFinite(newest) ? newest : null;
|
|
12691
|
+
}
|
|
12692
|
+
async function isGroupActiveOrAmbiguous(filePaths, nowMs, guardMs) {
|
|
12693
|
+
if (!Number.isFinite(guardMs) || guardMs <= 0)
|
|
12694
|
+
return true;
|
|
12695
|
+
const newest = await getNewestMtimeMs(filePaths);
|
|
12696
|
+
if (newest === null)
|
|
12697
|
+
return true;
|
|
12698
|
+
const ageMs = nowMs - newest;
|
|
12699
|
+
if (ageMs < 0)
|
|
12700
|
+
return true;
|
|
12701
|
+
return ageMs < guardMs;
|
|
12702
|
+
}
|
|
12642
12703
|
async function hasManualSessionLog(monthDir, date) {
|
|
12643
12704
|
const files = await listMdFiles2(monthDir);
|
|
12644
12705
|
const sessionLogs = files.filter((f2) => f2.startsWith(date) && f2.includes("-session-") && f2.endsWith(".md"));
|
|
@@ -12653,10 +12714,19 @@ async function hasManualSessionLog(monthDir, date) {
|
|
|
12653
12714
|
}
|
|
12654
12715
|
return false;
|
|
12655
12716
|
}
|
|
12656
|
-
async function
|
|
12717
|
+
async function collectCandidateGroupsForMonth(monthDir, currentToken, today) {
|
|
12718
|
+
const groups = new Map;
|
|
12657
12719
|
const files = await listMdFiles2(monthDir);
|
|
12658
12720
|
const checkpoints = files.filter((f2) => f2.includes("-checkpoint-") && f2.endsWith(".md"));
|
|
12659
|
-
|
|
12721
|
+
const manualLogCache = new Map;
|
|
12722
|
+
async function dateHasManualLog(date) {
|
|
12723
|
+
const cached = manualLogCache.get(date);
|
|
12724
|
+
if (cached !== undefined)
|
|
12725
|
+
return cached;
|
|
12726
|
+
const result = await hasManualSessionLog(monthDir, date);
|
|
12727
|
+
manualLogCache.set(date, result);
|
|
12728
|
+
return result;
|
|
12729
|
+
}
|
|
12660
12730
|
for (const fname of checkpoints) {
|
|
12661
12731
|
const dateMatch = fname.match(/^(\d{4}-\d{2}-\d{2})-/);
|
|
12662
12732
|
if (!dateMatch)
|
|
@@ -12673,32 +12743,51 @@ async function scanMonthDir(monthDir, currentToken, today, seenTokens) {
|
|
|
12673
12743
|
continue;
|
|
12674
12744
|
if (ftoken === currentToken)
|
|
12675
12745
|
continue;
|
|
12676
|
-
if (
|
|
12746
|
+
if (await dateHasManualLog(fdate))
|
|
12677
12747
|
continue;
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12748
|
+
const fpath = join9(monthDir, fname);
|
|
12749
|
+
const existing = groups.get(ftoken);
|
|
12750
|
+
if (existing)
|
|
12751
|
+
existing.push(fpath);
|
|
12752
|
+
else
|
|
12753
|
+
groups.set(ftoken, [fpath]);
|
|
12682
12754
|
}
|
|
12683
|
-
return
|
|
12755
|
+
return groups;
|
|
12684
12756
|
}
|
|
12685
|
-
async function runOrphanScan(logsFolder, sessionToken, now) {
|
|
12757
|
+
async function runOrphanScan(logsFolder, sessionToken, now, vaultRoot) {
|
|
12758
|
+
if (!vaultRoot) {
|
|
12759
|
+
throw new Error("runOrphanScan: vaultRoot is required and must be a non-empty path");
|
|
12760
|
+
}
|
|
12686
12761
|
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
12687
12762
|
const { thisYear, thisMonth, prevYear, prevMonth } = getMonthParts(now);
|
|
12688
12763
|
const monthDirs = [
|
|
12689
12764
|
{ year: thisYear, month: thisMonth },
|
|
12690
12765
|
{ year: prevYear, month: prevMonth }
|
|
12691
12766
|
];
|
|
12692
|
-
const
|
|
12693
|
-
let totalOrphans = 0;
|
|
12767
|
+
const allGroups = new Map;
|
|
12694
12768
|
for (const { year, month } of monthDirs) {
|
|
12695
12769
|
const monthDir = join9(logsFolder, year, month);
|
|
12696
|
-
|
|
12770
|
+
const monthGroups = await collectCandidateGroupsForMonth(monthDir, sessionToken, today);
|
|
12771
|
+
for (const [token, files] of monthGroups) {
|
|
12772
|
+
const existing = allGroups.get(token);
|
|
12773
|
+
if (existing)
|
|
12774
|
+
existing.push(...files);
|
|
12775
|
+
else
|
|
12776
|
+
allGroups.set(token, [...files]);
|
|
12777
|
+
}
|
|
12778
|
+
}
|
|
12779
|
+
const guardMs = await getActiveSessionGuardMs(vaultRoot);
|
|
12780
|
+
const nowMs = now.getTime();
|
|
12781
|
+
let totalOrphans = 0;
|
|
12782
|
+
for (const [, files] of allGroups) {
|
|
12783
|
+
if (await isGroupActiveOrAmbiguous(files, nowMs, guardMs))
|
|
12784
|
+
continue;
|
|
12785
|
+
totalOrphans++;
|
|
12697
12786
|
}
|
|
12698
12787
|
return { orphan_count: totalOrphans };
|
|
12699
12788
|
}
|
|
12700
12789
|
async function orphanScanCommand(logsFolder, sessionToken) {
|
|
12701
|
-
const result = await runOrphanScan(logsFolder, sessionToken, new Date);
|
|
12790
|
+
const result = await runOrphanScan(logsFolder, sessionToken, new Date, process.cwd());
|
|
12702
12791
|
process.stdout.write(`${JSON.stringify(result)}
|
|
12703
12792
|
`);
|
|
12704
12793
|
}
|
|
@@ -13220,7 +13309,7 @@ function patchUtf8(stream) {
|
|
|
13220
13309
|
}
|
|
13221
13310
|
|
|
13222
13311
|
// src/index.ts
|
|
13223
|
-
var VERSION = "2.2.
|
|
13312
|
+
var VERSION = "2.2.1";
|
|
13224
13313
|
var RELEASE_DATE = "2026-05-07";
|
|
13225
13314
|
patchUtf8(process.stdout);
|
|
13226
13315
|
patchUtf8(process.stderr);
|