create-egregore 0.21.0-runtime-mvp.20 → 0.21.0-runtime-mvp.22
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 +39 -13
- package/bin/cli.js +4 -0
- package/lib/setup.js +54 -7
- package/package.json +1 -1
- package/runtime/claude/bin/runtime-identity.sh +12 -3
- package/runtime/claude/bin/runtime-upgrade.sh +28 -6
- package/runtime/codex/bin/runtime-identity.sh +12 -3
- package/runtime/codex/bin/runtime-upgrade.sh +28 -6
- package/runtime/pi/bin/runtime-identity.sh +12 -3
- package/runtime/pi/bin/runtime-upgrade.sh +28 -6
- package/runtime/prime/bin/runtime-identity.sh +12 -3
- package/runtime/prime/bin/runtime-upgrade.sh +28 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// egregore-launcher-version: 0.21.0-runtime-mvp.
|
|
2
|
+
// egregore-launcher-version: 0.21.0-runtime-mvp.22
|
|
3
3
|
//
|
|
4
4
|
// egregore — launch and browse Egregore instances from your terminal.
|
|
5
5
|
// Installed by create-egregore. Reads ~/.egregore/instances.json.
|
|
@@ -35,7 +35,7 @@ const crypto = require("node:crypto");
|
|
|
35
35
|
const { spawnSync, spawn } = require("node:child_process");
|
|
36
36
|
const readline = require("node:readline");
|
|
37
37
|
|
|
38
|
-
const VERSION = "0.21.0-runtime-mvp.
|
|
38
|
+
const VERSION = "0.21.0-runtime-mvp.22";
|
|
39
39
|
const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
|
|
40
40
|
const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
|
|
41
41
|
const UPDATE_CACHE_FILE = path.join(os.homedir(), ".egregore", "update-check.json");
|
|
@@ -2341,8 +2341,18 @@ function connectedModeSuffix(instPath) {
|
|
|
2341
2341
|
function packagedUpgradeScript() {
|
|
2342
2342
|
const seeded = process.env.EGREGORE_RUNTIME_PACKAGED_BRIDGE;
|
|
2343
2343
|
if (seeded !== undefined) return seeded || null;
|
|
2344
|
-
|
|
2345
|
-
|
|
2344
|
+
// The launcher is copied into a PATH directory as a standalone executable,
|
|
2345
|
+
// so __dirname normally points at /usr/local/bin or ~/.local/bin rather than
|
|
2346
|
+
// the npm package that supplied it. installLauncherBinary keeps the matching
|
|
2347
|
+
// Runtime engine in a versioned per-user directory outside every Egregore
|
|
2348
|
+
// checkout. The package-adjacent fallback keeps direct source/package runs
|
|
2349
|
+
// working without a separate install step.
|
|
2350
|
+
const runtimeBase = process.env.EGREGORE_LAUNCHER_RUNTIME_DIR
|
|
2351
|
+
|| path.join(os.homedir(), ".egregore", "launcher-runtime");
|
|
2352
|
+
const installed = path.join(runtimeBase, VERSION, "claude", "bin", "runtime-upgrade.sh");
|
|
2353
|
+
if (fs.existsSync(installed)) return installed;
|
|
2354
|
+
const adjacent = path.join(__dirname, "..", "runtime", "claude", "bin", "runtime-upgrade.sh");
|
|
2355
|
+
return fs.existsSync(adjacent) ? adjacent : null;
|
|
2346
2356
|
}
|
|
2347
2357
|
|
|
2348
2358
|
function resolveUpgradeBridge(inst) {
|
|
@@ -2489,20 +2499,33 @@ function formatTelemetryLines(status) {
|
|
|
2489
2499
|
function upgradeStatus(inst, { fetch = false } = {}) {
|
|
2490
2500
|
const args = ["status"]; if (fetch) args.push("--fetch");
|
|
2491
2501
|
const r = runUpgrade(inst, args);
|
|
2492
|
-
if (!r || r.status !== 0 || !r.stdout)
|
|
2493
|
-
|
|
2502
|
+
if (!r || r.status !== 0 || !r.stdout) {
|
|
2503
|
+
const detail = String((r && (r.stderr || r.stdout)) || "Runtime status probe failed")
|
|
2504
|
+
.trim().split("\n")[0];
|
|
2505
|
+
return { status: "unavailable", failure: { message: detail } };
|
|
2506
|
+
}
|
|
2507
|
+
try { return JSON.parse(r.stdout); } catch {
|
|
2508
|
+
return { status: "unavailable", failure: { message: "Runtime status returned an unreadable response" } };
|
|
2509
|
+
}
|
|
2494
2510
|
}
|
|
2495
2511
|
|
|
2496
2512
|
function upgradeStatusAsync(inst, cb) {
|
|
2497
2513
|
const bridge = resolveUpgradeBridge(inst);
|
|
2498
|
-
if (!bridge) return cb(
|
|
2499
|
-
let buf = "";
|
|
2514
|
+
if (!bridge) return cb({ status: "unavailable", failure: { message: "No Runtime update engine is installed" } });
|
|
2515
|
+
let buf = ""; let err = "";
|
|
2500
2516
|
try {
|
|
2501
|
-
const child = spawn("bash", [bridge.script, "status"], { cwd: inst.path, stdio: ["ignore", "pipe", "
|
|
2517
|
+
const child = spawn("bash", [bridge.script, "status"], { cwd: inst.path, stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, ...bridge.env } });
|
|
2502
2518
|
child.stdout.on("data", (d) => { buf += d; });
|
|
2503
|
-
child.on("
|
|
2504
|
-
child.on("
|
|
2505
|
-
|
|
2519
|
+
child.stderr.on("data", (d) => { err += d; });
|
|
2520
|
+
child.on("close", (code) => {
|
|
2521
|
+
if (code === 0) {
|
|
2522
|
+
try { cb(JSON.parse(buf)); return; } catch {}
|
|
2523
|
+
}
|
|
2524
|
+
const detail = String(err || buf || "Runtime status probe failed").trim().split("\n")[0];
|
|
2525
|
+
cb({ status: "unavailable", failure: { message: detail } });
|
|
2526
|
+
});
|
|
2527
|
+
child.on("error", (error) => cb({ status: "unavailable", failure: { message: error.message } }));
|
|
2528
|
+
} catch (error) { cb({ status: "unavailable", failure: { message: error.message } }); }
|
|
2506
2529
|
}
|
|
2507
2530
|
|
|
2508
2531
|
// Local retrieval health for the settings surface. Package-update state,
|
|
@@ -2622,6 +2645,7 @@ const UPGRADE_STATUS_LABEL = {
|
|
|
2622
2645
|
active: "active",
|
|
2623
2646
|
cancelled: "cancelled",
|
|
2624
2647
|
"rolled-back": "rolled back",
|
|
2648
|
+
unavailable: "unavailable",
|
|
2625
2649
|
};
|
|
2626
2650
|
|
|
2627
2651
|
// Settings-row truth for the Runtime update line. The row must say outright
|
|
@@ -2635,6 +2659,7 @@ function runtimeUpdateRowValue(st, candidate) {
|
|
|
2635
2659
|
if (candidate && candidate !== v) return `${v} active ${YELLOW}· update available ${candidate}${RESET}`;
|
|
2636
2660
|
return `${GREEN}${v} active${RESET}${candidate ? `${DIM} · up to date${RESET}` : ""}`;
|
|
2637
2661
|
}
|
|
2662
|
+
if (st.status === "unavailable") return `${YELLOW}update unavailable${RESET}`;
|
|
2638
2663
|
if (st.status === "ready-to-activate") return `${GREEN}${upgradeSummary(st)}${RESET}`;
|
|
2639
2664
|
if (st.status === "failed" || st.status === "interrupted") return `${YELLOW}${upgradeSummary(st)}${RESET}`;
|
|
2640
2665
|
if (st.status === "preparing" || st.status === "pending") return `${DIM}${upgradeSummary(st)}${RESET}`;
|
|
@@ -2675,7 +2700,7 @@ function formatUpgradeLines(inst, st, { candidate = "", retrieval = null } = {})
|
|
|
2675
2700
|
if (d.candidate_digest) lines.push(`Package digest: sha256 ${String(d.candidate_digest).slice(0, 16)}…`);
|
|
2676
2701
|
// A recorded failure only needs attention while the transaction is stuck
|
|
2677
2702
|
// on it; once a later prepare succeeds the line would contradict "ready".
|
|
2678
|
-
if (d.failure && d.failure.message && (
|
|
2703
|
+
if (d.failure && d.failure.message && (["failed", "interrupted", "unavailable"].includes(d.status))) {
|
|
2679
2704
|
lines.push(`Attention: ${d.failure.message}`);
|
|
2680
2705
|
}
|
|
2681
2706
|
if (d.rollback_version && d.status !== "none") lines.push(`Rollback target: ${d.rollback_version}`);
|
|
@@ -2750,6 +2775,7 @@ async function cmdSettingsRuntime(inst, args) {
|
|
|
2750
2775
|
const st = upgradeStatus(inst, { fetch: fetchFlag });
|
|
2751
2776
|
if (st === null) { process.stderr.write("Runtime update state is unavailable for this egregore.\n"); process.exitCode = 1; return; }
|
|
2752
2777
|
emit(st);
|
|
2778
|
+
if (st.status === "unavailable") process.exitCode = 1;
|
|
2753
2779
|
if (action === "review" || (st.status !== "active" && st.status !== "none")) {
|
|
2754
2780
|
process.stdout.write("\nWhat stays:\n");
|
|
2755
2781
|
for (const s of UPGRADE_STAYS) process.stdout.write(` · ${s}\n`);
|
package/bin/cli.js
CHANGED
|
@@ -471,6 +471,10 @@ async function main() {
|
|
|
471
471
|
ui.error("Could not refresh the Egregore CLI.");
|
|
472
472
|
process.exit(1);
|
|
473
473
|
}
|
|
474
|
+
if (!alias.runtimeBridgePath || !fs.existsSync(alias.runtimeBridgePath)) {
|
|
475
|
+
ui.error("Could not refresh the Runtime update engine.");
|
|
476
|
+
process.exit(1);
|
|
477
|
+
}
|
|
474
478
|
ui.success(`Egregore CLI is current at ${alias.binaryPath}`);
|
|
475
479
|
return;
|
|
476
480
|
}
|
package/lib/setup.js
CHANGED
|
@@ -1283,6 +1283,7 @@ async function launchOrInstruct(egregoreDir, alias, ui, ctx = {}) {
|
|
|
1283
1283
|
// browser, better rendering, and richer keybinds.
|
|
1284
1284
|
const LAUNCHER_TEMPLATE_JS = path.join(__dirname, "..", "assets", "egregore-launcher.js");
|
|
1285
1285
|
const LAUNCHER_TEMPLATE_SH = path.join(__dirname, "..", "assets", "egregore-launcher.sh");
|
|
1286
|
+
const LAUNCHER_RUNTIME_TEMPLATE = path.join(__dirname, "..", "runtime", "claude");
|
|
1286
1287
|
|
|
1287
1288
|
function readLauncherTemplate() {
|
|
1288
1289
|
// Prefer the Node launcher; fall back to bash only if the .js is missing.
|
|
@@ -1294,6 +1295,50 @@ function currentTemplatePath() {
|
|
|
1294
1295
|
return fs.existsSync(LAUNCHER_TEMPLATE_JS) ? LAUNCHER_TEMPLATE_JS : LAUNCHER_TEMPLATE_SH;
|
|
1295
1296
|
}
|
|
1296
1297
|
|
|
1298
|
+
function launcherRuntimeRoot(version) {
|
|
1299
|
+
const base = process.env.EGREGORE_LAUNCHER_RUNTIME_DIR
|
|
1300
|
+
|| path.join(os.homedir(), ".egregore", "launcher-runtime");
|
|
1301
|
+
return version ? path.join(base, version) : null;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
function launcherRuntimeBridge(version) {
|
|
1305
|
+
const root = launcherRuntimeRoot(version);
|
|
1306
|
+
return root ? path.join(root, "claude", "bin", "runtime-upgrade.sh") : null;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// The PATH launcher is a copied standalone file, not an npm shim, so it cannot
|
|
1310
|
+
// reach runtime/ through __dirname after installation. Keep the matching
|
|
1311
|
+
// upgrade engine in a versioned per-user directory. This is deliberately
|
|
1312
|
+
// outside registered Egregore checkouts: refreshing the global CLI must never
|
|
1313
|
+
// spray framework files into an instance or dirty its Git working tree.
|
|
1314
|
+
function installLauncherRuntime(version, ui) {
|
|
1315
|
+
const destination = launcherRuntimeRoot(version);
|
|
1316
|
+
const bridge = launcherRuntimeBridge(version);
|
|
1317
|
+
if (!destination || !fs.existsSync(LAUNCHER_RUNTIME_TEMPLATE)) return null;
|
|
1318
|
+
if (bridge && fs.existsSync(bridge)) return bridge;
|
|
1319
|
+
|
|
1320
|
+
const parent = path.dirname(destination);
|
|
1321
|
+
const temporary = path.join(parent, `.${path.basename(destination)}.tmp-${process.pid}`);
|
|
1322
|
+
try {
|
|
1323
|
+
fs.mkdirSync(parent, { recursive: true, mode: 0o700 });
|
|
1324
|
+
fs.rmSync(temporary, { recursive: true, force: true });
|
|
1325
|
+
fs.mkdirSync(temporary, { recursive: true, mode: 0o700 });
|
|
1326
|
+
fs.cpSync(LAUNCHER_RUNTIME_TEMPLATE, path.join(temporary, "claude"), {
|
|
1327
|
+
recursive: true,
|
|
1328
|
+
dereference: false,
|
|
1329
|
+
});
|
|
1330
|
+
const stagedBridge = path.join(temporary, "claude", "bin", "runtime-upgrade.sh");
|
|
1331
|
+
if (!fs.existsSync(stagedBridge)) throw new Error("packaged runtime-upgrade.sh is missing");
|
|
1332
|
+
fs.rmSync(destination, { recursive: true, force: true });
|
|
1333
|
+
fs.renameSync(temporary, destination);
|
|
1334
|
+
return bridge;
|
|
1335
|
+
} catch (err) {
|
|
1336
|
+
try { fs.rmSync(temporary, { recursive: true, force: true }); } catch {}
|
|
1337
|
+
ui.warn(`Could not install the Runtime update engine: ${err.message}`);
|
|
1338
|
+
return null;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1297
1342
|
// Parse a semver from a version-stamp comment. Accepts both styles so we can
|
|
1298
1343
|
// upgrade a bash launcher to the Node launcher across a major line:
|
|
1299
1344
|
// # egregore-launcher-version: X.Y.Z (bash)
|
|
@@ -1400,6 +1445,8 @@ function appendLocalBinToRc(ui) {
|
|
|
1400
1445
|
*/
|
|
1401
1446
|
async function installLauncherBinary(egregoreDir, ui) {
|
|
1402
1447
|
const template = readLauncherTemplate();
|
|
1448
|
+
const templateVer = launcherVersion(template);
|
|
1449
|
+
const packagedBridge = installLauncherRuntime(templateVer, ui);
|
|
1403
1450
|
// Tests, containers, and managed installations can pin the launcher to an
|
|
1404
1451
|
// isolated directory. When explicitly configured, never fall through to a
|
|
1405
1452
|
// machine-wide path: isolation is the reason the override exists.
|
|
@@ -1444,7 +1491,7 @@ async function installLauncherBinary(egregoreDir, ui) {
|
|
|
1444
1491
|
try { fs.chmodSync(binaryPath, 0o755); } catch {}
|
|
1445
1492
|
if (chosen.location === "user" && !dirOnPath(chosen.dir)) appendLocalBinToRc(ui);
|
|
1446
1493
|
removeShadowingEgregoreAliases(ui);
|
|
1447
|
-
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false };
|
|
1494
|
+
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false, runtimeBridgePath: packagedBridge };
|
|
1448
1495
|
}
|
|
1449
1496
|
|
|
1450
1497
|
// Different content — decide upgrade vs preserve via version stamps.
|
|
@@ -1458,18 +1505,18 @@ async function installLauncherBinary(egregoreDir, ui) {
|
|
|
1458
1505
|
ui.success(`Upgraded ${ui.dim("egregore")} at ${binaryPath} ${ui.dim(`(${existingVer} → ${templateVer})`)}`);
|
|
1459
1506
|
if (chosen.location === "user" && !dirOnPath(chosen.dir)) appendLocalBinToRc(ui);
|
|
1460
1507
|
removeShadowingEgregoreAliases(ui);
|
|
1461
|
-
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: true };
|
|
1508
|
+
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: true, runtimeBridgePath: packagedBridge };
|
|
1462
1509
|
}
|
|
1463
1510
|
if (compareVersions(templateVer, existingVer) < 0) {
|
|
1464
1511
|
// Template is older — don't downgrade. Warn lightly.
|
|
1465
1512
|
ui.warn(`Existing ${binaryPath} (v${existingVer}) is newer than this installer's template (v${templateVer}) — leaving it alone.`);
|
|
1466
1513
|
removeShadowingEgregoreAliases(ui);
|
|
1467
|
-
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false };
|
|
1514
|
+
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false, runtimeBridgePath: launcherRuntimeBridge(existingVer) };
|
|
1468
1515
|
}
|
|
1469
1516
|
// Equal stamps but different content → user edited the file. Don't clobber.
|
|
1470
1517
|
ui.warn(`Existing ${binaryPath} has been edited locally — not overwriting.`);
|
|
1471
1518
|
ui.info(` To reset: cp ${currentTemplatePath()} ${binaryPath}`);
|
|
1472
|
-
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false };
|
|
1519
|
+
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false, runtimeBridgePath: packagedBridge };
|
|
1473
1520
|
}
|
|
1474
1521
|
|
|
1475
1522
|
// No version stamp on existing. If it looks like one of OUR old
|
|
@@ -1485,11 +1532,11 @@ async function installLauncherBinary(egregoreDir, ui) {
|
|
|
1485
1532
|
ui.success(`Upgraded ${ui.dim("egregore")} at ${binaryPath} ${ui.dim(`(pre-0.4.1 → ${templateVer})`)}`);
|
|
1486
1533
|
if (chosen.location === "user" && !dirOnPath(chosen.dir)) appendLocalBinToRc(ui);
|
|
1487
1534
|
removeShadowingEgregoreAliases(ui);
|
|
1488
|
-
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: true };
|
|
1535
|
+
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: true, runtimeBridgePath: packagedBridge };
|
|
1489
1536
|
}
|
|
1490
1537
|
ui.warn(`Existing ${binaryPath} doesn't look like an egregore launcher — not overwriting.`);
|
|
1491
1538
|
ui.info(` If you meant to install: rm ${binaryPath} and re-run create-egregore.`);
|
|
1492
|
-
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false };
|
|
1539
|
+
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced: false, runtimeBridgePath: null };
|
|
1493
1540
|
} catch {
|
|
1494
1541
|
// Fall through to write
|
|
1495
1542
|
}
|
|
@@ -1509,7 +1556,7 @@ async function installLauncherBinary(egregoreDir, ui) {
|
|
|
1509
1556
|
|
|
1510
1557
|
removeShadowingEgregoreAliases(ui);
|
|
1511
1558
|
ui.success(`Installed ${ui.dim("egregore")} at ${binaryPath}`);
|
|
1512
|
-
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced };
|
|
1559
|
+
return { aliasName: "egregore", binaryPath, location: chosen.location, replaced, runtimeBridgePath: packagedBridge };
|
|
1513
1560
|
}
|
|
1514
1561
|
|
|
1515
1562
|
// Strip legacy `alias egregore=...` lines from common shell rc files. These
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-egregore",
|
|
3
|
-
"version": "0.21.0-runtime-mvp.
|
|
3
|
+
"version": "0.21.0-runtime-mvp.22",
|
|
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": {
|
|
@@ -6,7 +6,12 @@ set -euo pipefail
|
|
|
6
6
|
# legacy Local instances create opaque local IDs once. Network failure remains
|
|
7
7
|
# non-fatal to startup and is retried next session.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
RUNTIME_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
10
|
+
# A launcher-carried bridge runs outside the selected instance. Keep code
|
|
11
|
+
# rooted in the packaged Runtime while resolving and persisting identity in
|
|
12
|
+
# exactly the instance the launcher selected.
|
|
13
|
+
ROOT="${EGREGORE_INSTANCE_ROOT:-$RUNTIME_ROOT}"
|
|
14
|
+
ROOT="$(cd "$ROOT" && pwd)"
|
|
10
15
|
CONFIG="$ROOT/egregore.json"
|
|
11
16
|
STATE="$ROOT/.egregore-state.json"
|
|
12
17
|
|
|
@@ -34,7 +39,9 @@ case "${1:-ensure}" in
|
|
|
34
39
|
resolved && exit 0
|
|
35
40
|
mode="$(jq -r 'if (.mode // "local") == "connected" or (.api_url // "") != "" then "connected" else "local" end' "$CONFIG" 2>/dev/null || echo local)"
|
|
36
41
|
if [ "$mode" = "local" ]; then
|
|
37
|
-
EGREGORE_ROOT="$ROOT"
|
|
42
|
+
EGREGORE_ROOT="$ROOT" \
|
|
43
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
44
|
+
python3 -m egregore_runtime.identity_cli initialize-local >/dev/null
|
|
38
45
|
else
|
|
39
46
|
api_url="$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)"
|
|
40
47
|
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2-)"
|
|
@@ -58,7 +65,9 @@ case "${1:-ensure}" in
|
|
|
58
65
|
--argjson organization "$control_plane" \
|
|
59
66
|
--argjson roster "$roster" \
|
|
60
67
|
'{organization:$organization,roster:$roster}' | \
|
|
61
|
-
EGREGORE_ROOT="$ROOT"
|
|
68
|
+
EGREGORE_ROOT="$ROOT" \
|
|
69
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
70
|
+
python3 -m egregore_runtime.identity_cli \
|
|
62
71
|
reconcile-records >/dev/null
|
|
63
72
|
fi
|
|
64
73
|
resolved
|
|
@@ -28,13 +28,35 @@ _runtime() {
|
|
|
28
28
|
python3 -m egregore_runtime.harness_cli "$@"
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
_ensure_identity() {
|
|
32
|
+
# Pre-Runtime instances can predate stable organization identity. Resolve it
|
|
33
|
+
# through the existing verified Local/Connected migration before computing
|
|
34
|
+
# the instance-scoped upgrade key; never infer identity from path or slug.
|
|
35
|
+
if jq -e '
|
|
36
|
+
.org_id | type == "string" and length > 0
|
|
37
|
+
' "$INSTANCE_ROOT/egregore.json" >/dev/null 2>&1; then
|
|
38
|
+
return 0
|
|
39
|
+
fi
|
|
40
|
+
EGREGORE_INSTANCE_ROOT="$INSTANCE_ROOT" \
|
|
41
|
+
PYTHONPATH="$SCRIPT_DIR${PYTHONPATH:+:$PYTHONPATH}" \
|
|
42
|
+
bash "$SCRIPT_DIR/bin/runtime-identity.sh" ensure
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_run_upgrade() {
|
|
46
|
+
_ensure_identity || {
|
|
47
|
+
echo "Runtime update could not resolve this Egregore's stable identity." >&2
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
_runtime upgrade "$@"
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
case "${1:-}" in
|
|
32
|
-
status) shift;
|
|
33
|
-
init) shift;
|
|
34
|
-
prepare) shift;
|
|
35
|
-
activate) shift;
|
|
36
|
-
cancel) shift;
|
|
37
|
-
rollback) shift;
|
|
54
|
+
status) shift; _run_upgrade status "$@" ;;
|
|
55
|
+
init) shift; _run_upgrade init "$@" ;;
|
|
56
|
+
prepare) shift; _run_upgrade prepare "$@" ;;
|
|
57
|
+
activate) shift; _run_upgrade activate "$@" ;;
|
|
58
|
+
cancel) shift; _run_upgrade cancel "$@" ;;
|
|
59
|
+
rollback) shift; _run_upgrade rollback "$@" ;;
|
|
38
60
|
team-sync) shift; _runtime team-sync "$@" ;;
|
|
39
61
|
*)
|
|
40
62
|
echo "usage: bash bin/runtime-upgrade.sh {status|init --candidate <version>|prepare|activate|cancel|rollback|team-sync}" >&2
|
|
@@ -6,7 +6,12 @@ set -euo pipefail
|
|
|
6
6
|
# legacy Local instances create opaque local IDs once. Network failure remains
|
|
7
7
|
# non-fatal to startup and is retried next session.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
RUNTIME_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
10
|
+
# A launcher-carried bridge runs outside the selected instance. Keep code
|
|
11
|
+
# rooted in the packaged Runtime while resolving and persisting identity in
|
|
12
|
+
# exactly the instance the launcher selected.
|
|
13
|
+
ROOT="${EGREGORE_INSTANCE_ROOT:-$RUNTIME_ROOT}"
|
|
14
|
+
ROOT="$(cd "$ROOT" && pwd)"
|
|
10
15
|
CONFIG="$ROOT/egregore.json"
|
|
11
16
|
STATE="$ROOT/.egregore-state.json"
|
|
12
17
|
|
|
@@ -34,7 +39,9 @@ case "${1:-ensure}" in
|
|
|
34
39
|
resolved && exit 0
|
|
35
40
|
mode="$(jq -r 'if (.mode // "local") == "connected" or (.api_url // "") != "" then "connected" else "local" end' "$CONFIG" 2>/dev/null || echo local)"
|
|
36
41
|
if [ "$mode" = "local" ]; then
|
|
37
|
-
EGREGORE_ROOT="$ROOT"
|
|
42
|
+
EGREGORE_ROOT="$ROOT" \
|
|
43
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
44
|
+
python3 -m egregore_runtime.identity_cli initialize-local >/dev/null
|
|
38
45
|
else
|
|
39
46
|
api_url="$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)"
|
|
40
47
|
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2-)"
|
|
@@ -58,7 +65,9 @@ case "${1:-ensure}" in
|
|
|
58
65
|
--argjson organization "$control_plane" \
|
|
59
66
|
--argjson roster "$roster" \
|
|
60
67
|
'{organization:$organization,roster:$roster}' | \
|
|
61
|
-
EGREGORE_ROOT="$ROOT"
|
|
68
|
+
EGREGORE_ROOT="$ROOT" \
|
|
69
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
70
|
+
python3 -m egregore_runtime.identity_cli \
|
|
62
71
|
reconcile-records >/dev/null
|
|
63
72
|
fi
|
|
64
73
|
resolved
|
|
@@ -28,13 +28,35 @@ _runtime() {
|
|
|
28
28
|
python3 -m egregore_runtime.harness_cli "$@"
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
_ensure_identity() {
|
|
32
|
+
# Pre-Runtime instances can predate stable organization identity. Resolve it
|
|
33
|
+
# through the existing verified Local/Connected migration before computing
|
|
34
|
+
# the instance-scoped upgrade key; never infer identity from path or slug.
|
|
35
|
+
if jq -e '
|
|
36
|
+
.org_id | type == "string" and length > 0
|
|
37
|
+
' "$INSTANCE_ROOT/egregore.json" >/dev/null 2>&1; then
|
|
38
|
+
return 0
|
|
39
|
+
fi
|
|
40
|
+
EGREGORE_INSTANCE_ROOT="$INSTANCE_ROOT" \
|
|
41
|
+
PYTHONPATH="$SCRIPT_DIR${PYTHONPATH:+:$PYTHONPATH}" \
|
|
42
|
+
bash "$SCRIPT_DIR/bin/runtime-identity.sh" ensure
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_run_upgrade() {
|
|
46
|
+
_ensure_identity || {
|
|
47
|
+
echo "Runtime update could not resolve this Egregore's stable identity." >&2
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
_runtime upgrade "$@"
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
case "${1:-}" in
|
|
32
|
-
status) shift;
|
|
33
|
-
init) shift;
|
|
34
|
-
prepare) shift;
|
|
35
|
-
activate) shift;
|
|
36
|
-
cancel) shift;
|
|
37
|
-
rollback) shift;
|
|
54
|
+
status) shift; _run_upgrade status "$@" ;;
|
|
55
|
+
init) shift; _run_upgrade init "$@" ;;
|
|
56
|
+
prepare) shift; _run_upgrade prepare "$@" ;;
|
|
57
|
+
activate) shift; _run_upgrade activate "$@" ;;
|
|
58
|
+
cancel) shift; _run_upgrade cancel "$@" ;;
|
|
59
|
+
rollback) shift; _run_upgrade rollback "$@" ;;
|
|
38
60
|
team-sync) shift; _runtime team-sync "$@" ;;
|
|
39
61
|
*)
|
|
40
62
|
echo "usage: bash bin/runtime-upgrade.sh {status|init --candidate <version>|prepare|activate|cancel|rollback|team-sync}" >&2
|
|
@@ -6,7 +6,12 @@ set -euo pipefail
|
|
|
6
6
|
# legacy Local instances create opaque local IDs once. Network failure remains
|
|
7
7
|
# non-fatal to startup and is retried next session.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
RUNTIME_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
10
|
+
# A launcher-carried bridge runs outside the selected instance. Keep code
|
|
11
|
+
# rooted in the packaged Runtime while resolving and persisting identity in
|
|
12
|
+
# exactly the instance the launcher selected.
|
|
13
|
+
ROOT="${EGREGORE_INSTANCE_ROOT:-$RUNTIME_ROOT}"
|
|
14
|
+
ROOT="$(cd "$ROOT" && pwd)"
|
|
10
15
|
CONFIG="$ROOT/egregore.json"
|
|
11
16
|
STATE="$ROOT/.egregore-state.json"
|
|
12
17
|
|
|
@@ -34,7 +39,9 @@ case "${1:-ensure}" in
|
|
|
34
39
|
resolved && exit 0
|
|
35
40
|
mode="$(jq -r 'if (.mode // "local") == "connected" or (.api_url // "") != "" then "connected" else "local" end' "$CONFIG" 2>/dev/null || echo local)"
|
|
36
41
|
if [ "$mode" = "local" ]; then
|
|
37
|
-
EGREGORE_ROOT="$ROOT"
|
|
42
|
+
EGREGORE_ROOT="$ROOT" \
|
|
43
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
44
|
+
python3 -m egregore_runtime.identity_cli initialize-local >/dev/null
|
|
38
45
|
else
|
|
39
46
|
api_url="$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)"
|
|
40
47
|
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2-)"
|
|
@@ -58,7 +65,9 @@ case "${1:-ensure}" in
|
|
|
58
65
|
--argjson organization "$control_plane" \
|
|
59
66
|
--argjson roster "$roster" \
|
|
60
67
|
'{organization:$organization,roster:$roster}' | \
|
|
61
|
-
EGREGORE_ROOT="$ROOT"
|
|
68
|
+
EGREGORE_ROOT="$ROOT" \
|
|
69
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
70
|
+
python3 -m egregore_runtime.identity_cli \
|
|
62
71
|
reconcile-records >/dev/null
|
|
63
72
|
fi
|
|
64
73
|
resolved
|
|
@@ -28,13 +28,35 @@ _runtime() {
|
|
|
28
28
|
python3 -m egregore_runtime.harness_cli "$@"
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
_ensure_identity() {
|
|
32
|
+
# Pre-Runtime instances can predate stable organization identity. Resolve it
|
|
33
|
+
# through the existing verified Local/Connected migration before computing
|
|
34
|
+
# the instance-scoped upgrade key; never infer identity from path or slug.
|
|
35
|
+
if jq -e '
|
|
36
|
+
.org_id | type == "string" and length > 0
|
|
37
|
+
' "$INSTANCE_ROOT/egregore.json" >/dev/null 2>&1; then
|
|
38
|
+
return 0
|
|
39
|
+
fi
|
|
40
|
+
EGREGORE_INSTANCE_ROOT="$INSTANCE_ROOT" \
|
|
41
|
+
PYTHONPATH="$SCRIPT_DIR${PYTHONPATH:+:$PYTHONPATH}" \
|
|
42
|
+
bash "$SCRIPT_DIR/bin/runtime-identity.sh" ensure
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_run_upgrade() {
|
|
46
|
+
_ensure_identity || {
|
|
47
|
+
echo "Runtime update could not resolve this Egregore's stable identity." >&2
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
_runtime upgrade "$@"
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
case "${1:-}" in
|
|
32
|
-
status) shift;
|
|
33
|
-
init) shift;
|
|
34
|
-
prepare) shift;
|
|
35
|
-
activate) shift;
|
|
36
|
-
cancel) shift;
|
|
37
|
-
rollback) shift;
|
|
54
|
+
status) shift; _run_upgrade status "$@" ;;
|
|
55
|
+
init) shift; _run_upgrade init "$@" ;;
|
|
56
|
+
prepare) shift; _run_upgrade prepare "$@" ;;
|
|
57
|
+
activate) shift; _run_upgrade activate "$@" ;;
|
|
58
|
+
cancel) shift; _run_upgrade cancel "$@" ;;
|
|
59
|
+
rollback) shift; _run_upgrade rollback "$@" ;;
|
|
38
60
|
team-sync) shift; _runtime team-sync "$@" ;;
|
|
39
61
|
*)
|
|
40
62
|
echo "usage: bash bin/runtime-upgrade.sh {status|init --candidate <version>|prepare|activate|cancel|rollback|team-sync}" >&2
|
|
@@ -6,7 +6,12 @@ set -euo pipefail
|
|
|
6
6
|
# legacy Local instances create opaque local IDs once. Network failure remains
|
|
7
7
|
# non-fatal to startup and is retried next session.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
RUNTIME_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
10
|
+
# A launcher-carried bridge runs outside the selected instance. Keep code
|
|
11
|
+
# rooted in the packaged Runtime while resolving and persisting identity in
|
|
12
|
+
# exactly the instance the launcher selected.
|
|
13
|
+
ROOT="${EGREGORE_INSTANCE_ROOT:-$RUNTIME_ROOT}"
|
|
14
|
+
ROOT="$(cd "$ROOT" && pwd)"
|
|
10
15
|
CONFIG="$ROOT/egregore.json"
|
|
11
16
|
STATE="$ROOT/.egregore-state.json"
|
|
12
17
|
|
|
@@ -34,7 +39,9 @@ case "${1:-ensure}" in
|
|
|
34
39
|
resolved && exit 0
|
|
35
40
|
mode="$(jq -r 'if (.mode // "local") == "connected" or (.api_url // "") != "" then "connected" else "local" end' "$CONFIG" 2>/dev/null || echo local)"
|
|
36
41
|
if [ "$mode" = "local" ]; then
|
|
37
|
-
EGREGORE_ROOT="$ROOT"
|
|
42
|
+
EGREGORE_ROOT="$ROOT" \
|
|
43
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
44
|
+
python3 -m egregore_runtime.identity_cli initialize-local >/dev/null
|
|
38
45
|
else
|
|
39
46
|
api_url="$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)"
|
|
40
47
|
api_key="$(grep '^EGREGORE_API_KEY=' "$ROOT/.env" 2>/dev/null | cut -d= -f2-)"
|
|
@@ -58,7 +65,9 @@ case "${1:-ensure}" in
|
|
|
58
65
|
--argjson organization "$control_plane" \
|
|
59
66
|
--argjson roster "$roster" \
|
|
60
67
|
'{organization:$organization,roster:$roster}' | \
|
|
61
|
-
EGREGORE_ROOT="$ROOT"
|
|
68
|
+
EGREGORE_ROOT="$ROOT" \
|
|
69
|
+
PYTHONPATH="$RUNTIME_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
70
|
+
python3 -m egregore_runtime.identity_cli \
|
|
62
71
|
reconcile-records >/dev/null
|
|
63
72
|
fi
|
|
64
73
|
resolved
|
|
@@ -28,13 +28,35 @@ _runtime() {
|
|
|
28
28
|
python3 -m egregore_runtime.harness_cli "$@"
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
_ensure_identity() {
|
|
32
|
+
# Pre-Runtime instances can predate stable organization identity. Resolve it
|
|
33
|
+
# through the existing verified Local/Connected migration before computing
|
|
34
|
+
# the instance-scoped upgrade key; never infer identity from path or slug.
|
|
35
|
+
if jq -e '
|
|
36
|
+
.org_id | type == "string" and length > 0
|
|
37
|
+
' "$INSTANCE_ROOT/egregore.json" >/dev/null 2>&1; then
|
|
38
|
+
return 0
|
|
39
|
+
fi
|
|
40
|
+
EGREGORE_INSTANCE_ROOT="$INSTANCE_ROOT" \
|
|
41
|
+
PYTHONPATH="$SCRIPT_DIR${PYTHONPATH:+:$PYTHONPATH}" \
|
|
42
|
+
bash "$SCRIPT_DIR/bin/runtime-identity.sh" ensure
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_run_upgrade() {
|
|
46
|
+
_ensure_identity || {
|
|
47
|
+
echo "Runtime update could not resolve this Egregore's stable identity." >&2
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
_runtime upgrade "$@"
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
case "${1:-}" in
|
|
32
|
-
status) shift;
|
|
33
|
-
init) shift;
|
|
34
|
-
prepare) shift;
|
|
35
|
-
activate) shift;
|
|
36
|
-
cancel) shift;
|
|
37
|
-
rollback) shift;
|
|
54
|
+
status) shift; _run_upgrade status "$@" ;;
|
|
55
|
+
init) shift; _run_upgrade init "$@" ;;
|
|
56
|
+
prepare) shift; _run_upgrade prepare "$@" ;;
|
|
57
|
+
activate) shift; _run_upgrade activate "$@" ;;
|
|
58
|
+
cancel) shift; _run_upgrade cancel "$@" ;;
|
|
59
|
+
rollback) shift; _run_upgrade rollback "$@" ;;
|
|
38
60
|
team-sync) shift; _runtime team-sync "$@" ;;
|
|
39
61
|
*)
|
|
40
62
|
echo "usage: bash bin/runtime-upgrade.sh {status|init --candidate <version>|prepare|activate|cancel|rollback|team-sync}" >&2
|