create-egregore 0.19.3 → 0.19.6
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 +410 -26
- package/bin/cli.js +34 -20
- package/lib/local.js +84 -11
- package/lib/pi-runtime.js +186 -0
- package/lib/setup.js +56 -11
- package/lib/ui.js +1 -1
- package/package.json +8 -6
- package/runtime/codex/.codex/hooks/search-hint.js +65 -0
- package/runtime/codex/.codex/hooks.json +13 -0
- package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +14 -10
- package/runtime/codex/.codex/skills/minion/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/scroll/SKILL.md +168 -0
- package/runtime/codex/.codex/skills/scroll/agents/openai.yaml +4 -0
- package/runtime/codex/.codex/skills/scroll/assets/shell.html +542 -0
- package/runtime/codex/.codex/skills/search/SKILL.md +56 -0
- package/runtime/codex/.codex/skills/session-view/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/thread/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/view/SKILL.md +147 -32
- package/runtime/codex/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/codex/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/codex/.codex/spec-manifest.json +4 -4
- package/runtime/codex/AGENTS.md +31 -5
- package/runtime/codex/bin/activity-data.sh +46 -4
- package/runtime/codex/bin/agent.sh +10 -2
- package/runtime/codex/bin/codex-install-skills.sh +1 -1
- package/runtime/codex/bin/codex-render-spec.mjs +24 -2
- package/runtime/codex/bin/codex-session-start.sh +6 -60
- package/runtime/codex/bin/codex-skill-render.mjs +20 -12
- package/runtime/codex/bin/codex-sync-skills.sh +4 -0
- package/runtime/codex/bin/graph-op.sh +56 -5
- package/runtime/codex/bin/graph.sh +36 -0
- package/runtime/codex/bin/handoff-run.sh +157 -7
- package/runtime/codex/bin/handoff-save-egregore.sh +6 -1
- package/runtime/codex/bin/index-handoff.sh +9 -3
- package/runtime/codex/bin/lib/context.sh +97 -18
- package/runtime/codex/bin/lib/dashboard-artifact.sh +1 -1
- package/runtime/codex/bin/lib/git-sync.sh +35 -9
- package/runtime/codex/bin/lib/greeting.sh +30 -104
- package/runtime/codex/bin/lib/metrics.sh +374 -0
- package/runtime/codex/bin/publish-artifact.sh +43 -1
- package/runtime/codex/bin/settings.sh +274 -0
- package/runtime/codex/manifest.json +18 -1
- 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.1
|
|
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.1";
|
|
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";
|
|
@@ -48,6 +49,8 @@ const NATIVE_CODEX_SKILLS = [
|
|
|
48
49
|
"invite",
|
|
49
50
|
"ask",
|
|
50
51
|
"save",
|
|
52
|
+
"view",
|
|
53
|
+
"scroll",
|
|
51
54
|
];
|
|
52
55
|
|
|
53
56
|
const PRIMARY_CODEX_SKILLS = [
|
|
@@ -343,6 +346,7 @@ function normalizeRuntime(raw) {
|
|
|
343
346
|
if (!value) return null;
|
|
344
347
|
if (value === "claude" || value === "claude-code" || value === "claude_code") return "claude-code";
|
|
345
348
|
if (value === "codex" || value === "openai-codex" || value === "openai_codex") return "codex";
|
|
349
|
+
if (value === "pi" || value === "pi-coding-agent" || value === "pi_coding_agent") return "pi";
|
|
346
350
|
return null;
|
|
347
351
|
}
|
|
348
352
|
|
|
@@ -353,6 +357,8 @@ function parseRuntimeFlags(argv) {
|
|
|
353
357
|
const arg = argv[i];
|
|
354
358
|
if (arg === "--codex") {
|
|
355
359
|
runtimeOverride = "codex";
|
|
360
|
+
} else if (arg === "--pi") {
|
|
361
|
+
runtimeOverride = "pi";
|
|
356
362
|
} else if (arg === "--claude" || arg === "--claude-code") {
|
|
357
363
|
runtimeOverride = "claude-code";
|
|
358
364
|
} else if (arg === "--runtime") {
|
|
@@ -366,7 +372,7 @@ function parseRuntimeFlags(argv) {
|
|
|
366
372
|
}
|
|
367
373
|
}
|
|
368
374
|
const normalized = runtimeOverride ? normalizeRuntime(runtimeOverride) : null;
|
|
369
|
-
if (runtimeOverride && !normalized) die(`unknown runtime: ${runtimeOverride}\n expected claude-code or
|
|
375
|
+
if (runtimeOverride && !normalized) die(`unknown runtime: ${runtimeOverride}\n expected claude-code, codex, or pi`);
|
|
370
376
|
return { args: rest, runtimeOverride: normalized };
|
|
371
377
|
}
|
|
372
378
|
|
|
@@ -383,21 +389,32 @@ function runtimeFor(inst, runtimeOverride) {
|
|
|
383
389
|
}
|
|
384
390
|
|
|
385
391
|
function runtimeLabel(runtime) {
|
|
386
|
-
|
|
392
|
+
if (runtime === "codex") return "Codex";
|
|
393
|
+
if (runtime === "pi") return "Pi";
|
|
394
|
+
return "Claude Code";
|
|
387
395
|
}
|
|
388
396
|
|
|
389
397
|
function runtimeShort(runtime) {
|
|
390
|
-
return runtime === "codex" ? "codex" : "claude-code";
|
|
398
|
+
return runtime === "codex" ? "codex" : runtime === "pi" ? "pi" : "claude-code";
|
|
391
399
|
}
|
|
392
400
|
|
|
393
401
|
function runtimeBinary(runtime) {
|
|
394
|
-
return runtime === "codex" ? "codex" : "claude";
|
|
402
|
+
return runtime === "codex" ? "codex" : runtime === "pi" ? "pi" : "claude";
|
|
395
403
|
}
|
|
396
404
|
|
|
397
405
|
function assistantInstallCommand(runtime) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
406
|
+
if (runtime === "codex") return "npm install -g @openai/codex";
|
|
407
|
+
if (runtime === "pi") return "npm install -g --ignore-scripts @earendil-works/pi-coding-agent";
|
|
408
|
+
return "npm install -g @anthropic-ai/claude-code";
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function piTrustArgs() {
|
|
412
|
+
try {
|
|
413
|
+
const help = spawnSync("pi", ["--help"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
414
|
+
return `${help.stdout || ""}\n${help.stderr || ""}`.includes("--approve") ? ["--approve"] : [];
|
|
415
|
+
} catch {
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
401
418
|
}
|
|
402
419
|
|
|
403
420
|
function commandExists(bin) {
|
|
@@ -408,13 +425,12 @@ function runtimeChoiceDescription(runtime, inst, stored) {
|
|
|
408
425
|
const installed = commandExists(runtimeBinary(runtime));
|
|
409
426
|
const bits = [];
|
|
410
427
|
if (!installed) {
|
|
411
|
-
return runtime
|
|
412
|
-
? "not installed · install Codex, then run egregore"
|
|
413
|
-
: "not installed · install Claude Code, then run egregore";
|
|
428
|
+
return `not installed · install ${runtimeLabel(runtime)}, then run egregore`;
|
|
414
429
|
}
|
|
415
430
|
bits.push("installed");
|
|
416
431
|
if (runtime === stored) bits.push("saved default");
|
|
417
432
|
if (runtime === "codex") bits.push("portable agent protocol");
|
|
433
|
+
else if (runtime === "pi") bits.push("project-local meta-harness");
|
|
418
434
|
else bits.push("Claude Code integration");
|
|
419
435
|
return bits.join(" · ");
|
|
420
436
|
}
|
|
@@ -437,7 +453,7 @@ function runtimePickerLines(inst, runtimes, stored, cursor) {
|
|
|
437
453
|
lines.push(` ${marker} ${BOLD}${label}${RESET} ${DIM}${desc}${RESET}`);
|
|
438
454
|
}
|
|
439
455
|
// Coming-soon harnesses — shown for visibility, not selectable yet.
|
|
440
|
-
for (const soon of ["Hermes"
|
|
456
|
+
for (const soon of ["Hermes"]) {
|
|
441
457
|
lines.push(` ${DIM}· ${pad(soon, labelWidth)} coming soon${RESET}`);
|
|
442
458
|
}
|
|
443
459
|
lines.push("");
|
|
@@ -527,9 +543,7 @@ function runtimeChoicesFor(inst, runtimeOverride) {
|
|
|
527
543
|
const override = normalizeRuntime(runtimeOverride);
|
|
528
544
|
if (override) return [override];
|
|
529
545
|
const stored = storedRuntimeFor(inst);
|
|
530
|
-
const choices = stored
|
|
531
|
-
? ["codex", "claude-code"]
|
|
532
|
-
: ["claude-code", "codex"];
|
|
546
|
+
const choices = [stored, ...["claude-code", "codex", "pi"].filter((runtime) => runtime !== stored)];
|
|
533
547
|
return choices.sort((a, b) => Number(commandExists(runtimeBinary(b))) - Number(commandExists(runtimeBinary(a))));
|
|
534
548
|
}
|
|
535
549
|
|
|
@@ -635,6 +649,25 @@ function hasCodexCoreSupport(egregoreDir) {
|
|
|
635
649
|
);
|
|
636
650
|
}
|
|
637
651
|
|
|
652
|
+
function hasPiCoreSupport(egregoreDir) {
|
|
653
|
+
return (
|
|
654
|
+
fs.existsSync(path.join(egregoreDir, "bin", "pi-session-start.sh")) &&
|
|
655
|
+
fs.existsSync(path.join(egregoreDir, ".pi", "APPEND_SYSTEM.md")) &&
|
|
656
|
+
fs.existsSync(path.join(egregoreDir, ".pi", "settings.json")) &&
|
|
657
|
+
fs.existsSync(path.join(egregoreDir, ".pi", "extensions", "egregore.ts")) &&
|
|
658
|
+
fs.existsSync(path.join(egregoreDir, ".codex", "skills"))
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function piSupportMessage(egregoreDir) {
|
|
663
|
+
return [
|
|
664
|
+
"Pi meta-harness support is missing from this Egregore checkout.",
|
|
665
|
+
` path: ${egregoreDir}`,
|
|
666
|
+
"",
|
|
667
|
+
"Run npx -y create-egregore@latest to install the packaged Pi runtime, then rerun egregore.",
|
|
668
|
+
].join("\n");
|
|
669
|
+
}
|
|
670
|
+
|
|
638
671
|
function installCodexSkills(egregoreDir) {
|
|
639
672
|
const script = path.join(egregoreDir, "bin", "codex-install-skills.sh");
|
|
640
673
|
if (!fs.existsSync(script)) return false;
|
|
@@ -660,6 +693,7 @@ function runtimeLaunchArgs(runtime, egregoreDir) {
|
|
|
660
693
|
"--cd", egregoreDir,
|
|
661
694
|
];
|
|
662
695
|
}
|
|
696
|
+
if (runtime === "pi") return piTrustArgs();
|
|
663
697
|
return ["start"];
|
|
664
698
|
}
|
|
665
699
|
|
|
@@ -693,6 +727,8 @@ async function launch(inst, runtimeOverride) {
|
|
|
693
727
|
if (!skillsInstalled || !cardRendered) {
|
|
694
728
|
die(codexSupportMessage(inst.path));
|
|
695
729
|
}
|
|
730
|
+
} else if (runtime === "pi") {
|
|
731
|
+
if (!hasPiCoreSupport(inst.path)) die(piSupportMessage(inst.path));
|
|
696
732
|
}
|
|
697
733
|
// Replace the current process with the selected assistant in the instance dir.
|
|
698
734
|
// spawn + detached + exit-on-exit replicates exec() in Node.
|
|
@@ -820,10 +856,12 @@ function cmdHelp() {
|
|
|
820
856
|
` ${CYAN}egregore${RESET} pick an instance, then pick a harness`,
|
|
821
857
|
` ${CYAN}egregore${RESET} ${DIM}<slug|name>${RESET} pick a harness for the matching instance`,
|
|
822
858
|
` ${CYAN}egregore --runtime${RESET} ${DIM}<name> <slug>${RESET} advanced harness override`,
|
|
859
|
+
` ${DIM}names: claude-code · codex · pi${RESET}`,
|
|
823
860
|
` ${CYAN}egregore browse${RESET} force the full-screen browser`,
|
|
824
861
|
` ${CYAN}egregore ls${RESET} ${DIM}| list${RESET} list installed instances`,
|
|
825
862
|
` ${CYAN}egregore use${RESET} ${DIM}<slug>${RESET} set the default for bare ${BOLD}egregore${RESET}`,
|
|
826
863
|
` ${CYAN}egregore /invite${RESET} ${DIM}<user> [slug]${RESET} invite a GitHub user`,
|
|
864
|
+
` ${CYAN}egregore settings${RESET} ${DIM}[slug]${RESET} hosting on/off, repos, admins`,
|
|
827
865
|
` ${CYAN}egregore prune${RESET} ${DIM}[--dry-run]${RESET} remove entries with missing paths`,
|
|
828
866
|
` ${CYAN}egregore rm${RESET} ${DIM}<slug|path>${RESET} remove a specific entry`,
|
|
829
867
|
``,
|
|
@@ -834,6 +872,7 @@ function cmdHelp() {
|
|
|
834
872
|
` ${DIM}n / +${RESET} create a new Egregore`,
|
|
835
873
|
` ${DIM}u${RESET} set selected as default`,
|
|
836
874
|
` ${DIM}i${RESET} invite a GitHub user to selected instance`,
|
|
875
|
+
` ${DIM}s${RESET} settings (hosting on/off, repos, admins)`,
|
|
837
876
|
` ${DIM}d${RESET} delete selected entry (offers cleanup of ${RED}✗${RESET} missing ones)`,
|
|
838
877
|
` ${DIM}?${RESET} toggle help overlay`,
|
|
839
878
|
` ${DIM}q${RESET} quit browser (esc goes back — it never quits)`,
|
|
@@ -1249,6 +1288,343 @@ async function cmdInvite(args) {
|
|
|
1249
1288
|
return inviteToInstance(inst, username);
|
|
1250
1289
|
}
|
|
1251
1290
|
|
|
1291
|
+
// ── settings ───────────────────────────────────────────────────────
|
|
1292
|
+
//
|
|
1293
|
+
// The launcher stays a THIN caller: every config change shells out to the
|
|
1294
|
+
// instance's deterministic `bin/settings.sh` verbs (one source of truth, no
|
|
1295
|
+
// JS reimplementation to drift from the script). This is the reliability point
|
|
1296
|
+
// — the correctness lives in the tested script; the screen below just drives it.
|
|
1297
|
+
|
|
1298
|
+
function settingsScriptPath(inst) {
|
|
1299
|
+
return path.join(inst.path, "bin", "settings.sh");
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
function runSettings(inst, args) {
|
|
1303
|
+
const script = settingsScriptPath(inst);
|
|
1304
|
+
if (!fs.existsSync(script)) {
|
|
1305
|
+
return { status: 127, stdout: "", stderr: "bin/settings.sh not found — update this egregore (run /pull) to get settings.\n", missing: true };
|
|
1306
|
+
}
|
|
1307
|
+
try {
|
|
1308
|
+
return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 15000 });
|
|
1309
|
+
} catch (err) {
|
|
1310
|
+
return { status: 1, stdout: "", stderr: String(err) };
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
function settingsDump(inst) {
|
|
1315
|
+
const r = runSettings(inst, ["dump"]);
|
|
1316
|
+
if (!r || r.status !== 0) return null;
|
|
1317
|
+
try { return JSON.parse(r.stdout); } catch { return null; }
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
// Nested raw-mode list editor for a domain (repo | admin | people): hover an
|
|
1321
|
+
// item and press `d` to remove it, `a` to open an inline add field, esc to go
|
|
1322
|
+
// back. Mirrors the main browser's affordances. Its own raw-mode loop; resolves
|
|
1323
|
+
// when the user backs out. Each mutation is ONE deterministic settings.sh verb;
|
|
1324
|
+
// validation, the last-admin guard, and GitHub-access notes surface as notices.
|
|
1325
|
+
function listEditor(inst, domain, label) {
|
|
1326
|
+
const fieldFor = (d) => {
|
|
1327
|
+
if (domain === "repo") return (d.repos || []).map((r) => r.name || r);
|
|
1328
|
+
if (domain === "admin") return d.admins || [];
|
|
1329
|
+
return d.people || [];
|
|
1330
|
+
};
|
|
1331
|
+
const noun = domain === "repo" ? "repo name" : "github handle";
|
|
1332
|
+
|
|
1333
|
+
return new Promise((resolve) => {
|
|
1334
|
+
let items = fieldFor(settingsDump(inst) || {});
|
|
1335
|
+
let cursor = 0;
|
|
1336
|
+
let mode = "browse"; // browse | add | confirm
|
|
1337
|
+
let input = "";
|
|
1338
|
+
let notice = "";
|
|
1339
|
+
let rendered = 0;
|
|
1340
|
+
let done = false;
|
|
1341
|
+
const previousRaw = !!process.stdin.isRaw;
|
|
1342
|
+
const isMouseEvent = makeMouseFilter();
|
|
1343
|
+
|
|
1344
|
+
const refresh = () => {
|
|
1345
|
+
items = fieldFor(settingsDump(inst) || {});
|
|
1346
|
+
if (cursor >= items.length) cursor = Math.max(0, items.length - 1);
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
const erase = () => {
|
|
1350
|
+
if (!rendered) return;
|
|
1351
|
+
process.stdout.write(`\x1b[${rendered}A` + ANSI.clearDown);
|
|
1352
|
+
rendered = 0;
|
|
1353
|
+
};
|
|
1354
|
+
|
|
1355
|
+
const buildLines = () => {
|
|
1356
|
+
const out = [];
|
|
1357
|
+
out.push(``);
|
|
1358
|
+
out.push(` ${BOLD}${label}${RESET}`);
|
|
1359
|
+
out.push(` ${DIM}────────────────────────────────────────${RESET}`);
|
|
1360
|
+
if (items.length === 0) {
|
|
1361
|
+
out.push(` ${DIM}(none)${RESET}`);
|
|
1362
|
+
} else {
|
|
1363
|
+
items.forEach((it, i) => {
|
|
1364
|
+
const sel = i === cursor;
|
|
1365
|
+
out.push(` ${sel ? CYAN + "❯" + RESET : " "} ${sel ? BOLD + it + RESET : it}`);
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
out.push(``);
|
|
1369
|
+
if (notice) out.push(` ${notice}`);
|
|
1370
|
+
if (mode === "add") {
|
|
1371
|
+
out.push(` ${CYAN}add ${noun}:${RESET} ${input}${CYAN}▌${RESET} ${DIM}enter save · esc cancel${RESET}`);
|
|
1372
|
+
} else if (mode === "confirm") {
|
|
1373
|
+
out.push(` ${YELLOW}remove ${items[cursor]}?${RESET} ${DIM}y / N${RESET}`);
|
|
1374
|
+
} else {
|
|
1375
|
+
out.push(` ${DIM}↑↓ nav · ${RESET}${BOLD}a${RESET}${DIM} add · ${RESET}${BOLD}d${RESET}${DIM} delete · esc back${RESET}`);
|
|
1376
|
+
}
|
|
1377
|
+
return out;
|
|
1378
|
+
};
|
|
1379
|
+
|
|
1380
|
+
const render = () => {
|
|
1381
|
+
erase();
|
|
1382
|
+
const lines = buildLines();
|
|
1383
|
+
rendered = lines.length;
|
|
1384
|
+
process.stdout.write(lines.map((l) => l + ANSI.clearLine).join("\n") + "\n");
|
|
1385
|
+
};
|
|
1386
|
+
|
|
1387
|
+
const cleanup = () => {
|
|
1388
|
+
if (done) return;
|
|
1389
|
+
done = true;
|
|
1390
|
+
process.stdin.removeListener("keypress", onKey);
|
|
1391
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1392
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(previousRaw);
|
|
1393
|
+
if (!previousRaw) process.stdin.pause();
|
|
1394
|
+
erase();
|
|
1395
|
+
};
|
|
1396
|
+
|
|
1397
|
+
// Run a verb (spawnSync blocks briefly — people ops hit GitHub). Surface the
|
|
1398
|
+
// last stdout/stderr line as a notice; refresh the list from disk after.
|
|
1399
|
+
const runVerb = (args) => {
|
|
1400
|
+
const r = runSettings(inst, args);
|
|
1401
|
+
const msg = ((r.stdout || "") + " " + (r.stderr || "")).trim().split("\n").map((s) => s.trim()).filter(Boolean).pop() || "";
|
|
1402
|
+
notice = r && r.status === 0 ? msg : `${YELLOW}${msg}${RESET}`;
|
|
1403
|
+
refresh();
|
|
1404
|
+
};
|
|
1405
|
+
|
|
1406
|
+
function onKey(chunk, key = {}) {
|
|
1407
|
+
if (isMouseEvent(chunk, key)) return;
|
|
1408
|
+
if (key.ctrl && key.name === "c") { cleanup(); process.exit(130); }
|
|
1409
|
+
|
|
1410
|
+
if (mode === "add") {
|
|
1411
|
+
if (key.name === "escape") { mode = "browse"; input = ""; render(); return; }
|
|
1412
|
+
if (key.name === "return") {
|
|
1413
|
+
const v = input.trim().split(/\s+/)[0];
|
|
1414
|
+
mode = "browse"; input = "";
|
|
1415
|
+
if (v) runVerb([domain, "add", v]);
|
|
1416
|
+
render();
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
if (key.name === "backspace") { input = input.slice(0, -1); render(); return; }
|
|
1420
|
+
if (chunk && chunk.length === 1 && chunk >= " " && !key.ctrl && !key.meta) { input += chunk; render(); return; }
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
if (mode === "confirm") {
|
|
1425
|
+
if (chunk === "y" || chunk === "Y") {
|
|
1426
|
+
const victim = items[cursor];
|
|
1427
|
+
mode = "browse";
|
|
1428
|
+
if (victim) runVerb([domain, "remove", victim]);
|
|
1429
|
+
} else { mode = "browse"; }
|
|
1430
|
+
render();
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// browse
|
|
1435
|
+
if (key.name === "escape" || key.name === "left") { cleanup(); resolve(); return; }
|
|
1436
|
+
if (key.name === "up" || key.name === "k") { if (items.length) cursor = (cursor - 1 + items.length) % items.length; render(); return; }
|
|
1437
|
+
if (key.name === "down" || key.name === "j") { if (items.length) cursor = (cursor + 1) % items.length; render(); return; }
|
|
1438
|
+
if (chunk === "a") { mode = "add"; input = ""; notice = ""; render(); return; }
|
|
1439
|
+
if (chunk === "d") { if (items.length) { mode = "confirm"; render(); } return; }
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
readline.emitKeypressEvents(process.stdin);
|
|
1443
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
1444
|
+
process.stdin.resume();
|
|
1445
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1446
|
+
process.stdin.on("keypress", onKey);
|
|
1447
|
+
render();
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// The `s`-key settings screen: a raw-mode menu (hosting toggle + repo/admin
|
|
1452
|
+
// editors) over bin/settings.sh. Modeled on pickRuntimeInteractive.
|
|
1453
|
+
function settingsScreen(inst) {
|
|
1454
|
+
const title = inst.slug || inst.name || path.basename(inst.path);
|
|
1455
|
+
|
|
1456
|
+
if (!fs.existsSync(settingsScriptPath(inst))) {
|
|
1457
|
+
console.log(`\n ${YELLOW}Settings unavailable${RESET} — ${BOLD}${title}${RESET} has no ${DIM}bin/settings.sh${RESET}.`);
|
|
1458
|
+
console.log(` Update it: open the egregore and run ${CYAN}/pull${RESET}.\n`);
|
|
1459
|
+
return Promise.resolve();
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
let data = settingsDump(inst) || { hosting: true, repos: [], admins: [], people: [] };
|
|
1463
|
+
|
|
1464
|
+
const rows = [
|
|
1465
|
+
{
|
|
1466
|
+
label: () => `Hosted Artifacts`,
|
|
1467
|
+
value: () => (data.hosting ? `${GREEN}ON${RESET}` : `${YELLOW}OFF${RESET}`),
|
|
1468
|
+
detailLines: () => [data.hosting
|
|
1469
|
+
? ` ${DIM}Enter toggles. When OFF, artifacts never upload to egregore.xyz.${RESET}`
|
|
1470
|
+
: ` ${DIM}Artifacts stay local. /view still renders them on localhost.${RESET}`],
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
label: () => `Managed repos`,
|
|
1474
|
+
value: () => `${DIM}${data.repos.length}${RESET}`,
|
|
1475
|
+
detailLines: () => data.repos.length
|
|
1476
|
+
? data.repos.map((r) => ` ${DIM}·${RESET} ${r.name || r}`)
|
|
1477
|
+
: [` ${DIM}(none)${RESET}`],
|
|
1478
|
+
},
|
|
1479
|
+
{
|
|
1480
|
+
label: () => `Admins`,
|
|
1481
|
+
value: () => `${DIM}${data.admins.length}${RESET}`,
|
|
1482
|
+
detailLines: () => data.admins.length
|
|
1483
|
+
? [` ${DIM}${data.admins.join(", ")}${RESET}`]
|
|
1484
|
+
: [` ${DIM}(none)${RESET}`],
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
label: () => `People`,
|
|
1488
|
+
value: () => `${DIM}${(data.people || []).length}${RESET}`,
|
|
1489
|
+
detailLines: () => (data.people && data.people.length)
|
|
1490
|
+
? [` ${DIM}${data.people.join(", ")}${RESET}`]
|
|
1491
|
+
: [` ${DIM}(none)${RESET}`],
|
|
1492
|
+
},
|
|
1493
|
+
];
|
|
1494
|
+
|
|
1495
|
+
return new Promise((resolve) => {
|
|
1496
|
+
let cursor = 0;
|
|
1497
|
+
let rendered = 0;
|
|
1498
|
+
let done = false;
|
|
1499
|
+
let notice = "";
|
|
1500
|
+
const previousRaw = !!process.stdin.isRaw;
|
|
1501
|
+
const isMouseEvent = makeMouseFilter();
|
|
1502
|
+
|
|
1503
|
+
const erase = () => {
|
|
1504
|
+
if (!rendered) return;
|
|
1505
|
+
// Move to the TOP of the last-rendered block, then wipe everything below
|
|
1506
|
+
// in one shot. Clearing line-by-line leaves the cursor at the BOTTOM, so
|
|
1507
|
+
// the next redraw starts a row lower each time — that's the drift that
|
|
1508
|
+
// pushes blank "margins" on top. Up-N + clearDown returns to the top and
|
|
1509
|
+
// clears cleanly, so every render repaints in place.
|
|
1510
|
+
process.stdout.write(`\x1b[${rendered}A` + ANSI.clearDown);
|
|
1511
|
+
rendered = 0;
|
|
1512
|
+
};
|
|
1513
|
+
|
|
1514
|
+
const buildLines = () => {
|
|
1515
|
+
const out = [];
|
|
1516
|
+
out.push(``);
|
|
1517
|
+
out.push(` ${BOLD}Settings${RESET} ${DIM}·${RESET} ${BOLD}${title}${RESET}`);
|
|
1518
|
+
out.push(` ${DIM}────────────────────────────────────────${RESET}`);
|
|
1519
|
+
rows.forEach((row, i) => {
|
|
1520
|
+
const sel = i === cursor;
|
|
1521
|
+
const marker = sel ? `${CYAN}❯${RESET}` : ` `;
|
|
1522
|
+
const name = sel ? `${BOLD}${row.label()}${RESET}` : row.label();
|
|
1523
|
+
out.push(` ${marker} ${name} ${row.value()}`);
|
|
1524
|
+
if (sel) for (const dl of row.detailLines()) out.push(dl);
|
|
1525
|
+
});
|
|
1526
|
+
out.push(``);
|
|
1527
|
+
if (notice) out.push(` ${notice}`);
|
|
1528
|
+
out.push(` ${DIM}↑↓ nav · enter ${cursor === 0 ? "toggle" : "edit"} · esc back · q quit${RESET}`);
|
|
1529
|
+
return out;
|
|
1530
|
+
};
|
|
1531
|
+
|
|
1532
|
+
const render = () => {
|
|
1533
|
+
erase();
|
|
1534
|
+
const lines = buildLines();
|
|
1535
|
+
rendered = lines.length;
|
|
1536
|
+
process.stdout.write(lines.map((l) => l + ANSI.clearLine).join("\n") + "\n");
|
|
1537
|
+
};
|
|
1538
|
+
|
|
1539
|
+
const teardownRaw = () => {
|
|
1540
|
+
process.stdin.removeListener("keypress", onKey);
|
|
1541
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1542
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(previousRaw);
|
|
1543
|
+
if (!previousRaw) process.stdin.pause();
|
|
1544
|
+
};
|
|
1545
|
+
|
|
1546
|
+
const setupRaw = () => {
|
|
1547
|
+
readline.emitKeypressEvents(process.stdin);
|
|
1548
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
1549
|
+
process.stdin.resume();
|
|
1550
|
+
process.stdout.write(ANSI.mouseOff);
|
|
1551
|
+
process.stdin.on("keypress", onKey);
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
const cleanup = () => {
|
|
1555
|
+
if (done) return;
|
|
1556
|
+
done = true;
|
|
1557
|
+
teardownRaw();
|
|
1558
|
+
erase();
|
|
1559
|
+
};
|
|
1560
|
+
|
|
1561
|
+
const toggleHosting = () => {
|
|
1562
|
+
const r = runSettings(inst, ["hosting", data.hosting ? "off" : "on"]);
|
|
1563
|
+
if (!r || r.status !== 0) {
|
|
1564
|
+
notice = `${YELLOW}${((r && r.stderr) || "could not change hosting").trim().split("\n")[0]}${RESET}`;
|
|
1565
|
+
} else {
|
|
1566
|
+
data = settingsDump(inst) || data;
|
|
1567
|
+
notice = `hosting ${data.hosting ? `${GREEN}ON${RESET}` : `${YELLOW}OFF${RESET}`}`;
|
|
1568
|
+
}
|
|
1569
|
+
render();
|
|
1570
|
+
};
|
|
1571
|
+
|
|
1572
|
+
// Hand off to the nested raw-mode list editor, then repaint this screen with
|
|
1573
|
+
// refreshed counts when the user backs out.
|
|
1574
|
+
const openList = (domain, label) => {
|
|
1575
|
+
erase();
|
|
1576
|
+
teardownRaw();
|
|
1577
|
+
listEditor(inst, domain, label).then(() => {
|
|
1578
|
+
data = settingsDump(inst) || data;
|
|
1579
|
+
notice = "";
|
|
1580
|
+
setupRaw();
|
|
1581
|
+
render();
|
|
1582
|
+
});
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
function onKey(chunk, key = {}) {
|
|
1586
|
+
if (isMouseEvent(chunk, key)) return;
|
|
1587
|
+
if (key.ctrl && key.name === "c") { cleanup(); process.exit(130); }
|
|
1588
|
+
if (key.name === "q") { cleanup(); resolve(); return; }
|
|
1589
|
+
// Esc / ← = back (esc never quits).
|
|
1590
|
+
if (key.name === "escape" || key.name === "left") { cleanup(); resolve(); return; }
|
|
1591
|
+
if (key.name === "up" || key.name === "k") { cursor = (cursor - 1 + rows.length) % rows.length; render(); return; }
|
|
1592
|
+
if (key.name === "down" || key.name === "j") { cursor = (cursor + 1) % rows.length; render(); return; }
|
|
1593
|
+
if (key.name === "return" || chunk === " ") {
|
|
1594
|
+
if (cursor === 0) toggleHosting();
|
|
1595
|
+
else if (cursor === 1) openList("repo", "Managed repos");
|
|
1596
|
+
else if (cursor === 2) openList("admin", "Admins");
|
|
1597
|
+
else if (cursor === 3) openList("people", "People");
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
setupRaw();
|
|
1602
|
+
render();
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
async function cmdSettings(args) {
|
|
1607
|
+
const registry = readRegistry();
|
|
1608
|
+
if (registry.length === 0) die("no egregores installed yet.\n run: npx -y create-egregore@latest");
|
|
1609
|
+
const DOMAINS = new Set(["hosting", "repo", "admin", "people", "dump"]);
|
|
1610
|
+
let rest = args.slice();
|
|
1611
|
+
let slug = "";
|
|
1612
|
+
if (rest.length && !DOMAINS.has(rest[0])) { slug = rest[0]; rest = rest.slice(1); }
|
|
1613
|
+
const inst = resolveInviteInstance(registry, slug);
|
|
1614
|
+
if (!inst) {
|
|
1615
|
+
die(`multiple egregores installed; choose one:\n egregore settings <slug> [hosting|repo|admin]\n run: egregore ls`);
|
|
1616
|
+
}
|
|
1617
|
+
// No verb + a TTY → interactive screen. Otherwise forward straight to the verb.
|
|
1618
|
+
if (rest.length === 0) {
|
|
1619
|
+
if (isTTY && canPrompt()) return settingsScreen(inst);
|
|
1620
|
+
rest = ["dump"];
|
|
1621
|
+
}
|
|
1622
|
+
const r = runSettings(inst, rest);
|
|
1623
|
+
if (r.stdout) process.stdout.write(r.stdout.endsWith("\n") ? r.stdout : r.stdout + "\n");
|
|
1624
|
+
if (r.stderr) process.stderr.write(r.stderr);
|
|
1625
|
+
process.exitCode = r.status || 0;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1252
1628
|
// ── tiny sync confirm (non-TUI flows) ───────────────────────────────
|
|
1253
1629
|
|
|
1254
1630
|
function syncConfirm(question) {
|
|
@@ -1368,11 +1744,11 @@ function renderHeroPanel({ selected, pv, width, height, countSuffix, filter, fil
|
|
|
1368
1744
|
? `filter /${filter}`
|
|
1369
1745
|
: "press ? for help";
|
|
1370
1746
|
const canShowBigLogo = bodyWidth >= Math.max(...EGREGORE_ART.map((line) => line.length)) && height >= 24;
|
|
1371
|
-
const skillStatus = `Codex ${nativeCount} native · ${adapterCount} adapter · ${skillsCount}
|
|
1747
|
+
const skillStatus = `Codex ${nativeCount} native · ${adapterCount} adapter · Pi ${skillsCount} shared · Claude ${claudeCount}`;
|
|
1372
1748
|
const skillGroups = [
|
|
1373
1749
|
`${DIM}core${RESET}: ${workflows}`,
|
|
1374
1750
|
`${DIM}team${RESET}: ${joinShort(["/handoff", "/ask", "/invite", "/quest"], Math.max(16, bodyWidth - 8))}`,
|
|
1375
|
-
`${DIM}deeper${RESET}: ${joinShort(["/announce", "/harvest", "/the-spiral", "/deep-reflect"], Math.max(16, bodyWidth - 10))}`,
|
|
1751
|
+
`${DIM}deeper${RESET}: ${joinShort(["/announce", "/harvest", "/the-spiral", "/deep-reflect", "/view", "/scroll"], Math.max(16, bodyWidth - 10))}`,
|
|
1376
1752
|
`${DIM}fallback${RESET}: ${adapterCount} adapter skills`,
|
|
1377
1753
|
];
|
|
1378
1754
|
|
|
@@ -1409,8 +1785,8 @@ function renderHeroPanel({ selected, pv, width, height, countSuffix, filter, fil
|
|
|
1409
1785
|
`${BOLD}Harnesses${RESET}`,
|
|
1410
1786
|
`${DIM}claude-code${RESET}: ${commandExists("claude") ? "installed" : "not installed"}`,
|
|
1411
1787
|
`${DIM}codex${RESET}: ${commandExists("codex") ? "installed" : "not installed"}`,
|
|
1788
|
+
`${DIM}pi${RESET}: ${commandExists("pi") ? "installed" : "not installed"}`,
|
|
1412
1789
|
`${DIM}Hermes — Coming Soon${RESET}`,
|
|
1413
|
-
`${DIM}Pi — Coming Soon${RESET}`,
|
|
1414
1790
|
];
|
|
1415
1791
|
const rows = Math.max(EGREGORE_SIGIL.length + 2, right.length);
|
|
1416
1792
|
for (let i = 0; i < rows; i++) {
|
|
@@ -1422,11 +1798,11 @@ function renderHeroPanel({ selected, pv, width, height, countSuffix, filter, fil
|
|
|
1422
1798
|
lines.push(boxLine(`${BOLD}Available Skills${RESET}`, innerWidth, margin));
|
|
1423
1799
|
for (const group of skillGroups) lines.push(boxLine(group, innerWidth, margin));
|
|
1424
1800
|
lines.push(emptyBoxLine(innerWidth, margin));
|
|
1425
|
-
lines.push(boxLine(`${BOLD}Harnesses${RESET} ${DIM}claude-code${RESET} ${commandExists("claude") ? "installed" : "missing"} · ${DIM}codex${RESET} ${commandExists("codex") ? "installed" : "missing"} · ${DIM}Hermes
|
|
1801
|
+
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));
|
|
1426
1802
|
}
|
|
1427
1803
|
|
|
1428
1804
|
lines.push(emptyBoxLine(innerWidth, margin));
|
|
1429
|
-
lines.push(boxLine(`${DIM}enter selects an instance, then choose Claude Code or
|
|
1805
|
+
lines.push(boxLine(`${DIM}enter selects an instance, then choose Claude Code, Codex, or Pi without leaving this screen${RESET}`, innerWidth, margin));
|
|
1430
1806
|
lines.push(bottom);
|
|
1431
1807
|
return lines;
|
|
1432
1808
|
}
|
|
@@ -1459,7 +1835,7 @@ function renderRuntimePanel({ inst, cursor, width, height }) {
|
|
|
1459
1835
|
lines.push(boxLine(`${marker} ${pad(labelText, 16)} ${DIM}${desc}${RESET}`, innerWidth, margin));
|
|
1460
1836
|
}
|
|
1461
1837
|
// Coming-soon harnesses — shown for visibility, not selectable yet.
|
|
1462
|
-
for (const soon of ["Hermes"
|
|
1838
|
+
for (const soon of ["Hermes"]) {
|
|
1463
1839
|
lines.push(boxLine(`${DIM}· ${pad(soon, 16)} coming soon${RESET}`, innerWidth, margin));
|
|
1464
1840
|
}
|
|
1465
1841
|
|
|
@@ -1672,7 +2048,7 @@ async function browser(args = {}) {
|
|
|
1672
2048
|
const label = (k) => `${DIM}${pad(k, 10)}${RESET}`;
|
|
1673
2049
|
previewLines.push(` ${label("action")} ${BOLD}Set up a new Egregore${RESET}`);
|
|
1674
2050
|
previewLines.push(` ${label("flow")} guided install, Telegram, invite, ready/start`);
|
|
1675
|
-
previewLines.push(` ${label("harness")} choose Claude Code or
|
|
2051
|
+
previewLines.push(` ${label("harness")} choose Claude Code, Codex, or Pi during setup`);
|
|
1676
2052
|
previewLines.push(` ${label("start")} press enter to begin`);
|
|
1677
2053
|
} else if (!selected) {
|
|
1678
2054
|
previewLines.push(`${DIM} (no selection)${RESET}`);
|
|
@@ -1695,7 +2071,7 @@ async function browser(args = {}) {
|
|
|
1695
2071
|
if (pv.skills) {
|
|
1696
2072
|
const skillLine = selectedWorkflowLine(pv, Math.max(16, blockWidth - 20));
|
|
1697
2073
|
previewLines.push(` ${label("invoke")} ${skillLine}`);
|
|
1698
|
-
previewLines.push(` ${label("skills")} Codex ${BOLD}${pv.skills.native.length}${RESET} native
|
|
2074
|
+
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}`);
|
|
1699
2075
|
}
|
|
1700
2076
|
const modeBits = [];
|
|
1701
2077
|
modeBits.push(runtimeShort(runtimeFor(selected, args.runtimeOverride)));
|
|
@@ -1755,8 +2131,8 @@ async function browser(args = {}) {
|
|
|
1755
2131
|
footer = band(`● ${stripAnsi(state.message)}`, bg);
|
|
1756
2132
|
} else {
|
|
1757
2133
|
footer = blockWidth < 96
|
|
1758
|
-
? band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("i", "invite")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46)
|
|
1759
|
-
: 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);
|
|
2134
|
+
? band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("i", "invite")} ${key("s", "settings")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46)
|
|
2135
|
+
: 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);
|
|
1760
2136
|
}
|
|
1761
2137
|
out.push(M + footer + "\n");
|
|
1762
2138
|
if (state.showHelp) {
|
|
@@ -2054,6 +2430,13 @@ async function browser(args = {}) {
|
|
|
2054
2430
|
render();
|
|
2055
2431
|
return;
|
|
2056
2432
|
}
|
|
2433
|
+
if (chunk === "s") {
|
|
2434
|
+
const pick = visible()[state.cursor]?.e;
|
|
2435
|
+
if (!pick) return;
|
|
2436
|
+
cleanup();
|
|
2437
|
+
resolve(settingsScreen(pick));
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2057
2440
|
if (chunk === "u") {
|
|
2058
2441
|
const pick = visible()[state.cursor]?.e;
|
|
2059
2442
|
if (!pick) return;
|
|
@@ -2172,6 +2555,7 @@ function main() {
|
|
|
2172
2555
|
if (cmd === "ls" || cmd === "list") return cmdLs();
|
|
2173
2556
|
if (cmd === "use") return cmdUse(args[1]);
|
|
2174
2557
|
if (cmd === "/invite" || cmd === "invite") return cmdInvite(args.slice(1));
|
|
2558
|
+
if (cmd === "settings" || cmd === "config") return cmdSettings(args.slice(1));
|
|
2175
2559
|
if (cmd === "prune") return cmdPruneNonInteractive(args[1] === "--dry-run" || args[1] === "-n");
|
|
2176
2560
|
if (cmd === "rm" || cmd === "remove") return cmdRmNonInteractive(args[1]);
|
|
2177
2561
|
if (cmd === "browse") return browser({ force: true, runtimeOverride });
|