create-egregore 0.19.17 → 0.19.19

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.19.17
2
+ // egregore-launcher-version: 0.19.19
3
3
  //
4
4
  // egregore — launch and browse Egregore instances from your terminal.
5
5
  // Installed by create-egregore. Reads ~/.egregore/instances.json.
@@ -33,7 +33,7 @@ const crypto = require("node:crypto");
33
33
  const { spawnSync, spawn } = require("node:child_process");
34
34
  const readline = require("node:readline");
35
35
 
36
- const VERSION = "0.19.17";
36
+ const VERSION = "0.19.19";
37
37
  const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
38
38
  const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
39
39
  const UPDATE_CACHE_FILE = path.join(os.homedir(), ".egregore", "update-check.json");
@@ -42,7 +42,6 @@ const UPDATE_REGISTRY_URL =
42
42
  process.env.EGREGORE_UPDATE_REGISTRY_URL ||
43
43
  `https://registry.npmjs.org/${PUBLIC_NPX_PACKAGE}/latest`;
44
44
  const UPDATE_AVAILABLE_CACHE_TTL_MS = 6 * 60 * 60 * 1000;
45
- const UPDATE_CURRENT_CACHE_TTL_MS = 5 * 60 * 1000;
46
45
  const UPDATE_FAILURE_CACHE_TTL_MS = 5 * 60 * 1000;
47
46
  const UPDATE_CHECK_TIMEOUT_MS = 1500;
