create-egregore 0.19.5 → 0.19.7
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/assets/egregore-launcher.js +411 -25
- package/bin/cli.js +34 -20
- package/lib/local.js +21 -5
- package/lib/pi-runtime.js +186 -0
- package/lib/setup.js +56 -11
- package/lib/ui.js +1 -1
- package/package.json +7 -5
- package/runtime/codex/.codex/spec-manifest.json +1 -1
- package/runtime/codex/AGENTS.md +7 -2
- package/runtime/codex/bin/codex-render-spec.mjs +6 -1
- package/runtime/codex/bin/codex-session-start.sh +5 -59
- package/runtime/codex/bin/codex-skill-render.mjs +7 -5
- package/runtime/codex/bin/lib/context.sh +8 -1
- package/runtime/codex/bin/lib/greeting.sh +12 -108
- package/runtime/codex/bin/lib/metrics.sh +374 -0
- package/runtime/codex/bin/publish-artifact.sh +14 -0
- package/runtime/codex/bin/settings.sh +274 -0
- package/runtime/codex/manifest.json +2 -0
- package/runtime/pi/.codex/config.toml +15 -0
- package/runtime/pi/.codex/hooks/branch-guard.js +242 -0
- package/runtime/pi/.codex/hooks/search-hint.js +65 -0
- package/runtime/pi/.codex/hooks.json +30 -0
- package/runtime/pi/.codex/skills/activity/SKILL.md +70 -0
- package/runtime/pi/.codex/skills/add/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/announce/SKILL.md +54 -0
- package/runtime/pi/.codex/skills/answer/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/archive/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/ask/SKILL.md +59 -0
- package/runtime/pi/.codex/skills/branch/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/checkup/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/commit/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/contribute/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/dark-mode/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/dashboard/SKILL.md +59 -0
- package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +74 -0
- package/runtime/pi/.codex/skills/delete-user/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/egregore-voice/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/emissary/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/env/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/handoff/SKILL.md +67 -0
- package/runtime/pi/.codex/skills/harvest/SKILL.md +107 -0
- package/runtime/pi/.codex/skills/ingest/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/ingest-google/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/invite/SKILL.md +40 -0
- package/runtime/pi/.codex/skills/issue/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/me/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/meeting/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/minion/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/note/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/onboarding/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/pr/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/project/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/pull/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/push/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/quest/SKILL.md +77 -0
- package/runtime/pi/.codex/skills/quest-suggest/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/reflect/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/review-pr/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/save/SKILL.md +62 -0
- package/runtime/pi/.codex/skills/scroll/SKILL.md +168 -0
- package/runtime/pi/.codex/skills/scroll/agents/openai.yaml +4 -0
- package/runtime/pi/.codex/skills/scroll/assets/shell.html +542 -0
- package/runtime/pi/.codex/skills/search/SKILL.md +56 -0
- package/runtime/pi/.codex/skills/session-view/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/setup/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/summon/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/sync-repos/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/telemetry/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/test/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/the-spiral/SKILL.md +84 -0
- package/runtime/pi/.codex/skills/thread/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/todo/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/tui-design/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/tutorial/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/update/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/view/SKILL.md +156 -0
- package/runtime/pi/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/pi/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/pi/.codex/skills/visual-explain/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/wrap/SKILL.md +55 -0
- package/runtime/pi/.codex/spec-manifest.json +114 -0
- package/runtime/pi/.pi/APPEND_SYSTEM.md +255 -0
- package/runtime/pi/.pi/extensions/egregore.ts +324 -0
- package/runtime/pi/.pi/settings.json +6 -0
- package/runtime/pi/.pi/spec-manifest.json +12 -0
- package/runtime/pi/AGENTS.md +350 -0
- package/runtime/pi/bin/activity-data.sh +242 -0
- package/runtime/pi/bin/agent.sh +677 -0
- package/runtime/pi/bin/codex-install-skills.sh +78 -0
- package/runtime/pi/bin/codex-render-spec.mjs +394 -0
- package/runtime/pi/bin/codex-session-start.sh +188 -0
- package/runtime/pi/bin/codex-skill-render.mjs +323 -0
- package/runtime/pi/bin/codex-sync-skills.sh +227 -0
- package/runtime/pi/bin/dashboard-data.sh +178 -0
- package/runtime/pi/bin/graph-batch.sh +60 -0
- package/runtime/pi/bin/graph-op.sh +431 -0
- package/runtime/pi/bin/graph-wal.sh +228 -0
- package/runtime/pi/bin/graph.sh +177 -0
- package/runtime/pi/bin/handoff-pr-backfill.sh +86 -0
- package/runtime/pi/bin/handoff-run.sh +581 -0
- package/runtime/pi/bin/handoff-save-egregore.sh +136 -0
- package/runtime/pi/bin/index-handoff.sh +312 -0
- package/runtime/pi/bin/lib/artifact-id.sh +46 -0
- package/runtime/pi/bin/lib/config.sh +71 -0
- package/runtime/pi/bin/lib/context.sh +542 -0
- package/runtime/pi/bin/lib/dashboard-artifact.sh +142 -0
- package/runtime/pi/bin/lib/ensure-develop.sh +183 -0
- package/runtime/pi/bin/lib/git-sync.sh +288 -0
- package/runtime/pi/bin/lib/greeting.sh +340 -0
- package/runtime/pi/bin/lib/hash.sh +13 -0
- package/runtime/pi/bin/lib/identity.sh +174 -0
- package/runtime/pi/bin/lib/metrics.sh +374 -0
- package/runtime/pi/bin/lib/permissions.sh +106 -0
- package/runtime/pi/bin/lib/time.sh +56 -0
- package/runtime/pi/bin/lib/worktree-links.sh +54 -0
- package/runtime/pi/bin/notify.sh +207 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +15 -0
- package/runtime/pi/bin/pi-product-workflows.mjs +324 -0
- package/runtime/pi/bin/pi-render-spec.mjs +114 -0
- package/runtime/pi/bin/pi-session-start.sh +24 -0
- package/runtime/pi/bin/publish-artifact.sh +201 -0
- package/runtime/pi/bin/publish-references.sh +144 -0
- package/runtime/pi/bin/repo-state.sh +99 -0
- package/runtime/pi/bin/telemetry.sh +391 -0
- package/runtime/pi/bin/worktree-create.sh +118 -0
- package/runtime/pi/bin/worktree-remove.sh +50 -0
- package/runtime/pi/bin/worktree.sh +198 -0
- package/runtime/pi/manifest.json +176 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// egregore-launcher-version: 0.
|
|
2
|
+
// egregore-launcher-version: 0.7.2
|
|
3
3
|
//
|
|
4
4
|
// egregore — launch and browse Egregore instances from your terminal.
|
|
5
5
|
// Installed by create-egregore. Reads ~/.egregore/instances.json.
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// egregore ls | list list instances (non-interactive table)
|
|
15
15
|
// egregore use <slug> set the default for bare `egregore`
|
|
16
16
|
// egregore /invite <user> invite a GitHub user to an instance
|
|
17
|
+
// egregore settings [slug] hosting on/off, managed repos, admins (s in browser)
|
|
17
18
|
// egregore prune [--dry-run] remove entries whose path is gone
|
|
18
19
|
// egregore rm <slug|path> remove a specific entry
|
|
19
20
|
// egregore browse force the full-screen browser
|
|
@@ -30,7 +31,7 @@ const https = require("node:https");
|
|
|
30
31
|
const { spawnSync, spawn } = require("node:child_process");
|
|
31
32
|
const readline = require("node:readline");
|
|
32
33
|
|
|
33
|
-
const VERSION = "0.
|
|
34
|
+
const VERSION = "0.7.2";
|
|
34
35
|
const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
|
|
35
36
|
const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
|
|
36
37
|
const PUBLIC_NPX_PACKAGE = "create-egregore";
|
|
@@ -263,6 +264,10 @@ function readRegistry() {
|
|
|
263
264
|
for (const e of entries) {
|
|
264
265
|
if (!e || typeof e.path !== "string" || !e.path) continue;
|
|
265
266
|
const key = path.resolve(e.path);
|
|
267
|
+
// Worktrees live under a parent instance's .claude/worktrees/ — they are
|
|
268
|
+
// NOT their own egregore. A session that ran inside one may have registered
|
|
269
|
+
// its cwd; keep those out of the instance list (browser, ls, default).
|
|
270
|
+
if (key.includes("/.claude/worktrees/")) continue;
|
|
266
271
|
if (seen.has(key)) continue;
|
|
267
272
|
seen.add(key);
|
|
268
273
|
result.push(e);
|
|
@@ -345,6 +350,7 @@ function normalizeRuntime(raw) {
|
|
|
345
350
|
if (!value) return null;
|
|
346
351
|
if (value === "claude" || value === "claude-code" || value === "claude_code") return "claude-code";
|
|
347
352
|
if (value === "codex" || value === "openai-codex" || value === "openai_codex") return "codex";
|
|
353
|
+
if (value === "pi" || value === "pi-coding-agent" || value === "pi_coding_agent") return "pi";
|
|
348
354
|
return null;
|
|
349
355
|
}
|
|
350
356
|
|
|
@@ -355,6 +361,8 @@ function parseRuntimeFlags(argv) {
|
|
|
355
361
|
const arg = argv[i];
|
|
356
362
|
if (arg === "--codex") {
|
|
357
363
|
runtimeOverride = "codex";
|
|
364
|
+
} else if (arg === "--pi") {
|
|
365
|
+
runtimeOverride = "pi";
|
|
358
366
|
} else if (arg === "--claude" || arg === "--claude-code") {
|
|
359
367
|
runtimeOverride = "claude-code";
|
|
360
368
|
} else if (arg === "--runtime") {
|
|
@@ -368,7 +376,7 @@ function parseRuntimeFlags(argv) {
|
|
|
368
376
|
}
|
|
369
377
|
}
|
|
370
378
|
const normalized = runtimeOverride ? normalizeRuntime(runtimeOverride) : null;
|
|
371
|
-
if (runtimeOverride && !normalized) die(`unknown runtime: ${runtimeOverride}\n expected claude-code or
|
|
379
|
+
if (runtimeOverride && !normalized) die(`unknown runtime: ${runtimeOverride}\n expected claude-code, codex, or pi`);
|
|
372
380
|
return { args: rest, runtimeOverride: normalized };
|
|
373
381
|
}
|
|
374
382
|
|
|
@@ -385,21 +393,32 @@ function runtimeFor(inst, runtimeOverride) {
|
|
|
385
393
|
}
|
|
386
394
|
|
|
387
395
|
function runtimeLabel(runtime) {
|
|
388
|
-
|
|
396
|
+
if (runtime === "codex") return "Codex";
|
|
397
|
+
if (runtime === "pi") return "Pi";
|
|
398
|
+
return "Claude Code";
|
|
389
399
|
}
|
|
390
400
|
|
|
391
401
|
function runtimeShort(runtime) {
|
|
392
|
-
return runtime === "codex" ? "codex" : "claude-code";
|
|
402
|
+
return runtime === "codex" ? "codex" : runtime === "pi" ? "pi" : "claude-code";
|
|
393
403
|
}
|
|
394
404
|
|
|
395
405
|
function runtimeBinary(runtime) {
|
|
396
|
-
return runtime === "codex" ? "codex" : "claude";
|
|
406
|
+
return runtime === "codex" ? "codex" : runtime === "pi" ? "pi" : "claude";
|
|
397
407
|
}
|
|
398
408
|
|
|
399
409
|
function assistantInstallCommand(runtime) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
410
|
+
if (runtime === "codex") return "npm install -g @openai/codex";
|
|
411
|
+
if (runtime === "pi") return "npm install -g --ignore-scripts @earendil-works/pi-coding-agent";
|
|
412
|
+
return "npm install -g @anthropic-ai/claude-code";
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function piTrustArgs() {
|
|
416
|
+
try {
|
|
417
|
+
const help = spawnSync("pi", ["--help"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
418
|
+
return `${help.stdout || ""}\n${help.stderr || ""}`.includes("--approve") ? ["--approve"] : [];
|
|
419
|
+
} catch {
|
|
420
|
+
return [];
|
|
421
|
+
}
|
|
403
422
|
}
|
|
404
423
|
|
|
405
424
|
function commandExists(bin) {
|
|
@@ -410,13 +429,12 @@ function runtimeChoiceDescription(runtime, inst, stored) {
|
|
|
410
429
|
const installed = commandExists(runtimeBinary(runtime));
|
|
411
430
|
const bits = [];
|
|
412
431
|
if (!installed) {
|
|
413
|
-
return runtime
|
|
414
|
-
? "not installed · install Codex, then run egregore"
|
|
415
|
-
: "not installed · install Claude Code, then run egregore";
|
|
432
|
+
return `not installed · install ${runtimeLabel(runtime)}, then run egregore`;
|
|
416
433
|
}
|
|
417
434
|
bits.push("installed");
|
|
418
435
|
if (runtime === stored) bits.push("saved default");
|
|
419
436
|
if (runtime === "codex") bits.push("portable agent protocol");
|
|
437
|
+
else if (runtime === "pi") bits.push("project-local meta-harness");
|
|
420
438
|
else bits.push("Claude Code integration");
|
|
421
439
|
return bits.join(" · ");
|
|
422
440
|
}
|
|
@@ -439,7 +457,7 @@ function runtimePickerLines(inst, runtimes, stored, cursor) {
|
|
|
439
457
|
lines.push(` ${marker} ${BOLD}${label}${RESET} ${DIM}${desc}${RESET}`);
|
|
440
458
|
}
|
|
441
459
|
// Coming-soon harnesses — shown for visibility, not selectable yet.
|
|
442
|
-
for (const soon of ["Hermes"
|
|
460
|
+
for (const soon of ["Hermes"]) {
|
|
443
461
|
lines.push(` ${DIM}· ${pad(soon, labelWidth)} coming soon${RESET}`);
|
|
444
462
|
}
|
|
445
463
|
lines.push("");
|
|
@@ -529,9 +547,7 @@ function runtimeChoicesFor(inst, runtimeOverride) {
|
|
|
529
547
|
const override = normalizeRuntime(runtimeOverride);
|
|
530
548
|
if (override) return [override];
|
|
531
549
|
const stored = storedRuntimeFor(inst);
|
|
532
|
-
const choices = stored
|
|
533
|
-
? ["codex", "claude-code"]
|
|
534
|
-
: ["claude-code", "codex"];
|
|
550
|
+
const choices = [stored, ...["claude-code", "codex", "pi"].filter((runtime) => runtime !== stored)];
|
|
535
551
|
return choices.sort((a, b) => Number(commandExists(runtimeBinary(b))) - Number(commandExists(runtimeBinary(a))));
|
|
536
552
|
}
|
|
537
553
|
|
|
@@ -637,6 +653,25 @@ function hasCodexCoreSupport(egregoreDir) {
|
|
|
637
653
|
);
|
|
638
654
|
}
|
|
639
655
|
|
|
656
|
+
function hasPiCoreSupport(egregoreDir) {
|
|
657
|
+
return (
|
|
658
|
+
fs.existsSync(path.join(egregoreDir, "bin", "pi-session-start.sh")) &&
|
|
659
|
+
fs.existsSync(path.join(egregoreDir, ".pi", "APPEND_SYSTEM.md")) &&
|
|
660
|
+
fs.existsSync(path.join(egregoreDir, ".pi", "settings.json")) &&
|
|
661
|
+
fs.existsSync(path.join(egregoreDir, ".pi", "extensions", "egregore.ts")) &&
|
|
662
|
+
fs.existsSync(path.join(egregoreDir, ".codex", "skills"))
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function piSupportMessage(egregoreDir) {
|
|
667
|
+
return [
|
|
668
|
+
"Pi meta-harness support is missing from this Egregore checkout.",
|
|
669
|
+
` path: ${egregoreDir}`,
|
|
670
|
+
"",
|
|
671
|
+
"Run npx -y create-egregore@latest to install the packaged Pi runtime, then rerun egregore.",
|
|
672
|
+
].join("\n");
|
|
673
|
+
}
|
|
674
|
+
|
|
640
675
|
function installCodexSkills(egregoreDir) {
|
|
641
676
|
const script = path.join(egregoreDir, "bin", "codex-install-skills.sh");
|
|
642
677
|
if (!fs.existsSync(script)) return false;
|
|
@@ -662,6 +697,7 @@ function runtimeLaunchArgs(runtime, egregoreDir) {
|
|
|
662
697
|
"--cd", egregoreDir,
|
|
663
698
|
];
|
|
664
699
|
}
|
|
700
|
+
if (runtime === "pi") return piTrustArgs();
|
|
665
701
|
return ["start"];
|
|
666
702
|
}
|
|
667
703
|
|
|
@@ -695,6 +731,8 @@ async function launch(inst, runtimeOverride) {
|
|
|
695
731
|
if (!skillsInstalled || !cardRendered) {
|
|
696
732
|
die(codexSupportMessage(inst.path));
|
|
697
733
|
}
|
|
734
|
+
} else if (runtime === "pi") {
|
|
735
|
+
if (!hasPiCoreSupport(inst.path)) die(piSupportMessage(inst.path));
|
|
698
736
|
}
|
|
699
737
|
// Replace the current process with the selected assistant in the instance dir.
|
|
700
738
|
// spawn + detached + exit-on-exit replicates exec() in Node.
|
|
@@ -822,10 +860,12 @@ function cmdHelp() {
|
|
|
822
860
|
` ${CYAN}egregore${RESET} pick an instance, then pick a harness`,
|
|
823
861
|
` ${CYAN}egregore${RESET} ${DIM}<slug|name>${RESET} pick a harness for the matching instance`,
|
|
824
862
|
` ${CYAN}egregore --runtime${RESET} ${DIM}<name> <slug>${RESET} advanced harness override`,
|
|
863
|
+
` ${DIM}names: claude-code · codex · pi${RESET}`,
|
|
825
864
|
` ${CYAN}egregore browse${RESET} force the full-screen browser`,
|
|
826
865
|
` ${CYAN}egregore ls${RESET} ${DIM}| list${RESET} list installed instances`,
|
|
827
866
|
` ${CYAN}egregore use${RESET} ${DIM}<slug>${RESET} set the default for bare ${BOLD}egregore${RESET}`,
|
|
828
867
|
` ${CYAN}egregore /invite${RESET} ${DIM}<user> [slug]${RESET} invite a GitHub user`,
|
|
868
|
+
` ${CYAN}egregore settings${RESET} ${DIM}[slug]${RESET} hosting on/off, repos, admins`,
|
|
829
869
|
` ${CYAN}egregore prune${RESET} ${DIM}[--dry-run]${RESET} remove entries with missing paths`,
|
|
830
870
|
` ${CYAN}egregore rm${RESET} ${DIM}<slug|path>${RESET} remove a specific entry`,
|
|
831
871
|
``,
|
|
@@ -836,6 +876,7 @@ function cmdHelp() {
|
|
|
836
876
|
` ${DIM}n / +${RESET} create a new Egregore`,
|
|
837
877
|
` ${DIM}u${RESET} set selected as default`,
|
|
838
878
|
` ${DIM}i${RESET} invite a GitHub user to selected instance`,
|
|
879
|
+
` ${DIM}s${RESET} settings (hosting on/off, repos, admins)`,
|
|
839
880
|
` ${DIM}d${RESET} delete selected entry (offers cleanup of ${RED}✗${RESET} missing ones)`,
|
|
840
881
|
` ${DIM}?${RESET} toggle help overlay`,
|
|
841
882
|
` ${DIM}q${RESET} quit browser (esc goes back — it never quits)`,
|
|
@@ -1251,6 +1292,343 @@ async function cmdInvite(args) {
|
|
|
1251
1292
|
return inviteToInstance(inst, username);
|
|
1252
1293
|
}
|
|
1253
1294
|
|
|
1295
|
+
// ── settings ───────────────────────────────────────────────────────
|
|
1296
|
+
//
|
|
1297
|
+
// The launcher stays a THIN caller: every config change shells out to the
|
|
1298
|
+
// instance's deterministic `bin/settings.sh` verbs (one source of truth, no
|
|
1299
|
+
// JS reimplementation to drift from the script). This is the reliability point
|
|
1300
|
+
// — the correctness lives in the tested script; the screen below just drives it.
|
|
1301
|
+
|
|
1302
|
+
function settingsScriptPath(inst) {
|
|
1303
|
+
return path.join(inst.path, "bin", "settings.sh");
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
function runSettings(inst, args) {
|
|
1307
|
+
const script = settingsScriptPath(inst);
|
|
1308
|
+
if (!fs.existsSync(script)) {
|
|
1309
|
+
return { status: 127, stdout: "", stderr: "bin/settings.sh not found — update this egregore (run /pull) to get settings.\n", missing: true };
|
|
1310
|
+
}
|
|
1311
|
+
try {
|
|
1312
|
+
return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 15000 });
|
|
1313
|
+
} catch (err) {
|
|
1314
|
+
return { status: 1, stdout: "", stderr: String(err) };
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
function settingsDump(inst) {
|
|
1319
|
+
const r = runSettings(inst, ["dump"]);
|
|
1320
|
+
if (!r || r.status !== 0) return null;
|
|
1321
|
+
try { return JSON.parse(r.stdout); } catch { return null; }
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// Nested raw-mode list editor for a domain (repo | admin | people): hover an
|
|
1325
|
+
// item and press `d` to remove it, `a` to open an inline add field, esc to go
|
|
1326
|
+
// back. Mirrors the main browser's affordances. Its own raw-mode loop; resolves
|
|
1327
|
+
// when the user backs out. Each mutation is ONE deterministic settings.sh verb;
|
|
1328
|
+
// validation, the last-admin guard, and GitHub-access notes surface as notices.
|
|
1329
|
+
function listEditor(inst, domain, label) {
|
|
1330
|
+
const fieldFor = (d) => {
|
|
1331
|
+
if (domain === "repo") return (d.repos || []).map((r) => r.name || r);
|
|
1332
|
+
if (domain === "admin") return d.admins || [];
|
|
1333
|
+
return d.people || [];
|
|
1334
|
+
};
|
|
1335
|
+
const noun = domain === "repo" ? "repo name" : "github handle";
|
|
1336
|
+
|
|
1337
|
+
return new Promise((resolve) => {
|
|
1338
|
+
let items = fieldFor(settingsDump(inst) || {});
|
|
1339
|
+
let cursor = 0;
|
|
1340
|
+
let mode = "browse"; // browse | add | confirm
|
|
1341
|
+
let input = "";
|
|
1342
|
+
let notice = "";
|
|
1343
|
+
let rendered = 0;
|
|
1344
|
+
let done = false;
|
|
1345
|
+
const previousRaw = !!process.stdin.isRaw;
|
|
1346
|
+
const isMouseEvent = makeMouseFilter();
|
|
1347
|
+
|
|
1348
|
+
const refresh = () => {
|
|
1349
|
+
items = fieldFor(settingsDump(inst) || {});
|
|
1350
|
+
if (cursor >= items.length) cursor = Math.max(0, items.length - 1);
|
|
1351
|
+
};
|
|
1352
|
+
|
|
1353
|
+
const erase = () => {
|
|
1354
|
+
if (!rendered) return;
|
|
1355
|
+
process.stdout.write(`\x1b[${rendered}A` + ANSI.clearDown);
|
|
1356
|
+
rendered = 0;
|
|
1357
|
+
};
|
|
1358
|
+
|
|
1359
|
+
const buildLines = () => {
|
|
1360
|
+
const out = [];
|
|
1361
|
+
out.push(``);
|
|
1362
|
+
out.push(` ${BOLD}${label}${RESET}`);
|
|
1363
|
+
out.push(` ${DIM}────────────────────────────────────────${RESET}`);
|
|
1364
|
+
if (items.length === 0) {
|
|
1365
|
+
out.push(` ${DIM}(none)${RESET}`);
|
|
1366
|
+
} else {
|
|
1367
|
+
items.forEach((it, i) => {
|
|
1368
|
+
const sel = i === cursor;
|
|
1369
|
+
out.push(` ${sel ? CYAN + "❯" + RESET : " "} ${sel ? BOLD + it + RESET : it}`);
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
out.push(``);
|
|
1373
|
+
if (notice) out.push(` ${notice}`);
|
|
1374
|
+
if (mode === "add") {
|
|
1375
|
+
out.push(` ${CYAN}add ${noun}:${RESET} ${input}${CYAN}▌${RESET} ${DIM}enter save · esc cancel${RESET}`);
|
|
1376
|
+
} else if (mode === "confirm") {
|
|
1377
|
+
out.push(` ${YELLOW}remove ${items[cursor]}?${RESET} ${DIM}y / N${RESET}`);
|
|
1378
|
+
} else {
|
|
1379
|
+
out.push(` ${DIM}↑↓ nav · ${RESET}${BOLD}a${RESET}${DIM} add · ${RESET}${BOLD}d${RESET}${DIM} delete · esc back${RESET}`);
|
|
1380
|
+
}
|
|
1381
|
+
return out;
|
|
1382
|
+
};
|
|
1383
|
+
|
|
1384
|
+
const render = () => {
|
|
1385
|
+
erase();
|
|
1386
|
+
const lines = buildLines();
|
|
1387
|
+
rendered = lines.length;
|
|
1388
|
+
process.stdout.write(lines.map((l) => l + ANSI.clearLine).join("\n") + "\n");
|
|
1389
|
+
};
|
|
1390
|
+
|
|
1391
|
+
const cleanup = () => {
|
|
1392
|
+
if (done) return;
|
|
1393
|
+
done = true;
|
|
1394
|
+
process.stdin.removeListener("keypress", onKey);
|
|
1395
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1396
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(previousRaw);
|
|
1397
|
+
if (!previousRaw) process.stdin.pause();
|
|
1398
|
+
erase();
|
|
1399
|
+
};
|
|
1400
|
+
|
|
1401
|
+
// Run a verb (spawnSync blocks briefly — people ops hit GitHub). Surface the
|
|
1402
|
+
// last stdout/stderr line as a notice; refresh the list from disk after.
|
|
1403
|
+
const runVerb = (args) => {
|
|
1404
|
+
const r = runSettings(inst, args);
|
|
1405
|
+
const msg = ((r.stdout || "") + " " + (r.stderr || "")).trim().split("\n").map((s) => s.trim()).filter(Boolean).pop() || "";
|
|
1406
|
+
notice = r && r.status === 0 ? msg : `${YELLOW}${msg}${RESET}`;
|
|
1407
|
+
refresh();
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
function onKey(chunk, key = {}) {
|
|
1411
|
+
if (isMouseEvent(chunk, key)) return;
|
|
1412
|
+
if (key.ctrl && key.name === "c") { cleanup(); process.exit(130); }
|
|
1413
|
+
|
|
1414
|
+
if (mode === "add") {
|
|
1415
|
+
if (key.name === "escape") { mode = "browse"; input = ""; render(); return; }
|
|
1416
|
+
if (key.name === "return") {
|
|
1417
|
+
const v = input.trim().split(/\s+/)[0];
|
|
1418
|
+
mode = "browse"; input = "";
|
|
1419
|
+
if (v) runVerb([domain, "add", v]);
|
|
1420
|
+
render();
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
if (key.name === "backspace") { input = input.slice(0, -1); render(); return; }
|
|
1424
|
+
if (chunk && chunk.length === 1 && chunk >= " " && !key.ctrl && !key.meta) { input += chunk; render(); return; }
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
if (mode === "confirm") {
|
|
1429
|
+
if (chunk === "y" || chunk === "Y") {
|
|
1430
|
+
const victim = items[cursor];
|
|
1431
|
+
mode = "browse";
|
|
1432
|
+
if (victim) runVerb([domain, "remove", victim]);
|
|
1433
|
+
} else { mode = "browse"; }
|
|
1434
|
+
render();
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// browse
|
|
1439
|
+
if (key.name === "escape" || key.name === "left") { cleanup(); resolve(); return; }
|
|
1440
|
+
if (key.name === "up" || key.name === "k") { if (items.length) cursor = (cursor - 1 + items.length) % items.length; render(); return; }
|
|
1441
|
+
if (key.name === "down" || key.name === "j") { if (items.length) cursor = (cursor + 1) % items.length; render(); return; }
|
|
1442
|
+
if (chunk === "a") { mode = "add"; input = ""; notice = ""; render(); return; }
|
|
1443
|
+
if (chunk === "d") { if (items.length) { mode = "confirm"; render(); } return; }
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
readline.emitKeypressEvents(process.stdin);
|
|
1447
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
1448
|
+
process.stdin.resume();
|
|
1449
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1450
|
+
process.stdin.on("keypress", onKey);
|
|
1451
|
+
render();
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// The `s`-key settings screen: a raw-mode menu (hosting toggle + repo/admin
|
|
1456
|
+
// editors) over bin/settings.sh. Modeled on pickRuntimeInteractive.
|
|
1457
|
+
function settingsScreen(inst) {
|
|
1458
|
+
const title = inst.slug || inst.name || path.basename(inst.path);
|
|
1459
|
+
|
|
1460
|
+
if (!fs.existsSync(settingsScriptPath(inst))) {
|
|
1461
|
+
console.log(`\n ${YELLOW}Settings unavailable${RESET} — ${BOLD}${title}${RESET} has no ${DIM}bin/settings.sh${RESET}.`);
|
|
1462
|
+
console.log(` Update it: open the egregore and run ${CYAN}/pull${RESET}.\n`);
|
|
1463
|
+
return Promise.resolve();
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
let data = settingsDump(inst) || { hosting: true, repos: [], admins: [], people: [] };
|
|
1467
|
+
|
|
1468
|
+
const rows = [
|
|
1469
|
+
{
|
|
1470
|
+
label: () => `Hosted Artifacts`,
|
|
1471
|
+
value: () => (data.hosting ? `${GREEN}ON${RESET}` : `${YELLOW}OFF${RESET}`),
|
|
1472
|
+
detailLines: () => [data.hosting
|
|
1473
|
+
? ` ${DIM}Enter toggles. When OFF, artifacts never upload to egregore.xyz.${RESET}`
|
|
1474
|
+
: ` ${DIM}Artifacts stay local. /view still renders them on localhost.${RESET}`],
|
|
1475
|
+
},
|
|
1476
|
+
{
|
|
1477
|
+
label: () => `Managed repos`,
|
|
1478
|
+
value: () => `${DIM}${data.repos.length}${RESET}`,
|
|
1479
|
+
detailLines: () => data.repos.length
|
|
1480
|
+
? data.repos.map((r) => ` ${DIM}·${RESET} ${r.name || r}`)
|
|
1481
|
+
: [` ${DIM}(none)${RESET}`],
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
label: () => `Admins`,
|
|
1485
|
+
value: () => `${DIM}${data.admins.length}${RESET}`,
|
|
1486
|
+
detailLines: () => data.admins.length
|
|
1487
|
+
? [` ${DIM}${data.admins.join(", ")}${RESET}`]
|
|
1488
|
+
: [` ${DIM}(none)${RESET}`],
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
label: () => `People`,
|
|
1492
|
+
value: () => `${DIM}${(data.people || []).length}${RESET}`,
|
|
1493
|
+
detailLines: () => (data.people && data.people.length)
|
|
1494
|
+
? [` ${DIM}${data.people.join(", ")}${RESET}`]
|
|
1495
|
+
: [` ${DIM}(none)${RESET}`],
|
|
1496
|
+
},
|
|
1497
|
+
];
|
|
1498
|
+
|
|
1499
|
+
return new Promise((resolve) => {
|
|
1500
|
+
let cursor = 0;
|
|
1501
|
+
let rendered = 0;
|
|
1502
|
+
let done = false;
|
|
1503
|
+
let notice = "";
|
|
1504
|
+
const previousRaw = !!process.stdin.isRaw;
|
|
1505
|
+
const isMouseEvent = makeMouseFilter();
|
|
1506
|
+
|
|
1507
|
+
const erase = () => {
|
|
1508
|
+
if (!rendered) return;
|
|
1509
|
+
// Move to the TOP of the last-rendered block, then wipe everything below
|
|
1510
|
+
// in one shot. Clearing line-by-line leaves the cursor at the BOTTOM, so
|
|
1511
|
+
// the next redraw starts a row lower each time — that's the drift that
|
|
1512
|
+
// pushes blank "margins" on top. Up-N + clearDown returns to the top and
|
|
1513
|
+
// clears cleanly, so every render repaints in place.
|
|
1514
|
+
process.stdout.write(`\x1b[${rendered}A` + ANSI.clearDown);
|
|
1515
|
+
rendered = 0;
|
|
1516
|
+
};
|
|
1517
|
+
|
|
1518
|
+
const buildLines = () => {
|
|
1519
|
+
const out = [];
|
|
1520
|
+
out.push(``);
|
|
1521
|
+
out.push(` ${BOLD}Settings${RESET} ${DIM}·${RESET} ${BOLD}${title}${RESET}`);
|
|
1522
|
+
out.push(` ${DIM}────────────────────────────────────────${RESET}`);
|
|
1523
|
+
rows.forEach((row, i) => {
|
|
1524
|
+
const sel = i === cursor;
|
|
1525
|
+
const marker = sel ? `${CYAN}❯${RESET}` : ` `;
|
|
1526
|
+
const name = sel ? `${BOLD}${row.label()}${RESET}` : row.label();
|
|
1527
|
+
out.push(` ${marker} ${name} ${row.value()}`);
|
|
1528
|
+
if (sel) for (const dl of row.detailLines()) out.push(dl);
|
|
1529
|
+
});
|
|
1530
|
+
out.push(``);
|
|
1531
|
+
if (notice) out.push(` ${notice}`);
|
|
1532
|
+
out.push(` ${DIM}↑↓ nav · enter ${cursor === 0 ? "toggle" : "edit"} · esc back · q quit${RESET}`);
|
|
1533
|
+
return out;
|
|
1534
|
+
};
|
|
1535
|
+
|
|
1536
|
+
const render = () => {
|
|
1537
|
+
erase();
|
|
1538
|
+
const lines = buildLines();
|
|
1539
|
+
rendered = lines.length;
|
|
1540
|
+
process.stdout.write(lines.map((l) => l + ANSI.clearLine).join("\n") + "\n");
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1543
|
+
const teardownRaw = () => {
|
|
1544
|
+
process.stdin.removeListener("keypress", onKey);
|
|
1545
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1546
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(previousRaw);
|
|
1547
|
+
if (!previousRaw) process.stdin.pause();
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1550
|
+
const setupRaw = () => {
|
|
1551
|
+
readline.emitKeypressEvents(process.stdin);
|
|
1552
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
1553
|
+
process.stdin.resume();
|
|
1554
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1555
|
+
process.stdin.on("keypress", onKey);
|
|
1556
|
+
};
|
|
1557
|
+
|
|
1558
|
+
const cleanup = () => {
|
|
1559
|
+
if (done) return;
|
|
1560
|
+
done = true;
|
|
1561
|
+
teardownRaw();
|
|
1562
|
+
erase();
|
|
1563
|
+
};
|
|
1564
|
+
|
|
1565
|
+
const toggleHosting = () => {
|
|
1566
|
+
const r = runSettings(inst, ["hosting", data.hosting ? "off" : "on"]);
|
|
1567
|
+
if (!r || r.status !== 0) {
|
|
1568
|
+
notice = `${YELLOW}${((r && r.stderr) || "could not change hosting").trim().split("\n")[0]}${RESET}`;
|
|
1569
|
+
} else {
|
|
1570
|
+
data = settingsDump(inst) || data;
|
|
1571
|
+
notice = `hosting ${data.hosting ? `${GREEN}ON${RESET}` : `${YELLOW}OFF${RESET}`}`;
|
|
1572
|
+
}
|
|
1573
|
+
render();
|
|
1574
|
+
};
|
|
1575
|
+
|
|
1576
|
+
// Hand off to the nested raw-mode list editor, then repaint this screen with
|
|
1577
|
+
// refreshed counts when the user backs out.
|
|
1578
|
+
const openList = (domain, label) => {
|
|
1579
|
+
erase();
|
|
1580
|
+
teardownRaw();
|
|
1581
|
+
listEditor(inst, domain, label).then(() => {
|
|
1582
|
+
data = settingsDump(inst) || data;
|
|
1583
|
+
notice = "";
|
|
1584
|
+
setupRaw();
|
|
1585
|
+
render();
|
|
1586
|
+
});
|
|
1587
|
+
};
|
|
1588
|
+
|
|
1589
|
+
function onKey(chunk, key = {}) {
|
|
1590
|
+
if (isMouseEvent(chunk, key)) return;
|
|
1591
|
+
if (key.ctrl && key.name === "c") { cleanup(); process.exit(130); }
|
|
1592
|
+
if (key.name === "q") { cleanup(); resolve(); return; }
|
|
1593
|
+
// Esc / ← = back (esc never quits).
|
|
1594
|
+
if (key.name === "escape" || key.name === "left") { cleanup(); resolve(); return; }
|
|
1595
|
+
if (key.name === "up" || key.name === "k") { cursor = (cursor - 1 + rows.length) % rows.length; render(); return; }
|
|
1596
|
+
if (key.name === "down" || key.name === "j") { cursor = (cursor + 1) % rows.length; render(); return; }
|
|
1597
|
+
if (key.name === "return" || chunk === " ") {
|
|
1598
|
+
if (cursor === 0) toggleHosting();
|
|
1599
|
+
else if (cursor === 1) openList("repo", "Managed repos");
|
|
1600
|
+
else if (cursor === 2) openList("admin", "Admins");
|
|
1601
|
+
else if (cursor === 3) openList("people", "People");
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
setupRaw();
|
|
1606
|
+
render();
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
async function cmdSettings(args) {
|
|
1611
|
+
const registry = readRegistry();
|
|
1612
|
+
if (registry.length === 0) die("no egregores installed yet.\n run: npx -y create-egregore@latest");
|
|
1613
|
+
const DOMAINS = new Set(["hosting", "repo", "admin", "people", "dump"]);
|
|
1614
|
+
let rest = args.slice();
|
|
1615
|
+
let slug = "";
|
|
1616
|
+
if (rest.length && !DOMAINS.has(rest[0])) { slug = rest[0]; rest = rest.slice(1); }
|
|
1617
|
+
const inst = resolveInviteInstance(registry, slug);
|
|
1618
|
+
if (!inst) {
|
|
1619
|
+
die(`multiple egregores installed; choose one:\n egregore settings <slug> [hosting|repo|admin]\n run: egregore ls`);
|
|
1620
|
+
}
|
|
1621
|
+
// No verb + a TTY → interactive screen. Otherwise forward straight to the verb.
|
|
1622
|
+
if (rest.length === 0) {
|
|
1623
|
+
if (isTTY && canPrompt()) return settingsScreen(inst);
|
|
1624
|
+
rest = ["dump"];
|
|
1625
|
+
}
|
|
1626
|
+
const r = runSettings(inst, rest);
|
|
1627
|
+
if (r.stdout) process.stdout.write(r.stdout.endsWith("\n") ? r.stdout : r.stdout + "\n");
|
|
1628
|
+
if (r.stderr) process.stderr.write(r.stderr);
|
|
1629
|
+
process.exitCode = r.status || 0;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1254
1632
|
// ── tiny sync confirm (non-TUI flows) ───────────────────────────────
|
|
1255
1633
|
|
|
1256
1634
|
function syncConfirm(question) {
|
|
@@ -1370,7 +1748,7 @@ function renderHeroPanel({ selected, pv, width, height, countSuffix, filter, fil
|
|
|
1370
1748
|
? `filter /${filter}`
|
|
1371
1749
|
: "press ? for help";
|
|
1372
1750
|
const canShowBigLogo = bodyWidth >= Math.max(...EGREGORE_ART.map((line) => line.length)) && height >= 24;
|
|
1373
|
-
const skillStatus = `Codex ${nativeCount} native · ${adapterCount} adapter · ${skillsCount}
|
|
1751
|
+
const skillStatus = `Codex ${nativeCount} native · ${adapterCount} adapter · Pi ${skillsCount} shared · Claude ${claudeCount}`;
|
|
1374
1752
|
const skillGroups = [
|
|
1375
1753
|
`${DIM}core${RESET}: ${workflows}`,
|
|
1376
1754
|
`${DIM}team${RESET}: ${joinShort(["/handoff", "/ask", "/invite", "/quest"], Math.max(16, bodyWidth - 8))}`,
|
|
@@ -1411,8 +1789,8 @@ function renderHeroPanel({ selected, pv, width, height, countSuffix, filter, fil
|
|
|
1411
1789
|
`${BOLD}Harnesses${RESET}`,
|
|
1412
1790
|
`${DIM}claude-code${RESET}: ${commandExists("claude") ? "installed" : "not installed"}`,
|
|
1413
1791
|
`${DIM}codex${RESET}: ${commandExists("codex") ? "installed" : "not installed"}`,
|
|
1792
|
+
`${DIM}pi${RESET}: ${commandExists("pi") ? "installed" : "not installed"}`,
|
|
1414
1793
|
`${DIM}Hermes — Coming Soon${RESET}`,
|
|
1415
|
-
`${DIM}Pi — Coming Soon${RESET}`,
|
|
1416
1794
|
];
|
|
1417
1795
|
const rows = Math.max(EGREGORE_SIGIL.length + 2, right.length);
|
|
1418
1796
|
for (let i = 0; i < rows; i++) {
|
|
@@ -1424,11 +1802,11 @@ function renderHeroPanel({ selected, pv, width, height, countSuffix, filter, fil
|
|
|
1424
1802
|
lines.push(boxLine(`${BOLD}Available Skills${RESET}`, innerWidth, margin));
|
|
1425
1803
|
for (const group of skillGroups) lines.push(boxLine(group, innerWidth, margin));
|
|
1426
1804
|
lines.push(emptyBoxLine(innerWidth, margin));
|
|
1427
|
-
lines.push(boxLine(`${BOLD}Harnesses${RESET} ${DIM}claude-code${RESET} ${commandExists("claude") ? "installed" : "missing"} · ${DIM}codex${RESET} ${commandExists("codex") ? "installed" : "missing"} · ${DIM}Hermes
|
|
1805
|
+
lines.push(boxLine(`${BOLD}Harnesses${RESET} ${DIM}claude-code${RESET} ${commandExists("claude") ? "installed" : "missing"} · ${DIM}codex${RESET} ${commandExists("codex") ? "installed" : "missing"} · ${DIM}pi${RESET} ${commandExists("pi") ? "installed" : "missing"} · ${DIM}Hermes — Coming Soon${RESET}`, innerWidth, margin));
|
|
1428
1806
|
}
|
|
1429
1807
|
|
|
1430
1808
|
lines.push(emptyBoxLine(innerWidth, margin));
|
|
1431
|
-
lines.push(boxLine(`${DIM}enter selects an instance, then choose Claude Code or
|
|
1809
|
+
lines.push(boxLine(`${DIM}enter selects an instance, then choose Claude Code, Codex, or Pi without leaving this screen${RESET}`, innerWidth, margin));
|
|
1432
1810
|
lines.push(bottom);
|
|
1433
1811
|
return lines;
|
|
1434
1812
|
}
|
|
@@ -1461,7 +1839,7 @@ function renderRuntimePanel({ inst, cursor, width, height }) {
|
|
|
1461
1839
|
lines.push(boxLine(`${marker} ${pad(labelText, 16)} ${DIM}${desc}${RESET}`, innerWidth, margin));
|
|
1462
1840
|
}
|
|
1463
1841
|
// Coming-soon harnesses — shown for visibility, not selectable yet.
|
|
1464
|
-
for (const soon of ["Hermes"
|
|
1842
|
+
for (const soon of ["Hermes"]) {
|
|
1465
1843
|
lines.push(boxLine(`${DIM}· ${pad(soon, 16)} coming soon${RESET}`, innerWidth, margin));
|
|
1466
1844
|
}
|
|
1467
1845
|
|
|
@@ -1674,7 +2052,7 @@ async function browser(args = {}) {
|
|
|
1674
2052
|
const label = (k) => `${DIM}${pad(k, 10)}${RESET}`;
|
|
1675
2053
|
previewLines.push(` ${label("action")} ${BOLD}Set up a new Egregore${RESET}`);
|
|
1676
2054
|
previewLines.push(` ${label("flow")} guided install, Telegram, invite, ready/start`);
|
|
1677
|
-
previewLines.push(` ${label("harness")} choose Claude Code or
|
|
2055
|
+
previewLines.push(` ${label("harness")} choose Claude Code, Codex, or Pi during setup`);
|
|
1678
2056
|
previewLines.push(` ${label("start")} press enter to begin`);
|
|
1679
2057
|
} else if (!selected) {
|
|
1680
2058
|
previewLines.push(`${DIM} (no selection)${RESET}`);
|
|
@@ -1697,7 +2075,7 @@ async function browser(args = {}) {
|
|
|
1697
2075
|
if (pv.skills) {
|
|
1698
2076
|
const skillLine = selectedWorkflowLine(pv, Math.max(16, blockWidth - 20));
|
|
1699
2077
|
previewLines.push(` ${label("invoke")} ${skillLine}`);
|
|
1700
|
-
previewLines.push(` ${label("skills")} Codex ${BOLD}${pv.skills.native.length}${RESET} native
|
|
2078
|
+
previewLines.push(` ${label("skills")} Codex ${BOLD}${pv.skills.native.length}${RESET} native + ${BOLD}${pv.skills.adapterCount}${RESET} adapters; Pi ${BOLD}${pv.skills.names.length}${RESET} shared; Claude ${BOLD}${pv.skills.claudeCount || 0}${RESET}`);
|
|
1701
2079
|
}
|
|
1702
2080
|
const modeBits = [];
|
|
1703
2081
|
modeBits.push(runtimeShort(runtimeFor(selected, args.runtimeOverride)));
|
|
@@ -1757,8 +2135,8 @@ async function browser(args = {}) {
|
|
|
1757
2135
|
footer = band(`● ${stripAnsi(state.message)}`, bg);
|
|
1758
2136
|
} else {
|
|
1759
2137
|
footer = blockWidth < 96
|
|
1760
|
-
? band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("i", "invite")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46)
|
|
1761
|
-
: band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("/", "filter")} ${key("i", "invite")} ${key("u", "default")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46);
|
|
2138
|
+
? band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("i", "invite")} ${key("s", "settings")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46)
|
|
2139
|
+
: band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("/", "filter")} ${key("i", "invite")} ${key("s", "settings")} ${key("u", "default")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46);
|
|
1762
2140
|
}
|
|
1763
2141
|
out.push(M + footer + "\n");
|
|
1764
2142
|
if (state.showHelp) {
|
|
@@ -2056,6 +2434,13 @@ async function browser(args = {}) {
|
|
|
2056
2434
|
render();
|
|
2057
2435
|
return;
|
|
2058
2436
|
}
|
|
2437
|
+
if (chunk === "s") {
|
|
2438
|
+
const pick = visible()[state.cursor]?.e;
|
|
2439
|
+
if (!pick) return;
|
|
2440
|
+
cleanup();
|
|
2441
|
+
resolve(settingsScreen(pick));
|
|
2442
|
+
return;
|
|
2443
|
+
}
|
|
2059
2444
|
if (chunk === "u") {
|
|
2060
2445
|
const pick = visible()[state.cursor]?.e;
|
|
2061
2446
|
if (!pick) return;
|
|
@@ -2174,6 +2559,7 @@ function main() {
|
|
|
2174
2559
|
if (cmd === "ls" || cmd === "list") return cmdLs();
|
|
2175
2560
|
if (cmd === "use") return cmdUse(args[1]);
|
|
2176
2561
|
if (cmd === "/invite" || cmd === "invite") return cmdInvite(args.slice(1));
|
|
2562
|
+
if (cmd === "settings" || cmd === "config") return cmdSettings(args.slice(1));
|
|
2177
2563
|
if (cmd === "prune") return cmdPruneNonInteractive(args[1] === "--dry-run" || args[1] === "-n");
|
|
2178
2564
|
if (cmd === "rm" || cmd === "remove") return cmdRmNonInteractive(args[1]);
|
|
2179
2565
|
if (cmd === "browse") return browser({ force: true, runtimeOverride });
|