@onebrain-ai/cli 2.1.11 → 2.1.13
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 -6
- package/dist/onebrain +119 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -111,20 +111,20 @@ The agent reaches outward FROM the vault to every surface where the work actuall
|
|
|
111
111
|
|
|
112
112
|
---
|
|
113
113
|
|
|
114
|
-
##
|
|
114
|
+
## Every Session Sharpens Both
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
OneBrain runs as a tight 3-step loop. Each cycle, both sides sharpen.
|
|
117
117
|
|
|
118
118
|
<p align="center">
|
|
119
119
|
<picture>
|
|
120
120
|
<source media="(prefers-color-scheme: dark)" srcset="assets/diagrams/coevo-loop-dark.svg">
|
|
121
|
-
<img alt="Co-Evolution loop — three nodes (01
|
|
121
|
+
<img alt="Co-Evolution loop — three nodes (01 CAPTURE at top, 02 EVOLVE at bottom-right, 03 WRAPUP at bottom-left) connected by curved arrows flowing clockwise" src="assets/diagrams/coevo-loop-light.svg" width="540">
|
|
122
122
|
</picture>
|
|
123
123
|
</p>
|
|
124
124
|
|
|
125
|
-
1. **
|
|
126
|
-
2. **
|
|
127
|
-
3. **
|
|
125
|
+
1. **Capture** — Talk to the agent in natural language. It writes, classifies, and links your thoughts in real time. → `/braindump` · `/capture` · `/bookmark`
|
|
126
|
+
2. **Evolve** — `/research` and `/distill` expand your knowledge. `/learn` deepens the agent. The loop tightens. → `/research` · `/distill` · `/learn`
|
|
127
|
+
3. **Wrapup** — `/wrapup` consolidates the session log. `/recap` promotes lessons to memory. → `/wrapup` · `/recap`
|
|
128
128
|
|
|
129
129
|
### Behind the loop
|
|
130
130
|
|
package/dist/onebrain
CHANGED
|
@@ -9521,7 +9521,7 @@ var init_lib = __esm(() => {
|
|
|
9521
9521
|
var require_package = __commonJS((exports, module) => {
|
|
9522
9522
|
module.exports = {
|
|
9523
9523
|
name: "@onebrain-ai/cli",
|
|
9524
|
-
version: "2.1.
|
|
9524
|
+
version: "2.1.13",
|
|
9525
9525
|
description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
|
|
9526
9526
|
keywords: [
|
|
9527
9527
|
"onebrain",
|
|
@@ -10280,7 +10280,11 @@ __export(exports_vault_sync, {
|
|
|
10280
10280
|
});
|
|
10281
10281
|
import { mkdir as mkdir2, mkdtemp, readFile as readFile2, readdir, rm, stat as stat3, unlink as unlink2, writeFile as writeFile3 } from "fs/promises";
|
|
10282
10282
|
import { homedir as homedir2, tmpdir } from "os";
|
|
10283
|
-
import { dirname as dirname2, join as join5, relative } from "path";
|
|
10283
|
+
import { dirname as dirname2, join as join5, sep as pathSep, relative, resolve as resolvePath } from "path";
|
|
10284
|
+
function normalizePath(p2) {
|
|
10285
|
+
const resolved = resolvePath(p2);
|
|
10286
|
+
return resolved.endsWith(pathSep) && resolved.length > pathSep.length ? resolved.slice(0, -pathSep.length) : resolved;
|
|
10287
|
+
}
|
|
10284
10288
|
function resolveBranch(updateChannel) {
|
|
10285
10289
|
return updateChannel === "stable" ? "main" : "next";
|
|
10286
10290
|
}
|
|
@@ -10484,9 +10488,12 @@ async function pinToVault(vaultRoot, installedPluginsPath, installedPluginsCache
|
|
|
10484
10488
|
return { skipped: true };
|
|
10485
10489
|
}
|
|
10486
10490
|
const vaultPluginDir = join5(vaultRoot, ".claude", "plugins", "onebrain");
|
|
10491
|
+
const normalizedVaultRoot = normalizePath(vaultRoot);
|
|
10492
|
+
const normalizedVaultPluginDir = normalizePath(vaultPluginDir);
|
|
10487
10493
|
const { version: pluginVersion, lastUpdated: pluginLastUpdated } = await readPluginMetadata(vaultRoot);
|
|
10488
10494
|
const updatedAt = pluginLastUpdated ?? now().toISOString();
|
|
10489
10495
|
const cacheDir = installedPluginsCacheDir ?? join5(dirname2(installedPluginsPath), "cache");
|
|
10496
|
+
const normalizedCacheDir = normalizePath(cacheDir);
|
|
10490
10497
|
const hasMarketplace = onebrainKeys.some((k2) => {
|
|
10491
10498
|
const entries = plugins[k2];
|
|
10492
10499
|
return entries.some((e2) => e2["source"] === "marketplace");
|
|
@@ -10525,22 +10532,28 @@ async function pinToVault(vaultRoot, installedPluginsPath, installedPluginsCache
|
|
|
10525
10532
|
for (const key of onebrainKeys) {
|
|
10526
10533
|
const entries = plugins[key];
|
|
10527
10534
|
for (const entry of entries) {
|
|
10528
|
-
const
|
|
10529
|
-
|
|
10535
|
+
const installPathRaw = entry["installPath"];
|
|
10536
|
+
const projectPathRaw = entry["projectPath"];
|
|
10537
|
+
const installPathBad = installPathRaw !== undefined && typeof installPathRaw !== "string";
|
|
10538
|
+
const projectPathBad = projectPathRaw !== undefined && typeof projectPathRaw !== "string";
|
|
10539
|
+
if (installPathBad || projectPathBad) {
|
|
10540
|
+
process.stderr.write(`vault-sync: pin warning: malformed entry \u2014 non-string installPath/projectPath in installed_plugins.json[${key}]
|
|
10541
|
+
`);
|
|
10530
10542
|
continue;
|
|
10531
10543
|
}
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10544
|
+
const installPath = typeof installPathRaw === "string" ? installPathRaw : undefined;
|
|
10545
|
+
const projectPath = typeof projectPathRaw === "string" ? projectPathRaw : undefined;
|
|
10546
|
+
const normalizedInstallPath = installPath !== undefined ? normalizePath(installPath) : undefined;
|
|
10547
|
+
const normalizedProjectPath = projectPath !== undefined ? normalizePath(projectPath) : undefined;
|
|
10548
|
+
const inCache = normalizedInstallPath !== undefined && (normalizedInstallPath === normalizedCacheDir || normalizedInstallPath.startsWith(`${normalizedCacheDir}${pathSep}`));
|
|
10549
|
+
const isThisVault = normalizedInstallPath === normalizedVaultPluginDir;
|
|
10550
|
+
const isThisProject = normalizedProjectPath === normalizedVaultRoot;
|
|
10551
|
+
if (!isThisVault && !inCache && !isThisProject) {
|
|
10552
|
+
continue;
|
|
10537
10553
|
}
|
|
10538
|
-
|
|
10539
|
-
if (inCache) {
|
|
10554
|
+
if (normalizedInstallPath !== normalizedVaultPluginDir) {
|
|
10540
10555
|
entry["installPath"] = vaultPluginDir;
|
|
10541
10556
|
changed = true;
|
|
10542
|
-
} else if (!isThisVault) {
|
|
10543
|
-
continue;
|
|
10544
10557
|
}
|
|
10545
10558
|
if (entry["version"] !== pluginVersion) {
|
|
10546
10559
|
entry["version"] = pluginVersion;
|
|
@@ -10845,7 +10858,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
|
10845
10858
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
10846
10859
|
function resolveBinaryVersion() {
|
|
10847
10860
|
if (true)
|
|
10848
|
-
return "2.1.
|
|
10861
|
+
return "2.1.13";
|
|
10849
10862
|
try {
|
|
10850
10863
|
const pkg = require_package();
|
|
10851
10864
|
return pkg.version ?? "dev";
|
|
@@ -12619,7 +12632,74 @@ function formatDatetime(date) {
|
|
|
12619
12632
|
const mm = String(date.getMinutes()).padStart(2, "0");
|
|
12620
12633
|
return `${dow} \xB7 ${day} ${mon} ${year} \xB7 ${hh}:${mm}`;
|
|
12621
12634
|
}
|
|
12622
|
-
|
|
12635
|
+
function commBasenameOf(raw) {
|
|
12636
|
+
return raw.trim().replace(/^.*[/\\]/, "").replace(/\.exe$/i, "");
|
|
12637
|
+
}
|
|
12638
|
+
var defaultProcLookup = (pid) => {
|
|
12639
|
+
if (process.platform === "win32")
|
|
12640
|
+
return null;
|
|
12641
|
+
let result;
|
|
12642
|
+
try {
|
|
12643
|
+
result = Bun.spawnSync(["ps", "-o", "ppid=,comm=", "-p", String(pid)], {
|
|
12644
|
+
stdout: "pipe",
|
|
12645
|
+
stderr: "pipe"
|
|
12646
|
+
});
|
|
12647
|
+
} catch (err) {
|
|
12648
|
+
const code = err?.code;
|
|
12649
|
+
process.stderr.write(`onebrain: ps spawn failed for pid ${pid} (${code ?? "unknown"})
|
|
12650
|
+
`);
|
|
12651
|
+
return null;
|
|
12652
|
+
}
|
|
12653
|
+
if (!result.success) {
|
|
12654
|
+
process.stderr.write(`onebrain: ps -p ${pid} exited ${result.exitCode}
|
|
12655
|
+
`);
|
|
12656
|
+
return null;
|
|
12657
|
+
}
|
|
12658
|
+
const out2 = new TextDecoder().decode(result.stdout).trim();
|
|
12659
|
+
if (!out2) {
|
|
12660
|
+
process.stderr.write(`onebrain: ps -p ${pid} returned empty output
|
|
12661
|
+
`);
|
|
12662
|
+
return null;
|
|
12663
|
+
}
|
|
12664
|
+
if (out2.includes(`
|
|
12665
|
+
`)) {
|
|
12666
|
+
process.stderr.write(`onebrain: ps -p ${pid} returned multi-line output: ${out2.replace(/\n/g, " | ").slice(0, 120)}
|
|
12667
|
+
`);
|
|
12668
|
+
return null;
|
|
12669
|
+
}
|
|
12670
|
+
const match = out2.match(/^\s*(\d+)\s+(.+)$/);
|
|
12671
|
+
if (!match) {
|
|
12672
|
+
process.stderr.write(`onebrain: ps -p ${pid} unparseable: ${out2.slice(0, 120)}
|
|
12673
|
+
`);
|
|
12674
|
+
return null;
|
|
12675
|
+
}
|
|
12676
|
+
const ppid = Number(match[1]);
|
|
12677
|
+
if (Number.isNaN(ppid))
|
|
12678
|
+
return null;
|
|
12679
|
+
return { ppid, commBasename: commBasenameOf(match[2] ?? "") };
|
|
12680
|
+
};
|
|
12681
|
+
function findClaudeAncestorPid(startPid, lookup = defaultProcLookup, maxDepth = 12) {
|
|
12682
|
+
let current = startPid;
|
|
12683
|
+
for (let i = 0;i < maxDepth; i++) {
|
|
12684
|
+
if (current <= 1)
|
|
12685
|
+
return null;
|
|
12686
|
+
const info = lookup(current);
|
|
12687
|
+
if (!info)
|
|
12688
|
+
return null;
|
|
12689
|
+
if (info.commBasename === "claude")
|
|
12690
|
+
return current;
|
|
12691
|
+
if (info.ppid <= 1) {
|
|
12692
|
+
process.stderr.write(`onebrain: walk-up reached init from pid ${startPid} without finding claude (last comm=${info.commBasename})
|
|
12693
|
+
`);
|
|
12694
|
+
return null;
|
|
12695
|
+
}
|
|
12696
|
+
current = info.ppid;
|
|
12697
|
+
}
|
|
12698
|
+
process.stderr.write(`onebrain: walk-up exhausted ${maxDepth} hops from pid ${startPid} without finding claude
|
|
12699
|
+
`);
|
|
12700
|
+
return null;
|
|
12701
|
+
}
|
|
12702
|
+
async function resolveSessionToken(tmpDir = osTmpdir2(), procLookup = defaultProcLookup) {
|
|
12623
12703
|
const wtSession = process.env["WT_SESSION"];
|
|
12624
12704
|
if (wtSession) {
|
|
12625
12705
|
const stripped = wtSession.replace(/[^a-zA-Z0-9]/g, "").slice(0, 8);
|
|
@@ -12638,6 +12718,13 @@ async function resolveSessionToken(tmpDir = osTmpdir2()) {
|
|
|
12638
12718
|
if (stripped.length > 0)
|
|
12639
12719
|
return stripped;
|
|
12640
12720
|
}
|
|
12721
|
+
const startPpid = process.ppid;
|
|
12722
|
+
if (startPpid !== undefined && startPpid > 1) {
|
|
12723
|
+
const claudePid = findClaudeAncestorPid(startPpid, procLookup);
|
|
12724
|
+
if (claudePid !== null && claudePid > 1) {
|
|
12725
|
+
return String(claudePid);
|
|
12726
|
+
}
|
|
12727
|
+
}
|
|
12641
12728
|
const today = new Date;
|
|
12642
12729
|
const yyyymmdd = [
|
|
12643
12730
|
today.getFullYear(),
|
|
@@ -12706,9 +12793,21 @@ async function cleanStaleStateFile(token, tmpDir) {
|
|
|
12706
12793
|
if (mtimeMs < processStartMs) {
|
|
12707
12794
|
try {
|
|
12708
12795
|
await unlink3(stateFile);
|
|
12709
|
-
} catch {
|
|
12796
|
+
} catch (err) {
|
|
12797
|
+
const code = err?.code;
|
|
12798
|
+
if (code !== "ENOENT") {
|
|
12799
|
+
process.stderr.write(`onebrain: cannot remove stale state file ${stateFile} (${code ?? "unknown"})
|
|
12800
|
+
`);
|
|
12801
|
+
}
|
|
12802
|
+
}
|
|
12710
12803
|
}
|
|
12711
|
-
} catch {
|
|
12804
|
+
} catch (err) {
|
|
12805
|
+
const code = err?.code;
|
|
12806
|
+
if (code && code !== "ENOENT") {
|
|
12807
|
+
process.stderr.write(`onebrain: cleanStaleStateFile failed (${code})
|
|
12808
|
+
`);
|
|
12809
|
+
}
|
|
12810
|
+
}
|
|
12712
12811
|
}
|
|
12713
12812
|
async function queryQmdUnembedded() {
|
|
12714
12813
|
try {
|
|
@@ -12739,13 +12838,13 @@ async function queryQmdUnembedded() {
|
|
|
12739
12838
|
return 0;
|
|
12740
12839
|
}
|
|
12741
12840
|
}
|
|
12742
|
-
async function runSessionInit(vaultRoot, tmpDir = osTmpdir2()) {
|
|
12841
|
+
async function runSessionInit(vaultRoot, tmpDir = osTmpdir2(), procLookup = defaultProcLookup) {
|
|
12743
12842
|
try {
|
|
12744
12843
|
await loadVaultConfig(vaultRoot);
|
|
12745
12844
|
} catch {
|
|
12746
12845
|
return { decision: "block", reason: "onebrain-init-required" };
|
|
12747
12846
|
}
|
|
12748
|
-
const sessionToken = await resolveSessionToken(tmpDir);
|
|
12847
|
+
const sessionToken = await resolveSessionToken(tmpDir, procLookup);
|
|
12749
12848
|
await cleanStaleStateFile(sessionToken, tmpDir);
|
|
12750
12849
|
const datetime = formatDatetime(new Date);
|
|
12751
12850
|
const qmdUnembedded = await queryQmdUnembedded();
|
|
@@ -12989,7 +13088,7 @@ function patchUtf8(stream) {
|
|
|
12989
13088
|
}
|
|
12990
13089
|
|
|
12991
13090
|
// src/index.ts
|
|
12992
|
-
var VERSION = "2.1.
|
|
13091
|
+
var VERSION = "2.1.13";
|
|
12993
13092
|
var RELEASE_DATE = "2026-05-06";
|
|
12994
13093
|
patchUtf8(process.stdout);
|
|
12995
13094
|
patchUtf8(process.stderr);
|