create-egregore 0.20.1 → 0.21.0-runtime-mvp.1

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 (715) hide show
  1. package/assets/egregore-launcher.js +1059 -21
  2. package/bin/cli.js +11 -0
  3. package/lib/claude-runtime.js +192 -0
  4. package/lib/local.js +42 -51
  5. package/lib/pi-runtime.js +1 -0
  6. package/lib/prime-runtime.js +1 -0
  7. package/lib/runtime-identity.js +146 -0
  8. package/lib/setup.js +116 -19
  9. package/package.json +10 -6
  10. package/runtime/claude/.claude/context/commit-format.md +110 -0
  11. package/runtime/claude/.claude/context/git-language.md +46 -0
  12. package/runtime/claude/.claude/context/notification-consent.md +66 -0
  13. package/runtime/claude/.claude/context/pr-format.md +67 -0
  14. package/runtime/claude/.claude/context/telemetry.md +133 -0
  15. package/runtime/claude/.claude/hooks/boundary-check.sh +333 -0
  16. package/runtime/claude/.claude/hooks/branch-guard.sh +231 -0
  17. package/runtime/claude/.claude/hooks/card-context.sh +38 -0
  18. package/runtime/claude/.claude/hooks/emissary-detect.sh +53 -0
  19. package/runtime/claude/.claude/hooks/memory-refresh.sh +67 -0
  20. package/runtime/claude/.claude/hooks/onboarding-guard.sh +86 -0
  21. package/runtime/claude/.claude/hooks/retrieval-context.sh +43 -0
  22. package/runtime/claude/.claude/rules/voice-bedrock.md +73 -0
  23. package/runtime/claude/.claude/settings.json +131 -0
  24. package/runtime/claude/.claude/skills/activity/SKILL.md +68 -0
  25. package/runtime/claude/.claude/skills/announce/SKILL.md +54 -0
  26. package/runtime/claude/.claude/skills/archive/SKILL.md +71 -0
  27. package/runtime/claude/.claude/skills/branch/SKILL.md +147 -0
  28. package/runtime/claude/.claude/skills/checkup/SKILL.md +159 -0
  29. package/runtime/claude/.claude/skills/commit/SKILL.md +103 -0
  30. package/runtime/claude/.claude/skills/contribute/SKILL.md +343 -0
  31. package/runtime/claude/.claude/skills/create-skill/SKILL.md +135 -0
  32. package/runtime/claude/.claude/skills/dark-mode/SKILL.md +410 -0
  33. package/runtime/claude/.claude/skills/dashboard/SKILL.md +43 -0
  34. package/runtime/claude/.claude/skills/deep-reflect/REPORT.md +140 -0
  35. package/runtime/claude/.claude/skills/deep-reflect/RESEARCH.md +132 -0
  36. package/runtime/claude/.claude/skills/deep-reflect/ROLES.md +104 -0
  37. package/runtime/claude/.claude/skills/deep-reflect/SKILL.md +170 -0
  38. package/runtime/claude/.claude/skills/delete-user/SKILL.md +150 -0
  39. package/runtime/claude/.claude/skills/emissary/SKILL.md +220 -0
  40. package/runtime/claude/.claude/skills/handoff/SKILL.md +124 -0
  41. package/runtime/claude/.claude/skills/harvest/AUDIT.md +546 -0
  42. package/runtime/claude/.claude/skills/harvest/FORMAT.md +436 -0
  43. package/runtime/claude/.claude/skills/harvest/PROCESS.md +395 -0
  44. package/runtime/claude/.claude/skills/harvest/QUESTION_PALETTE.md +76 -0
  45. package/runtime/claude/.claude/skills/harvest/SKILL.md +100 -0
  46. package/runtime/claude/.claude/skills/ingest/SKILL.md +112 -0
  47. package/runtime/claude/.claude/skills/ingest-corpus/SKILL.md +187 -0
  48. package/runtime/claude/.claude/skills/ingest-notion/SKILL.md +214 -0
  49. package/runtime/claude/.claude/skills/ingest-user-interview/SKILL.md +65 -0
  50. package/runtime/claude/.claude/skills/ingest-user-interview/references/analysis-contract.md +125 -0
  51. package/runtime/claude/.claude/skills/invite/SKILL.md +111 -0
  52. package/runtime/claude/.claude/skills/issue/SKILL.md +104 -0
  53. package/runtime/claude/.claude/skills/me/SKILL.md +81 -0
  54. package/runtime/claude/.claude/skills/meeting/SKILL.md +76 -0
  55. package/runtime/claude/.claude/skills/meeting/references/analysis-contract.md +102 -0
  56. package/runtime/claude/.claude/skills/note/SKILL.md +71 -0
  57. package/runtime/claude/.claude/skills/notion-connect/SKILL.md +124 -0
  58. package/runtime/claude/.claude/skills/onboarding/SKILL.md +159 -0
  59. package/runtime/claude/.claude/skills/pr/SKILL.md +85 -0
  60. package/runtime/claude/.claude/skills/pull/SKILL.md +79 -0
  61. package/runtime/claude/.claude/skills/push/SKILL.md +47 -0
  62. package/runtime/claude/.claude/skills/quest/SKILL.md +121 -0
  63. package/runtime/claude/.claude/skills/reflect/SKILL.md +69 -0
  64. package/runtime/claude/.claude/skills/review-pr/SKILL.md +276 -0
  65. package/runtime/claude/.claude/skills/save/SKILL.md +92 -0
  66. package/runtime/claude/.claude/skills/slack-connect/SKILL.md +148 -0
  67. package/runtime/claude/.claude/skills/summon/SKILL.md +240 -0
  68. package/runtime/claude/.claude/skills/sync-repos/SKILL.md +82 -0
  69. package/runtime/claude/.claude/skills/teams-connect/SKILL.md +216 -0
  70. package/runtime/claude/.claude/skills/telegram-connect/SKILL.md +110 -0
  71. package/runtime/claude/.claude/skills/telemetry/SKILL.md +117 -0
  72. package/runtime/claude/.claude/skills/test/SKILL.md +87 -0
  73. package/runtime/claude/.claude/skills/the-spiral/SKILL.md +492 -0
  74. package/runtime/claude/.claude/skills/tui-design/SKILL.md +188 -0
  75. package/runtime/claude/.claude/skills/tutorial/SKILL.md +100 -0
  76. package/runtime/claude/.claude/skills/update/SKILL.md +265 -0
  77. package/runtime/claude/.claude/skills/view/SKILL.md +393 -0
  78. package/runtime/claude/.claude/skills/view/compose-scaffold.html +221 -0
  79. package/runtime/claude/.claude/skills/visual-explain/SKILL.md +132 -0
  80. package/runtime/claude/.claude/skills/wrap/SKILL.md +98 -0
  81. package/runtime/claude/CLAUDE.md +447 -0
  82. package/runtime/claude/bin/activity-action.sh +92 -0
  83. package/runtime/claude/bin/activity-data.sh +17 -0
  84. package/runtime/claude/bin/agent.sh +783 -0
  85. package/runtime/claude/bin/artifact-register.sh +164 -0
  86. package/runtime/claude/bin/artifact-writeback.sh +53 -0
  87. package/runtime/claude/bin/artifacts.sh +288 -0
  88. package/runtime/claude/bin/attendant.sh +707 -0
  89. package/runtime/claude/bin/autosave.sh +112 -0
  90. package/runtime/claude/bin/boundary.sh +253 -0
  91. package/runtime/claude/bin/build-sealed-dataroom.mjs +722 -0
  92. package/runtime/claude/bin/capture-reconcile.sh +69 -0
  93. package/runtime/claude/bin/capture-run.sh +357 -0
  94. package/runtime/claude/bin/codex-install-skills.sh +78 -0
  95. package/runtime/claude/bin/codex-render-spec.mjs +462 -0
  96. package/runtime/claude/bin/codex-session-start.sh +275 -0
  97. package/runtime/claude/bin/codex-skill-render.mjs +349 -0
  98. package/runtime/claude/bin/codex-sync-skills.sh +237 -0
  99. package/runtime/claude/bin/connect-refresh.sh +33 -0
  100. package/runtime/claude/bin/contribute-guard.sh +79 -0
  101. package/runtime/claude/bin/corpus_map.py +806 -0
  102. package/runtime/claude/bin/corpus_survey.py +304 -0
  103. package/runtime/claude/bin/dashboard-data.sh +18 -0
  104. package/runtime/claude/bin/github-auth.sh +121 -0
  105. package/runtime/claude/bin/graph-batch.sh +86 -0
  106. package/runtime/claude/bin/graph-op.sh +1106 -0
  107. package/runtime/claude/bin/graph-projection.sh +54 -0
  108. package/runtime/claude/bin/graph-wal.sh +242 -0
  109. package/runtime/claude/bin/graph.sh +267 -0
  110. package/runtime/claude/bin/handoff-lifecycle-job.sh +146 -0
  111. package/runtime/claude/bin/handoff-lifecycle.sh +280 -0
  112. package/runtime/claude/bin/handoff-pr-backfill.sh +86 -0
  113. package/runtime/claude/bin/handoff-preview.sh +169 -0
  114. package/runtime/claude/bin/handoff-run.sh +692 -0
  115. package/runtime/claude/bin/handoff-save-egregore.sh +224 -0
  116. package/runtime/claude/bin/index-handoff.sh +322 -0
  117. package/runtime/claude/bin/ingest-graph.sh +86 -0
  118. package/runtime/claude/bin/ingest-item.sh +10 -0
  119. package/runtime/claude/bin/ingest-surface.html +495 -0
  120. package/runtime/claude/bin/ingest.py +1011 -0
  121. package/runtime/claude/bin/ingest.sh +308 -0
  122. package/runtime/claude/bin/ingest_graph.py +856 -0
  123. package/runtime/claude/bin/ingest_surface.py +544 -0
  124. package/runtime/claude/bin/invite.sh +6 -0
  125. package/runtime/claude/bin/issue.sh +10 -0
  126. package/runtime/claude/bin/knowledge.sh +10 -0
  127. package/runtime/claude/bin/lib/artifact-id.sh +46 -0
  128. package/runtime/claude/bin/lib/config.sh +136 -0
  129. package/runtime/claude/bin/lib/context.sh +642 -0
  130. package/runtime/claude/bin/lib/dashboard-artifact.sh +242 -0
  131. package/runtime/claude/bin/lib/ensure-develop.sh +183 -0
  132. package/runtime/claude/bin/lib/git-message.sh +37 -0
  133. package/runtime/claude/bin/lib/git-sync.sh +494 -0
  134. package/runtime/claude/bin/lib/greeting.sh +548 -0
  135. package/runtime/claude/bin/lib/handoff-meta.sh +97 -0
  136. package/runtime/claude/bin/lib/hash.sh +13 -0
  137. package/runtime/claude/bin/lib/identity.sh +213 -0
  138. package/runtime/claude/bin/lib/metrics.sh +374 -0
  139. package/runtime/claude/bin/lib/noncode.sh +31 -0
  140. package/runtime/claude/bin/lib/permissions.sh +106 -0
  141. package/runtime/claude/bin/lib/time.sh +56 -0
  142. package/runtime/claude/bin/lib/worktree-links.sh +85 -0
  143. package/runtime/claude/bin/node-run.sh +42 -0
  144. package/runtime/claude/bin/notification.sh +6 -0
  145. package/runtime/claude/bin/notify.sh +636 -0
  146. package/runtime/claude/bin/observe-context.sh +14 -0
  147. package/runtime/claude/bin/onboarding.sh +6 -0
  148. package/runtime/claude/bin/person.py +634 -0
  149. package/runtime/claude/bin/person.sh +481 -0
  150. package/runtime/claude/bin/pi-render-spec.mjs +140 -0
  151. package/runtime/claude/bin/post-update.sh +37 -0
  152. package/runtime/claude/bin/prime-render-spec.mjs +147 -0
  153. package/runtime/claude/bin/publish-artifact.sh +324 -0
  154. package/runtime/claude/bin/publish-references.sh +144 -0
  155. package/runtime/claude/bin/quest.sh +9 -0
  156. package/runtime/claude/bin/question.sh +8 -0
  157. package/runtime/claude/bin/repo-state.sh +96 -0
  158. package/runtime/claude/bin/research-ingest.sh +7 -0
  159. package/runtime/claude/bin/restore-owned-skills.sh +67 -0
  160. package/runtime/claude/bin/retrieval_eval.py +385 -0
  161. package/runtime/claude/bin/runtime-identity.sh +70 -0
  162. package/runtime/claude/bin/runtime-upgrade.sh +43 -0
  163. package/runtime/claude/bin/scroll.sh +9 -0
  164. package/runtime/claude/bin/search.sh +318 -0
  165. package/runtime/claude/bin/session-autosave.sh +220 -0
  166. package/runtime/claude/bin/session-log.sh +199 -0
  167. package/runtime/claude/bin/session-start.sh +696 -0
  168. package/runtime/claude/bin/settings.sh +532 -0
  169. package/runtime/claude/bin/startup-check.sh +136 -0
  170. package/runtime/claude/bin/statusline.sh +41 -0
  171. package/runtime/claude/bin/telemetry.sh +666 -0
  172. package/runtime/claude/bin/test-changes.sh +344 -0
  173. package/runtime/claude/bin/thread.sh +9 -0
  174. package/runtime/claude/bin/todo.sh +9 -0
  175. package/runtime/claude/bin/view-render.sh +126 -0
  176. package/runtime/claude/bin/worktree-create.sh +145 -0
  177. package/runtime/claude/bin/worktree-remove.sh +50 -0
  178. package/runtime/claude/bin/worktree.sh +198 -0
  179. package/runtime/claude/egregore_runtime/__init__.py +228 -0
  180. package/runtime/claude/egregore_runtime/adapters/__init__.py +5 -0
  181. package/runtime/claude/egregore_runtime/adapters/invitation.py +237 -0
  182. package/runtime/claude/egregore_runtime/adapters/notification.py +59 -0
  183. package/runtime/claude/egregore_runtime/adapters/qmd.py +1701 -0
  184. package/runtime/claude/egregore_runtime/adapters/qmd_cli.py +210 -0
  185. package/runtime/claude/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  186. package/runtime/claude/egregore_runtime/admin_gate.py +102 -0
  187. package/runtime/claude/egregore_runtime/artifacts.py +523 -0
  188. package/runtime/claude/egregore_runtime/contracts.py +499 -0
  189. package/runtime/claude/egregore_runtime/entitlements.py +85 -0
  190. package/runtime/claude/egregore_runtime/errors.py +10 -0
  191. package/runtime/claude/egregore_runtime/graph.py +356 -0
  192. package/runtime/claude/egregore_runtime/handoff_lookup.py +196 -0
  193. package/runtime/claude/egregore_runtime/harness_cli.py +1221 -0
  194. package/runtime/claude/egregore_runtime/identity.py +734 -0
  195. package/runtime/claude/egregore_runtime/identity_cli.py +91 -0
  196. package/runtime/claude/egregore_runtime/ingest.py +575 -0
  197. package/runtime/claude/egregore_runtime/ingest_cli.py +254 -0
  198. package/runtime/claude/egregore_runtime/ingest_index_cli.py +147 -0
  199. package/runtime/claude/egregore_runtime/invitation_cli.py +51 -0
  200. package/runtime/claude/egregore_runtime/invitations.py +116 -0
  201. package/runtime/claude/egregore_runtime/issue_cli.py +305 -0
  202. package/runtime/claude/egregore_runtime/issues.py +359 -0
  203. package/runtime/claude/egregore_runtime/knowledge.py +376 -0
  204. package/runtime/claude/egregore_runtime/knowledge_cli.py +173 -0
  205. package/runtime/claude/egregore_runtime/lifecycle.py +888 -0
  206. package/runtime/claude/egregore_runtime/lifecycle_cli.py +269 -0
  207. package/runtime/claude/egregore_runtime/notification_cli.py +125 -0
  208. package/runtime/claude/egregore_runtime/notifications.py +230 -0
  209. package/runtime/claude/egregore_runtime/observe.py +342 -0
  210. package/runtime/claude/egregore_runtime/onboarding.py +290 -0
  211. package/runtime/claude/egregore_runtime/onboarding_cli.py +110 -0
  212. package/runtime/claude/egregore_runtime/policy.py +144 -0
  213. package/runtime/claude/egregore_runtime/profile.py +193 -0
  214. package/runtime/claude/egregore_runtime/quest_cli.py +216 -0
  215. package/runtime/claude/egregore_runtime/question_cli.py +180 -0
  216. package/runtime/claude/egregore_runtime/questions.py +304 -0
  217. package/runtime/claude/egregore_runtime/quests.py +419 -0
  218. package/runtime/claude/egregore_runtime/readiness.py +379 -0
  219. package/runtime/claude/egregore_runtime/research_ingest.py +256 -0
  220. package/runtime/claude/egregore_runtime/research_ingest_cli.py +44 -0
  221. package/runtime/claude/egregore_runtime/runtime.py +464 -0
  222. package/runtime/claude/egregore_runtime/scroll_cli.py +185 -0
  223. package/runtime/claude/egregore_runtime/scrolls.py +726 -0
  224. package/runtime/claude/egregore_runtime/status.py +412 -0
  225. package/runtime/claude/egregore_runtime/status_cli.py +174 -0
  226. package/runtime/claude/egregore_runtime/sync.py +218 -0
  227. package/runtime/claude/egregore_runtime/teamsync.py +139 -0
  228. package/runtime/claude/egregore_runtime/telemetry.py +640 -0
  229. package/runtime/claude/egregore_runtime/thread_cli.py +173 -0
  230. package/runtime/claude/egregore_runtime/threads.py +517 -0
  231. package/runtime/claude/egregore_runtime/todo_cli.py +142 -0
  232. package/runtime/claude/egregore_runtime/todos.py +244 -0
  233. package/runtime/claude/egregore_runtime/upgrade.py +770 -0
  234. package/runtime/claude/egregore_runtime/upgrade_worker.py +53 -0
  235. package/runtime/claude/egregore_runtime/writeback.py +391 -0
  236. package/runtime/claude/egregore_runtime/writeback_cli.py +114 -0
  237. package/runtime/claude/manifest.json +284 -0
  238. package/runtime/codex/.codex/hooks/search-hint.js +21 -52
  239. package/runtime/codex/.codex/hooks.json +3 -3
  240. package/runtime/codex/.codex/skills/activity/SKILL.md +23 -66
  241. package/runtime/codex/.codex/skills/announce/SKILL.md +27 -50
  242. package/runtime/codex/.codex/skills/archive/SKILL.md +21 -36
  243. package/runtime/codex/.codex/skills/checkup/SKILL.md +77 -36
  244. package/runtime/codex/.codex/skills/dark-mode/SKILL.md +1 -1
  245. package/runtime/codex/.codex/skills/dashboard/SKILL.md +17 -47
  246. package/runtime/codex/.codex/skills/handoff/SKILL.md +84 -133
  247. package/runtime/codex/.codex/skills/harvest/SKILL.md +32 -117
  248. package/runtime/codex/.codex/skills/ingest/SKILL.md +47 -25
  249. package/runtime/codex/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  250. package/runtime/codex/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  251. package/runtime/codex/.codex/skills/invite/SKILL.md +21 -35
  252. package/runtime/codex/.codex/skills/issue/SKILL.md +60 -41
  253. package/runtime/codex/.codex/skills/me/SKILL.md +1 -1
  254. package/runtime/codex/.codex/skills/meeting/SKILL.md +16 -36
  255. package/runtime/codex/.codex/skills/meeting/references/analysis-contract.md +48 -0
  256. package/runtime/codex/.codex/skills/note/SKILL.md +30 -25
  257. package/runtime/codex/.codex/skills/onboarding/SKILL.md +36 -41
  258. package/runtime/codex/.codex/skills/pull/SKILL.md +1 -1
  259. package/runtime/codex/.codex/skills/quest/SKILL.md +27 -66
  260. package/runtime/codex/.codex/skills/reflect/SKILL.md +22 -36
  261. package/runtime/codex/.codex/skills/save/SKILL.md +2 -2
  262. package/runtime/codex/.codex/skills/telemetry/SKILL.md +1 -1
  263. package/runtime/codex/.codex/skills/test/SKILL.md +1 -1
  264. package/runtime/codex/.codex/skills/tutorial/SKILL.md +40 -41
  265. package/runtime/codex/.codex/skills/view/SKILL.md +115 -111
  266. package/runtime/codex/.codex/skills/wrap/SKILL.md +45 -41
  267. package/runtime/codex/.codex/spec-manifest.json +11 -11
  268. package/runtime/codex/AGENTS.md +85 -67
  269. package/runtime/codex/bin/activity-action.sh +92 -0
  270. package/runtime/codex/bin/activity-data.sh +12 -233
  271. package/runtime/codex/bin/agent.sh +99 -103
  272. package/runtime/codex/bin/artifact-register.sh +164 -0
  273. package/runtime/codex/bin/artifact-writeback.sh +53 -0
  274. package/runtime/codex/bin/artifacts.sh +288 -0
  275. package/runtime/codex/bin/build-sealed-dataroom.mjs +722 -0
  276. package/runtime/codex/bin/capture-run.sh +18 -2
  277. package/runtime/codex/bin/codex-render-spec.mjs +46 -19
  278. package/runtime/codex/bin/codex-session-start.sh +14 -4
  279. package/runtime/codex/bin/codex-skill-render.mjs +9 -7
  280. package/runtime/codex/bin/contribute-guard.sh +79 -0
  281. package/runtime/codex/bin/corpus_map.py +806 -0
  282. package/runtime/codex/bin/corpus_survey.py +304 -0
  283. package/runtime/codex/bin/dashboard-data.sh +11 -171
  284. package/runtime/codex/bin/github-auth.sh +121 -0
  285. package/runtime/codex/bin/graph-batch.sh +7 -0
  286. package/runtime/codex/bin/graph-op.sh +4 -0
  287. package/runtime/codex/bin/graph-projection.sh +54 -0
  288. package/runtime/codex/bin/graph-wal.sh +13 -0
  289. package/runtime/codex/bin/graph.sh +44 -0
  290. package/runtime/codex/bin/handoff-lifecycle-job.sh +146 -0
  291. package/runtime/codex/bin/handoff-lifecycle.sh +280 -0
  292. package/runtime/codex/bin/handoff-preview.sh +169 -0
  293. package/runtime/codex/bin/handoff-run.sh +42 -26
  294. package/runtime/codex/bin/handoff-save-egregore.sh +1 -1
  295. package/runtime/codex/bin/ingest-graph.sh +6 -0
  296. package/runtime/codex/bin/ingest-item.sh +10 -0
  297. package/runtime/codex/bin/ingest.sh +59 -30
  298. package/runtime/codex/bin/invite.sh +6 -0
  299. package/runtime/codex/bin/issue.sh +10 -0
  300. package/runtime/codex/bin/knowledge.sh +10 -0
  301. package/runtime/codex/bin/lib/config.sh +20 -0
  302. package/runtime/codex/bin/lib/context.sh +46 -25
  303. package/runtime/codex/bin/lib/git-sync.sh +86 -6
  304. package/runtime/codex/bin/lib/greeting.sh +36 -7
  305. package/runtime/codex/bin/lib/handoff-meta.sh +97 -0
  306. package/runtime/codex/bin/lib/worktree-links.sh +6 -0
  307. package/runtime/codex/bin/node-run.sh +42 -0
  308. package/runtime/codex/bin/notification.sh +6 -0
  309. package/runtime/codex/bin/observe-context.sh +14 -0
  310. package/runtime/codex/bin/onboarding.sh +6 -0
  311. package/runtime/codex/bin/person.py +4 -0
  312. package/runtime/codex/bin/person.sh +43 -10
  313. package/runtime/codex/bin/pi-render-spec.mjs +140 -0
  314. package/runtime/codex/bin/post-update.sh +37 -0
  315. package/runtime/codex/bin/prime-render-spec.mjs +147 -0
  316. package/runtime/codex/bin/publish-artifact.sh +55 -2
  317. package/runtime/codex/bin/quest.sh +9 -0
  318. package/runtime/codex/bin/question.sh +8 -0
  319. package/runtime/codex/bin/research-ingest.sh +7 -0
  320. package/runtime/codex/bin/restore-owned-skills.sh +67 -0
  321. package/runtime/codex/bin/retrieval_eval.py +385 -0
  322. package/runtime/codex/bin/runtime-identity.sh +70 -0
  323. package/runtime/codex/bin/runtime-upgrade.sh +43 -0
  324. package/runtime/codex/bin/scroll.sh +9 -0
  325. package/runtime/codex/bin/search.sh +243 -165
  326. package/runtime/codex/bin/session-autosave.sh +6 -1
  327. package/runtime/codex/bin/settings.sh +235 -7
  328. package/runtime/codex/bin/startup-check.sh +136 -0
  329. package/runtime/codex/bin/telemetry.sh +522 -247
  330. package/runtime/codex/bin/test-changes.sh +344 -0
  331. package/runtime/codex/bin/thread.sh +9 -0
  332. package/runtime/codex/bin/todo.sh +9 -0
  333. package/runtime/codex/bin/view-render.sh +126 -0
  334. package/runtime/codex/bin/worktree-create.sh +23 -6
  335. package/runtime/codex/egregore_runtime/__init__.py +228 -0
  336. package/runtime/codex/egregore_runtime/adapters/__init__.py +5 -0
  337. package/runtime/codex/egregore_runtime/adapters/invitation.py +237 -0
  338. package/runtime/codex/egregore_runtime/adapters/notification.py +59 -0
  339. package/runtime/codex/egregore_runtime/adapters/qmd.py +1701 -0
  340. package/runtime/codex/egregore_runtime/adapters/qmd_cli.py +210 -0
  341. package/runtime/codex/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  342. package/runtime/codex/egregore_runtime/admin_gate.py +102 -0
  343. package/runtime/codex/egregore_runtime/artifacts.py +523 -0
  344. package/runtime/codex/egregore_runtime/contracts.py +499 -0
  345. package/runtime/codex/egregore_runtime/entitlements.py +85 -0
  346. package/runtime/codex/egregore_runtime/errors.py +10 -0
  347. package/runtime/codex/egregore_runtime/graph.py +356 -0
  348. package/runtime/codex/egregore_runtime/handoff_lookup.py +196 -0
  349. package/runtime/codex/egregore_runtime/harness_cli.py +1221 -0
  350. package/runtime/codex/egregore_runtime/identity.py +734 -0
  351. package/runtime/codex/egregore_runtime/identity_cli.py +91 -0
  352. package/runtime/codex/egregore_runtime/ingest.py +575 -0
  353. package/runtime/codex/egregore_runtime/ingest_cli.py +254 -0
  354. package/runtime/codex/egregore_runtime/ingest_index_cli.py +147 -0
  355. package/runtime/codex/egregore_runtime/invitation_cli.py +51 -0
  356. package/runtime/codex/egregore_runtime/invitations.py +116 -0
  357. package/runtime/codex/egregore_runtime/issue_cli.py +305 -0
  358. package/runtime/codex/egregore_runtime/issues.py +359 -0
  359. package/runtime/codex/egregore_runtime/knowledge.py +376 -0
  360. package/runtime/codex/egregore_runtime/knowledge_cli.py +173 -0
  361. package/runtime/codex/egregore_runtime/lifecycle.py +888 -0
  362. package/runtime/codex/egregore_runtime/lifecycle_cli.py +269 -0
  363. package/runtime/codex/egregore_runtime/notification_cli.py +125 -0
  364. package/runtime/codex/egregore_runtime/notifications.py +230 -0
  365. package/runtime/codex/egregore_runtime/observe.py +342 -0
  366. package/runtime/codex/egregore_runtime/onboarding.py +290 -0
  367. package/runtime/codex/egregore_runtime/onboarding_cli.py +110 -0
  368. package/runtime/codex/egregore_runtime/policy.py +144 -0
  369. package/runtime/codex/egregore_runtime/profile.py +193 -0
  370. package/runtime/codex/egregore_runtime/quest_cli.py +216 -0
  371. package/runtime/codex/egregore_runtime/question_cli.py +180 -0
  372. package/runtime/codex/egregore_runtime/questions.py +304 -0
  373. package/runtime/codex/egregore_runtime/quests.py +419 -0
  374. package/runtime/codex/egregore_runtime/readiness.py +379 -0
  375. package/runtime/codex/egregore_runtime/research_ingest.py +256 -0
  376. package/runtime/codex/egregore_runtime/research_ingest_cli.py +44 -0
  377. package/runtime/codex/egregore_runtime/runtime.py +464 -0
  378. package/runtime/codex/egregore_runtime/scroll_cli.py +185 -0
  379. package/runtime/codex/egregore_runtime/scrolls.py +726 -0
  380. package/runtime/codex/egregore_runtime/status.py +412 -0
  381. package/runtime/codex/egregore_runtime/status_cli.py +174 -0
  382. package/runtime/codex/egregore_runtime/sync.py +218 -0
  383. package/runtime/codex/egregore_runtime/teamsync.py +139 -0
  384. package/runtime/codex/egregore_runtime/telemetry.py +640 -0
  385. package/runtime/codex/egregore_runtime/thread_cli.py +173 -0
  386. package/runtime/codex/egregore_runtime/threads.py +517 -0
  387. package/runtime/codex/egregore_runtime/todo_cli.py +142 -0
  388. package/runtime/codex/egregore_runtime/todos.py +244 -0
  389. package/runtime/codex/egregore_runtime/upgrade.py +770 -0
  390. package/runtime/codex/egregore_runtime/upgrade_worker.py +53 -0
  391. package/runtime/codex/egregore_runtime/writeback.py +391 -0
  392. package/runtime/codex/egregore_runtime/writeback_cli.py +114 -0
  393. package/runtime/codex/manifest.json +99 -1
  394. package/runtime/pi/.codex/hooks/search-hint.js +21 -52
  395. package/runtime/pi/.codex/hooks.json +3 -3
  396. package/runtime/pi/.codex/skills/activity/SKILL.md +23 -66
  397. package/runtime/pi/.codex/skills/announce/SKILL.md +27 -50
  398. package/runtime/pi/.codex/skills/archive/SKILL.md +21 -36
  399. package/runtime/pi/.codex/skills/checkup/SKILL.md +77 -36
  400. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +1 -1
  401. package/runtime/pi/.codex/skills/dashboard/SKILL.md +17 -47
  402. package/runtime/pi/.codex/skills/handoff/SKILL.md +84 -133
  403. package/runtime/pi/.codex/skills/harvest/SKILL.md +32 -117
  404. package/runtime/pi/.codex/skills/ingest/SKILL.md +47 -25
  405. package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  406. package/runtime/pi/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  407. package/runtime/pi/.codex/skills/invite/SKILL.md +21 -35
  408. package/runtime/pi/.codex/skills/issue/SKILL.md +60 -41
  409. package/runtime/pi/.codex/skills/me/SKILL.md +1 -1
  410. package/runtime/pi/.codex/skills/meeting/SKILL.md +16 -36
  411. package/runtime/pi/.codex/skills/meeting/references/analysis-contract.md +48 -0
  412. package/runtime/pi/.codex/skills/note/SKILL.md +30 -25
  413. package/runtime/pi/.codex/skills/onboarding/SKILL.md +36 -41
  414. package/runtime/pi/.codex/skills/pull/SKILL.md +1 -1
  415. package/runtime/pi/.codex/skills/quest/SKILL.md +27 -66
  416. package/runtime/pi/.codex/skills/reflect/SKILL.md +22 -36
  417. package/runtime/pi/.codex/skills/save/SKILL.md +2 -2
  418. package/runtime/pi/.codex/skills/telemetry/SKILL.md +1 -1
  419. package/runtime/pi/.codex/skills/test/SKILL.md +1 -1
  420. package/runtime/pi/.codex/skills/tutorial/SKILL.md +40 -41
  421. package/runtime/pi/.codex/skills/view/SKILL.md +115 -111
  422. package/runtime/pi/.codex/skills/wrap/SKILL.md +45 -41
  423. package/runtime/pi/.codex/spec-manifest.json +11 -11
  424. package/runtime/pi/.pi/APPEND_SYSTEM.md +80 -57
  425. package/runtime/pi/.pi/extensions/egregore.ts +7 -0
  426. package/runtime/pi/.pi/spec-manifest.json +2 -2
  427. package/runtime/pi/AGENTS.md +85 -67
  428. package/runtime/pi/bin/activity-action.sh +92 -0
  429. package/runtime/pi/bin/activity-data.sh +12 -233
  430. package/runtime/pi/bin/agent.sh +99 -103
  431. package/runtime/pi/bin/artifact-register.sh +164 -0
  432. package/runtime/pi/bin/artifact-writeback.sh +53 -0
  433. package/runtime/pi/bin/artifacts.sh +288 -0
  434. package/runtime/pi/bin/build-sealed-dataroom.mjs +722 -0
  435. package/runtime/pi/bin/capture-run.sh +18 -2
  436. package/runtime/pi/bin/codex-render-spec.mjs +46 -19
  437. package/runtime/pi/bin/codex-session-start.sh +14 -4
  438. package/runtime/pi/bin/codex-skill-render.mjs +9 -7
  439. package/runtime/pi/bin/contribute-guard.sh +79 -0
  440. package/runtime/pi/bin/corpus_map.py +806 -0
  441. package/runtime/pi/bin/corpus_survey.py +304 -0
  442. package/runtime/pi/bin/dashboard-data.sh +11 -171
  443. package/runtime/pi/bin/github-auth.sh +121 -0
  444. package/runtime/pi/bin/graph-batch.sh +7 -0
  445. package/runtime/pi/bin/graph-op.sh +4 -0
  446. package/runtime/pi/bin/graph-projection.sh +54 -0
  447. package/runtime/pi/bin/graph-wal.sh +13 -0
  448. package/runtime/pi/bin/graph.sh +44 -0
  449. package/runtime/pi/bin/handoff-lifecycle-job.sh +146 -0
  450. package/runtime/pi/bin/handoff-lifecycle.sh +280 -0
  451. package/runtime/pi/bin/handoff-preview.sh +169 -0
  452. package/runtime/pi/bin/handoff-run.sh +42 -26
  453. package/runtime/pi/bin/handoff-save-egregore.sh +1 -1
  454. package/runtime/pi/bin/ingest-graph.sh +6 -0
  455. package/runtime/pi/bin/ingest-item.sh +10 -0
  456. package/runtime/pi/bin/ingest.sh +59 -30
  457. package/runtime/pi/bin/invite.sh +6 -0
  458. package/runtime/pi/bin/issue.sh +10 -0
  459. package/runtime/pi/bin/knowledge.sh +10 -0
  460. package/runtime/pi/bin/lib/config.sh +20 -0
  461. package/runtime/pi/bin/lib/context.sh +46 -25
  462. package/runtime/pi/bin/lib/git-sync.sh +86 -6
  463. package/runtime/pi/bin/lib/greeting.sh +36 -7
  464. package/runtime/pi/bin/lib/handoff-meta.sh +97 -0
  465. package/runtime/pi/bin/lib/worktree-links.sh +6 -0
  466. package/runtime/pi/bin/node-run.sh +42 -0
  467. package/runtime/pi/bin/notification.sh +6 -0
  468. package/runtime/pi/bin/observe-context.sh +14 -0
  469. package/runtime/pi/bin/onboarding.sh +6 -0
  470. package/runtime/pi/bin/person.py +4 -0
  471. package/runtime/pi/bin/person.sh +43 -10
  472. package/runtime/pi/bin/pi-observe-context.mjs +93 -0
  473. package/runtime/pi/bin/pi-product-workflows.mjs +1 -1
  474. package/runtime/pi/bin/pi-render-spec.mjs +1 -1
  475. package/runtime/pi/bin/post-update.sh +37 -0
  476. package/runtime/pi/bin/prime-render-spec.mjs +147 -0
  477. package/runtime/pi/bin/publish-artifact.sh +55 -2
  478. package/runtime/pi/bin/quest.sh +9 -0
  479. package/runtime/pi/bin/question.sh +8 -0
  480. package/runtime/pi/bin/research-ingest.sh +7 -0
  481. package/runtime/pi/bin/restore-owned-skills.sh +67 -0
  482. package/runtime/pi/bin/retrieval_eval.py +385 -0
  483. package/runtime/pi/bin/runtime-identity.sh +70 -0
  484. package/runtime/pi/bin/runtime-upgrade.sh +43 -0
  485. package/runtime/pi/bin/scroll.sh +9 -0
  486. package/runtime/pi/bin/search.sh +243 -165
  487. package/runtime/pi/bin/session-autosave.sh +6 -1
  488. package/runtime/pi/bin/settings.sh +235 -7
  489. package/runtime/pi/bin/startup-check.sh +136 -0
  490. package/runtime/pi/bin/telemetry.sh +522 -247
  491. package/runtime/pi/bin/test-changes.sh +344 -0
  492. package/runtime/pi/bin/thread.sh +9 -0
  493. package/runtime/pi/bin/todo.sh +9 -0
  494. package/runtime/pi/bin/view-render.sh +126 -0
  495. package/runtime/pi/bin/worktree-create.sh +23 -6
  496. package/runtime/pi/egregore_runtime/__init__.py +228 -0
  497. package/runtime/pi/egregore_runtime/adapters/__init__.py +5 -0
  498. package/runtime/pi/egregore_runtime/adapters/invitation.py +237 -0
  499. package/runtime/pi/egregore_runtime/adapters/notification.py +59 -0
  500. package/runtime/pi/egregore_runtime/adapters/qmd.py +1701 -0
  501. package/runtime/pi/egregore_runtime/adapters/qmd_cli.py +210 -0
  502. package/runtime/pi/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  503. package/runtime/pi/egregore_runtime/admin_gate.py +102 -0
  504. package/runtime/pi/egregore_runtime/artifacts.py +523 -0
  505. package/runtime/pi/egregore_runtime/contracts.py +499 -0
  506. package/runtime/pi/egregore_runtime/entitlements.py +85 -0
  507. package/runtime/pi/egregore_runtime/errors.py +10 -0
  508. package/runtime/pi/egregore_runtime/graph.py +356 -0
  509. package/runtime/pi/egregore_runtime/handoff_lookup.py +196 -0
  510. package/runtime/pi/egregore_runtime/harness_cli.py +1221 -0
  511. package/runtime/pi/egregore_runtime/identity.py +734 -0
  512. package/runtime/pi/egregore_runtime/identity_cli.py +91 -0
  513. package/runtime/pi/egregore_runtime/ingest.py +575 -0
  514. package/runtime/pi/egregore_runtime/ingest_cli.py +254 -0
  515. package/runtime/pi/egregore_runtime/ingest_index_cli.py +147 -0
  516. package/runtime/pi/egregore_runtime/invitation_cli.py +51 -0
  517. package/runtime/pi/egregore_runtime/invitations.py +116 -0
  518. package/runtime/pi/egregore_runtime/issue_cli.py +305 -0
  519. package/runtime/pi/egregore_runtime/issues.py +359 -0
  520. package/runtime/pi/egregore_runtime/knowledge.py +376 -0
  521. package/runtime/pi/egregore_runtime/knowledge_cli.py +173 -0
  522. package/runtime/pi/egregore_runtime/lifecycle.py +888 -0
  523. package/runtime/pi/egregore_runtime/lifecycle_cli.py +269 -0
  524. package/runtime/pi/egregore_runtime/notification_cli.py +125 -0
  525. package/runtime/pi/egregore_runtime/notifications.py +230 -0
  526. package/runtime/pi/egregore_runtime/observe.py +342 -0
  527. package/runtime/pi/egregore_runtime/onboarding.py +290 -0
  528. package/runtime/pi/egregore_runtime/onboarding_cli.py +110 -0
  529. package/runtime/pi/egregore_runtime/policy.py +144 -0
  530. package/runtime/pi/egregore_runtime/profile.py +193 -0
  531. package/runtime/pi/egregore_runtime/quest_cli.py +216 -0
  532. package/runtime/pi/egregore_runtime/question_cli.py +180 -0
  533. package/runtime/pi/egregore_runtime/questions.py +304 -0
  534. package/runtime/pi/egregore_runtime/quests.py +419 -0
  535. package/runtime/pi/egregore_runtime/readiness.py +379 -0
  536. package/runtime/pi/egregore_runtime/research_ingest.py +256 -0
  537. package/runtime/pi/egregore_runtime/research_ingest_cli.py +44 -0
  538. package/runtime/pi/egregore_runtime/runtime.py +464 -0
  539. package/runtime/pi/egregore_runtime/scroll_cli.py +185 -0
  540. package/runtime/pi/egregore_runtime/scrolls.py +726 -0
  541. package/runtime/pi/egregore_runtime/status.py +412 -0
  542. package/runtime/pi/egregore_runtime/status_cli.py +174 -0
  543. package/runtime/pi/egregore_runtime/sync.py +218 -0
  544. package/runtime/pi/egregore_runtime/teamsync.py +139 -0
  545. package/runtime/pi/egregore_runtime/telemetry.py +640 -0
  546. package/runtime/pi/egregore_runtime/thread_cli.py +173 -0
  547. package/runtime/pi/egregore_runtime/threads.py +517 -0
  548. package/runtime/pi/egregore_runtime/todo_cli.py +142 -0
  549. package/runtime/pi/egregore_runtime/todos.py +244 -0
  550. package/runtime/pi/egregore_runtime/upgrade.py +770 -0
  551. package/runtime/pi/egregore_runtime/upgrade_worker.py +53 -0
  552. package/runtime/pi/egregore_runtime/writeback.py +391 -0
  553. package/runtime/pi/egregore_runtime/writeback_cli.py +114 -0
  554. package/runtime/pi/manifest.json +99 -1
  555. package/runtime/prime/.codex/hooks/search-hint.js +21 -52
  556. package/runtime/prime/.codex/hooks.json +3 -3
  557. package/runtime/prime/.codex/skills/activity/SKILL.md +23 -66
  558. package/runtime/prime/.codex/skills/announce/SKILL.md +27 -50
  559. package/runtime/prime/.codex/skills/archive/SKILL.md +21 -36
  560. package/runtime/prime/.codex/skills/checkup/SKILL.md +77 -36
  561. package/runtime/prime/.codex/skills/dark-mode/SKILL.md +1 -1
  562. package/runtime/prime/.codex/skills/dashboard/SKILL.md +17 -47
  563. package/runtime/prime/.codex/skills/handoff/SKILL.md +84 -133
  564. package/runtime/prime/.codex/skills/harvest/SKILL.md +32 -117
  565. package/runtime/prime/.codex/skills/ingest/SKILL.md +47 -25
  566. package/runtime/prime/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  567. package/runtime/prime/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  568. package/runtime/prime/.codex/skills/invite/SKILL.md +21 -35
  569. package/runtime/prime/.codex/skills/issue/SKILL.md +60 -41
  570. package/runtime/prime/.codex/skills/me/SKILL.md +1 -1
  571. package/runtime/prime/.codex/skills/meeting/SKILL.md +16 -36
  572. package/runtime/prime/.codex/skills/meeting/references/analysis-contract.md +48 -0
  573. package/runtime/prime/.codex/skills/note/SKILL.md +30 -25
  574. package/runtime/prime/.codex/skills/onboarding/SKILL.md +36 -41
  575. package/runtime/prime/.codex/skills/pull/SKILL.md +1 -1
  576. package/runtime/prime/.codex/skills/quest/SKILL.md +27 -66
  577. package/runtime/prime/.codex/skills/reflect/SKILL.md +22 -36
  578. package/runtime/prime/.codex/skills/save/SKILL.md +2 -2
  579. package/runtime/prime/.codex/skills/telemetry/SKILL.md +1 -1
  580. package/runtime/prime/.codex/skills/test/SKILL.md +1 -1
  581. package/runtime/prime/.codex/skills/tutorial/SKILL.md +40 -41
  582. package/runtime/prime/.codex/skills/view/SKILL.md +115 -111
  583. package/runtime/prime/.codex/skills/wrap/SKILL.md +45 -41
  584. package/runtime/prime/.codex/spec-manifest.json +11 -11
  585. package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +81 -58
  586. package/runtime/prime/.prime/agent/extensions/egregore.ts +7 -0
  587. package/runtime/prime/.prime/agent/spec-manifest.json +2 -2
  588. package/runtime/prime/AGENTS.md +85 -67
  589. package/runtime/prime/bin/activity-action.sh +92 -0
  590. package/runtime/prime/bin/activity-data.sh +12 -233
  591. package/runtime/prime/bin/agent.sh +99 -103
  592. package/runtime/prime/bin/artifact-register.sh +164 -0
  593. package/runtime/prime/bin/artifact-writeback.sh +53 -0
  594. package/runtime/prime/bin/artifacts.sh +288 -0
  595. package/runtime/prime/bin/build-sealed-dataroom.mjs +722 -0
  596. package/runtime/prime/bin/capture-run.sh +18 -2
  597. package/runtime/prime/bin/codex-render-spec.mjs +46 -19
  598. package/runtime/prime/bin/codex-session-start.sh +14 -4
  599. package/runtime/prime/bin/codex-skill-render.mjs +9 -7
  600. package/runtime/prime/bin/contribute-guard.sh +79 -0
  601. package/runtime/prime/bin/corpus_map.py +806 -0
  602. package/runtime/prime/bin/corpus_survey.py +304 -0
  603. package/runtime/prime/bin/dashboard-data.sh +11 -171
  604. package/runtime/prime/bin/github-auth.sh +121 -0
  605. package/runtime/prime/bin/graph-batch.sh +7 -0
  606. package/runtime/prime/bin/graph-op.sh +4 -0
  607. package/runtime/prime/bin/graph-projection.sh +54 -0
  608. package/runtime/prime/bin/graph-wal.sh +13 -0
  609. package/runtime/prime/bin/graph.sh +44 -0
  610. package/runtime/prime/bin/handoff-lifecycle-job.sh +146 -0
  611. package/runtime/prime/bin/handoff-lifecycle.sh +280 -0
  612. package/runtime/prime/bin/handoff-preview.sh +169 -0
  613. package/runtime/prime/bin/handoff-run.sh +42 -26
  614. package/runtime/prime/bin/handoff-save-egregore.sh +1 -1
  615. package/runtime/prime/bin/ingest-graph.sh +6 -0
  616. package/runtime/prime/bin/ingest-item.sh +10 -0
  617. package/runtime/prime/bin/ingest.sh +59 -30
  618. package/runtime/prime/bin/invite.sh +6 -0
  619. package/runtime/prime/bin/issue.sh +10 -0
  620. package/runtime/prime/bin/knowledge.sh +10 -0
  621. package/runtime/prime/bin/lib/config.sh +20 -0
  622. package/runtime/prime/bin/lib/context.sh +46 -25
  623. package/runtime/prime/bin/lib/git-sync.sh +86 -6
  624. package/runtime/prime/bin/lib/greeting.sh +36 -7
  625. package/runtime/prime/bin/lib/handoff-meta.sh +97 -0
  626. package/runtime/prime/bin/lib/worktree-links.sh +6 -0
  627. package/runtime/prime/bin/node-run.sh +42 -0
  628. package/runtime/prime/bin/notification.sh +6 -0
  629. package/runtime/prime/bin/observe-context.sh +14 -0
  630. package/runtime/prime/bin/onboarding.sh +6 -0
  631. package/runtime/prime/bin/person.py +4 -0
  632. package/runtime/prime/bin/person.sh +43 -10
  633. package/runtime/prime/bin/pi-observe-context.mjs +93 -0
  634. package/runtime/prime/bin/pi-product-workflows.mjs +1 -1
  635. package/runtime/prime/bin/pi-render-spec.mjs +140 -0
  636. package/runtime/prime/bin/post-update.sh +37 -0
  637. package/runtime/prime/bin/prime-render-spec.mjs +2 -2
  638. package/runtime/prime/bin/publish-artifact.sh +55 -2
  639. package/runtime/prime/bin/quest.sh +9 -0
  640. package/runtime/prime/bin/question.sh +8 -0
  641. package/runtime/prime/bin/research-ingest.sh +7 -0
  642. package/runtime/prime/bin/restore-owned-skills.sh +67 -0
  643. package/runtime/prime/bin/retrieval_eval.py +385 -0
  644. package/runtime/prime/bin/runtime-identity.sh +70 -0
  645. package/runtime/prime/bin/runtime-upgrade.sh +43 -0
  646. package/runtime/prime/bin/scroll.sh +9 -0
  647. package/runtime/prime/bin/search.sh +243 -165
  648. package/runtime/prime/bin/session-autosave.sh +6 -1
  649. package/runtime/prime/bin/settings.sh +235 -7
  650. package/runtime/prime/bin/startup-check.sh +136 -0
  651. package/runtime/prime/bin/telemetry.sh +522 -247
  652. package/runtime/prime/bin/test-changes.sh +344 -0
  653. package/runtime/prime/bin/thread.sh +9 -0
  654. package/runtime/prime/bin/todo.sh +9 -0
  655. package/runtime/prime/bin/view-render.sh +126 -0
  656. package/runtime/prime/bin/worktree-create.sh +23 -6
  657. package/runtime/prime/egregore_runtime/__init__.py +228 -0
  658. package/runtime/prime/egregore_runtime/adapters/__init__.py +5 -0
  659. package/runtime/prime/egregore_runtime/adapters/invitation.py +237 -0
  660. package/runtime/prime/egregore_runtime/adapters/notification.py +59 -0
  661. package/runtime/prime/egregore_runtime/adapters/qmd.py +1701 -0
  662. package/runtime/prime/egregore_runtime/adapters/qmd_cli.py +210 -0
  663. package/runtime/prime/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  664. package/runtime/prime/egregore_runtime/admin_gate.py +102 -0
  665. package/runtime/prime/egregore_runtime/artifacts.py +523 -0
  666. package/runtime/prime/egregore_runtime/contracts.py +499 -0
  667. package/runtime/prime/egregore_runtime/entitlements.py +85 -0
  668. package/runtime/prime/egregore_runtime/errors.py +10 -0
  669. package/runtime/prime/egregore_runtime/graph.py +356 -0
  670. package/runtime/prime/egregore_runtime/handoff_lookup.py +196 -0
  671. package/runtime/prime/egregore_runtime/harness_cli.py +1221 -0
  672. package/runtime/prime/egregore_runtime/identity.py +734 -0
  673. package/runtime/prime/egregore_runtime/identity_cli.py +91 -0
  674. package/runtime/prime/egregore_runtime/ingest.py +575 -0
  675. package/runtime/prime/egregore_runtime/ingest_cli.py +254 -0
  676. package/runtime/prime/egregore_runtime/ingest_index_cli.py +147 -0
  677. package/runtime/prime/egregore_runtime/invitation_cli.py +51 -0
  678. package/runtime/prime/egregore_runtime/invitations.py +116 -0
  679. package/runtime/prime/egregore_runtime/issue_cli.py +305 -0
  680. package/runtime/prime/egregore_runtime/issues.py +359 -0
  681. package/runtime/prime/egregore_runtime/knowledge.py +376 -0
  682. package/runtime/prime/egregore_runtime/knowledge_cli.py +173 -0
  683. package/runtime/prime/egregore_runtime/lifecycle.py +888 -0
  684. package/runtime/prime/egregore_runtime/lifecycle_cli.py +269 -0
  685. package/runtime/prime/egregore_runtime/notification_cli.py +125 -0
  686. package/runtime/prime/egregore_runtime/notifications.py +230 -0
  687. package/runtime/prime/egregore_runtime/observe.py +342 -0
  688. package/runtime/prime/egregore_runtime/onboarding.py +290 -0
  689. package/runtime/prime/egregore_runtime/onboarding_cli.py +110 -0
  690. package/runtime/prime/egregore_runtime/policy.py +144 -0
  691. package/runtime/prime/egregore_runtime/profile.py +193 -0
  692. package/runtime/prime/egregore_runtime/quest_cli.py +216 -0
  693. package/runtime/prime/egregore_runtime/question_cli.py +180 -0
  694. package/runtime/prime/egregore_runtime/questions.py +304 -0
  695. package/runtime/prime/egregore_runtime/quests.py +419 -0
  696. package/runtime/prime/egregore_runtime/readiness.py +379 -0
  697. package/runtime/prime/egregore_runtime/research_ingest.py +256 -0
  698. package/runtime/prime/egregore_runtime/research_ingest_cli.py +44 -0
  699. package/runtime/prime/egregore_runtime/runtime.py +464 -0
  700. package/runtime/prime/egregore_runtime/scroll_cli.py +185 -0
  701. package/runtime/prime/egregore_runtime/scrolls.py +726 -0
  702. package/runtime/prime/egregore_runtime/status.py +412 -0
  703. package/runtime/prime/egregore_runtime/status_cli.py +174 -0
  704. package/runtime/prime/egregore_runtime/sync.py +218 -0
  705. package/runtime/prime/egregore_runtime/teamsync.py +139 -0
  706. package/runtime/prime/egregore_runtime/telemetry.py +640 -0
  707. package/runtime/prime/egregore_runtime/thread_cli.py +173 -0
  708. package/runtime/prime/egregore_runtime/threads.py +517 -0
  709. package/runtime/prime/egregore_runtime/todo_cli.py +142 -0
  710. package/runtime/prime/egregore_runtime/todos.py +244 -0
  711. package/runtime/prime/egregore_runtime/upgrade.py +770 -0
  712. package/runtime/prime/egregore_runtime/upgrade_worker.py +53 -0
  713. package/runtime/prime/egregore_runtime/writeback.py +391 -0
  714. package/runtime/prime/egregore_runtime/writeback_cli.py +114 -0
  715. package/runtime/prime/manifest.json +99 -1
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // egregore-launcher-version: 0.20.1
2
+ // egregore-launcher-version: 0.21.0-runtime-mvp.1
3
3
  //
