@gorlitzer-labs/seldon 0.1.0 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +58 -11
  2. package/bin/seldon.js +50 -8
  3. package/package.json +24 -6
package/README.md CHANGED
@@ -1,18 +1,65 @@
1
1
  # @gorlitzer-labs/seldon
2
2
 
3
- The installer for **the Seldon stack**. Pick the tools you want from a checklist;
4
- each installs via its native method (npm for the node tools, the shell installer
5
- for bifrost, a venv for demerzel).
3
+ ```
4
+ ███████╗███████╗██╗ ██████╗ ██████╗ ███╗ ██╗
5
+ ██╔════╝██╔════╝██║ ██╔══██╗██╔═══██╗████╗ ██║
6
+ ███████╗█████╗ ██║ ██║ ██║██║ ██║██╔██╗ ██║
7
+ ╚════██║██╔══╝ ██║ ██║ ██║██║ ██║██║╚██╗██║
8
+ ███████║███████╗███████╗██████╔╝╚██████╔╝██║ ╚████║
9
+ ╚══════╝╚══════╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═══╝
10
+ ```
11
+
12
+ **The installer for the Seldon stack** — a software factory of AI agents.
13
+ Pick the tools you want from a checklist; each installs via its native method
14
+ (npm for the Node tools, a shell installer for bifrost, a venv for demerzel).
15
+
16
+ ## Install
6
17
 
7
18
  ```bash
8
19
  npm i -g @gorlitzer-labs/seldon
9
- seldon # open the checklist — space to pick, enter to install
10
- seldon install factory # or install named modules (pulls in apiary + foundation)
11
- seldon doctor # check external deps (tmux, sops, age, tailscale, python)
12
- seldon list
13
- seldon --dev # link node modules from a monorepo checkout instead of npm
20
+ seldon # open the checklist — ↑↓ move · space pick · a all · enter install
21
+ ```
22
+
23
+ Or name the modules directly:
24
+
25
+ ```bash
26
+ seldon install foundation comb # install just these
27
+ seldon doctor # check external deps (tmux, sops, age, tailscale, python)
28
+ seldon list # everything available
29
+ ```
30
+
31
+ ## The stack
32
+
33
+ | module | what it is | ships via |
34
+ |---|---|---|
35
+ | **foundation** | the seam — a deterministic plan agents follow | npm |
36
+ | **apiary** | the conversation — shared rooms where agents coordinate | npm |
37
+ | **comb** | the vault — keys by name, never by value | npm |
38
+ | **factory** | the floor — 24/7 supervisor + sandboxed agents | npm |
39
+ | **bifrost** | the bridge — many machines, one workspace | shell |
40
+ | **demerzel** | the voice — a fully-local voice assistant | python (macOS / Apple silicon) |
41
+
42
+ Ticking **factory** auto-includes **apiary** + **foundation** (it needs them on PATH).
43
+
44
+ ## Pick the combo for the job
45
+
46
+ It's a stack, not a bundle — install only what you use:
47
+
48
+ - **Solo, one agent** → `seldon install foundation comb` — a plan + secured keys. Add **factory** for the sandbox, **demerzel** for voice.
49
+ - **A team of agents** → add **apiary** (shared rooms) + **factory** (the supervisor).
50
+ - **Across machines / from your phone** → add **bifrost**.
51
+
52
+ ## Package managers
53
+
54
+ Node tools install via **pnpm** or **bun** if present (much faster than npm), else npm —
55
+ override with `seldon install --pm=pnpm|bun|npm`. demerzel (Python) always installs into
56
+ its **own isolated venv** — never your system/active Python — using **uv** if available,
57
+ else `python3 -m venv` + pip.
58
+
59
+ ## From a checkout
60
+
61
+ ```bash
62
+ seldon --dev # link Node modules from a monorepo checkout instead of npm
14
63
  ```
15
64
 
