create-egregore 0.20.1 → 0.20.3

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.
Files changed (58) hide show
  1. package/assets/egregore-launcher.js +34 -19
  2. package/bin/cli.js +3 -63
  3. package/lib/local.js +4 -20
  4. package/lib/setup.js +12 -16
  5. package/package.json +2 -2
  6. package/runtime/codex/.codex/spec-manifest.json +3 -3
  7. package/runtime/codex/AGENTS.md +23 -9
  8. package/runtime/codex/bin/agent.sh +15 -3
  9. package/runtime/codex/bin/attendant.sh +14 -301
  10. package/runtime/codex/bin/autosave.sh +1 -27
  11. package/runtime/codex/bin/codex-render-spec.mjs +5 -3
  12. package/runtime/codex/bin/codex-session-start.sh +3 -3
  13. package/runtime/codex/bin/contribute-guard.sh +79 -0
  14. package/runtime/codex/bin/handoff-save-egregore.sh +1 -1
  15. package/runtime/codex/bin/lib/git-sync.sh +16 -0
  16. package/runtime/codex/bin/lib/greeting.sh +2 -2
  17. package/runtime/codex/bin/search.sh +46 -4
  18. package/runtime/codex/bin/session-autosave.sh +6 -1
  19. package/runtime/codex/bin/settings.sh +62 -3
  20. package/runtime/codex/bin/worktree-create.sh +4 -1
  21. package/runtime/codex/manifest.json +1 -0
  22. package/runtime/pi/.codex/spec-manifest.json +3 -3
  23. package/runtime/pi/.pi/APPEND_SYSTEM.md +23 -9
  24. package/runtime/pi/.pi/spec-manifest.json +2 -2
  25. package/runtime/pi/AGENTS.md +23 -9
  26. package/runtime/pi/bin/agent.sh +15 -3
  27. package/runtime/pi/bin/attendant.sh +14 -301
  28. package/runtime/pi/bin/autosave.sh +1 -27
  29. package/runtime/pi/bin/codex-render-spec.mjs +5 -3
  30. package/runtime/pi/bin/codex-session-start.sh +3 -3
  31. package/runtime/pi/bin/contribute-guard.sh +79 -0
  32. package/runtime/pi/bin/handoff-save-egregore.sh +1 -1
  33. package/runtime/pi/bin/lib/git-sync.sh +16 -0
  34. package/runtime/pi/bin/lib/greeting.sh +2 -2
  35. package/runtime/pi/bin/search.sh +46 -4
  36. package/runtime/pi/bin/session-autosave.sh +6 -1
  37. package/runtime/pi/bin/settings.sh +62 -3
  38. package/runtime/pi/bin/worktree-create.sh +4 -1
  39. package/runtime/pi/manifest.json +1 -0
  40. package/runtime/prime/.codex/spec-manifest.json +3 -3
  41. package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +24 -10
  42. package/runtime/prime/.prime/agent/spec-manifest.json +2 -2
  43. package/runtime/prime/AGENTS.md +23 -9
  44. package/runtime/prime/bin/agent.sh +15 -3
  45. package/runtime/prime/bin/attendant.sh +14 -301
  46. package/runtime/prime/bin/autosave.sh +1 -27
  47. package/runtime/prime/bin/codex-render-spec.mjs +5 -3
  48. package/runtime/prime/bin/codex-session-start.sh +3 -3
  49. package/runtime/prime/bin/contribute-guard.sh +79 -0
  50. package/runtime/prime/bin/handoff-save-egregore.sh +1 -1
  51. package/runtime/prime/bin/lib/git-sync.sh +16 -0
  52. package/runtime/prime/bin/lib/greeting.sh +2 -2
  53. package/runtime/prime/bin/prime-render-spec.mjs +1 -1
  54. package/runtime/prime/bin/search.sh +46 -4
  55. package/runtime/prime/bin/session-autosave.sh +6 -1
  56. package/runtime/prime/bin/settings.sh +62 -3
  57. package/runtime/prime/bin/worktree-create.sh +4 -1
  58. package/runtime/prime/manifest.json +1 -0
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // egregore-launcher-version: 0.20.1
2
+ // egregore-launcher-version: 0.20.3
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.20.1";
36
+ const VERSION = "0.20.3";
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");
@@ -702,7 +702,8 @@ function codexSupportMessage(egregoreDir) {
702
702
  " .codex/hooks.json",
703
703
  " .codex/hooks/",
704
704
  "",
705
- "Run npx -y create-egregore@latest to install the packaged Codex runtime, then rerun egregore.",
705
+ "Restore this instance using its installed runtime version, then rerun egregore.",
706
+ "A global CLI refresh does not repair instance files.",
706
707
  "Egregore workflows appear as slash commands. In Codex, invoke them with the matching $skill token or ask in natural language.",
707
708
  ].join("\n");
708
709
  }
@@ -733,7 +734,7 @@ function piSupportMessage(egregoreDir) {
733
734
  "Pi meta-harness support is missing from this Egregore checkout.",
734
735
  ` path: ${egregoreDir}`,
735
736
  "",
736
- "Run npx -y create-egregore@latest to install the packaged Pi runtime, then rerun egregore.",
737
+ "Restore this instance using its installed runtime version, then rerun egregore.",
737
738
  ].join("\n");
738
739
  }
739
740
 