4
4
  // egregore — launch and browse Egregore instances from your terminal.
5
5
  // Installed by create-egregore. Reads ~/.egregore/instances.json.
@@ -14,6 +14,8 @@
14
14
  // egregore ls | list list instances (non-interactive table)
15
15
  // egregore use <slug> set the default for bare `egregore`
16
16
  // egregore connect [slug] activate Connected for an existing instance
17
+ // egregore telemetry <verb> manage local telemetry for an instance
18
+ // egregore runtime <verb> inspect or synchronize Local retrieval
17
19
  // egregore /invite <user> invite a GitHub user to an instance
18
20
  // egregore settings [slug] hosting on/off, managed repos, admins (s in browser)
19
21
  // egregore prune [--dry-run] remove entries whose path is gone
@@ -33,7 +35,7 @@ const crypto = require("node:crypto");
33
35
  const { spawnSync, spawn } = require("node:child_process");
34
36
  const readline = require("node:readline");
35
37
 
36
- const VERSION = "0.20.1";
38
+ const VERSION = "0.21.0-runtime-mvp.1";
37
39
  const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
38
40
  const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
39
41
  const UPDATE_CACHE_FILE = path.join(os.homedir(), ".egregore", "update-check.json");
@@ -360,6 +362,52 @@ function initialCursorForCwd(registry, cwd = safeCwd()) {
360
362
  return 0;
361
363
  }
