create-egregore 0.20.2 → 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 (706) hide show
  1. package/assets/egregore-launcher.js +1011 -16
  2. package/bin/cli.js +11 -0
  3. package/lib/claude-runtime.js +192 -0
  4. package/lib/local.js +38 -31
  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 -17
  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 +9 -9
  268. package/runtime/codex/AGENTS.md +62 -58
  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 +84 -100
  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 +41 -16
  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/corpus_map.py +806 -0
  281. package/runtime/codex/bin/corpus_survey.py +304 -0
  282. package/runtime/codex/bin/dashboard-data.sh +11 -171
  283. package/runtime/codex/bin/github-auth.sh +121 -0
  284. package/runtime/codex/bin/graph-batch.sh +7 -0
  285. package/runtime/codex/bin/graph-op.sh +4 -0
  286. package/runtime/codex/bin/graph-projection.sh +54 -0
  287. package/runtime/codex/bin/graph-wal.sh +13 -0
  288. package/runtime/codex/bin/graph.sh +44 -0
  289. package/runtime/codex/bin/handoff-lifecycle-job.sh +146 -0
  290. package/runtime/codex/bin/handoff-lifecycle.sh +280 -0
  291. package/runtime/codex/bin/handoff-preview.sh +169 -0
  292. package/runtime/codex/bin/handoff-run.sh +42 -26
  293. package/runtime/codex/bin/ingest-graph.sh +6 -0
  294. package/runtime/codex/bin/ingest-item.sh +10 -0
  295. package/runtime/codex/bin/ingest.sh +59 -30
  296. package/runtime/codex/bin/invite.sh +6 -0
  297. package/runtime/codex/bin/issue.sh +10 -0
  298. package/runtime/codex/bin/knowledge.sh +10 -0
  299. package/runtime/codex/bin/lib/config.sh +20 -0
  300. package/runtime/codex/bin/lib/context.sh +46 -25
  301. package/runtime/codex/bin/lib/git-sync.sh +70 -6
  302. package/runtime/codex/bin/lib/greeting.sh +34 -5
  303. package/runtime/codex/bin/lib/handoff-meta.sh +97 -0
  304. package/runtime/codex/bin/lib/worktree-links.sh +6 -0
  305. package/runtime/codex/bin/node-run.sh +42 -0
  306. package/runtime/codex/bin/notification.sh +6 -0
  307. package/runtime/codex/bin/observe-context.sh +14 -0
  308. package/runtime/codex/bin/onboarding.sh +6 -0
  309. package/runtime/codex/bin/person.py +4 -0
  310. package/runtime/codex/bin/person.sh +43 -10
  311. package/runtime/codex/bin/pi-render-spec.mjs +140 -0
  312. package/runtime/codex/bin/post-update.sh +37 -0
  313. package/runtime/codex/bin/prime-render-spec.mjs +147 -0
  314. package/runtime/codex/bin/publish-artifact.sh +55 -2
  315. package/runtime/codex/bin/quest.sh +9 -0
  316. package/runtime/codex/bin/question.sh +8 -0
  317. package/runtime/codex/bin/research-ingest.sh +7 -0
  318. package/runtime/codex/bin/restore-owned-skills.sh +67 -0
  319. package/runtime/codex/bin/retrieval_eval.py +385 -0
  320. package/runtime/codex/bin/runtime-identity.sh +70 -0
  321. package/runtime/codex/bin/runtime-upgrade.sh +43 -0
  322. package/runtime/codex/bin/scroll.sh +9 -0
  323. package/runtime/codex/bin/search.sh +231 -195
  324. package/runtime/codex/bin/settings.sh +174 -5
  325. package/runtime/codex/bin/startup-check.sh +136 -0
  326. package/runtime/codex/bin/telemetry.sh +522 -247
  327. package/runtime/codex/bin/test-changes.sh +344 -0
  328. package/runtime/codex/bin/thread.sh +9 -0
  329. package/runtime/codex/bin/todo.sh +9 -0
  330. package/runtime/codex/bin/view-render.sh +126 -0
  331. package/runtime/codex/bin/worktree-create.sh +19 -5
  332. package/runtime/codex/egregore_runtime/__init__.py +228 -0
  333. package/runtime/codex/egregore_runtime/adapters/__init__.py +5 -0
  334. package/runtime/codex/egregore_runtime/adapters/invitation.py +237 -0
  335. package/runtime/codex/egregore_runtime/adapters/notification.py +59 -0
  336. package/runtime/codex/egregore_runtime/adapters/qmd.py +1701 -0
  337. package/runtime/codex/egregore_runtime/adapters/qmd_cli.py +210 -0
  338. package/runtime/codex/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  339. package/runtime/codex/egregore_runtime/admin_gate.py +102 -0
  340. package/runtime/codex/egregore_runtime/artifacts.py +523 -0
  341. package/runtime/codex/egregore_runtime/contracts.py +499 -0
  342. package/runtime/codex/egregore_runtime/entitlements.py +85 -0
  343. package/runtime/codex/egregore_runtime/errors.py +10 -0
  344. package/runtime/codex/egregore_runtime/graph.py +356 -0
  345. package/runtime/codex/egregore_runtime/handoff_lookup.py +196 -0
  346. package/runtime/codex/egregore_runtime/harness_cli.py +1221 -0
  347. package/runtime/codex/egregore_runtime/identity.py +734 -0
  348. package/runtime/codex/egregore_runtime/identity_cli.py +91 -0
  349. package/runtime/codex/egregore_runtime/ingest.py +575 -0
  350. package/runtime/codex/egregore_runtime/ingest_cli.py +254 -0
  351. package/runtime/codex/egregore_runtime/ingest_index_cli.py +147 -0
  352. package/runtime/codex/egregore_runtime/invitation_cli.py +51 -0
  353. package/runtime/codex/egregore_runtime/invitations.py +116 -0
  354. package/runtime/codex/egregore_runtime/issue_cli.py +305 -0
  355. package/runtime/codex/egregore_runtime/issues.py +359 -0
  356. package/runtime/codex/egregore_runtime/knowledge.py +376 -0
  357. package/runtime/codex/egregore_runtime/knowledge_cli.py +173 -0
  358. package/runtime/codex/egregore_runtime/lifecycle.py +888 -0
  359. package/runtime/codex/egregore_runtime/lifecycle_cli.py +269 -0
  360. package/runtime/codex/egregore_runtime/notification_cli.py +125 -0
  361. package/runtime/codex/egregore_runtime/notifications.py +230 -0
  362. package/runtime/codex/egregore_runtime/observe.py +342 -0
  363. package/runtime/codex/egregore_runtime/onboarding.py +290 -0
  364. package/runtime/codex/egregore_runtime/onboarding_cli.py +110 -0
  365. package/runtime/codex/egregore_runtime/policy.py +144 -0
  366. package/runtime/codex/egregore_runtime/profile.py +193 -0
  367. package/runtime/codex/egregore_runtime/quest_cli.py +216 -0
  368. package/runtime/codex/egregore_runtime/question_cli.py +180 -0
  369. package/runtime/codex/egregore_runtime/questions.py +304 -0
  370. package/runtime/codex/egregore_runtime/quests.py +419 -0
  371. package/runtime/codex/egregore_runtime/readiness.py +379 -0
  372. package/runtime/codex/egregore_runtime/research_ingest.py +256 -0
  373. package/runtime/codex/egregore_runtime/research_ingest_cli.py +44 -0
  374. package/runtime/codex/egregore_runtime/runtime.py +464 -0
  375. package/runtime/codex/egregore_runtime/scroll_cli.py +185 -0
  376. package/runtime/codex/egregore_runtime/scrolls.py +726 -0
  377. package/runtime/codex/egregore_runtime/status.py +412 -0
  378. package/runtime/codex/egregore_runtime/status_cli.py +174 -0
  379. package/runtime/codex/egregore_runtime/sync.py +218 -0
  380. package/runtime/codex/egregore_runtime/teamsync.py +139 -0
  381. package/runtime/codex/egregore_runtime/telemetry.py +640 -0
  382. package/runtime/codex/egregore_runtime/thread_cli.py +173 -0
  383. package/runtime/codex/egregore_runtime/threads.py +517 -0
  384. package/runtime/codex/egregore_runtime/todo_cli.py +142 -0
  385. package/runtime/codex/egregore_runtime/todos.py +244 -0
  386. package/runtime/codex/egregore_runtime/upgrade.py +770 -0
  387. package/runtime/codex/egregore_runtime/upgrade_worker.py +53 -0
  388. package/runtime/codex/egregore_runtime/writeback.py +391 -0
  389. package/runtime/codex/egregore_runtime/writeback_cli.py +114 -0
  390. package/runtime/codex/manifest.json +98 -1
  391. package/runtime/pi/.codex/hooks/search-hint.js +21 -52
  392. package/runtime/pi/.codex/hooks.json +3 -3
  393. package/runtime/pi/.codex/skills/activity/SKILL.md +23 -66
  394. package/runtime/pi/.codex/skills/announce/SKILL.md +27 -50
  395. package/runtime/pi/.codex/skills/archive/SKILL.md +21 -36
  396. package/runtime/pi/.codex/skills/checkup/SKILL.md +77 -36
  397. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +1 -1
  398. package/runtime/pi/.codex/skills/dashboard/SKILL.md +17 -47
  399. package/runtime/pi/.codex/skills/handoff/SKILL.md +84 -133
  400. package/runtime/pi/.codex/skills/harvest/SKILL.md +32 -117
  401. package/runtime/pi/.codex/skills/ingest/SKILL.md +47 -25
  402. package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  403. package/runtime/pi/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  404. package/runtime/pi/.codex/skills/invite/SKILL.md +21 -35
  405. package/runtime/pi/.codex/skills/issue/SKILL.md +60 -41
  406. package/runtime/pi/.codex/skills/me/SKILL.md +1 -1
  407. package/runtime/pi/.codex/skills/meeting/SKILL.md +16 -36
  408. package/runtime/pi/.codex/skills/meeting/references/analysis-contract.md +48 -0
  409. package/runtime/pi/.codex/skills/note/SKILL.md +30 -25
  410. package/runtime/pi/.codex/skills/onboarding/SKILL.md +36 -41
  411. package/runtime/pi/.codex/skills/pull/SKILL.md +1 -1
  412. package/runtime/pi/.codex/skills/quest/SKILL.md +27 -66
  413. package/runtime/pi/.codex/skills/reflect/SKILL.md +22 -36
  414. package/runtime/pi/.codex/skills/save/SKILL.md +2 -2
  415. package/runtime/pi/.codex/skills/telemetry/SKILL.md +1 -1
  416. package/runtime/pi/.codex/skills/test/SKILL.md +1 -1
  417. package/runtime/pi/.codex/skills/tutorial/SKILL.md +40 -41
  418. package/runtime/pi/.codex/skills/view/SKILL.md +115 -111
  419. package/runtime/pi/.codex/skills/wrap/SKILL.md +45 -41
  420. package/runtime/pi/.codex/spec-manifest.json +9 -9
  421. package/runtime/pi/.pi/APPEND_SYSTEM.md +57 -48
  422. package/runtime/pi/.pi/extensions/egregore.ts +7 -0
  423. package/runtime/pi/.pi/spec-manifest.json +2 -2
  424. package/runtime/pi/AGENTS.md +62 -58
  425. package/runtime/pi/bin/activity-action.sh +92 -0
  426. package/runtime/pi/bin/activity-data.sh +12 -233
  427. package/runtime/pi/bin/agent.sh +84 -100
  428. package/runtime/pi/bin/artifact-register.sh +164 -0
  429. package/runtime/pi/bin/artifact-writeback.sh +53 -0
  430. package/runtime/pi/bin/artifacts.sh +288 -0
  431. package/runtime/pi/bin/build-sealed-dataroom.mjs +722 -0
  432. package/runtime/pi/bin/capture-run.sh +18 -2
  433. package/runtime/pi/bin/codex-render-spec.mjs +41 -16
  434. package/runtime/pi/bin/codex-session-start.sh +14 -4
  435. package/runtime/pi/bin/codex-skill-render.mjs +9 -7
  436. package/runtime/pi/bin/corpus_map.py +806 -0
  437. package/runtime/pi/bin/corpus_survey.py +304 -0
  438. package/runtime/pi/bin/dashboard-data.sh +11 -171
  439. package/runtime/pi/bin/github-auth.sh +121 -0
  440. package/runtime/pi/bin/graph-batch.sh +7 -0
  441. package/runtime/pi/bin/graph-op.sh +4 -0
  442. package/runtime/pi/bin/graph-projection.sh +54 -0
  443. package/runtime/pi/bin/graph-wal.sh +13 -0
  444. package/runtime/pi/bin/graph.sh +44 -0
  445. package/runtime/pi/bin/handoff-lifecycle-job.sh +146 -0
  446. package/runtime/pi/bin/handoff-lifecycle.sh +280 -0
  447. package/runtime/pi/bin/handoff-preview.sh +169 -0
  448. package/runtime/pi/bin/handoff-run.sh +42 -26
  449. package/runtime/pi/bin/ingest-graph.sh +6 -0
  450. package/runtime/pi/bin/ingest-item.sh +10 -0
  451. package/runtime/pi/bin/ingest.sh +59 -30
  452. package/runtime/pi/bin/invite.sh +6 -0
  453. package/runtime/pi/bin/issue.sh +10 -0
  454. package/runtime/pi/bin/knowledge.sh +10 -0
  455. package/runtime/pi/bin/lib/config.sh +20 -0
  456. package/runtime/pi/bin/lib/context.sh +46 -25
  457. package/runtime/pi/bin/lib/git-sync.sh +70 -6
  458. package/runtime/pi/bin/lib/greeting.sh +34 -5
  459. package/runtime/pi/bin/lib/handoff-meta.sh +97 -0
  460. package/runtime/pi/bin/lib/worktree-links.sh +6 -0
  461. package/runtime/pi/bin/node-run.sh +42 -0
  462. package/runtime/pi/bin/notification.sh +6 -0
  463. package/runtime/pi/bin/observe-context.sh +14 -0
  464. package/runtime/pi/bin/onboarding.sh +6 -0
  465. package/runtime/pi/bin/person.py +4 -0
  466. package/runtime/pi/bin/person.sh +43 -10
  467. package/runtime/pi/bin/pi-observe-context.mjs +93 -0
  468. package/runtime/pi/bin/pi-product-workflows.mjs +1 -1
  469. package/runtime/pi/bin/pi-render-spec.mjs +1 -1
  470. package/runtime/pi/bin/post-update.sh +37 -0
  471. package/runtime/pi/bin/prime-render-spec.mjs +147 -0
  472. package/runtime/pi/bin/publish-artifact.sh +55 -2
  473. package/runtime/pi/bin/quest.sh +9 -0
  474. package/runtime/pi/bin/question.sh +8 -0
  475. package/runtime/pi/bin/research-ingest.sh +7 -0
  476. package/runtime/pi/bin/restore-owned-skills.sh +67 -0
  477. package/runtime/pi/bin/retrieval_eval.py +385 -0
  478. package/runtime/pi/bin/runtime-identity.sh +70 -0
  479. package/runtime/pi/bin/runtime-upgrade.sh +43 -0
  480. package/runtime/pi/bin/scroll.sh +9 -0
  481. package/runtime/pi/bin/search.sh +231 -195
  482. package/runtime/pi/bin/settings.sh +174 -5
  483. package/runtime/pi/bin/startup-check.sh +136 -0
  484. package/runtime/pi/bin/telemetry.sh +522 -247
  485. package/runtime/pi/bin/test-changes.sh +344 -0
  486. package/runtime/pi/bin/thread.sh +9 -0
  487. package/runtime/pi/bin/todo.sh +9 -0
  488. package/runtime/pi/bin/view-render.sh +126 -0
  489. package/runtime/pi/bin/worktree-create.sh +19 -5
  490. package/runtime/pi/egregore_runtime/__init__.py +228 -0
  491. package/runtime/pi/egregore_runtime/adapters/__init__.py +5 -0
  492. package/runtime/pi/egregore_runtime/adapters/invitation.py +237 -0
  493. package/runtime/pi/egregore_runtime/adapters/notification.py +59 -0
  494. package/runtime/pi/egregore_runtime/adapters/qmd.py +1701 -0
  495. package/runtime/pi/egregore_runtime/adapters/qmd_cli.py +210 -0
  496. package/runtime/pi/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  497. package/runtime/pi/egregore_runtime/admin_gate.py +102 -0
  498. package/runtime/pi/egregore_runtime/artifacts.py +523 -0
  499. package/runtime/pi/egregore_runtime/contracts.py +499 -0
  500. package/runtime/pi/egregore_runtime/entitlements.py +85 -0
  501. package/runtime/pi/egregore_runtime/errors.py +10 -0
  502. package/runtime/pi/egregore_runtime/graph.py +356 -0
  503. package/runtime/pi/egregore_runtime/handoff_lookup.py +196 -0
  504. package/runtime/pi/egregore_runtime/harness_cli.py +1221 -0
  505. package/runtime/pi/egregore_runtime/identity.py +734 -0
  506. package/runtime/pi/egregore_runtime/identity_cli.py +91 -0
  507. package/runtime/pi/egregore_runtime/ingest.py +575 -0
  508. package/runtime/pi/egregore_runtime/ingest_cli.py +254 -0
  509. package/runtime/pi/egregore_runtime/ingest_index_cli.py +147 -0
  510. package/runtime/pi/egregore_runtime/invitation_cli.py +51 -0
  511. package/runtime/pi/egregore_runtime/invitations.py +116 -0
  512. package/runtime/pi/egregore_runtime/issue_cli.py +305 -0
  513. package/runtime/pi/egregore_runtime/issues.py +359 -0
  514. package/runtime/pi/egregore_runtime/knowledge.py +376 -0
  515. package/runtime/pi/egregore_runtime/knowledge_cli.py +173 -0
  516. package/runtime/pi/egregore_runtime/lifecycle.py +888 -0
  517. package/runtime/pi/egregore_runtime/lifecycle_cli.py +269 -0
  518. package/runtime/pi/egregore_runtime/notification_cli.py +125 -0
  519. package/runtime/pi/egregore_runtime/notifications.py +230 -0
  520. package/runtime/pi/egregore_runtime/observe.py +342 -0
  521. package/runtime/pi/egregore_runtime/onboarding.py +290 -0
  522. package/runtime/pi/egregore_runtime/onboarding_cli.py +110 -0
  523. package/runtime/pi/egregore_runtime/policy.py +144 -0
  524. package/runtime/pi/egregore_runtime/profile.py +193 -0
  525. package/runtime/pi/egregore_runtime/quest_cli.py +216 -0
  526. package/runtime/pi/egregore_runtime/question_cli.py +180 -0
  527. package/runtime/pi/egregore_runtime/questions.py +304 -0
  528. package/runtime/pi/egregore_runtime/quests.py +419 -0
  529. package/runtime/pi/egregore_runtime/readiness.py +379 -0
  530. package/runtime/pi/egregore_runtime/research_ingest.py +256 -0
  531. package/runtime/pi/egregore_runtime/research_ingest_cli.py +44 -0
  532. package/runtime/pi/egregore_runtime/runtime.py +464 -0
  533. package/runtime/pi/egregore_runtime/scroll_cli.py +185 -0
  534. package/runtime/pi/egregore_runtime/scrolls.py +726 -0
  535. package/runtime/pi/egregore_runtime/status.py +412 -0
  536. package/runtime/pi/egregore_runtime/status_cli.py +174 -0
  537. package/runtime/pi/egregore_runtime/sync.py +218 -0
  538. package/runtime/pi/egregore_runtime/teamsync.py +139 -0
  539. package/runtime/pi/egregore_runtime/telemetry.py +640 -0
  540. package/runtime/pi/egregore_runtime/thread_cli.py +173 -0
  541. package/runtime/pi/egregore_runtime/threads.py +517 -0
  542. package/runtime/pi/egregore_runtime/todo_cli.py +142 -0
  543. package/runtime/pi/egregore_runtime/todos.py +244 -0
  544. package/runtime/pi/egregore_runtime/upgrade.py +770 -0
  545. package/runtime/pi/egregore_runtime/upgrade_worker.py +53 -0
  546. package/runtime/pi/egregore_runtime/writeback.py +391 -0
  547. package/runtime/pi/egregore_runtime/writeback_cli.py +114 -0
  548. package/runtime/pi/manifest.json +98 -1
  549. package/runtime/prime/.codex/hooks/search-hint.js +21 -52
  550. package/runtime/prime/.codex/hooks.json +3 -3
  551. package/runtime/prime/.codex/skills/activity/SKILL.md +23 -66
  552. package/runtime/prime/.codex/skills/announce/SKILL.md +27 -50
  553. package/runtime/prime/.codex/skills/archive/SKILL.md +21 -36
  554. package/runtime/prime/.codex/skills/checkup/SKILL.md +77 -36
  555. package/runtime/prime/.codex/skills/dark-mode/SKILL.md +1 -1
  556. package/runtime/prime/.codex/skills/dashboard/SKILL.md +17 -47
  557. package/runtime/prime/.codex/skills/handoff/SKILL.md +84 -133
  558. package/runtime/prime/.codex/skills/harvest/SKILL.md +32 -117
  559. package/runtime/prime/.codex/skills/ingest/SKILL.md +47 -25
  560. package/runtime/prime/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  561. package/runtime/prime/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  562. package/runtime/prime/.codex/skills/invite/SKILL.md +21 -35
  563. package/runtime/prime/.codex/skills/issue/SKILL.md +60 -41
  564. package/runtime/prime/.codex/skills/me/SKILL.md +1 -1
  565. package/runtime/prime/.codex/skills/meeting/SKILL.md +16 -36
  566. package/runtime/prime/.codex/skills/meeting/references/analysis-contract.md +48 -0
  567. package/runtime/prime/.codex/skills/note/SKILL.md +30 -25
  568. package/runtime/prime/.codex/skills/onboarding/SKILL.md +36 -41
  569. package/runtime/prime/.codex/skills/pull/SKILL.md +1 -1
  570. package/runtime/prime/.codex/skills/quest/SKILL.md +27 -66
  571. package/runtime/prime/.codex/skills/reflect/SKILL.md +22 -36
  572. package/runtime/prime/.codex/skills/save/SKILL.md +2 -2
  573. package/runtime/prime/.codex/skills/telemetry/SKILL.md +1 -1
  574. package/runtime/prime/.codex/skills/test/SKILL.md +1 -1
  575. package/runtime/prime/.codex/skills/tutorial/SKILL.md +40 -41
  576. package/runtime/prime/.codex/skills/view/SKILL.md +115 -111
  577. package/runtime/prime/.codex/skills/wrap/SKILL.md +45 -41
  578. package/runtime/prime/.codex/spec-manifest.json +9 -9
  579. package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +57 -48
  580. package/runtime/prime/.prime/agent/extensions/egregore.ts +7 -0
  581. package/runtime/prime/.prime/agent/spec-manifest.json +2 -2
  582. package/runtime/prime/AGENTS.md +62 -58
  583. package/runtime/prime/bin/activity-action.sh +92 -0
  584. package/runtime/prime/bin/activity-data.sh +12 -233
  585. package/runtime/prime/bin/agent.sh +84 -100
  586. package/runtime/prime/bin/artifact-register.sh +164 -0
  587. package/runtime/prime/bin/artifact-writeback.sh +53 -0
  588. package/runtime/prime/bin/artifacts.sh +288 -0
  589. package/runtime/prime/bin/build-sealed-dataroom.mjs +722 -0
  590. package/runtime/prime/bin/capture-run.sh +18 -2
  591. package/runtime/prime/bin/codex-render-spec.mjs +41 -16
  592. package/runtime/prime/bin/codex-session-start.sh +14 -4
  593. package/runtime/prime/bin/codex-skill-render.mjs +9 -7
  594. package/runtime/prime/bin/corpus_map.py +806 -0
  595. package/runtime/prime/bin/corpus_survey.py +304 -0
  596. package/runtime/prime/bin/dashboard-data.sh +11 -171
  597. package/runtime/prime/bin/github-auth.sh +121 -0
  598. package/runtime/prime/bin/graph-batch.sh +7 -0
  599. package/runtime/prime/bin/graph-op.sh +4 -0
  600. package/runtime/prime/bin/graph-projection.sh +54 -0
  601. package/runtime/prime/bin/graph-wal.sh +13 -0
  602. package/runtime/prime/bin/graph.sh +44 -0
  603. package/runtime/prime/bin/handoff-lifecycle-job.sh +146 -0
  604. package/runtime/prime/bin/handoff-lifecycle.sh +280 -0
  605. package/runtime/prime/bin/handoff-preview.sh +169 -0
  606. package/runtime/prime/bin/handoff-run.sh +42 -26
  607. package/runtime/prime/bin/ingest-graph.sh +6 -0
  608. package/runtime/prime/bin/ingest-item.sh +10 -0
  609. package/runtime/prime/bin/ingest.sh +59 -30
  610. package/runtime/prime/bin/invite.sh +6 -0
  611. package/runtime/prime/bin/issue.sh +10 -0
  612. package/runtime/prime/bin/knowledge.sh +10 -0
  613. package/runtime/prime/bin/lib/config.sh +20 -0
  614. package/runtime/prime/bin/lib/context.sh +46 -25
  615. package/runtime/prime/bin/lib/git-sync.sh +70 -6
  616. package/runtime/prime/bin/lib/greeting.sh +34 -5
  617. package/runtime/prime/bin/lib/handoff-meta.sh +97 -0
  618. package/runtime/prime/bin/lib/worktree-links.sh +6 -0
  619. package/runtime/prime/bin/node-run.sh +42 -0
  620. package/runtime/prime/bin/notification.sh +6 -0
  621. package/runtime/prime/bin/observe-context.sh +14 -0
  622. package/runtime/prime/bin/onboarding.sh +6 -0
  623. package/runtime/prime/bin/person.py +4 -0
  624. package/runtime/prime/bin/person.sh +43 -10
  625. package/runtime/prime/bin/pi-observe-context.mjs +93 -0
  626. package/runtime/prime/bin/pi-product-workflows.mjs +1 -1
  627. package/runtime/prime/bin/pi-render-spec.mjs +140 -0
  628. package/runtime/prime/bin/post-update.sh +37 -0
  629. package/runtime/prime/bin/prime-render-spec.mjs +1 -1
  630. package/runtime/prime/bin/publish-artifact.sh +55 -2
  631. package/runtime/prime/bin/quest.sh +9 -0
  632. package/runtime/prime/bin/question.sh +8 -0
  633. package/runtime/prime/bin/research-ingest.sh +7 -0
  634. package/runtime/prime/bin/restore-owned-skills.sh +67 -0
  635. package/runtime/prime/bin/retrieval_eval.py +385 -0
  636. package/runtime/prime/bin/runtime-identity.sh +70 -0
  637. package/runtime/prime/bin/runtime-upgrade.sh +43 -0
  638. package/runtime/prime/bin/scroll.sh +9 -0
  639. package/runtime/prime/bin/search.sh +231 -195
  640. package/runtime/prime/bin/settings.sh +174 -5
  641. package/runtime/prime/bin/startup-check.sh +136 -0
  642. package/runtime/prime/bin/telemetry.sh +522 -247
  643. package/runtime/prime/bin/test-changes.sh +344 -0
  644. package/runtime/prime/bin/thread.sh +9 -0
  645. package/runtime/prime/bin/todo.sh +9 -0
  646. package/runtime/prime/bin/view-render.sh +126 -0
  647. package/runtime/prime/bin/worktree-create.sh +19 -5
  648. package/runtime/prime/egregore_runtime/__init__.py +228 -0
  649. package/runtime/prime/egregore_runtime/adapters/__init__.py +5 -0
  650. package/runtime/prime/egregore_runtime/adapters/invitation.py +237 -0
  651. package/runtime/prime/egregore_runtime/adapters/notification.py +59 -0
  652. package/runtime/prime/egregore_runtime/adapters/qmd.py +1701 -0
  653. package/runtime/prime/egregore_runtime/adapters/qmd_cli.py +210 -0
  654. package/runtime/prime/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  655. package/runtime/prime/egregore_runtime/admin_gate.py +102 -0
  656. package/runtime/prime/egregore_runtime/artifacts.py +523 -0
  657. package/runtime/prime/egregore_runtime/contracts.py +499 -0
  658. package/runtime/prime/egregore_runtime/entitlements.py +85 -0
  659. package/runtime/prime/egregore_runtime/errors.py +10 -0
  660. package/runtime/prime/egregore_runtime/graph.py +356 -0
  661. package/runtime/prime/egregore_runtime/handoff_lookup.py +196 -0
  662. package/runtime/prime/egregore_runtime/harness_cli.py +1221 -0
  663. package/runtime/prime/egregore_runtime/identity.py +734 -0
  664. package/runtime/prime/egregore_runtime/identity_cli.py +91 -0
  665. package/runtime/prime/egregore_runtime/ingest.py +575 -0
  666. package/runtime/prime/egregore_runtime/ingest_cli.py +254 -0
  667. package/runtime/prime/egregore_runtime/ingest_index_cli.py +147 -0
  668. package/runtime/prime/egregore_runtime/invitation_cli.py +51 -0
  669. package/runtime/prime/egregore_runtime/invitations.py +116 -0
  670. package/runtime/prime/egregore_runtime/issue_cli.py +305 -0
  671. package/runtime/prime/egregore_runtime/issues.py +359 -0
  672. package/runtime/prime/egregore_runtime/knowledge.py +376 -0
  673. package/runtime/prime/egregore_runtime/knowledge_cli.py +173 -0
  674. package/runtime/prime/egregore_runtime/lifecycle.py +888 -0
  675. package/runtime/prime/egregore_runtime/lifecycle_cli.py +269 -0
  676. package/runtime/prime/egregore_runtime/notification_cli.py +125 -0
  677. package/runtime/prime/egregore_runtime/notifications.py +230 -0
  678. package/runtime/prime/egregore_runtime/observe.py +342 -0
  679. package/runtime/prime/egregore_runtime/onboarding.py +290 -0
  680. package/runtime/prime/egregore_runtime/onboarding_cli.py +110 -0
  681. package/runtime/prime/egregore_runtime/policy.py +144 -0
  682. package/runtime/prime/egregore_runtime/profile.py +193 -0
  683. package/runtime/prime/egregore_runtime/quest_cli.py +216 -0
  684. package/runtime/prime/egregore_runtime/question_cli.py +180 -0
  685. package/runtime/prime/egregore_runtime/questions.py +304 -0
  686. package/runtime/prime/egregore_runtime/quests.py +419 -0
  687. package/runtime/prime/egregore_runtime/readiness.py +379 -0
  688. package/runtime/prime/egregore_runtime/research_ingest.py +256 -0
  689. package/runtime/prime/egregore_runtime/research_ingest_cli.py +44 -0
  690. package/runtime/prime/egregore_runtime/runtime.py +464 -0
  691. package/runtime/prime/egregore_runtime/scroll_cli.py +185 -0
  692. package/runtime/prime/egregore_runtime/scrolls.py +726 -0
  693. package/runtime/prime/egregore_runtime/status.py +412 -0
  694. package/runtime/prime/egregore_runtime/status_cli.py +174 -0
  695. package/runtime/prime/egregore_runtime/sync.py +218 -0
  696. package/runtime/prime/egregore_runtime/teamsync.py +139 -0
  697. package/runtime/prime/egregore_runtime/telemetry.py +640 -0
  698. package/runtime/prime/egregore_runtime/thread_cli.py +173 -0
  699. package/runtime/prime/egregore_runtime/threads.py +517 -0
  700. package/runtime/prime/egregore_runtime/todo_cli.py +142 -0
  701. package/runtime/prime/egregore_runtime/todos.py +244 -0
  702. package/runtime/prime/egregore_runtime/upgrade.py +770 -0
  703. package/runtime/prime/egregore_runtime/upgrade_worker.py +53 -0
  704. package/runtime/prime/egregore_runtime/writeback.py +391 -0
  705. package/runtime/prime/egregore_runtime/writeback_cli.py +114 -0
  706. package/runtime/prime/manifest.json +98 -1