48
47
  const CONNECT_API_URL = (
@@ -1051,11 +1050,14 @@ function readUpdateCache() {
1051
1050
  const age = Date.now() - new Date(cache.checked_at).getTime();
1052
1051
  const cachedUpdate = cache.latest ? cliUpdateState(cache.latest) : null;
1053
1052
  if (cache.latest && !cachedUpdate) return null;
1053
+ // A cached "current" result is never authoritative. Startup has already
1054
+ // rendered by the time this check runs, so revalidate it in the background
1055
+ // on every launch. Otherwise a release published seconds after a user opens
1056
+ // Egregore stays invisible until the cache TTL expires.
1057
+ if (cachedUpdate && !cachedUpdate.available) return null;
1054
1058
  const ttl = !cache.latest
1055
1059
  ? UPDATE_FAILURE_CACHE_TTL_MS
1056
- : cachedUpdate.available
1057
- ? UPDATE_AVAILABLE_CACHE_TTL_MS
1058
- : UPDATE_CURRENT_CACHE_TTL_MS;
1060
+ : UPDATE_AVAILABLE_CACHE_TTL_MS;
1059
1061
  if (!Number.isFinite(age) || age < 0 || age > ttl) return null;
1060
1062
  if (!cache.latest) return { current: VERSION, latest: null, available: false };
1061
1063
  return cachedUpdate;
@@ -1211,6 +1213,19 @@ function writeJsonFileAtomic(file, value) {
1211
1213
  atomicWrite(file, JSON.stringify(value, null, 2) + "\n", 0o644);
1212
1214
  }
1213
1215
 
1216
+ function normalizeClaudeRegistryDenyRule(instancePath) {
1217
+ const stale = "Write(~/.egregore/instances.json)";
1218
+ const supported = "Edit(~/.egregore/instances.json)";
1219
+ for (const relative of [".claude/settings.json", ".claude/settings.local.json"]) {
1220
+ const file = path.join(instancePath, relative);
1221
+ const settings = readJsonFile(file);
1222
+ const deny = settings?.permissions?.deny;
1223
+ if (!Array.isArray(deny) || !deny.includes(stale)) continue;
1224
+ settings.permissions.deny = [...new Set(deny.map((rule) => rule === stale ? supported : rule))];
1225
+ writeJsonFileAtomic(file, settings);
1226
+ }
1227
+ }
1228
+
1214
1229
  function writeEnvValueAtomic(file, key, value) {
1215
1230
  const lines = fs.existsSync(file)
1216
1231
  ? fs.readFileSync(file, "utf-8").split(/\r?\n/)
@@ -1439,6 +1454,7 @@ async function cmdConnect(args) {
1439
1454
  api_url: claim.data.api_url,
1440
1455
  });
1441
1456
  writeEnvValueAtomic(envFile, "EGREGORE_API_KEY", claim.data.api_key);
1457
+ normalizeClaudeRegistryDenyRule(inst.path);
1442
1458
  persistConnectState(inst, {
1443
1459
  status: "backfilling",
1444
1460
  activation_protocol: claim.data.activation_protocol,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-egregore",
3
- "version": "0.19.17",
3
+ "version": "0.19.19",
4
4
  "description": "Set up Egregore for your team in one command — installs the egregore launcher and your choice of Claude Code, Codex, or Pi.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -2,6 +2,8 @@
2
2
  hooks = true
3
3
 
4
4
  [tui]
5
+ # Codex currently accepts built-in footer item IDs only. Egregore's dynamic
6
+ # ◆ CONNECTED / ◇ LOCAL identity is rendered by bin/codex-session-start.sh.
5
7
  status_line = [
6
8
  "model-with-reasoning",
7
9
  "git-branch",
@@ -57,6 +57,7 @@ fi
57
57
 
58
58
  LOCAL_MODE="false"
59
59
  [ "$(_detect_mode)" = "local" ] && LOCAL_MODE="true"
60
+ MODE_BADGE="$(_runtime_mode_badge)"
60
61
 
61
62
  if [ "$LOCAL_MODE" != "true" ]; then
62
63
  if [ -f "$ENV_FILE" ] && grep -q '^EGREGORE_API_KEY=.' "$ENV_FILE" 2>/dev/null; then
@@ -133,7 +134,7 @@ EOF
133
134
  render_card() {
134
135
  local separator identity_left identity_right line_width pad footer_left footer_right board_url has_failure failed_services
135
136
  separator=" ..................................................................."
136
- identity_left=" ${GITHUB_ORG:-$ORG_NAME}/${REPO_NAME}"
137
+ identity_left=" ${GITHUB_ORG:-$ORG_NAME}/${REPO_NAME} · ${MODE_BADGE}"
137
138
  identity_right="${DISPLAY_NAME} · ${BRANCH:-?}"
138
139
  line_width=67
139
140
  pad=$((line_width - ${#identity_left} - ${#identity_right}))
@@ -59,13 +59,22 @@ _get_base_branch() {
59
59
  # Detect local vs connected mode
60
60
  _detect_mode() {
61
61
  local config="${CONFIG:-$SCRIPT_DIR/egregore.json}"
62
- local mode
63
- mode=$(jq -r '.mode // empty' "$config" 2>/dev/null || true)
64
- local api_url
65
- api_url=$(jq -r '.api_url // empty' "$config" 2>/dev/null || true)
66
- if [ "$mode" = "local" ] || [ -z "$api_url" ]; then
62
+ if [ -f "$config" ] && jq -e \
63
+ '(.mode // "") != "local" and ((.api_url // "") | length > 0)' \
64
+ "$config" >/dev/null 2>&1; then
65
+ echo "connected"
66
+ else
67
67
  echo "local"
68
+ fi
69
+ }
70
+
71
+ # Compact runtime identity shared by terminal surfaces. The sigils deliberately
72
+ # distinguish an active hosted connection from the self-contained local mode
73
+ # without implying that local Egregore is unhealthy.
74
+ _runtime_mode_badge() {
75
+ if [ "$(_detect_mode)" = "connected" ]; then
76
+ echo "◆ CONNECTED"
68
77
  else
69
- echo "connected"
78
+ echo "◇ LOCAL"
70
79
  fi
71
80
  }
@@ -2,6 +2,8 @@
2
2
  hooks = true
3
3
 
4
4
  [tui]
5
+ # Codex currently accepts built-in footer item IDs only. Egregore's dynamic
6
+ # ◆ CONNECTED / ◇ LOCAL identity is rendered by bin/codex-session-start.sh.
5
7
  status_line = [
6
8
  "model-with-reasoning",
7
9
  "git-branch",
@@ -57,6 +57,7 @@ fi
57
57
 
58
58
  LOCAL_MODE="false"
59
59
  [ "$(_detect_mode)" = "local" ] && LOCAL_MODE="true"
60
+ MODE_BADGE="$(_runtime_mode_badge)"
60
61
 
61
62
  if [ "$LOCAL_MODE" != "true" ]; then
62
63
  if [ -f "$ENV_FILE" ] && grep -q '^EGREGORE_API_KEY=.' "$ENV_FILE" 2>/dev/null; then
@@ -133,7 +134,7 @@ EOF
133
134
  render_card() {
134
135
  local separator identity_left identity_right line_width pad footer_left footer_right board_url has_failure failed_services
135
136
  separator=" ..................................................................."
136
- identity_left=" ${GITHUB_ORG:-$ORG_NAME}/${REPO_NAME}"
137
+ identity_left=" ${GITHUB_ORG:-$ORG_NAME}/${REPO_NAME} · ${MODE_BADGE}"
137
138
  identity_right="${DISPLAY_NAME} · ${BRANCH:-?}"
138
139
  line_width=67
139
140
  pad=$((line_width - ${#identity_left} - ${#identity_right}))
@@ -59,13 +59,22 @@ _get_base_branch() {
59
59
  # Detect local vs connected mode
60
60
  _detect_mode() {
61
61
  local config="${CONFIG:-$SCRIPT_DIR/egregore.json}"
62
- local mode
63
- mode=$(jq -r '.mode // empty' "$config" 2>/dev/null || true)
64
- local api_url
65
- api_url=$(jq -r '.api_url // empty' "$config" 2>/dev/null || true)
66
- if [ "$mode" = "local" ] || [ -z "$api_url" ]; then
62
+ if [ -f "$config" ] && jq -e \
63
+ '(.mode // "") != "local" and ((.api_url // "") | length > 0)' \
64
+ "$config" >/dev/null 2>&1; then
65
+ echo "connected"
66
+ else
67
67
  echo "local"
68
+ fi
69
+ }
70
+
71
+ # Compact runtime identity shared by terminal surfaces. The sigils deliberately
72
+ # distinguish an active hosted connection from the self-contained local mode
73
+ # without implying that local Egregore is unhealthy.
74
+ _runtime_mode_badge() {
75
+ if [ "$(_detect_mode)" = "connected" ]; then
76
+ echo "◆ CONNECTED"
68
77
  else
69
- echo "connected"
78
+ echo "◇ LOCAL"
70
79
  fi
71
80
  }