create-egregore 0.20.1 → 0.20.2
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 +57 -14
- package/lib/local.js +4 -20
- package/lib/setup.js +0 -2
- package/package.json +2 -2
- package/runtime/codex/.codex/spec-manifest.json +3 -3
- package/runtime/codex/AGENTS.md +23 -9
- package/runtime/codex/bin/agent.sh +15 -3
- package/runtime/codex/bin/codex-render-spec.mjs +5 -3
- package/runtime/codex/bin/contribute-guard.sh +79 -0
- package/runtime/codex/bin/handoff-save-egregore.sh +1 -1
- package/runtime/codex/bin/lib/git-sync.sh +16 -0
- package/runtime/codex/bin/lib/greeting.sh +2 -2
- package/runtime/codex/bin/search.sh +46 -4
- package/runtime/codex/bin/session-autosave.sh +6 -1
- package/runtime/codex/bin/settings.sh +62 -3
- package/runtime/codex/bin/worktree-create.sh +4 -1
- package/runtime/codex/manifest.json +1 -0
- package/runtime/pi/.codex/spec-manifest.json +3 -3
- package/runtime/pi/.pi/APPEND_SYSTEM.md +23 -9
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +23 -9
- package/runtime/pi/bin/agent.sh +15 -3
- package/runtime/pi/bin/codex-render-spec.mjs +5 -3
- package/runtime/pi/bin/contribute-guard.sh +79 -0
- package/runtime/pi/bin/handoff-save-egregore.sh +1 -1
- package/runtime/pi/bin/lib/git-sync.sh +16 -0
- package/runtime/pi/bin/lib/greeting.sh +2 -2
- package/runtime/pi/bin/search.sh +46 -4
- package/runtime/pi/bin/session-autosave.sh +6 -1
- package/runtime/pi/bin/settings.sh +62 -3
- package/runtime/pi/bin/worktree-create.sh +4 -1
- package/runtime/pi/manifest.json +1 -0
- package/runtime/prime/.codex/spec-manifest.json +3 -3
- package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +24 -10
- package/runtime/prime/.prime/agent/spec-manifest.json +2 -2
- package/runtime/prime/AGENTS.md +23 -9
- package/runtime/prime/bin/agent.sh +15 -3
- package/runtime/prime/bin/codex-render-spec.mjs +5 -3
- package/runtime/prime/bin/contribute-guard.sh +79 -0
- package/runtime/prime/bin/handoff-save-egregore.sh +1 -1
- package/runtime/prime/bin/lib/git-sync.sh +16 -0
- package/runtime/prime/bin/lib/greeting.sh +2 -2
- package/runtime/prime/bin/prime-render-spec.mjs +1 -1
- package/runtime/prime/bin/search.sh +46 -4
- package/runtime/prime/bin/session-autosave.sh +6 -1
- package/runtime/prime/bin/settings.sh +62 -3
- package/runtime/prime/bin/worktree-create.sh +4 -1
- package/runtime/prime/manifest.json +1 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// egregore-launcher-version: 0.20.
|
|
2
|
+
// egregore-launcher-version: 0.20.2
|
|
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.
|
|
36
|
+
const VERSION = "0.20.2";
|
|
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,9 @@ function codexSupportMessage(egregoreDir) {
|
|
|
702
702
|
" .codex/hooks.json",
|
|
703
703
|
" .codex/hooks/",
|
|
704
704
|
"",
|
|
705
|
-
"
|
|
705
|
+
"Automatic repair did not complete. Retry with:",
|
|
706
|
+
" npx -y create-egregore@latest --refresh-launcher",
|
|
707
|
+
"Then rerun egregore.",
|
|
706
708
|
"Egregore workflows appear as slash commands. In Codex, invoke them with the matching $skill token or ask in natural language.",
|
|
707
709
|
].join("\n");
|
|
708
710
|
}
|
|
@@ -756,6 +758,27 @@ function primeSupportMessage(egregoreDir) {
|
|
|
756
758
|
].join("\n");
|
|
757
759
|
}
|
|
758
760
|
|
|
761
|
+
function repairPortableRuntime(egregoreDir, runtime) {
|
|
762
|
+
const label = runtimeLabel(runtime);
|
|
763
|
+
process.stdout.write(`\n ${CYAN}↻${RESET} ${BOLD}Repairing ${label} support${RESET}${DIM} — updating this checkout${RESET}\n`);
|
|
764
|
+
const result = spawnSync(
|
|
765
|
+
"npx",
|
|
766
|
+
["-y", `${PUBLIC_NPX_PACKAGE}@latest`, "--refresh-launcher"],
|
|
767
|
+
{
|
|
768
|
+
cwd: egregoreDir,
|
|
769
|
+
stdio: "inherit",
|
|
770
|
+
env: { ...process.env, EGREGORE_RUNTIME_REPAIR: runtime },
|
|
771
|
+
timeout: 3 * 60 * 1000,
|
|
772
|
+
},
|
|
773
|
+
);
|
|
774
|
+
if (result.error || result.status !== 0) {
|
|
775
|
+
process.stderr.write(` ${YELLOW}!${RESET} Automatic ${label} repair failed; the checkout was left in place.\n`);
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
process.stdout.write(` ${GREEN}✓${RESET} ${label} support repaired\n\n`);
|
|
779
|
+
return true;
|
|
780
|
+
}
|
|
781
|
+
|
|
759
782
|
// Minimal y/N line prompt for pre-launch decisions (the TUI select machinery
|
|
760
783
|
// is torn down by the time launch() runs).
|
|
761
784
|
function confirmLine(question) {
|
|
@@ -886,7 +909,9 @@ async function launch(inst, runtimeOverride) {
|
|
|
886
909
|
}
|
|
887
910
|
if (runtime === "codex") {
|
|
888
911
|
if (!hasCodexCoreSupport(inst.path)) {
|
|
889
|
-
|
|
912
|
+
if (!repairPortableRuntime(inst.path, runtime) || !hasCodexCoreSupport(inst.path)) {
|
|
913
|
+
die(codexSupportMessage(inst.path));
|
|
914
|
+
}
|
|
890
915
|
}
|
|
891
916
|
const skillsInstalled = installCodexSkills(inst.path);
|
|
892
917
|
const cardRendered = await renderCodexStartupCard(inst.path);
|
|
@@ -894,7 +919,10 @@ async function launch(inst, runtimeOverride) {
|
|
|
894
919
|
die(codexSupportMessage(inst.path));
|
|
895
920
|
}
|
|
896
921
|
} else if (runtime === "pi") {
|
|
897
|
-
if (!hasPiCoreSupport(inst.path)
|
|
922
|
+
if (!hasPiCoreSupport(inst.path) &&
|
|
923
|
+
(!repairPortableRuntime(inst.path, runtime) || !hasPiCoreSupport(inst.path))) {
|
|
924
|
+
die(piSupportMessage(inst.path));
|
|
925
|
+
}
|
|
898
926
|
}
|
|
899
927
|
let launchArgs = null;
|
|
900
928
|
if (runtime === "prime") {
|
|
@@ -903,7 +931,10 @@ async function launch(inst, runtimeOverride) {
|
|
|
903
931
|
// check + the trust-flag probe, which shells out to the binary), then a
|
|
904
932
|
// single handoff line explains the remaining in-harness startup.
|
|
905
933
|
const stopLoader = startSpinner("Starting Prime Agent");
|
|
906
|
-
|
|
934
|
+
let coreOk = hasPrimeCoreSupport(inst.path);
|
|
935
|
+
if (!coreOk && repairPortableRuntime(inst.path, runtime)) {
|
|
936
|
+
coreOk = hasPrimeCoreSupport(inst.path);
|
|
937
|
+
}
|
|
907
938
|
launchArgs = coreOk ? runtimeLaunchArgs(runtime, inst.path) : null;
|
|
908
939
|
stopLoader();
|
|
909
940
|
if (!coreOk) die(primeSupportMessage(inst.path));
|
|
@@ -2102,7 +2133,7 @@ function runSettings(inst, args) {
|
|
|
2102
2133
|
return { status: 127, stdout: "", stderr: "bin/settings.sh not found — update this egregore (run /pull) to get settings.\n", missing: true };
|
|
2103
2134
|
}
|
|
2104
2135
|
try {
|
|
2105
|
-
return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout:
|
|
2136
|
+
return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 45000 });
|
|
2106
2137
|
} catch (err) {
|
|
2107
2138
|
return { status: 1, stdout: "", stderr: String(err) };
|
|
2108
2139
|
}
|
|
@@ -2117,13 +2148,13 @@ function settingsDump(inst) {
|
|
|
2117
2148
|
async function cmdSettings(args) {
|
|
2118
2149
|
const registry = readRegistry();
|
|
2119
2150
|
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"]);
|
|
2151
|
+
const DOMAINS = new Set(["hosting", "workflow", "repo", "admin", "people", "dump"]);
|
|
2121
2152
|
let rest = args.slice();
|
|
2122
2153
|
let slug = "";
|
|
2123
2154
|
if (rest.length && !DOMAINS.has(rest[0])) { slug = rest[0]; rest = rest.slice(1); }
|
|
2124
2155
|
const inst = resolveInviteInstance(registry, slug);
|
|
2125
2156
|
if (!inst) {
|
|
2126
|
-
die(`multiple egregores installed; choose one:\n egregore settings <slug> [hosting|repo|admin]\n run: egregore ls`);
|
|
2157
|
+
die(`multiple egregores installed; choose one:\n egregore settings <slug> [hosting|workflow|repo|admin|people]\n run: egregore ls`);
|
|
2127
2158
|
}
|
|
2128
2159
|
// Interactive editing lives in the launcher (press `s`). With no verb, print
|
|
2129
2160
|
// the snapshot; otherwise forward straight to the deterministic verb.
|
|
@@ -2421,6 +2452,14 @@ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCurs
|
|
|
2421
2452
|
} else {
|
|
2422
2453
|
const rows = [
|
|
2423
2454
|
{ name: "Hosted Artifacts", value: (d.hosting !== false) ? `${GREEN}ON${RESET}` : `${YELLOW}OFF${RESET}` },
|
|
2455
|
+
{
|
|
2456
|
+
name: "Git workflow",
|
|
2457
|
+
value: d.workflow === "simple"
|
|
2458
|
+
? `${DIM}PRs → main${RESET}`
|
|
2459
|
+
: d.workflow === "staged"
|
|
2460
|
+
? `${DIM}PRs → develop → main${RESET}`
|
|
2461
|
+
: `${DIM}PRs → ${d.base_branch || "custom"}${RESET}`,
|
|
2462
|
+
},
|
|
2424
2463
|
{ name: "Managed repos", value: `${DIM}${(d.repos || []).length}${RESET}` },
|
|
2425
2464
|
{ name: "Admins", value: `${DIM}${(d.admins || []).length}${RESET}` },
|
|
2426
2465
|
{ name: "People", value: `${DIM}${(d.people || []).length}${RESET}` },
|
|
@@ -2433,7 +2472,7 @@ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCurs
|
|
|
2433
2472
|
});
|
|
2434
2473
|
lines.push(emptyBoxLine(innerWidth, margin));
|
|
2435
2474
|
if (notice) lines.push(boxLine(notice, innerWidth, margin));
|
|
2436
|
-
lines.push(boxLine(`${DIM}↑↓ nav · ${RESET}${BOLD}enter${RESET}${DIM} ${cursor
|
|
2475
|
+
lines.push(boxLine(`${DIM}↑↓ nav · ${RESET}${BOLD}enter${RESET}${DIM} ${cursor < 2 ? "toggle" : "open"} · ← back · q quit${RESET}`, innerWidth, margin));
|
|
2437
2476
|
}
|
|
2438
2477
|
|
|
2439
2478
|
lines.push(emptyBoxLine(innerWidth, margin));
|
|
@@ -2891,15 +2930,19 @@ async function browser(args = {}) {
|
|
|
2891
2930
|
|
|
2892
2931
|
// menu view
|
|
2893
2932
|
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 +
|
|
2895
|
-
if (key.name === "down" || key.name === "j") { S.settingsCursor = (S.settingsCursor + 1) %
|
|
2933
|
+
if (key.name === "up" || key.name === "k") { S.settingsCursor = (S.settingsCursor - 1 + 5) % 5; render(); return; }
|
|
2934
|
+
if (key.name === "down" || key.name === "j") { S.settingsCursor = (S.settingsCursor + 1) % 5; render(); return; }
|
|
2896
2935
|
if (key.name === "return" || chunk === " ") {
|
|
2897
2936
|
if (S.settingsCursor === 0) {
|
|
2898
2937
|
const on = (S.settingsData && S.settingsData.hosting) !== false;
|
|
2899
2938
|
settingsRunVerb(["hosting", on ? "off" : "on"]);
|
|
2900
2939
|
render();
|
|
2940
|
+
} else if (S.settingsCursor === 1) {
|
|
2941
|
+
const simple = (S.settingsData && S.settingsData.workflow) === "simple";
|
|
2942
|
+
settingsRunVerb(["workflow", simple ? "staged" : "simple"]);
|
|
2943
|
+
render();
|
|
2901
2944
|
} else {
|
|
2902
|
-
const domain = S.settingsCursor ===
|
|
2945
|
+
const domain = S.settingsCursor === 2 ? "repo" : S.settingsCursor === 3 ? "admin" : "people";
|
|
2903
2946
|
S.settingsView = "list"; S.settingsDomain = domain;
|
|
2904
2947
|
S.settingsItems = settingsItemsFor(S.settingsData, domain);
|
|
2905
2948
|
S.settingsListCursor = 0; S.settingsMode = "browse"; S.settingsNotice = "";
|
|
@@ -3155,7 +3198,7 @@ async function browser(args = {}) {
|
|
|
3155
3198
|
return;
|
|
3156
3199
|
}
|
|
3157
3200
|
state.settingsInst = pick;
|
|
3158
|
-
state.settingsData = settingsDump(pick) || { hosting: true, repos: [], admins: [], people: [] };
|
|
3201
|
+
state.settingsData = settingsDump(pick) || { hosting: true, workflow: "staged", base_branch: "develop", repos: [], admins: [], people: [] };
|
|
3159
3202
|
state.settingsCursor = 0;
|
|
3160
3203
|
state.settingsView = "menu";
|
|
3161
3204
|
state.settingsNotice = "";
|
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
|
-
|
|
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 {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-egregore",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
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": "
|
|
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": "
|
|
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": "
|
|
92
|
+
"sourceHash": "40735c0c09ff",
|
|
93
93
|
"note": "Kept; slash tokens rendered as $skill tokens. Branch diagram unchanged (code fence)."
|
|
94
94
|
},
|
|
95
95
|
{
|
package/runtime/codex/AGENTS.md
CHANGED
|
@@ -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
|
-
|
|
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
|
-
- **
|
|
99
|
-
- **
|
|
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
|
-
|
|
217
|
+
If this Codex build does not support hooks, keep the same rule.
|
|
209
218
|
|
|
210
|
-
|
|
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 ←
|
|
359
|
-
|
|
360
|
-
|
|
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
|
|
|
@@ -193,7 +193,7 @@ The integration branch is \`develop\` unless top-level \`egregore.json.base_bran
|
|
|
193
193
|
|
|
194
194
|
**Fallback:** If \`bin/agent.sh branch\` fails, resolve \`{base}\` with
|
|
195
195
|
\`_get_base_branch\`, then use
|
|
196
|
-
\`git checkout -b dev/{author}/{slug} origin/{base}\`.
|
|
196
|
+
\`git checkout --no-track -b dev/{author}/{slug} origin/{base}\`.
|
|
197
197
|
|
|
198
198
|
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 &\`
|
|
199
199
|
|
|
@@ -259,9 +259,11 @@ The \`.codex/hooks/branch-guard.js\` PreToolUse hook (launcher \`--enable hooks\
|
|
|
259
259
|
Wait for the reply, then branch.
|
|
260
260
|
- **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.
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
If this Codex build does not support hooks, keep the same rule.
|
|
263
263
|
|
|
264
|
-
|
|
264
|
+
**History:** Do not merge, cherry-pick, or rebase another task merely to read
|
|
265
|
+
it; use \`gh pr view/diff\`, \`git show\`, or a temporary worktree. Integrate
|
|
266
|
+
only for dependencies. Deletion needs no rewrite unless purging secrets.
|
|
265
267
|
|
|
266
268
|
### Onboarding exception
|
|
267
269
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
CONFIG="$SCRIPT_DIR/egregore.json"
|
|
6
|
+
EXPECTED_REPO=""
|
|
7
|
+
|
|
8
|
+
usage() {
|
|
9
|
+
echo "usage: bash bin/contribute-guard.sh [--config <path>] [--expect <owner/repo>]" >&2
|
|
10
|
+
exit 2
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
fail() {
|
|
14
|
+
echo "contribute: $1" >&2
|
|
15
|
+
exit "${2:-2}"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
while [ $# -gt 0 ]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--config)
|
|
21
|
+
[ $# -ge 2 ] || usage
|
|
22
|
+
CONFIG="$2"
|
|
23
|
+
shift 2
|
|
24
|
+
;;
|
|
25
|
+
--expect)
|
|
26
|
+
[ $# -ge 2 ] || usage
|
|
27
|
+
EXPECTED_REPO="$2"
|
|
28
|
+
shift 2
|
|
29
|
+
;;
|
|
30
|
+
--help|-h)
|
|
31
|
+
usage
|
|
32
|
+
;;
|
|
33
|
+
*)
|
|
34
|
+
usage
|
|
35
|
+
;;
|
|
36
|
+
esac
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
[ -f "$CONFIG" ] || fail "cannot read configuration at $CONFIG; refusing to select an upstream target"
|
|
40
|
+
|
|
41
|
+
UPSTREAM_URL=$(jq -er '
|
|
42
|
+
if has("upstream_url") then
|
|
43
|
+
if .upstream_url == null then ""
|
|
44
|
+
elif (.upstream_url | type) == "string" then .upstream_url
|
|
45
|
+
else error("upstream_url must be a string")
|
|
46
|
+
end
|
|
47
|
+
else ""
|
|
48
|
+
end
|
|
49
|
+
' "$CONFIG" 2>/dev/null) ||
|
|
50
|
+
fail "configuration is invalid; refusing to select an upstream target"
|
|
51
|
+
|
|
52
|
+
if [ "$UPSTREAM_URL" = "none" ]; then
|
|
53
|
+
fail 'disabled because upstream_url is "none"; this checkout is a framework source, so use the save workflow for its configured integration branch' 3
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
[ -n "$UPSTREAM_URL" ] || UPSTREAM_URL="https://github.com/egregore-labs/egregore.git"
|
|
57
|
+
|
|
58
|
+
case "$UPSTREAM_URL" in
|
|
59
|
+
https://github.com/*/*)
|
|
60
|
+
UPSTREAM_REPO="${UPSTREAM_URL#*github.com/}"
|
|
61
|
+
;;
|
|
62
|
+
git@github.com:*/*)
|
|
63
|
+
UPSTREAM_REPO="${UPSTREAM_URL#git@github.com:}"
|
|
64
|
+
;;
|
|
65
|
+
*)
|
|
66
|
+
fail "unsupported upstream_url '$UPSTREAM_URL'; expected a GitHub repository URL"
|
|
67
|
+
;;
|
|
68
|
+
esac
|
|
69
|
+
|
|
70
|
+
UPSTREAM_REPO="${UPSTREAM_REPO%/}"
|
|
71
|
+
UPSTREAM_REPO="${UPSTREAM_REPO%.git}"
|
|
72
|
+
printf '%s\n' "$UPSTREAM_REPO" | grep -Eq '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$' ||
|
|
73
|
+
fail "invalid upstream repository '$UPSTREAM_REPO'; refusing external Git operations"
|
|
74
|
+
|
|
75
|
+
if [ -n "$EXPECTED_REPO" ] && [ "$EXPECTED_REPO" != "$UPSTREAM_REPO" ]; then
|
|
76
|
+
fail "target changed from '$EXPECTED_REPO' to '$UPSTREAM_REPO'; refusing external Git operations"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
printf '%s\n' "$UPSTREAM_REPO"
|
|
@@ -135,7 +135,7 @@ if [ -z "$CURRENT_BRANCH" ] || [ "$CURRENT_BRANCH" = "$BASE_BRANCH" ] \
|
|
|
135
135
|
# hash from the autosave sweep) — same-name pushes wedge on non-FF.
|
|
136
136
|
NEW_BRANCH="dev/${AUTHOR}/${KIND}-${SLUG_DATE}${BRANCH_SUFFIX:+-$BRANCH_SUFFIX}"
|
|
137
137
|
git fetch origin "$BASE_BRANCH" --quiet 2>/dev/null || true
|
|
138
|
-
git checkout -b "$NEW_BRANCH" "$BASE_REF" --quiet 2>/dev/null || \
|
|
138
|
+
git checkout --no-track -b "$NEW_BRANCH" "$BASE_REF" --quiet 2>/dev/null || \
|
|
139
139
|
git checkout "$NEW_BRANCH" --quiet 2>/dev/null || exit 0
|
|
140
140
|
CURRENT_BRANCH="$NEW_BRANCH"
|
|
141
141
|
fi
|
|
@@ -32,6 +32,22 @@ if [ -z "${BASE_BRANCH:-}" ]; then
|
|
|
32
32
|
fi
|
|
33
33
|
fi
|
|
34
34
|
|
|
35
|
+
# Migrate task branches created by older Egregore versions. `git branch
|
|
36
|
+
# <task> origin/<base>` implicitly made the task branch track the protected
|
|
37
|
+
# integration branch, so a bare push could target it when push.default was
|
|
38
|
+
# `upstream`. Task branches remain unpublished until the explicit save/push
|
|
39
|
+
# flow creates their same-name remote and sets that as upstream.
|
|
40
|
+
_CURRENT_TASK_BRANCH="$(git branch --show-current 2>/dev/null || true)"
|
|
41
|
+
case "$_CURRENT_TASK_BRANCH" in
|
|
42
|
+
dev/*|feature/*|bugfix/*)
|
|
43
|
+
_CURRENT_TASK_UPSTREAM="$(git rev-parse --abbrev-ref '@{upstream}' 2>/dev/null || true)"
|
|
44
|
+
if [ "$_CURRENT_TASK_UPSTREAM" = "origin/$BASE_BRANCH" ]; then
|
|
45
|
+
git branch --unset-upstream "$_CURRENT_TASK_BRANCH" >/dev/null 2>&1 || true
|
|
46
|
+
fi
|
|
47
|
+
;;
|
|
48
|
+
esac
|
|
49
|
+
unset _CURRENT_TASK_BRANCH _CURRENT_TASK_UPSTREAM
|
|
50
|
+
|
|
35
51
|
# --- Ensure pull.rebase is set (prevents "divergent branches" errors) ---
|
|
36
52
|
git config pull.rebase true 2>/dev/null || true
|
|
37
53
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# - Telemetry emit
|
|
14
14
|
# - First session welcome
|
|
15
15
|
#
|
|
16
|
-
# Inputs: SCRIPT_DIR, STATE_FILE, CONFIG, CTX_DIR, BRANCH, COMMITS_AHEAD,
|
|
16
|
+
# Inputs: SCRIPT_DIR, STATE_FILE, CONFIG, CTX_DIR, BRANCH, BASE_BRANCH, COMMITS_AHEAD,
|
|
17
17
|
# AUTHOR, LOCAL_MODE, MEMORY_SYNCED, SAVED_BRANCH,
|
|
18
18
|
# HEALTH_*, FRAMEWORK_VERSION, TIME_OF_DAY, EGREGORE_SESSION_ID,
|
|
19
19
|
# FIRST_SESSION, DISPLAY_NAME_STATE, DASHBOARD_URL
|
|
@@ -515,5 +515,5 @@ else
|
|
|
515
515
|
echo ""
|
|
516
516
|
echo "IMPORTANT: Display the above greeting to the user exactly as-is (preserve the ASCII art formatting and ornamented status) on their first message. Then ask: What are you working on?"
|
|
517
517
|
echo ""
|
|
518
|
-
echo "BRANCH RULE: When the user responds with what they're working on, your FIRST action is to create a working branch: git fetch origin
|
|
518
|
+
echo "BRANCH RULE: When the user responds with what they're working on, your FIRST action is to create a working branch: git fetch origin $BASE_BRANCH --quiet && git checkout --no-track -b dev/{author}/{topic-slug} origin/$BASE_BRANCH. Do this BEFORE any other work. Derive the topic slug from their description. If they ask a pure question with no work intent, skip branching."
|
|
519
519
|
fi
|