elanous 0.2.13 → 0.2.14

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 (445) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1307-6e7e0377c1db0bdc.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
  9. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4562-071d8bac44a01069.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5977-2df489622a52a33a.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
  31. package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
  42. package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/approvals/page-74383f890f075511.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-7b2b4f378354869a.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/board/page-c496bb16da85385f.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-f14987d5850a31e0.js → page-1abfe3aec3be6bdc.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/app/bots/page-1512d91c7491ed62.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/chat/page-a627db94ec6904a0.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/consult/page-fb260b9283dbf646.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/control/page-e6b84ab07d3567d5.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/design-check/page-61ec1d2e92bdd50a.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/editor/page-fed69f9759d248d0.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/exec/page-15374909d8f1aebd.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/field/page-012a742f81218b01.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/inside/page-fd7e200d4d83fbd7.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/intake/page-99effd9d893a43dc.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/layout-938de57ae0315e46.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/live/page-d47266766766d227.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/loops/page-160089123a40dd91.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/market/page-629e1ede482ec6eb.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-66c27608f651b866.js → page-2ce5471926761fdd.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/app/morning/page-27e99b4e54a849d4.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/not-found-e995d30f6800b6bf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/observatory/page-39f89c53038a51d4.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-32cde713be47cddb.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e7e10cd3386222e5.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-5a753bb4ec0cc511.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/outputs/page-04250f0e2c0d03df.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/page-341480ed8e3c1ea8.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/reflection/page-e64caff084f7ce21.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-db07eaffba0df7e3.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8ac8d71c2adf9c8a.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-78b40a344ed22f24.js → page-e1e47d8d940aba3d.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/app/settings/page-86f91034bd5cabe5.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-94dc383d3d54db1a.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/page-b3759cc14da80908.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/share/page-ce4d8a1215ce53a3.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/showroom/page-58043db78ba519ae.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/tasks/page-357750dfb91bf960.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/term/{page-63d14a4d8fe1e1c1.js → page-274703bc41b71333.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/app/today/page-194dce4a83143fce.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/trace/page-35bdeae2e2c17147.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/vault/page-3b7e821dc492bdfd.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-16bef3da05a900c3.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/workflows/page-f8da5dc6f3752276.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2f810b18d89ecba6.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-134c1bc762aee62c.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
  98. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
  104. package/apps/pwa/out/_next/static/css/2e33713c444d5b39.css +1 -0
  105. package/apps/pwa/out/_next/static/x6mjI6vqOkVVu0jFuDkz1/_buildManifest.js +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -1
  134. package/apps/pwa/out/inside/index.txt +22 -22
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/loops/index.html +1 -0
  140. package/apps/pwa/out/loops/index.txt +30 -0
  141. package/apps/pwa/out/market/index.html +1 -1
  142. package/apps/pwa/out/market/index.txt +22 -22
  143. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  144. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  145. package/apps/pwa/out/morning/index.html +1 -1
  146. package/apps/pwa/out/morning/index.txt +23 -23
  147. package/apps/pwa/out/observatory/index.html +1 -1
  148. package/apps/pwa/out/observatory/index.txt +23 -23
  149. package/apps/pwa/out/ops/checklist/index.html +1 -1
  150. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  151. package/apps/pwa/out/ops/release/index.html +1 -1
  152. package/apps/pwa/out/ops/release/index.txt +22 -22
  153. package/apps/pwa/out/ops/seats/index.html +1 -1
  154. package/apps/pwa/out/ops/seats/index.txt +22 -22
  155. package/apps/pwa/out/outputs/index.html +1 -1
  156. package/apps/pwa/out/outputs/index.txt +22 -22
  157. package/apps/pwa/out/reflection/index.html +1 -1
  158. package/apps/pwa/out/reflection/index.txt +23 -23
  159. package/apps/pwa/out/scheduler/index.html +1 -1
  160. package/apps/pwa/out/scheduler/index.txt +23 -23
  161. package/apps/pwa/out/sessions/index.html +1 -1
  162. package/apps/pwa/out/sessions/index.txt +22 -22
  163. package/apps/pwa/out/settings/devices/index.html +1 -1
  164. package/apps/pwa/out/settings/devices/index.txt +23 -23
  165. package/apps/pwa/out/settings/index.html +1 -1
  166. package/apps/pwa/out/settings/index.txt +23 -23
  167. package/apps/pwa/out/setup/done/index.html +1 -1
  168. package/apps/pwa/out/setup/done/index.txt +23 -23
  169. package/apps/pwa/out/setup/index.html +1 -1
  170. package/apps/pwa/out/setup/index.txt +23 -23
  171. package/apps/pwa/out/share/index.html +1 -1
  172. package/apps/pwa/out/share/index.txt +23 -23
  173. package/apps/pwa/out/showroom/index.html +1 -1
  174. package/apps/pwa/out/showroom/index.txt +22 -22
  175. package/apps/pwa/out/tasks/index.html +1 -1
  176. package/apps/pwa/out/tasks/index.txt +23 -23
  177. package/apps/pwa/out/term/index.html +1 -1
  178. package/apps/pwa/out/term/index.txt +23 -23
  179. package/apps/pwa/out/today/index.html +1 -1
  180. package/apps/pwa/out/today/index.txt +23 -23
  181. package/apps/pwa/out/trace/index.html +1 -1
  182. package/apps/pwa/out/trace/index.txt +23 -23
  183. package/apps/pwa/out/vault/index.html +1 -1
  184. package/apps/pwa/out/vault/index.txt +23 -23
  185. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  186. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  187. package/apps/pwa/out/workflows/index.html +1 -1
  188. package/apps/pwa/out/workflows/index.txt +23 -23
  189. package/apps/pwa/out/workspace/index.html +1 -1
  190. package/apps/pwa/out/workspace/index.txt +23 -23
  191. package/apps/pwa/out/worktrees/index.html +1 -1
  192. package/apps/pwa/out/worktrees/index.txt +23 -23
  193. package/graphs/orchestrator/orchestrator.yaml +59 -0
  194. package/graphs/orchestrator/recipes.yaml +18 -0
  195. package/graphs/release/recipes.yaml +3 -0
  196. package/graphs/release/release-loop.yaml +4 -1
  197. package/graphs/rhythm/daily.yaml +38 -0
  198. package/graphs/rhythm/recipes.yaml +18 -0
  199. package/graphs/rhythm/weekly.yaml +39 -0
  200. package/graphs/video/recipes.yaml +3 -0
  201. package/graphs/video/youtube-summary.yaml +17 -0
  202. package/package.json +1 -1
  203. package/scripts/audit-test-state-writes.ts +72 -17
  204. package/scripts/brand/check.ts +186 -0
  205. package/scripts/coord-post.sh +11 -1
  206. package/scripts/docs-cli-check.ts +23 -6
  207. package/scripts/expose-rubric-check.ts +118 -0
  208. package/scripts/expose-rubric-suggest.ts +163 -0
  209. package/scripts/heal/run-role.ts +14 -0
  210. package/scripts/hq/standby-verify.ts +11 -7
  211. package/scripts/lessons/handbook-page.ts +85 -0
  212. package/scripts/release-loop/gate-node.ts +9 -0
  213. package/scripts/release-loop/publish-node.ts +14 -1
  214. package/scripts/release-loop/unattended-release.ts +23 -1
  215. package/scripts/release-loop/vault-note-node.ts +196 -0
  216. package/scripts/release-story/draft.ts +172 -0
  217. package/scripts/rhythm/daily.ts +383 -0
  218. package/scripts/rhythm/weekly.ts +294 -0
  219. package/scripts/skills/public-check.ts +169 -0
  220. package/scripts/test-deterministic.ts +4 -8
  221. package/scripts/test-diet/effectiveness.ts +195 -0
  222. package/scripts/test-diet/lib.ts +16 -8
  223. package/scripts/test-diet/node.ts +77 -9
  224. package/scripts/ux/demo-rehearsal.ts +2 -2
  225. package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
  226. package/scripts/video/youtube-summary.ts +133 -0
  227. package/skills/diagram-master/SKILL.md +42 -49
  228. package/skills/diagram-master/references/pyproject.toml +4 -1
  229. package/skills/diagram-master/references/routing-guide.md +4 -2
  230. package/skills/grill-me/SKILL.md +1 -0
  231. package/skills/youtube-master/SKILL.md +13 -13
  232. package/skills/youtube-master/package-lock.json +0 -545
  233. package/skills/youtube-master/package.json +2 -5
  234. package/skills/youtube-master/scripts/main.ts +2 -2
  235. package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
  236. package/skills/youtube-master/src/util.ts +30 -7
  237. package/src/agent-mission/driver.ts +3 -3
  238. package/src/autopilot/build/llm-conflict-merge.ts +45 -8
  239. package/src/autopilot/build/merge-intent.ts +53 -0
  240. package/src/chat/index.ts +2 -0
  241. package/src/claims/claims-ledger.ts +232 -0
  242. package/src/claims/claims-render.ts +157 -0
  243. package/src/cli/claims-cli.ts +94 -0
  244. package/src/cli/decisions-cli.ts +35 -3
  245. package/src/cli/docs-cli.ts +2 -0
  246. package/src/cli/flow-cli.ts +11 -0
  247. package/src/cli/freeze-cli.ts +45 -0
  248. package/src/cli/lesson-cli.ts +108 -0
  249. package/src/cli/logs-cli.ts +104 -2
  250. package/src/cli/logs-model-input.ts +131 -0
  251. package/src/cli/pr-cli.ts +29 -1
  252. package/src/cli/private-ledger-commands.ts +54 -4
  253. package/src/cli/pty-drive-verdict.ts +11 -2
  254. package/src/cli/release-cli.ts +144 -21
  255. package/src/cli/rfc-status.ts +91 -0
  256. package/src/connectors/linear.ts +5 -3
  257. package/src/context-bus/condense.ts +15 -20
  258. package/src/context-bus/context-now-public.ts +86 -0
  259. package/src/context-bus/context-now-surfaces.ts +55 -2
  260. package/src/context-bus/context-now.ts +4 -3
  261. package/src/context-bus/long-term-memory.ts +92 -11
  262. package/src/dashboard/index.ts +75 -22
  263. package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
  264. package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
  265. package/src/dashboard/slash-runtime/loops-table.ts +77 -0
  266. package/src/decisions/decision-ledger.ts +40 -1
  267. package/src/discord/sprint21-runtime.ts +16 -0
  268. package/src/discord-self-message.ts +8 -0
  269. package/src/discord-slash-wire.ts +31 -2
  270. package/src/domains/outbound-alert.ts +1 -1
  271. package/src/elanous-config-dir.ts +29 -4
  272. package/src/execution-loop/launch-gate.ts +29 -14
  273. package/src/flow/cards.ts +239 -0
  274. package/src/graph-runner/graph-tick.ts +4 -0
  275. package/src/graph-runner/runner.ts +30 -5
  276. package/src/harness/harness-cli-command.ts +152 -27
  277. package/src/harness/harness-incidents.ts +43 -12
  278. package/src/harness/harness-pod-dispatch.ts +2 -0
  279. package/src/harness/harness-queue-child.ts +3 -3
  280. package/src/harness/harness-queue.ts +216 -28
  281. package/src/harness/helper-scan.ts +139 -0
  282. package/src/harness/model-input-observation.ts +37 -0
  283. package/src/hq/hq.ts +1 -1
  284. package/src/hq/promote.ts +301 -0
  285. package/src/index.ts +83 -21
  286. package/src/intake-plane/linear-wish.ts +39 -11
  287. package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
  288. package/src/intake-plane/wish-card.ts +53 -2
  289. package/src/intake-plane/wish-folder.ts +5 -2
  290. package/src/intake-plane/wish-reply.ts +72 -0
  291. package/src/lessons/lesson-import.ts +106 -0
  292. package/src/lessons/lesson-ledger.ts +206 -0
  293. package/src/loops/activity.ts +203 -0
  294. package/src/loops/budget.ts +32 -0
  295. package/src/loops/checker.ts +5 -3
  296. package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
  297. package/src/loops/loop-cli.ts +36 -4
  298. package/src/loops/neighbors.ts +40 -0
  299. package/src/loops/observe.ts +10 -0
  300. package/src/loops/orchestrator/author-depth.ts +164 -0
  301. package/src/loops/orchestrator/author-input-check.ts +77 -0
  302. package/src/loops/orchestrator/author-ledger.ts +230 -0
  303. package/src/loops/orchestrator/finish-rate.ts +175 -0
  304. package/src/loops/orchestrator/overlap.ts +51 -12
  305. package/src/loops/orchestrator/resync-shadow.ts +227 -0
  306. package/src/loops/orchestrator/tick.ts +302 -0
  307. package/src/loops/orchestrator/traffic.ts +18 -3
  308. package/src/loops/registry.ts +454 -9
  309. package/src/loops/status-rows.ts +118 -0
  310. package/src/loops/verdict.ts +17 -5
  311. package/src/maturity/bot-slash-catalog.ts +66 -0
  312. package/src/maturity/feature-maturity.ts +7 -4
  313. package/src/nexus/api/dashboard.ts +6 -1
  314. package/src/nexus/api/http-server.ts +18 -2
  315. package/src/nexus/api/merge-approvals-gate.ts +1 -1
  316. package/src/nexus/api/schedules-read.ts +5 -1
  317. package/src/nexus/api/task-cards-api.ts +44 -5
  318. package/src/nexus/api/workflows.ts +2 -1
  319. package/src/release-loop/auto-start.ts +48 -0
  320. package/src/release-loop/checklist.ts +13 -4
  321. package/src/release-loop/feature-store.ts +28 -16
  322. package/src/release-loop/landing-freeze.ts +121 -0
  323. package/src/release-loop/placement.ts +242 -0
  324. package/src/release-loop/release-schedule.ts +3 -1
  325. package/src/seat-dispatch/ceo-commands.ts +2 -2
  326. package/src/seat-dispatch/seat-ask.ts +16 -3
  327. package/src/seat-dispatch/seat-questions.ts +58 -0
  328. package/src/seat-loop/seat-loop.ts +406 -31
  329. package/src/self-dev/dev-pipeline.ts +6 -2
  330. package/src/self-dev/draft-sweep.ts +76 -0
  331. package/src/self-dev/run-store.ts +73 -1
  332. package/src/self-dev/run-supervisor.ts +8 -0
  333. package/src/self-dev/self-orchestrate-runtime.ts +5 -1
  334. package/src/self-implement/budget-gate.ts +29 -0
  335. package/src/self-implement/expose-gate.ts +47 -0
  336. package/src/self-implement/frozen-merges.ts +294 -0
  337. package/src/self-implement/gate-cli.ts +10 -4
  338. package/src/self-implement/gate-scope.ts +46 -9
  339. package/src/self-implement/goal-archive.ts +222 -0
  340. package/src/self-implement/goal-lookup.ts +147 -0
  341. package/src/self-implement/heal-intake.ts +79 -0
  342. package/src/self-implement/host-regate.ts +25 -2
  343. package/src/self-implement/orchestrator.ts +114 -10
  344. package/src/self-implement/revert-guard.ts +62 -0
  345. package/src/self-implement/run-ledger.ts +1 -1
  346. package/src/self-implement/seams.ts +28 -8
  347. package/src/session/index.ts +2 -0
  348. package/src/task-cards/card-cli.ts +10 -2
  349. package/src/task-cards/card-store.ts +10 -6
  350. package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
  351. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
  352. package/src/task-orchestrator/surfaces/self-implement-pod.ts +80 -16
  353. package/src/telegram-commands.ts +27 -3
  354. package/src/telegram-loops-command.ts +44 -0
  355. package/src/user-config.ts +120 -16
  356. package/src/version/packed-revision.json +1 -1
  357. package/src/workflow-runtime/storage.ts +31 -13
  358. package/apps/pwa/out/_next/static/D51l8jUBplJrIpWvENsDK/_buildManifest.js +0 -1
  359. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
  360. package/apps/pwa/out/_next/static/chunks/1394-931c9827067b2276.js +0 -1
  361. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
  362. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
  363. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
  364. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
  365. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
  366. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
  367. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
  368. package/apps/pwa/out/_next/static/chunks/3992-fe5c06d6b31f8b25.js +0 -25
  369. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
  370. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
  371. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
  372. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
  373. package/apps/pwa/out/_next/static/chunks/5250-c78ca295585bbf95.js +0 -1
  374. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
  375. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
  376. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
  377. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
  378. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
  379. package/apps/pwa/out/_next/static/chunks/6511-ff8360be3d65aaa4.js +0 -1
  380. package/apps/pwa/out/_next/static/chunks/6588-ba380869b67c4fa7.js +0 -1
  381. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
  382. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
  383. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
  384. package/apps/pwa/out/_next/static/chunks/7758-85c2b53f731da024.js +0 -1
  385. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
  386. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
  387. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
  388. package/apps/pwa/out/_next/static/chunks/8605-9da4678f8a310d18.js +0 -1
  389. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
  390. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
  391. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
  392. package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
  393. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
  394. package/apps/pwa/out/_next/static/chunks/9906-e7b8b5310a169dfe.js +0 -1
  395. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
  396. package/apps/pwa/out/_next/static/chunks/app/approvals/page-e5b4e1b256f41076.js +0 -1
  397. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e49b9b76c565a0b1.js +0 -1
  398. package/apps/pwa/out/_next/static/chunks/app/board/page-b4f032c893b21cc9.js +0 -1
  399. package/apps/pwa/out/_next/static/chunks/app/bots/page-b433308aad13ceb6.js +0 -1
  400. package/apps/pwa/out/_next/static/chunks/app/chat/page-4c1dbb21861beab2.js +0 -1
  401. package/apps/pwa/out/_next/static/chunks/app/consult/page-c85b816e3b269dbb.js +0 -1
  402. package/apps/pwa/out/_next/static/chunks/app/control/page-f6bc66b919b2ea7d.js +0 -1
  403. package/apps/pwa/out/_next/static/chunks/app/design-check/page-60603c1e056c9b25.js +0 -1
  404. package/apps/pwa/out/_next/static/chunks/app/editor/page-a0ea8f5a2341ee6b.js +0 -1
  405. package/apps/pwa/out/_next/static/chunks/app/exec/page-45c5bf04b4a605e6.js +0 -1
  406. package/apps/pwa/out/_next/static/chunks/app/field/page-36c6c4183353ac9e.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/app/inside/page-cb2eb0fd809980da.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/app/intake/page-31012264da8a341f.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/app/layout-50309aeb0bdd554a.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/app/live/page-bc00e964e855f4df.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/app/market/page-0696ee3fac9fe56c.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/app/morning/page-6ddd2109b7fc3a80.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/app/not-found-4e50b7298c1f69a5.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7a2bf830038a2264.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1f327f18694fabca.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e5cef2fe6e4028df.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cf596128d2b420ba.js +0 -1
  419. package/apps/pwa/out/_next/static/chunks/app/outputs/page-f672536f14f0969f.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/app/page-b52365662232db89.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/app/reflection/page-e7a6c80f288b1948.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-29a709616df9b050.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fee842d7c2151129.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/app/settings/page-75d199f448171014.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a011dd5b0bff29c5.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/app/setup/page-d92e32d51ab5157e.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/app/share/page-5f21aed6932ef375.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/app/showroom/page-1e1a53946804debf.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/app/tasks/page-a1833cd43d832601.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/app/today/page-2a511d320f762e06.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/app/trace/page-1c3e03f88dac1e21.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/app/vault/page-c4d5289c2ea97a89.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b91f8952deaeaf27.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/app/workflows/page-71b43a2588489987.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2b256feed331546f.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-505bb96d69a8622c.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
  444. package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
  445. /package/apps/pwa/out/_next/static/{D51l8jUBplJrIpWvENsDK → x6mjI6vqOkVVu0jFuDkz1}/_ssgManifest.js +0 -0
@@ -38,7 +38,7 @@ import { lookupEntrance, type EntranceId } from './entrance-registry.js';
38
38
  import type { IngestionEntry } from '../agent-substrate/execution/ingestion-policy.js';
39
39
  import type { ReviewerContextItem } from '../agent-substrate/pr-reviewer.js';
40
40
  import { resolveRunIdentity, type RunIdSource } from '../harness/harness-space.js';
41
- import { addSelfDevRunParticipant, saveSelfDevRun } from './run-store.js';
41
+ import { addSelfDevRunParticipant, processBirthId, saveSelfDevRun } from './run-store.js';
42
42
  import { getUserConfig, resolveRoleLlm } from '../user-config.js';
43
43
  import { reviewReasoningEffort } from '../model-tier/review-effort.js';
44
44
  import { getProvider, inferProviderFromModel } from '../llm.js';
@@ -1718,7 +1718,11 @@ export async function runDevPipeline(spec: DevPipelineSpec, deps: DevPipelineDep
1718
1718
  if (spec.runId) {
1719
1719
  const runIdSource = spec.runIdSource ?? resolveRunIdentity({ explicit: spec.runId }).source;
1720
1720
  const now = Date.now();
1721
- saveSelfDevRun({ runId: spec.runId, createdAt: now, updatedAt: now, results: [], pid: process.pid });
1721
+ const seat = process.env.ELANOUS_HARNESS_SEAT;
1722
+ const pidStart = processBirthId(process.pid);
1723
+ saveSelfDevRun({ runId: spec.runId, createdAt: now, updatedAt: now, results: [], pid: process.pid,
1724
+ ...(pidStart ? { pidStart } : {}),
1725
+ ...(seat === 'OP' || seat === 'TC' || seat === 'MK' || seat === 'UX' ? { seat } : {}) });
1722
1726
  addSelfDevRunParticipant(spec.runId, {
1723
1727
  id: `process:${process.pid}`,
1724
1728
  kind: 'process',
@@ -31,6 +31,8 @@ export interface DraftSweepAdapters {
31
31
  hasFinalRunResult?(draft: SweepDraft, repository: string): Promise<boolean | undefined>;
32
32
  /** Per-file last change on the draft branch; undefined means file coverage is unverified. */
33
33
  getLatestFileChanges?(draft: SweepDraft, repository: string): Promise<Readonly<Record<string, string>> | undefined>;
34
+ /** Optional merge-time file inventory for the existing all-files-landed decision. */
35
+ getPrFiles?(repository: string, number: number): Promise<readonly string[] | undefined>;
34
36
  }
35
37
 
36
38
  export interface DraftSweepOptions {
@@ -84,6 +86,80 @@ const PAGE_SIZE = 100;
84
86
  /** At most this many closes per tick, so a wrong rule cannot close everything at once. */
85
87
  export const DRAFT_SWEEP_CLOSE_CAP = 10;
86
88
 
89
+ /** Post-merge shortcut: only the existing superseded-by decision can authorize a close. */
90
+ export async function supersedeDraftsOnMerge(input: {
91
+ repository: string;
92
+ merged: SweepMergedPr & { createdAt: string; mergedAt: string };
93
+ adapters: Pick<DraftSweepAdapters, 'listDrafts' | 'listLiveBranches' | 'getRunStatus' | 'setLabels' | 'closeDraft'>
94
+ & Pick<Partial<DraftSweepAdapters>, 'getLatestFileChanges' | 'getPrFiles'>;
95
+ }): Promise<{ closed: number[]; kept: number[] }> {
96
+ const { repository, merged, adapters } = input;
97
+ const closed: number[] = [];
98
+ const kept: number[] = [];
99
+ let drafts: SweepDraft[] = [];
100
+ let error: string | undefined;
101
+ const failed: number[] = [];
102
+ let closeAttempts = 0;
103
+ try {
104
+ const [listedDrafts, liveBranches] = await Promise.all([
105
+ collectPages((page, size) => adapters.listDrafts(page, size, repository)),
106
+ adapters.listLiveBranches(repository),
107
+ ]);
108
+ drafts = listedDrafts;
109
+ if (!liveBranches || !Number.isInteger(merged.number) || !merged.branch || !merged.title
110
+ || !Number.isFinite(Date.parse(merged.createdAt)) || !Number.isFinite(Date.parse(merged.mergedAt))
111
+ || drafts.some((pr) => !Number.isInteger(pr.number) || !pr.branch || !Array.isArray(pr.labels)
112
+ || !Number.isFinite(Date.parse(pr.createdAt)))) throw new Error('Incomplete merge draft inventory');
113
+ const statuses = new Map<number, string | undefined>();
114
+ const latestChanges = new Map<number, Readonly<Record<string, string>> | undefined>();
115
+ const mergedFiles = await adapters.getPrFiles?.(repository, merged.number);
116
+ const landed = { ...merged, changedFiles: mergedFiles };
117
+ for (const draft of drafts) {
118
+ if (draft.number !== merged.number && !liveBranches.has(draft.branch)
119
+ && Date.parse(draft.createdAt) < Date.parse(merged.mergedAt)) {
120
+ statuses.set(draft.number, await adapters.getRunStatus(draft, repository));
121
+ if (draft.changedFiles?.length && adapters.getLatestFileChanges) {
122
+ latestChanges.set(draft.number, await adapters.getLatestFileChanges(draft, repository));
123
+ }
124
+ }
125
+ }
126
+ for (const listedDraft of drafts) {
127
+ const draft = { ...listedDraft, latestFileChanges: latestChanges.get(listedDraft.number) };
128
+ if (draft.number === merged.number || liveBranches.has(draft.branch)
129
+ || Date.parse(draft.createdAt) >= Date.parse(merged.mergedAt)) {
130
+ kept.push(draft.number);
131
+ continue;
132
+ }
133
+ const decision = decideDraft({ draft, runStatus: statuses.get(draft.number),
134
+ mergedTwins: [landed], liveBranches, ageHours: NaN });
135
+ if (decision.action !== 'close' || !decision.reason.startsWith(`superseded-by #${merged.number}`)
136
+ || PR_LABELS.filter((entry) => entry.axis === 'state' && draft.labels.includes(entry.name)).length > 1
137
+ || (draft.labels.length === 0 && !draft.branch.startsWith('self-impl/'))
138
+ || closeAttempts >= DRAFT_SWEEP_CLOSE_CAP) {
139
+ kept.push(draft.number);
140
+ continue;
141
+ }
142
+ closeAttempts += 1;
143
+ const remove = stateLabels.filter((entry) => draft.labels.includes(entry.name) && entry.name !== supersededLabel).map((entry) => entry.name);
144
+ try {
145
+ // Label first: a failed label write must never strand a closed, unlabelled PR outside open-draft sweeps.
146
+ if (!draft.labels.includes(supersededLabel)) await adapters.setLabels(repository, draft.number, { add: supersededLabel, remove });
147
+ await adapters.closeDraft(repository, draft.number, `Draft sweep: superseded-by #${merged.number}. Branch preserved.`);
148
+ closed.push(draft.number);
149
+ } catch (failure) {
150
+ kept.push(draft.number);
151
+ failed.push(draft.number);
152
+ error = String(failure);
153
+ }
154
+ }
155
+ } catch (failure) {
156
+ error = String(failure);
157
+ kept.push(...drafts.map((draft) => draft.number).filter((number) => !closed.includes(number) && !kept.includes(number)));
158
+ }
159
+ debug.log('drafts.cleanup', 'superseded-on-merge', { merged: merged.number, closed, kept, ...(failed.length ? { failed } : {}), ...(error ? { error } : {}) });
160
+ return { closed, kept };
161
+ }
162
+
87
163
  async function collectPages<T>(fetch: (page: number, perPage: number) => Promise<readonly T[]>): Promise<T[]> {
88
164
  const rows: T[] = [];
89
165
  for (let page = 1; page <= 100; page++) {
@@ -16,8 +16,9 @@
16
16
  * Cf. PLAN-parallel-self-dev-orchestrator-2026-07-21 §5 (S3).
17
17
  */
18
18
  import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
19
+ import { dlopen, FFIType } from 'bun:ffi';
19
20
  import { randomUUID } from 'node:crypto';
20
- import { debug } from '../debug/log.js';
21
+ import { debug, redactSecretText } from '../debug/log.js';
21
22
  import { elanousStateRoot } from '../autopilot/state-paths.js';
22
23
  import { loadRunLedger, queryInterruptedRunLedgers, runLedgerDir, type RunLedgerEntry } from '../self-implement/run-ledger.js';
23
24
  import { join, resolve, sep } from 'node:path';
@@ -68,6 +69,8 @@ export interface SelfDevRunState {
68
69
  createdAt: number;
69
70
  updatedAt: number;
70
71
  results: SelfDevJobResult[];
72
+ /** Redacted, bounded one-line projection for loop readers; legacy checkpoints omit it. */
73
+ summaryLine?: string;
71
74
  /** Undefined means a legacy checkpoint has no dependency information; each key is a shard ID and its array lists predecessor shard IDs. */
72
75
  dependencies?: Record<string, string[]>;
73
76
  /**
@@ -93,6 +96,10 @@ export interface SelfDevRunState {
93
96
  * non-terminal goal 은 **실행중(running)** 이지 막힌(interrupted) 게 아니다. 죽었으면(오케스트레이터
94
97
  * killed) 진짜 interrupted. isPidAlive 로 구분해 라이브 잡을 parked/repair-signals 에서 제외. */
95
98
  pid?: number;
99
+ /** OS process birth identity, paired with pid to reject a recycled pid. */
100
+ pidStart?: string;
101
+ /** Seat fixed at launch; survives removal of the launch worktree. */
102
+ seat?: 'OP' | 'TC' | 'MK' | 'UX';
96
103
  }
97
104
 
98
105
  /** `<ELANOUS_STATE_DIR or ~/.elanous>/self-dev-runs`. */
@@ -103,6 +110,34 @@ export function selfDevRunsDir(stateDir?: string): string {
103
110
 
104
111
  const RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
105
112
 
113
+ /** Kernel process birth identity: Linux boot ID + start ticks or Darwin microseconds since epoch. */
114
+ export function processBirthId(pid: number, platform: NodeJS.Platform = process.platform): string | undefined {
115
+ if (!Number.isSafeInteger(pid) || pid < 1) return undefined;
116
+ try {
117
+ if (platform === 'linux') {
118
+ const stat = readFileSync(`/proc/${pid}/stat`, 'utf8');
119
+ const tail = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\s+/);
120
+ const ticks = tail[19]; // field 22 (starttime), after pid and parenthesized comm
121
+ const bootId = readFileSync('/proc/sys/kernel/random/boot_id', 'utf8').trim();
122
+ return ticks && /^\d+$/.test(ticks) && /^[0-9a-f-]{36}$/i.test(bootId)
123
+ ? `linux:${bootId}:${ticks}` : undefined;
124
+ }
125
+ if (platform === 'darwin') {
126
+ const libproc = dlopen('/usr/lib/libproc.dylib', {
127
+ proc_pidinfo: { args: [FFIType.i32, FFIType.i32, FFIType.u64, FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
128
+ });
129
+ try {
130
+ const buf = new Uint8Array(136);
131
+ if (libproc.symbols.proc_pidinfo(pid, 3, 0n, buf, buf.length) !== buf.length) return undefined;
132
+ const view = new DataView(buf.buffer);
133
+ if (view.getUint32(12, true) !== pid) return undefined;
134
+ return `darwin:${view.getBigUint64(120, true) * 1_000_000n + view.getBigUint64(128, true)}`;
135
+ } finally { libproc.close(); }
136
+ }
137
+ } catch { /* Unreadable birth identity is not evidence of a match. */ }
138
+ return undefined;
139
+ }
140
+
106
141
  function runPath(runId: string, dir: string): string {
107
142
  if (!RUN_ID.test(runId)) throw new Error(`invalid self-dev run ID: ${runId}`);
108
143
  const root = resolve(dir);
@@ -154,6 +189,40 @@ function mergeParticipants(
154
189
  return [...byId.values()];
155
190
  }
156
191
 
192
+ const SUMMARY_LINE_LIMIT = 120;
193
+ const FINISHED_RESULT_STATUSES = new Set(['done', 'failed', 'cancelled', 'superseded']);
194
+
195
+ function boundedSummaryLine(text: string): string {
196
+ const redacted = redactSecretText(text.replace(/\s+/g, ' ').trim());
197
+ if (redacted.length <= SUMMARY_LINE_LIMIT) return redacted;
198
+ const head = redacted.slice(0, SUMMARY_LINE_LIMIT - 1).replace(/[\uD800-\uDBFF]$/, '');
199
+ return `${head}…`;
200
+ }
201
+
202
+ /** Read-only projection for loop readers; missing legacy fields are derived in memory. */
203
+ export function runSummaryLine(state: SelfDevRunState): string {
204
+ if (state.summaryLine !== undefined) return boundedSummaryLine(state.summaryLine);
205
+ const feature = state.goals?.[0]?.feature ?? state.results[0]?.feature ?? '';
206
+ const head = feature.split(/\r?\n/, 1)[0]?.trim() ?? '';
207
+ const header = /^「하니스로 구현」\s+(\S+?)\s+—\s*(.*)$/.exec(head);
208
+ const id = state.goals?.[0]?.goalId ?? header?.[1] ?? state.goals?.[0]?.id ?? state.runId;
209
+ const phrase = (header?.[2] ?? head).split(/[.!?。;;]/, 1)[0]?.trim() ?? '';
210
+ const finished = state.results.length > 0
211
+ && state.results.every((result) => FINISHED_RESULT_STATUSES.has(result.status));
212
+ if (finished) {
213
+ // A completed shard cannot hide a failed one merely by settling later.
214
+ const result = state.results.find(({ status }) => status === 'failed')
215
+ ?? state.results.find(({ status }) => status === 'cancelled')
216
+ ?? state.results.find(({ status }) => status === 'superseded')
217
+ ?? state.results.at(-1)!;
218
+ const stage = result.stage ?? result.status;
219
+ const prNumber = result.prNumber ?? Number(/\/pull\/(\d+)(?:[/?#]|$)/.exec(result.prUrl ?? '')?.[1]);
220
+ const pr = Number.isSafeInteger(prNumber) && prNumber > 0 ? ` · PR #${prNumber}` : '';
221
+ return boundedSummaryLine(`${id} · ${stage}${pr}`);
222
+ }
223
+ return boundedSummaryLine(`「하니스로 구현」 ${id}${phrase ? ` — ${phrase}` : ''}`);
224
+ }
225
+
157
226
  /** Persist a run checkpoint (fail-soft — never throws into the caller). */
158
227
  export function saveSelfDevRun(state: SelfDevRunState, dir = selfDevRunsDir()): void {
159
228
  try {
@@ -163,7 +232,10 @@ export function saveSelfDevRun(state: SelfDevRunState, dir = selfDevRunsDir()):
163
232
  const participants = mergeParticipants(current?.participants, state.participants);
164
233
  const saved = {
165
234
  ...state,
235
+ summaryLine: runSummaryLine({ ...state, goals: state.goals ?? current?.goals, summaryLine: undefined }),
166
236
  ...(participants === undefined ? {} : { participants }),
237
+ ...(current?.seat && !state.seat ? { seat: current.seat } : {}),
238
+ ...(current?.pidStart && current.pid === state.pid && !state.pidStart ? { pidStart: current.pidStart } : {}),
167
239
  ...(current?.parkedResolution && !state.parkedResolution ? { parkedResolution: current.parkedResolution } : {}),
168
240
  };
169
241
  writeSelfDevRun(saved, dir);
@@ -5,6 +5,7 @@ import type { DeployVerifyFinding } from '../harness/browser-verify.js';
5
5
  import type { SelfDevJobResult } from './orchestrate.js';
6
6
  import { recordSelfDevRunSupervisorStop, selfDevRunsDir } from './run-store.js';
7
7
  import { debug } from '../debug/log.js';
8
+ import { sweepFrozenMerges } from '../self-implement/frozen-merges.js';
8
9
 
9
10
  export interface SupervisorRound {
10
11
  round: number;
@@ -410,6 +411,7 @@ export interface SuperviseRunOptions {
410
411
  onRound?: (results: readonly SupervisorJobResult[]) => void;
411
412
  runStore?: { runId?: string; operatorDir?: string; dir?: string; isolatedDir?: string };
412
413
  observe?: (event: string, data: Record<string, unknown>) => void;
414
+ sweepPendingMerges?: typeof sweepFrozenMerges;
413
415
  observeDeliverables?: () => Promise<{
414
416
  readonly deployFindings: ReadonlyMap<string, { target: string; findings?: readonly DeployVerifyFinding[] | readonly unknown[] }>;
415
417
  readonly unmeasured: readonly unknown[];
@@ -432,6 +434,12 @@ export async function superviseRun(opts: SuperviseRunOptions): Promise<Superviso
432
434
  let history: SupervisorRound[] = [];
433
435
 
434
436
  for (;;) {
437
+ try {
438
+ const resumed = await (opts.sweepPendingMerges ?? sweepFrozenMerges)();
439
+ if (resumed.pending || resumed.merged) opts.observe?.('frozen-merges', resumed);
440
+ } catch (error) {
441
+ try { debug.log('harness.merge', 'resume-failed', { error: String(error) }); } catch { /* observation must not interrupt supervision */ }
442
+ }
435
443
  if (opts.enrich) results = [...opts.enrich(results)];
436
444
 
437
445
  let observed: {
@@ -13,7 +13,7 @@ import { posix as posixPath } from 'node:path';
13
13
  import type { LLMToolSpec } from '../llm.js';
14
14
  import type { ToolRuntime, ToolRuntimeContext } from '../tool-runtime/types.js';
15
15
  import { orchestrateSelfDev, type SelfDevJobResult, type OrchestrateSelfDevOptions, type SelfDevGoal } from './orchestrate.js';
16
- import type { SelfDevRunParticipant, SelfDevRunState } from './run-store.js';
16
+ import { processBirthId, type SelfDevRunParticipant, type SelfDevRunState } from './run-store.js';
17
17
  import { HARNESS_RUN_ID_ENV, resolveRunIdentity as defaultResolveRunIdentity } from '../harness/harness-space.js';
18
18
  import { decomposeSelfDevGoal, type SelfDevDecomposition, type SelfDevDecomposeOptions } from './decompose.js';
19
19
  import { decomposeFabricRequest, type FabricDecomposeRequestOptions, type FabricDecomposeRequestResult } from './fabric-decompose-adapter.js';
@@ -302,6 +302,7 @@ interface OrchestrateRunLedgerInput {
302
302
  readonly prior: Pick<SelfDevRunState, 'dependencies' | 'results'> | null;
303
303
  readonly goals: readonly SelfDevGoal[];
304
304
  readonly pid: number;
305
+ readonly seat?: SelfDevRunState['seat'];
305
306
  readonly runIdSource: SelfDevRunParticipant['runIdSource'];
306
307
  readonly now: () => number;
307
308
  readonly onPersistenceFailure?: (stage: 'checkpoint' | 'participant', error: unknown) => void;
@@ -421,6 +422,7 @@ export function bindOrchestrateRunLedger(
421
422
  input: OrchestrateRunLedgerInput,
422
423
  ): OrchestrateRunLedgerBinding {
423
424
  const dependencies = deps.checkpointDependencies(input.prior, input.goals);
425
+ const pidStart = processBirthId(input.pid);
424
426
  const checkpoint = (results: SelfDevRunState['results']): void => {
425
427
  try {
426
428
  deps.saveRun({
@@ -431,6 +433,8 @@ export function bindOrchestrateRunLedger(
431
433
  dependencies,
432
434
  goals: [...input.goals],
433
435
  pid: input.pid,
436
+ ...(pidStart ? { pidStart } : {}),
437
+ ...(input.seat ? { seat: input.seat } : {}),
434
438
  });
435
439
  } catch (error) {
436
440
  if (input.onPersistenceFailure) input.onPersistenceFailure('checkpoint', error);
@@ -3,8 +3,10 @@
3
3
 
4
4
  import type { RotationCandidate } from '../oauth/codex-account-rotation.js';
5
5
  import { inspectCodexRotation } from '../oauth/codex-account-store.js';
6
+ import { codexPolicyAllowsCredits } from '../oauth/codex-quota-policy.js';
6
7
  import { getUsageStore } from '../budget/usage-store.js';
7
8
  import type { UsageSnapshot } from '../budget/types.js';
9
+ import { debug } from '../debug/log.js';
8
10
  import {
9
11
  DEFAULT_BUDGET_GATE_MAX_USED_PERCENT,
10
12
  type BudgetGateMaxUsedPercent,
@@ -25,6 +27,9 @@ export interface BudgetCodexCandidate {
25
27
  readonly name: string;
26
28
  readonly reached?: boolean;
27
29
  readonly usedPercent?: number;
30
+ /** 선불 크레딧 잔액(계정에 귀속된 신호만). 모르면 비운다. */
31
+ readonly creditBalance?: number;
32
+ readonly hasCredits?: boolean;
28
33
  }
29
34
 
30
35
  export interface DecideBudgetInput {
@@ -36,6 +41,8 @@ export interface DecideBudgetInput {
36
41
  /** 주간 사용률. `undefined` 는 «모름» — 쓸 수 있다고 보지 않는다. */
37
42
  readonly grokUsedPercent: number | undefined;
38
43
  readonly maxUsedPercent: BudgetGateMaxUsedPercent;
44
+ /** codex 한도 정책이 credits 인가(`codexPolicyAllowsCredits` · 회전·Pod 배분과 같은 해석). 없으면 false. */
45
+ readonly codexCreditsAllowed?: boolean;
39
46
  }
40
47
 
41
48
  export interface BudgetDecision {
@@ -50,6 +57,7 @@ export interface BudgetInputs {
50
57
  readonly codexCandidates: readonly BudgetCodexCandidate[];
51
58
  readonly grokUsedPercent: number | undefined;
52
59
  readonly maxUsedPercent: BudgetGateMaxUsedPercent;
60
+ readonly codexCreditsAllowed?: boolean;
53
61
  }
54
62
 
55
63
  const WEEKLY_WINDOW_MINUTES = 7 * 24 * 60;
@@ -98,6 +106,16 @@ function codexCandidateUsable(candidate: BudgetCodexCandidate, cap: number | und
98
106
  return candidate.usedPercent < cap;
99
107
  }
100
108
 
109
+ /** BUDGET-GATE(10-05) — 정책이 credits 면 구독 % 가 차도 크레딧 잔액이 «확인된» 계정으로 계속 간다(Pod 배분과 같은 결론).
110
+ * 잔액을 모르면 쓰지 않는다 — 크레딧은 돈이라 fail-closed. 잔액이 가장 큰 계정 하나를 돌려준다. */
111
+ function codexCreditCandidate(input: DecideBudgetInput): BudgetCodexCandidate | undefined {
112
+ if (input.codexCreditsAllowed !== true) return undefined;
113
+ return input.codexCandidates
114
+ .filter((candidate) => candidate.hasCredits !== false
115
+ && typeof candidate.creditBalance === 'number' && Number.isFinite(candidate.creditBalance) && candidate.creditBalance > 0)
116
+ .sort((a, b) => (b.creditBalance! - a.creditBalance!) || (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))[0];
117
+ }
118
+
101
119
  function slotUsable(
102
120
  provider: string,
103
121
  input: DecideBudgetInput,
@@ -106,6 +124,13 @@ function slotUsable(
106
124
  if (provider === CODEX_PROVIDER) {
107
125
  const cap = capFor(input.maxUsedPercent, CODEX_PROVIDER);
108
126
  const measuredUsable = input.codexCandidates.some((candidate) => codexCandidateUsable(candidate, cap));
127
+ const credit = measuredUsable ? undefined : codexCreditCandidate(input);
128
+ if (credit) {
129
+ try {
130
+ debug.log('budget.gate', 'credits-allowed', { used: credit.usedPercent ?? null, balance: credit.creditBalance, policy: 'credits' });
131
+ } catch { /* observation is fail-soft */ }
132
+ return { usable: true, reason: `${formatCodexReason(input.codexCandidates, cap)} · credits allowed (balance ${credit.creditBalance})` };
133
+ }
109
134
  const unmeasured = allowUnmeasured && !measuredUsable && (input.codexCandidates.length === 0
110
135
  || input.codexCandidates.some((candidate) => candidate.reached !== true
111
136
  && (typeof candidate.usedPercent !== 'number' || !Number.isFinite(candidate.usedPercent))));
@@ -188,6 +213,8 @@ export function codexCandidatesFromRotation(
188
213
  name: candidate.name,
189
214
  ...(candidate.reached !== undefined ? { reached: candidate.reached } : {}),
190
215
  ...(candidate.usedPercent !== undefined ? { usedPercent: candidate.usedPercent } : {}),
216
+ ...(candidate.creditBalance !== undefined ? { creditBalance: candidate.creditBalance } : {}),
217
+ ...(candidate.hasCredits !== undefined ? { hasCredits: candidate.hasCredits } : {}),
191
218
  }));
192
219
  }
193
220
 
@@ -212,6 +239,8 @@ export function readBudgetInputs(deps: ReadBudgetInputsDeps = {}): BudgetInputs
212
239
  codexCandidates: codexCandidatesFromRotation(rotation.candidates),
213
240
  grokUsedPercent: grokWeeklyUsedPercent(snapshot),
214
241
  maxUsedPercent,
242
+ // 회전·Pod 배분과 같은 해석(`resolveCodexQuotaPolicy` → `codexPolicyAllowsCredits`)을 읽는다 — 다시 짓지 않는다.
243
+ ...(rotation.policy && codexPolicyAllowsCredits(rotation.policy.policy) ? { codexCreditsAllowed: true } : {}),
215
244
  };
216
245
  }
217
246
 
@@ -0,0 +1,47 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { debug } from '../debug/log.js';
3
+
4
+ type ExposeMode = 'warn' | 'strict';
5
+ type ProcessResult = { status: number | null; stdout?: string; stderr?: string; error?: Error };
6
+ type ExposeResult = { passed: boolean; log: string };
7
+
8
+ /** The rubric only accepts root-level public Markdown documents. */
9
+ export function publicExposureFiles(changed: readonly string[]): string[] {
10
+ return [...new Set(changed.filter((file) => /^release\/public\/docs\/[^/]+\.md$/.test(file)))];
11
+ }
12
+
13
+ export function runExposeGate(
14
+ cwd: string,
15
+ changed: readonly string[],
16
+ mode: ExposeMode,
17
+ run: (command: string, args: string[], cwd: string) => ProcessResult = (command, args, dir) => {
18
+ const result = spawnSync(command, args, { cwd: dir, encoding: 'utf8', timeout: 300_000 });
19
+ return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '', error: result.error };
20
+ },
21
+ ): ExposeResult {
22
+ const files = publicExposureFiles(changed);
23
+ if (files.length === 0) return { passed: true, log: '' };
24
+ let unreviewed: number | null = null;
25
+ let failed: number | null = null;
26
+ let docs: number | null = null;
27
+ let error = '';
28
+ try {
29
+ const result = run('bun', ['scripts/expose-rubric-check.ts', '--json', '--files', ...files], cwd);
30
+ if (result.status !== 0 || result.error) throw new Error(result.stderr?.trim() || result.error?.message || `exit ${result.status}`);
31
+ const parsed = JSON.parse(result.stdout ?? '') as Record<string, unknown>;
32
+ const lists = ['missing', 'orphan', 'failing', 'internal', 'unreviewed', 'unjudged'] as const;
33
+ if (!Number.isSafeInteger(parsed.docs) || (parsed.docs as number) < 0 || !lists.every((key) => Array.isArray(parsed[key]))) {
34
+ throw new Error('invalid exposure rubric JSON');
35
+ }
36
+ docs = parsed.docs as number;
37
+ unreviewed = new Set([...(parsed.missing as string[]), ...(parsed.unjudged as string[])]).size;
38
+ failed = new Set([...(parsed.orphan as string[]), ...(parsed.failing as Array<{ path: string }>).map((item) => item.path), ...(parsed.internal as string[])]).size;
39
+ } catch (cause) {
40
+ error = cause instanceof Error ? cause.message : String(cause);
41
+ }
42
+ try { debug.log('self-implement.gate', 'expose', { files, unreviewed, failed, mode }); } catch { /* observation must not change judgment */ }
43
+ const log = docs === null
44
+ ? `[expose] 못 쟀다 — ${error}`
45
+ : `[expose] ${files.length}개 · 미판정 ${unreviewed} · fail ${failed}`;
46
+ return { passed: mode === 'warn' || (docs !== null && unreviewed === 0 && failed === 0), log };
47
+ }