create-egregore 0.19.8 → 0.19.12
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 +266 -4
- package/lib/local.js +11 -1
- package/lib/setup.js +33 -0
- package/package.json +2 -2
- package/runtime/codex/.codex/hooks/branch-guard.js +242 -34
- package/runtime/codex/.codex/skills/activity/SKILL.md +18 -6
- package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +90 -55
- package/runtime/codex/.codex/skills/deploy-bridge/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/handoff/SKILL.md +6 -2
- package/runtime/codex/.codex/skills/save/SKILL.md +29 -5
- package/runtime/codex/.codex/skills/scroll/SKILL.md +54 -3
- package/runtime/codex/.codex/skills/task/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/tui-design/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/wrap/SKILL.md +4 -1
- package/runtime/codex/.codex/spec-manifest.json +19 -7
- package/runtime/codex/AGENTS.md +63 -19
- package/runtime/codex/bin/activity-data.sh +1 -1
- package/runtime/codex/bin/agent.sh +88 -25
- package/runtime/codex/bin/attendant.sh +525 -0
- package/runtime/codex/bin/capture-reconcile.sh +67 -0
- package/runtime/codex/bin/capture-run.sh +341 -0
- package/runtime/codex/bin/codex-render-spec.mjs +29 -14
- package/runtime/codex/bin/codex-session-start.sh +49 -4
- package/runtime/codex/bin/codex-skill-render.mjs +23 -4
- package/runtime/codex/bin/graph-op.sh +719 -49
- package/runtime/codex/bin/graph-wal.sh +3 -2
- package/runtime/codex/bin/handoff-run.sh +72 -0
- package/runtime/codex/bin/handoff-save-egregore.sh +51 -11
- package/runtime/codex/bin/index-handoff.sh +26 -17
- package/runtime/codex/bin/ingest-graph.sh +80 -0
- package/runtime/codex/bin/ingest-surface.html +429 -0
- package/runtime/codex/bin/ingest.py +614 -0
- package/runtime/codex/bin/ingest.sh +231 -0
- package/runtime/codex/bin/ingest_graph.py +776 -0
- package/runtime/codex/bin/ingest_surface.py +464 -0
- package/runtime/codex/bin/lib/git-sync.sh +2 -6
- package/runtime/codex/bin/lib/greeting.sh +157 -22
- package/runtime/codex/bin/lib/identity.sh +50 -29
- package/runtime/codex/bin/lib/noncode.sh +31 -0
- package/runtime/codex/bin/person.py +610 -0
- package/runtime/codex/bin/person.sh +448 -0
- package/runtime/codex/bin/session-autosave.sh +184 -0
- package/runtime/codex/bin/session-log.sh +199 -0
- package/runtime/codex/bin/settings.sh +1 -1
- package/runtime/codex/manifest.json +19 -1
- package/runtime/pi/.codex/hooks/branch-guard.js +242 -34
- package/runtime/pi/.codex/skills/activity/SKILL.md +18 -6
- package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +90 -55
- package/runtime/pi/.codex/skills/deploy-bridge/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/handoff/SKILL.md +6 -2
- package/runtime/pi/.codex/skills/save/SKILL.md +29 -5
- package/runtime/pi/.codex/skills/scroll/SKILL.md +54 -3
- package/runtime/pi/.codex/skills/task/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/tui-design/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/wrap/SKILL.md +4 -1
- package/runtime/pi/.codex/spec-manifest.json +19 -7
- package/runtime/pi/.pi/APPEND_SYSTEM.md +57 -14
- package/runtime/pi/.pi/extensions/egregore.ts +98 -8
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +63 -19
- package/runtime/pi/bin/activity-data.sh +1 -1
- package/runtime/pi/bin/agent.sh +88 -25
- package/runtime/pi/bin/attendant.sh +525 -0
- package/runtime/pi/bin/capture-reconcile.sh +67 -0
- package/runtime/pi/bin/capture-run.sh +341 -0
- package/runtime/pi/bin/codex-render-spec.mjs +29 -14
- package/runtime/pi/bin/codex-session-start.sh +49 -4
- package/runtime/pi/bin/codex-skill-render.mjs +23 -4
- package/runtime/pi/bin/graph-op.sh +719 -49
- package/runtime/pi/bin/graph-wal.sh +3 -2
- package/runtime/pi/bin/handoff-run.sh +72 -0
- package/runtime/pi/bin/handoff-save-egregore.sh +51 -11
- package/runtime/pi/bin/index-handoff.sh +26 -17
- package/runtime/pi/bin/ingest-graph.sh +80 -0
- package/runtime/pi/bin/ingest-surface.html +429 -0
- package/runtime/pi/bin/ingest.py +614 -0
- package/runtime/pi/bin/ingest.sh +231 -0
- package/runtime/pi/bin/ingest_graph.py +776 -0
- package/runtime/pi/bin/ingest_surface.py +464 -0
- package/runtime/pi/bin/lib/git-sync.sh +2 -6
- package/runtime/pi/bin/lib/greeting.sh +157 -22
- package/runtime/pi/bin/lib/identity.sh +50 -29
- package/runtime/pi/bin/lib/noncode.sh +31 -0
- package/runtime/pi/bin/person.py +610 -0
- package/runtime/pi/bin/person.sh +448 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +164 -4
- package/runtime/pi/bin/pi-product-workflows.mjs +31 -2
- package/runtime/pi/bin/publish-artifact.sh +14 -0
- package/runtime/pi/bin/session-autosave.sh +184 -0
- package/runtime/pi/bin/session-log.sh +199 -0
- package/runtime/pi/bin/settings.sh +274 -0
- package/runtime/pi/manifest.json +20 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// egregore-launcher-version: 0.
|
|
2
|
+
// egregore-launcher-version: 0.8.0
|
|
3
3
|
//
|
|
4
4
|
// egregore — launch and browse Egregore instances from your terminal.
|
|
5
5
|
// Installed by create-egregore. Reads ~/.egregore/instances.json.
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// egregore <slug|name> pick a harness for the matching instance
|
|
14
14
|
// egregore ls | list list instances (non-interactive table)
|
|
15
15
|
// egregore use <slug> set the default for bare `egregore`
|
|
16
|
+
// egregore connect [slug] activate Connected for an existing instance
|
|
16
17
|
// egregore /invite <user> invite a GitHub user to an instance
|
|
17
18
|
// egregore settings [slug] hosting on/off, managed repos, admins (s in browser)
|
|
18
19
|
// egregore prune [--dry-run] remove entries whose path is gone
|
|
@@ -28,13 +29,18 @@ const path = require("node:path");
|
|
|
28
29
|
const os = require("node:os");
|
|
29
30
|
const http = require("node:http");
|
|
30
31
|
const https = require("node:https");
|
|
32
|
+
const crypto = require("node:crypto");
|
|
31
33
|
const { spawnSync, spawn } = require("node:child_process");
|
|
32
34
|
const readline = require("node:readline");
|
|
33
35
|
|
|
34
|
-
const VERSION = "0.
|
|
36
|
+
const VERSION = "0.8.0";
|
|
35
37
|
const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
|
|
36
38
|
const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
|
|
37
39
|
const PUBLIC_NPX_PACKAGE = "create-egregore";
|
|
40
|
+
const CONNECT_API_URL = (
|
|
41
|
+
process.env.EGREGORE_CONNECT_API_URL ||
|
|
42
|
+
"https://egregore-production-55f2.up.railway.app"
|
|
43
|
+
).replace(/\/+$/, "");
|
|
38
44
|
|
|
39
45
|
const NATIVE_CODEX_SKILLS = [
|
|
40
46
|
"activity",
|
|
@@ -864,6 +870,7 @@ function cmdHelp() {
|
|
|
864
870
|
` ${CYAN}egregore browse${RESET} force the full-screen browser`,
|
|
865
871
|
` ${CYAN}egregore ls${RESET} ${DIM}| list${RESET} list installed instances`,
|
|
866
872
|
` ${CYAN}egregore use${RESET} ${DIM}<slug>${RESET} set the default for bare ${BOLD}egregore${RESET}`,
|
|
873
|
+
` ${CYAN}egregore connect${RESET} ${DIM}[slug]${RESET} activate Connected for an existing instance`,
|
|
867
874
|
` ${CYAN}egregore /invite${RESET} ${DIM}<user> [slug]${RESET} invite a GitHub user`,
|
|
868
875
|
` ${CYAN}egregore settings${RESET} ${DIM}[slug]${RESET} hosting on/off, repos, admins`,
|
|
869
876
|
` ${CYAN}egregore prune${RESET} ${DIM}[--dry-run]${RESET} remove entries with missing paths`,
|
|
@@ -874,6 +881,7 @@ function cmdHelp() {
|
|
|
874
881
|
` ${DIM}enter${RESET} choose selected instance`,
|
|
875
882
|
` ${DIM}/${RESET} filter (type to narrow; esc to clear)`,
|
|
876
883
|
` ${DIM}n / +${RESET} create a new Egregore`,
|
|
884
|
+
` ${DIM}c${RESET} connect selected instance`,
|
|
877
885
|
` ${DIM}u${RESET} set selected as default`,
|
|
878
886
|
` ${DIM}i${RESET} invite a GitHub user to selected instance`,
|
|
879
887
|
` ${DIM}s${RESET} settings (hosting on/off, repos, admins)`,
|
|
@@ -994,6 +1002,252 @@ function apiRequest(apiUrl, apiKey, apiPath, body) {
|
|
|
994
1002
|
}, body);
|
|
995
1003
|
}
|
|
996
1004
|
|
|
1005
|
+
function connectedApiRequest(githubToken, method, apiPath, body, headers = {}) {
|
|
1006
|
+
const url = new URL(apiPath, CONNECT_API_URL + "/");
|
|
1007
|
+
return requestJson({
|
|
1008
|
+
hostname: url.hostname,
|
|
1009
|
+
port: url.port || undefined,
|
|
1010
|
+
path: `${url.pathname}${url.search}`,
|
|
1011
|
+
method,
|
|
1012
|
+
protocol: url.protocol,
|
|
1013
|
+
headers: {
|
|
1014
|
+
Authorization: `Bearer ${githubToken}`,
|
|
1015
|
+
...headers,
|
|
1016
|
+
},
|
|
1017
|
+
}, body);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
function openExternalUrl(url) {
|
|
1021
|
+
try {
|
|
1022
|
+
if (process.platform === "darwin") {
|
|
1023
|
+
spawn("open", [url], { detached: true, stdio: "ignore" }).unref();
|
|
1024
|
+
} else if (process.platform === "win32") {
|
|
1025
|
+
spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
|
|
1026
|
+
} else {
|
|
1027
|
+
spawn("xdg-open", [url], { detached: true, stdio: "ignore" }).unref();
|
|
1028
|
+
}
|
|
1029
|
+
return true;
|
|
1030
|
+
} catch {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
function atomicWrite(file, content, mode) {
|
|
1036
|
+
const temp = path.join(
|
|
1037
|
+
path.dirname(file),
|
|
1038
|
+
`.${path.basename(file)}.${process.pid}.${crypto.randomBytes(4).toString("hex")}.tmp`,
|
|
1039
|
+
);
|
|
1040
|
+
fs.writeFileSync(temp, content, { mode });
|
|
1041
|
+
fs.renameSync(temp, file);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
function writeJsonFileAtomic(file, value) {
|
|
1045
|
+
atomicWrite(file, JSON.stringify(value, null, 2) + "\n", 0o644);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
function writeEnvValueAtomic(file, key, value) {
|
|
1049
|
+
const lines = fs.existsSync(file)
|
|
1050
|
+
? fs.readFileSync(file, "utf-8").split(/\r?\n/)
|
|
1051
|
+
: [];
|
|
1052
|
+
let replaced = false;
|
|
1053
|
+
const next = lines
|
|
1054
|
+
.filter((line, index) => !(index === lines.length - 1 && line === ""))
|
|
1055
|
+
.map((line) => {
|
|
1056
|
+
if (!line.startsWith(`${key}=`)) return line;
|
|
1057
|
+
replaced = true;
|
|
1058
|
+
return `${key}=${value}`;
|
|
1059
|
+
});
|
|
1060
|
+
if (!replaced) next.push(`${key}=${value}`);
|
|
1061
|
+
atomicWrite(file, next.join("\n") + "\n", 0o600);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
function persistConnectState(inst, fields) {
|
|
1065
|
+
const file = path.join(inst.path, ".egregore-state.json");
|
|
1066
|
+
const state = readJsonFile(file);
|
|
1067
|
+
state.connected_activation = {
|
|
1068
|
+
...(state.connected_activation || {}),
|
|
1069
|
+
...fields,
|
|
1070
|
+
updated_at: new Date().toISOString(),
|
|
1071
|
+
};
|
|
1072
|
+
writeJsonFileAtomic(file, state);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
function connectError(result, fallback) {
|
|
1076
|
+
if (!result) return fallback;
|
|
1077
|
+
const data = result.data || {};
|
|
1078
|
+
return data.detail || data.message || (typeof data === "string" ? data : fallback);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
function sleep(ms) {
|
|
1082
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
async function cmdConnect(args) {
|
|
1086
|
+
const registry = readRegistry();
|
|
1087
|
+
if (registry.length === 0) die("no egregores installed yet.\n run: npx -y create-egregore@latest");
|
|
1088
|
+
const inst = resolveInviteInstance(registry, args[0] || "");
|
|
1089
|
+
if (!inst) {
|
|
1090
|
+
die("multiple egregores installed; choose one:\n egregore connect <slug>\n run: egregore ls");
|
|
1091
|
+
}
|
|
1092
|
+
if (!fs.existsSync(inst.path)) die(`instance path is missing: ${inst.path}`);
|
|
1093
|
+
|
|
1094
|
+
const { cfg, state, env } = configForInstance(inst);
|
|
1095
|
+
const githubToken = env.GITHUB_TOKEN || "";
|
|
1096
|
+
if (!githubToken) {
|
|
1097
|
+
die(`GITHUB_TOKEN is missing for ${inst.slug}.\n Add it to ${path.join(inst.path, ".env")} and retry.`);
|
|
1098
|
+
}
|
|
1099
|
+
const activation = state.connected_activation || {};
|
|
1100
|
+
if (cfg.mode === "connected" && activation.status === "connected") {
|
|
1101
|
+
console.log(`\n ${GREEN}✓${RESET} ${BOLD}${inst.slug}${RESET} is already connected.\n`);
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
console.log("");
|
|
1106
|
+
console.log(` ${BOLD}CONNECT${RESET} ${DIM}${inst.slug}${RESET}`);
|
|
1107
|
+
console.log(` ${DIM}€500/month · Stripe checkout · existing Markdown and Git stay in place${RESET}`);
|
|
1108
|
+
console.log("");
|
|
1109
|
+
|
|
1110
|
+
let intentId = activation.intent_id || "";
|
|
1111
|
+
let connectUrl = activation.connect_url || "";
|
|
1112
|
+
if (!intentId || !["checkout_pending", "entitled", "backfilling"].includes(activation.status)) {
|
|
1113
|
+
console.log(` [1/5] ${DIM}Creating connection intent…${RESET}`);
|
|
1114
|
+
const checkout = await connectedApiRequest(
|
|
1115
|
+
githubToken,
|
|
1116
|
+
"POST",
|
|
1117
|
+
"/api/billing/checkout",
|
|
1118
|
+
{
|
|
1119
|
+
org_slug: cfg.slug || inst.slug,
|
|
1120
|
+
plan: "connect",
|
|
1121
|
+
instance_metadata: {
|
|
1122
|
+
launcher_version: VERSION,
|
|
1123
|
+
mode: cfg.mode || "local",
|
|
1124
|
+
repo_name: cfg.repo_name || "",
|
|
1125
|
+
managed_repo_count: Array.isArray(cfg.repos) ? cfg.repos.length : 0,
|
|
1126
|
+
},
|
|
1127
|
+
},
|
|
1128
|
+
{ "X-Idempotency-Key": `cli:${inst.slug}:${crypto.randomUUID()}` },
|
|
1129
|
+
);
|
|
1130
|
+
if (checkout.status !== 200) {
|
|
1131
|
+
die(`could not start Connected checkout: ${connectError(checkout, `HTTP ${checkout.status}`)}`);
|
|
1132
|
+
}
|
|
1133
|
+
intentId = checkout.data.connection_intent_id;
|
|
1134
|
+
connectUrl = checkout.data.connect_url;
|
|
1135
|
+
persistConnectState(inst, {
|
|
1136
|
+
intent_id: intentId,
|
|
1137
|
+
checkout_session_id: checkout.data.checkout_session_id,
|
|
1138
|
+
connect_url: connectUrl,
|
|
1139
|
+
status: "checkout_pending",
|
|
1140
|
+
});
|
|
1141
|
+
console.log(` [1/5] ${GREEN}✓${RESET} Connection intent`);
|
|
1142
|
+
} else {
|
|
1143
|
+
console.log(` [1/5] ${GREEN}✓${RESET} Resuming connection intent`);
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
if (activation.status !== "backfilling") {
|
|
1147
|
+
if (connectUrl) {
|
|
1148
|
+
const opened = openExternalUrl(connectUrl);
|
|
1149
|
+
const mark = opened ? `${GREEN}✓${RESET}` : `${YELLOW}!${RESET}`;
|
|
1150
|
+
console.log(` [2/5] ${mark} ${opened ? "Opened" : "Open"} Egregore Connect`);
|
|
1151
|
+
console.log(` ${CYAN}${connectUrl}${RESET}`);
|
|
1152
|
+
}
|
|
1153
|
+
console.log(` ${DIM}Complete checkout in the browser. Promotion codes are entered in Stripe.${RESET}`);
|
|
1154
|
+
} else {
|
|
1155
|
+
console.log(` [2/5] ${GREEN}✓${RESET} Subscription already confirmed`);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
const pollMs = Math.max(100, Number(process.env.EGREGORE_CONNECT_POLL_INTERVAL_MS || 2000));
|
|
1159
|
+
const timeoutMs = Math.max(pollMs, Number(process.env.EGREGORE_CONNECT_TIMEOUT_MS || 30 * 60 * 1000));
|
|
1160
|
+
const deadline = Date.now() + timeoutMs;
|
|
1161
|
+
let status;
|
|
1162
|
+
while (Date.now() < deadline) {
|
|
1163
|
+
const result = await connectedApiRequest(
|
|
1164
|
+
githubToken,
|
|
1165
|
+
"GET",
|
|
1166
|
+
`/api/billing/connect/${encodeURIComponent(intentId)}`,
|
|
1167
|
+
);
|
|
1168
|
+
if (result.status === 200) {
|
|
1169
|
+
status = result.data;
|
|
1170
|
+
if (
|
|
1171
|
+
status.entitled ||
|
|
1172
|
+
["entitled", "provisioning", "backfilling", "connected"].includes(status.status)
|
|
1173
|
+
) break;
|
|
1174
|
+
if (["canceled", "failed"].includes(status.status)) {
|
|
1175
|
+
persistConnectState(inst, { status: status.status });
|
|
1176
|
+
die(`Connected checkout ${status.status}. Your local Egregore was not changed.`);
|
|
1177
|
+
}
|
|
1178
|
+
} else if (result.status !== 0) {
|
|
1179
|
+
die(`could not read Connected status: ${connectError(result, `HTTP ${result.status}`)}`);
|
|
1180
|
+
}
|
|
1181
|
+
await sleep(pollMs);
|
|
1182
|
+
}
|
|
1183
|
+
if (!status || !(status.entitled || ["entitled", "provisioning", "backfilling", "connected"].includes(status.status))) {
|
|
1184
|
+
die("timed out waiting for checkout. Run the same command to resume.");
|
|
1185
|
+
}
|
|
1186
|
+
console.log(` [3/5] ${GREEN}✓${RESET} Subscription confirmed`);
|
|
1187
|
+
persistConnectState(inst, { status: "entitled" });
|
|
1188
|
+
|
|
1189
|
+
const claim = await connectedApiRequest(
|
|
1190
|
+
githubToken,
|
|
1191
|
+
"POST",
|
|
1192
|
+
`/api/billing/connect/${encodeURIComponent(intentId)}/claim`,
|
|
1193
|
+
{},
|
|
1194
|
+
);
|
|
1195
|
+
if (claim.status !== 200) {
|
|
1196
|
+
die(`could not activate Connected infrastructure: ${connectError(claim, `HTTP ${claim.status}`)}`);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
const configFile = path.join(inst.path, "egregore.json");
|
|
1200
|
+
const envFile = path.join(inst.path, ".env");
|
|
1201
|
+
const currentConfig = readJsonFile(configFile);
|
|
1202
|
+
writeJsonFileAtomic(configFile, {
|
|
1203
|
+
...currentConfig,
|
|
1204
|
+
mode: "connected",
|
|
1205
|
+
api_url: claim.data.api_url,
|
|
1206
|
+
});
|
|
1207
|
+
writeEnvValueAtomic(envFile, "EGREGORE_API_KEY", claim.data.api_key);
|
|
1208
|
+
persistConnectState(inst, {
|
|
1209
|
+
status: "backfilling",
|
|
1210
|
+
activation_protocol: claim.data.activation_protocol,
|
|
1211
|
+
});
|
|
1212
|
+
console.log(` [4/5] ${GREEN}✓${RESET} Connected credential and graph node`);
|
|
1213
|
+
|
|
1214
|
+
const syncScript = path.join(inst.path, "bin", "sync-graph.sh");
|
|
1215
|
+
if (!fs.existsSync(syncScript)) {
|
|
1216
|
+
die("bin/sync-graph.sh is missing. Update the installed Egregore version, then run egregore connect again.");
|
|
1217
|
+
}
|
|
1218
|
+
const sync = spawnSync("bash", [syncScript], {
|
|
1219
|
+
cwd: inst.path,
|
|
1220
|
+
encoding: "utf-8",
|
|
1221
|
+
stdio: "pipe",
|
|
1222
|
+
timeout: 10 * 60 * 1000,
|
|
1223
|
+
});
|
|
1224
|
+
if (sync.status !== 0) {
|
|
1225
|
+
const detail = (sync.stderr || sync.stdout || "graph replay failed").trim();
|
|
1226
|
+
die(`Connected is configured, but graph replay did not finish.\n ${detail}\n Run egregore connect ${inst.slug} to retry; existing data is unchanged.`);
|
|
1227
|
+
}
|
|
1228
|
+
let backfillSummary = { replayed: true };
|
|
1229
|
+
try { backfillSummary = JSON.parse((sync.stdout || "").trim()); } catch {}
|
|
1230
|
+
|
|
1231
|
+
const complete = await connectedApiRequest(
|
|
1232
|
+
githubToken,
|
|
1233
|
+
"POST",
|
|
1234
|
+
`/api/billing/connect/${encodeURIComponent(intentId)}/complete`,
|
|
1235
|
+
{ backfill_summary: backfillSummary },
|
|
1236
|
+
);
|
|
1237
|
+
if (complete.status !== 200) {
|
|
1238
|
+
die(`graph replay finished, but activation could not be finalized: ${connectError(complete, `HTTP ${complete.status}`)}`);
|
|
1239
|
+
}
|
|
1240
|
+
persistConnectState(inst, {
|
|
1241
|
+
status: "connected",
|
|
1242
|
+
connected_at: new Date().toISOString(),
|
|
1243
|
+
backfill_summary: backfillSummary,
|
|
1244
|
+
});
|
|
1245
|
+
console.log(` [5/5] ${GREEN}✓${RESET} Existing memory projected into the graph`);
|
|
1246
|
+
console.log("");
|
|
1247
|
+
console.log(` ${GREEN}✓${RESET} ${BOLD}${inst.slug}${RESET} is connected. Local files remain the source of truth.`);
|
|
1248
|
+
console.log("");
|
|
1249
|
+
}
|
|
1250
|
+
|
|
997
1251
|
function accessLabel(status) {
|
|
998
1252
|
if (status === 201) return `${GREEN}sent${RESET}`;
|
|
999
1253
|
if (status === 204) return `${GREEN}already added${RESET}`;
|
|
@@ -1952,8 +2206,8 @@ async function browser(args = {}) {
|
|
|
1952
2206
|
footer = band(`● ${stripAnsi(state.message)}`, bg);
|
|
1953
2207
|
} else {
|
|
1954
2208
|
footer = blockWidth < 96
|
|
1955
|
-
? band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("
|
|
1956
|
-
: band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("/", "filter")} ${key("i", "invite")} ${key("s", "settings")} ${key("u", "default")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46);
|
|
2209
|
+
? band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("c", "connect")} ${key("i", "invite")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46)
|
|
2210
|
+
: band(`${key("↑↓", "nav")} ${key("enter", "select")} ${key("n/+", "new")} ${key("/", "filter")} ${key("c", "connect")} ${key("i", "invite")} ${key("s", "settings")} ${key("u", "default")} ${key("d", "delete")} ${key("?", "help")} ${key("q", "quit")}`, 46);
|
|
1957
2211
|
}
|
|
1958
2212
|
out.push(M + footer + "\n");
|
|
1959
2213
|
if (state.showHelp) {
|
|
@@ -2310,6 +2564,13 @@ async function browser(args = {}) {
|
|
|
2310
2564
|
resolve(setupNewEgregore(args.runtimeOverride));
|
|
2311
2565
|
return;
|
|
2312
2566
|
}
|
|
2567
|
+
if (chunk === "c") {
|
|
2568
|
+
const pick = visible()[state.cursor]?.e;
|
|
2569
|
+
if (!pick) return;
|
|
2570
|
+
cleanup();
|
|
2571
|
+
resolve(cmdConnect([pick.slug]));
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2313
2574
|
if (chunk === "i") {
|
|
2314
2575
|
const pick = visible()[state.cursor]?.e;
|
|
2315
2576
|
if (!pick) return;
|
|
@@ -2451,6 +2712,7 @@ function main() {
|
|
|
2451
2712
|
// Non-interactive subcommands
|
|
2452
2713
|
if (cmd === "ls" || cmd === "list") return cmdLs();
|
|
2453
2714
|
if (cmd === "use") return cmdUse(args[1]);
|
|
2715
|
+
if (cmd === "connect") return cmdConnect(args.slice(1));
|
|
2454
2716
|
if (cmd === "/invite" || cmd === "invite") return cmdInvite(args.slice(1));
|
|
2455
2717
|
if (cmd === "settings" || cmd === "config") return cmdSettings(args.slice(1));
|
|
2456
2718
|
if (cmd === "prune") return cmdPruneNonInteractive(args[1] === "--dry-run" || args[1] === "-n");
|
package/lib/local.js
CHANGED
|
@@ -47,7 +47,12 @@ const TEMPLATE_REPO = "egregore";
|
|
|
47
47
|
async function getUser(token) {
|
|
48
48
|
const { status, data } = await ghApi("GET", "/user", token);
|
|
49
49
|
if (status !== 200) throw new Error("GitHub auth failed — could not fetch user");
|
|
50
|
-
return {
|
|
50
|
+
return {
|
|
51
|
+
login: data.login,
|
|
52
|
+
id: data.id || null,
|
|
53
|
+
name: data.name || data.login,
|
|
54
|
+
email: data.email || null,
|
|
55
|
+
};
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
async function listOrgs(token) {
|
|
@@ -1286,11 +1291,14 @@ async function localFounderFlow(ui, ctx = {}) {
|
|
|
1286
1291
|
const slugifiedName = (displayName || user.login).toLowerCase().replace(/\s+/g, "-");
|
|
1287
1292
|
const state = {
|
|
1288
1293
|
github_username: user.login,
|
|
1294
|
+
github_id: user.id,
|
|
1295
|
+
person_id: user.id ? `github:${user.id}` : `github-login:${user.login.toLowerCase()}`,
|
|
1289
1296
|
github_name: user.name,
|
|
1290
1297
|
display_name: displayName || user.login,
|
|
1291
1298
|
name: slugifiedName,
|
|
1292
1299
|
member_role: memberRole,
|
|
1293
1300
|
email: user.email,
|
|
1301
|
+
emails: user.email ? [user.email.toLowerCase()] : [],
|
|
1294
1302
|
onboarding_complete: false,
|
|
1295
1303
|
usage_type: "founder_group",
|
|
1296
1304
|
org_setup: true,
|
|
@@ -1430,6 +1438,7 @@ async function localFounderFlow(ui, ctx = {}) {
|
|
|
1430
1438
|
const invPersonContent = [
|
|
1431
1439
|
"---",
|
|
1432
1440
|
`name: ${invUsername}`,
|
|
1441
|
+
`person_id: github-login:${invUsername.toLowerCase()}`,
|
|
1433
1442
|
`github: ${invUsername}`,
|
|
1434
1443
|
`invited_by: ${user.login}`,
|
|
1435
1444
|
`joined: ${today}`,
|
|
@@ -1755,6 +1764,7 @@ async function localJoinFlow(orgArg, ui, ctx = {}) {
|
|
|
1755
1764
|
org_name: orgName,
|
|
1756
1765
|
github_org: orgLogin,
|
|
1757
1766
|
github_username: user.login,
|
|
1767
|
+
github_id: user.id,
|
|
1758
1768
|
github_name: user.name,
|
|
1759
1769
|
github_email: user.email,
|
|
1760
1770
|
slug: config.slug || orgLogin,
|
package/lib/setup.js
CHANGED
|
@@ -174,12 +174,24 @@ function mergeProfileFields(existing, additions = []) {
|
|
|
174
174
|
function personProfileContent(state = {}, opts = {}) {
|
|
175
175
|
const now = opts.onboardedAt || new Date().toISOString();
|
|
176
176
|
const username = state.github_username || opts.githubUsername || "unknown";
|
|
177
|
+
const githubId = state.github_id || opts.githubId || "";
|
|
178
|
+
const personId = state.person_id || (githubId ? `github:${githubId}` : `github-login:${username.toLowerCase()}`);
|
|
177
179
|
const displayName = state.display_name || state.github_name || username;
|
|
178
180
|
const role = state.member_role || state.onboarding?.member_role || opts.memberRole || "Member";
|
|
181
|
+
const emails = [...new Set(
|
|
182
|
+
[state.email, ...(Array.isArray(state.emails) ? state.emails : [])]
|
|
183
|
+
.filter(Boolean)
|
|
184
|
+
.map((value) => String(value).trim().toLowerCase()),
|
|
185
|
+
)];
|
|
179
186
|
return [
|
|
180
187
|
`# ${displayName}`,
|
|
181
188
|
"",
|
|
189
|
+
`Person-ID: ${personId}`,
|
|
182
190
|
`GitHub: ${username}`,
|
|
191
|
+
`GitHub-ID: ${githubId}`,
|
|
192
|
+
"GitHub-Aliases: ",
|
|
193
|
+
`Email: ${emails[0] || ""}`,
|
|
194
|
+
`Emails: ${emails.join(", ")}`,
|
|
183
195
|
`Role: ${role}`,
|
|
184
196
|
`Joined: ${now.split("T")[0]}`,
|
|
185
197
|
`Onboarded: ${now}`,
|
|
@@ -234,6 +246,7 @@ function buildOnboardingState(existing = {}, data = {}, opts = {}) {
|
|
|
234
246
|
const state = { ...existing };
|
|
235
247
|
const preferredRuntime = normalizeRuntime(opts.runtime);
|
|
236
248
|
const githubUsername = data.github_username || state.github_username || "";
|
|
249
|
+
const githubId = data.github_id || state.github_id || null;
|
|
237
250
|
const githubName = data.github_name || state.github_name || githubUsername;
|
|
238
251
|
const displayName = data.display_name || state.display_name || githubName || githubUsername;
|
|
239
252
|
const usageType = normalizeUsageType(data);
|
|
@@ -248,6 +261,12 @@ function buildOnboardingState(existing = {}, data = {}, opts = {}) {
|
|
|
248
261
|
const shouldComplete = alreadyComplete || (requestedComplete && !!memberRole);
|
|
249
262
|
|
|
250
263
|
if (githubUsername) state.github_username = githubUsername;
|
|
264
|
+
if (githubId) {
|
|
265
|
+
state.github_id = githubId;
|
|
266
|
+
state.person_id = `github:${githubId}`;
|
|
267
|
+
} else if (githubUsername && !state.person_id) {
|
|
268
|
+
state.person_id = `github-login:${githubUsername.toLowerCase()}`;
|
|
269
|
+
}
|
|
251
270
|
if (githubName) state.github_name = githubName;
|
|
252
271
|
if (displayName) {
|
|
253
272
|
state.display_name = displayName;
|
|
@@ -457,6 +476,20 @@ async function install(data, ui, targetDir, opts = {}) {
|
|
|
457
476
|
reportPiRuntimeSummary(piRuntime, ui);
|
|
458
477
|
}
|
|
459
478
|
|
|
479
|
+
// Reconcile the installer-captured identity through the same portable writer
|
|
480
|
+
// used by /me and onboarding. Failure is recoverable: the state + person
|
|
481
|
+
// profile already exist and the next session retries `bin/person.sh sync`.
|
|
482
|
+
const personScript = path.join(egregoreDir, "bin", "person.sh");
|
|
483
|
+
if (fs.existsSync(personScript)) {
|
|
484
|
+
try {
|
|
485
|
+
spawnSync("bash", [personScript, "onboard"], {
|
|
486
|
+
cwd: egregoreDir,
|
|
487
|
+
stdio: "ignore",
|
|
488
|
+
timeout: 15000,
|
|
489
|
+
});
|
|
490
|
+
} catch {}
|
|
491
|
+
}
|
|
492
|
+
|
|
460
493
|
// 5. Register instance + install launcher binary
|
|
461
494
|
ui.step(5, totalSteps, "Registering instance...");
|
|
462
495
|
registerInstance(forkDirName, org_name, egregoreDir, preferredRuntime);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-egregore",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.12",
|
|
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": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build:runtime": "node scripts/build-runtime-bundle.mjs && node scripts/build-pi-runtime-bundle.mjs",
|
|
14
14
|
"build:pi-runtime": "node scripts/build-pi-runtime-bundle.mjs",
|
|
15
|
-
"test": "node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node --test test/context.test.js test/parse-join-target.test.js test/skip-repos.test.js test/onboarding-shortcircuit.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/codex-runtime.test.js test/pi-runtime.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",
|
|
15
|
+
"test": "node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node --test test/context.test.js test/parse-join-target.test.js test/skip-repos.test.js test/onboarding-shortcircuit.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/codex-runtime.test.js test/pi-runtime.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",
|
|
16
16
|
"test:e2e": "node --test test/e2e-local.test.js",
|
|
17
17
|
"test:all": "node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node --test test/"
|
|
18
18
|
},
|