362
364
 
365
+ function currentWorktreeInstance(registry, cwd = safeCwd()) {
366
+ // Development checkouts are intentionally not persisted as separate
367
+ // Egregore instances, but launching from one must preserve the exact code
368
+ // under test. A linked worktree has a `.git` file; a safe standalone clone
369
+ // has a `.git` directory. Walk upward and borrow only display/runtime
370
+ // preferences from a registered parent when one exists.
371
+ let candidate = path.resolve(cwd);
372
+ const filesystemRoot = path.parse(candidate).root;
373
+ while (candidate !== filesystemRoot) {
374
+ const marker = path.join(candidate, ".git");
375
+ const config = path.join(candidate, "egregore.json");
376
+ try {
377
+ const gitMarker = fs.statSync(marker);
378
+ if ((gitMarker.isFile() || gitMarker.isDirectory()) && fs.statSync(config).isFile()) {
379
+ const exact = registry.find(
380
+ (entry) => entry?.path && path.resolve(entry.path) === candidate,
381
+ );
382
+ if (exact) return null;
383
+ const parent = registry
384
+ .filter((entry) => entry?.path && pathContains(entry.path, candidate))
385
+ .sort((a, b) => path.resolve(b.path).length - path.resolve(a.path).length)[0];
386
+ if (parent) return { ...parent, path: candidate, transientWorktree: true };
387
+ const local = JSON.parse(fs.readFileSync(config, "utf-8"));
388
+ return {
389
+ slug: local.slug || path.basename(candidate),
390
+ name: local.org_name || local.slug || path.basename(candidate),
391
+ path: candidate,
392
+ transientWorktree: true,
393
+ };
394
+ }
395
+ } catch {
396
+ // Keep walking: normal subdirectories do not contain both markers.
397
+ }
398
+ candidate = path.dirname(candidate);
399
+ }
400
+ return null;
401
+ }
402
+
403
+ function isLinkedGitWorktree(directory) {
404
+ try {
405
+ return fs.statSync(path.join(directory, ".git")).isFile();
406
+ } catch {
407
+ return false;
408
+ }
409
+ }
410
+
363
411
  // ── launch ──────────────────────────────────────────────────────────