@@ -752,7 +753,7 @@ function primeSupportMessage(egregoreDir) {
752
753
  "Prime Agent runtime support is missing from this Egregore checkout.",
753
754
  ` path: ${egregoreDir}`,
754
755
  "",
755
- "Run npx -y create-egregore@latest to install the packaged Prime Agent runtime, then rerun egregore.",
756
+ "Restore this instance using its installed runtime version, then rerun egregore.",
756
757
  ].join("\n");
757
758
  }
758
759
 
@@ -885,16 +886,17 @@ async function launch(inst, runtimeOverride) {
885
886
  }
886
887
  }
887
888
  if (runtime === "codex") {
888
- if (!hasCodexCoreSupport(inst.path)) {
889
- die(codexSupportMessage(inst.path));
890
- }
889
+ // Launching never changes an instance's runtime or release channel.
890
+ if (!hasCodexCoreSupport(inst.path)) die(codexSupportMessage(inst.path));
891
891
  const skillsInstalled = installCodexSkills(inst.path);
892
892
  const cardRendered = await renderCodexStartupCard(inst.path);
893
893
  if (!skillsInstalled || !cardRendered) {
894
894
  die(codexSupportMessage(inst.path));
895
895
  }
896
896
  } else if (runtime === "pi") {
897
- if (!hasPiCoreSupport(inst.path)) die(piSupportMessage(inst.path));
897
+ if (!hasPiCoreSupport(inst.path)) {
898
+ die(piSupportMessage(inst.path));
899
+ }
898
900
  }
899
901
  let launchArgs = null;
900
902
  if (runtime === "prime") {
@@ -1766,9 +1768,10 @@ async function cmdConnect(args) {
1766
1768
  console.log(` ${DIM}${line}${RESET}`);
1767
1769
  }
1768
1770
  }
1771
+ // Connect is an instance-scoped overlay; never refresh other runtimes here.
1769
1772
  const runtimeRefresh = spawnSync(
1770
1773
  "npx",
1771
- ["-y", `${PUBLIC_NPX_PACKAGE}@latest`, "--refresh-launcher"],
1774
+ ["-y", `${PUBLIC_NPX_PACKAGE}@${VERSION}`, "--refresh-connect"],
1772
1775
  {
1773
1776
  cwd: inst.path,
1774
1777
  encoding: "utf-8",
@@ -1780,7 +1783,7 @@ async function cmdConnect(args) {
1780
1783
  console.log(` ${GREEN}✓${RESET} Connect features installed`);
1781
1784
  } else {
1782
1785
  console.log(` ${YELLOW}!${RESET} Connect features will retry on the next update`);
1783
- console.log(` ${DIM}npx -y ${PUBLIC_NPX_PACKAGE}@latest --refresh-launcher${RESET}`);
1786
+ console.log(` ${DIM}npx -y ${PUBLIC_NPX_PACKAGE}@${VERSION} --refresh-connect${RESET}`);
1784
1787
  }
1785
1788
  console.log("");
1786
1789
  console.log(` ${GREEN}✓${RESET} ${BOLD}${inst.slug}${RESET} is connected. Local files remain the source of truth.`);
@@ -2102,7 +2105,7 @@ function runSettings(inst, args) {
2102
2105
  return { status: 127, stdout: "", stderr: "bin/settings.sh not found — update this egregore (run /pull) to get settings.\n", missing: true };
2103
2106
  }
2104
2107
  try {
2105
- return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 15000 });
2108
+ return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 45000 });
2106
2109
  } catch (err) {
2107
2110
  return { status: 1, stdout: "", stderr: String(err) };
2108
2111
  }
@@ -2117,13 +2120,13 @@ function settingsDump(inst) {
2117
2120
  async function cmdSettings(args) {
2118
2121
  const registry = readRegistry();
2119
2122
  if (registry.length === 0) die("no egregores installed yet.\n run: npx -y create-egregore@latest");
2120
- const DOMAINS = new Set(["hosting", "repo", "admin", "people", "dump"]);
2123
+ const DOMAINS = new Set(["hosting", "workflow", "repo", "admin", "people", "dump"]);
2121
2124
  let rest = args.slice();
2122
2125
  let slug = "";
2123
2126
  if (rest.length && !DOMAINS.has(rest[0])) { slug = rest[0]; rest = rest.slice(1); }
2124
2127
  const inst = resolveInviteInstance(registry, slug);
2125
2128
  if (!inst) {
2126
- die(`multiple egregores installed; choose one:\n egregore settings <slug> [hosting|repo|admin]\n run: egregore ls`);
2129
+ die(`multiple egregores installed; choose one:\n egregore settings <slug> [hosting|workflow|repo|admin|people]\n run: egregore ls`);
2127
2130
  }
2128
2131
  // Interactive editing lives in the launcher (press `s`). With no verb, print
2129
2132
  // the snapshot; otherwise forward straight to the deterministic verb.
@@ -2421,6 +2424,14 @@ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCurs
2421
2424
  } else {
2422
2425
  const rows = [
2423
2426
  { name: "Hosted Artifacts", value: (d.hosting !== false) ? `${GREEN}ON${RESET}` : `${YELLOW}OFF${RESET}` },
2427
+ {
2428
+ name: "Git workflow",
2429
+ value: d.workflow === "simple"
2430
+ ? `${DIM}PRs → main${RESET}`
2431
+ : d.workflow === "staged"
2432
+ ? `${DIM}PRs → develop → main${RESET}`
2433
+ : `${DIM}PRs → ${d.base_branch || "custom"}${RESET}`,
2434
+ },
2424
2435
  { name: "Managed repos", value: `${DIM}${(d.repos || []).length}${RESET}` },
2425
2436
  { name: "Admins", value: `${DIM}${(d.admins || []).length}${RESET}` },
2426
2437
  { name: "People", value: `${DIM}${(d.people || []).length}${RESET}` },
@@ -2433,7 +2444,7 @@ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCurs
2433
2444
  });
2434
2445
  lines.push(emptyBoxLine(innerWidth, margin));
2435
2446
  if (notice) lines.push(boxLine(notice, innerWidth, margin));
2436
- lines.push(boxLine(`${DIM}↑↓ nav · ${RESET}${BOLD}enter${RESET}${DIM} ${cursor === 0 ? "toggle" : "open"} · ← back · q quit${RESET}`, innerWidth, margin));
2447
+ lines.push(boxLine(`${DIM}↑↓ nav · ${RESET}${BOLD}enter${RESET}${DIM} ${cursor < 2 ? "toggle" : "open"} · ← back · q quit${RESET}`, innerWidth, margin));
2437
2448
  }
