create-egregore 0.18.3 → 0.18.5
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.19
|
|
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.19";
|
|
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)));
|
|
@@ -363,6 +411,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
363
411
|
let done = false;
|
|
364
412
|
const title = inst.slug || inst.name || path.basename(inst.path);
|
|
365
413
|
const previousRaw = !!process.stdin.isRaw;
|
|
414
|
+
const isMouseEvent = makeMouseFilter();
|
|
366
415
|
|
|
367
416
|
const erase = () => {
|
|
368
417
|
if (!rendered) return;
|
|
@@ -378,6 +427,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
378
427
|
if (done) return;
|
|
379
428
|
done = true;
|
|
380
429
|
process.stdin.removeListener("keypress", onKey);
|
|
430
|
+
process.stdout.write(ANSI.mouseOff);
|
|
381
431
|
if (process.stdin.setRawMode) process.stdin.setRawMode(previousRaw);
|
|
382
432
|
if (!previousRaw) process.stdin.pause();
|
|
383
433
|
erase();
|
|
@@ -399,6 +449,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
399
449
|
};
|
|
400
450
|
|
|
401
451
|
function onKey(chunk, key = {}) {
|
|
452
|
+
if (isMouseEvent(chunk, key)) return; // drop scroll-wheel / mouse escape sequences
|
|
402
453
|
if (key.ctrl && key.name === "c") {
|
|
403
454
|
cleanup();
|
|
404
455
|
process.exit(130);
|
|
@@ -424,6 +475,7 @@ function pickRuntimeInteractive(inst, runtimes, stored) {
|
|
|
424
475
|
readline.emitKeypressEvents(process.stdin);
|
|
425
476
|
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
426
477
|
process.stdin.resume();
|
|
478
|
+
process.stdout.write(ANSI.mouseOff);
|
|
427
479
|
process.stdin.on("keypress", onKey);
|
|
428
480
|
render();
|
|
429
481
|
});
|
|
@@ -1338,6 +1390,10 @@ function renderRuntimePanel({ inst, cursor, width, height }) {
|
|
|
1338
1390
|
const desc = runtimeChoiceDescription(runtime, inst, stored);
|
|
1339
1391
|
lines.push(boxLine(`${marker} ${pad(labelText, 16)} ${DIM}${desc}${RESET}`, innerWidth, margin));
|
|
1340
1392
|
}
|
|
1393
|
+
// Coming-soon harnesses — shown for visibility, not selectable yet.
|
|
1394
|
+
for (const soon of ["Hermes", "Pi"]) {
|
|
1395
|
+
lines.push(boxLine(`${DIM}· ${pad(soon, 16)} coming soon${RESET}`, innerWidth, margin));
|
|
1396
|
+
}
|
|
1341
1397
|
|
|
1342
1398
|
lines.push(emptyBoxLine(innerWidth, margin));
|
|
1343
1399
|
lines.push(boxLine(`${DIM}↑↓ navigate · enter select · 1-${runtimes.length} quick select · esc back · q quit${RESET}`, innerWidth, margin));
|
|
@@ -1582,7 +1638,8 @@ async function browser(args = {}) {
|
|
|
1582
1638
|
};
|
|
1583
1639
|
|
|
1584
1640
|
// ── setup / teardown ───────────────────
|
|
1585
|
-
process.stdout.write(ANSI.altScreenEnter + ANSI.cursorHide + ANSI.clear + ANSI.home);
|
|
1641
|
+
process.stdout.write(ANSI.altScreenEnter + ANSI.mouseOff + ANSI.cursorHide + ANSI.clear + ANSI.home);
|
|
1642
|
+
const isMouseEvent = makeMouseFilter();
|
|
1586
1643
|
let done = false;
|
|
1587
1644
|
const cleanup = () => {
|
|
1588
1645
|
if (done) return;
|
|
@@ -1590,7 +1647,7 @@ async function browser(args = {}) {
|
|
|
1590
1647
|
process.stdin.setRawMode(false);
|
|
1591
1648
|
process.stdin.pause();
|
|
1592
1649
|
process.stdin.removeAllListeners("keypress");
|
|
1593
|
-
process.stdout.write(ANSI.cursorShow + ANSI.altScreenLeave);
|
|
1650
|
+
process.stdout.write(ANSI.mouseOff + ANSI.cursorShow + ANSI.altScreenLeave);
|
|
1594
1651
|
};
|
|
1595
1652
|
process.on("exit", cleanup);
|
|
1596
1653
|
process.on("SIGINT", () => { cleanup(); process.exit(130); });
|
|
@@ -1614,6 +1671,7 @@ async function browser(args = {}) {
|
|
|
1614
1671
|
return new Promise((resolve) => {
|
|
1615
1672
|
process.stdin.on("keypress", (chunk, key) => {
|
|
1616
1673
|
if (!key) return;
|
|
1674
|
+
if (isMouseEvent(chunk, key)) return; // drop scroll-wheel / mouse escape sequences
|
|
1617
1675
|
|
|
1618
1676
|
if (state.runtimeInst) {
|
|
1619
1677
|
const runtimes = runtimeChoicesFor(state.runtimeInst, args.runtimeOverride);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-egregore",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.5",
|
|
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
|
},
|
|
@@ -154,6 +154,26 @@ wait $API_PID $GIT_PID $LOCAL_PID 2>/dev/null || true
|
|
|
154
154
|
# --- Read results ---
|
|
155
155
|
PRS=$(cat "$TMPDIR/prs.json" 2>/dev/null || echo "[]")
|
|
156
156
|
echo "$PRS" | jq . >/dev/null 2>&1 || PRS="[]"
|
|
157
|
+
|
|
158
|
+
# Resolve PR author GitHub logins -> egregore display names. `gh pr list` returns
|
|
159
|
+
# the raw github login (e.g. "fcdagdelen"); without this it leaks into activity
|
|
160
|
+
# instead of the person's display name ("cem"). Map via the graph when connected;
|
|
161
|
+
# fall back to the github profile name, then the login. Author becomes a string.
|
|
162
|
+
if [ -n "$PRS" ] && [ "$PRS" != "[]" ]; then
|
|
163
|
+
AUTHOR_MAP='{}'
|
|
164
|
+
if [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
|
|
165
|
+
MAP_RAW=$(bash "$SCRIPT_DIR/bin/graph.sh" query \
|
|
166
|
+
"MATCH (p:Person) WHERE p.github IS NOT NULL RETURN p.github AS gh, p.name AS name" 2>/dev/null)
|
|
167
|
+
AUTHOR_MAP=$(printf '%s' "$MAP_RAW" | jq -c \
|
|
168
|
+
'reduce (.values[]?) as $v ({}; .[($v[0]|ascii_downcase)] = $v[1])' 2>/dev/null || echo '{}')
|
|
169
|
+
fi
|
|
170
|
+
PRS=$(printf '%s' "$PRS" | jq -c --argjson map "$AUTHOR_MAP" '
|
|
171
|
+
map(
|
|
172
|
+
(if (.author|type)=="object" then .author else {login: (.author|tostring), name: null} end) as $a
|
|
173
|
+
| .author = ([$map[(($a.login // "") | ascii_downcase)], $a.name, $a.login]
|
|
174
|
+
| map(select(. != null and . != "")) | first // "unknown")
|
|
175
|
+
)' 2>/dev/null || printf '%s' "$PRS")
|
|
176
|
+
fi
|
|
157
177
|
DISK_HANDOFFS=$(cat "$TMPDIR/disk_handoffs.txt" 2>/dev/null || echo "")
|
|
158
178
|
DISK_DECISIONS=$(cat "$TMPDIR/disk_decisions.txt" 2>/dev/null || echo "")
|
|
159
179
|
LOCAL_SESSIONS=$(cat "$TMPDIR/local_sessions.json" 2>/dev/null || echo '{"my_sessions":[],"team_sessions":[]}')
|
|
@@ -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
|