@onebrain-ai/cli 2.1.7 → 2.1.9
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 +118 -18
- package/dist/onebrain +149 -94
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/header-dark.png">
|
|
4
|
+
<img alt="OneBrain — Your AI Thinking Partner" src="assets/header-light.png" width="640">
|
|
5
|
+
</picture>
|
|
3
6
|
</p>
|
|
4
7
|
|
|
5
8
|
<p align="center">
|
|
6
|
-
<a href="https://
|
|
7
|
-
<a href="
|
|
8
|
-
<a href="https://
|
|
9
|
-
<a href="https://github.com/onebrain-ai/onebrain/
|
|
9
|
+
<a href="https://onebrain.run"><img alt="Website" src="https://img.shields.io/badge/onebrain.run-0a0a14?style=for-the-badge&labelColor=ff2d92"></a>
|
|
10
|
+
<a href="https://x.com/onebrain_run"><img alt="@onebrain_run on X" src="https://img.shields.io/badge/follow-@onebrain__run-000000?style=for-the-badge&logo=x&logoColor=white"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@onebrain-ai/cli"><img alt="npm" src="https://img.shields.io/npm/v/@onebrain-ai/cli?style=for-the-badge&logo=npm&color=cb3837&label=%40onebrain-ai%2Fcli"></a>
|
|
12
|
+
<a href="https://github.com/onebrain-ai/onebrain/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/onebrain-ai/onebrain?style=for-the-badge&color=00f3ff&logo=github"></a>
|
|
13
|
+
<a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-7c3aed?style=for-the-badge"></a>
|
|
10
14
|
</p>
|
|
11
15
|
|
|
12
|
-
<h1 align="center">OneBrain</h1>
|
|
13
|
-
|
|
14
16
|
<p align="center">
|
|
15
17
|
<em>Your AI forgets everything when the session ends.<br>
|
|
16
18
|
Your notes, your AI, and your tools live in separate silos.<br>
|
|
@@ -34,11 +36,81 @@ OneBrain is an AI operating system layer built on top of Obsidian. It gives your
|
|
|
34
36
|
|
|
35
37
|
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.
|
|
36
38
|
|
|
37
|
-
**
|
|
39
|
+
> Most tools ask you to query an AI. OneBrain **co-evolves** with you — every preference you teach sharpens the agent, every link it surfaces sharpens you.
|
|
40
|
+
|
|
41
|
+
**The bidirectional flow:**
|
|
42
|
+
|
|
43
|
+
- **Human → Agent** — Every preference, decision, and correction becomes persistent memory. The agent calibrates to you with every interaction.
|
|
44
|
+
- **Agent → Human** — Captures, classifies, links, and synthesizes the noise of your day — so your attention stays on what only you can do.
|
|
45
|
+
|
|
46
|
+
**Harness-agnostic** — Claude Code · Gemini CLI · OpenAI Codex · Qwen · or BYO LLM via API key. [See the architecture ↓](#the-harness-os-architecture)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## The Harness OS Architecture
|
|
51
|
+
|
|
52
|
+
OneBrain doesn't compete with Claude Code, Gemini CLI, or any other AI harness. It sits **underneath them** — the OS layer that keeps your context, memory, and skills consistent no matter which harness you're driving.
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img alt="OneBrain Harness OS — 5-layer architecture: Obsidian Vault, OneBrain Plugin, OneBrain CLI, Harness, LLM" src="assets/diagrams/harness-os-stack.svg" width="780">
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
| # | Layer | Role | What lives here |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| 01 | **Obsidian Vault** | Cognitive interface | Plain Markdown — notes, memory, decisions, knowledge graph |
|
|
61
|
+
| 02 | **OneBrain Plugin** | Skills + hooks | 24+ skills + lifecycle hooks, loaded into any harness |
|
|
62
|
+
| 03 | **OneBrain CLI** | Harness orchestrator | Indexing, checkpoints, vault sync, harness routing |
|
|
63
|
+
| 04 | **Harness** | Agentic runtime | Bring your own — Claude Code · Gemini CLI · Codex · Qwen · ... |
|
|
64
|
+
| 05 | **LLM** | Intelligence source | Local (mlx, ollama) · cloud (claude, gemini, gpt) · raw API |
|
|
65
|
+
|
|
66
|
+
The **Harness** layer is where most AI tools pick a fight with each other. We don't — pick whichever harness you love. By familiarity, by task, or by cost. Your vault stays the same.
|
|
67
|
+
|
|
68
|
+
### Pick Your Harness
|
|
69
|
+
|
|
70
|
+
Each harness reads OneBrain's instruction file automatically. Install it, run it inside your vault, and the plugin loads on first prompt.
|
|
71
|
+
|
|
72
|
+
| Harness | Install | Run | Reads |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| **Claude Code** *(recommended)* | `npm install -g @anthropic-ai/claude-code` | `claude` | `CLAUDE.md` |
|
|
75
|
+
| **Gemini CLI** | `npm install -g @google/gemini-cli` | `gemini` | `GEMINI.md` |
|
|
76
|
+
| **OpenAI Codex** | `npm install -g @openai/codex` | `codex` | `AGENTS.md` |
|
|
77
|
+
| **Qwen Code** | `npm install -g @qwen-code/qwen-code` | `qwen` | `AGENTS.md` |
|
|
78
|
+
|
|
79
|
+
> Auto-checkpoint and the Stop hook are wired up for Claude Code today. The other harnesses get the rest of the skill surface (24+ commands) immediately, and gain hook coverage as upstream support lands.
|
|
80
|
+
|
|
81
|
+
### Bring Your Own LLM (via Claude Code)
|
|
82
|
+
|
|
83
|
+
Already love Claude Code? Use it as a universal frontend. Point `ANTHROPIC_BASE_URL` at any OpenAI-compatible endpoint — Claude Code stays the harness, the LLM behind it changes per task.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Recommended: claude-code-router handles Anthropic ↔ provider translation
|
|
87
|
+
npm install -g @musistudio/claude-code-router
|
|
88
|
+
ccr code # first-run config, then launches Claude Code via the router
|
|
89
|
+
# (later) ccr stop # tear down the router before going native again
|
|
90
|
+
|
|
91
|
+
# Or direct: point ANTHROPIC_BASE_URL at any Anthropic-protocol endpoint
|
|
92
|
+
export ANTHROPIC_BASE_URL=https://your-router-or-anthropic-compatible-host
|
|
93
|
+
export ANTHROPIC_API_KEY=sk-byok-key
|
|
94
|
+
cd vault && claude
|
|
95
|
+
|
|
96
|
+
# Switch back to native Claude any time (manual-export route)
|
|
97
|
+
unset ANTHROPIC_BASE_URL ANTHROPIC_API_KEY
|
|
98
|
+
claude
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Route | What it gets you |
|
|
102
|
+
|---|---|
|
|
103
|
+
| **Local** (mlx, ollama, llama.cpp) | Cost-free routine work, full privacy. Pair with [`litellm`](https://github.com/BerriAI/litellm) or [`claude-code-router`](https://github.com/musistudio/claude-code-router). |
|
|
104
|
+
| **Cloud BYOK** (Claude, Gemini, GPT, Groq, OpenRouter) | Pay-as-you-go premium reasoning. One env-var swap, no code changes. |
|
|
105
|
+
| **Hybrid** (route by task or by cost) | Cheap models for routine, premium when it counts. |
|
|
106
|
+
|
|
107
|
+
Same vault. Same skills. Same memory. The LLM swaps; OneBrain doesn't notice.
|
|
38
108
|
|
|
39
109
|
---
|
|
40
110
|
|
|
41
|
-
##
|
|
111
|
+
## Built for Synergetic Thinking
|
|
112
|
+
|
|
113
|
+
OneBrain doesn't just store markdown. Every feature exists to make you and the agent better at each other's job.
|
|
42
114
|
|
|
43
115
|
| | Feature | Description |
|
|
44
116
|
|---|---|---|
|
|
@@ -46,7 +118,7 @@ Unlike chat-based AI tools, OneBrain lives in plain Markdown files you own forev
|
|
|
46
118
|
| 🖥️ | **Personal AI OS** | Full local stack: Claude Code + Obsidian + tmux + Telegram — no cloud infra needed |
|
|
47
119
|
| ⚡ | **24+ Skills** | Braindump, research, consolidate, bookmark, import files, daily briefing, and more |
|
|
48
120
|
| 📂 | **Vault-native Markdown** | Plain Markdown, no lock-in. Your data stays yours forever |
|
|
49
|
-
|
|
|
121
|
+
| 🔀 | **Multi-Harness OS** | Switch between Claude Code, Gemini CLI, Codex, Qwen, or BYO LLM — context never breaks. [See architecture ↑](#the-harness-os-architecture) |
|
|
50
122
|
| 🔌 | **Zero Config** | Clone, open in Obsidian, run `/onboarding`. Ready in under 2 minutes |
|
|
51
123
|
| 📓 | **Session Logs & Checkpoints** | Every conversation saved with summaries and action items. Auto-checkpoints fire every 15 messages or 30 min so nothing is lost mid-session *(auto-checkpoint requires Claude Code)* |
|
|
52
124
|
| 💾 | **Auto Session Summary** | When you say "bye", the agent silently saves a complete session log — no `/wrapup` needed |
|
|
@@ -97,7 +169,29 @@ Turn your AI into a knowledge curator: research, summarize, import files, and bu
|
|
|
97
169
|
|
|
98
170
|
---
|
|
99
171
|
|
|
100
|
-
##
|
|
172
|
+
## One Vault, All Projects — The Command Center
|
|
173
|
+
|
|
174
|
+
Obsidian becomes your dispatch hub for everything you do:
|
|
175
|
+
|
|
176
|
+
- **Read once, understand all** — agent context lives in one place, never re-explained.
|
|
177
|
+
- **Code in repos, orchestration in vault** — agent dispatches from here to wherever the work actually lives.
|
|
178
|
+
- **Markdown replaces Slack / Linear / Notion** — version-controlled, AI-readable, yours forever.
|
|
179
|
+
|
|
180
|
+
The agent reaches outward FROM the vault to: **CLI / repo · website · cloud infra · social media · office docs · project notes · research · MCP servers**.
|
|
181
|
+
|
|
182
|
+
No tab juggling. No tool sprawl.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## How It Works — The Path to Co-Evolution
|
|
187
|
+
|
|
188
|
+
A tightening 3-step loop:
|
|
189
|
+
|
|
190
|
+
1. **Initiate** — Install the CLI, run `/onboarding`. The agent learns your name, vault, and identity. → `npm install -g @onebrain-ai/cli`
|
|
191
|
+
2. **Capture intent** — Talk in natural language. The agent writes, classifies, and links in real time. → `/braindump` · `/capture` · `/bookmark`
|
|
192
|
+
3. **Mutual evolution** — `/research` and `/distill` expand your knowledge. `/learn` deepens the agent. The loop tightens. → `/research` · `/distill` · `/learn`
|
|
193
|
+
|
|
194
|
+
### Behind the loop
|
|
101
195
|
|
|
102
196
|
After `/onboarding`, your AI agent:
|
|
103
197
|
|
|
@@ -202,13 +296,7 @@ In Claude Code: `/onboarding`
|
|
|
202
296
|
|
|
203
297
|
---
|
|
204
298
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
| Agent | Instruction file | Setup |
|
|
208
|
-
|-------|-----------------|-------|
|
|
209
|
-
| Claude Code | `CLAUDE.md` | Loaded automatically |
|
|
210
|
-
| Gemini CLI | `GEMINI.md` | Loaded automatically |
|
|
211
|
-
| Any agent | `AGENTS.md` | Read manually or via system prompt |
|
|
299
|
+
> **Choosing a harness?** See [The Harness OS Architecture ↑](#the-harness-os-architecture) for install commands per harness, BYO-LLM via Claude Code, and the full 5-layer stack.
|
|
212
300
|
|
|
213
301
|
---
|
|
214
302
|
|
|
@@ -347,6 +435,18 @@ Tasks live inline in your notes — the Tasks plugin surfaces them across the va
|
|
|
347
435
|
|
|
348
436
|
</details>
|
|
349
437
|
|
|
438
|
+
## OneBrain Cloud
|
|
439
|
+
|
|
440
|
+
Multi-device sync and hosted agent runtimes. Your unified intelligence travels with you.
|
|
441
|
+
|
|
442
|
+
| Tier | What you get | Status |
|
|
443
|
+
|---|---|---|
|
|
444
|
+
| **FREE** | Local vault · OSS skills · BYOK | ✅ Available now |
|
|
445
|
+
| **PRO** | Sync · mobile · hosted runtime | 🟡 [Join waitlist](https://onebrain.run) |
|
|
446
|
+
| **TEAM** | Shared intelligence · team mesh | 🟡 Coming soon |
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
350
450
|
<details>
|
|
351
451
|
<summary><strong>⚙️ Prerequisites & Detailed Setup</strong></summary>
|
|
352
452
|
<br>
|
package/dist/onebrain
CHANGED
|
@@ -9459,7 +9459,7 @@ var init_lib = __esm(() => {
|
|
|
9459
9459
|
var require_package = __commonJS((exports, module) => {
|
|
9460
9460
|
module.exports = {
|
|
9461
9461
|
name: "@onebrain-ai/cli",
|
|
9462
|
-
version: "2.1.
|
|
9462
|
+
version: "2.1.9",
|
|
9463
9463
|
description: "CLI for OneBrain \u2014 personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
|
|
9464
9464
|
keywords: [
|
|
9465
9465
|
"onebrain",
|
|
@@ -9474,7 +9474,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
9474
9474
|
"productivity",
|
|
9475
9475
|
"vault"
|
|
9476
9476
|
],
|
|
9477
|
-
homepage: "https://
|
|
9477
|
+
homepage: "https://onebrain.run",
|
|
9478
9478
|
repository: {
|
|
9479
9479
|
type: "git",
|
|
9480
9480
|
url: "git+https://github.com/onebrain-ai/onebrain.git"
|
|
@@ -10761,7 +10761,7 @@ var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
|
10761
10761
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
10762
10762
|
function resolveBinaryVersion() {
|
|
10763
10763
|
if (true)
|
|
10764
|
-
return "2.1.
|
|
10764
|
+
return "2.1.9";
|
|
10765
10765
|
try {
|
|
10766
10766
|
const pkg = require_package();
|
|
10767
10767
|
return pkg.version ?? "dev";
|
|
@@ -10770,62 +10770,91 @@ function resolveBinaryVersion() {
|
|
|
10770
10770
|
}
|
|
10771
10771
|
}
|
|
10772
10772
|
var ART_LINES = [
|
|
10773
|
-
|
|
10774
|
-
"
|
|
10775
|
-
"
|
|
10776
|
-
"
|
|
10777
|
-
|
|
10773
|
+
" ____ ____ _ ",
|
|
10774
|
+
" / __ \\ | _ \\ (_) ",
|
|
10775
|
+
"| | | |_ __ ___| |_) |_ __ __ _ _ _ __ ",
|
|
10776
|
+
"| | | | '_ \\ / _ \\ _ <| '__/ _` | | '_ \\ ",
|
|
10777
|
+
"| |__| | | | | __/ |_) | | | (_| | | | | |",
|
|
10778
|
+
" \\____/|_| |_|\\___|____/|_| \\__,_|_|_| |_|"
|
|
10778
10779
|
];
|
|
10779
|
-
var PREFIX = "
|
|
10780
|
-
var TAGLINE_LEAD = "
|
|
10781
|
-
var TAGLINE_FALLBACK = `${PREFIX}
|
|
10780
|
+
var PREFIX = "YOUR AI ";
|
|
10781
|
+
var TAGLINE_LEAD = " ";
|
|
10782
|
+
var TAGLINE_FALLBACK = `${PREFIX}THINKING PARTNER`;
|
|
10783
|
+
var SUBTITLE = "A unified intelligence in your Obsidian vault";
|
|
10782
10784
|
var BANNER_LINE_COUNT = 1 + ART_LINES.length + 3;
|
|
10783
|
-
var PREFIX_COLOR = [
|
|
10784
|
-
var TRAILING_COLOR = [255,
|
|
10785
|
-
var FINAL_COLOR = [
|
|
10785
|
+
var PREFIX_COLOR = [0, 243, 255];
|
|
10786
|
+
var TRAILING_COLOR = [255, 45, 146];
|
|
10787
|
+
var FINAL_COLOR = [0, 243, 255];
|
|
10788
|
+
var SUBTITLE_COLOR = [0, 170, 178];
|
|
10786
10789
|
var SENTENCES = [
|
|
10787
|
-
{ trailing: "
|
|
10788
|
-
{ trailing: "
|
|
10789
|
-
{ trailing: "
|
|
10790
|
+
{ trailing: "REMEMBERS YOU", trailingWords: ["REMEMBERS", "YOU"], wordTicks: [24, 32] },
|
|
10791
|
+
{ trailing: "CATCHES INSIGHTS", trailingWords: ["CATCHES", "INSIGHTS"], wordTicks: [27, 26] },
|
|
10792
|
+
{ trailing: "THINKING PARTNER", trailingWords: ["THINKING", "PARTNER"], wordTicks: [26, 31] }
|
|
10790
10793
|
];
|
|
10791
10794
|
function supportsRgb() {
|
|
10795
|
+
if (process.env["FORCE_COLOR"] === "3")
|
|
10796
|
+
return true;
|
|
10792
10797
|
const c = process.env["COLORTERM"] ?? "";
|
|
10793
10798
|
return c === "truecolor" || c === "24bit";
|
|
10794
10799
|
}
|
|
10800
|
+
function isInteractiveStdout() {
|
|
10801
|
+
if (process.env["ONEBRAIN_FORCE_TTY"] === "1")
|
|
10802
|
+
return true;
|
|
10803
|
+
if (process.env["FORCE_COLOR"] === "3")
|
|
10804
|
+
return true;
|
|
10805
|
+
return Boolean(process.stdout.isTTY);
|
|
10806
|
+
}
|
|
10795
10807
|
function rgb(r, g, b, ch) {
|
|
10796
10808
|
return `\x1B[1;38;2;${r};${g};${b}m${ch}\x1B[0m`;
|
|
10797
10809
|
}
|
|
10798
10810
|
function rgbStr(c, ch) {
|
|
10799
10811
|
return rgb(c[0], c[1], c[2], ch);
|
|
10800
10812
|
}
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10813
|
+
var BRAND_STOPS = [
|
|
10814
|
+
{ t: 0, rgb: [255, 45, 146] },
|
|
10815
|
+
{ t: 0.55, rgb: [255, 90, 163] },
|
|
10816
|
+
{ t: 1, rgb: [0, 243, 255] }
|
|
10817
|
+
];
|
|
10818
|
+
function brandGradient(t) {
|
|
10819
|
+
const tt = Math.max(0, Math.min(1, t));
|
|
10820
|
+
for (let i = 0;i < BRAND_STOPS.length - 1; i++) {
|
|
10821
|
+
const a = BRAND_STOPS[i];
|
|
10822
|
+
const b = BRAND_STOPS[i + 1];
|
|
10823
|
+
if (tt <= b.t) {
|
|
10824
|
+
const local = (tt - a.t) / (b.t - a.t);
|
|
10825
|
+
return [
|
|
10826
|
+
Math.round(a.rgb[0] + (b.rgb[0] - a.rgb[0]) * local),
|
|
10827
|
+
Math.round(a.rgb[1] + (b.rgb[1] - a.rgb[1]) * local),
|
|
10828
|
+
Math.round(a.rgb[2] + (b.rgb[2] - a.rgb[2]) * local)
|
|
10829
|
+
];
|
|
10830
|
+
}
|
|
10831
|
+
}
|
|
10832
|
+
return BRAND_STOPS[BRAND_STOPS.length - 1].rgb;
|
|
10833
|
+
}
|
|
10834
|
+
var [DIAG_MIN, DIAG_MAX] = (() => {
|
|
10835
|
+
let min = 0;
|
|
10836
|
+
let max = 0;
|
|
10837
|
+
for (let row = 0;row < ART_LINES.length; row++) {
|
|
10838
|
+
min = Math.min(min, -row * 3);
|
|
10839
|
+
max = Math.max(max, ART_LINES[row].length - 1 - row * 3);
|
|
10840
|
+
}
|
|
10841
|
+
return [min, max];
|
|
10842
|
+
})();
|
|
10843
|
+
var DIAG_RANGE = DIAG_MAX - DIAG_MIN;
|
|
10844
|
+
function gradientForCell(row, col) {
|
|
10845
|
+
const d = col - 3 * row;
|
|
10846
|
+
return brandGradient((d - DIAG_MIN) / DIAG_RANGE);
|
|
10847
|
+
}
|
|
10848
|
+
var WHITE_SGR = "\x1B[1;97m";
|
|
10849
|
+
var SGR_RESET = "\x1B[0m";
|
|
10850
|
+
function whiteCell(ch) {
|
|
10851
|
+
return `${WHITE_SGR}${ch}${SGR_RESET}`;
|
|
10820
10852
|
}
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
function neonLine(line, lineIndex = 0, floor = 80) {
|
|
10824
|
-
return line.split("").map((ch, i) => {
|
|
10853
|
+
function neonLine(line, lineIndex = 0) {
|
|
10854
|
+
return line.split("").map((ch, col) => {
|
|
10825
10855
|
if (ch === " ")
|
|
10826
10856
|
return ch;
|
|
10827
|
-
const
|
|
10828
|
-
const [r, g, b] = hsvToRgb(hue, floor);
|
|
10857
|
+
const [r, g, b] = gradientForCell(lineIndex, col);
|
|
10829
10858
|
return rgb(r, g, b, ch);
|
|
10830
10859
|
}).join("");
|
|
10831
10860
|
}
|
|
@@ -10835,13 +10864,18 @@ function whiteLine(line) {
|
|
|
10835
10864
|
function whiteGlowLine(line, alpha) {
|
|
10836
10865
|
return line.split("").map((ch) => ch === " " ? ch : `\x1B[1;38;2;${alpha};${alpha};${alpha}m${ch}\x1B[0m`).join("");
|
|
10837
10866
|
}
|
|
10867
|
+
function renderSubtitle() {
|
|
10868
|
+
const [r, g, b] = SUBTITLE_COLOR;
|
|
10869
|
+
return `\x1B[2;38;2;${r};${g};${b}m${SUBTITLE}\x1B[0m`;
|
|
10870
|
+
}
|
|
10838
10871
|
function dimLine(line) {
|
|
10839
|
-
return line.split("").map((ch) => ch === " " ? ch : `\x1B[2;38;2;
|
|
10872
|
+
return line.split("").map((ch) => ch === " " ? ch : `\x1B[2;38;2;30;60;70m${ch}\x1B[0m`).join("");
|
|
10840
10873
|
}
|
|
10841
10874
|
function scanLineCh(line) {
|
|
10842
10875
|
return line.split("").map((ch) => ch === " " ? ch : rgb(140, 255, 255, ch)).join("");
|
|
10843
10876
|
}
|
|
10844
|
-
var
|
|
10877
|
+
var SCAN_CYAN = [140, 255, 255];
|
|
10878
|
+
var CURSOR = rgb(SCAN_CYAN[0], SCAN_CYAN[1], SCAN_CYAN[2], "\u258C");
|
|
10845
10879
|
var GLYPHS = "\u2593\u2591\u2592\u2588\u2502\u2524\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u256A\u256B\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u2518\u250C\u2551\u258C\u2580\u2584\u2590\u2206\u0192\u03A9\xA7\xB6\xB1\xF7\xD7\xF8\xA5\u20AC";
|
|
10846
10880
|
var randGlyph = () => GLYPHS[Math.floor(Math.random() * GLYPHS.length)] ?? "?";
|
|
10847
10881
|
var glitchWhite = (g) => `\x1B[1;97m${g}\x1B[0m`;
|
|
@@ -10883,7 +10917,7 @@ var SENTENCE_HOLD_MS = 500;
|
|
|
10883
10917
|
var WIPE_TICK_MS = 22;
|
|
10884
10918
|
var WIPE_TRAIL = 3;
|
|
10885
10919
|
var WIPE_PAUSE_MS = 80;
|
|
10886
|
-
async function playBannerIntro(
|
|
10920
|
+
async function playBannerIntro(brandArt, whiteArt) {
|
|
10887
10921
|
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
10888
10922
|
const up = (n) => outb(`\x1B[${n}F`);
|
|
10889
10923
|
printFrame(ART_LINES.map(dimLine), blankTagline());
|
|
@@ -10906,32 +10940,25 @@ async function playBannerIntro(rainbowArt, whiteArt) {
|
|
|
10906
10940
|
up(BANNER_LINE_COUNT);
|
|
10907
10941
|
printFrame(whiteArt, blankTagline());
|
|
10908
10942
|
await delay(600);
|
|
10909
|
-
let minD = 0;
|
|
10910
|
-
let maxD = 0;
|
|
10911
|
-
for (let row = 0;row < ART_LINES.length; row++) {
|
|
10912
|
-
minD = Math.min(minD, -row * 3);
|
|
10913
|
-
maxD = Math.max(maxD, ART_LINES[row].length - 1 - row * 3);
|
|
10914
|
-
}
|
|
10915
10943
|
function flowFrame(frontD) {
|
|
10916
10944
|
return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
|
|
10917
10945
|
if (ch === " ")
|
|
10918
10946
|
return ch;
|
|
10919
10947
|
const d = col - 3 * row;
|
|
10920
10948
|
if (d <= frontD) {
|
|
10921
|
-
const
|
|
10922
|
-
const [r, g, b] = hsvToRgb(hue);
|
|
10949
|
+
const [r, g, b] = gradientForCell(row, col);
|
|
10923
10950
|
return rgb(r, g, b, ch);
|
|
10924
10951
|
}
|
|
10925
|
-
return
|
|
10952
|
+
return whiteCell(ch);
|
|
10926
10953
|
}).join(""));
|
|
10927
10954
|
}
|
|
10928
|
-
for (let d =
|
|
10955
|
+
for (let d = DIAG_MIN;d <= DIAG_MAX; d++) {
|
|
10929
10956
|
await delay(9);
|
|
10930
10957
|
up(BANNER_LINE_COUNT);
|
|
10931
10958
|
printFrame(flowFrame(d), blankTagline());
|
|
10932
10959
|
}
|
|
10933
10960
|
up(BANNER_LINE_COUNT);
|
|
10934
|
-
printFrame(
|
|
10961
|
+
printFrame(brandArt, blankTagline());
|
|
10935
10962
|
await delay(180);
|
|
10936
10963
|
function shimmerArtFrame(highlight) {
|
|
10937
10964
|
return ART_LINES.map((line, row) => line.split("").map((ch, col) => {
|
|
@@ -10939,25 +10966,24 @@ async function playBannerIntro(rainbowArt, whiteArt) {
|
|
|
10939
10966
|
return ch;
|
|
10940
10967
|
const d = col - 3 * row;
|
|
10941
10968
|
if (Math.abs(d - highlight) <= 1)
|
|
10942
|
-
return
|
|
10943
|
-
const
|
|
10944
|
-
const [r, g, b] = hsvToRgb(hue);
|
|
10969
|
+
return whiteCell(ch);
|
|
10970
|
+
const [r, g, b] = gradientForCell(row, col);
|
|
10945
10971
|
return rgb(r, g, b, ch);
|
|
10946
10972
|
}).join(""));
|
|
10947
10973
|
}
|
|
10948
|
-
for (let d =
|
|
10974
|
+
for (let d = DIAG_MIN;d <= DIAG_MAX; d++) {
|
|
10949
10975
|
await delay(9);
|
|
10950
10976
|
up(BANNER_LINE_COUNT);
|
|
10951
10977
|
printFrame(shimmerArtFrame(d), blankTagline());
|
|
10952
10978
|
}
|
|
10953
10979
|
up(BANNER_LINE_COUNT);
|
|
10954
|
-
printFrame(
|
|
10980
|
+
printFrame(brandArt, blankTagline());
|
|
10955
10981
|
await delay(80);
|
|
10956
10982
|
}
|
|
10957
|
-
async function decodeFirstSentence(
|
|
10983
|
+
async function decodeFirstSentence(brandArt, s) {
|
|
10958
10984
|
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
10959
10985
|
const up = (n) => outb(`\x1B[${n}F`);
|
|
10960
|
-
const prefixWords = ["
|
|
10986
|
+
const prefixWords = ["YOUR", "AI"];
|
|
10961
10987
|
for (let wi = 0;wi < prefixWords.length; wi++) {
|
|
10962
10988
|
const w = prefixWords[wi];
|
|
10963
10989
|
const tickMs = PREFIX_TICK_MS[wi];
|
|
@@ -10986,16 +11012,16 @@ async function decodeFirstSentence(rainbowArt, s) {
|
|
|
10986
11012
|
}
|
|
10987
11013
|
}
|
|
10988
11014
|
const trailingBlank = " ".repeat(s.trailing.length);
|
|
10989
|
-
printFrame(
|
|
11015
|
+
printFrame(brandArt, `${prefixPart}${trailingBlank}\x1B[K`);
|
|
10990
11016
|
}
|
|
10991
11017
|
if (wi < prefixWords.length - 1) {
|
|
10992
11018
|
await delay(INTER_WORD_PAUSE_MS);
|
|
10993
11019
|
}
|
|
10994
11020
|
}
|
|
10995
11021
|
await delay(INTER_WORD_PAUSE_MS);
|
|
10996
|
-
await decodeTrailing(
|
|
11022
|
+
await decodeTrailing(brandArt, s, PREFIX.length);
|
|
10997
11023
|
}
|
|
10998
|
-
async function decodeTrailing(
|
|
11024
|
+
async function decodeTrailing(brandArt, s, lockedPrefixChars) {
|
|
10999
11025
|
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
11000
11026
|
const up = (n) => outb(`\x1B[${n}F`);
|
|
11001
11027
|
const words = s.trailingWords;
|
|
@@ -11047,14 +11073,14 @@ async function decodeTrailing(rainbowArt, s, lockedPrefixChars) {
|
|
|
11047
11073
|
trailing += " ";
|
|
11048
11074
|
}
|
|
11049
11075
|
}
|
|
11050
|
-
printFrame(
|
|
11076
|
+
printFrame(brandArt, buildTaglineLine(lockedPrefixChars, trailing));
|
|
11051
11077
|
}
|
|
11052
11078
|
if (wi < words.length - 1) {
|
|
11053
11079
|
await delay(INTER_WORD_PAUSE_MS);
|
|
11054
11080
|
}
|
|
11055
11081
|
}
|
|
11056
11082
|
}
|
|
11057
|
-
async function wipeSwapTransition(
|
|
11083
|
+
async function wipeSwapTransition(brandArt, from, to) {
|
|
11058
11084
|
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
11059
11085
|
const up = (n) => outb(`\x1B[${n}F`);
|
|
11060
11086
|
for (let pos = from.trailing.length - 1;pos >= -WIPE_TRAIL; pos--) {
|
|
@@ -11076,20 +11102,20 @@ async function wipeSwapTransition(rainbowArt, from, to) {
|
|
|
11076
11102
|
trailing += rgbStr(TRAILING_COLOR, ch);
|
|
11077
11103
|
}
|
|
11078
11104
|
}
|
|
11079
|
-
printFrame(
|
|
11105
|
+
printFrame(brandArt, buildTaglineLine(PREFIX.length, trailing));
|
|
11080
11106
|
}
|
|
11081
11107
|
await delay(WIPE_PAUSE_MS);
|
|
11082
|
-
await decodeTrailing(
|
|
11108
|
+
await decodeTrailing(brandArt, to, PREFIX.length);
|
|
11083
11109
|
}
|
|
11084
|
-
async function lockShimmer(
|
|
11110
|
+
async function lockShimmer(brandArt, s) {
|
|
11085
11111
|
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
11086
11112
|
const up = (n) => outb(`\x1B[${n}F`);
|
|
11087
11113
|
const SHIMMER_TICK_MS = 22;
|
|
11088
11114
|
const TRAIL = 3;
|
|
11089
11115
|
const STOPS = [
|
|
11090
11116
|
[255, 255, 255],
|
|
11091
|
-
[
|
|
11092
|
-
[
|
|
11117
|
+
[180, 220, 255],
|
|
11118
|
+
[0, 243, 255]
|
|
11093
11119
|
];
|
|
11094
11120
|
const fullText = PREFIX + s.trailing;
|
|
11095
11121
|
const N = fullText.length;
|
|
@@ -11114,7 +11140,7 @@ async function lockShimmer(rainbowArt, s) {
|
|
|
11114
11140
|
}
|
|
11115
11141
|
}
|
|
11116
11142
|
line += "\x1B[K";
|
|
11117
|
-
printFrame(
|
|
11143
|
+
printFrame(brandArt, line);
|
|
11118
11144
|
}
|
|
11119
11145
|
up(BANNER_LINE_COUNT);
|
|
11120
11146
|
let finalLine = TAGLINE_LEAD;
|
|
@@ -11123,38 +11149,68 @@ async function lockShimmer(rainbowArt, s) {
|
|
|
11123
11149
|
finalLine += ch === " " ? " " : rgbStr(FINAL_COLOR, ch);
|
|
11124
11150
|
}
|
|
11125
11151
|
finalLine += "\x1B[K";
|
|
11126
|
-
|
|
11152
|
+
const subtitleLine = `${TAGLINE_LEAD}${renderSubtitle()}\x1B[K`;
|
|
11153
|
+
outb(`
|
|
11154
|
+
`);
|
|
11155
|
+
for (const l of brandArt)
|
|
11156
|
+
outb(`${l}
|
|
11157
|
+
`);
|
|
11158
|
+
outb(`
|
|
11159
|
+
`);
|
|
11160
|
+
outb(`${finalLine}
|
|
11161
|
+
`);
|
|
11162
|
+
outb(`${subtitleLine}
|
|
11163
|
+
`);
|
|
11164
|
+
outb(`
|
|
11165
|
+
`);
|
|
11127
11166
|
await delay(150);
|
|
11128
11167
|
}
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
if (!supportsRgb()) {
|
|
11133
|
-
outb(`
|
|
11168
|
+
function printStaticBanner() {
|
|
11169
|
+
const truecolor = supportsRgb();
|
|
11170
|
+
outb(`
|
|
11134
11171
|
`);
|
|
11172
|
+
if (truecolor) {
|
|
11173
|
+
for (let i = 0;i < ART_LINES.length; i++)
|
|
11174
|
+
outb(`${neonLine(ART_LINES[i], i)}
|
|
11175
|
+
`);
|
|
11176
|
+
} else {
|
|
11135
11177
|
for (const l of ART_LINES)
|
|
11136
11178
|
outb(`${import_picocolors.default.bold(import_picocolors.default.cyan(l))}
|
|
11137
11179
|
`);
|
|
11138
|
-
|
|
11180
|
+
}
|
|
11181
|
+
outb(`
|
|
11182
|
+
`);
|
|
11183
|
+
if (truecolor) {
|
|
11184
|
+
outb(`${TAGLINE_LEAD}${rgbStr(FINAL_COLOR, TAGLINE_FALLBACK)}
|
|
11139
11185
|
`);
|
|
11186
|
+
outb(`${TAGLINE_LEAD}${renderSubtitle()}
|
|
11187
|
+
`);
|
|
11188
|
+
} else {
|
|
11140
11189
|
outb(`${TAGLINE_LEAD}${import_picocolors.default.bold(import_picocolors.default.cyan(TAGLINE_FALLBACK))}
|
|
11141
11190
|
`);
|
|
11142
|
-
outb(
|
|
11191
|
+
outb(`${TAGLINE_LEAD}${import_picocolors.default.dim(import_picocolors.default.cyan(SUBTITLE))}
|
|
11143
11192
|
`);
|
|
11193
|
+
}
|
|
11194
|
+
outb(`
|
|
11195
|
+
`);
|
|
11196
|
+
}
|
|
11197
|
+
async function printBanner() {
|
|
11198
|
+
if (!isInteractiveStdout() || !supportsRgb()) {
|
|
11199
|
+
printStaticBanner();
|
|
11144
11200
|
return;
|
|
11145
11201
|
}
|
|
11146
|
-
const
|
|
11202
|
+
const brandArt = ART_LINES.map((l, i) => neonLine(l, i));
|
|
11147
11203
|
const whiteArt = ART_LINES.map((l) => whiteLine(l));
|
|
11148
11204
|
try {
|
|
11149
11205
|
outb("\x1B[?25l");
|
|
11150
|
-
await playBannerIntro(
|
|
11151
|
-
await decodeFirstSentence(
|
|
11206
|
+
await playBannerIntro(brandArt, whiteArt);
|
|
11207
|
+
await decodeFirstSentence(brandArt, SENTENCES[0]);
|
|
11152
11208
|
await new Promise((r) => setTimeout(r, SENTENCE_HOLD_MS));
|
|
11153
|
-
await wipeSwapTransition(
|
|
11209
|
+
await wipeSwapTransition(brandArt, SENTENCES[0], SENTENCES[1]);
|
|
11154
11210
|
await new Promise((r) => setTimeout(r, SENTENCE_HOLD_MS));
|
|
11155
|
-
await wipeSwapTransition(
|
|
11211
|
+
await wipeSwapTransition(brandArt, SENTENCES[1], SENTENCES[2]);
|
|
11156
11212
|
await new Promise((r) => setTimeout(r, SENTENCE_HOLD_MS));
|
|
11157
|
-
await lockShimmer(
|
|
11213
|
+
await lockShimmer(brandArt, SENTENCES[2]);
|
|
11158
11214
|
} finally {
|
|
11159
11215
|
outb("\x1B[?25h");
|
|
11160
11216
|
}
|
|
@@ -12340,10 +12396,9 @@ async function scanMonthDir(monthDir, currentToken, today, seenTokens) {
|
|
|
12340
12396
|
}
|
|
12341
12397
|
return count;
|
|
12342
12398
|
}
|
|
12343
|
-
async function runOrphanScan(logsFolder, sessionToken) {
|
|
12344
|
-
const now = new Date;
|
|
12399
|
+
async function runOrphanScan(logsFolder, sessionToken, now) {
|
|
12345
12400
|
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
12346
|
-
const { thisYear, thisMonth, prevYear, prevMonth } = getMonthParts();
|
|
12401
|
+
const { thisYear, thisMonth, prevYear, prevMonth } = getMonthParts(now);
|
|
12347
12402
|
const monthDirs = [
|
|
12348
12403
|
{ year: thisYear, month: thisMonth },
|
|
12349
12404
|
{ year: prevYear, month: prevMonth }
|
|
@@ -12357,7 +12412,7 @@ async function runOrphanScan(logsFolder, sessionToken) {
|
|
|
12357
12412
|
return { orphan_count: totalOrphans };
|
|
12358
12413
|
}
|
|
12359
12414
|
async function orphanScanCommand(logsFolder, sessionToken) {
|
|
12360
|
-
const result = await runOrphanScan(logsFolder, sessionToken);
|
|
12415
|
+
const result = await runOrphanScan(logsFolder, sessionToken, new Date);
|
|
12361
12416
|
process.stdout.write(`${JSON.stringify(result)}
|
|
12362
12417
|
`);
|
|
12363
12418
|
}
|
|
@@ -12793,8 +12848,8 @@ function patchUtf8(stream) {
|
|
|
12793
12848
|
}
|
|
12794
12849
|
|
|
12795
12850
|
// src/index.ts
|
|
12796
|
-
var VERSION = "2.1.
|
|
12797
|
-
var RELEASE_DATE = "2026-
|
|
12851
|
+
var VERSION = "2.1.9";
|
|
12852
|
+
var RELEASE_DATE = "2026-05-05";
|
|
12798
12853
|
patchUtf8(process.stdout);
|
|
12799
12854
|
patchUtf8(process.stderr);
|
|
12800
12855
|
var VERSION_STRING = `OneBrain v${VERSION} \u2014 released ${RELEASE_DATE}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onebrain-ai/cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.9",
|
|
4
4
|
"description": "CLI for OneBrain — personal AI OS for Obsidian with persistent memory, 24+ skills, and Claude Code integration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"onebrain",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"productivity",
|
|
16
16
|
"vault"
|
|
17
17
|
],
|
|
18
|
-
"homepage": "https://
|
|
18
|
+
"homepage": "https://onebrain.run",
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
21
|
"url": "git+https://github.com/onebrain-ai/onebrain.git"
|