2438
2449
 
2439
2450
  lines.push(emptyBoxLine(innerWidth, margin));
@@ -2891,15 +2902,19 @@ async function browser(args = {}) {
2891
2902
 
2892
2903
  // menu view
2893
2904
  if (key.name === "escape" || key.name === "left") { S.settingsInst = null; S.settingsNotice = ""; render(); return; }
2894
- if (key.name === "up" || key.name === "k") { S.settingsCursor = (S.settingsCursor - 1 + 4) % 4; render(); return; }
2895
- if (key.name === "down" || key.name === "j") { S.settingsCursor = (S.settingsCursor + 1) % 4; render(); return; }
2905
+ if (key.name === "up" || key.name === "k") { S.settingsCursor = (S.settingsCursor - 1 + 5) % 5; render(); return; }
2906
+ if (key.name === "down" || key.name === "j") { S.settingsCursor = (S.settingsCursor + 1) % 5; render(); return; }
2896
2907
  if (key.name === "return" || chunk === " ") {
2897
2908
  if (S.settingsCursor === 0) {
2898
2909
  const on = (S.settingsData && S.settingsData.hosting) !== false;
2899
2910
  settingsRunVerb(["hosting", on ? "off" : "on"]);
2900
2911
  render();
2912
+ } else if (S.settingsCursor === 1) {
2913
+ const simple = (S.settingsData && S.settingsData.workflow) === "simple";
2914
+ settingsRunVerb(["workflow", simple ? "staged" : "simple"]);
2915
+ render();
2901
2916
  } else {
2902
- const domain = S.settingsCursor === 1 ? "repo" : S.settingsCursor === 2 ? "admin" : "people";
2917
+ const domain = S.settingsCursor === 2 ? "repo" : S.settingsCursor === 3 ? "admin" : "people";
2903
2918
  S.settingsView = "list"; S.settingsDomain = domain;
2904
2919
  S.settingsItems = settingsItemsFor(S.settingsData, domain);
2905
2920
  S.settingsListCursor = 0; S.settingsMode = "browse"; S.settingsNotice = "";
@@ -3155,7 +3170,7 @@ async function browser(args = {}) {
3155
3170
  return;
3156
3171
  }
3157
3172
  state.settingsInst = pick;
3158
- state.settingsData = settingsDump(pick) || { hosting: true, repos: [], admins: [], people: [] };
3173
+ state.settingsData = settingsDump(pick) || { hosting: true, workflow: "staged", base_branch: "develop", repos: [], admins: [], people: [] };
3159
3174
  state.settingsCursor = 0;
3160
3175
  state.settingsView = "menu";
3161
3176
  state.settingsNotice = "";
package/bin/cli.js CHANGED
@@ -25,27 +25,8 @@ const {
25
25
  ghCliExists,
26
26
  tryGhAuthOrLogin,
27
27
  } = require("../lib/auth");
28
- const {
29
- hasCodexRuntimeSupport,
30
- installCodexRuntime,
31
- reportCodexRuntimeSummary,
32
- } = require("../lib/codex-runtime");
33
- const {
34
- hasPiRuntimeSupport,
35
- installPiRuntime,
36
- reportPiRuntimeSummary,
37
- } = require("../lib/pi-runtime");
38
- const {
39
- hasPrimeRuntimeSupport,
40
- installPrimeRuntime,
41
- reportPrimeRuntimeSummary,
42
- } = require("../lib/prime-runtime");
43
- const {
44
- connectEligibility,
45
- fetchConnectRuntimePack,
46
- installConnectRuntime,
47
- reportConnectRuntimeSummary,
48
- } = require("../lib/connect-runtime");
28
+ // Global CLI maintenance never installs or reconciles instance runtimes.
29
+ // Fresh installation and explicit instance updates own those writes.
49
30
  const {
50
31
  install,
51
32
  ghApi,
@@ -120,45 +101,6 @@ function assistantLabel(runtime) {
120
101
  return "Claude Code";
121
102
  }
122
103
 
123
- async function upgradePortableRuntimesForExisting(instances) {
124
- for (const inst of instances) {
125
- if (!inst || !inst.path || !fs.existsSync(inst.path)) continue;
126
- try {
127
- // Fetch and validate the private overlay before pruning the old public
128
- // bundle. During the one-time ownership migration, an API outage must
129
- // leave an existing Connect installation untouched.
130
- const eligibility = connectEligibility(inst.path);
131
- const connectPack = eligibility.eligible
132
- ? await fetchConnectRuntimePack(inst.path)
133
- : null;
134
- const summary = installCodexRuntime(inst.path);
135
- const ready = hasCodexRuntimeSupport(inst.path);
136
- reportCodexRuntimeSummary(summary, ui, {
137
- label: `Codex runtime for ${inst.slug || inst.name || path.basename(inst.path)}`,
138
- includeConflicts: !ready,
139
- });
140
- const piSummary = installPiRuntime(inst.path);
141
- const piReady = hasPiRuntimeSupport(inst.path);
142
- reportPiRuntimeSummary(piSummary, ui, {
143
- label: `Pi meta-harness for ${inst.slug || inst.name || path.basename(inst.path)}`,
144
- includeConflicts: !piReady,
145
- });
146
- const primeSummary = installPrimeRuntime(inst.path);
147
- const primeReady = hasPrimeRuntimeSupport(inst.path);
148
- reportPrimeRuntimeSummary(primeSummary, ui, {
149
- label: `Prime Agent runtime for ${inst.slug || inst.name || path.basename(inst.path)}`,
150
- includeConflicts: !primeReady,
151
- });
152
- const connectSummary = await installConnectRuntime(inst.path, { validatedPack: connectPack });
153
- reportConnectRuntimeSummary(connectSummary, ui, {
154
- label: `Connect features for ${inst.slug || inst.name || path.basename(inst.path)}`,
155
- });
156
- } catch (err) {
157
- ui.warn(`Could not refresh shell-runtime support for ${inst.path}: ${err.message}`);
158
- }
159
- }
160
- }
161
-
162
104
  async function chooseRuntime(args) {
163
105
  if (args.runtime) {
164
106
  try {
@@ -199,7 +141,6 @@ async function chooseRuntime(args) {
199
141
  }
200
142
 
201
143
  async function upgradeLauncherFromExisting(instances) {
202
- await upgradePortableRuntimesForExisting(instances);
203
144
  const inst = instances.find((entry) => entry && entry.path && fs.existsSync(entry.path));
204
145
  if (!inst) return null;
205
146
  try {
@@ -433,7 +374,7 @@ function showHelp() {
433
374
  ui.info(" --force Skip the in-repo detection check");
434
375
  ui.info(" --no-autolaunch Don't launch the harness at the end (for CI)");
435
376
  ui.info(" --no-screens Skip the full-screen welcome/ready bookends");
436
- ui.info(" --refresh-launcher Refresh the Egregore CLI and runtime packs, then exit");
377
+ ui.info(" --refresh-launcher Refresh only the global Egregore CLI, then exit");
437
378
  ui.info(" -h, --help Show this help");
438
379
  ui.info("");
439
380
  }
@@ -513,7 +454,6 @@ async function main() {
513
454
  ui.error("No installed Egregore instance was found. Run create-egregore without --refresh-launcher.");
514
455
  process.exit(1);
515
456
  }
516
- await upgradePortableRuntimesForExisting(instances);
517
457
  const alias = await installLauncherBinary(instances[0].path, ui);
518
458
  if (!alias || !alias.binaryPath) {
519
459
  ui.error("Could not refresh the Egregore CLI.");
package/lib/local.js CHANGED
@@ -31,7 +31,6 @@ const {
31
31
  configureGitCredentials,
32
32
  gitCloneEnv,
33
33
  initMemoryDirs,
34
- ensureDevelop,
35
34
  ensurePersonOnboardingWitness,
36
35
  ensureInstallerMemberRole,
37
36
  run,
@@ -1031,7 +1030,6 @@ async function localFounderFlow(ui, ctx = {}) {
1031
1030
 
1032
1031
  const githubOrg = st.githubOrg;
1033
1032
  const isOrg = st.isOrg;
1034
- const isNewProject = st.isNewProject;
1035
1033
  const orgName = st.orgName;
1036
1034
  const description = st.description;
1037
1035
  let newProjectRepo = st.newProjectRepo;
@@ -1156,13 +1154,14 @@ async function localFounderFlow(ui, ctx = {}) {
1156
1154
  const s3 = ui.spinner(`Creating ${newProjectRepo}...`);
1157
1155
  const projExists = await repoExists(githubToken, githubOrg, newProjectRepo);
1158
1156
  if (projExists) {
1159
- selectedRepos.push({ name: newProjectRepo });
1157
+ const branchInfo = await detectRepoBranches(githubToken, githubOrg, newProjectRepo).catch(() => null);
1158
+ selectedRepos.push({ name: newProjectRepo, base_branch: branchInfo?.defaultBranch || "main" });
1160
1159
  s3.stop(`${newProjectRepo} already exists — added to managed repos`);
1161
1160
  } else {
1162
1161
  try {
1163
1162
  await createRepo(githubToken, githubOrg, newProjectRepo, isOrg, description || "");
1164
1163
  if (await waitForRepo(githubToken, githubOrg, newProjectRepo)) {
1165
- selectedRepos.push({ name: newProjectRepo });
1164
+ selectedRepos.push({ name: newProjectRepo, base_branch: "main" });
1166
1165
  s3.stop(`Created ${newProjectRepo}`);
1167
1166
  } else {
1168
1167
  s3.fail(`${newProjectRepo} creation timed out`);
@@ -1181,6 +1180,7 @@ async function localFounderFlow(ui, ctx = {}) {
1181
1180
  memory_repo: `https://github.com/${githubOrg}/${memoryRepoName}.git`,
1182
1181
  slug: slug,
1183
1182
  repo_name: repoName,
1183
+ base_branch: "main",
1184
1184
  repos: selectedRepos,
1185
1185
  upstream_url: "https://github.com/egregore-labs/egregore.git",
1186
1186
  report_url: "https://xgksfrirtdumacvmfkzj.supabase.co",
@@ -1241,18 +1241,6 @@ async function localFounderFlow(ui, ctx = {}) {
1241
1241
  ui.step(1, totalSteps, "Cloning egregore...");
1242
1242
  cloneRepo(forkUrl, egregoreDir, githubToken, ui, "egregore");
1243
1243
  setGitIdentity(egregoreDir, user);
1244
- ensureDevelop(egregoreDir);
1245
- // ensureDevelop only creates develop on the REMOTE (git branch, no checkout),
1246
- // so the clone is still on main. The egregore operates on develop, so switch
1247
- // to it now — otherwise local overlays (the codex runtime) get committed to
1248
- // main and are orphaned when session-start later checks out develop.
1249
- try {
1250
- execFileSync("git", ["-C", egregoreDir, "checkout", "develop"], { stdio: "pipe" });
1251
- } catch {
1252
- try {
1253
- execFileSync("git", ["-C", egregoreDir, "checkout", "-b", "develop", "origin/develop"], { stdio: "pipe" });
1254
- } catch {}
1255
- }
1256
1244
 
1257
1245
  ui.step(2, totalSteps, "Cloning shared memory...");
1258
1246
  cloneRepo(memoryUrl, memoryDir, githubToken, ui, "memory");
@@ -1356,10 +1344,6 @@ async function localFounderFlow(ui, ctx = {}) {
1356
1344
  const repoUrl = `https://github.com/${githubOrg}/${mrName}.git`;
1357
1345
  cloneRepo(repoUrl, repoDir, githubToken, ui, mrName);
1358
1346
  setGitIdentity(repoDir, user);
1359
- // New repos get develop branch (our workflow). Existing repos keep their default.
1360
- if (isNewProject) {
1361
- ensureDevelop(repoDir);
1362
- }
1363
1347
  } catch {
1364
1348
  ui.warn(`Could not clone ${mrName} — you may not have access.`);
1365
1349
  }
package/lib/setup.js CHANGED
@@ -435,7 +435,6 @@ async function install(data, ui, targetDir, opts = {}) {
435
435
  }
436
436
  }
437
437
  try { run("git config credential.helper store", { cwd: egregoreDir }); } catch {}
438
- ensureDevelop(egregoreDir);
439
438
  ui.success("Cloned egregore");
440
439
 
441
440
  // Set repo-local git identity from GitHub user (not machine-global config)
@@ -587,7 +586,6 @@ async function install(data, ui, targetDir, opts = {}) {
587
586
  }
588
587
  }
589
588
  try { run("git config credential.helper store", { cwd: repoDir }); } catch {}
590
- ensureDevelop(repoDir);
591
589
  clonedRepos.push(repoName);
592
590
  ui.success(`Cloned ${repoName}`);
593
591
  } catch {
@@ -1023,7 +1021,7 @@ function codexSupportMessage(egregoreDir) {
1023
1021
  " .codex/hooks.json",
1024
1022
  " .codex/hooks/",
1025
1023
  "",
1026
- "Run npx -y create-egregore@latest to install the packaged Codex runtime, then rerun egregore.",
1024
+ "Restore this instance using its installed runtime version, then rerun egregore.",
1027
1025
  "Egregore workflows appear as slash commands. In Codex, invoke them with the matching $skill token or ask in natural language.",
1028
1026
  ].join("\n");
1029
1027
  }
@@ -1037,7 +1035,7 @@ function piSupportMessage(egregoreDir) {
1037
1035
  "Pi meta-harness support is missing from this Egregore checkout.",
1038
1036
  ` path: ${egregoreDir}`,
1039
1037
  "",
1040
- "Run npx -y create-egregore@latest to install the packaged Pi runtime, then rerun egregore.",
1038
+ "Restore this instance using its installed runtime version, then rerun egregore.",
1041
1039
  "Pi loads Egregore through project-local .pi resources and the shared portable skill corpus.",
1042
1040
  ].join("\n");
1043
1041
  }
@@ -1047,7 +1045,7 @@ function primeSupportMessage(egregoreDir) {
1047
1045
  "Prime Agent runtime support is missing from this Egregore checkout.",
1048
1046
  ` path: ${egregoreDir}`,
1049
1047
  "",
1050
- "Run npx -y create-egregore@latest to install the packaged Prime Agent runtime, then rerun egregore.",
1048
+ "Restore this instance using its installed runtime version, then rerun egregore.",
1051
1049
  "Prime Agent loads Egregore through project-local .prime/agent resources and the shared portable skill corpus.",
1052
1050
  ].join("\n");
1053
1051
  }
@@ -1173,8 +1171,6 @@ async function launchOrInstruct(egregoreDir, alias, ui, ctx = {}) {
1173
1171
  console.log("");
1174
1172
 
1175
1173
  if (runtime === "codex") {
1176
- const codexRuntime = installCodexRuntime(egregoreDir);
1177
- reportCodexRuntimeSummary(codexRuntime, ui);
1178
1174
  if (!hasCodexCoreSupport(egregoreDir)) {
1179
1175
  ui.warn(codexSupportMessage(egregoreDir));
1180
1176
  ui.info(`Run ${ui.bold(aliasName)} after updating the checkout.`);
@@ -1190,8 +1186,6 @@ async function launchOrInstruct(egregoreDir, alias, ui, ctx = {}) {
1190
1186
  return;
1191
1187
  }
1192
1188
  } else if (runtime === "pi") {
1193
- const piRuntime = installPiRuntime(egregoreDir);
1194
- reportPiRuntimeSummary(piRuntime, ui);
1195
1189
  if (!hasPiRuntimeSupport(egregoreDir)) {
1196
1190
  ui.warn(piSupportMessage(egregoreDir));
1197
1191
  ui.info(`Run ${ui.bold(aliasName)} after updating the checkout.`);
@@ -1199,8 +1193,6 @@ async function launchOrInstruct(egregoreDir, alias, ui, ctx = {}) {
1199
1193
  return;
1200
1194
  }
1201
1195
  } else if (runtime === "prime") {
1202
- const primeRuntime = installPrimeRuntime(egregoreDir);
1203
- reportPrimeRuntimeSummary(primeRuntime, ui);
1204
1196
  if (!hasPrimeRuntimeSupport(egregoreDir)) {
1205
1197
  ui.warn(primeSupportMessage(egregoreDir));
1206
1198
  ui.info(`Run ${ui.bold(aliasName)} after updating the checkout.`);
@@ -1311,11 +1303,15 @@ function appendLocalBinToRc(ui) {
1311
1303
  */
1312
1304
  async function installLauncherBinary(egregoreDir, ui) {
1313
1305
  const template = readLauncherTemplate();
1314
- const candidates = [
1315
- { dir: "/usr/local/bin", location: "system" },
1316
- { dir: "/opt/homebrew/bin", location: "system" },
1317
- { dir: path.join(os.homedir(), ".local", "bin"), location: "user" },
1318
- ];
1306
+ // An explicit destination must never fall through to machine-wide paths.
1307
+ const configuredBinDir = process.env.EGREGORE_LAUNCHER_BIN_DIR;
1308
+ const candidates = configuredBinDir
1309
+ ? [{ dir: path.resolve(configuredBinDir), location: "user" }]
1310
+ : [
1311
+ { dir: "/usr/local/bin", location: "system" },
1312
+ { dir: "/opt/homebrew/bin", location: "system" },
1313
+ { dir: path.join(os.homedir(), ".local", "bin"), location: "user" },
1314
+ ];
1319
1315
 
1320
1316
  let chosen = null;
1321
1317
  for (const c of candidates) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-egregore",
3
- "version": "0.20.1",
3
+ "version": "0.20.3",
4
4
  "description": "Set up Egregore for your team in one command \u2014 installs the egregore launcher and your choice of Claude Code, Codex, or Pi.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "build:runtime": "node ../../bin/capability-distribution.mjs generate-skill-view --root ../.. && node scripts/build-runtime-bundle.mjs && node scripts/build-pi-runtime-bundle.mjs && node scripts/build-prime-runtime-bundle.mjs && node ../../api/scripts/build-connect-runtime-pack.mjs",
14
14
  "build:pi-runtime": "node scripts/build-pi-runtime-bundle.mjs",
15
15
  "build:prime-runtime": "node scripts/build-prime-runtime-bundle.mjs",
16
- "test": "node ../../bin/capability-distribution.mjs validate --root ../.. && node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node scripts/build-prime-runtime-bundle.mjs --check && node ../../bin/prime-render-spec.mjs --check && node ../../bin/pi-render-spec.mjs --check && node ../../api/scripts/build-connect-runtime-pack.mjs --check && node --test test/capability-distribution.test.js test/connect-runtime.test.js test/context.test.js test/path-lookup.test.js test/nixos-portability.test.js test/parse-join-target.test.js test/skip-repos.test.js test/install-origin-guard.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/pi-runtime.test.js test/prime-runtime.test.js test/prime-branch-policy.test.js test/prime-bridge-skill.test.js test/prime-session-smoke.test.js test/pi-product-workflows.test.js test/installer-runtime-source.test.js test/scroll-repro.test.js test/launcher-refocus-redraw.test.js test/multiselect-remote-search.test.js test/back-navigation.test.js test/manifest-form.test.js test/launcher-delete.test.js test/launcher-connect.test.js test/installer-connect-choice.test.js test/launcher-connected-status.test.js test/launcher-permissions.test.js test/launcher-update.test.js test/connected-config.test.js",
16
+ "test": "node ../../bin/capability-distribution.mjs validate --root ../.. && node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node scripts/build-prime-runtime-bundle.mjs --check && node ../../bin/prime-render-spec.mjs --check && node ../../bin/pi-render-spec.mjs --check && node ../../api/scripts/build-connect-runtime-pack.mjs --check && node --test test/capability-distribution.test.js test/connect-runtime.test.js test/context.test.js test/path-lookup.test.js test/nixos-portability.test.js test/parse-join-target.test.js test/skip-repos.test.js test/install-origin-guard.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/pi-runtime.test.js test/prime-runtime.test.js test/prime-branch-policy.test.js test/prime-bridge-skill.test.js test/prime-session-smoke.test.js test/pi-product-workflows.test.js test/installer-runtime-source.test.js test/scroll-repro.test.js test/launcher-refocus-redraw.test.js test/multiselect-remote-search.test.js test/back-navigation.test.js test/manifest-form.test.js test/launcher-delete.test.js test/launcher-connect.test.js test/installer-connect-choice.test.js test/launcher-connected-status.test.js test/launcher-permissions.test.js test/launcher-update.test.js test/connected-config.test.js test/workflow-settings.test.js",
17
17
  "test:e2e": "node --test test/e2e-local.test.js",
18
18
  "test:all": "node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node --test test/"
19
19
  },
@@ -11,7 +11,7 @@
11
11
  {
12
12
  "section": "Identity & Upstream",
13
13
  "action": "keep",
14
- "sourceHash": "ddcbc0083aff",
14
+ "sourceHash": "86a2c62ce498",
15
15
  "note": "Kept; /update, /contribute, /save tokens rendered as $skill tokens."
16
16
  },
17
17
  {
@@ -35,7 +35,7 @@
35
35
  {
36
36
  "section": "After Greeting — BRANCH ON FIRST RESPONSE",
37
37
  "action": "replace",
38
- "sourceHash": "b13b81aea8f3",
38
+ "sourceHash": "3bac01c0a00a",
39
39
  "note": "EnterWorktree -> bin/agent.sh branch with git checkout fallback; AskUserQuestion -> numbered options in plain text; branch-guard mapped to .codex/hooks/branch-guard.js with instruction fallback; plan-mode note dropped (no plan mode on Codex); /branch + /onboarding -> skill tokens. Handoff claiming and repoState auto-checkout bash kept verbatim (pure git); surrounding prose compressed 2026-08 for the 32 KiB budget, every rule retained."
40
40
  },
41
41
  {
@@ -89,7 +89,7 @@
89
89
  {
90
90
  "section": "Git Workflow",
91
91
  "action": "keep",
92
- "sourceHash": "23df84b5fe80",
92
+ "sourceHash": "40735c0c09ff",
93
93
  "note": "Kept; slash tokens rendered as $skill tokens. Branch diagram unchanged (code fence)."
94
94
  },
95
95
  {
@@ -92,11 +92,20 @@ This block is the Codex-native Egregore behavioral spec, rendered from CLAUDE.md
92
92
 
93
93
  ## Identity & Upstream
94
94
 
95
- This is an Egregore instance — a downstream fork of the upstream framework at `egregore-labs/egregore`. The framework (`bin/`, `.claude/skills/`, `.claude/hooks/`, `.claude/context/`, `.claude/agents/`, `.pi/`, `loom/`, `CLAUDE.md`, `skills/`) is synced from upstream on every session start and via `$update`. It is not authored in this repo.
95
+ Framework direction comes only from `egregore.json.upstream_url`:
96
+
97
+ - **Source** — literal `"none"`: framework changes are authored here.
98
+ `$update` and `$contribute` stop; use `$save`. Public OSS is downstream and
99
+ receives changes only through this repository's release flow.
100
+ - **Downstream** — a repository URL, or an absent key defaulting to
101
+ `egregore-labs/egregore`: framework paths are synced and not authored here.
102
+
103
+ Never infer direction from a repository name or Git remote.
96
104
 
97
105
  **Where changes belong:**
98
- - **Framework is outdated or a skill is missing:** run `$update` first. It pulls the latest from upstream.
99
- - **Framework behavior needs changing or has a bug:** `$contribute` opens a PR against `egregore-labs/egregore`, or file a GitHub issue on that repo. Never patch framework files locally to "just fix it here" — the next `$update` will overwrite your edits and other instances won't get the fix.
106
+ - **Downstream framework is stale:** run `$update`.
107
+ - **Downstream framework needs a fix:** use `$contribute` or file an upstream issue; local patches are overwritten by `$update`.
108
+ - **Source framework needs a fix:** use `$save` into its configured integration and release flow; never `$contribute`.
100
109
  - **Org-level work** (memory, org-specific knowledge, managed repos, `egregore.json`): `$save` to this repo.
101
110
 
102
111
  When a user reports broken or missing framework behavior, the first question is "when did you last `$update`?"
@@ -139,7 +148,7 @@ The integration branch is `develop` unless top-level `egregore.json.base_branch`
139
148
 
140
149
  **Fallback:** If `bin/agent.sh branch` fails, resolve `{base}` with
141
150
  `_get_base_branch`, then use
142
- `git checkout -b dev/{author}/{slug} origin/{base}`.
151
+ `git checkout --no-track -b dev/{author}/{slug} origin/{base}`.
143
152
 
144
153
  4. Update graph (fire-and-forget): `bash bin/graph-op.sh set-topic "$(cat .egregore-session-id 2>/dev/null)" "topic from slug" "dev/author/slug" 2>/dev/null &`
145
154
 
@@ -205,9 +214,11 @@ The `.codex/hooks/branch-guard.js` PreToolUse hook (launcher `--enable hooks`) p
205
214
  Wait for the reply, then branch.
206
215
  - **The user explicitly requested the protected branch** → that request is consent. Record it with `echo '{branch}' > .egregore-branch-consent`, then retry. Never create the marker merely to silence the hook.
207
216
 
208
- Memory, managed-repo, and runtime-state writes bypass the project guard — if one triggers it, correct the target/context instead of asking for consent.
217
+ If this Codex build does not support hooks, keep the same rule.
209
218
 
210
- If this Codex build does not support hooks, follow the same discipline as a standing instruction: never write or commit on the configured base, develop, main, or master.
219
+ **History:** Do not merge, cherry-pick, or rebase another task merely to read
220
+ it; use `gh pr view/diff`, `git show`, or a temporary worktree. Integrate
221
+ only for dependencies. Deletion needs no rewrite unless purging secrets.
211
222
 
212
223
  ### Onboarding exception
213
224
 
@@ -355,11 +366,14 @@ branch; `base_branch: "main"` is single-branch mode. Users never interact with
355
366
  git directly.
356
367
 
357
368
  ```
358
- main ← stable (/release)
359
- develop ← integration (PRs land here)
360
- dev/{author}/{topic-slug} | feature/{slug} | bugfix/{slug}
369
+ main ← selected `/release` candidates
370
+ develop ← CL integration (available internally)
371
+ dev/{author}/{topic-slug} | feature/{slug} | bugfix/{slug}
361
372
  ```
362
373
 
374
+ - **Develop is not release**: merged PRs stay inside CL.
375
+ - **`$release` is selective**: the Release Desk queues exact PR SHAs into a candidate from main. Never merge all of develop.
376
+ - **OSS is separate**: `$sync-public` reviews delivery after private main.
363
377
  - **On launch**: syncs the configured base branch + memory. Does NOT create a branch.
364
378
  - **Branch creation**: MANDATORY on first work-related message (see above).
365
379
  - **Resuming**: rebase onto the configured base branch and continue.
@@ -187,6 +187,15 @@ base_ref() {
187
187
  fi
188
188
  }
189
189
 
190
+ clear_base_upstream() {
191
+ local repo="$1" branch="$2" base="$3" upstream=""
192
+ case "$branch" in dev/*|feature/*|bugfix/*) ;; *) return 0 ;; esac
193
+ upstream="$(git -C "$repo" rev-parse --abbrev-ref "${branch}@{upstream}" 2>/dev/null || true)"
194
+ if [ "$upstream" = "$base" ]; then
195
+ git -C "$repo" branch --unset-upstream "$branch" >/dev/null 2>&1 || true
196
+ fi
197
+ }
198
+
190
199
  cmd_protocol() {
191
200
  cat <<'EOF'
192
201
  Egregore portable agent protocol
@@ -306,8 +315,9 @@ cmd_branch() {
306
315
  if git -C "$SCRIPT_DIR" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
307
316
  git -C "$SCRIPT_DIR" checkout "$branch" --quiet
308
317
  else
309
- git -C "$SCRIPT_DIR" checkout -b "$branch" "$base" --quiet
318
+ git -C "$SCRIPT_DIR" checkout --no-track -b "$branch" "$base" --quiet
310
319
  fi
320
+ clear_base_upstream "$SCRIPT_DIR" "$branch" "$base"
311
321
  egregore_link_shared_state "$SCRIPT_DIR" "$MAIN_PROJECT_DIR" >/dev/null 2>/dev/null || true
312
322
  echo "branch: $branch"
313
323
  echo "worktree: $SCRIPT_DIR"
@@ -323,8 +333,9 @@ cmd_branch() {
323
333
  fi
324
334
 
325
335
  if ! git -C "$MAIN_PROJECT_DIR" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
326
- git -C "$MAIN_PROJECT_DIR" branch "$branch" "$base" >/dev/null 2>&1 || die "failed to create branch $branch"
336
+ git -C "$MAIN_PROJECT_DIR" branch --no-track "$branch" "$base" >/dev/null 2>&1 || die "failed to create branch $branch"
327
337
  fi
338
+ clear_base_upstream "$MAIN_PROJECT_DIR" "$branch" "$base"
328
339
 
329
340
  wt_path="$MAIN_PROJECT_DIR/.claude/worktrees/$slug"
330
341
  if [ -e "$wt_path" ]; then
@@ -356,8 +367,9 @@ ensure_working_branch() {
356
367
  if git -C "$SCRIPT_DIR" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
357
368
  git -C "$SCRIPT_DIR" checkout "$branch" --quiet || die "failed to checkout $branch"
358
369
  else
359
- git -C "$SCRIPT_DIR" checkout -b "$branch" "$base" --quiet || die "failed to create $branch"
370
+ git -C "$SCRIPT_DIR" checkout --no-track -b "$branch" "$base" --quiet || die "failed to create $branch"
360
371
  fi
372
+ clear_base_upstream "$SCRIPT_DIR" "$branch" "$base"
361
373
  echo "$branch"
362
374
  }
363
375