364
412
 
365
413
  function normalizeRuntime(raw) {
@@ -676,7 +724,7 @@ async function renderCodexStartupCard(egregoreDir) {
676
724
  }, "Preparing Codex startup");
677
725
  let output = result.stdout || "";
678
726
  if (isConnectedPath(egregoreDir) && !output.includes("◆ CONNECTED")) {
679
- const connectedLine = " ◆ CONNECTED · hosted graph active\n";
727
+ const connectedLine = ` ◆ CONNECTED ${connectedModeSuffix(egregoreDir)}\n`;
680
728
  output = output.includes("\nWhat are you working on?")
681
729
  ? output.replace("\nWhat are you working on?", `\n${connectedLine}\nWhat are you working on?`)
682
730
  : `${output}${output.endsWith("\n") || !output ? "" : "\n"}${connectedLine}`;
@@ -702,7 +750,9 @@ function codexSupportMessage(egregoreDir) {
702
750
  " .codex/hooks.json",
703
751
  " .codex/hooks/",
704
752
  "",
705
- "Run npx -y create-egregore@latest to install the packaged Codex runtime, then rerun egregore.",
753
+ "Automatic repair did not complete. Retry with:",
754
+ " npx -y create-egregore@latest --refresh-launcher",
755
+ "Then rerun egregore.",
706
756
  "Egregore workflows appear as slash commands. In Codex, invoke them with the matching $skill token or ask in natural language.",
707
757
  ].join("\n");
708
758
  }
@@ -756,6 +806,27 @@ function primeSupportMessage(egregoreDir) {
756
806
  ].join("\n");
757
807
  }
758
808
 
809
+ function repairPortableRuntime(egregoreDir, runtime) {
810
+ const label = runtimeLabel(runtime);
811
+ process.stdout.write(`\n ${CYAN}↻${RESET} ${BOLD}Repairing ${label} support${RESET}${DIM} — updating this checkout${RESET}\n`);
812
+ const result = spawnSync(
813
+ "npx",
814
+ ["-y", `${PUBLIC_NPX_PACKAGE}@latest`, "--refresh-launcher"],
815
+ {
816
+ cwd: egregoreDir,
817
+ stdio: "inherit",
818
+ env: { ...process.env, EGREGORE_RUNTIME_REPAIR: runtime },
819
+ timeout: 3 * 60 * 1000,
820
+ },
821
+ );
822
+ if (result.error || result.status !== 0) {
823
+ process.stderr.write(` ${YELLOW}!${RESET} Automatic ${label} repair failed; the checkout was left in place.\n`);
824
+ return false;
825
+ }
826
+ process.stdout.write(` ${GREEN}✓${RESET} ${label} support repaired\n\n`);
827
+ return true;
828
+ }
829
+
759
830
  // Minimal y/N line prompt for pre-launch decisions (the TUI select machinery
760
831
  // is torn down by the time launch() runs).
