@gorlitzer-labs/seldon 0.1.18 → 0.1.20
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 +3 -1
- package/bin/seldon.js +33 -3
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -37,7 +37,9 @@ seldon up # starts the voice (demerzel) + the supervisor (factory wat
|
|
|
37
37
|
# then prints: Voice → http://localhost:8770, how to put agents
|
|
38
38
|
# to work, rooms, phone access
|
|
39
39
|
seldon up --tailnet # also expose the voice on your tailnet → reach it from your phone
|
|
40
|
-
seldon status # what's running (pids)
|
|
40
|
+
seldon status # what's running (pids) — and warns if docker's daemon is down
|
|
41
|
+
seldon adopt [dir] # put an existing repo on the line (foundation · hive · supervised)
|
|
42
|
+
# and print what's next from its queue. Safe to re-run.
|
|
41
43
|
seldon down # stop everything
|
|
42
44
|
```
|
|
43
45
|
|
package/bin/seldon.js
CHANGED
|
@@ -317,8 +317,10 @@ async function doUninstall(ids, { yes = false, all = false } = {}) {
|
|
|
317
317
|
// The stack's only always-on services are the voice (demerzel) and the
|
|
318
318
|
// supervisor loop (factory watch). We run them as detached background daemons,
|
|
319
319
|
// track them by pidfile under ~/.seldon/run, and print one map of where to go.
|
|
320
|
-
|
|
321
|
-
|
|
320
|
+
// SELDON_HOME can be overridden (tests point it at a temp dir; also a legit
|
|
321
|
+
// user override). Everything — run/, bonsai/, demerzel/, brain — derives from it.
|
|
322
|
+
const SELDON_HOME = process.env.SELDON_HOME || path.join(process.env.HOME, ".seldon");
|
|
323
|
+
const RUN_DIR = path.join(SELDON_HOME, "run");
|
|
322
324
|
const pidFile = (name) => path.join(RUN_DIR, name + ".pid");
|
|
323
325
|
const readPid = (name) => { try { return parseInt(fs.readFileSync(pidFile(name), "utf8").trim(), 10) || 0; } catch { return 0; } };
|
|
324
326
|
const isAlive = (pid) => { try { process.kill(pid, 0); return true; } catch { return false; } };
|
|
@@ -328,7 +330,9 @@ function startDaemon(name, cmd, args, opts = {}) {
|
|
|
328
330
|
if (daemonUp(name)) return { already: true, pid: readPid(name) };
|
|
329
331
|
fs.mkdirSync(RUN_DIR, { recursive: true });
|
|
330
332
|
const log = fs.openSync(path.join(RUN_DIR, name + ".log"), "a");
|
|
331
|
-
|
|
333
|
+
// cwd defaults to SELDON_HOME: a long-lived daemon must not pin whatever folder
|
|
334
|
+
// `seldon up` was typed in (it did — the supervisor held a project dir open).
|
|
335
|
+
const child = spawn(cmd, args, { detached: true, stdio: ["ignore", log, log], cwd: SELDON_HOME, ...opts });
|
|
332
336
|
fs.writeFileSync(pidFile(name), String(child.pid));
|
|
333
337
|
child.unref();
|
|
334
338
|
return { pid: child.pid };
|
|
@@ -591,6 +595,7 @@ async function up() {
|
|
|
591
595
|
|
|
592
596
|
// The rest are on-demand, not daemons — point at the command.
|
|
593
597
|
if (has("factory")) go.push(`${C.bold("Put agents to work")} ${C.cyan('factory new "<your idea>"')} ${C.dim("→ repo · foundation · apiary hive")}`);
|
|
598
|
+
if (has("factory")) go.push(`${C.bold("An existing repo")} ${C.cyan("seldon adopt [dir]")} ${C.dim("→ foundation (keeps your docs) · hive · supervised")}`);
|
|
594
599
|
if (has("apiary")) go.push(`${C.bold("Agent rooms")} ${C.cyan("apiary ps")} ${C.dim("(active rooms + join links)")}`);
|
|
595
600
|
if (has("bifrost")) go.push(`${C.bold("Across machines / phone")} ${C.cyan("bifrost sessions")}`);
|
|
596
601
|
|
|
@@ -688,9 +693,31 @@ function statusCmd() {
|
|
|
688
693
|
const phone = tailscaleServeUrl();
|
|
689
694
|
if (phone) console.log(C.dim(" phone (HTTPS): ") + C.cyan(phone));
|
|
690
695
|
}
|
|
696
|
+
const dk = dockerState();
|
|
697
|
+
if (dk === "down") console.log(C.gold("\n ⚠ docker: installed but the daemon is not running") + C.dim(" — factory box and containerised gates need it (open Docker Desktop)"));
|
|
698
|
+
else if (dk === "up") console.log(C.dim("\n docker: ") + C.green("up"));
|
|
691
699
|
console.log(C.dim(`\n start: seldon up · stop: seldon down · logs: ${RUN_DIR}/\n`));
|
|
692
700
|
}
|
|
693
701
|
|
|
702
|
+
// "none" (no docker CLI) | "down" (CLI but no daemon) | "up". Only shown when docker exists.
|
|
703
|
+
function dockerState() {
|
|
704
|
+
if (!has("docker")) return "none";
|
|
705
|
+
try { execSync("docker info", { stdio: "ignore", timeout: 8000 }); return "up"; } catch { return "down"; }
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// ---- adopt: bring an existing repo onto the line ----------------------------
|
|
709
|
+
// factory owns the registry + hive, so this is a front door onto `factory adopt`.
|
|
710
|
+
function adopt(target) {
|
|
711
|
+
if (!has("factory")) {
|
|
712
|
+
console.log(C.red(" adopt needs factory — install it: ") + C.cyan("seldon install factory"));
|
|
713
|
+
process.exitCode = 1; return;
|
|
714
|
+
}
|
|
715
|
+
const passthru = process.argv.slice(3).filter((a) => a !== "--dev");
|
|
716
|
+
const r = spawnSync("factory", ["adopt", ...passthru], { stdio: "inherit" });
|
|
717
|
+
if (r.status !== 0) { process.exitCode = r.status || 1; return; }
|
|
718
|
+
if (!daemonUp("factory-watch")) console.log(C.gold(" the supervisor is not running — ") + C.cyan("seldon up") + C.dim(" starts it, so agents here get healed and nudged.") + "\n");
|
|
719
|
+
}
|
|
720
|
+
|
|
694
721
|
// ---- the checklist TUI ------------------------------------------------------
|
|
695
722
|
const BANNER = [
|
|
696
723
|
" ███████╗███████╗██╗ ██████╗ ██████╗ ███╗ ██╗",
|
|
@@ -774,6 +801,8 @@ ${C.bold("seldon")} — install the Seldon stack, pick what you use.
|
|
|
774
801
|
${C.bold("seldon up --tailnet")} expose the voice over HTTPS (tailscale serve) so the mic works on your phone
|
|
775
802
|
${C.bold("seldon up --brain=X")} pick the voice brain: qwen (in-process) | bonsai (local server); remembered
|
|
776
803
|
${C.bold("seldon status")} what's running · ${C.bold("seldon down")} stop it
|
|
804
|
+
${C.bold("seldon adopt")} [dir] put an existing repo on the line: foundation docs (never overwritten),
|
|
805
|
+
an apiary hive, supervised by factory — and print what's next. Safe to re-run.
|
|
777
806
|
${C.bold("seldon install")} [ids…] install everything picked, or the named modules
|
|
778
807
|
${C.bold("seldon uninstall")} ids… remove the named modules (global CLI / isolated venv)
|
|
779
808
|
${C.bold("seldon uninstall --all")} remove the whole stack (also drops ~/.seldon)
|
|
@@ -815,6 +844,7 @@ const ids = tokens.filter((id) => byId[id]); // only the valid module
|
|
|
815
844
|
if (cmd === "up") return up();
|
|
816
845
|
if (cmd === "down") return down();
|
|
817
846
|
if (cmd === "status") return statusCmd();
|
|
847
|
+
if (cmd === "adopt") return adopt(tokens[0]);
|
|
818
848
|
if (cmd && cmd !== "install") { help(); process.exitCode = 1; return; }
|
|
819
849
|
// interactive
|
|
820
850
|
if (!process.stdin.isTTY) { console.log(C.red("no TTY — use: seldon install <ids…>")); process.exitCode = 1; return; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gorlitzer-labs/seldon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"description": "Install the Seldon stack — pick your tools from a checklist; each installs via its native method.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,5 +27,8 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "node --test test/*.test.mjs"
|
|
30
33
|
}
|
|
31
34
|
}
|