create-egregore 0.20.2 → 0.21.0-runtime-mvp.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (706) hide show
  1. package/assets/egregore-launcher.js +1013 -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,1106 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ # Named graph operations — clean interface over raw Cypher.
4
+ # Keeps implementation details out of the TUI.
5
+ #
6
+ # Usage: bash bin/graph-op.sh <operation> [args...]
7
+ #
8
+ # Operations:
9
+ # mark-read <session-id> [user] Mark a handoff as read
10
+ # mark-done <session-id> [user] Mark a handoff as done/resolved
11
+ # mark-expired <session-id> [user] Explicitly expire an open handoff
12
+ # reopen-handoff <session-id> [user] Reopen a terminal handoff
13
+ # answer-question <set-id> Mark a question set as answered
14
+ # resolve-handoffs <user> Resolve completed explicit implementation lineage
15
+ # set-topic <session-id> <topic> [branch]
16
+ # Set topic (and optionally branch) on a Session node
17
+ # record-focus <session-id> <shown-json> <selected> [dismissed-json]
18
+ # Track Focus option selection for adaptive options
19
+ # merge-person <keep-name> <alias-name>
20
+ # Reconcile two Person nodes — projects relationships
21
+ # to keep-name and retains alias-name append-only
22
+ # create-harvest <id> <topic> <intent> <initiator>
23
+ # Create a Harvest node and link to initiator (WAL-backed)
24
+ # create-harvest-session <harvest-id> <session-id> <person-name> [status]
25
+ # Create a HarvestSession linked to a Harvest and Person.
26
+ # status defaults to 'active' (back-compat). Valid values:
27
+ # pending | active | answered | complete | incorporated.
28
+ # Async respondents should be created with 'pending'.
29
+ # record-harvest-turn <session-id> <turn> <question> <intent> [answer] [eval]
30
+ # Record a question-answer turn in a HarvestSession
31
+ # complete-harvest <harvest-id> <artifact-path>
32
+ # Mark harvest complete and link synthesis artifact
33
+ # catalog List bounded read operations and their contracts
34
+ # open-handoffs <user> [limit] Read non-terminal handoffs addressed to a person
35
+ # pending-questions <user> [limit] Read active question sets awaiting a person
36
+ # lineage <topic> [limit] Trace matching sessions, handoffs, implementations,
37
+ # PRs, and canonical evidence files
38
+ # meeting-history <query> [limit]
39
+ # Find a meeting sequence, participants, derived
40
+ # knowledge, and unprojected canonical meeting files
41
+
42
+ SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
43
+
44
+ if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
45
+ echo "Usage: graph-op.sh <operation> [args...]"
46
+ echo ""
47
+ echo "Named graph operations — clean interface over raw Cypher."
48
+ echo ""
49
+ echo "Operations:"
50
+ echo " mark-read <sid> [user] Mark handoff as read"
51
+ echo " mark-done <sid> [user] Mark handoff as done"
52
+ echo " mark-expired <sid> [user] Explicitly expire an open handoff"
53
+ echo " reopen-handoff <sid> [user] Reopen a done/expired handoff"
54
+ echo " answer-question <qid> Mark question set as answered"
55
+ echo " resolve-handoffs <user> Resolve completed implementation lineage"
56
+ echo " set-topic <sid> <topic> Set topic on a Session node"
57
+ echo " merge-person <keep> <alias> Reconcile a Person as a canonical alias"
58
+ echo " claim-handoff <sid> <ho> Link implementing session to handoff"
59
+ echo " create-pr <sid> <num> <repo> <author> [title]"
60
+ echo " register-artifact <id> <url> <title> <type> <author> <topics> <excerpt>"
61
+ echo " create-harvest / complete-harvest / record-harvest-turn"
62
+ echo " catalog List bounded read operation contracts"
63
+ echo " open-handoffs <user> [n] Read recent non-terminal handoffs"
64
+ echo " pending-questions <user> [n] Read recent active question sets"
65
+ echo " lineage <topic> [n] Trace handoff/implementation/PR evidence"
66
+ echo " meeting-history <query> [n] Find meeting continuity and coverage gaps"
67
+ echo " wal-status Show WAL pending count"
68
+ exit 0
69
+ fi
70
+
71
+ GS="$SCRIPT_DIR/bin/graph.sh"
72
+
73
+ # Named reads are explicit projection requests by definition — they pass the
74
+ # Runtime cutover gate that silences background graph callers.
75
+ export EGREGORE_GRAPH_EXPLICIT=1
76
+
77
+ OP="${1:-}"
78
+ shift || true
79
+
80
+ # --- Local mode gate: bail immediately ---
81
+ _MODE=$(jq -r '.mode // "connected"' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
82
+
83
+ # The catalog is static runtime metadata, not a graph read. Keep it available
84
+ # in local mode so every harness can route correctly without opening this file
85
+ # or guessing whether an operation exists.
86
+ if [ "$OP" = "catalog" ]; then
87
+ jq -n --arg mode "$_MODE" '{
88
+ schema: "egregore.graph-operation-catalog/v1",
89
+ definitionVersion: 1,
90
+ mode: $mode,
91
+ operations: [
92
+ {
93
+ name: "open-handoffs",
94
+ intent: "current non-terminal handoffs addressed to a person",
95
+ usage: "bash bin/graph-op.sh open-handoffs <user> [limit]",
96
+ availability: "connected",
97
+ maxResults: 25,
98
+ evidence: "live graph state"
99
+ },
100
+ {
101
+ name: "pending-questions",
102
+ intent: "current active question sets awaiting a person",
103
+ usage: "bash bin/graph-op.sh pending-questions <user> [limit]",
104
+ availability: "connected",
105
+ maxResults: 25,
106
+ evidence: "live graph state"
107
+ },
108
+ {
109
+ name: "lineage",
110
+ intent: "handoff to implementation, branch, PR, and superseding direction",
111
+ usage: "bash bin/graph-op.sh lineage <topic> [limit]",
112
+ availability: "connected",
113
+ maxResults: 15,
114
+ evidence: "graph relationships plus canonical file pointers"
115
+ },
116
+ {
117
+ name: "meeting-history",
118
+ intent: "cross-meeting continuity for a company, person, or topic",
119
+ usage: "bash bin/graph-op.sh meeting-history <query> [limit]",
120
+ availability: "connected",
121
+ maxResults: 15,
122
+ evidence: "projected meeting relationships plus canonical file coverage"
123
+ }
124
+ ]
125
+ }'
126
+ exit 0
127
+ fi
128
+
129
+ if [ "$_MODE" = "local" ]; then
130
+ echo '{"results":[]}'
131
+ exit 0
132
+ fi
133
+
134
+ # Return a bounded set of exact canonical paths containing a literal query.
135
+ # This is intentionally a coverage check around graph results, not a second
136
+ # full-text answer corpus: agents still open only the relevant canonical files.
137
+ memory_file_candidates() {
138
+ local query="$1"
139
+ local limit="$2"
140
+ shift 2
141
+ local filename_hits=""
142
+ local content_hits=""
143
+ local hits=""
144
+
145
+ if command -v rg >/dev/null 2>&1; then
146
+ filename_hits="$(
147
+ rg --files --glob '*.md' --glob '!index.md' "$@" 2>/dev/null \
148
+ | sort \
149
+ | while IFS= read -r path; do
150
+ printf '%s' "$path" | grep -Fqi -- "$query" \
151
+ && printf 'filename\t%s\n' "$path"
152
+ done || true
153
+ )"
154
+ content_hits="$(
155
+ rg -i -l -F --glob '*.md' --glob '!index.md' -- "$query" "$@" 2>/dev/null \
156
+ | sort \
157
+ | while IFS= read -r path; do printf 'content\t%s\n' "$path"; done || true
158
+ )"
159
+ else
160
+ content_hits="$(
161
+ find -L "$@" -type f -name '*.md' -print 2>/dev/null \
162
+ | while IFS= read -r path; do
163
+ [ "$(basename "$path")" = "index.md" ] && continue
164
+ printf '%s' "$path" | grep -Fqi -- "$query" \
165
+ && printf 'filename\t%s\n' "$path"
166
+ grep -Fqi -- "$query" "$path" 2>/dev/null \
167
+ && printf 'content\t%s\n' "$path"
168
+ done || true
169
+ )"
170
+ fi
171
+
172
+ hits="$(
173
+ printf '%s\n%s\n' "$filename_hits" "$content_hits" \
174
+ | awk -F ' ' 'NF >= 2 && !seen[$2]++' \
175
+ | head -n "$limit"
176
+ )"
177
+
178
+ while IFS=$'\t' read -r match_kind path; do
179
+ [ -n "$path" ] || continue
180
+ case "$path" in
181
+ "$SCRIPT_DIR"/memory/*)
182
+ printf 'memory/%s\t%s\n' "${path#"$SCRIPT_DIR"/memory/}" "$match_kind"
183
+ ;;
184
+ esac
185
+ done <<< "$hits" | jq -Rsc '
186
+ split("\n")
187
+ | map(select(length > 0))
188
+ | map(split("\t") | {evidencePath: .[0], matchKind: .[1]})
189
+ '
190
+ }
191
+
192
+ # Reduce natural-language read queries to a small set of discriminative terms.
193
+ # Named reads should tolerate "42CAP Moritz partner call" without requiring that
194
+ # exact phrase to exist in a graph property or canonical Markdown file.
195
+ meaningful_query_terms() {
196
+ jq -Rn --arg query "$1" '
197
+ [
198
+ $query
199
+ | ascii_downcase
200
+ | scan("[a-z0-9][a-z0-9._+-]*")
201
+ | select(length >= 3)
202
+ | select(. as $term |
203
+ [
204
+ "about","across","after","before","between","call","calls",
205
+ "company","conversation","evolved","first","from","history",
206
+ "later","meeting","meetings","month","partner","partners",
207
+ "person","the","topic","transcript","transcripts","what","with"
208
+ ]
209
+ | index($term) == null
210
+ )
211
+ ]
212
+ | unique
213
+ | if length == 0 then [$query | ascii_downcase] else .[0:8] end
214
+ '
215
+ }
216
+
217
+ # Build a bounded union of literal coverage checks for each meaningful term.
218
+ # The result remains a list of exact canonical paths, not a second answer corpus.
219
+ memory_file_candidates_for_terms() {
220
+ local terms_json="$1"
221
+ local limit="$2"
222
+ shift 2
223
+ local combined='[]'
224
+ local term=""
225
+ local term_hits=""
226
+
227
+ while IFS= read -r term; do
228
+ [ -n "$term" ] || continue
229
+ term_hits="$(memory_file_candidates "$term" "$limit" "$@")"
230
+ combined="$(
231
+ jq -n \
232
+ --argjson prior "$combined" \
233
+ --argjson next "$term_hits" \
234
+ --argjson limit "$limit" '
235
+ ($prior + $next)
236
+ | unique_by(.evidencePath)
237
+ | .[0:$limit]
238
+ '
239
+ )"
240
+ done < <(printf '%s' "$terms_json" | jq -r '.[]')
241
+
242
+ printf '%s\n' "$combined"
243
+ }
244
+
245
+ case "$OP" in
246
+
247
+ mark-read)
248
+ SID="${1:?missing session-id}"
249
+ USER="${2:-}"
250
+ bash "$GS" query "
251
+ MATCH (s:Session {id: \$sid})
252
+ OPTIONAL MATCH (s)-[:HANDED_TO]->(recipient:Person)
253
+ WITH s, collect(DISTINCT recipient) AS recipients
254
+ WHERE (\$user = '' OR any(p IN recipients WHERE
255
+ toLower(p.name) = toLower(\$user)
256
+ OR toLower(coalesce(p.github, '')) = toLower(\$user)))
257
+ AND coalesce(s.handoffStatus, 'pending') IN ['pending','read']
258
+ SET s.handoffReadDate = coalesce(s.handoffReadDate, date()),
259
+ s.handoffUpdatedAt = datetime(),
260
+ s.handoffLifecycleVersion = 1
261
+ FOREACH (_ IN CASE WHEN s.handoffIntent = 'fyi' THEN [1] ELSE [] END |
262
+ SET s.handoffStatus = 'done',
263
+ s.handoffDoneAt = coalesce(s.handoffDoneAt, datetime()),
264
+ s.handoffLifecycleReason = 'fyi_read')
265
+ FOREACH (_ IN CASE WHEN coalesce(s.handoffIntent, 'unclassified') <> 'fyi' THEN [1] ELSE [] END |
266
+ SET s.handoffStatus = 'read',
267
+ s.handoffLifecycleReason = 'recipient_read')
268
+ RETURN s.id AS id, s.topic AS topic, s.handoffStatus AS status,
269
+ coalesce(s.handoffIntent, 'unclassified') AS intent
270
+ " "$(jq -n --arg sid "$SID" --arg user "$USER" '{sid: $sid,user: $user}')"
271
+ ;;
272
+
273
+ mark-done)
274
+ SID="${1:?missing session-id}"
275
+ USER="${2:-}"
276
+ bash "$GS" query "
277
+ MATCH (s:Session {id: \$sid})
278
+ OPTIONAL MATCH (s)-[:HANDED_TO]->(recipient:Person)
279
+ WITH s, collect(DISTINCT recipient) AS recipients
280
+ WHERE (\$user = '' OR any(p IN recipients WHERE
281
+ toLower(p.name) = toLower(\$user)
282
+ OR toLower(coalesce(p.github, '')) = toLower(\$user)))
283
+ AND coalesce(s.handoffStatus, 'pending') IN ['pending','read','claimed']
284
+ SET s.handoffStatus = 'done',
285
+ s.handoffDoneAt = datetime(),
286
+ s.handoffUpdatedAt = datetime(),
287
+ s.handoffLifecycleReason = 'explicit_done',
288
+ s.handoffLifecycleVersion = 1
289
+ RETURN s.id AS id, s.topic AS topic, s.handoffStatus AS status
290
+ " "$(jq -n --arg sid "$SID" --arg user "$USER" '{sid: $sid,user: $user}')"
291
+ ;;
292
+
293
+ mark-expired)
294
+ SID="${1:?missing session-id}"
295
+ USER="${2:-}"
296
+ bash "$GS" query "
297
+ MATCH (s:Session {id: \$sid})
298
+ OPTIONAL MATCH (s)-[:HANDED_TO]->(recipient:Person)
299
+ WITH s, collect(DISTINCT recipient) AS recipients
300
+ WHERE (\$user = '' OR any(p IN recipients WHERE
301
+ toLower(p.name) = toLower(\$user)
302
+ OR toLower(coalesce(p.github, '')) = toLower(\$user)))
303
+ AND coalesce(s.handoffStatus, 'pending') IN ['pending','read','claimed']
304
+ SET s.handoffStatus = 'expired',
305
+ s.handoffExpiredAt = datetime(),
306
+ s.handoffUpdatedAt = datetime(),
307
+ s.handoffLifecycleReason = 'explicit_expired',
308
+ s.handoffLifecycleVersion = 1
309
+ RETURN s.id AS id, s.topic AS topic, s.handoffStatus AS status
310
+ " "$(jq -n --arg sid "$SID" --arg user "$USER" '{sid: $sid,user: $user}')"
311
+ ;;
312
+
313
+ reopen-handoff)
314
+ SID="${1:?missing session-id}"
315
+ USER="${2:-}"
316
+ bash "$GS" query "
317
+ MATCH (s:Session {id: \$sid})
318
+ OPTIONAL MATCH (s)-[:HANDED_TO]->(recipient:Person)
319
+ WITH s, collect(DISTINCT recipient) AS recipients
320
+ WHERE (\$user = '' OR any(p IN recipients WHERE
321
+ toLower(p.name) = toLower(\$user)
322
+ OR toLower(coalesce(p.github, '')) = toLower(\$user)))
323
+ AND s.handoffStatus IN ['done','expired','completed']
324
+ SET s.handoffLastDoneAt = s.handoffDoneAt,
325
+ s.handoffLastExpiredAt = s.handoffExpiredAt,
326
+ s.handoffDoneAt = null,
327
+ s.handoffExpiredAt = null,
328
+ s.handoffStatus = 'pending',
329
+ s.handoffReopenedAt = datetime(),
330
+ s.handoffUpdatedAt = datetime(),
331
+ s.handoffLifecycleReason = 'explicit_reopened',
332
+ s.handoffLifecycleVersion = 1
333
+ RETURN s.id AS id, s.topic AS topic, s.handoffStatus AS status
334
+ " "$(jq -n --arg sid "$SID" --arg user "$USER" '{sid: $sid,user: $user}')"
335
+ ;;
336
+
337
+ answer-question)
338
+ QID="${1:?missing question-set-id}"
339
+ bash "$GS" query "
340
+ MATCH (qs:QuestionSet {id: \$qid})
341
+ SET qs.status = 'answered'
342
+ RETURN qs.id AS id, qs.topic AS topic
343
+ " "$(jq -n --arg qid "$QID" '{qid: $qid}')"
344
+ ;;
345
+
346
+ resolve-handoffs)
347
+ USER="${1:?missing username}"
348
+ bash "$GS" query "
349
+ MATCH (s:Session)-[:HANDED_TO]->(p:Person {name: \$user})
350
+ WHERE s.handoffStatus IN ['read','claimed']
351
+ WITH DISTINCT s, p, size([(s)-[:HANDED_TO]->(:Person) | 1]) AS recipientCount
352
+ WHERE recipientCount = 1
353
+ MATCH (implementation:Session)-[:IMPLEMENTS]->(s)
354
+ MATCH (implementation)-[:BY]->(p)
355
+ WHERE implementation.wrappedAt IS NOT NULL
356
+ OR implementation.status IN ['completed','handed_off','wrapped']
357
+ WITH DISTINCT s, implementation
358
+ SET s.handoffStatus = 'done',
359
+ s.handoffDoneAt = coalesce(s.handoffDoneAt, datetime()),
360
+ s.handoffUpdatedAt = datetime(),
361
+ s.handoffLifecycleReason = 'single_recipient_implemented',
362
+ s.handoffLifecycleVersion = 1
363
+ RETURN s.id AS resolved, implementation.id AS implementation
364
+ " "$(jq -n --arg user "$USER" '{user: $user}')"
365
+ ;;
366
+
367
+ set-topic)
368
+ SID="${1:?missing session-id}"
369
+ TOPIC="${2:?missing topic}"
370
+ BRANCH="${3:-}"
371
+ if [ -n "$BRANCH" ]; then
372
+ bash "$GS" query "
373
+ MATCH (s:Session {id: \$sid})
374
+ SET s.topic = \$topic, s.branch = \$branch
375
+ RETURN s.id AS id, s.topic AS topic, s.branch AS branch
376
+ " "$(jq -n --arg sid "$SID" --arg topic "$TOPIC" --arg branch "$BRANCH" '{sid: $sid, topic: $topic, branch: $branch}')"
377
+ else
378
+ bash "$GS" query "
379
+ MATCH (s:Session {id: \$sid})
380
+ SET s.topic = \$topic
381
+ RETURN s.id AS id, s.topic AS topic
382
+ " "$(jq -n --arg sid "$SID" --arg topic "$TOPIC" '{sid: $sid, topic: $topic}')"
383
+ fi
384
+ ;;
385
+
386
+ record-focus)
387
+ SID="${1:?missing session-id}"
388
+ SHOWN="${2:?missing shown options}"
389
+ SELECTED="${3:?missing selected option}"
390
+ DISMISSED="${4:-[]}"
391
+ bash "$GS" query "
392
+ MATCH (s:Session {id: \$sid})
393
+ SET s.focusShown = \$shown,
394
+ s.focusSelected = \$selected,
395
+ s.focusDismissed = \$dismissed
396
+ RETURN s.id AS id
397
+ " "$(jq -n --arg sid "$SID" --argjson shown "$SHOWN" --arg selected "$SELECTED" --argjson dismissed "$DISMISSED" '{sid: $sid, shown: $shown, selected: $selected, dismissed: $dismissed}')"
398
+ ;;
399
+
400
+ merge-person)
401
+ KEEP="${1:?missing keep-name (the Person to keep)}"
402
+ ALIAS="${2:?missing alias-name (the Person to reconcile)}"
403
+ bash "$GS" query "
404
+ MATCH (keep:Person) WHERE (toLower(keep.name) = toLower(\$keep) OR toLower(keep.github) = toLower(\$keep) OR keep.personId = \$keep OR toLower(\$keep) IN [x IN coalesce(keep.githubAliases, []) | toLower(x)] OR toLower(\$keep) IN [x IN coalesce(keep.emails, []) | toLower(x)])
405
+ AND NOT coalesce(keep.kind, '') IN ['external', 'identity_alias']
406
+ AND coalesce(keep.status, 'active') = 'active' AND keep.ingestRef IS NULL
407
+ MATCH (alias:Person) WHERE (toLower(alias.name) = toLower(\$alias) OR toLower(alias.github) = toLower(\$alias) OR alias.personId = \$alias OR toLower(\$alias) IN [x IN coalesce(alias.githubAliases, []) | toLower(x)] OR toLower(\$alias) IN [x IN coalesce(alias.emails, []) | toLower(x)])
408
+ AND NOT coalesce(alias.kind, '') IN ['external', 'identity_alias']
409
+ AND coalesce(alias.status, 'active') = 'active' AND alias.ingestRef IS NULL
410
+ WITH keep, alias WHERE keep <> alias
411
+ AND (
412
+ keep.githubId IS NULL OR alias.githubId IS NULL
413
+ OR toString(keep.githubId) = toString(alias.githubId)
414
+ )
415
+ AND NOT (
416
+ coalesce(keep.personId, '') STARTS WITH 'github:'
417
+ AND coalesce(alias.personId, '') STARTS WITH 'github:'
418
+ AND keep.personId <> alias.personId
419
+ )
420
+ SET keep.previousNames = reduce(
421
+ acc = coalesce(keep.previousNames, []),
422
+ value IN coalesce(alias.previousNames, []) + [alias.name, alias.displayName] |
423
+ CASE WHEN value IS NULL OR toLower(value) = toLower(keep.name) OR value IN acc
424
+ THEN acc ELSE acc + value END
425
+ ),
426
+ keep.githubAliases = reduce(
427
+ acc = coalesce(keep.githubAliases, []),
428
+ value IN coalesce(alias.githubAliases, []) + [alias.github] |
429
+ CASE WHEN value IS NULL OR toLower(value) = toLower(keep.github) OR value IN acc
430
+ THEN acc ELSE acc + value END
431
+ ),
432
+ keep.emails = reduce(
433
+ acc = coalesce(keep.emails, []),
434
+ value IN coalesce(alias.emails, []) + [alias.email] |
435
+ CASE WHEN value IS NULL OR value IN acc THEN acc ELSE acc + value END
436
+ ),
437
+ keep.joined = coalesce(alias.joined, keep.joined),
438
+ keep.invited = coalesce(keep.invited, alias.invited),
439
+ keep.invitedBy = coalesce(keep.invitedBy, alias.invitedBy),
440
+ keep.role = coalesce(keep.role, alias.role),
441
+ keep.domain = coalesce(keep.domain, alias.domain),
442
+ keep.focus = coalesce(keep.focus, alias.focus),
443
+ keep.workStyle = coalesce(keep.workStyle, alias.workStyle),
444
+ keep.telegramId = coalesce(keep.telegramId, alias.telegramId),
445
+ keep.lastBrief = coalesce(keep.lastBrief, alias.lastBrief),
446
+ keep.lastBriefDate = coalesce(keep.lastBriefDate, alias.lastBriefDate),
447
+ keep.lastRecommendations = coalesce(keep.lastRecommendations, alias.lastRecommendations)
448
+ WITH keep, alias
449
+ OPTIONAL MATCH (s1:Session)-[:BY]->(alias)
450
+ FOREACH (_ IN CASE WHEN s1 IS NOT NULL THEN [1] ELSE [] END | MERGE (s1)-[:BY]->(keep))
451
+ WITH keep, alias
452
+ OPTIONAL MATCH (s2:Session)-[:HANDED_TO]->(alias)
453
+ FOREACH (_ IN CASE WHEN s2 IS NOT NULL THEN [1] ELSE [] END | MERGE (s2)-[:HANDED_TO]->(keep))
454
+ WITH keep, alias
455
+ OPTIONAL MATCH (m:Meeting)-[:INVOLVES]->(alias)
456
+ FOREACH (_ IN CASE WHEN m IS NOT NULL THEN [1] ELSE [] END | MERGE (m)-[:INVOLVES]->(keep))
457
+ WITH keep, alias
458
+ OPTIONAL MATCH (a:Artifact)-[:CONTRIBUTED_BY]->(alias)
459
+ FOREACH (_ IN CASE WHEN a IS NOT NULL THEN [1] ELSE [] END | MERGE (a)-[:CONTRIBUTED_BY]->(keep))
460
+ WITH keep, alias
461
+ OPTIONAL MATCH (i:Interview)-[:CONDUCTED_BY]->(alias)
462
+ FOREACH (_ IN CASE WHEN i IS NOT NULL THEN [1] ELSE [] END | MERGE (i)-[:CONDUCTED_BY]->(keep))
463
+ WITH keep, alias
464
+ OPTIONAL MATCH (t:Todo)-[:BY]->(alias)
465
+ FOREACH (_ IN CASE WHEN t IS NOT NULL THEN [1] ELSE [] END | MERGE (t)-[:BY]->(keep))
466
+ WITH keep, alias
467
+ OPTIONAL MATCH (mentionedArtifact:Artifact)-[:MENTIONS]->(alias)
468
+ FOREACH (_ IN CASE WHEN mentionedArtifact IS NOT NULL THEN [1] ELSE [] END | MERGE (mentionedArtifact)-[:MENTIONS]->(keep))
469
+ WITH keep, alias
470
+ OPTIONAL MATCH (mentionedTodo:Todo)-[:MENTIONS]->(alias)
471
+ FOREACH (_ IN CASE WHEN mentionedTodo IS NOT NULL THEN [1] ELSE [] END | MERGE (mentionedTodo)-[:MENTIONS]->(keep))
472
+ WITH keep, alias
473
+ OPTIONAL MATCH (q:Quest)-[:STARTED_BY]->(alias)
474
+ FOREACH (_ IN CASE WHEN q IS NOT NULL THEN [1] ELSE [] END | MERGE (q)-[:STARTED_BY]->(keep))
475
+ WITH keep, alias
476
+ OPTIONAL MATCH (askedBy:QuestionSet)-[:ASKED_BY]->(alias)
477
+ FOREACH (_ IN CASE WHEN askedBy IS NOT NULL THEN [1] ELSE [] END | MERGE (askedBy)-[:ASKED_BY]->(keep))
478
+ WITH keep, alias
479
+ OPTIONAL MATCH (askedTo:QuestionSet)-[:ASKED_TO]->(alias)
480
+ FOREACH (_ IN CASE WHEN askedTo IS NOT NULL THEN [1] ELSE [] END | MERGE (askedTo)-[:ASKED_TO]->(keep))
481
+ WITH keep, alias
482
+ OPTIONAL MATCH (tu:TelegramUser)-[:IDENTIFIES]->(alias)
483
+ FOREACH (_ IN CASE WHEN tu IS NOT NULL THEN [1] ELSE [] END | MERGE (tu)-[:IDENTIFIES]->(keep))
484
+ WITH keep, alias
485
+ OPTIONAL MATCH (reported:Issue)-[:REPORTED_BY]->(alias)
486
+ FOREACH (_ IN CASE WHEN reported IS NOT NULL THEN [1] ELSE [] END | MERGE (reported)-[:REPORTED_BY]->(keep))
487
+ WITH keep, alias
488
+ OPTIONAL MATCH (initiated:Harvest)-[:INITIATED_BY]->(alias)
489
+ FOREACH (_ IN CASE WHEN initiated IS NOT NULL THEN [1] ELSE [] END | MERGE (initiated)-[:INITIATED_BY]->(keep))
490
+ WITH keep, alias
491
+ OPTIONAL MATCH (withPerson:HarvestSession)-[:WITH]->(alias)
492
+ FOREACH (_ IN CASE WHEN withPerson IS NOT NULL THEN [1] ELSE [] END | MERGE (withPerson)-[:WITH]->(keep))
493
+ WITH keep, alias
494
+ OPTIONAL MATCH (alias)-[:SENT_EMISSARY]->(emissary:Emissary)
495
+ FOREACH (_ IN CASE WHEN emissary IS NOT NULL THEN [1] ELSE [] END | MERGE (keep)-[:SENT_EMISSARY]->(emissary))
496
+ WITH keep, alias
497
+ OPTIONAL MATCH (alias)-[:MEMBER_OF]->(o:Org)
498
+ FOREACH (_ IN CASE WHEN o IS NOT NULL THEN [1] ELSE [] END | MERGE (keep)-[:MEMBER_OF]->(o))
499
+ WITH keep, alias
500
+ MERGE (alias)-[:ALIAS_OF]->(keep)
501
+ SET alias.kind = 'identity_alias',
502
+ alias.canonicalPersonId = keep.personId,
503
+ alias.identityStatus = 'alias'
504
+ RETURN keep.name AS name, keep.github AS github, keep.previousNames AS aliases
505
+ " "$(jq -n --arg keep "$KEEP" --arg alias "$ALIAS" '{keep: $keep, alias: $alias}')"
506
+ ;;
507
+
508
+ claim-handoff)
509
+ IMPL_SID="${1:?missing implementing-session-id}"
510
+ HO_SID="${2:?missing handoff-session-id}"
511
+ CYPHER="
512
+ MATCH (impl:Session {id: \$implSid}), (ho:Session {id: \$hoSid})
513
+ MATCH (impl)-[:BY]->(claimant:Person)
514
+ MATCH (ho)-[:HANDED_TO]->(claimant)
515
+ WHERE ho.handoffStatus IN ['pending','read','claimed']
516
+ MERGE (impl)-[:IMPLEMENTS]->(ho)
517
+ WITH impl, ho, size([(ho)-[:HANDED_TO]->(:Person) | 1]) AS recipientCount
518
+ FOREACH (_ IN CASE WHEN recipientCount = 1 THEN [1] ELSE [] END |
519
+ SET ho.handoffStatus = 'claimed',
520
+ ho.handoffClaimedAt = coalesce(ho.handoffClaimedAt, datetime()),
521
+ ho.handoffUpdatedAt = datetime(),
522
+ ho.handoffLifecycleReason = 'implementation_claimed',
523
+ ho.handoffLifecycleVersion = 1)
524
+ RETURN impl.id AS implementor, ho.id AS handoff, ho.topic AS topic,
525
+ ho.handoffStatus AS status, recipientCount
526
+ "
527
+ PARAMS="$(jq -n --arg implSid "$IMPL_SID" --arg hoSid "$HO_SID" '{implSid: $implSid, hoSid: $hoSid}')"
528
+ bash "$SCRIPT_DIR/bin/graph-wal.sh" append "$CYPHER" "$PARAMS" 2>/dev/null || true
529
+ bash "$GS" query "$CYPHER" "$PARAMS"
530
+ ;;
531
+
532
+ claim-handoff-nudge)
533
+ SID="${1:?missing handoff-session-id}"
534
+ bash "$GS" query "
535
+ MATCH (s:Session {id: \$sid})-[:HANDED_TO]->(recipient:Person)
536
+ WHERE coalesce(s.handoffStatus, 'pending') IN ['pending','read','claimed']
537
+ AND coalesce(s.handoffLifecycleVersion, 0) >= 1
538
+ AND coalesce(s.handoffIntent, 'unclassified') IN ['action','feedback','fyi']
539
+ AND s.handoffNudgedAt IS NULL
540
+ AND (s.handoffNudgeClaimedAt IS NULL
541
+ OR s.handoffNudgeClaimedAt < datetime() - duration('PT1H'))
542
+ WITH s, collect(DISTINCT recipient.name) AS recipients
543
+ WHERE size(recipients) = 1
544
+ SET s.handoffNudgeClaimedAt = datetime(),
545
+ s.handoffNudgeStatus = 'claimed'
546
+ RETURN s.id AS id, s.topic AS topic, recipients
547
+ " "$(jq -n --arg sid "$SID" '{sid:$sid}')"
548
+ ;;
549
+
550
+ mark-handoff-nudged)
551
+ SID="${1:?missing handoff-session-id}"
552
+ bash "$GS" query "
553
+ MATCH (s:Session {id: \$sid})
554
+ WHERE s.handoffNudgeStatus = 'claimed' AND s.handoffNudgedAt IS NULL
555
+ SET s.handoffNudgedAt = datetime(),
556
+ s.handoffNudgeStatus = 'sent',
557
+ s.handoffUpdatedAt = datetime(),
558
+ s.handoffLifecycleReason = 'recipient_nudged',
559
+ s.handoffLifecycleVersion = 1
560
+ RETURN s.id AS id, s.handoffNudgeStatus AS status
561
+ " "$(jq -n --arg sid "$SID" '{sid:$sid}')"
562
+ ;;
563
+
564
+ release-handoff-nudge)
565
+ SID="${1:?missing handoff-session-id}"
566
+ bash "$GS" query "
567
+ MATCH (s:Session {id: \$sid})
568
+ WHERE s.handoffNudgeStatus = 'claimed' AND s.handoffNudgedAt IS NULL
569
+ SET s.handoffNudgeClaimedAt = null,
570
+ s.handoffNudgeStatus = 'failed',
571
+ s.handoffNudgeFailedAt = datetime()
572
+ RETURN s.id AS id, s.handoffNudgeStatus AS status
573
+ " "$(jq -n --arg sid "$SID" '{sid:$sid}')"
574
+ ;;
575
+
576
+ create-pr)
577
+ SID="${1:?missing session-id}"
578
+ PR_NUM="${2:?missing pr-number}"
579
+ REPO="${3:?missing repo}"
580
+ AUTHOR_GH="${4:?missing author-github}"
581
+ TITLE="${5:-}"
582
+ CYPHER="
583
+ MERGE (pr:PR {number: toInteger(\$num), repo: \$repo})
584
+ ON CREATE SET pr.author = \$author, pr.status = 'open',
585
+ pr.createdAt = datetime(), pr.title = \$title
586
+ WITH pr
587
+ OPTIONAL MATCH (s:Session {id: \$sid})
588
+ FOREACH (_ IN CASE WHEN s IS NOT NULL THEN [1] ELSE [] END |
589
+ MERGE (s)-[:PRODUCED]->(pr))
590
+ RETURN pr.number AS number, pr.repo AS repo
591
+ "
592
+ PARAMS="$(jq -n --arg sid "$SID" --argjson num "$PR_NUM" --arg repo "$REPO" --arg author "$AUTHOR_GH" --arg title "$TITLE" '{sid: $sid, num: $num, repo: $repo, author: $author, title: $title}')"
593
+ bash "$SCRIPT_DIR/bin/graph-wal.sh" append "$CYPHER" "$PARAMS" 2>/dev/null || true
594
+ bash "$GS" query "$CYPHER" "$PARAMS"
595
+ ;;
596
+
597
+ register-artifact)
598
+ # Index a published (hosted) artifact as an Artifact node so the finder can
599
+ # retrieve it from the graph in connected mode — by content (title/topics/
600
+ # excerpt CONTAINS) and by relationship (who made it, which quest). The node
601
+ # id is the registry FILENAME STEM (date-author-slug), matching sync-graph.sh
602
+ # so a later /save sync upserts the same node instead of duplicating it.
603
+ # args: <id> <url> <title> <type> <author-handle> <topics-csv> <excerpt>
604
+ A_ID="${1:?missing id}"
605
+ A_URL="${2:?missing url}"
606
+ A_TITLE="${3:-}"
607
+ A_TYPE="${4:-artifact}"
608
+ A_AUTHOR="$(printf '%s' "${5:-}" | tr '[:upper:]' '[:lower:]' | awk '{print $1}')"
609
+ A_TOPICS_JSON="$(printf '%s' "${6:-}" | jq -Rc 'split(",") | map(gsub("^\\s+|\\s+$";"")) | map(select(length > 0))' 2>/dev/null || echo '[]')"
610
+ A_EXCERPT="$(printf '%s' "${7:-}" | tr '\n' ' ' | cut -c1-2000)"
611
+ CYPHER="
612
+ MERGE (a:Artifact {id: \$id})
613
+ ON CREATE SET a.created = datetime()
614
+ SET a.title = \$title, a.type = \$type, a.url = \$url,
615
+ a.topics = \$topics, a.excerpt = \$excerpt, a.published = true
616
+ WITH a
617
+ OPTIONAL MATCH (p:Person)
618
+ WHERE \$author <> '' AND (toLower(p.name) = \$author OR p.github = \$author)
619
+ FOREACH (_ IN CASE WHEN p IS NOT NULL THEN [1] ELSE [] END |
620
+ MERGE (a)-[:CONTRIBUTED_BY]->(p))
621
+ RETURN a.id AS id
622
+ "
623
+ PARAMS="$(jq -n --arg id "$A_ID" --arg url "$A_URL" --arg title "$A_TITLE" --arg type "$A_TYPE" \
624
+ --arg author "$A_AUTHOR" --argjson topics "$A_TOPICS_JSON" --arg excerpt "$A_EXCERPT" \
625
+ '{id: $id, url: $url, title: $title, type: $type, author: $author, topics: $topics, excerpt: $excerpt}')"
626
+ bash "$SCRIPT_DIR/bin/graph-wal.sh" append "$CYPHER" "$PARAMS" 2>/dev/null || true
627
+ bash "$GS" query "$CYPHER" "$PARAMS"
628
+ ;;
629
+
630
+ check-implements)
631
+ SID="${1:?missing session-id}"
632
+ bash "$GS" query "
633
+ MATCH (impl:Session {id: \$sid})-[:IMPLEMENTS]->(ho:Session)-[:BY]->(author:Person)
634
+ RETURN ho.id AS handoffId, ho.topic AS topic, author.name AS author,
635
+ author.github AS authorGithub
636
+ " "$(jq -n --arg sid "$SID" '{sid: $sid}')"
637
+ ;;
638
+
639
+ update-pr)
640
+ PR_NUM="${1:?missing pr-number}"
641
+ REPO="${2:?missing repo}"
642
+ STATUS="${3:?missing status}"
643
+ MERGED_AT="${4:-}"
644
+ if [ -n "$MERGED_AT" ]; then
645
+ bash "$GS" query "
646
+ MATCH (pr:PR {number: toInteger(\$num), repo: \$repo})
647
+ SET pr.status = \$status, pr.mergedAt = datetime(\$mergedAt)
648
+ RETURN pr.number AS number, pr.status AS status
649
+ " "$(jq -n --argjson num "$PR_NUM" --arg repo "$REPO" --arg status "$STATUS" --arg mergedAt "$MERGED_AT" '{num: $num, repo: $repo, status: $status, mergedAt: $mergedAt}')"
650
+ else
651
+ bash "$GS" query "
652
+ MATCH (pr:PR {number: toInteger(\$num), repo: \$repo})
653
+ SET pr.status = \$status
654
+ RETURN pr.number AS number, pr.status AS status
655
+ " "$(jq -n --argjson num "$PR_NUM" --arg repo "$REPO" --arg status "$STATUS" '{num: $num, repo: $repo, status: $status}')"
656
+ fi
657
+ ;;
658
+
659
+ my-merged-prs)
660
+ AUTHOR_GH="${1:?missing author-github}"
661
+ SINCE="${2:-}"
662
+ if [ -n "$SINCE" ]; then
663
+ bash "$GS" query "
664
+ MATCH (pr:PR {author: \$author})
665
+ WHERE pr.status = 'merged' AND pr.mergedAt >= datetime(\$since)
666
+ RETURN pr.number AS number, pr.repo AS repo, pr.title AS title,
667
+ toString(pr.mergedAt) AS mergedAt
668
+ ORDER BY pr.mergedAt DESC LIMIT 10
669
+ " "$(jq -n --arg author "$AUTHOR_GH" --arg since "${SINCE}T00:00:00Z" '{author: $author, since: $since}')"
670
+ else
671
+ bash "$GS" query "
672
+ MATCH (pr:PR {author: \$author})
673
+ WHERE pr.status = 'merged'
674
+ RETURN pr.number AS number, pr.repo AS repo, pr.title AS title,
675
+ toString(pr.mergedAt) AS mergedAt
676
+ ORDER BY pr.mergedAt DESC LIMIT 5
677
+ " "$(jq -n --arg author "$AUTHOR_GH" '{author: $author}')"
678
+ fi
679
+ ;;
680
+
681
+ my-implemented-handoffs)
682
+ AUTHOR_NAME="${1:?missing author-name}"
683
+ SINCE="${2:-}"
684
+ if [ -n "$SINCE" ]; then
685
+ bash "$GS" query "
686
+ MATCH (impl:Session)-[:IMPLEMENTS]->(ho:Session)-[:BY]->(author:Person)
687
+ WHERE toLower(author.name) = toLower(\$author)
688
+ AND impl.wrappedAt >= datetime(\$since)
689
+ MATCH (impl)-[:BY]->(implementor:Person)
690
+ RETURN ho.topic AS handoffTopic, implementor.name AS implementedBy,
691
+ toString(impl.wrappedAt) AS completedAt, impl.summary AS summary
692
+ ORDER BY impl.wrappedAt DESC LIMIT 10
693
+ " "$(jq -n --arg author "$AUTHOR_NAME" --arg since "${SINCE}T00:00:00Z" '{author: $author, since: $since}')"
694
+ else
695
+ bash "$GS" query "
696
+ MATCH (impl:Session)-[:IMPLEMENTS]->(ho:Session)-[:BY]->(author:Person)
697
+ WHERE toLower(author.name) = toLower(\$author)
698
+ MATCH (impl)-[:BY]->(implementor:Person)
699
+ RETURN ho.topic AS handoffTopic, implementor.name AS implementedBy,
700
+ toString(impl.wrappedAt) AS completedAt, impl.summary AS summary
701
+ ORDER BY impl.wrappedAt DESC LIMIT 5
702
+ " "$(jq -n --arg author "$AUTHOR_NAME" '{author: $author}')"
703
+ fi
704
+ ;;
705
+
706
+ open-handoffs)
707
+ USER="${1:?missing username}"
708
+ LIMIT="${2:-10}"
709
+ if ! [[ "$LIMIT" =~ ^[0-9]+$ ]] || [ "$LIMIT" -lt 1 ] || [ "$LIMIT" -gt 25 ]; then
710
+ echo '{"error":"limit must be between 1 and 25"}'
711
+ exit 2
712
+ fi
713
+ bash "$GS" query "
714
+ MATCH (s:Session)-[:HANDED_TO]->(p:Person)
715
+ WHERE NOT coalesce(p.kind, '') IN ['identity_alias']
716
+ AND (
717
+ toLower(coalesce(p.name, '')) = toLower(\$user)
718
+ OR toLower(coalesce(p.github, '')) = toLower(\$user)
719
+ OR toLower(coalesce(p.githubUsername, '')) = toLower(\$user)
720
+ OR any(alias IN coalesce(p.previousNames, [])
721
+ WHERE toLower(alias) = toLower(\$user))
722
+ )
723
+ AND coalesce(s.handoffStatus, 'pending')
724
+ IN ['pending','unread','read','claimed']
725
+ WITH DISTINCT s
726
+ WITH s, head([(s)-[:BY]->(author:Person)
727
+ WHERE NOT coalesce(author.kind, '') IN ['identity_alias'] | author.name]) AS authorName,
728
+ CASE WHEN s.date IS NULL THEN null
729
+ ELSE duration.inDays(date(s.date), date()).days END AS ageDays
730
+ RETURN s.id AS id,
731
+ coalesce(s.topic, s.summary, s.branch) AS topic,
732
+ coalesce(authorName, s.author, 'unknown') AS author,
733
+ toString(s.date) AS date,
734
+ coalesce(s.handoffStatus, 'pending') AS status,
735
+ coalesce(s.handoffIntent, 'unclassified') AS intent,
736
+ ageDays,
737
+ CASE WHEN ageDays IS NULL THEN 'unknown'
738
+ WHEN ageDays <= 14 THEN 'current'
739
+ WHEN ageDays <= 30 THEN 'aging'
740
+ ELSE 'stale' END AS freshness,
741
+ 1 AS definitionVersion
742
+ ORDER BY s.date DESC, s.id
743
+ LIMIT \$limit
744
+ " "$(jq -n --arg user "$USER" --argjson limit "$LIMIT" '{user: $user, limit: $limit}')"
745
+ ;;
746
+
747
+ pending-questions)
748
+ USER="${1:?missing username}"
749
+ LIMIT="${2:-10}"
750
+ if ! [[ "$LIMIT" =~ ^[0-9]+$ ]] || [ "$LIMIT" -lt 1 ] || [ "$LIMIT" -gt 25 ]; then
751
+ echo '{"error":"limit must be between 1 and 25"}'
752
+ exit 2
753
+ fi
754
+ bash "$GS" query "
755
+ MATCH (qs:QuestionSet)-[:ASKED_TO]->(p:Person)
756
+ WHERE (
757
+ toLower(coalesce(p.name, '')) = toLower(\$user)
758
+ OR toLower(coalesce(p.github, '')) = toLower(\$user)
759
+ OR toLower(coalesce(p.githubUsername, '')) = toLower(\$user)
760
+ OR any(alias IN coalesce(p.previousNames, [])
761
+ WHERE toLower(alias) = toLower(\$user))
762
+ )
763
+ AND coalesce(qs.status, 'pending') IN ['pending','active']
764
+ WITH DISTINCT qs
765
+ OPTIONAL MATCH (q:Question)-[:PART_OF]->(qs)
766
+ OPTIONAL MATCH (qs)-[:ASKED_BY]->(asker:Person)
767
+ WITH qs, asker, count(DISTINCT q) AS questions,
768
+ CASE WHEN qs.created IS NULL THEN null
769
+ ELSE duration.inDays(date(datetime(qs.created)), date()).days END AS ageDays
770
+ RETURN qs.id AS id,
771
+ qs.topic AS topic,
772
+ coalesce(asker.name, qs.askedBy, qs.from, 'unknown') AS askedBy,
773
+ questions,
774
+ toString(qs.created) AS created,
775
+ ageDays,
776
+ CASE WHEN ageDays IS NULL THEN 'unknown'
777
+ WHEN ageDays <= 14 THEN 'current'
778
+ WHEN ageDays <= 30 THEN 'aging'
779
+ ELSE 'stale-open' END AS freshness,
780
+ 1 AS definitionVersion
781
+ ORDER BY qs.created DESC, qs.id
782
+ LIMIT \$limit
783
+ " "$(jq -n --arg user "$USER" --argjson limit "$LIMIT" '{user: $user, limit: $limit}')"
784
+ ;;
785
+
786
+ lineage)
787
+ QUERY="${1:?missing topic}"
788
+ LIMIT="${2:-10}"
789
+ if ! [[ "$LIMIT" =~ ^[0-9]+$ ]] || [ "$LIMIT" -lt 1 ] || [ "$LIMIT" -gt 15 ]; then
790
+ echo '{"error":"limit must be between 1 and 15"}'
791
+ exit 2
792
+ fi
793
+ GRAPH_RAW="$(bash "$GS" query "
794
+ MATCH (s:Session)
795
+ WHERE toLower(coalesce(s.topic, '')) CONTAINS toLower(\$query)
796
+ OR toLower(coalesce(s.summary, '')) CONTAINS toLower(\$query)
797
+ OR toLower(coalesce(s.branch, '')) CONTAINS toLower(\$query)
798
+ OPTIONAL MATCH (s)-[:BY]->(author:Person)
799
+ OPTIONAL MATCH (s)-[:HANDED_TO]->(recipient:Person)
800
+ OPTIONAL MATCH (implementation:Session)-[:IMPLEMENTS]->(s)
801
+ OPTIONAL MATCH (implementation)-[:BY]->(implementer:Person)
802
+ OPTIONAL MATCH (s)-[:IMPLEMENTS]->(prior:Session)
803
+ OPTIONAL MATCH (prior)-[:BY]->(priorAuthor:Person)
804
+ OPTIONAL MATCH (s)-[:PRODUCED]->(pr:PR)
805
+ OPTIONAL MATCH (implementation)-[:PRODUCED]->(implementationPr:PR)
806
+ WITH s, author,
807
+ collect(DISTINCT coalesce(recipient.name, recipient.github)) AS recipients,
808
+ collect(DISTINCT CASE WHEN implementation IS NULL THEN null ELSE {
809
+ id: implementation.id,
810
+ topic: implementation.topic,
811
+ summary: implementation.summary,
812
+ branch: implementation.branch,
813
+ date: toString(implementation.date),
814
+ evidencePath: CASE
815
+ WHEN implementation.filePath IS NULL THEN null
816
+ WHEN implementation.filePath STARTS WITH 'memory/' THEN implementation.filePath
817
+ ELSE 'memory/' + implementation.filePath END,
818
+ implementedBy: coalesce(implementer.name, implementer.github)
819
+ } END) AS implementations,
820
+ collect(DISTINCT CASE WHEN prior IS NULL THEN null ELSE {
821
+ id: prior.id,
822
+ topic: prior.topic,
823
+ summary: prior.summary,
824
+ branch: prior.branch,
825
+ date: toString(prior.date),
826
+ evidencePath: CASE
827
+ WHEN prior.filePath IS NULL THEN null
828
+ WHEN prior.filePath STARTS WITH 'memory/' THEN prior.filePath
829
+ ELSE 'memory/' + prior.filePath END,
830
+ author: coalesce(priorAuthor.name, priorAuthor.github)
831
+ } END) AS implements,
832
+ collect(DISTINCT CASE WHEN pr IS NULL THEN null ELSE {
833
+ number: pr.number, repo: pr.repo, title: pr.title,
834
+ status: pr.status, mergedAt: toString(pr.mergedAt)
835
+ } END)
836
+ + collect(DISTINCT CASE WHEN implementationPr IS NULL THEN null ELSE {
837
+ number: implementationPr.number, repo: implementationPr.repo,
838
+ title: implementationPr.title, status: implementationPr.status,
839
+ mergedAt: toString(implementationPr.mergedAt)
840
+ } END) AS prs
841
+ RETURN s.id AS sessionId,
842
+ s.topic AS topic,
843
+ s.summary AS summary,
844
+ s.branch AS branch,
845
+ toString(s.date) AS date,
846
+ CASE WHEN s.filePath IS NULL THEN null
847
+ WHEN s.filePath STARTS WITH 'memory/' THEN s.filePath
848
+ ELSE 'memory/' + s.filePath END AS evidencePath,
849
+ coalesce(author.name, author.github, s.author, 'unknown') AS author,
850
+ recipients[0..20] AS recipients,
851
+ implementations[0..10] AS implementations,
852
+ implements[0..10] AS implements,
853
+ prs[0..10] AS prs
854
+ ORDER BY s.date DESC, s.id
855
+ LIMIT \$limit
856
+ " "$(jq -n --arg query "$QUERY" --argjson limit "$LIMIT" '{query:$query,limit:$limit}')")"
857
+ FILES_RAW="$(memory_file_candidates "$QUERY" "$LIMIT" \
858
+ "$SCRIPT_DIR/memory/handoffs" \
859
+ "$SCRIPT_DIR/memory/wraps" \
860
+ "$SCRIPT_DIR/memory/sessions")"
861
+ jq -n \
862
+ --arg query "$QUERY" \
863
+ --argjson limit "$LIMIT" \
864
+ --argjson graph "$GRAPH_RAW" \
865
+ --argjson files "$FILES_RAW" '
866
+ ($graph.values // [] | map({
867
+ sessionId: .[0], topic: .[1], summary: .[2], branch: .[3],
868
+ date: .[4], evidencePath: .[5], author: .[6],
869
+ recipients: (.[7] // []), implementations: (.[8] // []),
870
+ implements: (.[9] // []), prs: (.[10] // [])
871
+ })) as $matches
872
+ | ($matches | map(.evidencePath) | map(select(. != null)) | unique) as $graphPaths
873
+ | ($files | map(.evidencePath) | unique) as $filePaths
874
+ | ($filePaths - $graphPaths) as $unprojected
875
+ | {
876
+ schema: "egregore.graph-read/v1",
877
+ operation: "lineage",
878
+ definitionVersion: 1,
879
+ query: $query,
880
+ limit: $limit,
881
+ coverage:
882
+ (if ($graphPaths | length) == 0 then
883
+ (if ($filePaths | length) == 0 then "none" else "filesystem-only" end)
884
+ elif ($unprojected | length) > 0 then "partial"
885
+ else "complete" end),
886
+ graphMatches: $matches,
887
+ fileCandidates:
888
+ ($files | map(
889
+ . as $candidate
890
+ | . + {
891
+ projection:
892
+ (if ($graphPaths | index($candidate.evidencePath)) != null
893
+ then "projected" else "unprojected" end)
894
+ }
895
+ )),
896
+ unprojectedPaths: $unprojected
897
+ }
898
+ '
899
+ ;;
900
+
901
+ meeting-history)
902
+ QUERY="${1:?missing company, person, or topic}"
903
+ LIMIT="${2:-10}"
904
+ if ! [[ "$LIMIT" =~ ^[0-9]+$ ]] || [ "$LIMIT" -lt 1 ] || [ "$LIMIT" -gt 15 ]; then
905
+ echo '{"error":"limit must be between 1 and 15"}'
906
+ exit 2
907
+ fi
908
+ QUERY_TERMS="$(meaningful_query_terms "$QUERY")"
909
+ GRAPH_RAW="$(bash "$GS" query "
910
+ MATCH (m:Meeting)
911
+ OPTIONAL MATCH (m)-[:INVOLVES|CONDUCTED_BY]->(participant:Person)
912
+ WITH m, collect(DISTINCT participant) AS participants
913
+ WITH m, participants,
914
+ [term IN \$terms WHERE
915
+ toLower(coalesce(m.title, '')) CONTAINS term
916
+ OR toLower(coalesce(m.name, '')) CONTAINS term
917
+ OR toLower(coalesce(m.id, '')) CONTAINS term
918
+ OR any(p IN participants WHERE
919
+ toLower(coalesce(p.name, '')) CONTAINS term
920
+ OR toLower(coalesce(p.github, '')) CONTAINS term)
921
+ ] AS matchedTerms
922
+ WHERE size(matchedTerms) > 0
923
+ OPTIONAL MATCH (artifact:Artifact)-[:FROM_MEETING]->(m)
924
+ RETURN m.id AS meetingId,
925
+ coalesce(m.title, m.name, m.id) AS title,
926
+ toString(m.date) AS date,
927
+ CASE WHEN m.filePath IS NULL THEN null
928
+ WHEN m.filePath STARTS WITH 'memory/' THEN m.filePath
929
+ ELSE 'memory/' + m.filePath END AS evidencePath,
930
+ ([p IN participants | coalesce(p.name, p.github)])[0..20] AS participants,
931
+ (collect(DISTINCT CASE WHEN artifact IS NULL THEN null ELSE {
932
+ id: artifact.id,
933
+ type: artifact.type,
934
+ title: artifact.title,
935
+ summary: artifact.summary,
936
+ evidencePath: CASE
937
+ WHEN artifact.filePath IS NULL THEN null
938
+ WHEN artifact.filePath STARTS WITH 'memory/' THEN artifact.filePath
939
+ ELSE 'memory/' + artifact.filePath END
940
+ } END))[0..10] AS derivedKnowledge,
941
+ coalesce(m.verificationStatus, 'legacy') AS verificationStatus,
942
+ m.ingestManifestId AS ingestManifestId,
943
+ matchedTerms,
944
+ size(matchedTerms) AS matchScore
945
+ ORDER BY matchScore DESC, date ASC, meetingId
946
+ LIMIT \$limit
947
+ " "$(jq -n --arg query "$QUERY" --argjson terms "$QUERY_TERMS" --argjson limit "$LIMIT" \
948
+ '{query:$query,terms:$terms,limit:$limit}')")"
949
+ FILES_RAW="$(memory_file_candidates_for_terms \
950
+ "$QUERY_TERMS" "$LIMIT" "$SCRIPT_DIR/memory/meetings")"
951
+ jq -n \
952
+ --arg query "$QUERY" \
953
+ --argjson queryTerms "$QUERY_TERMS" \
954
+ --argjson limit "$LIMIT" \
955
+ --argjson graph "$GRAPH_RAW" \
956
+ --argjson files "$FILES_RAW" '
957
+ ($graph.values // [] | map({
958
+ meetingId: .[0], title: .[1], date: .[2], evidencePath: .[3],
959
+ participants: (.[4] // []), derivedKnowledge: (.[5] // []),
960
+ verificationStatus: .[6], ingestManifestId: .[7],
961
+ matchedTerms: (.[8] // []), matchScore: (.[9] // 0)
962
+ })) as $meetings
963
+ | ($meetings | map(.evidencePath) | map(select(. != null)) | unique) as $graphPaths
964
+ | ($files | map(.evidencePath) | unique) as $filePaths
965
+ | ($filePaths - $graphPaths) as $unprojected
966
+ | {
967
+ schema: "egregore.graph-read/v1",
968
+ operation: "meeting-history",
969
+ definitionVersion: 1,
970
+ query: $query,
971
+ queryTerms: $queryTerms,
972
+ limit: $limit,
973
+ coverage:
974
+ (if ($graphPaths | length) == 0 then
975
+ (if ($filePaths | length) == 0 then "none" else "filesystem-only" end)
976
+ elif ($unprojected | length) > 0 then "partial"
977
+ else "complete" end),
978
+ graphMeetings: $meetings,
979
+ fileCandidates:
980
+ ($files | map(
981
+ . as $candidate
982
+ | . + {
983
+ projection:
984
+ (if ($graphPaths | index($candidate.evidencePath)) != null
985
+ then "projected" else "unprojected" end)
986
+ }
987
+ )),
988
+ unprojectedPaths: $unprojected
989
+ }
990
+ '
991
+ ;;
992
+
993
+ wal-status)
994
+ bash "$SCRIPT_DIR/bin/graph-wal.sh" status
995
+ ;;
996
+
997
+ create-harvest)
998
+ HID="${1:?missing harvest-id}"
999
+ TOPIC="${2:?missing topic}"
1000
+ INTENT="${3:?missing intent}"
1001
+ INITIATOR="${4:?missing initiator}"
1002
+ CYPHER="
1003
+ MERGE (h:Harvest {id: \$hid})
1004
+ ON CREATE SET h.topic = \$topic, h.intent = \$intent,
1005
+ h.status = 'active', h.created = datetime()
1006
+ WITH h
1007
+ MATCH (p:Person) WHERE toLower(p.name) = toLower(\$initiator) OR p.github = \$initiator
1008
+ MERGE (h)-[:INITIATED_BY]->(p)
1009
+ RETURN h.id AS id, h.topic AS topic, h.status AS status
1010
+ "
1011
+ PARAMS="$(jq -n --arg hid "$HID" --arg topic "$TOPIC" --arg intent "$INTENT" --arg initiator "$INITIATOR" '{hid: $hid, topic: $topic, intent: $intent, initiator: $initiator}')"
1012
+ bash "$SCRIPT_DIR/bin/graph-wal.sh" append "$CYPHER" "$PARAMS" 2>/dev/null || true
1013
+ bash "$GS" query "$CYPHER" "$PARAMS"
1014
+ ;;
1015
+
1016
+ create-harvest-session)
1017
+ HID="${1:?missing harvest-id}"
1018
+ HSID="${2:?missing session-id}"
1019
+ PERSON="${3:?missing person-name}"
1020
+ STATUS="${4:-active}"
1021
+ case "$STATUS" in
1022
+ pending|active|answered|complete|incorporated) ;;
1023
+ *) jq -n --arg s "$STATUS" '{error:("invalid status: "+$s),valid:["pending","active","answered","complete","incorporated"]}' >&2; exit 2 ;;
1024
+ esac
1025
+ CYPHER="
1026
+ MATCH (h:Harvest {id: \$hid})
1027
+ MERGE (hs:HarvestSession {id: \$hsid})
1028
+ ON CREATE SET hs.status = \$status, hs.created = datetime()
1029
+ MERGE (h)-[:HAS_SESSION]->(hs)
1030
+ WITH hs
1031
+ MATCH (p:Person) WHERE toLower(p.name) = toLower(\$person) OR p.github = \$person
1032
+ MERGE (hs)-[:WITH]->(p)
1033
+ RETURN hs.id AS id, hs.status AS status
1034
+ "
1035
+ PARAMS="$(jq -n --arg hid "$HID" --arg hsid "$HSID" --arg person "$PERSON" --arg status "$STATUS" '{hid: $hid, hsid: $hsid, person: $person, status: $status}')"
1036
+ bash "$SCRIPT_DIR/bin/graph-wal.sh" append "$CYPHER" "$PARAMS" 2>/dev/null || true
1037
+ OUT="$(bash "$GS" query "$CYPHER" "$PARAMS")"
1038
+ if [ "$(echo "$OUT" | jq -r '.results | length' 2>/dev/null)" = "0" ]; then
1039
+ jq -n --arg hid "$HID" --arg hsid "$HSID" --arg person "$PERSON" \
1040
+ '{error:"create-harvest-session: harvest or person not found",hid:$hid,hsid:$hsid,person:$person}' >&2
1041
+ exit 3
1042
+ fi
1043
+ echo "$OUT"
1044
+ ;;
1045
+
1046
+ record-harvest-turn)
1047
+ HSID="${1:?missing session-id}"
1048
+ TURN="${2:?missing turn-number}"
1049
+ QUESTION="${3:?missing question}"
1050
+ QINTENT="${4:?missing question-intent}"
1051
+ ANSWER="${5:-}"
1052
+ EVAL="${6:-}"
1053
+ TURN_ID="${HSID}-turn-${TURN}"
1054
+ PARAMS=$(jq -n \
1055
+ --arg hsid "$HSID" --arg tid "$TURN_ID" --arg turn "$TURN" \
1056
+ --arg question "$QUESTION" --arg qintent "$QINTENT" \
1057
+ --arg answer "$ANSWER" --arg eval "$EVAL" \
1058
+ '{hsid:$hsid, tid:$tid, turn:$turn, question:$question, qintent:$qintent, answer:$answer, eval:$eval}')
1059
+ if [ -n "$ANSWER" ]; then
1060
+ bash "$GS" query "
1061
+ MATCH (hs:HarvestSession {id: \$hsid})
1062
+ MERGE (t:HarvestTurn {id: \$tid})
1063
+ ON CREATE SET t.turnNumber = toInteger(\$turn), t.question = \$question,
1064
+ t.questionIntent = \$qintent, t.created = datetime()
1065
+ SET t.answer = \$answer, t.answeredAt = datetime()
1066
+ SET t.evaluation = CASE WHEN \$eval <> '' THEN \$eval ELSE t.evaluation END
1067
+ MERGE (hs)-[:HAS_TURN]->(t)
1068
+ RETURN t.id AS id, t.turnNumber AS turnNumber
1069
+ " "$PARAMS"
1070
+ else
1071
+ bash "$GS" query "
1072
+ MATCH (hs:HarvestSession {id: \$hsid})
1073
+ MERGE (t:HarvestTurn {id: \$tid})
1074
+ ON CREATE SET t.turnNumber = toInteger(\$turn), t.question = \$question,
1075
+ t.questionIntent = \$qintent, t.created = datetime()
1076
+ MERGE (hs)-[:HAS_TURN]->(t)
1077
+ RETURN t.id AS id, t.turnNumber AS turnNumber
1078
+ " "$PARAMS"
1079
+ fi
1080
+ ;;
1081
+
1082
+ complete-harvest)
1083
+ HID="${1:?missing harvest-id}"
1084
+ ARTIFACT_PATH="${2:?missing artifact-path}"
1085
+ bash "$GS" query "
1086
+ MATCH (h:Harvest {id: \$hid})
1087
+ SET h.status = 'complete', h.completedAt = datetime(), h.synthesisPath = \$path
1088
+ WITH h
1089
+ OPTIONAL MATCH (h)-[:HAS_SESSION]->(hs:HarvestSession)
1090
+ WHERE hs.status <> 'complete'
1091
+ SET hs.status = 'complete', hs.completedAt = datetime()
1092
+ WITH h
1093
+ MERGE (a:Artifact {id: \$hid + '-synthesis'})
1094
+ ON CREATE SET a.type = 'harvest', a.title = h.topic, a.filePath = \$path,
1095
+ a.created = datetime(), a.topics = coalesce([h.topic], [])
1096
+ MERGE (h)-[:PRODUCED]->(a)
1097
+ RETURN h.id AS id, h.status AS status, a.id AS artifact
1098
+ " "$(jq -n --arg hid "$HID" --arg path "$ARTIFACT_PATH" '{hid: $hid, path: $path}')"
1099
+ ;;
1100
+
1101
+ *)
1102
+ echo '{"error":"unknown operation: '"$OP"'","operations":["catalog","mark-read","mark-done","mark-expired","reopen-handoff","answer-question","resolve-handoffs","set-topic","record-focus","merge-person","claim-handoff","claim-handoff-nudge","mark-handoff-nudged","release-handoff-nudge","check-implements","create-pr","update-pr","my-merged-prs","my-implemented-handoffs","open-handoffs","pending-questions","lineage","meeting-history","wal-status","create-harvest","create-harvest-session","record-harvest-turn","complete-harvest"]}'
1103
+ exit 1
1104
+ ;;
1105
+
1106
+ esac