brein 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -4
- package/bin/brein.js +170 -0
- package/package.json +22 -7
- package/index.js +0 -3
package/README.md
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
|
-
# brein
|
|
1
|
+
# brein (npm)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Thin Node wrapper for [brein](https://github.com/brein-sh/brein) — the MCP server for a company memory that lives in git.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
## Quickstart
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx brein init
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Verifies Python 3.11+ and [`uv`](https://docs.astral.sh/uv/), installs the brein Python package via `uv tool install`, then runs the setup wizard.
|
|
12
|
+
|
|
13
|
+
After install, the wrapper forwards subcommands to the real CLI:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx brein doctor
|
|
17
|
+
npx brein mcp claude
|
|
18
|
+
npx brein setup mcp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or use the installed binary directly (`brein`, `brain-mcp`, `brain-eval`).
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
- Node 18+
|
|
26
|
+
- Python 3.11+
|
|
27
|
+
- [`uv`](https://docs.astral.sh/uv/) (single static binary, no Python prereq for install)
|
|
28
|
+
- `git`
|
|
29
|
+
|
|
30
|
+
The wrapper prints actionable install hints if anything is missing.
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
MIT.
|
package/bin/brein.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Thin Node shim. Verifies python3 + uv, installs the brein Python package
|
|
3
|
+
// from git, then execs the real `brein` CLI. No deps.
|
|
4
|
+
|
|
5
|
+
const { spawnSync, spawn } = require("node:child_process");
|
|
6
|
+
const { platform } = require("node:os");
|
|
7
|
+
const path = require("node:path");
|
|
8
|
+
|
|
9
|
+
const REPO_URL = "git+https://github.com/brein-sh/brein.git";
|
|
10
|
+
const MIN_PY = [3, 11];
|
|
11
|
+
|
|
12
|
+
const C = {
|
|
13
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
14
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
15
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
16
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
17
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function which(cmd) {
|
|
21
|
+
const r = spawnSync(platform() === "win32" ? "where" : "which", [cmd], {
|
|
22
|
+
encoding: "utf8",
|
|
23
|
+
});
|
|
24
|
+
return r.status === 0 ? r.stdout.trim().split(/\r?\n/)[0] : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function pythonVersion(bin) {
|
|
28
|
+
const r = spawnSync(bin, ["-c", "import sys; print(sys.version_info[0], sys.version_info[1])"], { encoding: "utf8" });
|
|
29
|
+
if (r.status !== 0) return null;
|
|
30
|
+
const [maj, min] = r.stdout.trim().split(/\s+/).map(Number);
|
|
31
|
+
return [maj, min];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function findPython() {
|
|
35
|
+
for (const cmd of ["python3.13", "python3.12", "python3.11", "python3", "python"]) {
|
|
36
|
+
if (!which(cmd)) continue;
|
|
37
|
+
const v = pythonVersion(cmd);
|
|
38
|
+
if (!v) continue;
|
|
39
|
+
if (v[0] > MIN_PY[0] || (v[0] === MIN_PY[0] && v[1] >= MIN_PY[1])) {
|
|
40
|
+
return { bin: cmd, version: v };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function pythonInstallHint() {
|
|
47
|
+
const p = platform();
|
|
48
|
+
if (p === "darwin") return "brew install python@3.12 # or visit https://www.python.org/downloads/";
|
|
49
|
+
if (p === "linux") return "sudo apt install python3.12 # or your distro's equivalent";
|
|
50
|
+
if (p === "win32") return "winget install Python.Python.3.12 # or https://www.python.org/downloads/";
|
|
51
|
+
return "Install Python 3.11+ from https://www.python.org/downloads/";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function uvInstallHint() {
|
|
55
|
+
if (platform() === "win32") return "powershell -c \"irm https://astral.sh/uv/install.ps1 | iex\"";
|
|
56
|
+
return "curl -LsSf https://astral.sh/uv/install.sh | sh";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function run(cmd, args, opts = {}) {
|
|
60
|
+
const r = spawnSync(cmd, args, { stdio: "inherit", ...opts });
|
|
61
|
+
return r.status === 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function execReplace(cmd, args) {
|
|
65
|
+
// No exec() in Node; spawn with inherited stdio and forward the exit code.
|
|
66
|
+
const child = spawn(cmd, args, { stdio: "inherit" });
|
|
67
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function preflight() {
|
|
71
|
+
const py = findPython();
|
|
72
|
+
if (!py) {
|
|
73
|
+
console.error(C.red("✗") + " Python " + MIN_PY.join(".") + "+ not found.");
|
|
74
|
+
console.error(" → " + pythonInstallHint());
|
|
75
|
+
process.exit(2);
|
|
76
|
+
}
|
|
77
|
+
console.log(C.green("✓") + ` python ${py.version.join(".")} (${py.bin})`);
|
|
78
|
+
|
|
79
|
+
const uv = which("uv");
|
|
80
|
+
if (!uv) {
|
|
81
|
+
console.error(C.red("✗") + " uv not found.");
|
|
82
|
+
console.error(" → " + uvInstallHint());
|
|
83
|
+
console.error(" (uv is a single static binary, no Python prereq.)");
|
|
84
|
+
process.exit(2);
|
|
85
|
+
}
|
|
86
|
+
console.log(C.green("✓") + ` uv (${uv})`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function installBrein(branch) {
|
|
90
|
+
const url = branch ? `${REPO_URL}@${branch}` : REPO_URL;
|
|
91
|
+
console.log(C.bold("\nInstalling brein from") + " " + C.dim(url));
|
|
92
|
+
const ok = run("uv", ["tool", "install", "--force", url]);
|
|
93
|
+
if (!ok) {
|
|
94
|
+
console.error(C.red("\nuv tool install failed."));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function uvToolBin() {
|
|
100
|
+
// Resolve the installed brein binary directly via uv. PATH lookup is
|
|
101
|
+
// unreliable inside `npx` (which prepends its own .bin and finds this
|
|
102
|
+
// wrapper instead of the Python CLI → recursion).
|
|
103
|
+
const r = spawnSync("uv", ["tool", "dir", "--bin"], { encoding: "utf8" });
|
|
104
|
+
if (r.status !== 0) return null;
|
|
105
|
+
const dir = r.stdout.trim();
|
|
106
|
+
const exe = platform() === "win32" ? "brein.exe" : "brein";
|
|
107
|
+
return path.join(dir, exe);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function resolveInstalledBrein() {
|
|
111
|
+
const direct = uvToolBin();
|
|
112
|
+
if (direct) {
|
|
113
|
+
const fs = require("node:fs");
|
|
114
|
+
if (fs.existsSync(direct)) return direct;
|
|
115
|
+
}
|
|
116
|
+
// Fallback: trust PATH (only safe outside npx, but worth a try).
|
|
117
|
+
const onPath = which("brein");
|
|
118
|
+
if (onPath && onPath !== process.argv[1]) return onPath;
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function usage() {
|
|
123
|
+
console.log(`brein — npm wrapper for the brein MCP server
|
|
124
|
+
|
|
125
|
+
Usage:
|
|
126
|
+
npx brein init [--branch <name>] Install Python package + run setup wizard
|
|
127
|
+
npx brein <subcommand> [args...] Forward to the installed brein CLI
|
|
128
|
+
(setup | doctor | mcp | config)
|
|
129
|
+
|
|
130
|
+
Examples:
|
|
131
|
+
npx brein init
|
|
132
|
+
npx brein doctor
|
|
133
|
+
npx brein mcp claude
|
|
134
|
+
`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function main() {
|
|
138
|
+
const [, , cmd, ...rest] = process.argv;
|
|
139
|
+
|
|
140
|
+
if (!cmd || cmd === "--help" || cmd === "-h") {
|
|
141
|
+
usage();
|
|
142
|
+
process.exit(cmd ? 0 : 1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (cmd === "init") {
|
|
146
|
+
const branchIdx = rest.indexOf("--branch");
|
|
147
|
+
const branch = branchIdx >= 0 ? rest[branchIdx + 1] : null;
|
|
148
|
+
preflight();
|
|
149
|
+
installBrein(branch);
|
|
150
|
+
const installed = resolveInstalledBrein();
|
|
151
|
+
if (!installed) {
|
|
152
|
+
console.error(C.red("✗") + " brein installed but binary not found.");
|
|
153
|
+
console.error(" → run: " + C.bold("uv tool update-shell"));
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
console.log(C.bold("\nRunning ") + C.bold("brein setup") + C.bold("...\n"));
|
|
157
|
+
execReplace(installed, ["setup"]);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Forward anything else to the installed CLI.
|
|
162
|
+
const installed = resolveInstalledBrein();
|
|
163
|
+
if (!installed) {
|
|
164
|
+
console.error(C.red("✗") + " brein is not installed. Run: npx brein init");
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
execReplace(installed, [cmd, ...rest]);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brein",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "npx wrapper for brein — installs the Python MCP server and runs the setup wizard.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"homepage": "https://brein.
|
|
6
|
+
"homepage": "https://brein.sh",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/
|
|
9
|
+
"url": "git+https://github.com/brein-sh/brein.git",
|
|
10
|
+
"directory": "npm"
|
|
10
11
|
},
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
"bin": {
|
|
13
|
+
"brein": "bin/brein.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin/",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"llm",
|
|
25
|
+
"knowledge-base",
|
|
26
|
+
"rag",
|
|
27
|
+
"brain"
|
|
28
|
+
]
|
|
14
29
|
}
|
package/index.js
DELETED