16
- Modules: `apiary` · `foundation` · `comb` · `factory` · `bifrost` · `demerzel`.
17
- Ticking `factory` auto-includes `apiary` + `foundation` (it needs them on PATH).
18
- `demerzel` is offered only on macOS / Apple silicon.
65
+ Part of the [seldon](https://github.com/gorlitzer-labs/seldon) monorepo.
package/bin/seldon.js CHANGED
@@ -52,14 +52,31 @@ function run(cmd, args, opts = {}) {
52
52
  return r.status === 0;
53
53
  }
54
54
 
55
+ // Is a command on PATH? (used to pick the fastest package manager)
56
+ const has = (bin) => { try { execSync(`command -v ${bin}`, { stdio: "ignore" }); return true; } catch { return false; } };
57
+
58
+ // Pick the node package manager: --pm=<x> override, else the fastest present.
59
+ // pnpm/bun install globally far faster than npm; npm is the universal fallback.
60
+ function nodePM() {
61
+ const ov = (process.argv.find((a) => a.startsWith("--pm=")) || "").split("=")[1];
62
+ if (ov) return ov;
63
+ if (has("pnpm")) return "pnpm";
64
+ if (has("bun")) return "bun";
65
+ return "npm";
66
+ }
67
+
55
68
  function installNpm(m, dev) {
69
+ const pm = nodePM();
56
70
  if (dev && IN_CHECKOUT) {
57
71
  const dir = path.join(REPO_ROOT, m.dir);
58
72
  const pj = JSON.parse(fs.readFileSync(path.join(dir, "package.json")));
59
- if (pj.scripts?.build) run("npm", ["--prefix", dir, "run", "build"]);
60
- return run("npm", ["link"], { cwd: dir });
73
+ if (pj.scripts?.build) run(pm, ["run", "build"], { cwd: dir });
74
+ const link = pm === "pnpm" ? ["link", "--global"] : ["link"]; // bun/npm: `link`
75
+ return run(pm, link, { cwd: dir });
61
76
  }
62
- return run("npm", ["install", "-g", m.pkg]);
77
+ // pnpm/bun: `add -g` · npm: `install -g` — a global CLI, no project touched
78
+ const add = pm === "npm" ? ["install", "-g", m.pkg] : ["add", "-g", m.pkg];
79
+ return run(pm, add);
63
80
  }
64
81
 
65
82
  function installShell(m, dev) {
@@ -86,10 +103,21 @@ function installPython(m, dev) {
86
103
  fs.rmSync(dest + ".tmp", { recursive: true, force: true });
87
104
  }
88
105
  }
106
+ // Always a DEDICATED venv under the module dir — we never install into the
107
+ // user's system/global/active Python. uv (if present) is faster and can even
108
+ // fetch its own CPython, so it doesn't touch their interpreter at all; plain
109
+ // venv+pip is the isolated fallback. No `--system`, no active-env writes.
89
110
  const venv = path.join(dest, ".venv");
90
- run("python3", ["-m", "venv", venv]);
91
- const ok = run(path.join(venv, "bin", "pip"), ["install", "-r", path.join(dest, "requirements.txt")]);
92
- if (ok) console.log(C.dim(` run it: ${path.join(dest, m.bin)} (venv at ${venv})`));
111
+ const req = path.join(dest, "requirements.txt");
112
+ let ok;
113
+ if (has("uv")) {
114
+ if (!run("uv", ["venv", venv])) return false;
115
+ ok = run("uv", ["pip", "install", "--python", path.join(venv, "bin", "python"), "-r", req]);
116
+ } else {
117
+ run("python3", ["-m", "venv", venv]);
118
+ ok = run(path.join(venv, "bin", "pip"), ["install", "-r", req]);
119
+ }
120
+ if (ok) console.log(C.dim(` run it: ${path.join(dest, m.bin)} (isolated venv at ${venv})`));
93
121
  return ok;
94
122
  }
95
123
 
@@ -114,6 +142,14 @@ function doInstall(ids, { dev } = {}) {
114
142
  }
115
143
 
116
144
  // ---- the checklist TUI ------------------------------------------------------