761
832
  function confirmLine(question) {
@@ -823,6 +894,9 @@ function installCodexSkills(egregoreDir) {
823
894
  }
824
895
 
825
896
  function claudeLaunchArgs(egregoreDir) {
897
+ // Claude treats the positional value as the initial user prompt. Egregore
898
+ // deliberately submits `start` so the opening experience renders without
899
+ // requiring the user to type first.
826
900
  const args = ["start"];
827
901
  const memoryLink = path.join(egregoreDir, "memory");
828
902
  try {
@@ -840,14 +914,21 @@ function claudeLaunchArgs(egregoreDir) {
840
914
  return args;
841
915
  }
842
916
 
843
- function runtimeLaunchArgs(runtime, egregoreDir) {
917
+ function runtimeLaunchArgs(runtime, egregoreDir, options = {}) {
844
918
  if (runtime === "codex") {
845
- return [
919
+ const args = [
846
920
  "--enable", "hooks",
847
921
  "--sandbox", "danger-full-access",
848
922
  "--ask-for-approval", "never",
849
923
  "--cd", egregoreDir,
850
924
  ];
925
+ // Codex treats each linked worktree as a separate hook-trust root, while
926
+ // project hooks may still be discovered from the registered primary
927
+ // checkout. The Egregore launcher validates the Runtime surface above;
928
+ // trust that bounded hook set for this transient invocation so Observe
929
+ // and the branch guard are not silently skipped in the worktree.
930
+ if (options.bypassHookTrust) args.push("--dangerously-bypass-hook-trust");
931
+ return args;
851
932
  }
852
933
  if (runtime === "pi") return piTrustArgs();
853
934
  if (runtime === "prime") return primeTrustArgs();
@@ -871,6 +952,12 @@ async function launch(inst, runtimeOverride) {
871
952
  }
872
953
  const runtime = await chooseRuntimeForLaunch(inst, runtimeOverride);
873
954
  if (!runtime) return;
955
+ if (runtime === "claude-code" && isLinkedGitWorktree(inst.path)) {
956
+ die(
957
+ "Claude Code automatically removes linked Git worktrees when its worktree session ends.\n" +
958
+ " Launch Claude from a standalone clone of this branch instead; Codex, Pi, and Prime may use this worktree directly.",
959
+ );
960
+ }
874
961
  if (runtime === "claude-code") {
875
962
  normalizeClaudeDenyRules(inst.path);
876
963
  ensureClaudeModeStatusLine(inst.path);
@@ -886,7 +973,9 @@ async function launch(inst, runtimeOverride) {
886
973
  }
887
974
  if (runtime === "codex") {
888
975
  if (!hasCodexCoreSupport(inst.path)) {
889
- die(codexSupportMessage(inst.path));
976
+ if (!repairPortableRuntime(inst.path, runtime) || !hasCodexCoreSupport(inst.path)) {
977
+ die(codexSupportMessage(inst.path));
978
+ }
890
979
  }
891
980
  const skillsInstalled = installCodexSkills(inst.path);
892
981
  const cardRendered = await renderCodexStartupCard(inst.path);
@@ -894,7 +983,10 @@ async function launch(inst, runtimeOverride) {
894
983
  die(codexSupportMessage(inst.path));
895
984
  }
896
985
  } else if (runtime === "pi") {
897
- if (!hasPiCoreSupport(inst.path)) die(piSupportMessage(inst.path));
986
+ if (!hasPiCoreSupport(inst.path) &&
987
+ (!repairPortableRuntime(inst.path, runtime) || !hasPiCoreSupport(inst.path))) {
988
+ die(piSupportMessage(inst.path));
989
+ }
898
990
  }
899
991
  let launchArgs = null;
900
992
  if (runtime === "prime") {
@@ -903,7 +995,10 @@ async function launch(inst, runtimeOverride) {
903
995
  // check + the trust-flag probe, which shells out to the binary), then a
904
996
  // single handoff line explains the remaining in-harness startup.
905
997
  const stopLoader = startSpinner("Starting Prime Agent");
906
- const coreOk = hasPrimeCoreSupport(inst.path);
998
+ let coreOk = hasPrimeCoreSupport(inst.path);
999
+ if (!coreOk && repairPortableRuntime(inst.path, runtime)) {
1000
+ coreOk = hasPrimeCoreSupport(inst.path);
1001
+ }
907
1002
  launchArgs = coreOk ? runtimeLaunchArgs(runtime, inst.path) : null;
908
1003
  stopLoader();
909
1004
  if (!coreOk) die(primeSupportMessage(inst.path));
@@ -918,9 +1013,12 @@ async function launch(inst, runtimeOverride) {
918
1013
  const launchEnv = {
919
1014
  ...process.env,
920
1015
  EGREGORE_RUNTIME: runtime,
1016
+ EGREGORE_TRANSIENT_CHECKOUT: inst.transientWorktree ? "1" : process.env.EGREGORE_TRANSIENT_CHECKOUT,
921
1017
  EGREGORE_CODEX_TRUSTED: runtime === "codex" ? "1" : process.env.EGREGORE_CODEX_TRUSTED,
922
1018
  };
923
- const child = spawn(binary, launchArgs || runtimeLaunchArgs(runtime, inst.path), {
1019
+ const child = spawn(binary, launchArgs || runtimeLaunchArgs(runtime, inst.path, {
1020
+ bypassHookTrust: runtime === "codex" && Boolean(inst.transientWorktree),
1021
+ }), {
924
1022
  cwd: inst.path,
925
1023
  stdio: "inherit",
926
1024
  env: launchEnv,
@@ -1049,8 +1147,11 @@ function cmdHelp() {
1049
1147
  ` ${CYAN}egregore ls${RESET} ${DIM}| list${RESET} list installed instances`,
1050
1148
  ` ${CYAN}egregore use${RESET} ${DIM}<slug>${RESET} set the default for bare ${BOLD}egregore${RESET}`,
1051
1149
  ` ${CYAN}egregore connect${RESET} ${DIM}[slug]${RESET} activate Connected for an existing instance`,
1150
+ ` ${CYAN}egregore telemetry${RESET} ${DIM}<verb>${RESET} status, inspect, enable, disable, export, or share`,
1151
+ ` ${CYAN}egregore runtime${RESET} ${DIM}<verb>${RESET} status, sync, start, or stop Local retrieval`,
1052
1152
  ` ${CYAN}egregore /invite${RESET} ${DIM}<user> [slug]${RESET} invite a GitHub user`,
1053
1153
  ` ${CYAN}egregore settings${RESET} ${DIM}[slug]${RESET} hosting on/off, repos, admins`,
1154
+ ` ${CYAN}egregore settings${RESET} ${DIM}<slug> runtime${RESET} Runtime update: review, prepare, activate, roll back`,
1054
1155
  ` ${CYAN}egregore prune${RESET} ${DIM}[--dry-run]${RESET} remove entries with missing paths`,
1055
1156
  ` ${CYAN}egregore rm${RESET} ${DIM}<slug|path>${RESET} remove a specific entry`,
1056
1157
  ``,
@@ -2085,6 +2186,79 @@ async function cmdInvite(args) {
2085
2186
  return inviteToInstance(inst, username);
2086
2187
  }
2087
2188
 
2189
+ function cmdTelemetry(args) {
2190
+ const registry = readRegistry();
2191
+ if (registry.length === 0) die("no egregores installed yet.\n run: npx -y create-egregore@latest");
2192
+
2193
+ const forwarded = args.slice();
2194
+ let instanceQuery = "";
2195
+ const marker = forwarded.indexOf("--instance");
2196
+ if (marker !== -1) {
2197
+ instanceQuery = forwarded[marker + 1] || "";
2198
+ if (!instanceQuery) die("usage: egregore telemetry <verb> [args] --instance <slug>");
2199
+ forwarded.splice(marker, 2);
2200
+ }
2201
+ if (forwarded.length === 0) forwarded.push("status");
2202
+
2203
+ const inst = resolveInviteInstance(registry, instanceQuery);
2204
+ if (!inst) {
2205
+ die("multiple egregores installed; choose one:\n egregore telemetry <verb> --instance <slug>\n run: egregore ls");
2206
+ }
2207
+ const script = path.join(inst.path, "bin", "telemetry.sh");
2208
+ if (!fs.existsSync(script)) {
2209
+ die("bin/telemetry.sh not found — update this Egregore before managing telemetry");
2210
+ }
2211
+ const result = spawnSync("bash", [script, ...forwarded], {
2212
+ cwd: inst.path,
2213
+ stdio: "inherit",
2214
+ env: { ...process.env },
2215
+ });
2216
+ if (result.error) die(`telemetry command failed: ${result.error.message}`);
2217
+ process.exitCode = result.status ?? 1;
2218
+ }
2219
+
2220
+ function cmdRuntime(args) {
2221
+ const registry = readRegistry();
2222
+ if (registry.length === 0) die("no egregores installed yet.\n run: npx -y create-egregore@latest");
2223
+
2224
+ const forwarded = args.slice();
2225
+ let instanceQuery = "";
2226
+ const marker = forwarded.indexOf("--instance");
2227
+ if (marker !== -1) {
2228
+ instanceQuery = forwarded[marker + 1] || "";
2229
+ if (!instanceQuery) die("usage: egregore runtime <status|sync|start|stop> --instance <slug>");
2230
+ forwarded.splice(marker, 2);
2231
+ }
2232
+ const verb = forwarded[0] || "status";
2233
+ if (!["status", "sync", "start", "stop", "update"].includes(verb) || forwarded.length > 1) {
2234
+ die("usage: egregore runtime <status|sync|start|stop> [--instance <slug>]");
2235
+ }
2236
+ const inst = resolveInviteInstance(registry, instanceQuery);
2237
+ if (!inst) {
2238
+ die("multiple egregores installed; choose one:\n egregore runtime status --instance <slug>\n run: egregore ls");
2239
+ }
2240
+
2241
+ let script;
2242
+ let scriptArgs;
2243
+ if (verb === "sync" || verb === "update") {
2244
+ script = path.join(inst.path, "bin", "agent.sh");
2245
+ scriptArgs = ["sync"];
2246
+ } else {
2247
+ script = path.join(inst.path, "bin", "search.sh");
2248
+ scriptArgs = [verb];
2249
+ }
2250
+ if (!fs.existsSync(script)) {
2251
+ die("Local Runtime controls are missing — update this Egregore before managing retrieval");
2252
+ }
2253
+ const result = spawnSync("bash", [script, ...scriptArgs], {
2254
+ cwd: inst.path,
2255
+ stdio: "inherit",
2256
+ env: { ...process.env },
2257
+ });
2258
+ if (result.error) die(`runtime command failed: ${result.error.message}`);
2259
+ process.exitCode = result.status ?? 1;
2260
+ }
2261
+
2088
2262
  // ── settings ───────────────────────────────────────────────────────
2089
2263
  //
2090
2264
  // The launcher stays a THIN caller: every config change shells out to the
@@ -2102,7 +2276,7 @@ function runSettings(inst, args) {
2102
2276
  return { status: 127, stdout: "", stderr: "bin/settings.sh not found — update this egregore (run /pull) to get settings.\n", missing: true };
2103
2277
  }
2104
2278
  try {
2105
- return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 15000 });
2279
+ return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 45000 });
2106
2280
  } catch (err) {
2107
2281
  return { status: 1, stdout: "", stderr: String(err) };
2108
2282
  }
@@ -2114,17 +2288,440 @@ function settingsDump(inst) {
2114
2288
  try { return JSON.parse(r.stdout); } catch { return null; }
2115
2289
  }
2116
2290
 
2291
+ // ── runtime upgrade (per-instance, settings-first) ──────────────────
2292
+ // The launcher stays a thin caller: the transactional engine, gates,
2293
+ // activation, and rollback live in the instance's Python Runtime behind
2294
+ // bin/runtime-upgrade.sh. The launcher renders that state and forwards
2295
+ // explicit verbs — one source of truth, no JS reimplementation.
2296
+
2297
+ const RUNTIME_MVP_VERSION_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-runtime-mvp\.(0|[1-9]\d*)$/;
2298
+ const RUNTIME_MVP_REGISTRY_URL = process.env.EGREGORE_RUNTIME_MVP_REGISTRY_URL
2299
+ || "https://registry.npmjs.org/create-egregore/runtime-mvp";
2300
+
2301
+ function upgradeScriptPath(inst) {
2302
+ return path.join(inst.path, "bin", "runtime-upgrade.sh");
2303
+ }
2304
+
2305
+ // After the Runtime cutover, a Connected instance's hosted link no longer
2306
+ // serves retrieval — saying "hosted graph active" would misstate what the
2307
+ // connection is for. Mirror the shell gate (bin/search.sh): stable org
2308
+ // identity composed with the main installation path keys the activation
2309
+ // record; only a real record flips the wording.
2310
+ function upgradedGraphRetrievalOff(instPath) {
2311
+ try {
2312
+ const cfg = JSON.parse(fs.readFileSync(path.join(instPath, "egregore.json"), "utf-8"));
2313
+ const orgId = String(cfg.org_id || "").trim();
2314
+ if (!orgId) return false;
2315
+ let main = instPath;
2316
+ const gitFile = path.join(instPath, ".git");
2317
+ if (fs.existsSync(gitFile) && fs.statSync(gitFile).isFile()) {
2318
+ const m = /^gitdir: (.*)$/m.exec(fs.readFileSync(gitFile, "utf-8"));
2319
+ if (m && m[1].includes("/.git/worktrees/")) main = m[1].split("/.git/worktrees/")[0];
2320
+ }
2321
+ main = fs.realpathSync(main);
2322
+ const key = crypto.createHash("sha256").update(`${orgId}|${main}`).digest("hex").slice(0, 16);
2323
+ const base = process.env.EGREGORE_UPGRADE_ROOT || path.join(os.homedir(), ".egregore", "runtime", "upgrade");
2324
+ const record = JSON.parse(fs.readFileSync(path.join(base, key, "active.json"), "utf-8"));
2325
+ return record.retrieval === "runtime-qmd";
2326
+ } catch {
2327
+ return false;
2328
+ }
2329
+ }
2330
+
2331
+ function connectedModeSuffix(instPath) {
2332
+ return upgradedGraphRetrievalOff(instPath)
2333
+ ? "· hosted services · graph retrieval off"
2334
+ : "· hosted graph active";
2335
+ }
2336
+
2337
+ // An instance that predates the bridge (0.20.1 and earlier) is still
2338
+ // upgradable: the installed launcher package carries the candidate's own
2339
+ // engine, so the bootstrap never depends on a git sync delivering it.
2340
+ // EGREGORE_RUNTIME_PACKAGED_BRIDGE is the test seam ("" disables).
2341
+ function packagedUpgradeScript() {
2342
+ const seeded = process.env.EGREGORE_RUNTIME_PACKAGED_BRIDGE;
2343
+ if (seeded !== undefined) return seeded || null;
2344
+ const script = path.join(__dirname, "..", "runtime", "claude", "bin", "runtime-upgrade.sh");
2345
+ return fs.existsSync(script) ? script : null;
2346
+ }
2347
+
2348
+ function resolveUpgradeBridge(inst) {
2349
+ const own = upgradeScriptPath(inst);
2350
+ if (fs.existsSync(own)) return { script: own, env: {} };
2351
+ const packaged = packagedUpgradeScript();
2352
+ if (packaged && fs.existsSync(packaged)) {
2353
+ return { script: packaged, env: { EGREGORE_INSTANCE_ROOT: inst.path } };
2354
+ }
2355
+ return null;
2356
+ }
2357
+
2358
+ function runUpgrade(inst, args, timeout = 60000) {
2359
+ const bridge = resolveUpgradeBridge(inst);
2360
+ if (!bridge) {
2361
+ return { status: 127, stdout: "", stderr: "Runtime update is unavailable — no upgrade engine in this egregore or the installed launcher package.\n", missing: true };
2362
+ }
2363
+ try {
2364
+ return spawnSync("bash", [bridge.script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout, env: { ...process.env, ...bridge.env } });
2365
+ } catch (err) {
2366
+ return { status: 1, stdout: "", stderr: String(err) };
2367
+ }
2368
+ }
2369
+
2370
+ // ── privacy & access + telemetry (Settings sections) ───────────────
2371
+ // Thin callers over deterministic adapters: bin/settings.sh privacy and
2372
+ // bin/telemetry.sh. The Runtime authorization backend supplies identity,
2373
+ // membership, and capability truth; the launcher only renders it. No model
2374
+ // round-trip, no raw JSON shown, no secrets or internal paths.
2375
+
2376
+ function runTelemetry(inst, args) {
2377
+ const script = path.join(inst.path, "bin", "telemetry.sh");
2378
+ if (!fs.existsSync(script)) return { status: 127, stdout: "", stderr: "telemetry adapter unavailable\n" };
2379
+ try {
2380
+ return spawnSync("bash", [script, ...args], { cwd: inst.path, stdio: "pipe", encoding: "utf-8", timeout: 15000 });
2381
+ } catch (err) {
2382
+ return { status: 1, stdout: "", stderr: String(err) };
2383
+ }
2384
+ }
2385
+
2386
+ function privacySnapshot(inst) {
2387
+ const r = runSettings(inst, ["privacy"]);
2388
+ if (!r || r.status !== 0 || !r.stdout) return null;
2389
+ try { return JSON.parse(r.stdout); } catch { return null; }
2390
+ }
2391
+
2392
+ function telemetrySnapshot(inst) {
2393
+ const r = runTelemetry(inst, ["status", "--json"]);
2394
+ if (!r || r.status !== 0 || !r.stdout) return null;
2395
+ try { return JSON.parse(r.stdout); } catch { return null; }
2396
+ }
2397
+
2398
+ function formatPrivacyLines(snapshot) {
2399
+ if (!snapshot) return ["Privacy & access state is unavailable for this egregore."];
2400
+ const a = snapshot.access || {};
2401
+ const b = snapshot.boundary || {};
2402
+ const lines = [];
2403
+ if (a.status !== "ok") {
2404
+ lines.push("Access needs attention — identity could not be resolved.");
2405
+ return lines;
2406
+ }
2407
+ lines.push(`Member: ${a.display_name || "unknown"}`);
2408
+ lines.push(`Organization: ${a.org_name || "unknown"} — membership ${a.membership_status || "unknown"}`);
2409
+ lines.push(`Details: actor ${String(a.actor_id || "").slice(0, 18)}…`);
2410
+ lines.push("");
2411
+ const caps = a.capabilities || {};
2412
+ const capLine = ["read", "create", "update", "publish", "notify", "org_settings"]
2413
+ .map((k) => `${k.replace("_", " ")} ${caps[k] ? "yes" : "no"}`)
2414
+ .join(" · ");
2415
+ lines.push(`Authorized capabilities: ${capLine}`);
2416
+ lines.push("For publish and notify, yes means you may request the action —");
2417
+ lines.push("every delivery still needs its own explicit approval.");
2418
+ lines.push("Custom roles: not enabled in this MVP.");
2419
+ lines.push(a.admin ? "Admin content: visible (you are an organization admin)" : "Admin content: hidden on Egregore surfaces");
2420
+ lines.push("");
2421
+ lines.push("Shared memory: available to authorized organization members");
2422
+ lines.push("Per-document restrictions: not enabled (raw repository access is organization-wide)");
2423
+ lines.push("Admin-marked content: hidden in Egregore surfaces from non-admin members");
2424
+ lines.push("External publication of admin-marked content: blocked unless an authorized admin separately confirms");
2425
+ lines.push("Publications require approval; notifications require separate exact approval.");
2426
+ lines.push("");
2427
+ lines.push(`Boundary posture: ${b.posture || "standard"}${b.locked ? " · organization policy locked" : ""}`);
2428
+ lines.push(`Other Egregore instances: ${snapshot.isolation ? snapshot.isolation.foreign_instances_denied : 0} isolated (hard, no consent path)`);
2429
+ const orgRoots = (b.org_read_roots || []).length;
2430
+ const personalRoots = b.personal_read_roots || [];
2431
+ lines.push(`Organization read roots: ${orgRoots} (managed by your organization)`);
2432
+ lines.push(`Personal read roots: ${personalRoots.length ? personalRoots.join(", ") : "none"}`);
2433
+ lines.push(
2434
+ snapshot.graph_retrieval === "not-used-by-this-runtime"
2435
+ ? "Graph retrieval: not used by this Runtime"
2436
+ : "Graph retrieval: legacy configuration",
2437
+ );
2438
+ return lines;
2439
+ }
2440
+
2441
+ function telemetryEvents(inst, n = 50) {
2442
+ const r = runTelemetry(inst, ["inspect", String(n), "--json"]);
2443
+ if (!r || r.status !== 0 || !r.stdout) return [];
2444
+ try {
2445
+ const events = JSON.parse(r.stdout);
2446
+ return Array.isArray(events) ? events : [];
2447
+ } catch { return []; }
2448
+ }
2449
+
2450
+ function formatEventRow(event) {
2451
+ const at = String(event.occurred_at || "").replace("T", " ").slice(0, 16) || "????-?? ??:??";
2452
+ const metrics = event.metrics || {};
2453
+ const what = metrics.command || metrics.subcommand || metrics.action || "";
2454
+ const extras = [];
2455
+ if (metrics.duration_ms != null) extras.push(`${metrics.duration_ms}ms`);
2456
+ if (metrics.model) extras.push(String(metrics.model));
2457
+ if (metrics.result) extras.push(String(metrics.result));
2458
+ return `${at} ${pad(String(event.event_type || "event"), 12)} ${pad(String(what), 16)} ${extras.join(" · ")}`;
2459
+ }
2460
+
2461
+ function listSubdirectories(dir, showHidden) {
2462
+ try {
2463
+ return fs.readdirSync(dir, { withFileTypes: true })
2464
+ .filter((entry) => entry.isDirectory() && (showHidden || !entry.name.startsWith(".")))
2465
+ .map((entry) => entry.name)
2466
+ .sort();
2467
+ } catch { return []; }
2468
+ }
2469
+
2470
+ function formatTelemetryLines(status) {
2471
+ if (!status) return ["Telemetry state is unavailable for this egregore."];
2472
+ const lines = [];
2473
+ lines.push(`Telemetry: ${status.enabled ? "On" : "Off"}${status.reason ? ` (${status.reason})` : ""}`);
2474
+ lines.push(`Notice shown: ${status.notice_shown ? "yes" : "not yet"}`);
2475
+ lines.push(
2476
+ status.buffered_events > 0
2477
+ ? `Local events waiting: ${status.buffered_events}`
2478
+ : "No buffered events",
2479
+ );
2480
+ if (status.last_event_at) lines.push(`Last event: ${status.last_event_at}`);
2481
+ lines.push("Events are held in a local buffer and never shared automatically.");
2482
+ lines.push("Collected: command names, timings, counts, model tiers — documented metadata only.");
2483
+ lines.push("Never collected: file contents, code, prompts, document excerpts,");
2484
+ lines.push("environment values, credentials, message bodies, personal memory content.");
2485
+ lines.push("Turning telemetry on or off is a personal setting for this member only.");
2486
+ return lines;
2487
+ }
2488
+
2489
+ function upgradeStatus(inst, { fetch = false } = {}) {
2490
+ const args = ["status"]; if (fetch) args.push("--fetch");
2491
+ const r = runUpgrade(inst, args);
2492
+ if (!r || r.status !== 0 || !r.stdout) return null;
2493
+ try { return JSON.parse(r.stdout); } catch { return null; }
2494
+ }
2495
+
2496
+ function upgradeStatusAsync(inst, cb) {
2497
+ const bridge = resolveUpgradeBridge(inst);
2498
+ if (!bridge) return cb(null);
2499
+ let buf = "";
2500
+ try {
2501
+ const child = spawn("bash", [bridge.script, "status"], { cwd: inst.path, stdio: ["ignore", "pipe", "ignore"], env: { ...process.env, ...bridge.env } });
2502
+ child.stdout.on("data", (d) => { buf += d; });
2503
+ child.on("close", () => { try { cb(JSON.parse(buf)); } catch { cb(null); } });
2504
+ child.on("error", () => cb(null));
2505
+ } catch { cb(null); }
2506
+ }
2507
+
2508
+ // Exact candidate resolution: the runtime-mvp dist-tag only, validated
2509
+ // against the prerelease scheme — never latest, never a retired scheme.
2510
+ // EGREGORE_RUNTIME_MVP_CANDIDATE is the offline/test seam.
2511
+ async function fetchRuntimeMvpCandidate() {
2512
+ const seeded = process.env.EGREGORE_RUNTIME_MVP_CANDIDATE;
2513
+ if (seeded !== undefined) return RUNTIME_MVP_VERSION_RE.test(seeded) ? seeded : null;
2514
+ try {
2515
+ const url = new URL(RUNTIME_MVP_REGISTRY_URL);
2516
+ const result = await requestJson({
2517
+ hostname: url.hostname,
2518
+ port: url.port || undefined,
2519
+ path: `${url.pathname}${url.search}`,
2520
+ method: "GET",
2521
+ protocol: url.protocol,
2522
+ timeoutMs: 1500,
2523
+ unref: true,
2524
+ headers: { Accept: "application/json" },
2525
+ });
2526
+ const version = result.status === 200 && result.data && result.data.version;
2527
+ return version && RUNTIME_MVP_VERSION_RE.test(version) ? version : null;
2528
+ } catch {
2529
+ return null;
2530
+ }
2531
+ }
2532
+
2533
+ const UPGRADE_STATUS_LABEL = {
2534
+ none: "no update staged",
2535
+ pending: "staged, not started",
2536
+ preparing: "preparing…",
2537
+ interrupted: "interrupted — resume to continue",
2538
+ failed: "needs attention",
2539
+ "ready-to-activate": "ready to activate",
2540
+ active: "active",
2541
+ cancelled: "cancelled",
2542
+ "rolled-back": "rolled back",
2543
+ };
2544
+
2545
+ function upgradeSummary(st) {
2546
+ if (!st || st.status === "none") return "up to date";
2547
+ if (st.status === "active") return `${st.active_version || "?"} active`;
2548
+ return UPGRADE_STATUS_LABEL[st.status] || st.status;
2549
+ }
2550
+
2551
+ function upgradeElapsed(st) {
2552
+ const worker = (st && st.worker) || {};
2553
+ const from = worker.started_at || st?.started_at;
2554
+ if (!from) return "";
2555
+ const s = Math.max(0, Math.floor(Date.now() / 1000 - from));
2556
+ return s >= 3600 ? `${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m` : s >= 60 ? `${Math.floor(s / 60)}m ${s % 60}s` : `${s}s`;
2557
+ }
2558
+
2559
+ // Plain-language body shared by the non-interactive `settings <slug> runtime`
2560
+ // output and the interactive panel. Returns undecorated strings; callers add
2561
+ // color. Never JSON, never internal paths beyond the instance's own root.
2562
+ function formatUpgradeLines(inst, st, { candidate = "" } = {}) {
2563
+ const lines = [];
2564
+ const d = st || { status: "none" };
2565
+ lines.push(`Selected Egregore: ${inst.name || inst.slug} (${inst.slug || "?"})`);
2566
+ lines.push(`Location: ${inst.path}`);
2567
+ lines.push("");
2568
+ lines.push(`Runtime: ${d.active_version || "unknown"} active`
2569
+ + (d.candidate_version ? ` → candidate ${d.candidate_version}` : candidate ? ` → candidate ${candidate} available` : ""));
2570
+ lines.push(`Status: ${UPGRADE_STATUS_LABEL[d.status] || d.status}`);
2571
+ if (d.candidate_digest) lines.push(`Package digest: sha256 ${String(d.candidate_digest).slice(0, 16)}…`);
2572
+ if (d.failure && d.failure.message) lines.push(`Attention: ${d.failure.message}`);
2573
+ if (d.rollback_version && d.status !== "none") lines.push(`Rollback target: ${d.rollback_version}`);
2574
+ const ts = d.team_sync;
2575
+ if (ts && ts.label) lines.push(`Team memory: ${ts.label}`);
2576
+ if (d.status === "active") {
2577
+ lines.push("Organizational retrieval: Runtime/QMD");
2578
+ lines.push("Graph retrieval: not used by this Runtime version");
2579
+ } else if (d.status !== "none") {
2580
+ lines.push("Previous Runtime remains active until activation.");
2581
+ }
2582
+ if (Array.isArray(d.stages) && d.status !== "none" && d.status !== "active") {
2583
+ lines.push("");
2584
+ for (const stage of d.stages) {
2585
+ const glyph = stage.state === "done" ? "✓" : stage.state === "running" ? "◦" : stage.state === "failed" ? "✗" : "·";
2586
+ let detail = "";
2587
+ if (stage.key === "embed" || stage.key === "delta") {
2588
+ const p = d.progress || {};
2589
+ if (stage.state === "running") {
2590
+ const parts = [];
2591
+ if (p.vectors) parts.push(`${p.vectors} chunks embedded`);
2592
+ if (p.pending) parts.push(`${p.pending} pending`);
2593
+ parts.push(`${upgradeElapsed(d)} elapsed`);
2594
+ detail = ` — ${parts.join(" · ")}`;
2595
+ } else if (stage.state === "done" && stage.detail) {
2596
+ detail = ` — ${stage.detail}`;
2597
+ }
2598
+ } else if (stage.state === "failed" && stage.detail) {
2599
+ detail = ` — ${stage.detail}`;
2600
+ }
2601
+ lines.push(` ${glyph} ${stage.label}${detail}`);
2602
+ }
2603
+ }
2604
+ return lines;
2605
+ }
2606
+
2607
+ const UPGRADE_STAYS = [
2608
+ "Your team memory and organizational history",
2609
+ "Your identity and organization membership",
2610
+ "Permissions and authorization",
2611
+ "Projects, handoffs, and artifacts",
2612
+ "Connection configuration",
2613
+ "The current Runtime, until the new one is fully ready",
2614
+ ];
2615
+ const UPGRADE_CHANGES = [
2616
+ "Runtime version",
2617
+ "Organizational retrieval moves to Runtime/QMD",
2618
+ "Keyword and meaning search become owned by this Egregore",
2619
+ "Graph retrieval stops after activation (kept only for rollback)",
2620
+ "Cross-session continuity uses the new Runtime",
2621
+ "Readiness and synchronization become visible here in Settings",
2622
+ ];
2623
+
2624
+ async function cmdSettingsRuntime(inst, args) {
2625
+ const action = args[0] || "status";
2626
+ const fetchFlag = args.includes("--fetch");
2627
+ const emit = (st, extra = {}) => {
2628
+ for (const line of formatUpgradeLines(inst, st, extra)) process.stdout.write(line + "\n");
2629
+ };
2630
+ if (action === "status" || action === "review") {
2631
+ const st = upgradeStatus(inst, { fetch: fetchFlag });
2632
+ if (st === null) { process.stderr.write("Runtime update state is unavailable for this egregore.\n"); process.exitCode = 1; return; }
2633
+ emit(st);
2634
+ if (action === "review" || (st.status !== "active" && st.status !== "none")) {
2635
+ process.stdout.write("\nWhat stays:\n");
2636
+ for (const s of UPGRADE_STAYS) process.stdout.write(` · ${s}\n`);
2637
+ process.stdout.write("What changes:\n");
2638
+ for (const c of UPGRADE_CHANGES) process.stdout.write(` · ${c}\n`);
2639
+ }
2640
+ return;
2641
+ }
2642
+ if (action === "init") {
2643
+ const version = (args[1] || "").trim();
2644
+ const tarball = (args[2] || "").trim();
2645
+ if (!RUNTIME_MVP_VERSION_RE.test(version)) {
2646
+ process.stderr.write("Runtime update needs an exact candidate like 0.21.0-runtime-mvp.1.\n");
2647
+ process.exitCode = 1; return;
2648
+ }
2649
+ if (!tarball || !fs.existsSync(tarball)) {
2650
+ process.stderr.write("Runtime update installs actual packaged bytes: egregore settings <slug> runtime init <version> <candidate.tgz>\n");
2651
+ process.exitCode = 1; return;
2652
+ }
2653
+ const r = runUpgrade(inst, ["init", "--candidate", version, "--tarball", path.resolve(tarball)]);
2654
+ if (r.status !== 0) { process.stderr.write(r.stderr || "could not stage the candidate\n"); process.exitCode = r.status; return; }
2655
+ emit(upgradeStatus(inst) || null);
2656
+ return;
2657
+ }
2658
+ if (["prepare", "activate", "cancel", "rollback"].includes(action)) {
2659
+ const r = runUpgrade(inst, [action]);
2660
+ if (r.status !== 0) { process.stderr.write(r.stderr || `${action} failed\n`); process.exitCode = r.status; return; }
2661
+ const st = upgradeStatus(inst);
2662
+ emit(st);
2663
+ if (action === "activate" && st && st.status === "active") {
2664
+ process.stdout.write("\nUpdate complete. Start a session to work on the new Runtime.\n");
2665
+ }
2666
+ return;
2667
+ }
2668
+ process.stderr.write("usage: egregore settings <slug> runtime [status|review|init <version>|prepare|activate|cancel|rollback]\n");
2669
+ process.exitCode = 2;
2670
+ }
2671
+
2117
2672
  async function cmdSettings(args) {
2118
2673
  const registry = readRegistry();
2119
2674
  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"]);
2675
+ const DOMAINS = new Set(["hosting", "workflow", "repo", "admin", "people", "dump", "runtime", "privacy", "telemetry", "boundary"]);
2121
2676
  let rest = args.slice();
2122
2677
  let slug = "";
2123
2678
  if (rest.length && !DOMAINS.has(rest[0])) { slug = rest[0]; rest = rest.slice(1); }
2124
2679
  const inst = resolveInviteInstance(registry, slug);
2125
2680
  if (!inst) {
2126
- die(`multiple egregores installed; choose one:\n egregore settings <slug> [hosting|repo|admin]\n run: egregore ls`);
2681
+ die(`multiple egregores installed; choose one:\n egregore settings <slug> [runtime|hosting|workflow|repo|admin|people|privacy|telemetry]\n run: egregore ls`);
2682
+ }
2683
+ // Runtime update is Runtime-owned state, not org config — it routes to the
2684
+ // upgrade bridge instead of bin/settings.sh.
2685
+ if (rest[0] === "runtime") return cmdSettingsRuntime(inst, rest.slice(1));
2686
+ // Privacy & access: rendered plain-language snapshot backed by the Runtime
2687
+ // authorization decision — never raw JSON, secrets, or internal paths.
2688
+ if (rest[0] === "privacy") {
2689
+ for (const line of formatPrivacyLines(privacySnapshot(inst))) console.log(line);
2690
+ return;
2127
2691
  }
2692
+ // Telemetry: personal, opt-out, content-free. Mutations require the exact
2693
+ // --confirm because a non-interactive verb has no y/N checkpoint.
2694
+ if (rest[0] === "telemetry") {
2695
+ const verb = rest[1] || "status";
2696
+ if (verb === "status") {
2697
+ for (const line of formatTelemetryLines(telemetrySnapshot(inst))) console.log(line);
2698
+ return;
2699
+ }
2700
+ if (verb === "inspect") {
2701
+ const n = /^\d+$/.test(rest[2] || "") ? Number(rest[2]) : 20;
2702
+ const events = telemetryEvents(inst, n);
2703
+ if (!events.length) { console.log("No buffered events."); return; }
2704
+ for (const event of events) console.log(formatEventRow(event));
2705
+ return;
2706
+ }
2707
+ if (verb === "on" || verb === "off" || verb === "clear") {
2708
+ if (!rest.includes("--confirm")) {
2709
+ const what = verb === "clear"
2710
+ ? `delete ${(telemetrySnapshot(inst) || {}).buffered_events || 0} locally buffered event(s); nothing else is removed`
2711
+ : `turn telemetry ${verb} for this member only`;
2712
+ process.stderr.write(`this will ${what}.\nre-run with --confirm to proceed: egregore settings ${inst.slug} telemetry ${verb} --confirm\n`);
2713
+ process.exitCode = 1;
2714
+ return;
2715
+ }
2716
+ const r = runTelemetry(inst, [verb]);
2717
+ if (r.stdout) process.stdout.write(r.stdout);
2718
+ if (r.stderr) process.stderr.write(r.stderr);
2719
+ process.exitCode = r.status || 0;
2720
+ return;
2721
+ }
2722
+ die("usage: egregore settings <slug> telemetry [status|inspect [n]|on|off|clear] [--confirm]");
2723
+ }
2724
+
2128
2725
  // Interactive editing lives in the launcher (press `s`). With no verb, print
2129
2726
  // the snapshot; otherwise forward straight to the deterministic verb.
2130
2727
  if (rest.length === 0) rest = ["dump"];
@@ -2342,7 +2939,7 @@ function renderRuntimePanel({ inst, cursor, width, height }) {
2342
2939
  boxLine(`${DIM}${inst.path}${RESET}`, innerWidth, margin),
2343
2940
  boxLine(
2344
2941
  isConnectedInstance(inst)
2345
- ? `${CYAN}◆ CONNECTED${RESET} ${DIM}· hosted graph active${RESET}`
2942
+ ? `${CYAN}◆ CONNECTED${RESET} ${DIM}${connectedModeSuffix(inst.path)}${RESET}`
2346
2943
  : `${DIM}◇ LOCAL · Markdown + Git${RESET}`,
2347
2944
  innerWidth,
2348
2945
  margin,
@@ -2382,7 +2979,67 @@ const SETTINGS_DOMAIN_LABEL = { repo: "Managed repos", admin: "Admins", people:
2382
2979
  const SETTINGS_DOMAIN_NOUN = { repo: "repo name", admin: "github handle", people: "github handle" };
2383
2980
 
2384
2981
  // Same box geometry as renderRuntimePanel so pressing `s` keeps the frame put.
2385
- function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCursor, mode, input, notice, width }) {
2982
+ // Runtime-update panel: renders the durable upgrade state from the Python
2983
+ // engine. Same geometry as the settings panel; plain-language body from
2984
+ // formatUpgradeLines with launcher glyph decoration only.
2985
+ function renderUpgradePanel({ inst, data, candidate, mode, notice, width }) {
2986
+ const outerWidth = Math.min(Math.max(50, width - 2), 126);
2987
+ const innerWidth = Math.max(48, outerWidth - 2);
2988
+ const margin = " ".repeat(Math.max(0, Math.floor((width - outerWidth) / 2)));
2989
+ const label = " runtime update ";
2990
+ const lines = [
2991
+ `${margin}${DIM}┌${"─".repeat(2)}${label}${"─".repeat(Math.max(0, innerWidth - label.length - 2))}┐${RESET}`,
2992
+ emptyBoxLine(innerWidth, margin),
2993
+ ];
2994
+ const body = data === undefined
2995
+ ? ["Checking this egregore's Runtime state…"]
2996
+ : data === null
2997
+ ? ["Runtime update state is unavailable for this egregore."]
2998
+ : formatUpgradeLines(inst, data, { candidate });
2999
+ for (const raw of body) {
3000
+ let line = raw;
3001
+ if (/^ ✓ /.test(raw)) line = ` ${GREEN}✓${RESET} ${raw.slice(4)}`;
3002
+ else if (/^ ◦ /.test(raw)) line = ` ${CYAN}◦${RESET} ${raw.slice(4)}`;
3003
+ else if (/^ ✗ /.test(raw)) line = ` ${RED}✗${RESET} ${raw.slice(4)}`;
3004
+ else if (/^ · /.test(raw)) line = ` ${DIM}·${RESET} ${DIM}${raw.slice(4)}${RESET}`;
3005
+ else if (/^(Location|Rollback target):/.test(raw)) line = `${DIM}${raw}${RESET}`;
3006
+ lines.push(boxLine(line, innerWidth, margin));
3007
+ }
3008
+ const status = data && data.status;
3009
+ if (mode === "confirm-prepare") {
3010
+ lines.push(emptyBoxLine(innerWidth, margin));
3011
+ lines.push(boxLine(`${BOLD}What stays${RESET}`, innerWidth, margin));
3012
+ for (const s of UPGRADE_STAYS) lines.push(boxLine(` · ${s}`, innerWidth, margin));
3013
+ lines.push(boxLine(`${BOLD}What changes${RESET}`, innerWidth, margin));
3014
+ for (const c of UPGRADE_CHANGES) lines.push(boxLine(` · ${c}`, innerWidth, margin));
3015
+ lines.push(emptyBoxLine(innerWidth, margin));
3016
+ lines.push(boxLine(`${YELLOW}Prepare the update for ${BOLD}${inst.slug}${RESET}${YELLOW} at this location only?${RESET} ${DIM}y / N${RESET}`, innerWidth, margin));
3017
+ } else if (mode === "confirm-activate") {
3018
+ lines.push(emptyBoxLine(innerWidth, margin));
3019
+ lines.push(boxLine(`${YELLOW}Activate the new Runtime for ${BOLD}${inst.slug}${RESET}${YELLOW}?${RESET} ${DIM}y / N${RESET}`, innerWidth, margin));
3020
+ } else if (mode === "confirm-rollback") {
3021
+ lines.push(emptyBoxLine(innerWidth, margin));
3022
+ lines.push(boxLine(`${YELLOW}Roll ${BOLD}${inst.slug}${RESET}${YELLOW} back to ${data?.rollback_version || "the previous Runtime"}?${RESET} ${DIM}y / N${RESET}`, innerWidth, margin));
3023
+ } else if (mode === "confirm-cancel") {
3024
+ lines.push(emptyBoxLine(innerWidth, margin));
3025
+ lines.push(boxLine(`${YELLOW}Cancel preparation? The current Runtime stays untouched.${RESET} ${DIM}y / N${RESET}`, innerWidth, margin));
3026
+ } else {
3027
+ lines.push(emptyBoxLine(innerWidth, margin));
3028
+ if (notice) lines.push(boxLine(notice, innerWidth, margin));
3029
+ const keys = [];
3030
+ if (!status || status === "none" || ["pending", "failed", "interrupted", "cancelled", "rolled-back"].includes(status)) keys.push(`${BOLD}p${RESET}${DIM} prepare${RESET}`);
3031
+ if (status === "ready-to-activate") keys.push(`${BOLD}a${RESET}${DIM} activate${RESET}`);
3032
+ if (status === "preparing") keys.push(`${BOLD}c${RESET}${DIM} cancel${RESET}`);
3033
+ if (status === "active") keys.push(`${BOLD}r${RESET}${DIM} roll back${RESET}`);
3034
+ keys.push(`${DIM}← back · q quit${RESET}`);
3035
+ lines.push(boxLine(keys.join(`${DIM} · ${RESET}`), innerWidth, margin));
3036
+ }
3037
+ lines.push(emptyBoxLine(innerWidth, margin));
3038
+ lines.push(`${margin}${DIM}└${"─".repeat(innerWidth)}┘${RESET}`);
3039
+ return lines;
3040
+ }
3041
+
3042
+ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCursor, mode, input, notice, width, upgrade }) {
2386
3043
  const title = inst.slug || inst.name || path.basename(inst.path);
2387
3044
  const outerWidth = Math.min(Math.max(50, width - 2), 126);
2388
3045
  const innerWidth = Math.max(48, outerWidth - 2);
@@ -2397,6 +3054,114 @@ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCurs
2397
3054
  emptyBoxLine(innerWidth, margin),
2398
3055
  ];
2399
3056
 
3057
+ if (view === "privacy" || view === "telemetry") {
3058
+ lines.push(boxLine(`${BOLD}${view === "privacy" ? "Privacy & access" : "Telemetry"}${RESET}`, innerWidth, margin));
3059
+ lines.push(emptyBoxLine(innerWidth, margin));
3060
+ if (mode === "shareinfo") {
3061
+ const shareLines = (data && data.shareLines) || ["share proposal unavailable"];
3062
+ lines.push(boxLine(`${BOLD}Share proposal${RESET} ${DIM}(nothing has been sent)${RESET}`, innerWidth, margin));
3063
+ lines.push(emptyBoxLine(innerWidth, margin));
3064
+ for (const line of shareLines.slice(0, 16)) {
3065
+ lines.push(boxLine(`${line.includes("--confirm") ? "" : DIM}${line}${RESET}`, innerWidth, margin));
3066
+ }
3067
+ lines.push(emptyBoxLine(innerWidth, margin));
3068
+ lines.push(boxLine(`${DIM}Sharing completes only by running the confirm command above in a terminal. ← back${RESET}`, innerWidth, margin));
3069
+ lines.push(emptyBoxLine(innerWidth, margin));
3070
+ lines.push(`${margin}${DIM}└${"─".repeat(innerWidth)}┘${RESET}`);
3071
+ return lines;
3072
+ }
3073
+ if (mode === "events") {
3074
+ const events = (data && data.telemetryEvents) || [];
3075
+ lines.push(boxLine(`${BOLD}Local events${RESET} ${DIM}(newest last · nothing here ever uploads by itself)${RESET}`, innerWidth, margin));
3076
+ lines.push(emptyBoxLine(innerWidth, margin));
3077
+ if (!events.length) {
3078
+ lines.push(boxLine(`${DIM}(no buffered events)${RESET}`, innerWidth, margin));
3079
+ } else {
3080
+ const cursorAt = Math.min(listCursor || 0, events.length - 1);
3081
+ const windowSize = 12;
3082
+ const start = Math.max(0, Math.min(cursorAt - Math.floor(windowSize / 2), events.length - windowSize));
3083
+ events.slice(start, start + windowSize).forEach((event, i) => {
3084
+ const sel = start + i === cursorAt;
3085
+ lines.push(boxLine(`${sel ? `${CYAN}❯${RESET} ` : " "}${sel ? "" : DIM}${formatEventRow(event)}${RESET}`, innerWidth, margin));
3086
+ });
3087
+ if (events.length > windowSize) lines.push(boxLine(`${DIM}${cursorAt + 1}/${events.length}${RESET}`, innerWidth, margin));
3088
+ }
3089
+ lines.push(emptyBoxLine(innerWidth, margin));
3090
+ if (notice) lines.push(boxLine(notice, innerWidth, margin));
3091
+ lines.push(boxLine(`${DIM}↑↓ scroll · ${RESET}${BOLD}e${RESET}${DIM} export to file · ${RESET}${BOLD}s${RESET}${DIM} share (two-step consent) · ← back${RESET}`, innerWidth, margin));
3092
+ lines.push(emptyBoxLine(innerWidth, margin));
3093
+ lines.push(`${margin}${DIM}└${"─".repeat(innerWidth)}┘${RESET}`);
3094
+ return lines;
3095
+ }
3096
+ if (mode === "pickdir") {
3097
+ const pick = (data && data.dirPick) || { dir: os.homedir(), entries: [], cursor: 0, hidden: false };
3098
+ lines.push(boxLine(`${BOLD}Choose a directory to allow reading${RESET}`, innerWidth, margin));
3099
+ lines.push(boxLine(`${DIM}${pick.dir}${RESET}`, innerWidth, margin));
3100
+ lines.push(emptyBoxLine(innerWidth, margin));
3101
+ if (!pick.entries.length) {
3102
+ lines.push(boxLine(`${DIM}(no subdirectories${pick.hidden ? "" : " — press . to show hidden"})${RESET}`, innerWidth, margin));
3103
+ } else {
3104
+ const windowSize = 10;
3105
+ const start = Math.max(0, Math.min(pick.cursor - Math.floor(windowSize / 2), pick.entries.length - windowSize));
3106
+ pick.entries.slice(start, start + windowSize).forEach((name, i) => {
3107
+ const sel = start + i === pick.cursor;
3108
+ lines.push(boxLine(`${sel ? `${CYAN}❯${RESET} ` : " "}${sel ? BOLD : DIM}${name}/${RESET}`, innerWidth, margin));
3109
+ });
3110
+ }
3111
+ lines.push(emptyBoxLine(innerWidth, margin));
3112
+ if (notice) lines.push(boxLine(notice, innerWidth, margin));
3113
+ lines.push(boxLine(`${DIM}↑↓ nav · → enter descend · ← up · ${RESET}${BOLD}space${RESET}${DIM} allow this directory · . hidden · esc cancel${RESET}`, innerWidth, margin));
3114
+ lines.push(emptyBoxLine(innerWidth, margin));
3115
+ lines.push(`${margin}${DIM}└${"─".repeat(innerWidth)}┘${RESET}`);
3116
+ return lines;
3117
+ }
3118
+ if (mode === "pickroot") {
3119
+ const roots = (data && data.privacySnapshot && data.privacySnapshot.boundary && data.privacySnapshot.boundary.personal_read_roots) || [];
3120
+ lines.push(boxLine(`${BOLD}Remove a personal read root${RESET}`, innerWidth, margin));
3121
+ lines.push(emptyBoxLine(innerWidth, margin));
3122
+ if (!roots.length) {
3123
+ lines.push(boxLine(`${DIM}(no personal read roots)${RESET}`, innerWidth, margin));
3124
+ } else {
3125
+ roots.forEach((root, i) => {
3126
+ const sel = i === (listCursor || 0);
3127
+ lines.push(boxLine(`${sel ? `${CYAN}❯${RESET} ` : " "}${sel ? BOLD : DIM}${root}${RESET}`, innerWidth, margin));
3128
+ });
3129
+ }
3130
+ lines.push(emptyBoxLine(innerWidth, margin));
3131
+ if (notice) lines.push(boxLine(notice, innerWidth, margin));
3132
+ lines.push(boxLine(`${DIM}↑↓ nav · enter remove · esc cancel${RESET}`, innerWidth, margin));
3133
+ lines.push(emptyBoxLine(innerWidth, margin));
3134
+ lines.push(`${margin}${DIM}└${"─".repeat(innerWidth)}┘${RESET}`);
3135
+ return lines;
3136
+ }
3137
+ const body = view === "privacy" ? formatPrivacyLines(data && data.privacySnapshot) : formatTelemetryLines(data && data.telemetrySnapshot);
3138
+ for (const line of body) {
3139
+ lines.push(line === "" ? emptyBoxLine(innerWidth, margin) : boxLine(`${line.startsWith("Access needs") || line.startsWith("Telemetry needs") ? YELLOW : ""}${line}${RESET}`, innerWidth, margin));
3140
+ }
3141
+ lines.push(emptyBoxLine(innerWidth, margin));
3142
+ if (mode === "confirm" && input) {
3143
+ lines.push(boxLine(`${YELLOW}${input}${RESET}`, innerWidth, margin));
3144
+ } else if (mode === "input") {
3145
+ lines.push(boxLine(`${BOLD}directory:${RESET} ${input}${DIM}▌${RESET}`, innerWidth, margin));
3146
+ }
3147
+ if (notice) lines.push(boxLine(notice, innerWidth, margin));
3148
+ if (view === "privacy") {
3149
+ const locked = !!(data && data.privacySnapshot && data.privacySnapshot.boundary && data.privacySnapshot.boundary.locked);
3150
+ lines.push(boxLine(
3151
+ locked
3152
+ ? `${DIM}Boundary policy is managed by your organization. ← back · q quit${RESET}`
3153
+ : `${DIM}${RESET}${BOLD}a${RESET}${DIM} add personal read root · ${RESET}${BOLD}r${RESET}${DIM} remove · ← back · q quit${RESET}`,
3154
+ innerWidth, margin,
3155
+ ));
3156
+ } else {
3157
+ const on = !!(data && data.telemetrySnapshot && data.telemetrySnapshot.enabled);
3158
+ lines.push(boxLine(`${DIM}${RESET}${BOLD}i${RESET}${DIM} view events · ${RESET}${BOLD}t${RESET}${DIM} turn ${on ? "off" : "on"} · ${RESET}${BOLD}x${RESET}${DIM} clear local buffer · ← back · q quit${RESET}`, innerWidth, margin));
3159
+ }
3160
+ lines.push(emptyBoxLine(innerWidth, margin));
3161
+ lines.push(`${margin}${DIM}└${"─".repeat(innerWidth)}┘${RESET}`);
3162
+ return lines;
3163
+ }
3164
+
2400
3165
  if (view === "list") {
2401
3166
  lines.push(boxLine(`${BOLD}${SETTINGS_DOMAIN_LABEL[domain] || domain}${RESET}`, innerWidth, margin));
2402
3167
  lines.push(emptyBoxLine(innerWidth, margin));
@@ -2419,8 +3184,28 @@ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCurs
2419
3184
  lines.push(boxLine(`${DIM}↑↓ nav · ${RESET}${BOLD}a${RESET}${DIM} add · ${RESET}${BOLD}d${RESET}${DIM} delete · ← back · q quit${RESET}`, innerWidth, margin));
2420
3185
  }
2421
3186
  } else {
3187
+ const upgradeValue = upgrade === undefined
3188
+ ? `${DIM}checking…${RESET}`
3189
+ : upgrade === null
3190
+ ? `${DIM}unavailable${RESET}`
3191
+ : upgrade.status === "ready-to-activate"
3192
+ ? `${GREEN}${upgradeSummary(upgrade)}${RESET}`
3193
+ : upgrade.status === "failed" || upgrade.status === "interrupted"
3194
+ ? `${YELLOW}${upgradeSummary(upgrade)}${RESET}`
3195
+ : `${DIM}${upgradeSummary(upgrade)}${RESET}`;
2422
3196
  const rows = [
3197
+ { name: "Runtime update", value: upgradeValue },
3198
+ { name: "Privacy & access", value: `${DIM}identity · boundary · consent${RESET}` },
3199
+ { name: "Telemetry", value: `${DIM}personal · opt-out${RESET}` },
2423
3200
  { name: "Hosted Artifacts", value: (d.hosting !== false) ? `${GREEN}ON${RESET}` : `${YELLOW}OFF${RESET}` },
3201
+ {
3202
+ name: "Git workflow",
3203
+ value: d.workflow === "simple"
3204
+ ? `${DIM}PRs → main${RESET}`
3205
+ : d.workflow === "staged"
3206
+ ? `${DIM}PRs → develop → main${RESET}`
3207
+ : `${DIM}PRs → ${d.base_branch || "custom"}${RESET}`,
3208
+ },
2424
3209
  { name: "Managed repos", value: `${DIM}${(d.repos || []).length}${RESET}` },
2425
3210
  { name: "Admins", value: `${DIM}${(d.admins || []).length}${RESET}` },
2426
3211
  { name: "People", value: `${DIM}${(d.people || []).length}${RESET}` },
@@ -2433,7 +3218,7 @@ function renderSettingsPanel({ inst, data, cursor, view, domain, items, listCurs
2433
3218
  });
2434
3219
  lines.push(emptyBoxLine(innerWidth, margin));
2435
3220
  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));
3221
+ lines.push(boxLine(`${DIM}↑↓ nav · ${RESET}${BOLD}enter${RESET}${DIM} ${cursor === 3 || cursor === 4 ? "toggle" : "open"} · ← back · q quit${RESET}`, innerWidth, margin));
2437
3222
  }
2438
3223
 
2439
3224
  lines.push(emptyBoxLine(innerWidth, margin));
@@ -2558,6 +3343,22 @@ async function browser(args = {}) {
2558
3343
  return;
2559
3344
  }
2560
3345
 
3346
+ if (state.upgradeInst) {
3347
+ const upgradeLines = renderUpgradePanel({
3348
+ inst: state.upgradeInst,
3349
+ data: state.upgradeData,
3350
+ candidate: state.upgradeCandidate,
3351
+ mode: state.upgradeMode,
3352
+ notice: state.upgradeNotice,
3353
+ width: w,
3354
+ });
3355
+ for (const line of upgradeLines) out.push(line + ANSI.clearLine + "\n");
3356
+ const upgradeRemaining = Math.max(0, h - upgradeLines.length - 1);
3357
+ for (let i = 0; i < upgradeRemaining; i++) out.push(ANSI.clearLine + "\n");
3358
+ process.stdout.write(out.join(""));
3359
+ return;
3360
+ }
3361
+
2561
3362
  if (state.settingsInst) {
2562
3363
  const settingsLines = renderSettingsPanel({
2563
3364
  inst: state.settingsInst,
@@ -2571,6 +3372,7 @@ async function browser(args = {}) {
2571
3372
  input: state.settingsInput,
2572
3373
  notice: state.settingsNotice,
2573
3374
  width: w,
3375
+ upgrade: state.settingsUpgrade,
2574
3376
  });
2575
3377
  for (const line of settingsLines) out.push(line + ANSI.clearLine + "\n");
2576
3378
  const remainingRows = Math.max(0, h - settingsLines.length - 1);
@@ -2697,7 +3499,7 @@ async function browser(args = {}) {
2697
3499
  : ` ${label("path")} ${truncate(selected.path, valW)}`);
2698
3500
  if (pv.org) previewLines.push(` ${label("org")} ${truncate(`${pv.org} ${DIM}(${pv.githubOrg || "?"})${RESET}`, valW)}`);
2699
3501
  previewLines.push(pv.connected
2700
- ? ` ${label("mode")} ${CYAN}◆ CONNECTED${RESET} ${DIM}· hosted graph active${RESET}`
3502
+ ? ` ${label("mode")} ${CYAN}◆ CONNECTED${RESET} ${DIM}${connectedModeSuffix(selected.path)}${RESET}`
2701
3503
  : ` ${label("mode")} ${DIM}◇ LOCAL · Markdown + Git${RESET}`);
2702
3504
  if (pv.branch) previewLines.push(` ${label("branch")} ${BOLD}${pv.branch}${RESET}`);
2703
3505
  if (pv.lastCommit) previewLines.push(` ${label("last")} ${DIM}${truncate(pv.lastCommit, valW)}${RESET}`);
@@ -2798,9 +3600,27 @@ async function browser(args = {}) {
2798
3600
  const onResize = () => render(); // render() itself no-ops once done is set
2799
3601
  let onSigint;
2800
3602
  let onSigterm;
3603
+ const stopUpgradePoll = () => {
3604
+ if (state.upgradePoll) { clearInterval(state.upgradePoll); state.upgradePoll = null; }
3605
+ };
3606
+ const refreshUpgrade = () => {
3607
+ if (!state.upgradeInst) return;
3608
+ upgradeStatusAsync(state.upgradeInst, (st) => {
3609
+ if (!state.upgradeInst) return;
3610
+ state.upgradeData = st;
3611
+ if (st && st.status === "preparing") {
3612
+ if (!state.upgradePoll) state.upgradePoll = setInterval(refreshUpgrade, 2500);
3613
+ } else {
3614
+ stopUpgradePoll();
3615
+ }
3616
+ render();
3617
+ });
3618
+ };
3619
+
2801
3620
  const cleanup = () => {
2802
3621
  if (done) return;
2803
3622
  done = true;
3623
+ stopUpgradePoll();
2804
3624
  process.stdin.setRawMode(false);
2805
3625
  process.stdin.pause();
2806
3626
  process.stdin.removeAllListeners("keypress");
@@ -2854,11 +3674,195 @@ async function browser(args = {}) {
2854
3674
  if (!key) return;
2855
3675
  if (isMouseEvent(chunk, key)) return; // drop scroll-wheel / mouse escape sequences
2856
3676
 
3677
+ if (state.upgradeInst) {
3678
+ if (key.ctrl && key.name === "c") { cleanup(); process.exit(130); }
3679
+ if (key.name === "q") { cleanup(); resolve(); return; }
3680
+ if (state.upgradeMode && state.upgradeMode.startsWith("confirm-")) {
3681
+ const mode = state.upgradeMode;
3682
+ state.upgradeMode = "view";
3683
+ if (chunk === "y" || chunk === "Y") {
3684
+ const inst = state.upgradeInst;
3685
+ if (mode === "confirm-prepare") {
3686
+ const r = runUpgrade(inst, ["prepare"]);
3687
+ state.upgradeNotice = r.status === 0
3688
+ ? `${DIM}Preparing in the background — safe to leave this screen.${RESET}`
3689
+ : `${YELLOW}${(r.stderr || "prepare failed").trim().split("\n")[0]}${RESET}`;
3690
+ } else if (mode === "confirm-activate") {
3691
+ const r = runUpgrade(inst, ["activate"]);
3692
+ state.upgradeNotice = r.status === 0
3693
+ ? `${GREEN}Update complete. Start a session to work on the new Runtime.${RESET}`
3694
+ : `${YELLOW}${(r.stderr || "activation refused — a gate has not passed").trim().split("\n")[0]}${RESET}`;
3695
+ } else if (mode === "confirm-rollback") {
3696
+ const r = runUpgrade(inst, ["rollback"]);
3697
+ state.upgradeNotice = r.status === 0
3698
+ ? `${DIM}Rolled back. The previous Runtime is active again.${RESET}`
3699
+ : `${YELLOW}${(r.stderr || "rollback failed").trim().split("\n")[0]}${RESET}`;
3700
+ } else if (mode === "confirm-cancel") {
3701
+ runUpgrade(inst, ["cancel"]);
3702
+ state.upgradeNotice = `${DIM}Preparation cancelled. The current Runtime was never touched.${RESET}`;
3703
+ }
3704
+ refreshUpgrade();
3705
+ }
3706
+ render(); return;
3707
+ }
3708
+ if (key.name === "escape" || key.name === "left") {
3709
+ stopUpgradePoll();
3710
+ state.settingsUpgrade = state.upgradeData;
3711
+ state.upgradeInst = null; state.upgradeNotice = "";
3712
+ render(); return;
3713
+ }
3714
+ const status = state.upgradeData && state.upgradeData.status;
3715
+ if (chunk === "p" && (!status || ["none", "pending", "failed", "interrupted", "cancelled", "rolled-back"].includes(status))) {
3716
+ const staged = state.upgradeData
3717
+ && !["none", "cancelled", "rolled-back"].includes(status)
3718
+ && state.upgradeData.candidate_version;
3719
+ if (!staged) {
3720
+ state.upgradeNotice = `${DIM}Stage a candidate package first: egregore settings ${state.upgradeInst.slug} runtime init <version> <candidate.tgz>${RESET}`;
3721
+ render(); return;
3722
+ }
3723
+ state.upgradeMode = "confirm-prepare"; render(); return;
3724
+ }
3725
+ if (chunk === "a" && status === "ready-to-activate") { state.upgradeMode = "confirm-activate"; render(); return; }
3726
+ if (chunk === "c" && status === "preparing") { state.upgradeMode = "confirm-cancel"; render(); return; }
3727
+ if (chunk === "r" && status === "active") { state.upgradeMode = "confirm-rollback"; render(); return; }
3728
+ return;
3729
+ }
3730
+
2857
3731
  if (state.settingsInst) {
2858
3732
  const S = state;
2859
3733
  if (key.ctrl && key.name === "c") { cleanup(); process.exit(130); }
2860
3734
  if (key.name === "q") { cleanup(); resolve(); return; }
2861
3735
 
3736
+ if (S.settingsView === "privacy" || S.settingsView === "telemetry") {
3737
+ const backToMenu = () => {
3738
+ S.settingsView = "menu"; S.settingsMode = "browse"; S.settingsInput = ""; S.settingsNotice = ""; render();
3739
+ };
3740
+ const refreshPanel = () => {
3741
+ if (S.settingsView === "privacy") S.settingsData = { ...(S.settingsData || {}), privacySnapshot: privacySnapshot(S.settingsInst) };
3742
+ else S.settingsData = { ...(S.settingsData || {}), telemetrySnapshot: telemetrySnapshot(S.settingsInst) };
3743
+ };
3744
+ if (S.settingsMode === "events") {
3745
+ const events = (S.settingsData && S.settingsData.telemetryEvents) || [];
3746
+ if (key.name === "escape" || key.name === "left") { S.settingsMode = "browse"; S.settingsListCursor = 0; S.settingsNotice = ""; render(); return; }
3747
+ if (key.name === "up" || key.name === "k") { S.settingsListCursor = Math.max(0, (S.settingsListCursor || 0) - 1); render(); return; }
3748
+ if (key.name === "down" || key.name === "j") { S.settingsListCursor = Math.min(Math.max(0, events.length - 1), (S.settingsListCursor || 0) + 1); render(); return; }
3749
+ if (chunk === "e") {
3750
+ const stamp = new Date().toISOString().slice(0, 10);
3751
+ S.settingsPendingDir = path.join(os.homedir(), "Desktop", `egregore-telemetry-${S.settingsInst.slug}-${stamp}.jsonl`);
3752
+ S.settingsAction = "tele-export";
3753
+ S.settingsMode = "confirm";
3754
+ S.settingsInput = `Export ${events.length} local event(s) to ${S.settingsPendingDir}? [y/N]`;
3755
+ render(); return;
3756
+ }
3757
+ if (chunk === "s") {
3758
+ const r = runTelemetry(S.settingsInst, ["share"]);
3759
+ const shareLines = ((r && (r.stdout || r.stderr)) || "share preview unavailable").split("\n").filter(Boolean);
3760
+ S.settingsData = { ...(S.settingsData || {}), shareLines };
3761
+ S.settingsMode = "shareinfo"; S.settingsNotice = "";
3762
+ render(); return;
3763
+ }
3764
+ return;
3765
+ }
3766
+ if (S.settingsMode === "shareinfo") {
3767
+ if (key.name === "escape" || key.name === "left") { S.settingsMode = "events"; render(); return; }
3768
+ return;
3769
+ }
3770
+ if (S.settingsMode === "pickdir") {
3771
+ const pick = S.settingsData.dirPick;
3772
+ const reload = () => { pick.entries = listSubdirectories(pick.dir, pick.hidden); pick.cursor = Math.min(pick.cursor, Math.max(0, pick.entries.length - 1)); };
3773
+ if (key.name === "escape") { S.settingsMode = "browse"; S.settingsNotice = ""; render(); return; }
3774
+ if (key.name === "up" || key.name === "k") { pick.cursor = Math.max(0, pick.cursor - 1); render(); return; }
3775
+ if (key.name === "down" || key.name === "j") { pick.cursor = Math.min(Math.max(0, pick.entries.length - 1), pick.cursor + 1); render(); return; }
3776
+ if (key.name === "right" || key.name === "return") {
3777
+ if (pick.entries.length) { pick.dir = path.join(pick.dir, pick.entries[pick.cursor]); pick.cursor = 0; reload(); }
3778
+ render(); return;
3779
+ }
3780
+ if (key.name === "left") {
3781
+ const parent = path.dirname(pick.dir);
3782
+ if (parent !== pick.dir) { pick.dir = parent; pick.cursor = 0; reload(); }
3783
+ render(); return;
3784
+ }
3785
+ if (chunk === ".") { pick.hidden = !pick.hidden; reload(); render(); return; }
3786
+ if (chunk === " ") {
3787
+ S.settingsPendingDir = pick.dir;
3788
+ S.settingsAction = "add";
3789
+ S.settingsMode = "confirm";
3790
+ S.settingsInput = `Allow reading ${pick.dir} for this member? [y/N]`;
3791
+ render(); return;
3792
+ }
3793
+ return;
3794
+ }
3795
+ if (S.settingsMode === "pickroot") {
3796
+ const roots = (S.settingsData.privacySnapshot && S.settingsData.privacySnapshot.boundary && S.settingsData.privacySnapshot.boundary.personal_read_roots) || [];
3797
+ if (key.name === "escape" || key.name === "left") { S.settingsMode = "browse"; S.settingsListCursor = 0; render(); return; }
3798
+ if (key.name === "up" || key.name === "k") { S.settingsListCursor = Math.max(0, (S.settingsListCursor || 0) - 1); render(); return; }
3799
+ if (key.name === "down" || key.name === "j") { S.settingsListCursor = Math.min(Math.max(0, roots.length - 1), (S.settingsListCursor || 0) + 1); render(); return; }
3800
+ if (key.name === "return" && roots.length) {
3801
+ S.settingsPendingDir = roots[Math.min(S.settingsListCursor || 0, roots.length - 1)];
3802
+ S.settingsAction = "remove";
3803
+ S.settingsMode = "confirm";
3804
+ S.settingsInput = `Stop allowing reads of ${S.settingsPendingDir}? [y/N]`;
3805
+ render(); return;
3806
+ }
3807
+ return;
3808
+ }
3809
+ if (S.settingsMode === "confirm") {
3810
+ if (chunk === "y" || chunk === "Y") {
3811
+ let r = null;
3812
+ if (S.settingsAction === "add" || S.settingsAction === "remove") {
3813
+ r = runSettings(S.settingsInst, ["boundary", S.settingsAction, S.settingsPendingDir]);
3814
+ } else if (S.settingsAction === "tele-export") {
3815
+ r = runTelemetry(S.settingsInst, ["export", S.settingsPendingDir]);
3816
+ } else if (S.settingsAction === "tele-on") {
3817
+ r = runTelemetry(S.settingsInst, ["on"]);
3818
+ } else if (S.settingsAction === "tele-off") {
3819
+ r = runTelemetry(S.settingsInst, ["off"]);
3820
+ } else if (S.settingsAction === "tele-clear") {
3821
+ r = runTelemetry(S.settingsInst, ["clear"]);
3822
+ }
3823
+ S.settingsNotice = r && r.status === 0
3824
+ ? `${GREEN}done${RESET}`
3825
+ : `${YELLOW}${((r && (r.stderr || r.stdout)) || "action failed").split("\n")[0]}${RESET}`;
3826
+ S.settingsMode = "browse"; S.settingsInput = ""; S.settingsPendingDir = "";
3827
+ refreshPanel(); render(); return;
3828
+ }
3829
+ S.settingsMode = "browse"; S.settingsInput = ""; S.settingsPendingDir = ""; S.settingsNotice = ""; render(); return;
3830
+ }
3831
+ if (key.name === "escape" || key.name === "left") { backToMenu(); return; }
3832
+ if (S.settingsView === "privacy") {
3833
+ const locked = !!(S.settingsData && S.settingsData.privacySnapshot && S.settingsData.privacySnapshot.boundary && S.settingsData.privacySnapshot.boundary.locked);
3834
+ if (!locked && chunk === "a") {
3835
+ const dir = os.homedir();
3836
+ S.settingsData = { ...(S.settingsData || {}), dirPick: { dir, entries: listSubdirectories(dir, false), cursor: 0, hidden: false } };
3837
+ S.settingsMode = "pickdir"; S.settingsNotice = ""; render(); return;
3838
+ }
3839
+ if (!locked && chunk === "r") {
3840
+ S.settingsMode = "pickroot"; S.settingsListCursor = 0; S.settingsNotice = ""; render(); return;
3841
+ }
3842
+ return;
3843
+ }
3844
+ // telemetry view
3845
+ if (chunk === "i") {
3846
+ S.settingsData = { ...(S.settingsData || {}), telemetryEvents: telemetryEvents(S.settingsInst, 100) };
3847
+ S.settingsMode = "events"; S.settingsListCursor = 0; S.settingsNotice = ""; render(); return;
3848
+ }
3849
+ if (chunk === "t") {
3850
+ const on = !!(S.settingsData && S.settingsData.telemetrySnapshot && S.settingsData.telemetrySnapshot.enabled);
3851
+ S.settingsAction = on ? "tele-off" : "tele-on";
3852
+ S.settingsMode = "confirm";
3853
+ S.settingsInput = `Turn telemetry ${on ? "off" : "on"} for this member only? [y/N]`;
3854
+ render(); return;
3855
+ }
3856
+ if (chunk === "x") {
3857
+ const count = (S.settingsData && S.settingsData.telemetrySnapshot && S.settingsData.telemetrySnapshot.buffered_events) || 0;
3858
+ S.settingsAction = "tele-clear";
3859
+ S.settingsMode = "confirm";
3860
+ S.settingsInput = `Delete ${count} locally buffered telemetry event(s)? Nothing else is removed. [y/N]`;
3861
+ render(); return;
3862
+ }
3863
+ return;
3864
+ }
3865
+
2862
3866
  if (S.settingsView === "list") {
2863
3867
  if (S.settingsMode === "add") {
2864
3868
  if (key.name === "escape") { S.settingsMode = "browse"; S.settingsInput = ""; render(); return; }
@@ -2891,15 +3895,40 @@ async function browser(args = {}) {
2891
3895
 
2892
3896
  // menu view
2893
3897
  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; }
3898
+ if (key.name === "up" || key.name === "k") { S.settingsCursor = (S.settingsCursor - 1 + 8) % 8; render(); return; }
3899
+ if (key.name === "down" || key.name === "j") { S.settingsCursor = (S.settingsCursor + 1) % 8; render(); return; }
2896
3900
  if (key.name === "return" || chunk === " ") {
2897
3901
  if (S.settingsCursor === 0) {
3902
+ state.upgradeInst = S.settingsInst;
3903
+ state.upgradeData = S.settingsUpgrade;
3904
+ state.upgradeMode = "view";
3905
+ state.upgradeNotice = "";
3906
+ refreshUpgrade();
3907
+ if (!state.upgradeCandidate) {
3908
+ fetchRuntimeMvpCandidate().then((v) => {
3909
+ state.upgradeCandidate = v || "";
3910
+ if (state.upgradeInst) render();
3911
+ });
3912
+ }
3913
+ render();
3914
+ } else if (S.settingsCursor === 1) {
3915
+ S.settingsView = "privacy"; S.settingsMode = "browse"; S.settingsInput = ""; S.settingsNotice = "";
3916
+ S.settingsData = { ...(S.settingsData || {}), privacySnapshot: privacySnapshot(S.settingsInst) };
3917
+ render();
3918
+ } else if (S.settingsCursor === 2) {
3919
+ S.settingsView = "telemetry"; S.settingsMode = "browse"; S.settingsInput = ""; S.settingsNotice = "";
3920
+ S.settingsData = { ...(S.settingsData || {}), telemetrySnapshot: telemetrySnapshot(S.settingsInst) };
3921
+ render();
3922
+ } else if (S.settingsCursor === 3) {
2898
3923
  const on = (S.settingsData && S.settingsData.hosting) !== false;
2899
3924
  settingsRunVerb(["hosting", on ? "off" : "on"]);
2900
3925
  render();
3926
+ } else if (S.settingsCursor === 4) {
3927
+ const simple = (S.settingsData && S.settingsData.workflow) === "simple";
3928
+ settingsRunVerb(["workflow", simple ? "staged" : "simple"]);
3929
+ render();
2901
3930
  } else {
2902
- const domain = S.settingsCursor === 1 ? "repo" : S.settingsCursor === 2 ? "admin" : "people";
3931
+ const domain = S.settingsCursor === 5 ? "repo" : S.settingsCursor === 6 ? "admin" : "people";
2903
3932
  S.settingsView = "list"; S.settingsDomain = domain;
2904
3933
  S.settingsItems = settingsItemsFor(S.settingsData, domain);
2905
3934
  S.settingsListCursor = 0; S.settingsMode = "browse"; S.settingsNotice = "";
@@ -3155,9 +4184,14 @@ async function browser(args = {}) {
3155
4184
  return;
3156
4185
  }
3157
4186
  state.settingsInst = pick;
3158
- state.settingsData = settingsDump(pick) || { hosting: true, repos: [], admins: [], people: [] };
4187
+ state.settingsData = settingsDump(pick) || { hosting: true, workflow: "staged", base_branch: "develop", repos: [], admins: [], people: [] };
3159
4188
  state.settingsCursor = 0;
3160
4189
  state.settingsView = "menu";
4190
+ state.settingsUpgrade = undefined;
4191
+ upgradeStatusAsync(pick, (st) => {
4192
+ state.settingsUpgrade = st;
4193
+ if (state.settingsInst === pick && !state.upgradeInst) render();
4194
+ });
3161
4195
  state.settingsNotice = "";
3162
4196
  render();
3163
4197
  return;
@@ -3285,6 +4319,8 @@ function main() {
3285
4319
  if (cmd === "ls" || cmd === "list") return cmdLs();
3286
4320
  if (cmd === "use") return cmdUse(args[1]);
3287
4321
  if (cmd === "connect") return cmdConnect(args.slice(1));
4322
+ if (cmd === "telemetry") return cmdTelemetry(args.slice(1));
4323
+ if (cmd === "runtime") return cmdRuntime(args.slice(1));
3288
4324
  if (cmd === "/invite" || cmd === "invite") return cmdInvite(args.slice(1));
3289
4325
  if (cmd === "settings" || cmd === "config") return cmdSettings(args.slice(1));
3290
4326
  if (cmd === "prune") return cmdPruneNonInteractive(args[1] === "--dry-run" || args[1] === "-n");
@@ -3295,6 +4331,8 @@ function main() {
3295
4331
  if (cmd.startsWith("-")) die(`unknown flag: ${cmd}\n run: egregore help`);
3296
4332
 
3297
4333
  const registry = readRegistry();
4334
+ const worktree = currentWorktreeInstance(registry);
4335
+ if (!cmd && worktree) return launch(worktree, runtimeOverride);
3298
4336
  if (registry.length === 0) {
3299
4337
  if (canPrompt()) return setupNewEgregore(runtimeOverride);
3300
4338
  die("no egregores installed yet.\n run: npx -y create-egregore@latest");