create-egregore 0.18.4 → 0.18.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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// egregore-launcher-version: 0.5.
|
|
2
|
+
// egregore-launcher-version: 0.5.20
|
|
3
3
|
//
|
|
4
4
|
// egregore — launch and browse Egregore instances from your terminal.
|
|
5
5
|
// Installed by create-egregore. Reads ~/.egregore/instances.json.
|
|
@@ -30,7 +30,7 @@ const https = require("node:https");
|
|
|
30
30
|
const { spawnSync, spawn } = require("node:child_process");
|
|
31
31
|
const readline = require("node:readline");
|
|
32
32
|
|
|
33
|
-
const VERSION = "0.5.
|
|
33
|
+
const VERSION = "0.5.20";
|
|
34
34
|
const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
|
|
35
35
|
const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
|
|
36
36
|
const PUBLIC_NPX_PACKAGE = "create-egregore";
|
|
@@ -99,9 +99,57 @@ const ANSI = {
|
|
|
99
99
|
clear: "\x1b[2J",
|
|
100
100
|
home: "\x1b[H",
|
|
101
101
|
clearLine: "\x1b[K",
|
|
102
|
+
// Disable every terminal mouse-reporting mode. Some terminals (tmux,
|
|
103
|
+
// iTerm2) or a TUI run earlier in the session leave mouse reporting ON,
|
|
104
|
+
// which turns the scroll wheel into escape sequences that corrupt our
|
|
105
|
+
// pickers. Emitting this on picker entry makes the wheel do native
|
|
106
|
+
// scrollback instead. Modes: 1000 (click), 1002 (drag), 1003 (any-motion),
|
|
107
|
+
// 1006 (SGR encoding), 1015 (urxvt encoding).
|
|
108
|
+
mouseOff: "\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1015l",
|
|
102
109
|
moveTo: (row, col) => `\x1b[${row};${col}H`,
|
|
103
110
|
};
|
|
104
111
|
|
|
112
|
+
// Scroll-wheel / mouse-event filter (defense-in-depth for ANSI.mouseOff).
|
|
113
|
+
// With mouse reporting on, the scroll wheel and shift+arrow arrive as escape
|
|
114
|
+
// sequences. Node's readline decomposes them into stray keypresses:
|
|
115
|
+
// • SGR mouse "\x1b[<b;x;yM" → an event with key.code "[<", then each
|
|
116
|
+
// coordinate DIGIT as its own keypress (a "1"/"2" hits the picker's
|
|
117
|
+
// number quick-select and LAUNCHES a runtime), then a final "M".
|
|
118
|
+
// • X11 mouse "\x1b[M" + 3 raw bytes → key.code "[M" then 3 stray chars.
|
|
119
|
+
// • shift+arrow "\x1b[1;2A" / "\x1b[1;2B" → key.name "up"/"down" with
|
|
120
|
+
// key.shift set, which would advance the selection.
|
|
121
|
+
// This factory returns a stateful predicate: pass it every (chunk, key) at the
|
|
122
|
+
// top of a keypress handler and early-return when it reports true, so no
|
|
123
|
+
// mouse-derived byte is ever treated as navigation.
|
|
124
|
+
function makeMouseFilter() {
|
|
125
|
+
let sgr = false; // inside an SGR mouse report (ESC [ < ... M|m)
|
|
126
|
+
let x11 = 0; // raw bytes left to swallow after ESC [ M
|
|
127
|
+
return function isMouseEvent(chunk, key) {
|
|
128
|
+
const seq = (key && key.sequence) || (typeof chunk === "string" ? chunk : "") || "";
|
|
129
|
+
if (sgr) {
|
|
130
|
+
if (/[Mm]/.test(seq)) sgr = false; // SGR terminates on M (press) / m (release)
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
if (x11 > 0) {
|
|
134
|
+
x11 -= seq.length || 1;
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if ((key && key.code === "[<") || seq.startsWith("\x1b[<")) {
|
|
138
|
+
sgr = !/[Mm]$/.test(seq); // single-chunk variant already includes terminator
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
if ((key && key.code === "[M") || seq.startsWith("\x1b[M")) {
|
|
142
|
+
const extra = Math.max(0, seq.length - 3); // bytes past "ESC [ M" in this chunk
|
|
143
|
+
x11 = Math.max(0, 3 - extra);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
if (key && key.shift && (key.name === "up" || key.name === "down")) {
|
|
147
|
+
return true; // shift+arrow scroll fallback
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
105
153
|
const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
106
154
|
const visLen = (s) => stripAnsi(s).length;
|
|
107
155
|
const pad = (s, n) => s + " ".repeat(Math.max(0, n - visLen(s)));
|
|
@@ -152,6 +200,28 @@ function die(msg) {
|
|
|
152
200
|
process.exit(1);
|
|
153
201
|
}
|
|
154
202
|
|
|
203
|
+
// process.cwd() throws (EPERM/ENOENT, "uv_cwd") when the shell's working
|
|
204
|
+
// directory was moved, deleted, or recreated out from under it. Fall back to
|
|
205
|
+
// home so spawned children never inherit a dead cwd.
|
|
206
|
+
function safeCwd() {
|
|
207
|
+
try {
|
|
208
|
+
return process.cwd();
|
|
209
|
+
} catch {
|
|
210
|
+
return os.homedir();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Turn a raw startup error into actionable guidance when it's a stale-cwd one.
|
|
215
|
+
function friendlyError(err) {
|
|
216
|
+
const msg = (err && (err.message || String(err))) || "unknown error";
|
|
217
|
+
if (/uv_cwd|getcwd/i.test(msg)) {
|
|
218
|
+
return "your terminal's working directory is stale or inaccessible.\n" +
|
|
219
|
+
" It was likely moved, deleted, or recreated out from under the shell.\n" +
|
|
220
|
+
" Open a new terminal (or run: cd ~), then run: egregore";
|
|
221
|
+
}
|
|
222
|
+
return msg;
|
|
223
|
+
}
|
|
224
|
+
|
|
155
225
|
function readRegistry() {
|
|
156
226
|
if (!fs.existsSync(REGISTRY)) return [];
|
|
157
227
|
try {
|
|
@@ -226,7 +296,7 @@ function pathContains(parent, child) {
|
|
|
226
296
|
return rel === "" || (!!rel && !rel.startsWith("..") && !path.isAbsolute(rel));
|
|
227
297
|
}
|
|
228
298
|
|
|
229
|
-
function initialCursorForCwd(registry, cwd =
|
|
299
|
+
function initialCursorForCwd(registry, cwd = safeCwd()) {
|
|
230
300
|
let best = -1;
|
|
231
301
|
let bestLen = -1;
|
|
232
302
|
for (let i = 0; i < registry.length; i++) {
|
|
@@ -363,6 +433,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
363
433
|
let done = false;
|
|
364
434
|
const title = inst.slug || inst.name || path.basename(inst.path);
|
|
365
435
|
const previousRaw = !!process.stdin.isRaw;
|
|
436
|
+
const isMouseEvent = makeMouseFilter();
|
|
366
437
|
|
|
367
438
|
const erase = () => {
|
|
368
439
|
if (!rendered) return;
|
|
@@ -378,6 +449,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
378
449
|
if (done) return;
|
|
379
450
|
done = true;
|
|
380
451
|
process.stdin.removeListener("keypress", onKey);
|
|
452
|
+
process.stdout.write(ANSI.mouseOff);
|
|
381
453
|
if (process.stdin.setRawMode) process.stdin.setRawMode(previousRaw);
|
|
382
454
|
if (!previousRaw) process.stdin.pause();
|
|
383
455
|
erase();
|
|
@@ -399,6 +471,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
399
471
|
};
|
|
400
472
|
|
|
401
473
|
function onKey(chunk, key = {}) {
|
|
474
|
+
if (isMouseEvent(chunk, key)) return; // drop scroll-wheel / mouse escape sequences
|
|
402
475
|
if (key.ctrl && key.name === "c") {
|
|
403
476
|
cleanup();
|
|
404
477
|
process.exit(130);
|
|
@@ -424,6 +497,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
424
497
|
readline.emitKeypressEvents(process.stdin);
|
|
425
498
|
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
426
499
|
process.stdin.resume();
|
|
500
|
+
process.stdout.write(ANSI.mouseOff);
|
|
427
501
|
process.stdin.on("keypress", onKey);
|
|
428
502
|
render();
|
|
429
503
|
});
|
|
@@ -572,6 +646,18 @@ function runtimeLaunchArgs(runtime, egregoreDir) {
|
|
|
572
646
|
async function launch(inst, runtimeOverride) {
|
|
573
647
|
if (!inst) die("no instance to launch");
|
|
574
648
|
if (!fs.existsSync(inst.path)) die(`instance path does not exist: ${inst.path}`);
|
|
649
|
+
// existsSync can pass while the path is still untraversable (a parent lost
|
|
650
|
+
// execute permission, or the dir was recreated under the shell). realpathSync
|
|
651
|
+
// walks the full path and surfaces that before we spawn the harness into a
|
|
652
|
+
// dead directory and produce a cryptic getcwd/EPERM cascade.
|
|
653
|
+
try {
|
|
654
|
+
fs.realpathSync(inst.path);
|
|
655
|
+
fs.accessSync(inst.path, fs.constants.X_OK);
|
|
656
|
+
} catch {
|
|
657
|
+
die(`instance directory isn't accessible: ${inst.path}\n` +
|
|
658
|
+
" Your terminal's working directory may be stale (the folder was moved or recreated).\n" +
|
|
659
|
+
" Open a new terminal (or run: cd ~), then run: egregore");
|
|
660
|
+
}
|
|
575
661
|
const runtime = await chooseRuntimeForLaunch(inst, runtimeOverride);
|
|
576
662
|
if (!runtime) return;
|
|
577
663
|
const binary = runtimeBinary(runtime);
|
|
@@ -609,7 +695,7 @@ function setupNewEgregore(runtimeOverride) {
|
|
|
609
695
|
if (runtimeOverride) args.push("--runtime", runtimeOverride);
|
|
610
696
|
const child = spawn("npx", args, {
|
|
611
697
|
stdio: "inherit",
|
|
612
|
-
cwd:
|
|
698
|
+
cwd: safeCwd(),
|
|
613
699
|
env: { ...process.env },
|
|
614
700
|
});
|
|
615
701
|
child.on("exit", (code, signal) => {
|
|
@@ -1586,7 +1672,8 @@ async function browser(args = {}) {
|
|
|
1586
1672
|
};
|
|
1587
1673
|
|
|
1588
1674
|
// ── setup / teardown ───────────────────
|
|
1589
|
-
process.stdout.write(ANSI.altScreenEnter + ANSI.cursorHide + ANSI.clear + ANSI.home);
|
|
1675
|
+
process.stdout.write(ANSI.altScreenEnter + ANSI.mouseOff + ANSI.cursorHide + ANSI.clear + ANSI.home);
|
|
1676
|
+
const isMouseEvent = makeMouseFilter();
|
|
1590
1677
|
let done = false;
|
|
1591
1678
|
const cleanup = () => {
|
|
1592
1679
|
if (done) return;
|
|
@@ -1594,7 +1681,7 @@ async function browser(args = {}) {
|
|
|
1594
1681
|
process.stdin.setRawMode(false);
|
|
1595
1682
|
process.stdin.pause();
|
|
1596
1683
|
process.stdin.removeAllListeners("keypress");
|
|
1597
|
-
process.stdout.write(ANSI.cursorShow + ANSI.altScreenLeave);
|
|
1684
|
+
process.stdout.write(ANSI.mouseOff + ANSI.cursorShow + ANSI.altScreenLeave);
|
|
1598
1685
|
};
|
|
1599
1686
|
process.on("exit", cleanup);
|
|
1600
1687
|
process.on("SIGINT", () => { cleanup(); process.exit(130); });
|
|
@@ -1618,6 +1705,7 @@ async function browser(args = {}) {
|
|
|
1618
1705
|
return new Promise((resolve) => {
|
|
1619
1706
|
process.stdin.on("keypress", (chunk, key) => {
|
|
1620
1707
|
if (!key) return;
|
|
1708
|
+
if (isMouseEvent(chunk, key)) return; // drop scroll-wheel / mouse escape sequences
|
|
1621
1709
|
|
|
1622
1710
|
if (state.runtimeInst) {
|
|
1623
1711
|
const runtimes = runtimeChoicesFor(state.runtimeInst, args.runtimeOverride);
|
|
@@ -1910,6 +1998,15 @@ async function numberedPicker(registry, runtimeOverride) {
|
|
|
1910
1998
|
// ── main ────────────────────────────────────────────────────────────
|
|
1911
1999
|
|
|
1912
2000
|
function main() {
|
|
2001
|
+
// Self-heal a stale/inaccessible working directory before anything spawns —
|
|
2002
|
+
// otherwise every child (harness, npx) inherits the dead cwd and fails with
|
|
2003
|
+
// getcwd/EPERM. Home is always a safe place to stand.
|
|
2004
|
+
try {
|
|
2005
|
+
process.cwd();
|
|
2006
|
+
} catch {
|
|
2007
|
+
try { process.chdir(os.homedir()); } catch { /* nothing more we can do */ }
|
|
2008
|
+
}
|
|
2009
|
+
|
|
1913
2010
|
const parsed = parseRuntimeFlags(process.argv.slice(2));
|
|
1914
2011
|
const args = parsed.args;
|
|
1915
2012
|
const runtimeOverride = parsed.runtimeOverride;
|
|
@@ -1968,8 +2065,8 @@ function main() {
|
|
|
1968
2065
|
try {
|
|
1969
2066
|
const r = main();
|
|
1970
2067
|
if (r && typeof r.then === "function") {
|
|
1971
|
-
r.catch((err) => die(
|
|
2068
|
+
r.catch((err) => die(friendlyError(err)));
|
|
1972
2069
|
}
|
|
1973
2070
|
} catch (err) {
|
|
1974
|
-
die(
|
|
2071
|
+
die(friendlyError(err));
|
|
1975
2072
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-egregore",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.6",
|
|
4
4
|
"description": "Set up Egregore for your team in one command — installs the egregore launcher and your choice of Claude Code or Codex.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build:runtime": "node scripts/build-runtime-bundle.mjs",
|
|
14
|
-
"test": "node scripts/build-runtime-bundle.mjs --check && node --test test/context.test.js test/parse-join-target.test.js test/skip-repos.test.js test/onboarding-shortcircuit.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/codex-runtime.test.js test/installer-runtime-source.test.js",
|
|
14
|
+
"test": "node scripts/build-runtime-bundle.mjs --check && node --test test/context.test.js test/parse-join-target.test.js test/skip-repos.test.js test/onboarding-shortcircuit.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/codex-runtime.test.js test/installer-runtime-source.test.js test/scroll-repro.test.js",
|
|
15
15
|
"test:e2e": "node --test test/e2e-local.test.js",
|
|
16
16
|
"test:all": "node scripts/build-runtime-bundle.mjs --check && node --test test/"
|
|
17
17
|
},
|
|
@@ -134,7 +134,7 @@ DASHBOARD_URL=$(echo "$_DB_PUBLISH_OUT" | grep -o 'https://[^ ]*' | tail -1)
|
|
|
134
134
|
if [ -z "$DASHBOARD_URL" ]; then
|
|
135
135
|
_DB_HTML="/tmp/egregore-artifacts/dashboard-${EGREGORE_SESSION_ID}.html"
|
|
136
136
|
mkdir -p /tmp/egregore-artifacts
|
|
137
|
-
if npx egregore-artifacts document "$_DB_MD" --output "$_DB_HTML" --no-open >/dev/null 2>&1 && [ -f "$_DB_HTML" ]; then
|
|
137
|
+
if npx egregore-artifacts@latest document "$_DB_MD" --output "$_DB_HTML" --no-open >/dev/null 2>&1 && [ -f "$_DB_HTML" ]; then
|
|
138
138
|
DASHBOARD_URL="file://${_DB_HTML}"
|
|
139
139
|
fi
|
|
140
140
|
fi
|