145
+ const BANNER = [
146
+ " ███████╗███████╗██╗ ██████╗ ██████╗ ███╗ ██╗",
147
+ " ██╔════╝██╔════╝██║ ██╔══██╗██╔═══██╗████╗ ██║",
148
+ " ███████╗█████╗ ██║ ██║ ██║██║ ██║██╔██╗ ██║",
149
+ " ╚════██║██╔══╝ ██║ ██║ ██║██║ ██║██║╚██╗██║",
150
+ " ███████║███████╗███████╗██████╔╝╚██████╔╝██║ ╚████║",
151
+ " ╚══════╝╚══════╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═══╝",
152
+ ];
117
153
  function tui() {
118
154
  return new Promise((resolve) => {
119
155
  const rows = MODULES.map((m) => ({ m, on: platformOk(m) && ["apiary", "foundation", "factory"].includes(m.id) }));
@@ -123,13 +159,14 @@ function tui() {
123
159
  readline.cursorTo(process.stdout, 0, 0);
124
160
  readline.clearScreenDown(process.stdout);
125
161
  const out = [];
126
- out.push(C.bold(C.gold(" The Seldon stack")) + C.dim(" — pick your tools"));
162
+ BANNER.forEach((l) => out.push(C.gold(l)));
163
+ out.push(C.dim(" the AI-agent-factory stack — pick your tools"));
127
164
  out.push(C.dim(" ↑↓ move · space toggle · a all · enter install · q quit\n"));
128
165
  rows.forEach((r, i) => {
129
166
  const sel = r.on ? C.green("[x]") : "[ ]";
130
167
  const cursor = i === cur ? C.gold("❯") : " ";
131
168
  const okp = !platformOk(r.m);
132
- const name = (i === cur ? C.bold(r.m.id) : r.m.id).padEnd(11);
169
+ const name = i === cur ? C.bold(r.m.id.padEnd(11)) : r.m.id.padEnd(11);
133
170
  const deps = r.m.needs.map((d) => (depOk(d) ? d : C.red(d))).join(" ");
134
171
  const platNote = okp ? C.red(" (unsupported OS)") : "";
135
172
  out.push(` ${cursor} ${sel} ${name} ${C.dim(methodTag(r.m).padEnd(7))} ${C.dim(r.m.blurb)}${platNote}`);
@@ -177,6 +214,11 @@ ${C.bold("seldon")} — install the Seldon stack, pick what you use.
177
214
  ${C.bold("seldon doctor")} [ids…] check external deps (tmux, sops, age, tailscale, python…)
178
215
  ${C.bold("seldon list")} list the modules
179
216
  ${C.bold("seldon --dev")} link node modules from this checkout instead of npm
217
+ ${C.bold("seldon install --pm=pnpm")} force the node package manager (pnpm|bun|npm; auto-detected)
218
+
219
+ ${C.dim("node tools install via pnpm/bun if present (faster), else npm.")}
220
+ ${C.dim("python (demerzel) installs into its own isolated venv — never your system Python;")}
221
+ ${C.dim("uses uv if present, else python3 -m venv + pip.")}
180
222
 
181
223
  modules: ${MODULES.map((m) => m.id).join(", ")}
182
224
  `);
package/package.json CHANGED
@@ -1,13 +1,31 @@
1
1
  {
2
2
  "name": "@gorlitzer-labs/seldon",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Install the Seldon stack — pick your tools from a checklist; each installs via its native method.",
5
5
  "type": "module",
6
- "bin": { "seldon": "bin/seldon.js" },
7
- "files": ["bin", "modules.mjs", "README.md"],
8
- "engines": { "node": ">=20" },
9
- "keywords": ["ai", "agents", "installer", "cli", "seldon", "apiary", "factory"],
6
+ "bin": {
7
+ "seldon": "bin/seldon.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "modules.mjs",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=20"
16
+ },
17
+ "keywords": [
18
+ "ai",
19
+ "agents",
20
+ "installer",
21
+ "cli",
22
+ "seldon",
23
+ "apiary",
24
+ "factory"
25
+ ],
10
26
  "author": "Franco Berardi",
11
27
  "license": "MIT",
12
- "publishConfig": { "access": "public" }
28
+ "publishConfig": {
29
+ "access": "public"
30
+ }
13
31
  }