@@ -0,0 +1,770 @@
1
+ """Transactional Runtime upgrade engine — staged, durable, per instance.
2
+
3
+ The engine prepares a candidate Runtime for exactly one registered Egregore
4
+ instance while the currently active Runtime keeps serving. Preparation is a
5
+ sequence of durable stages; every transition is an atomic write to an
6
+ instance-scoped state file, so an interrupted worker resumes completed work
7
+ instead of restarting it. Activation is a separate, explicit, atomic step
8
+ that only succeeds when every gate passes — BM25 alone never activates.
9
+
10
+ All state lives under the instance's own runtime root, keyed by the same
11
+ stable instance hash the QMD adapter uses. Nothing here reads or writes
12
+ another instance's files, processes, indexes, or configuration.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import os
19
+ import subprocess
20
+ import sys
21
+ import time
22
+ from dataclasses import dataclass, field
23
+ from pathlib import Path
24
+ from typing import Any, Mapping
25
+
26
+ from .adapters.qmd import QMD_VERSION, RERANKING_ENABLED, QmdLocalRetriever
27
+
28
+ SCHEMA_VERSION = "egregore-runtime-upgrade/v1"
29
+
30
+ # Stage keys in preparation order. Labels are the user-facing truth shown by
31
+ # Settings; keep them in plain team language.
32
+ STAGES: tuple[tuple[str, str], ...] = (
33
+ ("sync", "Team memory synchronized"),
34
+ ("candidate", "Runtime candidate recorded"),
35
+ ("install", "Runtime candidate installed"),
36
+ ("node", "Node runtime ready"),
37
+ ("qmd", "QMD installed"),
38
+ ("bm25", "Keyword index built"),
39
+ ("embed", "Meaning index generated"),
40
+ ("delta", "Late team changes embedded"),
41
+ ("verify", "Retrieval, identity, and boundary verified"),
42
+ )
43
+
44
+ # The harness bundle applied to the instance at activation. All four bundles
45
+ # must be present in the candidate package; the Claude bundle carries the
46
+ # shared core (bin/, egregore_runtime/, .claude/) this instance runs on.
47
+ BUNDLE_TREES = ("claude", "codex", "pi", "prime")
48
+ # Activation applies every harness adapter tree, not only Claude's: the
49
+ # Codex black-box found a live instance whose .codex adapters were still the
50
+ # pre-cutover generation, sending Codex sessions through a broken global QMD
51
+ # and graph-era instructions while Claude ran the new Runtime. Shared paths
52
+ # (bin/, egregore_runtime/) are byte-identical across trees; the first tree
53
+ # wins and duplicates are skipped.
54
+ APPLY_TREES = ("claude", "codex", "pi", "prime")
55
+ APPLY_TREE = APPLY_TREES[0]
56
+
57
+ STATUS_PENDING = "pending"
58
+ STATUS_PREPARING = "preparing"
59
+ STATUS_FAILED = "failed"
60
+ STATUS_READY = "ready-to-activate"
61
+ STATUS_ACTIVE = "active"
62
+ STATUS_CANCELLED = "cancelled"
63
+ STATUS_ROLLED_BACK = "rolled-back"
64
+
65
+
66
+ class UpgradeError(RuntimeError):
67
+ pass
68
+
69
+
70
+ def _now() -> int:
71
+ return int(time.time())
72
+
73
+
74
+ @dataclass
75
+ class UpgradeStore:
76
+ """Durable, instance-scoped upgrade state with atomic writes."""
77
+
78
+ root: Path
79
+
80
+ @property
81
+ def state_path(self) -> Path:
82
+ return self.root / "state.json"
83
+
84
+ @property
85
+ def activation_path(self) -> Path:
86
+ return self.root / "active.json"
87
+
88
+ @property
89
+ def cancel_path(self) -> Path:
90
+ return self.root / "cancel"
91
+
92
+ def load(self) -> dict[str, Any] | None:
93
+ try:
94
+ value = json.loads(self.state_path.read_text(encoding="utf-8"))
95
+ except (OSError, ValueError):
96
+ return None
97
+ return value if isinstance(value, dict) else None
98
+
99
+ def write(self, state: Mapping[str, Any]) -> None:
100
+ self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
101
+ os.chmod(self.root, 0o700)
102
+ payload = dict(state)
103
+ payload["updated_at"] = _now()
104
+ temporary = self.state_path.with_suffix(f".tmp.{os.getpid()}")
105
+ temporary.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
106
+ os.chmod(temporary, 0o600)
107
+ temporary.replace(self.state_path)
108
+
109
+ def load_activation(self) -> dict[str, Any] | None:
110
+ try:
111
+ value = json.loads(self.activation_path.read_text(encoding="utf-8"))
112
+ except (OSError, ValueError):
113
+ return None
114
+ return value if isinstance(value, dict) else None
115
+
116
+ def write_activation(self, record: Mapping[str, Any]) -> None:
117
+ self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
118
+ temporary = self.activation_path.with_suffix(f".tmp.{os.getpid()}")
119
+ temporary.write_text(json.dumps(dict(record), indent=2, sort_keys=True) + "\n", encoding="utf-8")
120
+ os.chmod(temporary, 0o600)
121
+ temporary.replace(self.activation_path)
122
+
123
+ def cancel_requested(self) -> bool:
124
+ return self.cancel_path.exists()
125
+
126
+ def request_cancel(self) -> None:
127
+ self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
128
+ self.cancel_path.write_text(str(_now()) + "\n", encoding="utf-8")
129
+
130
+ def clear_cancel(self) -> None:
131
+ self.cancel_path.unlink(missing_ok=True)
132
+
133
+
134
+ def installation_root(repository_root: Path) -> Path:
135
+ """The main installation directory a checkout belongs to.
136
+
137
+ A linked git worktree (``.git`` is a file) belongs to its main checkout;
138
+ upgrade state is per installation, so every worktree of one install
139
+ shares it. A standalone clone is its own installation.
140
+ """
141
+ root = repository_root.resolve()
142
+ git_marker = root / ".git"
143
+ if git_marker.is_file():
144
+ try:
145
+ content = git_marker.read_text(encoding="utf-8")
146
+ for line in content.splitlines():
147
+ if line.startswith("gitdir:"):
148
+ git_dir = Path(line.split(":", 1)[1].strip())
149
+ if not git_dir.is_absolute():
150
+ git_dir = (root / git_dir).resolve()
151
+ # <main>/.git/worktrees/<name> → <main>
152
+ if git_dir.parent.name == "worktrees" and git_dir.parent.parent.name == ".git":
153
+ return git_dir.parent.parent.parent.resolve()
154
+ except OSError:
155
+ pass
156
+ return root
157
+
158
+
159
+ def instance_key(repository_root: Path) -> str:
160
+ """Durable upgrade-state key: stable org identity × installation identity.
161
+
162
+ Identity is never inferred from a path alone: the stable organization ID
163
+ from egregore.json is required and leads the key, so two organizations
164
+ that share, symlink, or otherwise resolve to the same memory repository
165
+ can never share activation, worker, lock, or rollback state. The
166
+ installation path is composed in explicitly so two installs of the same
167
+ organization stay independent, while worktrees of one install share it.
168
+ A checkout without a stable org_id fails closed.
169
+ """
170
+ root = repository_root.resolve()
171
+ try:
172
+ config = json.loads((root / "egregore.json").read_text(encoding="utf-8"))
173
+ except (OSError, ValueError) as exc:
174
+ raise UpgradeError(f"cannot read egregore.json for instance identity: {exc}") from exc
175
+ org_id = str(config.get("org_id") or "").strip()
176
+ if not org_id:
177
+ raise UpgradeError(
178
+ "this instance has no stable org_id; upgrade state fails closed "
179
+ "without a stable organization identity"
180
+ )
181
+ install = installation_root(root)
182
+ import hashlib
183
+
184
+ return hashlib.sha256(f"{org_id}|{install}".encode("utf-8")).hexdigest()[:16]
185
+
186
+
187
+ def upgrade_root(repository_root: Path) -> Path:
188
+ """Instance-scoped upgrade state dir, keyed by composed stable identity."""
189
+ override = os.environ.get("EGREGORE_UPGRADE_ROOT")
190
+ if override:
191
+ return Path(override).expanduser() / instance_key(repository_root)
192
+ return Path.home() / ".egregore" / "runtime" / "upgrade" / instance_key(repository_root)
193
+
194
+
195
+ def build_cli_context(repository_root: Path):
196
+ """Store/engine/retriever wiring for the CLI — keeps retrieval adapter
197
+ imports out of harness_cli, which must stay behind Runtime contracts."""
198
+ from .runtime import local_runtime
199
+
200
+ retriever = QmdLocalRetriever(repository_root=repository_root)
201
+ store = UpgradeStore(root=upgrade_root(repository_root))
202
+ engine = UpgradeEngine(
203
+ repository_root=repository_root,
204
+ store=store,
205
+ runtime=local_runtime(repository_root, push_remote=False),
206
+ retriever=retriever,
207
+ )
208
+ return store, engine, retriever
209
+
210
+
211
+ def _pid_alive(pid: int) -> bool:
212
+ try:
213
+ os.kill(pid, 0)
214
+ return True
215
+ except (OSError, ValueError, TypeError):
216
+ return False
217
+
218
+
219
+ def new_state(
220
+ *,
221
+ instance_path: Path,
222
+ org_id: str,
223
+ instance_hash: str,
224
+ candidate_version: str,
225
+ active_version: str,
226
+ candidate_source: str = "",
227
+ ) -> dict[str, Any]:
228
+ return {
229
+ "schema_version": SCHEMA_VERSION,
230
+ "instance_path": str(instance_path),
231
+ "org_id": org_id,
232
+ "instance_hash": instance_hash,
233
+ "candidate_version": candidate_version,
234
+ "candidate_source": candidate_source,
235
+ "candidate_digest": None,
236
+ "installed_path": None,
237
+ "active_version": active_version,
238
+ "rollback_version": active_version,
239
+ "status": STATUS_PENDING,
240
+ "stages": [
241
+ {"key": key, "label": label, "state": "pending", "detail": ""}
242
+ for key, label in STAGES
243
+ ],
244
+ "source_revision": None,
245
+ "semantic_revision": None,
246
+ "progress": {},
247
+ "gates": {},
248
+ "failure": None,
249
+ "worker": None,
250
+ "started_at": _now(),
251
+ }
252
+
253
+
254
+ def stage_index(state: Mapping[str, Any], key: str) -> int:
255
+ for index, stage in enumerate(state.get("stages", ())):
256
+ if stage.get("key") == key:
257
+ return index
258
+ raise UpgradeError(f"unknown upgrade stage: {key}")
259
+
260
+
261
+ def describe(state: Mapping[str, Any] | None, *, worker_alive: bool | None = None) -> dict[str, Any]:
262
+ """Status projection for adapters (Settings, session start, readiness)."""
263
+ if state is None:
264
+ return {"schema_version": SCHEMA_VERSION, "status": "none"}
265
+ projected = dict(state)
266
+ worker = state.get("worker") or {}
267
+ pid = worker.get("pid")
268
+ alive = worker_alive if worker_alive is not None else (_pid_alive(pid) if pid else False)
269
+ projected["worker_alive"] = bool(alive)
270
+ # A preparing status with a dead worker is not "active work" — it is a
271
+ # resumable interruption and must be presented as such.
272
+ if state.get("status") == STATUS_PREPARING and not alive:
273
+ projected["status"] = "interrupted"
274
+ return projected
275
+
276
+
277
+ @dataclass
278
+ class UpgradeEngine:
279
+ """Runs preparation stages against one instance. Resumable by design."""
280
+
281
+ repository_root: Path
282
+ store: UpgradeStore
283
+ runtime: Any # EgregoreRuntime; typed loosely to keep import edges thin
284
+ retriever: QmdLocalRetriever
285
+ poll_seconds: float = 1.0
286
+ log: Any = None # callable(str) for worker logs; never user-facing
287
+
288
+ def _mark(self, state: dict[str, Any], key: str, stage_state: str, detail: str = "") -> None:
289
+ index = stage_index(state, key)
290
+ stage = state["stages"][index]
291
+ stage["state"] = stage_state
292
+ stage["detail"] = detail
293
+ if stage_state == "running" and "started_at" not in stage:
294
+ stage["started_at"] = _now()
295
+ if stage_state in ("done", "failed"):
296
+ stage["finished_at"] = _now()
297
+ self.store.write(state)
298
+
299
+ def _fail(self, state: dict[str, Any], key: str, message: str) -> None:
300
+ self._mark(state, key, "failed", message[:300])
301
+ state["status"] = STATUS_FAILED
302
+ state["failure"] = {"stage": key, "message": message[:300]}
303
+ self.store.write(state)
304
+
305
+ def _cancelled(self, state: dict[str, Any]) -> bool:
306
+ if not self.store.cancel_requested():
307
+ return False
308
+ state["status"] = STATUS_CANCELLED
309
+ self.store.write(state)
310
+ return True
311
+
312
+ def _stage_done(self, state: dict[str, Any], key: str) -> bool:
313
+ return state["stages"][stage_index(state, key)].get("state") == "done"
314
+
315
+ # -- stages ----------------------------------------------------------
316
+
317
+ def _run_sync(self, state: dict[str, Any]) -> bool:
318
+ receipt = self.runtime.synchronize()
319
+ current = bool(getattr(receipt, "canonical_current", False))
320
+ if not current:
321
+ failures = tuple(getattr(receipt, "failures", ()) or ())
322
+ self._fail(state, "sync", "; ".join(failures) or "team memory could not be synchronized")
323
+ return False
324
+ self._mark(state, "sync", "done", "canonical memory current")
325
+ return True
326
+
327
+ def _run_candidate(self, state: dict[str, Any]) -> bool:
328
+ revision = self.retriever._source_revision()
329
+ state["source_revision"] = revision
330
+ self._mark(state, "candidate", "done", revision)
331
+ return True
332
+
333
+ @staticmethod
334
+ def _sha256(path: Path) -> str:
335
+ import hashlib
336
+
337
+ digest = hashlib.sha256()
338
+ with path.open("rb") as handle:
339
+ for block in iter(lambda: handle.read(1 << 20), b""):
340
+ digest.update(block)
341
+ return digest.hexdigest()
342
+
343
+ def _run_install(self, state: dict[str, Any]) -> bool:
344
+ import shutil
345
+ import tarfile
346
+
347
+ source = Path(state.get("candidate_source") or "")
348
+ if not source.is_file():
349
+ self._fail(state, "install", "no candidate package tarball was staged for this upgrade")
350
+ return False
351
+ state["candidate_digest"] = self._sha256(source)
352
+ self.store.write(state)
353
+
354
+ target = self.store.root / "candidate"
355
+ if target.exists():
356
+ shutil.rmtree(target)
357
+ target.mkdir(parents=True, mode=0o700)
358
+ try:
359
+ with tarfile.open(source, "r:gz") as archive:
360
+ for member in archive.getmembers():
361
+ member_path = (target / member.name).resolve()
362
+ if not str(member_path).startswith(str(target.resolve())):
363
+ raise UpgradeError(f"unsafe path in candidate archive: {member.name}")
364
+ archive.extractall(target)
365
+ except Exception as exc:
366
+ self._fail(state, "install", f"candidate extraction failed: {exc}")
367
+ return False
368
+
369
+ package_root = target / "package"
370
+ try:
371
+ manifest = json.loads((package_root / "package.json").read_text(encoding="utf-8"))
372
+ except (OSError, ValueError) as exc:
373
+ self._fail(state, "install", f"candidate package.json unreadable: {exc}")
374
+ return False
375
+ if str(manifest.get("version")) != state["candidate_version"]:
376
+ self._fail(
377
+ state,
378
+ "install",
379
+ f"candidate package is {manifest.get('version')}, expected {state['candidate_version']}",
380
+ )
381
+ return False
382
+ scripts = manifest.get("scripts") or {}
383
+ for lifecycle in ("preinstall", "install", "postinstall"):
384
+ if lifecycle in scripts:
385
+ self._fail(state, "install", f"candidate declares a {lifecycle} lifecycle script; refused")
386
+ return False
387
+ missing = [tree for tree in BUNDLE_TREES if not (package_root / "runtime" / tree).is_dir()]
388
+ if missing:
389
+ self._fail(state, "install", "candidate is missing packaged bundles: " + ", ".join(missing))
390
+ return False
391
+ state["installed_path"] = str(package_root)
392
+ self._mark(
393
+ state,
394
+ "install",
395
+ "done",
396
+ f"{manifest.get('version')} · sha256 {state['candidate_digest'][:16]} · all four bundles present",
397
+ )
398
+ return True
399
+
400
+ def _run_node(self, state: dict[str, Any]) -> bool:
401
+ node = self.retriever.environment.get("EGREGORE_QMD_NODE_BIN")
402
+ if not node:
403
+ self._fail(state, "node", "no usable Node runtime was found for this instance")
404
+ return False
405
+ probe = subprocess.run(
406
+ (node, "--version"), capture_output=True, text=True, timeout=15, check=False
407
+ )
408
+ if probe.returncode != 0:
409
+ self._fail(state, "node", "the selected Node runtime failed its version probe")
410
+ return False
411
+ self._mark(state, "node", "done", f"{probe.stdout.strip()} at instance-selected path")
412
+ return True
413
+
414
+ def _run_qmd(self, state: dict[str, Any]) -> bool:
415
+ # An explicitly pinned QMD (constructor command or EGREGORE_QMD_BIN)
416
+ # is the instance's chosen binary — verify it instead of installing
417
+ # over it. Otherwise ensure the instance-owned managed install.
418
+ if self.retriever._configured_command or self.retriever.environment.get("EGREGORE_QMD_BIN"):
419
+ try:
420
+ self.retriever._ensure_version()
421
+ except Exception as exc:
422
+ self._fail(state, "qmd", f"pinned QMD failed verification: {exc}")
423
+ return False
424
+ self._mark(state, "qmd", "done", f"QMD {QMD_VERSION} (pinned by configuration)")
425
+ return True
426
+ binary = self.retriever._managed_binary()
427
+ if not (binary.is_file() and os.access(binary, os.X_OK)):
428
+ try:
429
+ binary = self.retriever.install_managed()
430
+ except Exception as exc:
431
+ self._fail(state, "qmd", f"QMD {QMD_VERSION} install failed: {exc}")
432
+ return False
433
+ self._mark(state, "qmd", "done", f"QMD {QMD_VERSION} (instance-owned)")
434
+ return True
435
+
436
+ def _run_bm25(self, state: dict[str, Any]) -> bool:
437
+ try:
438
+ health = self.retriever.update()
439
+ except Exception as exc:
440
+ self._fail(state, "bm25", f"keyword index build failed: {exc}")
441
+ return False
442
+ if not health.bm25_ready:
443
+ self._fail(state, "bm25", "keyword index did not become ready")
444
+ return False
445
+ self._record_progress(state)
446
+ self._mark(state, "bm25", "done", "keyword search current for the candidate revision")
447
+ return True
448
+
449
+ def _record_progress(self, state: dict[str, Any]) -> None:
450
+ completed = self.retriever._run(("status",), timeout=30)
451
+ counts = self.retriever._status_counts(completed.stdout if completed.returncode == 0 else "")
452
+ state["progress"] = {
453
+ "documents": counts["documents"],
454
+ "vectors": counts["vectors"],
455
+ "pending": counts["pending"],
456
+ "counted_at": _now(),
457
+ }
458
+ self.store.write(state)
459
+
460
+ def _run_embed(self, state: dict[str, Any], key: str = "embed") -> bool:
461
+ self._mark(state, key, "running", "embedding team memory")
462
+ # One `qmd embed` invocation proves nothing by itself: qmd embeds in
463
+ # bounded batches, a concurrent session's embedder can hold the embed
464
+ # lock (our pass prints "Skipping" and exits 0 while theirs runs), and
465
+ # freshly written vectors become countable slightly after the process
466
+ # exits. Drain instead: keep invoking embed and re-reading the real
467
+ # count for as long as pending falls; fail only after a full settle
468
+ # window passes with no progress from anyone.
469
+ try:
470
+ settle = float(
471
+ self.retriever.environment.get(
472
+ "EGREGORE_UPGRADE_EMBED_SETTLE_SECONDS", "20"
473
+ )
474
+ )
475
+ except (AttributeError, TypeError, ValueError):
476
+ settle = 20.0
477
+ previous: int | None = None
478
+ deadline = time.monotonic() + settle
479
+ while True:
480
+ if self._cancelled(state):
481
+ return False
482
+ try:
483
+ self.retriever.embed_foreground()
484
+ except Exception as exc:
485
+ self._fail(state, key, f"meaning-index build failed: {exc}")
486
+ return False
487
+ self._record_progress(state)
488
+ pending = int(state["progress"].get("pending", 0) or 0)
489
+ if not pending:
490
+ break
491
+ if previous is None or pending < previous:
492
+ previous = pending
493
+ deadline = time.monotonic() + settle
494
+ vectors = state["progress"].get("vectors", 0)
495
+ self._mark(
496
+ state, key, "running", f"{vectors} chunks embedded · {pending} pending"
497
+ )
498
+ elif time.monotonic() >= deadline:
499
+ self._fail(state, key, f"{pending} documents still awaiting embeddings after the build")
500
+ return False
501
+ if settle > 0:
502
+ time.sleep(min(2.0, settle))
503
+ self._mark(state, key, "done", f"{state['progress'].get('vectors', 0)} chunks embedded")
504
+ return True
505
+
506
+ def _run_delta(self, state: dict[str, Any]) -> bool:
507
+ # Canonical memory may have moved while the initial build ran. Converge:
508
+ # re-sync, re-index, embed the remaining delta — bounded, resumable.
509
+ for _ in range(5):
510
+ if self._cancelled(state):
511
+ return False
512
+ self.retriever._source_revision_cache = None
513
+ if self.retriever._semantic_state_current():
514
+ state["semantic_revision"] = self.retriever._semantic_source_revision()
515
+ state["source_revision"] = self.retriever._source_revision()
516
+ self._mark(state, "delta", "done", "meaning index matches the candidate revision")
517
+ return True
518
+ receipt = self.runtime.synchronize()
519
+ if not bool(getattr(receipt, "canonical_current", False)):
520
+ self._fail(state, "delta", "team memory changed and could not be re-synchronized")
521
+ return False
522
+ # Bring the keyword index to the new revision before embedding the
523
+ # delta — a no-op when synchronize already did it.
524
+ try:
525
+ self.retriever.update()
526
+ except Exception as exc:
527
+ self._fail(state, "delta", f"keyword index refresh failed: {exc}")
528
+ return False
529
+ if not self._run_embed(state, key="delta"):
530
+ return False
531
+ # _run_embed marked delta done; loop re-checks currency in case
532
+ # memory moved again during that embed.
533
+ self._mark(state, "delta", "running", "verifying the delta landed")
534
+ self._fail(state, "delta", "team memory kept changing during preparation; retry when quieter")
535
+ return False
536
+
537
+ def _run_verify(self, state: dict[str, Any]) -> bool:
538
+ from .readiness import build_report, session_boundary_state
539
+ from .contracts import Permission
540
+
541
+ health = self.retriever.health()
542
+ gates: dict[str, bool | str] = {}
543
+ gates["bm25_current"] = bool(health.bm25_ready and health.index_source_revision == health.source_revision)
544
+ gates["semantic_complete"] = bool(health.semantic_ready)
545
+ gates["semantic_matches_source"] = bool(
546
+ health.semantic_source_revision is not None
547
+ and health.semantic_source_revision == health.source_revision
548
+ )
549
+ gates["reranker_disabled"] = not RERANKING_ENABLED
550
+ boundary = session_boundary_state(self.repository_root)
551
+ authorization: Any
552
+ try:
553
+ actor = self.runtime.resolve_actor(
554
+ session_id=os.environ.get("EGREGORE_SESSION_ID", "upgrade-verify"),
555
+ harness="upgrade",
556
+ )
557
+ authorization = self.runtime.authorize(actor, Permission.READ)
558
+ gates["identity_resolves"] = True
559
+ gates["authorization_allows"] = bool(authorization.allowed)
560
+ except Exception as exc:
561
+ authorization = exc
562
+ gates["identity_resolves"] = False
563
+ gates["authorization_allows"] = False
564
+ report = build_report(
565
+ root=self.repository_root,
566
+ health=health,
567
+ boundary=boundary,
568
+ authorization=authorization if not isinstance(authorization, bool) else None,
569
+ )
570
+ stages = {item.key: item.stage for item in report.items}
571
+ gates["boundary_ready"] = stages.get("boundary") == "ready"
572
+ gates["hybrid_probe"] = stages.get("search") == "ready" and gates["semantic_complete"]
573
+ # Retrieval in the upgraded Runtime is QMD-only by construction: the
574
+ # engine never consults graph projections and records that contract.
575
+ gates["graph_retrieval"] = "not-used-by-this-runtime"
576
+ state["gates"] = gates
577
+ state["semantic_revision"] = health.semantic_source_revision
578
+ failed = [name for name, value in gates.items() if value is False]
579
+ if failed:
580
+ self._fail(state, "verify", "gates failed: " + ", ".join(failed))
581
+ return False
582
+ self._mark(state, "verify", "done", "all activation gates passed")
583
+ return True
584
+
585
+ # -- driver ----------------------------------------------------------
586
+
587
+ def prepare(self) -> dict[str, Any]:
588
+ state = self.store.load()
589
+ if state is None:
590
+ raise UpgradeError("no upgrade has been initialized for this instance")
591
+ if state.get("status") == STATUS_ACTIVE:
592
+ return state
593
+ self.store.clear_cancel()
594
+ state["status"] = STATUS_PREPARING
595
+ state["worker"] = {"pid": os.getpid(), "started_at": _now()}
596
+ self.store.write(state)
597
+
598
+ runners = {
599
+ "sync": self._run_sync,
600
+ "candidate": self._run_candidate,
601
+ "install": self._run_install,
602
+ "node": self._run_node,
603
+ "qmd": self._run_qmd,
604
+ "bm25": self._run_bm25,
605
+ "embed": self._run_embed,
606
+ "delta": self._run_delta,
607
+ "verify": self._run_verify,
608
+ }
609
+ for key, _label in STAGES:
610
+ if self._cancelled(state):
611
+ return state
612
+ if self._stage_done(state, key):
613
+ continue
614
+ self._mark(state, key, "running")
615
+ if not runners[key](state):
616
+ return state
617
+ state["status"] = STATUS_READY
618
+ self.store.write(state)
619
+ return state
620
+
621
+ def _apply_candidate_bytes(self, state: dict[str, Any]) -> dict[str, Any]:
622
+ """Copy the installed candidate bundle into the instance, backing up
623
+ every replaced file so rollback restores exact previous bytes."""
624
+ import shutil
625
+ import tarfile
626
+
627
+ package_root = Path(state.get("installed_path") or "")
628
+ if not (package_root / "runtime" / APPLY_TREES[0]).is_dir():
629
+ raise UpgradeError("candidate bundle tree is missing; re-run preparation")
630
+ instance = Path(state["instance_path"])
631
+ replaced: list[str] = []
632
+ added: list[str] = []
633
+ selected: dict[str, Path] = {}
634
+ for tree_name in APPLY_TREES:
635
+ tree = package_root / "runtime" / tree_name
636
+ if not tree.is_dir():
637
+ continue
638
+ for source_file in tree.rglob("*"):
639
+ if not source_file.is_file():
640
+ continue
641
+ relative = str(source_file.relative_to(tree))
642
+ selected.setdefault(relative, source_file)
643
+ backup_path = self.store.root / "rollback-files.tar.gz"
644
+ with tarfile.open(backup_path, "w:gz") as backup:
645
+ for relative in sorted(selected):
646
+ destination = instance / relative
647
+ if destination.exists():
648
+ backup.add(destination, arcname=relative)
649
+ replaced.append(relative)
650
+ else:
651
+ added.append(relative)
652
+ for relative in sorted(selected):
653
+ destination = instance / relative
654
+ destination.parent.mkdir(parents=True, exist_ok=True)
655
+ shutil.copy2(selected[relative], destination)
656
+ manifest = {"replaced": replaced, "added": added, "trees": list(APPLY_TREES)}
657
+ (self.store.root / "rollback-manifest.json").write_text(
658
+ json.dumps(manifest, indent=2) + "\n", encoding="utf-8"
659
+ )
660
+ return {"applied_files": len(selected), "replaced": len(replaced), "added": len(added)}
661
+
662
+ def activate(self) -> dict[str, Any]:
663
+ state = self.store.load()
664
+ if state is None or state.get("status") != STATUS_READY:
665
+ raise UpgradeError(
666
+ "the candidate Runtime is not ready to activate; every gate must pass first"
667
+ )
668
+ gates = state.get("gates", {})
669
+ if any(value is False for value in gates.values()):
670
+ raise UpgradeError("activation refused: a recorded gate is failing")
671
+ # The recorded tarball digest must still match the bytes on disk —
672
+ # a swapped or corrupted candidate never activates.
673
+ source = Path(state.get("candidate_source") or "")
674
+ if not source.is_file() or self._sha256(source) != state.get("candidate_digest"):
675
+ raise UpgradeError("candidate package digest no longer matches; re-run preparation")
676
+ applied = self._apply_candidate_bytes(state)
677
+ record = {
678
+ "schema_version": SCHEMA_VERSION,
679
+ "active_version": state["candidate_version"],
680
+ "rollback_version": state["rollback_version"],
681
+ "source_revision": state["source_revision"],
682
+ "semantic_revision": state["semantic_revision"],
683
+ "candidate_digest": state["candidate_digest"],
684
+ "installed_path": state["installed_path"],
685
+ "applied": applied,
686
+ "activated_at": _now(),
687
+ "retrieval": "runtime-qmd",
688
+ "graph_retrieval": "not-used-by-this-runtime",
689
+ }
690
+ # Atomic: the activation record replaces in one rename; the state file
691
+ # then records active status. A crash between the two leaves a valid
692
+ # activation record and a resumable state — never partial retrieval.
693
+ self.store.write_activation(record)
694
+ state["status"] = STATUS_ACTIVE
695
+ state["active_version"] = state["candidate_version"]
696
+ self.store.write(state)
697
+ return state
698
+
699
+ def rollback(self) -> dict[str, Any]:
700
+ import tarfile
701
+
702
+ state = self.store.load()
703
+ if state is None:
704
+ raise UpgradeError("no upgrade state exists for this instance")
705
+ activation = self.store.load_activation() or {}
706
+ target = activation.get("rollback_version") or state.get("rollback_version")
707
+ if not target:
708
+ raise UpgradeError("no rollback version is recorded for this instance")
709
+ # Restore exact previous bytes: replaced files come back from the
710
+ # backup archive, files the candidate added are removed.
711
+ backup_path = self.store.root / "rollback-files.tar.gz"
712
+ manifest_path = self.store.root / "rollback-manifest.json"
713
+ if activation.get("applied") and backup_path.is_file() and manifest_path.is_file():
714
+ instance = Path(state["instance_path"])
715
+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
716
+ with tarfile.open(backup_path, "r:gz") as backup:
717
+ for member in backup.getmembers():
718
+ member_path = (instance / member.name).resolve()
719
+ if not str(member_path).startswith(str(instance.resolve())):
720
+ raise UpgradeError(f"unsafe path in rollback archive: {member.name}")
721
+ backup.extractall(instance)
722
+ for relative in manifest.get("added", ()): # candidate-only files
723
+ candidate_file = (instance / relative).resolve()
724
+ if str(candidate_file).startswith(str(instance.resolve())):
725
+ candidate_file.unlink(missing_ok=True)
726
+ record = {
727
+ "schema_version": SCHEMA_VERSION,
728
+ "active_version": target,
729
+ "rollback_version": target,
730
+ "rolled_back_from": state.get("candidate_version"),
731
+ "rolled_back_at": _now(),
732
+ "retrieval": "previous-runtime",
733
+ }
734
+ self.store.write_activation(record)
735
+ state["status"] = STATUS_ROLLED_BACK
736
+ state["active_version"] = target
737
+ self.store.write(state)
738
+ return state
739
+
740
+ def cancel(self) -> dict[str, Any]:
741
+ state = self.store.load()
742
+ if state is None:
743
+ raise UpgradeError("no upgrade state exists for this instance")
744
+ self.store.request_cancel()
745
+ worker = state.get("worker") or {}
746
+ pid = worker.get("pid")
747
+ if state.get("status") == STATUS_PREPARING and not (pid and _pid_alive(pid)):
748
+ # No live worker will observe the flag — record the cancel now.
749
+ state["status"] = STATUS_CANCELLED
750
+ self.store.write(state)
751
+ return self.store.load() or state
752
+
753
+
754
+ __all__ = [
755
+ "SCHEMA_VERSION",
756
+ "STAGES",
757
+ "STATUS_ACTIVE",
758
+ "STATUS_CANCELLED",
759
+ "STATUS_FAILED",
760
+ "STATUS_PENDING",
761
+ "STATUS_PREPARING",
762
+ "STATUS_READY",
763
+ "STATUS_ROLLED_BACK",
764
+ "UpgradeEngine",
765
+ "UpgradeError",
766
+ "UpgradeStore",
767
+ "describe",
768
+ "new_state",
769
+ "upgrade_root",
770
+ ]