@onebrain-ai/cli 2.2.3 → 2.2.5
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 +36 -18
- package/dist/onebrain +128 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
25
|
<p align="center">
|
|
26
|
-
<strong>Your personal AI OS</strong> — persistent memory,
|
|
26
|
+
<strong>Your personal AI OS</strong> — persistent memory, 25+ skills, and a full local stack<br>
|
|
27
27
|
(Claude Code + Obsidian + tmux + Telegram), entirely on your own machine.
|
|
28
28
|
</p>
|
|
29
29
|
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
## What is OneBrain?
|
|
37
37
|
|
|
38
|
-
OneBrain is an AI operating system layer built on top of Obsidian. It gives your AI agent persistent memory, a structured knowledge vault, and
|
|
38
|
+
OneBrain is an AI operating system layer built on top of Obsidian. It gives your AI agent persistent memory, a structured knowledge vault, and 25+ pre-built skills — so every session picks up exactly where the last one left off.
|
|
39
39
|
|
|
40
40
|
Unlike chat-based AI tools, OneBrain lives in plain Markdown files you own forever. No cloud sync required. No proprietary format. Just your agent, your vault, your data.
|
|
41
41
|
|
|
@@ -70,7 +70,7 @@ OneBrain doesn't compete with Claude Code, Gemini CLI, or any other AI harness
|
|
|
70
70
|
|
|
71
71
|
| # | Layer | Role | What lives here |
|
|
72
72
|
|---|---|---|---|
|
|
73
|
-
| 01 | **OneBrain** | OS layer (plugin + CLI) |
|
|
73
|
+
| 01 | **OneBrain** | OS layer (plugin + CLI) | 25+ skills · lifecycle hooks · vault sync · indexing · checkpoints · harness routing |
|
|
74
74
|
| 02 | **Harness** | Agentic runtime | Bring your own — Claude Code · Gemini CLI · Codex · Qwen · ... |
|
|
75
75
|
| 03 | **LLM** | Intelligence source | Local (mlx, ollama) · cloud (claude, gemini, gpt) · raw API |
|
|
76
76
|
| 04 | **Obsidian Vault** | Source of truth | Plain Markdown — notes, memory, decisions, knowledge graph |
|
|
@@ -84,7 +84,7 @@ A great harness already knows how to talk to an LLM, edit files, and run shell c
|
|
|
84
84
|
| | What OneBrain adds | Why it matters |
|
|
85
85
|
|---|---|---|
|
|
86
86
|
| 🧠 | **Memory** — Identity, preferences, decisions, project state — promoted across four tiers as it earns trust | The harness alone starts every session from zero. OneBrain doesn't. |
|
|
87
|
-
| ⚡ | **Skills** —
|
|
87
|
+
| ⚡ | **Skills** — 25+ vault-aware verbs (`/braindump`, `/research`, `/distill`, `/learn`, `/wrapup`, …) | Pre-built workflows the harness would otherwise need you to script every time. |
|
|
88
88
|
| 🎯 | **Calibration** — Every correction, every preference, every learned habit tunes the agent to *you* | The longer you use it, the sharper it gets — your vault is the training data. |
|
|
89
89
|
| 🔀 | **Continuity** — Context lives in the vault, not the harness | Switch from Claude Code to Gemini CLI to Codex. Same memory. Same skills. Same agent. |
|
|
90
90
|
|
|
@@ -210,7 +210,7 @@ OneBrain doesn't just store markdown. Every feature exists to make you and the a
|
|
|
210
210
|
|---|---|---|
|
|
211
211
|
| 🧠 | **Persistent Memory** | Remembers your name, goals, preferences, and decisions across every session |
|
|
212
212
|
| 🖥️ | **Personal AI OS** | Full local stack: Claude Code + Obsidian + tmux + Telegram — no cloud infra needed |
|
|
213
|
-
| ⚡ | **
|
|
213
|
+
| ⚡ | **25+ Skills** | Braindump, research, consolidate, bookmark, import files, daily briefing, and more |
|
|
214
214
|
| 📂 | **Vault-native Markdown** | Plain Markdown, no lock-in. Your data stays yours forever |
|
|
215
215
|
| 🔀 | **Multi-Harness OS** | Switch between Claude Code, Gemini CLI, Codex, Qwen, or BYO LLM — context never breaks. [See architecture ↑](#the-harness-os-architecture) |
|
|
216
216
|
| 🔌 | **Zero Config** | Clone, open in Obsidian, run `/onboarding`. Ready in under 2 minutes |
|
|
@@ -340,37 +340,55 @@ Same vault. Same skills. Same memory. The LLM swaps; OneBrain doesn't notice.
|
|
|
340
340
|
|
|
341
341
|
<a id="commands"></a>
|
|
342
342
|
|
|
343
|
-
## 📋
|
|
343
|
+
## 📋 25+ Commands
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
Skills are organized by workflow phase. **Gemini CLI users:** prepend the `onebrain:` namespace, e.g. `/onebrain:braindump` instead of `/braindump` (avoids collisions with Gemini built-in commands like `/help` and `/tasks`).
|
|
346
|
+
|
|
347
|
+
### 📥 INPUT — Capture & ingest
|
|
346
348
|
|
|
347
349
|
| Command | What it does |
|
|
348
350
|
|---------|-------------|
|
|
349
|
-
| `/onboarding` | First-run setup — run this first |
|
|
351
|
+
| `/onboarding` | First-run setup — run this first · *first run only* |
|
|
350
352
|
| `/braindump` | Dump everything on your mind — it gets classified and filed |
|
|
351
353
|
| `/capture` | Quick note with auto-linking to related notes |
|
|
352
354
|
| `/bookmark [url]` | Save a URL with AI-generated name, description, and category to Bookmarks.md |
|
|
353
|
-
| `/consolidate` | Process inbox into permanent knowledge |
|
|
354
|
-
| `/connect` | Find connections between notes, suggest wikilinks |
|
|
355
|
-
| `/research [topic]` | Web research → structured note in your vault |
|
|
356
355
|
| `/summarize [url]` | Fetch a URL and save a deep summary note |
|
|
357
356
|
| `/import [path]` | Import local files (PDF, Word, images, scripts) into vault notes |
|
|
358
357
|
| `/reading-notes` | Turn a book or article into structured notes |
|
|
358
|
+
| `/research [topic]` | Web research → structured note in your vault |
|
|
359
|
+
|
|
360
|
+
### ⚙️ PROCESS — Synthesize & organize
|
|
361
|
+
|
|
362
|
+
| Command | What it does |
|
|
363
|
+
|---------|-------------|
|
|
364
|
+
| `/consolidate` | Process inbox into permanent knowledge |
|
|
365
|
+
| `/distill [topic]` | Crystallize a completed topic thread into a permanent knowledge note in `03-knowledge/` |
|
|
366
|
+
| `/connect` | Find connections between notes, suggest wikilinks |
|
|
367
|
+
| `/recap` | Cross-session synthesis — batch-promote recurring insights from session logs into `memory/` files (does NOT write to MEMORY.md) |
|
|
359
368
|
| `/weekly` | Review the week, surface patterns, set intentions |
|
|
360
369
|
| `/daily` | Daily briefing — surfaces tasks and last session context, then saves your focus as a daily note |
|
|
361
|
-
| `/
|
|
362
|
-
|
|
370
|
+
| `/learn` | Teach the agent something — facts about your world or behavioral preferences |
|
|
371
|
+
|
|
372
|
+
### 🔍 RECALL — Retrieve & navigate
|
|
373
|
+
|
|
374
|
+
| Command | What it does |
|
|
375
|
+
|---------|-------------|
|
|
376
|
+
| `/search` | General vault retrieval — answers what + why questions across MEMORY, sessions, plans, decisions logs, notes |
|
|
363
377
|
| `/tasks` | Live task dashboard in Obsidian — creates/updates `TASKS.md` with always-current query sections |
|
|
364
378
|
| `/moc` | Vault portal in Obsidian — creates/updates `MOC.md` with projects, areas, knowledge, tasks, and pinned links |
|
|
365
|
-
| `/wrapup` | Wrap up session — merges any auto-checkpoints and saves full summary to session log |
|
|
366
|
-
| `/learn` | Teach the agent something — facts about your world or behavioral preferences |
|
|
367
379
|
| `/memory-review` | Interactive review of memory files — keep, update, deprecate, or delete entries |
|
|
368
|
-
|
|
380
|
+
|
|
381
|
+
### 🔧 MAINTAIN — System housekeeping
|
|
382
|
+
|
|
383
|
+
| Command | What it does |
|
|
384
|
+
|---------|-------------|
|
|
385
|
+
| `/update` | Update skills, config, and plugins from GitHub |
|
|
386
|
+
| `/doctor` | Vault + config health check — broken links, orphan notes, stale memory entries, inbox backlog |
|
|
369
387
|
| `/reorganize` | Migrate flat notes into organized subfolders |
|
|
388
|
+
| `/clone` | Package your agent context for transfer to a new vault |
|
|
370
389
|
| `/qmd` | Set up fast vault search index — enables semantic search across all notes |
|
|
371
|
-
| `/doctor` | Vault + config health check — broken links, orphan notes, stale memory entries, inbox backlog |
|
|
372
|
-
| `/update` | Update skills, config, and plugins from GitHub |
|
|
373
390
|
| `/help` | List all available commands with descriptions |
|
|
391
|
+
| `/wrapup` | Wrap up session — merges any auto-checkpoints and saves full summary to session log |
|
|
374
392
|
|
|
375
393
|
<details>
|
|
376
394
|
<summary><strong>📁 Vault Structure</strong></summary>
|
package/dist/onebrain
CHANGED
|
@@ -9560,7 +9560,7 @@ var init_lib = __esm(() => {
|
|
|
9560
9560
|
var require_package = __commonJS((exports, module) => {
|
|
9561
9561
|
module.exports = {
|
|
9562
9562
|
name: "@onebrain-ai/cli",
|
|
9563
|
-
version: "2.2.
|
|
9563
|
+
version: "2.2.5",
|
|
9564
9564
|
description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
|
|
9565
9565
|
keywords: [
|
|
9566
9566
|
"onebrain",
|
|
@@ -10015,23 +10015,30 @@ async function pathExists(p2) {
|
|
|
10015
10015
|
return false;
|
|
10016
10016
|
}
|
|
10017
10017
|
}
|
|
10018
|
-
async function
|
|
10018
|
+
async function detectHarnesses(vaultRoot) {
|
|
10019
10019
|
const env = process.env["ONEBRAIN_HARNESS"];
|
|
10020
10020
|
if (env) {
|
|
10021
10021
|
if (env === "claude" || env === "claude-code")
|
|
10022
|
-
return "claude";
|
|
10022
|
+
return ["claude"];
|
|
10023
10023
|
if (env === "gemini")
|
|
10024
|
-
return "gemini";
|
|
10024
|
+
return ["gemini"];
|
|
10025
10025
|
if (env === "direct")
|
|
10026
|
-
return "direct";
|
|
10026
|
+
return ["direct"];
|
|
10027
10027
|
process.stderr.write(`harness: unknown ONEBRAIN_HARNESS value "${env}" \u2014 ignoring, falling back to directory detection
|
|
10028
10028
|
`);
|
|
10029
10029
|
}
|
|
10030
|
-
|
|
10031
|
-
return "gemini";
|
|
10030
|
+
const detected = [];
|
|
10032
10031
|
if (await pathExists(join3(vaultRoot, ".claude")))
|
|
10033
|
-
|
|
10034
|
-
|
|
10032
|
+
detected.push("claude");
|
|
10033
|
+
if (await pathExists(join3(vaultRoot, ".gemini")))
|
|
10034
|
+
detected.push("gemini");
|
|
10035
|
+
if (detected.length === 0)
|
|
10036
|
+
return ["direct"];
|
|
10037
|
+
return detected;
|
|
10038
|
+
}
|
|
10039
|
+
async function detectHarness(vaultRoot) {
|
|
10040
|
+
const [first] = await detectHarnesses(vaultRoot);
|
|
10041
|
+
return first ?? "direct";
|
|
10035
10042
|
}
|
|
10036
10043
|
var init_harness = () => {};
|
|
10037
10044
|
|
|
@@ -10060,13 +10067,34 @@ async function writeSettings(settingsPath, settings) {
|
|
|
10060
10067
|
await writeFile2(tmpPath, JSON.stringify(settings, null, 4), "utf8");
|
|
10061
10068
|
await rename2(tmpPath, settingsPath);
|
|
10062
10069
|
}
|
|
10063
|
-
function
|
|
10070
|
+
function matchesSpec(entry, spec) {
|
|
10071
|
+
const fullCmd = [spec.command, ...spec.args].join(" ");
|
|
10072
|
+
if (entry.command === spec.command && JSON.stringify(entry.args ?? []) === JSON.stringify(spec.args)) {
|
|
10073
|
+
return true;
|
|
10074
|
+
}
|
|
10075
|
+
if (entry.command === fullCmd && !entry.args) {
|
|
10076
|
+
return true;
|
|
10077
|
+
}
|
|
10078
|
+
return false;
|
|
10079
|
+
}
|
|
10080
|
+
function rewriteIfShellForm(entry, spec) {
|
|
10081
|
+
const fullCmd = [spec.command, ...spec.args].join(" ");
|
|
10082
|
+
if (entry.command === fullCmd && !entry.args) {
|
|
10083
|
+
entry.command = spec.command;
|
|
10084
|
+
entry.args = [...spec.args];
|
|
10085
|
+
if (!entry.type)
|
|
10086
|
+
entry.type = "command";
|
|
10087
|
+
return true;
|
|
10088
|
+
}
|
|
10089
|
+
return false;
|
|
10090
|
+
}
|
|
10091
|
+
function checkHookPresence(groups, spec) {
|
|
10064
10092
|
let foundMigrate = false;
|
|
10065
10093
|
for (const group of groups) {
|
|
10066
10094
|
for (const entry of group.hooks ?? []) {
|
|
10067
|
-
|
|
10068
|
-
if (cmd === targetCmd)
|
|
10095
|
+
if (matchesSpec(entry, spec))
|
|
10069
10096
|
return "found";
|
|
10097
|
+
const cmd = entry.command ?? "";
|
|
10070
10098
|
if (cmd.includes("checkpoint-hook.sh"))
|
|
10071
10099
|
foundMigrate = true;
|
|
10072
10100
|
}
|
|
@@ -10096,22 +10124,30 @@ function applyHooks(settings) {
|
|
|
10096
10124
|
}
|
|
10097
10125
|
}
|
|
10098
10126
|
for (const event of HOOK_EVENTS) {
|
|
10099
|
-
const
|
|
10100
|
-
if (!
|
|
10127
|
+
const spec = HOOK_SPECS[event];
|
|
10128
|
+
if (!spec)
|
|
10101
10129
|
continue;
|
|
10102
10130
|
if (!hooks[event])
|
|
10103
10131
|
hooks[event] = [];
|
|
10104
10132
|
const groups = hooks[event];
|
|
10105
|
-
|
|
10133
|
+
let rewroteShellForm = false;
|
|
10134
|
+
for (const group of groups) {
|
|
10135
|
+
for (const entry of group.hooks ?? []) {
|
|
10136
|
+
if (rewriteIfShellForm(entry, spec))
|
|
10137
|
+
rewroteShellForm = true;
|
|
10138
|
+
}
|
|
10139
|
+
}
|
|
10140
|
+
const presence = checkHookPresence(groups, spec);
|
|
10106
10141
|
if (presence === "found") {
|
|
10107
|
-
result[event] = "ok";
|
|
10142
|
+
result[event] = rewroteShellForm ? "migrated" : "ok";
|
|
10108
10143
|
} else if (presence === "migrate") {
|
|
10109
10144
|
for (const group of groups) {
|
|
10110
10145
|
if (group.matcher === undefined)
|
|
10111
10146
|
group.matcher = "";
|
|
10112
10147
|
for (const entry of group.hooks ?? []) {
|
|
10113
10148
|
if ((entry.command ?? "").includes("checkpoint-hook.sh")) {
|
|
10114
|
-
entry.command =
|
|
10149
|
+
entry.command = spec.command;
|
|
10150
|
+
entry.args = [...spec.args];
|
|
10115
10151
|
if (!entry.type)
|
|
10116
10152
|
entry.type = "command";
|
|
10117
10153
|
}
|
|
@@ -10119,12 +10155,18 @@ function applyHooks(settings) {
|
|
|
10119
10155
|
}
|
|
10120
10156
|
result[event] = "migrated";
|
|
10121
10157
|
} else {
|
|
10122
|
-
groups.push({
|
|
10158
|
+
groups.push({
|
|
10159
|
+
matcher: "",
|
|
10160
|
+
hooks: [{ type: "command", command: spec.command, args: [...spec.args] }]
|
|
10161
|
+
});
|
|
10123
10162
|
result[event] = "added";
|
|
10124
10163
|
}
|
|
10125
10164
|
}
|
|
10126
10165
|
return result;
|
|
10127
10166
|
}
|
|
10167
|
+
function isCanonicalQmdEntry(entry) {
|
|
10168
|
+
return matchesSpec(entry, QMD_SPEC);
|
|
10169
|
+
}
|
|
10128
10170
|
function isLegacyQmdCmd(cmd) {
|
|
10129
10171
|
return /\bqmd\s+update\b/.test(cmd);
|
|
10130
10172
|
}
|
|
@@ -10137,7 +10179,8 @@ function migrateLegacyQmdEntries(groups, keepCanonical) {
|
|
|
10137
10179
|
let groupTouched = false;
|
|
10138
10180
|
for (const entry of group.hooks) {
|
|
10139
10181
|
if (isLegacyQmdCmd(entry.command ?? "")) {
|
|
10140
|
-
entry.command =
|
|
10182
|
+
entry.command = QMD_SPEC.command;
|
|
10183
|
+
entry.args = [...QMD_SPEC.args];
|
|
10141
10184
|
if (!entry.type)
|
|
10142
10185
|
entry.type = "command";
|
|
10143
10186
|
groupTouched = true;
|
|
@@ -10151,20 +10194,26 @@ function migrateLegacyQmdEntries(groups, keepCanonical) {
|
|
|
10151
10194
|
const before = group.hooks.length;
|
|
10152
10195
|
group.hooks = group.hooks.filter((h) => {
|
|
10153
10196
|
const cmd = h.command ?? "";
|
|
10154
|
-
return !isLegacyQmdCmd(cmd) &&
|
|
10197
|
+
return !isLegacyQmdCmd(cmd) && !isCanonicalQmdEntry(h);
|
|
10155
10198
|
});
|
|
10156
10199
|
if (group.hooks.length !== before)
|
|
10157
10200
|
touched = true;
|
|
10158
10201
|
}
|
|
10159
10202
|
}
|
|
10160
10203
|
if (keepCanonical) {
|
|
10204
|
+
for (const group of groups) {
|
|
10205
|
+
for (const entry of group.hooks ?? []) {
|
|
10206
|
+
if (rewriteIfShellForm(entry, QMD_SPEC))
|
|
10207
|
+
touched = true;
|
|
10208
|
+
}
|
|
10209
|
+
}
|
|
10161
10210
|
let seenCanonical = false;
|
|
10162
10211
|
for (const group of groups) {
|
|
10163
10212
|
if (!group.hooks)
|
|
10164
10213
|
continue;
|
|
10165
10214
|
const before = group.hooks.length;
|
|
10166
10215
|
group.hooks = group.hooks.filter((h) => {
|
|
10167
|
-
if (h
|
|
10216
|
+
if (!isCanonicalQmdEntry(h))
|
|
10168
10217
|
return true;
|
|
10169
10218
|
if (seenCanonical)
|
|
10170
10219
|
return false;
|
|
@@ -10189,10 +10238,13 @@ function applyQmdHook(settings) {
|
|
|
10189
10238
|
settings.hooks["PostToolUse"] = [];
|
|
10190
10239
|
const groups = settings.hooks["PostToolUse"];
|
|
10191
10240
|
const migrated = migrateLegacyQmdEntries(groups, true);
|
|
10192
|
-
const already = groups.some((g) => g.hooks?.some((h) => h
|
|
10241
|
+
const already = groups.some((g) => g.hooks?.some((h) => isCanonicalQmdEntry(h)));
|
|
10193
10242
|
if (already)
|
|
10194
10243
|
return migrated ? "migrated" : "ok";
|
|
10195
|
-
groups.push({
|
|
10244
|
+
groups.push({
|
|
10245
|
+
matcher: QMD_MATCHER,
|
|
10246
|
+
hooks: [{ type: "command", command: QMD_SPEC.command, args: [...QMD_SPEC.args] }]
|
|
10247
|
+
});
|
|
10196
10248
|
return "added";
|
|
10197
10249
|
}
|
|
10198
10250
|
function applyPermissions(settings) {
|
|
@@ -10237,7 +10289,7 @@ ${PATH_EXPORT}
|
|
|
10237
10289
|
async function runRegisterHooks(opts = {}) {
|
|
10238
10290
|
const vaultRoot = opts.vaultDir ?? process.cwd();
|
|
10239
10291
|
const isTTY = opts.isTTY ?? process.stdout.isTTY ?? false;
|
|
10240
|
-
const
|
|
10292
|
+
const harnesses = await detectHarnesses(vaultRoot);
|
|
10241
10293
|
let qmdCollection;
|
|
10242
10294
|
try {
|
|
10243
10295
|
const vaultConfig = await loadVaultConfig(vaultRoot);
|
|
@@ -10263,52 +10315,53 @@ async function runRegisterHooks(opts = {}) {
|
|
|
10263
10315
|
let hooksSpinner = null;
|
|
10264
10316
|
let permSpinner = null;
|
|
10265
10317
|
try {
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10318
|
+
for (const harness of harnesses) {
|
|
10319
|
+
if (harness === "claude") {
|
|
10320
|
+
hooksSpinner = isTTY ? L2() : null;
|
|
10321
|
+
hooksSpinner?.start("Registering hooks...");
|
|
10322
|
+
const settings = await readSettings(settingsPath);
|
|
10323
|
+
result.hooks = applyHooks(settings);
|
|
10324
|
+
let qmdStatus;
|
|
10325
|
+
if (qmdCollection) {
|
|
10326
|
+
qmdStatus = applyQmdHook(settings);
|
|
10327
|
+
} else {
|
|
10328
|
+
const groups = settings.hooks?.["PostToolUse"] ?? [];
|
|
10329
|
+
const stripped = migrateLegacyQmdEntries(groups, false);
|
|
10330
|
+
if (stripped && groups.length === 0 && settings.hooks) {
|
|
10331
|
+
delete settings.hooks["PostToolUse"];
|
|
10332
|
+
}
|
|
10279
10333
|
}
|
|
10334
|
+
if (isTTY) {
|
|
10335
|
+
const parts = HOOK_EVENTS.map((e2) => {
|
|
10336
|
+
const status = result.hooks[e2];
|
|
10337
|
+
const icon = import_picocolors4.default.green(status === "ok" ? "\u2713" : status === "migrated" ? "\u2191" : "+");
|
|
10338
|
+
return `${import_picocolors4.default.dim(e2)} ${icon}`;
|
|
10339
|
+
});
|
|
10340
|
+
if (qmdStatus) {
|
|
10341
|
+
const qmdIcon = qmdStatus === "ok" ? "\u2713" : qmdStatus === "migrated" ? "\u2191" : "+";
|
|
10342
|
+
parts.push(`${import_picocolors4.default.dim("PostToolUse")} ${import_picocolors4.default.green(qmdIcon)}`);
|
|
10343
|
+
}
|
|
10344
|
+
hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
|
|
10345
|
+
} else {
|
|
10346
|
+
const hookLine = HOOK_EVENTS.map((e2) => {
|
|
10347
|
+
const status = result.hooks[e2] ?? "ok";
|
|
10348
|
+
return `${e2} ${status}`;
|
|
10349
|
+
}).join(" ");
|
|
10350
|
+
note(hookLine);
|
|
10351
|
+
if (qmdStatus)
|
|
10352
|
+
note(`PostToolUse ${qmdStatus}`);
|
|
10353
|
+
}
|
|
10354
|
+
permSpinner = isTTY ? L2() : null;
|
|
10355
|
+
permSpinner?.start("Updating permissions...");
|
|
10356
|
+
result.permissionsAdded = applyPermissions(settings);
|
|
10357
|
+
await writeSettings(settingsPath, settings);
|
|
10358
|
+
permSpinner?.stop("Permissions ok");
|
|
10359
|
+
if (!isTTY)
|
|
10360
|
+
note("permissions ok");
|
|
10361
|
+
}
|
|
10362
|
+
if (harness === "direct") {
|
|
10363
|
+
await registerDirectPath();
|
|
10280
10364
|
}
|
|
10281
|
-
if (isTTY) {
|
|
10282
|
-
const parts = HOOK_EVENTS.map((e2) => {
|
|
10283
|
-
const status = result.hooks[e2];
|
|
10284
|
-
const icon = import_picocolors4.default.green(status === "ok" ? "\u2713" : status === "migrated" ? "\u2191" : "+");
|
|
10285
|
-
return `${import_picocolors4.default.dim(e2)} ${icon}`;
|
|
10286
|
-
});
|
|
10287
|
-
if (qmdStatus) {
|
|
10288
|
-
const qmdIcon = qmdStatus === "ok" ? "\u2713" : qmdStatus === "migrated" ? "\u2191" : "+";
|
|
10289
|
-
parts.push(`${import_picocolors4.default.dim("PostToolUse")} ${import_picocolors4.default.green(qmdIcon)}`);
|
|
10290
|
-
}
|
|
10291
|
-
hooksSpinner?.stop(`Hooks ${parts.join(" ")}`);
|
|
10292
|
-
} else {
|
|
10293
|
-
const hookLine = HOOK_EVENTS.map((e2) => {
|
|
10294
|
-
const status = result.hooks[e2];
|
|
10295
|
-
const label = status === "ok" || status === "added" || status === "migrated" ? "ok" : status ?? "ok";
|
|
10296
|
-
return `${e2} ${label}`;
|
|
10297
|
-
}).join(" ");
|
|
10298
|
-
note(hookLine);
|
|
10299
|
-
if (qmdStatus)
|
|
10300
|
-
note(`PostToolUse ${qmdStatus}`);
|
|
10301
|
-
}
|
|
10302
|
-
permSpinner = isTTY ? L2() : null;
|
|
10303
|
-
permSpinner?.start("Updating permissions...");
|
|
10304
|
-
result.permissionsAdded = applyPermissions(settings);
|
|
10305
|
-
await writeSettings(settingsPath, settings);
|
|
10306
|
-
permSpinner?.stop("Permissions ok");
|
|
10307
|
-
if (!isTTY)
|
|
10308
|
-
note("permissions ok");
|
|
10309
|
-
}
|
|
10310
|
-
if (harness === "direct") {
|
|
10311
|
-
await registerDirectPath();
|
|
10312
10365
|
}
|
|
10313
10366
|
result.ok = true;
|
|
10314
10367
|
if (!isTTY) {
|
|
@@ -10332,14 +10385,14 @@ async function registerHooksCommand(vaultDir) {
|
|
|
10332
10385
|
process.exit(1);
|
|
10333
10386
|
}
|
|
10334
10387
|
}
|
|
10335
|
-
var import_picocolors4,
|
|
10388
|
+
var import_picocolors4, HOOK_SPECS, HOOK_EVENTS, PERMISSIONS_TO_ADD, ONEBRAIN_MARKER = "# onebrain", PATH_EXPORT = 'export PATH="$HOME/.bun/bin:$HOME/.npm-global/bin:$PATH"', ALLOWED_HOOK_EVENTS2, QMD_SPEC, QMD_MATCHER = "Write|Edit";
|
|
10336
10389
|
var init_register_hooks = __esm(() => {
|
|
10337
10390
|
init_dist2();
|
|
10338
10391
|
init_lib();
|
|
10339
10392
|
init_harness();
|
|
10340
10393
|
import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
10341
|
-
|
|
10342
|
-
Stop: "onebrain checkpoint stop"
|
|
10394
|
+
HOOK_SPECS = {
|
|
10395
|
+
Stop: { command: "onebrain", args: ["checkpoint", "stop"] }
|
|
10343
10396
|
};
|
|
10344
10397
|
HOOK_EVENTS = ["Stop"];
|
|
10345
10398
|
PERMISSIONS_TO_ADD = [
|
|
@@ -10359,6 +10412,7 @@ var init_register_hooks = __esm(() => {
|
|
|
10359
10412
|
"WebSearch"
|
|
10360
10413
|
];
|
|
10361
10414
|
ALLOWED_HOOK_EVENTS2 = new Set(["Stop", "PostToolUse"]);
|
|
10415
|
+
QMD_SPEC = { command: "onebrain", args: ["qmd-reindex"] };
|
|
10362
10416
|
});
|
|
10363
10417
|
|
|
10364
10418
|
// src/commands/internal/vault-sync.ts
|
|
@@ -10994,7 +11048,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
|
10994
11048
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
10995
11049
|
function resolveBinaryVersion() {
|
|
10996
11050
|
if (true)
|
|
10997
|
-
return "2.2.
|
|
11051
|
+
return "2.2.5";
|
|
10998
11052
|
try {
|
|
10999
11053
|
const pkg = require_package();
|
|
11000
11054
|
return pkg.version ?? "dev";
|
|
@@ -13292,8 +13346,8 @@ function patchUtf8(stream) {
|
|
|
13292
13346
|
}
|
|
13293
13347
|
|
|
13294
13348
|
// src/index.ts
|
|
13295
|
-
var VERSION = "2.2.
|
|
13296
|
-
var RELEASE_DATE = "2026-05-
|
|
13349
|
+
var VERSION = "2.2.5";
|
|
13350
|
+
var RELEASE_DATE = "2026-05-12";
|
|
13297
13351
|
patchUtf8(process.stdout);
|
|
13298
13352
|
patchUtf8(process.stderr);
|
|
13299
13353
|
var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
|