@cpenned/cli 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chris Pennington
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # @cpenned/cli
2
+
3
+ `ob` - a terminal client for Open Brain. It is a thin, full-coverage wrapper
4
+ over the [`/v1` HTTP API](../../README.md#v1-http-api--docs): every command maps
5
+ to one endpoint, so the API + guard layer stay the single source of truth. Same
6
+ contract as the [MCP server](../mcp/README.md), different front end.
7
+
8
+ ## Install
9
+
10
+ The CLI is published to npm. Install it globally and you have the `ob` bin on
11
+ your `PATH` - no clone or build required:
12
+
13
+ ```bash
14
+ npm install -g @cpenned/cli
15
+ ob --help
16
+ ```
17
+
18
+ ### From source (development)
19
+
20
+ Building from the monorepo instead:
21
+
22
+ ```bash
23
+ npm run build -w @cpenned/cli # emits packages/cli/dist/index.js
24
+ node packages/cli/dist/index.js --help
25
+ npm link -w @cpenned/cli # …or link it onto PATH, then: ob --help
26
+ ```
27
+
28
+ ## Configure
29
+
30
+ `ob` needs the deployment origin and an `obr_` API key. **Mint the key from the
31
+ web app (Settings → New API key)** so the CLI hits the same vault as the web UI
32
+ and email. Then save it:
33
+
34
+ ```bash
35
+ ob config set --url https://<deployment>.convex.site --key obr_...
36
+ ```
37
+
38
+ This writes `~/.open-brain/config.json` (chmod 600). Resolution order is
39
+ **environment over file**, so you can override per-command or in CI without
40
+ touching the file:
41
+
42
+ | Variable | Meaning |
43
+ | --- | --- |
44
+ | `OPEN_BRAIN_API_URL` | Deployment origin (`.convex.site` on Convex) |
45
+ | `OPEN_BRAIN_API_KEY` | `obr_` API key |
46
+ | `OPEN_BRAIN_CLIENT_TYPE` | Stamped as `X-Client` (default `cli`) |
47
+
48
+ Inspect with `ob config show` (the key is masked) or `ob config path`.
49
+
50
+ ## Usage
51
+
52
+ Every command prints a calm, human-readable summary. Add `--json` to any command
53
+ to get the raw API payload for piping into `jq` or scripts.
54
+
55
+ ```bash
56
+ # Views
57
+ ob today
58
+ ob view upcoming --tz America/New_York
59
+
60
+ # Tasks
61
+ ob task create "Email the landlord" --garden <gardenId> --when today --priority high
62
+ ob task list --garden <gardenId> --status todo in_progress
63
+ ob task get <taskId>
64
+ ob task update <taskId> --deadline 2026-07-01
65
+ ob task done <taskId>
66
+ ob task rm <taskId>
67
+ ob task tag-add <taskId> --tag <tagId> <tagId>
68
+ echo '[{"gardenId":"...","title":"a"},{"gardenId":"...","title":"b"}]' \
69
+ | ob task create-batch --partial
70
+
71
+ # Projects / gardens / tags (same create|list|get|update|rm shape)
72
+ ob project create "Q3 launch" --garden <gardenId>
73
+ ob garden create "Health" --context "fitness, doctor, meds"
74
+ ob tag create urgent --color "#c1502e"
75
+
76
+ # Reviews
77
+ ob review queue
78
+ ob review garden <gardenId> # deep review
79
+ ob review request <gardenId> # force into the queue
80
+ ob review task <taskId> # mark reviewed
81
+
82
+ # AI (needs the relevant provider keys configured on the deployment)
83
+ ob find authentication bug
84
+ ob triage "call dentist, buy milk, draft the Q3 deck"
85
+
86
+ # API keys (needs the keys:manage scope)
87
+ ob key create "ci runner" --scope tasks:write reviews:*
88
+ ob key list
89
+ ob key rotate <keyId>
90
+ ob key revoke <keyId>
91
+ ```
92
+
93
+ Run `ob <group> --help` (e.g. `ob task --help`) for the full option list of any
94
+ command group.
95
+
96
+ ## Agent skills
97
+
98
+ The CLI ships with the `open-brain-cli` agent skill so an assistant (e.g. Claude
99
+ Code) can drive `ob` on your machine. Install it into your skills directory:
100
+
101
+ ```bash
102
+ ob skills list # what's bundled, and whether it's installed
103
+ ob skills install # copy into ~/.claude/skills
104
+ ob skills install --force # overwrite an existing copy
105
+ ob skills uninstall # remove it again
106
+ ```
107
+
108
+ Skills install into `~/.claude/skills` by default; pass `--dir <path>` to target
109
+ another location. Restart your agent afterwards so it picks up the new skill.
110
+
111
+ ## Develop
112
+
113
+ ```bash
114
+ npm run typecheck -w @cpenned/cli
115
+ npm test -w @cpenned/cli # vitest: client, config, format
116
+ ```
117
+
118
+ The CLI is intentionally logic-light - it builds request bodies/queries and
119
+ renders responses. All validation, the status machine, ownership, and rate
120
+ limits are enforced server-side by `/v1`.
121
+
122
+ ## Publishing
123
+
124
+ MIT-licensed and publish-ready (`files`, `publishConfig`, `prepublishOnly`
125
+ build). To cut a release: bump the version, then `npm publish -w @cpenned/cli`
126
+ from the repo root (`@cpenned` is the owner's npm username scope, so no org is
127
+ needed; you must be authenticated as that user). `prepublishOnly` runs the build
128
+ (bundle skills + `tsc`) first.
package/dist/client.js ADDED
@@ -0,0 +1,58 @@
1
+ export class ApiError extends Error {
2
+ status;
3
+ constructor(status, message) {
4
+ super(message);
5
+ this.status = status;
6
+ this.name = "ApiError";
7
+ }
8
+ }
9
+ export class OpenBrainClient {
10
+ config;
11
+ fetchFn;
12
+ constructor(config, fetchFn = fetch) {
13
+ this.config = config;
14
+ this.fetchFn = fetchFn;
15
+ }
16
+ async request(method, path, opts = {}) {
17
+ const url = new URL(this.config.baseUrl + path);
18
+ if (opts.query) {
19
+ for (const [key, value] of Object.entries(opts.query)) {
20
+ if (value !== undefined && value !== null)
21
+ url.searchParams.set(key, String(value));
22
+ }
23
+ }
24
+ const headers = {
25
+ Authorization: `Bearer ${this.config.apiKey}`,
26
+ "X-Client": this.config.clientType,
27
+ };
28
+ if (opts.body !== undefined)
29
+ headers["Content-Type"] = "application/json";
30
+ if (opts.timezone)
31
+ headers["X-Timezone"] = opts.timezone;
32
+ const res = await this.fetchFn(url.toString(), {
33
+ method,
34
+ headers,
35
+ body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
36
+ });
37
+ const text = await res.text();
38
+ const data = text ? JSON.parse(text) : null;
39
+ if (!res.ok) {
40
+ const message = data?.error?.message ?? res.statusText ?? `HTTP ${res.status}`;
41
+ throw new ApiError(res.status, message);
42
+ }
43
+ return data;
44
+ }
45
+ get(path, query) {
46
+ return this.request("GET", path, { query });
47
+ }
48
+ post(path, body, timezone) {
49
+ return this.request("POST", path, { body, timezone });
50
+ }
51
+ patch(path, body) {
52
+ return this.request("PATCH", path, { body });
53
+ }
54
+ del(path, body) {
55
+ return this.request("DELETE", path, { body });
56
+ }
57
+ }
58
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,55 @@
1
+ // CLI configuration. Resolution order: environment variables override the
2
+ // on-disk config file (~/.open-brain/config.json), which `ob config set`
3
+ // writes. This lets you keep a key on disk for daily use yet override it per
4
+ // command (e.g. point at a different deployment) without editing the file.
5
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { join } from "node:path";
8
+ const CONFIG_DIR = join(homedir(), ".open-brain");
9
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
10
+ export function configPath() {
11
+ return CONFIG_FILE;
12
+ }
13
+ export function readStoredConfig() {
14
+ if (!existsSync(CONFIG_FILE))
15
+ return {};
16
+ try {
17
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf8"));
18
+ }
19
+ catch {
20
+ return {};
21
+ }
22
+ }
23
+ export function saveConfig(patch) {
24
+ const next = { ...readStoredConfig() };
25
+ for (const [key, value] of Object.entries(patch)) {
26
+ if (value !== undefined && value !== "")
27
+ next[key] = value;
28
+ }
29
+ mkdirSync(CONFIG_DIR, { recursive: true });
30
+ writeFileSync(CONFIG_FILE, `${JSON.stringify(next, null, 2)}\n`);
31
+ chmodSync(CONFIG_FILE, 0o600); // contains the secret key
32
+ return next;
33
+ }
34
+ const normalizeBaseUrl = (url) => url.replace(/\/+$/, "").replace(/\/v1$/, "");
35
+ // Pure resolver (env over file). Exported for testing; loadConfig wires the
36
+ // real file in.
37
+ export function resolveConfig(env, file) {
38
+ const baseUrl = env.OPEN_BRAIN_API_URL ?? file.url;
39
+ const apiKey = env.OPEN_BRAIN_API_KEY ?? file.apiKey;
40
+ if (!baseUrl) {
41
+ throw new Error("No API URL configured. Run `ob config set --url https://<deployment>.convex.site` or set OPEN_BRAIN_API_URL.");
42
+ }
43
+ if (!apiKey) {
44
+ throw new Error("No API key configured. Run `ob config set --key obr_...` or set OPEN_BRAIN_API_KEY.");
45
+ }
46
+ return {
47
+ baseUrl: normalizeBaseUrl(baseUrl),
48
+ apiKey,
49
+ clientType: env.OPEN_BRAIN_CLIENT_TYPE ?? file.clientType ?? "cli",
50
+ };
51
+ }
52
+ export function loadConfig(env = process.env) {
53
+ return resolveConfig(env, readStoredConfig());
54
+ }
55
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAiBjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AAClD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD,MAAM,UAAU,UAAU;IACxB,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAiB,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,MAAM,IAAI,GAAiB,EAAE,GAAG,gBAAgB,EAAE,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;YAAE,IAAI,CAAC,GAAyB,CAAC,GAAG,KAAK,CAAC;IACnF,CAAC;IACD,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IACjE,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,0BAA0B;IACzD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAU,EAAE,CAC/C,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAE/C,4EAA4E;AAC5E,gBAAgB;AAChB,MAAM,UAAU,aAAa,CAAC,GAAsB,EAAE,IAAkB;IACtE,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,IAAI,IAAI,CAAC,GAAG,CAAC;IACnD,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,IAAI,IAAI,CAAC,MAAM,CAAC;IACrD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,8GAA8G,CAC/G,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,qFAAqF,CACtF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;QAClC,MAAM;QACN,UAAU,EAAE,GAAG,CAAC,sBAAsB,IAAI,IAAI,CAAC,UAAU,IAAI,KAAK;KACnE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,OAAO,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAChD,CAAC"}
package/dist/format.js ADDED
@@ -0,0 +1,174 @@
1
+ // Output rendering. With --json we print the raw API payload (for piping into
2
+ // jq/scripts); otherwise we render a calm, human-readable summary and steer
3
+ // power users to --json for full detail. The renderer recognises the API's
4
+ // response envelopes (list pagination, search, review queue, issued key,
5
+ // triage) and falls back to a key/value dump for single resources.
6
+ import { ApiError } from "./client.js";
7
+ const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
8
+ const wrap = (code, s) => useColor ? `\x1b[${code}m${s}\x1b[0m` : s;
9
+ const dim = (s) => wrap(2, s);
10
+ const bold = (s) => wrap(1, s);
11
+ const red = (s) => wrap(31, s);
12
+ const green = (s) => wrap(32, s);
13
+ const yellow = (s) => wrap(33, s);
14
+ const isRec = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
15
+ function fmtDate(value) {
16
+ if (typeof value === "number")
17
+ return new Date(value).toISOString().slice(0, 10);
18
+ return String(value);
19
+ }
20
+ function label(item) {
21
+ return String(item.title ?? item.name ?? item.id ?? "(item)");
22
+ }
23
+ function meta(item) {
24
+ const bits = [];
25
+ if (typeof item.status === "string")
26
+ bits.push(item.status);
27
+ if (isRec(item.when) && typeof item.when.type === "string")
28
+ bits.push(item.when.type);
29
+ else if (typeof item.when === "string")
30
+ bits.push(item.when);
31
+ if (typeof item.priority === "string" && item.priority !== "none")
32
+ bits.push(`!${item.priority}`);
33
+ if (item.deadline)
34
+ bits.push(`due ${fmtDate(item.deadline)}`);
35
+ if (Array.isArray(item.scopes))
36
+ bits.push(item.scopes.join(","));
37
+ if (item.archived === true)
38
+ bits.push("archived");
39
+ if (typeof item.prefix === "string")
40
+ bits.push(`${item.prefix}…`);
41
+ if (typeof item.color === "string")
42
+ bits.push(item.color);
43
+ return bits.join(" ");
44
+ }
45
+ function renderList(items) {
46
+ if (items.length === 0) {
47
+ console.log(dim("(none)"));
48
+ return;
49
+ }
50
+ for (const item of items) {
51
+ if (!isRec(item)) {
52
+ console.log(String(item));
53
+ continue;
54
+ }
55
+ const parts = [];
56
+ if (item.id)
57
+ parts.push(dim(String(item.id)));
58
+ parts.push(bold(label(item)));
59
+ const m = meta(item);
60
+ if (m)
61
+ parts.push(dim(m));
62
+ console.log(parts.join(" "));
63
+ }
64
+ console.log(dim(`${items.length} item${items.length === 1 ? "" : "s"}`));
65
+ }
66
+ function renderItem(obj) {
67
+ const keys = Object.keys(obj);
68
+ const width = keys.reduce((w, k) => Math.max(w, k.length), 0);
69
+ for (const key of keys) {
70
+ const value = obj[key];
71
+ const shown = value === null || value === undefined
72
+ ? dim("—")
73
+ : isRec(value) || Array.isArray(value)
74
+ ? JSON.stringify(value)
75
+ : String(value);
76
+ console.log(`${dim(`${key}:`.padEnd(width + 1))} ${shown}`);
77
+ }
78
+ }
79
+ function renderIssuedKey(obj) {
80
+ console.log(green("API key issued."));
81
+ if (obj.id)
82
+ console.log(`${dim("id: ")} ${obj.id}`);
83
+ console.log(`${dim("secret:")} ${bold(String(obj.secret))}`);
84
+ console.log(yellow("Copy the secret now — it is never shown again."));
85
+ }
86
+ function renderTriage(obj) {
87
+ const created = Array.isArray(obj.created) ? obj.created : [];
88
+ console.log(green(`Triaged into ${created.length} task(s).`));
89
+ if (created.length)
90
+ renderList(created);
91
+ if (Array.isArray(obj.clarifications) && obj.clarifications.length) {
92
+ console.log(yellow("Clarifications needed (resolve, then re-run):"));
93
+ for (const c of obj.clarifications) {
94
+ const q = isRec(c) ? (c.question ?? c.prompt ?? JSON.stringify(c)) : String(c);
95
+ console.log(` - ${q}`);
96
+ }
97
+ }
98
+ if (Array.isArray(obj.errors) && obj.errors.length) {
99
+ console.log(red("Errors:"));
100
+ for (const e of obj.errors)
101
+ console.log(` - ${JSON.stringify(e)}`);
102
+ }
103
+ }
104
+ function render(data) {
105
+ if (data === null || data === undefined) {
106
+ console.log(dim("(done)"));
107
+ return;
108
+ }
109
+ if (!isRec(data)) {
110
+ if (Array.isArray(data))
111
+ renderList(data);
112
+ else
113
+ console.log(String(data));
114
+ return;
115
+ }
116
+ // Cursor-paginated list envelope.
117
+ if (Array.isArray(data.items)) {
118
+ renderList(data.items);
119
+ if (data.hasMore)
120
+ console.log(dim(`… more (cursor: ${data.nextCursor})`));
121
+ return;
122
+ }
123
+ // Hybrid search result.
124
+ if (Array.isArray(data.results)) {
125
+ renderList(data.results);
126
+ if (data.mode)
127
+ console.log(dim(`mode: ${data.mode}`));
128
+ return;
129
+ }
130
+ // Review queue.
131
+ if (Array.isArray(data.tasks) || Array.isArray(data.projects)) {
132
+ const tasks = Array.isArray(data.tasks) ? data.tasks : [];
133
+ const projects = Array.isArray(data.projects) ? data.projects : [];
134
+ if (tasks.length) {
135
+ console.log(bold("Tasks"));
136
+ renderList(tasks);
137
+ }
138
+ if (projects.length) {
139
+ console.log(bold("Projects"));
140
+ renderList(projects);
141
+ }
142
+ if (!tasks.length && !projects.length)
143
+ console.log(dim("Nothing due."));
144
+ return;
145
+ }
146
+ if (typeof data.secret === "string") {
147
+ renderIssuedKey(data);
148
+ return;
149
+ }
150
+ if (Array.isArray(data.created) || Array.isArray(data.clarifications)) {
151
+ renderTriage(data);
152
+ return;
153
+ }
154
+ renderItem(data);
155
+ }
156
+ export function printResult(data, opts) {
157
+ if (opts.json) {
158
+ console.log(JSON.stringify(data ?? null, null, 2));
159
+ return;
160
+ }
161
+ render(data);
162
+ }
163
+ export function printError(err) {
164
+ if (err instanceof ApiError) {
165
+ console.error(red(`Error ${err.status}: ${err.message}`));
166
+ }
167
+ else if (err instanceof Error) {
168
+ console.error(red(err.message));
169
+ }
170
+ else {
171
+ console.error(red(String(err)));
172
+ }
173
+ }
174
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,526 @@
1
+ #!/usr/bin/env node
2
+ // Open Brain CLI. A thin, full-coverage terminal client over the /v1 HTTP API:
3
+ // every command maps to one endpoint, so the API + guard layer stay the single
4
+ // source of truth. Auth/headers live in client.ts; rendering in format.ts.
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { Command } from "commander";
8
+ import { OpenBrainClient } from "./client.js";
9
+ import { configPath, loadConfig, readStoredConfig, saveConfig } from "./config.js";
10
+ import { printError, printResult } from "./format.js";
11
+ import { defaultSkillsDir, installSkills, listBundledSkills, uninstallSkills, } from "./skills.js";
12
+ const program = new Command();
13
+ program
14
+ .name("ob")
15
+ .description("Open Brain CLI — manage tasks, projects, gardens over the /v1 API")
16
+ .version("0.1.0")
17
+ .option("--json", "output the raw JSON response (for piping into jq/scripts)");
18
+ const num = (v) => (v === undefined ? undefined : Number(v));
19
+ const csv = (v) => Array.isArray(v) && v.length ? v.join(",") : undefined;
20
+ const str = (v) => (typeof v === "string" ? v : undefined);
21
+ const whenOf = (v) => typeof v === "string" ? { type: v } : undefined;
22
+ async function run(fn) {
23
+ try {
24
+ const data = await fn(new OpenBrainClient(loadConfig()));
25
+ printResult(data, { json: Boolean(program.opts().json) });
26
+ }
27
+ catch (err) {
28
+ printError(err);
29
+ process.exitCode = 1;
30
+ }
31
+ }
32
+ function readStdin() {
33
+ return new Promise((resolve, reject) => {
34
+ let data = "";
35
+ process.stdin.setEncoding("utf8");
36
+ process.stdin.on("data", (chunk) => {
37
+ data += chunk;
38
+ });
39
+ process.stdin.on("end", () => resolve(data));
40
+ process.stdin.on("error", reject);
41
+ });
42
+ }
43
+ async function readJsonInput(file) {
44
+ const text = file ? readFileSync(file, "utf8") : await readStdin();
45
+ return JSON.parse(text);
46
+ }
47
+ // --- config ---------------------------------------------------------------
48
+ const config = program.command("config").description("Manage CLI credentials");
49
+ config
50
+ .command("set")
51
+ .description("Save the deployment URL / API key to ~/.open-brain/config.json")
52
+ .option("--url <url>", "deployment origin, e.g. https://<deployment>.convex.site")
53
+ .option("--key <key>", "API key (obr_...)")
54
+ .option("--client <type>", "client type stamped on requests (default cli)")
55
+ .action((o) => {
56
+ saveConfig({ url: str(o.url), apiKey: str(o.key), clientType: str(o.client) });
57
+ console.log(`Saved to ${configPath()}`);
58
+ });
59
+ config
60
+ .command("show")
61
+ .description("Show the stored config (the key is masked)")
62
+ .action(() => {
63
+ const c = readStoredConfig();
64
+ const masked = c.apiKey ? `${c.apiKey.slice(0, 8)}…${c.apiKey.slice(-4)}` : undefined;
65
+ printResult({ path: configPath(), url: c.url, apiKey: masked, clientType: c.clientType }, { json: Boolean(program.opts().json) });
66
+ });
67
+ config
68
+ .command("path")
69
+ .description("Print the config file path")
70
+ .action(() => console.log(configPath()));
71
+ // --- skills ----------------------------------------------------------------
72
+ // Local-only: install the agent skills bundled with this CLI into the user's
73
+ // Claude Code skills directory so an assistant can drive `ob` on their machine.
74
+ // No API call — these commands only touch the local filesystem.
75
+ const skills = program
76
+ .command("skills")
77
+ .description("Install the agent skills bundled with this CLI (~/.claude/skills)");
78
+ const wantsJson = () => Boolean(program.opts().json);
79
+ function unknownSkills(names) {
80
+ if (!names.length)
81
+ return [];
82
+ const have = new Set(listBundledSkills().map((s) => s.name));
83
+ return names.filter((n) => !have.has(n));
84
+ }
85
+ skills
86
+ .command("list")
87
+ .description("List the bundled skills and whether each is installed")
88
+ .option("--dir <path>", "skills directory to check (default ~/.claude/skills)")
89
+ .action((o) => {
90
+ const dir = str(o.dir) ?? defaultSkillsDir();
91
+ const items = listBundledSkills().map((s) => ({
92
+ name: s.name,
93
+ installed: existsSync(join(dir, s.name)),
94
+ description: s.description,
95
+ }));
96
+ if (wantsJson())
97
+ return printResult({ dir, skills: items }, { json: true });
98
+ if (!items.length)
99
+ return console.log("No skills are bundled with this CLI build.");
100
+ console.log(`Skills directory: ${dir}`);
101
+ for (const s of items) {
102
+ console.log(`${s.installed ? "✓" : "·"} ${s.name} — ${s.description}`);
103
+ }
104
+ });
105
+ skills
106
+ .command("install [names...]")
107
+ .description("Copy bundled skills into ~/.claude/skills (name one or more for a subset)")
108
+ .option("--dir <path>", "target skills directory (default ~/.claude/skills)")
109
+ .option("--force", "overwrite skills that are already installed")
110
+ .action((names, o) => {
111
+ const unknown = unknownSkills(names);
112
+ if (unknown.length) {
113
+ printError(new Error(`Unknown skill(s): ${unknown.join(", ")}. Try 'ob skills list'.`));
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+ const results = installSkills({
118
+ dir: str(o.dir),
119
+ force: Boolean(o.force),
120
+ only: names,
121
+ });
122
+ if (wantsJson())
123
+ return printResult({ skills: results }, { json: true });
124
+ if (!results.length)
125
+ return console.log("No skills are bundled with this CLI build.");
126
+ for (const r of results) {
127
+ if (r.status === "skipped") {
128
+ console.log(`Skipped ${r.name} (already at ${r.dest}; use --force to overwrite)`);
129
+ }
130
+ else {
131
+ const verb = r.status === "overwritten" ? "Updated" : "Installed";
132
+ console.log(`${verb} ${r.name} → ${r.dest}`);
133
+ }
134
+ }
135
+ console.log("Restart Claude Code (or your agent) to pick up the changes.");
136
+ });
137
+ skills
138
+ .command("uninstall [names...]")
139
+ .description("Remove installed Open Brain skills from ~/.claude/skills")
140
+ .option("--dir <path>", "target skills directory (default ~/.claude/skills)")
141
+ .action((names, o) => {
142
+ const unknown = unknownSkills(names);
143
+ if (unknown.length) {
144
+ printError(new Error(`Unknown skill(s): ${unknown.join(", ")}. Try 'ob skills list'.`));
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ const results = uninstallSkills({ dir: str(o.dir), only: names });
149
+ if (wantsJson())
150
+ return printResult({ skills: results }, { json: true });
151
+ for (const r of results) {
152
+ console.log(r.removed
153
+ ? `Removed ${r.name} from ${r.dest}`
154
+ : `${r.name} was not installed (${r.dest})`);
155
+ }
156
+ });
157
+ // --- tasks -----------------------------------------------------------------
158
+ const task = program.command("task").description("Create, list and update tasks");
159
+ function taskBody(o) {
160
+ return {
161
+ title: str(o.title),
162
+ gardenId: str(o.garden),
163
+ projectId: str(o.project),
164
+ notes: str(o.notes),
165
+ when: whenOf(o.when),
166
+ deferDate: str(o.defer),
167
+ deadline: str(o.deadline),
168
+ priority: str(o.priority),
169
+ estimateMinutes: num(o.estimate),
170
+ tagIds: Array.isArray(o.tag) ? o.tag : undefined,
171
+ status: str(o.status),
172
+ };
173
+ }
174
+ const withTaskWriteOpts = (cmd) => cmd
175
+ .option("--garden <id>", "garden id")
176
+ .option("--project <id>", "project id")
177
+ .option("--notes <markdown>", "notes (markdown)")
178
+ .option("--when <bucket>", "today | anytime | someday")
179
+ .option("--defer <date>", "defer date (ISO/epoch/natural language)")
180
+ .option("--deadline <date>", "deadline (ISO/epoch/natural language)")
181
+ .option("--priority <p>", "none | low | medium | high")
182
+ .option("--estimate <minutes>", "estimate in minutes")
183
+ .option("--tag <id...>", "tag ids");
184
+ withTaskWriteOpts(task.command("create <title>").description("Create a task (must belong to a garden)")).action((title, o) => run((c) => c.post("/v1/tasks", { ...taskBody({ ...o, title }) })));
185
+ task
186
+ .command("list")
187
+ .description("List/filter tasks (or multi-get with --ids)")
188
+ .option("--ids <id...>", "fetch specific task ids")
189
+ .option("--garden <id>")
190
+ .option("--project <id>")
191
+ .option("--status <s...>", "backlog|todo|in_progress|done|canceled")
192
+ .option("--priority <p...>", "none|low|medium|high")
193
+ .option("--when <w...>", "today|anytime|someday")
194
+ .option("--tag <id...>", "tag ids")
195
+ .option("--q <text>", "substring text filter")
196
+ .option("--deferred <mode>", "respect | all")
197
+ .option("--include-canceled")
198
+ .option("--sort <spec>", "field:dir,field:dir")
199
+ .option("--limit <n>")
200
+ .option("--cursor <cursor>")
201
+ .action((o) => run((c) => c.get("/v1/tasks", {
202
+ ids: csv(o.ids),
203
+ gardenId: str(o.garden),
204
+ projectId: str(o.project),
205
+ status: csv(o.status),
206
+ priority: csv(o.priority),
207
+ when: csv(o.when),
208
+ tag: csv(o.tag),
209
+ q: str(o.q),
210
+ deferred: str(o.deferred),
211
+ includeCanceled: o.includeCanceled ? true : undefined,
212
+ sort: str(o.sort),
213
+ limit: num(o.limit),
214
+ cursor: str(o.cursor),
215
+ })));
216
+ task
217
+ .command("get <id>")
218
+ .description("Fetch one task (full detail)")
219
+ .action((id) => run((c) => c.get(`/v1/tasks/${id}`)));
220
+ withTaskWriteOpts(task.command("update <id>").description("Patch task fields and/or drive status"))
221
+ .option("--title <title>", "new title")
222
+ .option("--status <status>", "backlog|todo|in_progress|done|canceled")
223
+ .action((id, o) => {
224
+ const body = taskBody(o);
225
+ delete body.tagIds;
226
+ return run((c) => c.patch(`/v1/tasks/${id}`, body));
227
+ });
228
+ task
229
+ .command("rm <id>")
230
+ .description("Soft-delete (cancel) a task")
231
+ .action((id) => run((c) => c.del(`/v1/tasks/${id}`)));
232
+ task
233
+ .command("done <id>")
234
+ .description("Mark a task done (shortcut for update --status done)")
235
+ .action((id) => run((c) => c.patch(`/v1/tasks/${id}`, { status: "done" })));
236
+ task
237
+ .command("tag-add <id>")
238
+ .description("Attach tags to a task")
239
+ .requiredOption("--tag <id...>", "tag ids")
240
+ .action((id, o) => run((c) => c.post(`/v1/tasks/${id}/tags`, { tagIds: o.tag })));
241
+ task
242
+ .command("tag-remove <id>")
243
+ .description("Detach tags from a task")
244
+ .requiredOption("--tag <id...>", "tag ids")
245
+ .action((id, o) => run((c) => c.del(`/v1/tasks/${id}/tags`, { tagIds: o.tag })));
246
+ task
247
+ .command("create-batch")
248
+ .description("Create many tasks from a JSON array (file or stdin)")
249
+ .option("--file <path>", "JSON file; omit to read stdin")
250
+ .option("--partial", "best-effort per item instead of all-or-nothing")
251
+ .action((o) => run(async (c) => c.post("/v1/tasks/batch", {
252
+ items: await readJsonInput(str(o.file)),
253
+ partial: o.partial ? true : undefined,
254
+ })));
255
+ task
256
+ .command("update-batch")
257
+ .description("Patch many tasks from a JSON array of { id, ...fields }")
258
+ .option("--file <path>", "JSON file; omit to read stdin")
259
+ .option("--partial", "best-effort per item")
260
+ .action((o) => run(async (c) => c.patch("/v1/tasks/batch", {
261
+ items: await readJsonInput(str(o.file)),
262
+ partial: o.partial ? true : undefined,
263
+ })));
264
+ // --- projects --------------------------------------------------------------
265
+ const project = program.command("project").description("Manage projects");
266
+ function projectBody(o) {
267
+ return {
268
+ name: str(o.name),
269
+ gardenId: str(o.garden),
270
+ notes: str(o.notes),
271
+ when: whenOf(o.when),
272
+ deferDate: str(o.defer),
273
+ deadline: str(o.deadline),
274
+ estimateMinutes: num(o.estimate),
275
+ status: str(o.status),
276
+ };
277
+ }
278
+ const withProjectWriteOpts = (cmd) => cmd
279
+ .option("--garden <id>", "garden id")
280
+ .option("--notes <markdown>")
281
+ .option("--when <bucket>", "today | anytime | someday")
282
+ .option("--defer <date>")
283
+ .option("--deadline <date>")
284
+ .option("--estimate <minutes>");
285
+ withProjectWriteOpts(project.command("create <name>").description("Create a project in a garden")).action((name, o) => run((c) => c.post("/v1/projects", projectBody({ ...o, name }))));
286
+ project
287
+ .command("list")
288
+ .description("List/filter projects (or multi-get with --ids)")
289
+ .option("--ids <id...>")
290
+ .option("--garden <id>")
291
+ .option("--status <s...>")
292
+ .option("--deferred <mode>", "respect | all")
293
+ .option("--include-canceled")
294
+ .option("--sort <spec>")
295
+ .option("--limit <n>")
296
+ .option("--cursor <cursor>")
297
+ .action((o) => run((c) => c.get("/v1/projects", {
298
+ ids: csv(o.ids),
299
+ gardenId: str(o.garden),
300
+ status: csv(o.status),
301
+ deferred: str(o.deferred),
302
+ includeCanceled: o.includeCanceled ? true : undefined,
303
+ sort: str(o.sort),
304
+ limit: num(o.limit),
305
+ cursor: str(o.cursor),
306
+ })));
307
+ project
308
+ .command("get <id>")
309
+ .description("Fetch one project")
310
+ .action((id) => run((c) => c.get(`/v1/projects/${id}`)));
311
+ withProjectWriteOpts(project.command("update <id>").description("Patch project fields and/or status"))
312
+ .option("--name <name>")
313
+ .option("--status <status>")
314
+ .action((id, o) => run((c) => c.patch(`/v1/projects/${id}`, projectBody(o))));
315
+ project
316
+ .command("rm <id>")
317
+ .description("Soft-delete (drop) a project")
318
+ .action((id) => run((c) => c.del(`/v1/projects/${id}`)));
319
+ // --- gardens ---------------------------------------------------------------
320
+ const garden = program.command("garden").description("Manage life-domain gardens");
321
+ function gardenBody(o) {
322
+ return {
323
+ name: str(o.name),
324
+ notes: str(o.notes),
325
+ context: str(o.context),
326
+ color: str(o.color),
327
+ icon: str(o.icon),
328
+ };
329
+ }
330
+ const withGardenWriteOpts = (cmd) => cmd
331
+ .option("--notes <text>")
332
+ .option("--context <markdown>", "context AI triage uses to assign tasks here")
333
+ .option("--color <color>")
334
+ .option("--icon <icon>");
335
+ withGardenWriteOpts(garden.command("create <name>").description("Create a garden")).action((name, o) => run((c) => c.post("/v1/gardens", gardenBody({ ...o, name }))));
336
+ garden
337
+ .command("list")
338
+ .description("List gardens (or multi-get with --ids)")
339
+ .option("--ids <id...>")
340
+ .option("--archived", "include archived gardens")
341
+ .option("--limit <n>")
342
+ .action((o) => run((c) => c.get("/v1/gardens", {
343
+ ids: csv(o.ids),
344
+ includeArchived: o.archived ? true : undefined,
345
+ limit: num(o.limit),
346
+ })));
347
+ garden
348
+ .command("get <id>")
349
+ .description("Fetch one garden (incl. markdown context)")
350
+ .action((id) => run((c) => c.get(`/v1/gardens/${id}`)));
351
+ withGardenWriteOpts(garden.command("update <id>").description("Patch garden fields"))
352
+ .option("--name <name>")
353
+ .option("--archived <bool>", "true | false")
354
+ .action((id, o) => run((c) => c.patch(`/v1/gardens/${id}`, {
355
+ ...gardenBody(o),
356
+ archived: o.archived === undefined ? undefined : String(o.archived) === "true",
357
+ })));
358
+ garden
359
+ .command("rm <id>")
360
+ .description("Soft-delete (archive) a garden")
361
+ .action((id) => run((c) => c.del(`/v1/gardens/${id}`)));
362
+ // --- tags ------------------------------------------------------------------
363
+ const tag = program.command("tag").description("Manage vault-scoped tags");
364
+ tag
365
+ .command("create <name>")
366
+ .description("Create a tag")
367
+ .option("--color <color>")
368
+ .action((name, o) => run((c) => c.post("/v1/tags", { name, color: str(o.color) })));
369
+ tag
370
+ .command("list")
371
+ .description("List tags (or multi-get with --ids)")
372
+ .option("--ids <id...>")
373
+ .option("--limit <n>")
374
+ .action((o) => run((c) => c.get("/v1/tags", { ids: csv(o.ids), limit: num(o.limit) })));
375
+ tag
376
+ .command("get <id>")
377
+ .description("Fetch one tag")
378
+ .action((id) => run((c) => c.get(`/v1/tags/${id}`)));
379
+ tag
380
+ .command("update <id>")
381
+ .description("Rename or recolor a tag")
382
+ .option("--name <name>")
383
+ .option("--color <color>")
384
+ .action((id, o) => run((c) => c.patch(`/v1/tags/${id}`, { name: str(o.name), color: str(o.color) })));
385
+ tag
386
+ .command("rm <id>")
387
+ .description("Delete a tag (detaches it from every task)")
388
+ .action((id) => run((c) => c.del(`/v1/tags/${id}`)));
389
+ // --- saved lists -----------------------------------------------------------
390
+ const listFilters = (o) => ({
391
+ q: str(o.q),
392
+ status: csv(o.status),
393
+ priority: csv(o.priority),
394
+ when: csv(o.when),
395
+ gardenId: str(o.garden),
396
+ tagIds: csv(o.tag),
397
+ includeCanceled: o.includeCanceled ? true : undefined,
398
+ sort: str(o.sort),
399
+ });
400
+ const withListFilters = (cmd) => cmd
401
+ .option("--q <text>")
402
+ .option("--status <s...>", "backlog|todo|in_progress|done|canceled")
403
+ .option("--priority <p...>", "none|low|medium|high")
404
+ .option("--when <w...>", "today|anytime|someday")
405
+ .option("--garden <id>")
406
+ .option("--tag <id...>")
407
+ .option("--include-canceled")
408
+ .option("--sort <spec>", "field:dir,field:dir");
409
+ const lists = program.command("lists").description("Saved smart lists");
410
+ withListFilters(lists.command("create <name>").description("Save a named set of task filters")).action((name, o) => run((c) => c.post("/v1/lists", { name, filters: listFilters(o) })));
411
+ lists
412
+ .command("ls")
413
+ .description("List saved lists (or multi-get with --ids)")
414
+ .option("--ids <id...>")
415
+ .action((o) => run((c) => c.get("/v1/lists", { ids: csv(o.ids) })));
416
+ lists
417
+ .command("get <id>")
418
+ .description("Fetch one saved list")
419
+ .action((id) => run((c) => c.get(`/v1/lists/${id}`)));
420
+ withListFilters(lists
421
+ .command("update <id>")
422
+ .description("Rename a saved list and/or replace its filters")
423
+ .option("--name <name>")).action((id, o) => {
424
+ const f = listFilters(o);
425
+ const hasFilter = Object.values(f).some((v) => v !== undefined);
426
+ return run((c) => c.patch(`/v1/lists/${id}`, {
427
+ name: str(o.name),
428
+ filters: hasFilter ? f : undefined,
429
+ }));
430
+ });
431
+ lists
432
+ .command("rm <id>")
433
+ .description("Delete a saved list")
434
+ .action((id) => run((c) => c.del(`/v1/lists/${id}`)));
435
+ // --- views -----------------------------------------------------------------
436
+ program
437
+ .command("view <name>")
438
+ .description("A computed view: today | upcoming | anytime | someday | overdue")
439
+ .option("--tz <iana>", "IANA timezone (defaults to the system timezone)")
440
+ .option("--limit <n>")
441
+ .option("--cursor <cursor>")
442
+ .action((name, o) => run((c) => c.get(`/v1/views/${name}`, {
443
+ tz: str(o.tz) ?? systemTz(),
444
+ limit: num(o.limit),
445
+ cursor: str(o.cursor),
446
+ })));
447
+ program
448
+ .command("today")
449
+ .description("Shortcut for `view today`")
450
+ .option("--tz <iana>")
451
+ .option("--limit <n>")
452
+ .action((o) => run((c) => c.get("/v1/views/today", { tz: str(o.tz) ?? systemTz(), limit: num(o.limit) })));
453
+ function systemTz() {
454
+ try {
455
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
456
+ }
457
+ catch {
458
+ return undefined;
459
+ }
460
+ }
461
+ // --- reviews ---------------------------------------------------------------
462
+ const review = program.command("review").description("The review system");
463
+ review
464
+ .command("queue")
465
+ .description("Items due for review now")
466
+ .option("--garden <id>", "restrict to one garden")
467
+ .option("--limit <n>")
468
+ .action((o) => run((c) => c.get("/v1/reviews", { gardenId: str(o.garden), limit: num(o.limit) })));
469
+ review
470
+ .command("garden <id>")
471
+ .description("Deep-review: every active item under a garden")
472
+ .action((id) => run((c) => c.get(`/v1/gardens/${id}/review`)));
473
+ review
474
+ .command("request <gardenId>")
475
+ .description("Force a garden's active items into the due-review queue")
476
+ .action((id) => run((c) => c.post(`/v1/gardens/${id}/request-review`)));
477
+ review
478
+ .command("task <id>")
479
+ .description("Mark a task reviewed (restarts its review clock)")
480
+ .action((id) => run((c) => c.post(`/v1/tasks/${id}/reviewed`)));
481
+ review
482
+ .command("project <id>")
483
+ .description("Mark a project reviewed")
484
+ .action((id) => run((c) => c.post(`/v1/projects/${id}/reviewed`)));
485
+ // --- AI --------------------------------------------------------------------
486
+ program
487
+ .command("find <query...>")
488
+ .description("Hybrid keyword + semantic search over active tasks")
489
+ .option("--limit <n>")
490
+ .option("--deadline-before <date>", "Only tasks due on or before this (epoch ms or date string)")
491
+ .option("--deadline-after <date>", "Only tasks due on or after this (epoch ms or date string)")
492
+ .action((query, o) => run((c) => c.post("/v1/ai/search", {
493
+ query: query.join(" "),
494
+ limit: num(o.limit),
495
+ deadlineBefore: str(o.deadlineBefore),
496
+ deadlineAfter: str(o.deadlineAfter),
497
+ })));
498
+ program
499
+ .command("triage <input...>")
500
+ .description("Triage a brain dump into garden-assigned tasks")
501
+ .action((input) => run((c) => c.post("/v1/ai/triage", { input: input.join(" ") })));
502
+ // --- keys ------------------------------------------------------------------
503
+ const key = program.command("key").description("Manage API keys (keys:manage scope)");
504
+ key
505
+ .command("create <name>")
506
+ .description("Mint an API key (secret shown once)")
507
+ .requiredOption("--scope <scope...>", "scopes, e.g. * or tasks:write reviews:*")
508
+ .option("--client <type>", "cli | mcp | web | integration")
509
+ .action((name, o) => run((c) => c.post("/v1/keys", { name, scopes: o.scope, clientType: str(o.client) })));
510
+ key
511
+ .command("list")
512
+ .description("List the vault's API keys (secrets are never returned)")
513
+ .action(() => run((c) => c.get("/v1/keys")));
514
+ key
515
+ .command("rotate <id>")
516
+ .description("Issue a new secret and revoke the old one")
517
+ .action((id) => run((c) => c.post(`/v1/keys/${id}/rotate`)));
518
+ key
519
+ .command("revoke <id>")
520
+ .description("Soft-revoke an API key")
521
+ .action((id) => run((c) => c.del(`/v1/keys/${id}`)));
522
+ program.parseAsync().catch((err) => {
523
+ printError(err);
524
+ process.exit(1);
525
+ });
526
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/skills.js ADDED
@@ -0,0 +1,84 @@
1
+ // Bundled agent skills shipped with the CLI. `ob skills install` copies them
2
+ // into the user's Claude Code skills directory (~/.claude/skills) so an
3
+ // assistant can drive `ob` on the user's own machine. These are pure local
4
+ // file operations — no API or auth involved. The skill content is copied into
5
+ // this package at build time from the repo's .agents/skills (see
6
+ // scripts/bundle-skills.mjs), which stays the single source of truth.
7
+ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, } from "node:fs";
8
+ import { homedir } from "node:os";
9
+ import { dirname, join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ // Resolved relative to the compiled file (dist/skills.js) so it points at the
12
+ // package's bundled `skills/` dir regardless of where the CLI is installed.
13
+ const here = dirname(fileURLToPath(import.meta.url));
14
+ const bundledSkillsDir = join(here, "..", "skills");
15
+ export function defaultSkillsDir() {
16
+ return join(homedir(), ".claude", "skills");
17
+ }
18
+ export function listBundledSkills(srcDir = bundledSkillsDir) {
19
+ if (!existsSync(srcDir))
20
+ return [];
21
+ return readdirSync(srcDir)
22
+ .filter((name) => existsSync(join(srcDir, name, "SKILL.md")))
23
+ .map((name) => ({
24
+ name,
25
+ description: readDescription(join(srcDir, name, "SKILL.md")),
26
+ path: join(srcDir, name),
27
+ }));
28
+ }
29
+ // Pull the `description:` out of a skill's YAML frontmatter for display.
30
+ // Handles both inline (`description: text`) and the indented block form the
31
+ // skills use, where the value spills onto the following lines.
32
+ function readDescription(skillFile) {
33
+ const fm = readFileSync(skillFile, "utf8").match(/^---\n([\s\S]*?)\n---/);
34
+ if (!fm)
35
+ return "";
36
+ const lines = fm[1].split("\n");
37
+ const start = lines.findIndex((l) => /^description:/.test(l));
38
+ if (start === -1)
39
+ return "";
40
+ const parts = [lines[start].replace(/^description:\s*/, "")];
41
+ for (let i = start + 1; i < lines.length && !/^\S/.test(lines[i]); i++) {
42
+ parts.push(lines[i].trim());
43
+ }
44
+ return parts.join(" ").replace(/\s+/g, " ").trim();
45
+ }
46
+ export function installSkills(opts = {}) {
47
+ const root = opts.dir ?? defaultSkillsDir();
48
+ const wanted = pick(listBundledSkills(opts.srcDir), opts.only);
49
+ if (wanted.length)
50
+ mkdirSync(root, { recursive: true });
51
+ return wanted.map((skill) => {
52
+ const dest = join(root, skill.name);
53
+ const exists = existsSync(dest);
54
+ if (exists && !opts.force)
55
+ return { name: skill.name, status: "skipped", dest };
56
+ if (exists)
57
+ rmSync(dest, { recursive: true, force: true });
58
+ cpSync(skill.path, dest, {
59
+ recursive: true,
60
+ filter: (p) => !lstatSync(p).isSymbolicLink(),
61
+ });
62
+ return { name: skill.name, status: exists ? "overwritten" : "installed", dest };
63
+ });
64
+ }
65
+ export function uninstallSkills(opts = {}) {
66
+ const root = opts.dir ?? defaultSkillsDir();
67
+ const names = opts.only?.length
68
+ ? opts.only
69
+ : listBundledSkills(opts.srcDir).map((s) => s.name);
70
+ return names.map((name) => {
71
+ const dest = join(root, name);
72
+ const removed = existsSync(dest);
73
+ if (removed)
74
+ rmSync(dest, { recursive: true, force: true });
75
+ return { name, removed, dest };
76
+ });
77
+ }
78
+ function pick(skills, only) {
79
+ if (!only?.length)
80
+ return skills;
81
+ const set = new Set(only);
82
+ return skills.filter((s) => set.has(s.name));
83
+ }
84
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@cpenned/cli",
3
+ "version": "0.1.0",
4
+ "description": "Open Brain CLI - a terminal client over the /v1 HTTP API.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Chris Pennington",
8
+ "homepage": "https://github.com/cpenned/open-brain/tree/main/packages/cli#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/cpenned/open-brain.git",
12
+ "directory": "packages/cli"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/cpenned/open-brain/issues"
16
+ },
17
+ "keywords": [
18
+ "cli",
19
+ "open-brain",
20
+ "tasks",
21
+ "todo",
22
+ "productivity",
23
+ "gtd"
24
+ ],
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "bin": {
29
+ "ob": "./dist/index.js",
30
+ "open-brain": "./dist/index.js"
31
+ },
32
+ "main": "./dist/index.js",
33
+ "files": [
34
+ "dist",
35
+ "skills",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "node scripts/bundle-skills.mjs && tsc -p tsconfig.json",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit",
45
+ "test": "vitest run",
46
+ "start": "node dist/index.js",
47
+ "prepublishOnly": "npm run build"
48
+ },
49
+ "dependencies": {
50
+ "commander": "^12.1.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.0.0",
54
+ "typescript": "^5.6.0",
55
+ "vitest": "^4.1.8"
56
+ }
57
+ }
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: open-brain-cli
3
+ description:
4
+ Drive the Open Brain `ob` CLI to manage tasks, projects, gardens, tags,
5
+ views, reviews, search, and triage from the terminal. Use when asked to
6
+ capture/list/update to-dos, plan a day, or script against Open Brain over
7
+ the /v1 API. Not for editing the Open Brain codebase itself.
8
+ ---
9
+
10
+ # Open Brain CLI (`ob`)
11
+
12
+ A thin terminal client over the Open Brain `/v1` HTTP API. Every command maps to
13
+ one endpoint; the API + guard layer enforce validation, the status machine,
14
+ ownership, and scopes. Build artifact: `packages/cli/dist/index.js` (bin `ob`).
15
+
16
+ ## When to use
17
+
18
+ - Capturing or editing tasks/projects/gardens/tags from the shell.
19
+ - Pulling a view (today/upcoming/…), the review queue, or search results.
20
+ - Scripting Open Brain (pipe `--json` into `jq`).
21
+
22
+ ## When not to use
23
+
24
+ - Modifying the Open Brain app/backend code (that is normal repo work).
25
+ - Bulk/agent workflows where the MCP server is already connected — prefer the
26
+ `open-brain-mcp` tools there.
27
+
28
+ ## Setup (once)
29
+
30
+ The CLI needs the deployment origin and an `obr_` API key. Mint the key from the
31
+ web app (**Settings → New API key**) so it targets your real vault.
32
+
33
+ ```bash
34
+ ob config set --url https://<deployment>.convex.site --key obr_...
35
+ ob config show # verify (key masked)
36
+ ```
37
+
38
+ Env vars override the saved file: `OPEN_BRAIN_API_URL`, `OPEN_BRAIN_API_KEY`,
39
+ `OPEN_BRAIN_CLIENT_TYPE`. The URL is the `.convex.site` origin (not `.cloud`).
40
+
41
+ Get `ob` on PATH with a global install (`npm i -g @cpenned/cli`). Working in
42
+ the repo instead? Build the package (`npm run build -w @cpenned/cli`) and call
43
+ `node packages/cli/dist/index.js`, or `npm link -w @cpenned/cli` for the `ob` bin.
44
+
45
+ ## Command map
46
+
47
+ | Area | Commands |
48
+ | --- | --- |
49
+ | tasks | `task create <title>`, `task list`, `task get <id>`, `task update <id>`, `task rm <id>`, `task done <id>`, `task tag-add/<tag-remove> <id> --tag …`, `task create-batch`/`update-batch` |
50
+ | projects | `project create <name>`, `project list/get/update/rm` |
51
+ | gardens | `garden create <name>`, `garden list/get/update/rm` |
52
+ | tags | `tag create <name>`, `tag list/get/update`, `tag rm <id>` (detaches from every task) |
53
+ | lists | `lists create <name> [--status/--priority/--when/--garden/--tag/--q/--sort]`, `lists ls/get/update/rm` (saved smart lists) |
54
+ | views | `view <today\|upcoming\|anytime\|someday\|overdue>`, `today` |
55
+ | reviews | `review queue`, `review garden <id>`, `review request <id>`, `review task <id>`, `review project <id>` |
56
+ | AI | `find <query…>`, `triage <input…>` |
57
+ | keys | `key create <name> --scope …`, `key list/rotate/revoke` |
58
+ | config | `config set/show/path` |
59
+
60
+ `task create`/`project create` require `--garden <id>`. Run `ob <group> --help`
61
+ for the full option list (e.g. `ob task --help`).
62
+
63
+ ## Common workflows
64
+
65
+ ```bash
66
+ # Plan the day
67
+ ob today
68
+ ob view upcoming
69
+
70
+ # Capture
71
+ ob garden list # get a garden id
72
+ ob task create "Email the landlord" --garden <g> --when today --priority high
73
+ ob triage "call dentist, buy milk, draft Q3 deck" # AI splits into tasks
74
+
75
+ # Progress an item
76
+ ob task list --garden <g> --status todo in_progress
77
+ ob task done <taskId>
78
+
79
+ # Saved smart lists
80
+ ob lists create "Hot" --priority high --status todo in_progress
81
+ ob lists ls # then open one in the web app
82
+
83
+ # Review cadence
84
+ ob review queue
85
+ ob review task <taskId> # mark reviewed → restarts its clock
86
+
87
+ # Find something
88
+ ob find quarterly report
89
+ ob find taxes --deadline-before friday # narrow hits to a due window
90
+ ```
91
+
92
+ ## Scripting
93
+
94
+ Add `--json` to ANY command for the raw API payload:
95
+
96
+ ```bash
97
+ ob task list --status todo --json | jq -r '.items[].title'
98
+ TODAY=$(ob today --json | jq '.items | length')
99
+ ```
100
+
101
+ Lists use a `{ items, hasMore, nextCursor }` envelope — page with `--cursor`.
102
+
103
+ ## Gotchas
104
+
105
+ - The CLI acts on the vault behind its key. A key from `apiKeys:bootstrap` is a
106
+ separate empty vault; use a key minted in the web Settings page to share data
107
+ with the web UI and email.
108
+ - Dates (`--defer`, `--deadline`) accept ISO, epoch ms, or relative shorthand
109
+ (`today`, `tomorrow`, `+3d`, `+2w`, `+1m`). `--when` is the intent bucket
110
+ (today/anytime/someday), no date.
111
+ - Statuses are `backlog | todo | in_progress | done | canceled`; `--include-canceled`
112
+ surfaces canceled items, which list filters hide by default.
113
+ - Status transitions are enforced server-side; an illegal move returns an error,
114
+ not a silent no-op.
115
+ - Scopes gate commands: `key` needs `keys:manage`; `find`/`triage` need
116
+ `ai:invoke`. A `*` (owner) key unlocks everything.