elanous 0.2.19 → 0.2.21

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 (509) 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/MObU8ujkMciAKr6ljAV05/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/088d8e8a.8069543d082bec12.js +160 -0
  5. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +148 -0
  6. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/119fc678.6f591cdb84ca5791.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +309 -0
  9. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 1268.0840ff91e083fcbd.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +122 -0
  12. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +149 -0
  13. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +79 -0
  14. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +24 -0
  16. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +27 -0
  21. package/apps/pwa/out/_next/static/chunks/1948.5f35b39eef222a94.js +5 -0
  22. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{2977-e38442e86289f1d3.js → 211-9c9090c59e2c5907.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +36 -0
  31. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +286 -0
  32. package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +94 -0
  45. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/3522-1de1319d028ac89c.js +25 -0
  49. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +74 -0
  54. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +34 -0
  59. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +115 -0
  61. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/4588.ad3364cb7fb97ada.js +86 -0
  63. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +77 -0
  66. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +90 -0
  70. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/{4847.56f5bc454fbcc827.js → 6110.1297d4093fdfbb0d.js} +2 -2
  76. package/apps/pwa/out/_next/static/chunks/6158.566c890adc06a459.js +2 -0
  77. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +64 -0
  78. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +287 -0
  80. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +226 -0
  81. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6767.8e6c5f6e744fcd9f.js +38 -0
  83. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7175-350f4ce2873bc038.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +41 -0
  91. package/apps/pwa/out/_next/static/chunks/{1470.98a6ab61ccb4131c.js → 726.83532d69452ee24b.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 7327-2d69fb321ba73389.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +24 -0
  95. package/apps/pwa/out/_next/static/chunks/7630.2b9a68659053ff4e.js +193 -0
  96. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/7899.597af4a9996c907f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/79b78388.663188133449d707.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8194.484f51e273d9abd2.js +217 -0
  105. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +104 -0
  109. package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/88729267.9c6c000157c83f2f.js +62 -0
  111. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +93 -0
  113. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{7647.2fcd30d894d5ee30.js → 935.4ddaa99fc1d1126c.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +23 -0
  118. package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +62 -0
  120. package/apps/pwa/out/_next/static/chunks/9832.2ab2e818013574c7.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/a9f2b54d-40c16bd0efdb04b8.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-111cabe4d1fd69ae.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/{page-b70cd005d9169e25.js → page-be8b4615c919e36c.js} +1 -1
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/d70879db.c66c56a95a91efc6.js +66 -0
  174. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → f6231284-45726550aba08fca.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{2ea96958.e8c7e112de50b067.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/f8626309.a4e5d362b1d55e59.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +1 -0
  183. package/apps/pwa/out/_next/static/css/{d3427996da11e480.css → b9d8151e48998417.css} +1 -1
  184. package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +24 -24
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +23 -23
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -0
  223. package/apps/pwa/out/live-run/index.txt +35 -0
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/graphs/demo/editor-recipes.yaml +22 -0
  279. package/graphs/drafts/recipes.yaml +4 -4
  280. package/graphs/implement-loop.yaml +277 -5
  281. package/graphs/retro/daily.yaml +25 -0
  282. package/graphs/retro/recipes.yaml +24 -0
  283. package/package.json +1 -1
  284. package/scripts/ask-marker-check.ts +3 -1
  285. package/scripts/coord-channel-watch.sh +31 -4
  286. package/scripts/docs-lint.ts +4 -1
  287. package/scripts/land-global-checks.ts +89 -0
  288. package/scripts/lib/pch-regress-map.ts +2 -1
  289. package/scripts/marketing/generate-ax-brief.ts +18 -1
  290. package/scripts/measure-nl-routing-corpus.ts +11 -3
  291. package/scripts/release-loop/gate-node.ts +296 -25
  292. package/scripts/release-loop/gate-timing.ts +116 -7
  293. package/scripts/release-loop/preflight.ts +6 -4
  294. package/scripts/release-loop/publish-window.ts +141 -0
  295. package/scripts/release-loop/release-docs.ts +1 -4
  296. package/scripts/release-loop/release-universe.ts +38 -0
  297. package/scripts/release-loop/resume-release.ts +4 -1
  298. package/scripts/release-loop/shard-plan.ts +50 -5
  299. package/scripts/release-loop/unattended-release.ts +10 -2
  300. package/scripts/release-story/draft.ts +5 -1
  301. package/scripts/retro/shadow-compare.ts +71 -0
  302. package/scripts/rhythm/daily.ts +8 -2
  303. package/src/agent-mission/driver.ts +34 -6
  304. package/src/autopilot/build/llm-conflict-merge.ts +132 -7
  305. package/src/autopilot/build/merge-intent.ts +135 -7
  306. package/src/away/release-watch.ts +20 -3
  307. package/src/browser-cdp/client.ts +10 -5
  308. package/src/cli/config-drift.ts +513 -0
  309. package/src/cli/log-event-names.ts +4 -0
  310. package/src/cli/ops-cli.ts +11 -0
  311. package/src/cli/ops-overview-cli.ts +50 -0
  312. package/src/cli/pod-cli.ts +1 -0
  313. package/src/cli/pr-cli.ts +20 -0
  314. package/src/cli/release-cli.ts +20 -5
  315. package/src/cli/retro-cli.ts +78 -0
  316. package/src/cli/tasks-cli.ts +200 -8
  317. package/src/dashboard/index.ts +40 -4
  318. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -4
  319. package/src/dashboard/slash-runtime/help-from-registry.ts +57 -31
  320. package/src/domains/outbound-log-probe.ts +6 -1
  321. package/src/esc-abort-gate.ts +3 -1
  322. package/src/graph-runner/graph-cli.ts +57 -0
  323. package/src/graph-runner/graph-run-api.ts +218 -0
  324. package/src/graph-runner/runner.ts +11 -1
  325. package/src/graph-wizard/archetypes.ts +88 -0
  326. package/src/graph-wizard/generate.ts +545 -0
  327. package/src/graph-wizard/saved-steps.ts +120 -0
  328. package/src/graph-wizard/steps.ts +193 -0
  329. package/src/harness/harness-cli-command.ts +482 -59
  330. package/src/harness/harness-queue.ts +315 -25
  331. package/src/harness/harness-salvage-cli.ts +62 -0
  332. package/src/hq/fence-outcomes.ts +63 -0
  333. package/src/hq/fence-wrapper.ts +33 -0
  334. package/src/hq/hq.ts +11 -1
  335. package/src/index.ts +76 -10
  336. package/src/intake-plane/digest.ts +18 -11
  337. package/src/maturity/feature-maturity.ts +4 -3
  338. package/src/nexus/api/draft-metrics.ts +114 -0
  339. package/src/nexus/api/graph-kinds.ts +10 -4
  340. package/src/nexus/api/graph-wizard-api.ts +53 -0
  341. package/src/nexus/api/graphs-api.ts +220 -10
  342. package/src/nexus/api/harness-traversal.ts +205 -0
  343. package/src/nexus/api/http-server.ts +69 -3
  344. package/src/nexus/api/loop-edges.ts +4 -2
  345. package/src/nexus/api/ops-api.ts +22 -7
  346. package/src/nexus/api/ops-board-route.ts +48 -0
  347. package/src/nexus/outbound/router.ts +28 -8
  348. package/src/onboarding/entry-hints.ts +5 -0
  349. package/src/onboarding/first-run.ts +3 -0
  350. package/src/onboarding.ts +24 -6
  351. package/src/ops/overview-collect.ts +345 -0
  352. package/src/ops/overview-seat-era.ts +90 -0
  353. package/src/ops/overview.ts +223 -0
  354. package/src/release-loop/feature-store.ts +14 -11
  355. package/src/release-loop/gate-shards.ts +163 -0
  356. package/src/release-loop/release-schedule.ts +6 -2
  357. package/src/retro/daily.ts +372 -0
  358. package/src/seat-loop/op-decide.ts +173 -0
  359. package/src/seat-loop/seat-loop.ts +60 -3
  360. package/src/seat-loop/seat-report.ts +58 -3
  361. package/src/self-dev/ask-launch-flow.ts +9 -6
  362. package/src/self-dev/ask-launch-io.ts +52 -2
  363. package/src/self-dev/ask-path-candidates.ts +40 -2
  364. package/src/self-dev/draft-sweep.ts +371 -16
  365. package/src/self-dev/draft-triage-rules.ts +19 -4
  366. package/src/self-dev/graph-journey-nodes.ts +157 -0
  367. package/src/self-dev/graph-journey-route.ts +105 -0
  368. package/src/self-dev/launch-preflight.ts +43 -3
  369. package/src/self-dev/pr-preview.ts +84 -16
  370. package/src/self-dev/release-path-guard.ts +7 -4
  371. package/src/self-implement/blocked-draft-policy.ts +101 -0
  372. package/src/self-implement/execution-clarification.ts +11 -0
  373. package/src/self-implement/frozen-merges.ts +23 -0
  374. package/src/self-implement/gate-env-retry.ts +83 -0
  375. package/src/self-implement/goal-author.ts +14 -0
  376. package/src/self-implement/heal-intake.ts +3 -0
  377. package/src/self-implement/orchestrator.ts +234 -6
  378. package/src/self-implement/run-stop.ts +123 -0
  379. package/src/self-implement/run-ttl.ts +258 -0
  380. package/src/self-implement/salvage-retention.ts +123 -0
  381. package/src/self-implement/seams.ts +7 -0
  382. package/src/self-implement/self-implement-cli.ts +2 -0
  383. package/src/self-implement/self-implement-runtime.ts +12 -0
  384. package/src/self-implement/sibling-resync.ts +223 -0
  385. package/src/self-implement/stop-autoheal.ts +204 -0
  386. package/src/session-runtime/index.ts +5 -3
  387. package/src/shell-env-bootstrap.ts +17 -3
  388. package/src/task-agent/board.ts +1 -1
  389. package/src/task-agent/card-evidence.ts +105 -10
  390. package/src/task-agent/judge.ts +7 -0
  391. package/src/task-agent/live-moves.ts +120 -20
  392. package/src/task-agent/mission.ts +1 -1
  393. package/src/task-agent/parent-host.ts +315 -0
  394. package/src/task-agent/shadow.ts +10 -1
  395. package/src/task-agent/task-hand.ts +16 -4
  396. package/src/task-orchestrator/surfaces/pod-command-job.ts +60 -11
  397. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +4 -0
  398. package/src/task-orchestrator/surfaces/pod-gate-deps.ts +123 -0
  399. package/src/task-orchestrator/surfaces/pod-install-slots.ts +89 -0
  400. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -10
  401. package/src/task-orchestrator/surfaces/pod-pool.ts +147 -34
  402. package/src/task-orchestrator/surfaces/self-implement-pod.ts +58 -9
  403. package/src/telegram-commands.ts +41 -0
  404. package/src/testing/real-cli-spawn.ts +106 -0
  405. package/src/tool-runtime/browser-runtime.ts +87 -3
  406. package/src/tool-runtime/index.ts +1 -0
  407. package/src/user-config.ts +76 -7
  408. package/src/version/packed-revision.json +1 -1
  409. package/apps/pwa/out/_next/static/J5H7BvqgSI8DUjtRRcA_S/_buildManifest.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/1157-cba0e8553d35a980.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/171-23a877ed11720de9.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/2336-e830c777eb6bce04.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/2375-e061bb24cd2b5cde.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/3094.67339318c7f72a3a.js +0 -2
  419. package/apps/pwa/out/_next/static/chunks/338-ceb956612dcfaa86.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/3395-835e4ceaa6335ba4.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  422. package/apps/pwa/out/_next/static/chunks/3441-be82e3595aef3a20.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/3689-89905039bf3e7257.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/3822-6f268bc26c6a84ac.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/4457-d7df81c90f9d0268.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/4551-77dadae76f6cbace.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/4978.6fd93b974441e87f.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/5012-f746f6549b869f91.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/62-5bfed1e23790b745.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/6320-9bc8561fde416e07.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/649-ca96d1c5d09e02b8.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/6726-85a7db59b288c53f.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/6735-33267c4630d0d963.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/7633-141682015873beb6.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/8067-143791231c99bd02.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/8430-a10cfba8ef282d4e.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/8870-9614a213b990b10b.js +0 -25
  447. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/9454-12c2f30dea62291c.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/976-4a9b4ebdca7c739a.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/9989-15cdf568bafa9fc8.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/ae787e4c-e5b1ef00b2dbceca.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/app/approvals/page-deef5ee191830f14.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-b193da485f9a14b2.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/app/board/page-b6e1a79df0e214f4.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/app/botlab/page-e84df4d907f703c7.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/app/bots/page-a5fb9a5db89ae4ea.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/app/ceo/page-1499f481d7fc52d6.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/app/chat/page-c7cf753aeb648790.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/app/consult/page-4118469e514e10fd.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/app/control/page-e968f7630654332a.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/app/decisions/page-505915052f947022.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c2f962fb4a3b06c6.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/app/editor/page-7b5ed0bd8a589ec4.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/app/exec/page-cf8193250dd42dd4.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/app/field/page-cf3f5dfa35dea8e9.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/app/inside/page-5b29d9b06ceadade.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/app/intake/page-a15e7fcc283e9ca7.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/app/layout-d2915e7b70ff3d0e.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/loops/page-2595f0eba29f57e1.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/app/market/page-c776322454156e36.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-77bbd17f4435aa10.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/app/morning/page-049689e611ecc936.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/app/not-found-85954a4fb09c44eb.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e773e552e1068ee6.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5633c4bfa7684b4a.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d829b92bd01b4994.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-061c317fc771becf.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a45ece8865ed4b6.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/app/page-0be990618c0d56bd.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/app/reflection/page-bfea4865dc244b73.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d6ba8e337741484.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/app/sessions/page-76a88b55d816482e.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-bba1542df59f61ce.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/app/settings/page-4185c95689bb372e.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b699e1a8d5d34b8b.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/app/setup/page-c225e338c31bf274.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/app/share/page-449353f70507ca1f.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/app/showroom/page-90b889714102476d.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f1ee7fbeb7f96ddc.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/app/term/page-d59a95e1434dfaa0.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/app/today/page-71491a23414d1a47.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/app/trace/page-de7112bdb65fa4fe.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/app/vault/page-feb4d0d88079660d.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f17d887b40dd6b1d.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/workflows/page-8da77be2192bcd5d.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72c3b9a5e9582b29.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3afe4c8d0c48c39.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/main-app-b9308f2d8a931531.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/webpack-6f35f9d892fa630b.js +0 -1
  507. package/apps/pwa/out/_next/static/css/85f53c6f35d11382.css +0 -1
  508. /package/apps/pwa/out/_next/static/{J5H7BvqgSI8DUjtRRcA_S → MObU8ujkMciAKr6ljAV05}/_ssgManifest.js +0 -0
  509. /package/skills/project-onboarding/{skill.md → SKILL.md} +0 -0
@@ -43,11 +43,15 @@ export function buildEssentialHelpLines({
43
43
  descriptions,
44
44
  width,
45
45
  audience = readTuiSlashAudience(),
46
+ maxRows,
46
47
  }: {
47
48
  names: readonly string[];
48
49
  descriptions: readonly Pick<SlashCommand, 'name' | 'aliases' | 'description'>[];
49
50
  width: number;
50
51
  audience?: { role: Role; showBeta: boolean };
52
+ /** The modal's row budget. When the readable layout overflows it, add columns (shorter descriptions)
53
+ * before the caller has to fall back to the chat log — TUI-HELP-OVERLAY (0.2.19 tui node «help-closes»). */
54
+ maxRows?: number;
51
55
  }): string[] {
52
56
  const registered = new Set(names);
53
57
  const entries = descriptions
@@ -67,41 +71,63 @@ export function buildEssentialHelpLines({
67
71
  // in each cell. Never trade a missing label for a shorter modal.
68
72
  const widestLabel = Math.max(0, ...entries.map(({ label }) => visibleWidth(label)));
69
73
  const readableCellWidth = widestLabel + 2 + 28 + 1;
70
- const columns = entries.length >= 40 && width >= 100
74
+ const baseColumns = entries.length >= 40 && width >= 100
71
75
  ? Math.max(1, Math.floor(width / (readableCellWidth + 1)))
72
76
  : 1;
73
- const columnWidth = Math.floor(width / columns);
74
- // Task order (TUI-SLASH-DECIDE-NOW C): group head line, then that group's commands by name.
75
- // Empty groups print no head; unmapped commands land in «그 밖», so none disappears.
76
- const commandLines: string[] = [];
77
- for (const group of HELP_GROUP_ORDER) {
78
- const members = entries.filter(({ name }) => helpGroupFor(name) === group);
79
- if (members.length === 0) continue;
80
- commandLines.push(fitLine(helpGroupHeading(group), width));
81
- for (let start = 0; start < members.length; start += columns) {
82
- const cells = members.slice(start, start + columns).map(({ label, description }) => {
83
- const cellWidth = columnWidth - (columns > 1 ? 1 : 0);
84
- return visibleWidth(`${label} `) > cellWidth ? '' : fitLine(`${label} ${description}`, cellWidth);
85
- });
86
- commandLines.push(cells.map((cell, index) =>
87
- index === cells.length - 1 ? cell : cell + ' '.repeat(columnWidth - visibleWidth(cell)),
88
- ).join('').trimEnd());
89
- }
77
+ // Narrowest cell that still shows the whole label and a few description characters.
78
+ const minCellWidth = widestLabel + 2 + 10 + 1;
79
+ let lines = layout(baseColumns);
80
+ for (let columns = baseColumns + 1; maxRows !== undefined && lines.length > maxRows
81
+ && Math.floor(width / columns) - 1 >= minCellWidth; columns++) {
82
+ lines = layout(columns);
90
83
  }
91
- const keyItems = ESSENTIAL_KEYS.map(([key, description]) => `${key} ${description}`);
92
- const keyLines: string[] = [];
93
- if (entries.length >= 40 && width >= 100) {
94
- let keyRow = '';
95
- for (const item of keyItems) {
96
- if (keyRow && visibleWidth(keyRow) + 2 + visibleWidth(item) > width) {
97
- keyLines.push(keyRow);
98
- keyRow = '';
84
+ return lines;
85
+
86
+ function layout(columns: number): string[] {
87
+ const columnWidth = Math.floor(width / columns);
88
+ // Task order (TUI-SLASH-DECIDE-NOW C): group head line, then that group's commands by name.
89
+ // Empty groups print no head; unmapped commands land in «그 밖», so none disappears.
90
+ const commandLines: string[] = [];
91
+ const cellWidth = columnWidth - (columns > 1 ? 1 : 0);
92
+ const cellOf = ({ label, description }: { label: string; description: string }) =>
93
+ visibleWidth(`${label} `) > cellWidth ? '' : fitLine(`${label} ${description}`, cellWidth);
94
+ const pushRow = (cells: string[]) => commandLines.push(cells.map((cell, index) =>
95
+ index === cells.length - 1 ? cell : cell + ' '.repeat(columnWidth - visibleWidth(cell)),
96
+ ).join('').trimEnd());
97
+ if (columns > 1) {
98
+ // TUI-HELP-OVERLAY · 2026-10-07 — in columns the group head is a cell and groups flow on: a head line plus a
99
+ // half-empty last row per group pushed the catalog past the modal's rows, so /help fell back to the chat log
100
+ // and Esc no longer closed it (0.2.19 release tui node «help-closes»).
101
+ const cells: string[] = [];
102
+ for (const group of HELP_GROUP_ORDER) {
103
+ const members = entries.filter(({ name }) => helpGroupFor(name) === group);
104
+ if (members.length === 0) continue;
105
+ cells.push(fitLine(helpGroupHeading(group), cellWidth), ...members.map(cellOf));
106
+ }
107
+ for (let start = 0; start < cells.length; start += columns) pushRow(cells.slice(start, start + columns));
108
+ } else {
109
+ for (const group of HELP_GROUP_ORDER) {
110
+ const members = entries.filter(({ name }) => helpGroupFor(name) === group);
111
+ if (members.length === 0) continue;
112
+ commandLines.push(fitLine(helpGroupHeading(group), width));
113
+ for (const member of members) pushRow([cellOf(member)]);
114
+ }
115
+ }
116
+ const keyItems = ESSENTIAL_KEYS.map(([key, description]) => `${key} ${description}`);
117
+ const keyLines: string[] = [];
118
+ if (entries.length >= 40 && width >= 100) {
119
+ let keyRow = '';
120
+ for (const item of keyItems) {
121
+ if (keyRow && visibleWidth(keyRow) + 2 + visibleWidth(item) > width) {
122
+ keyLines.push(keyRow);
123
+ keyRow = '';
124
+ }
125
+ keyRow += (keyRow ? ' ' : '') + fitLine(item, width);
99
126
  }
100
- keyRow += (keyRow ? ' ' : '') + fitLine(item, width);
127
+ if (keyRow) keyLines.push(keyRow);
128
+ } else {
129
+ keyLines.push(...keyItems.map((item) => fitLine(item, width)));
101
130
  }
102
- if (keyRow) keyLines.push(keyRow);
103
- } else {
104
- keyLines.push(...keyItems.map((item) => fitLine(item, width)));
131
+ return [fitLine('Commands', width), ...commandLines, '', fitLine('Keys', width), ...keyLines];
105
132
  }
106
- return [fitLine('Commands', width), ...commandLines, '', fitLine('Keys', width), ...keyLines];
107
133
  }
@@ -2,7 +2,12 @@ import { inQuietHours, kstMinutes, sendOutbound, setInProcessOutbound } from './
2
2
  import { setUserConfigOverlay } from '../user-config.js';
3
3
 
4
4
  // Focused subprocess fixture: isolated state/config roots and a fake curl on PATH.
5
- setUserConfigOverlay(cfg => ({ ...cfg, telegram: { ...cfg.telegram, botToken: '123456:private-secret', homeChannel: 98765 } }));
5
+ // Hermetic: the shared `.elanous-test` config may carry a routing table another test left behind (a declared
6
+ // `channels` table is authoritative and never falls back to the main home), so the fixture owns every routing key.
7
+ setUserConfigOverlay(cfg => ({ ...cfg, telegram: {
8
+ ...cfg.telegram, channels: undefined, reportChannel: undefined, testChannel: undefined,
9
+ botToken: '123456:private-secret', homeChannel: 98765,
10
+ } }));
6
11
  process.env.SEND_VIA_ELANOUS = '0';
7
12
  // Quiet hours (00:00~06:30 KST) defer instead of sending, so a gate run at night saw no `sent` row.
8
13
  // Shift this fixture's clock back to 23:59 KST of the previous day; the shift stays inside this process.
@@ -55,6 +55,8 @@ export interface EscAbortGateDeps {
55
55
  getTheme?: () => ThemeTokens | null | undefined;
56
56
  /** Names shown/logged while a turn abort request is waiting for running work to unwind. */
57
57
  getWaitingTargetNames?: () => readonly string[];
58
+ /** Only an identified foreground harness run may bypass the sub-agent confirmation. */
59
+ shouldAbortImmediately?: () => boolean;
58
60
  /** Called before abortTurnOnly so the UI can paint a visible pending state immediately. */
59
61
  onAbortPending?: (event: { running: number; repeat: number; targets: readonly string[] }) => void;
60
62
  /** Called when another Escape arrives after the first abort request. */
@@ -211,7 +213,7 @@ export function createEscAbortGate(deps: EscAbortGateDeps): EscAbortGate {
211
213
  return;
212
214
  }
213
215
  const running = deps.getRunningCount();
214
- if (running <= 0) {
216
+ if (running <= 0 || deps.shouldAbortImmediately?.()) {
215
217
  debug.log('esc.abort', 'abort-immediately', { running, repeat: Math.max(0, escapePresses - 1) });
216
218
  abortPendingTurn(running);
217
219
  return;
@@ -94,6 +94,63 @@ export function registerGraphCommands(program: Command, runsDeps: { root?: strin
94
94
  process.exitCode = 1;
95
95
  }
96
96
  });
97
+ graph.command('wizard <prompt>')
98
+ .description('말 한 줄로 그래프 YAML 을 짓고 같은 검증기 ⊕ graph run --dry-run 으로 확인한다(저장하지 않는다) — --from 이면 그 그래프를 고친다')
99
+ .option('--kind <kind>', 'harness | workflow', 'harness')
100
+ .option('--from <file>', '고칠 그래프 YAML (편집 경로)')
101
+ .option('--out <file>', 'YAML 을 이 파일에 쓰고, 하니스면 같은 폴더에 recipes.yaml 도 쓴다(있으면 덮지 않는다)')
102
+ .option('--json', '결과를 JSON 으로')
103
+ .option('--run', '생성된 그래프의 dry-run 경로를 보여 준다(--dry-run 과 함께만)')
104
+ .option('--dry-run', '--run 과 함께: 명령을 실행하지 않고 경로만 걷는다')
105
+ .action(async (prompt: string, opts: { kind: string; from?: string; out?: string; json?: boolean; run?: boolean; dryRun?: boolean }) => {
106
+ try {
107
+ if (opts.kind !== 'harness' && opts.kind !== 'workflow') throw new Error('--kind must be harness or workflow');
108
+ if (opts.run && !opts.dryRun) throw new Error('--run is only supported with --dry-run (run the saved graph with `elanous graph run <file>`)');
109
+ if (opts.run && opts.kind !== 'harness') throw new Error('--run --dry-run walks harness graphs only');
110
+ await (await import('../domains/standalone-log-sink.js')).registerStandaloneLogSink('graph');
111
+ const { generateGraphFromPrompt } = await import('../graph-wizard/generate.js');
112
+ const currentYaml = opts.from ? readFileSync(opts.from, 'utf8') : undefined;
113
+ const started = Date.now();
114
+ const result = await generateGraphFromPrompt({ prompt, kind: opts.kind, ...(currentYaml ? { currentYaml } : {}) });
115
+ const ms = Date.now() - started;
116
+ let recipesNote: string | undefined;
117
+ if (opts.out) {
118
+ const { writeFileSync } = await import('node:fs');
119
+ const { dirname } = await import('node:path');
120
+ writeFileSync(opts.out, result.yaml);
121
+ if (result.recipes) {
122
+ const recipesPath = join(dirname(resolve(opts.out)), 'recipes.yaml');
123
+ if (existsSync(recipesPath) && readFileSync(recipesPath, 'utf8') !== result.recipes) recipesNote = `recipes.yaml 이 이미 있어 덮지 않았다: ${recipesPath}`;
124
+ else { writeFileSync(recipesPath, result.recipes); recipesNote = `recipes ${recipesPath}`; }
125
+ }
126
+ }
127
+ if (opts.json) {
128
+ await writeStdoutJson(JSON.stringify({ ...result, ms, ...(recipesNote ? { recipesNote } : {}) }) + '\n');
129
+ } else {
130
+ if (!opts.out) process.stdout.write(result.yaml);
131
+ console.log(`# ${result.ok ? 'ok' : 'invalid'} · id ${result.id} · base ${result.base ?? '-'} · attempts ${result.attempts} · ${(ms / 1000).toFixed(1)}s${opts.out ? ` · saved ${opts.out}` : ''}`);
132
+ console.log(`# ${result.summary}`);
133
+ if (recipesNote) console.log(`# ${recipesNote}`);
134
+ for (const issue of result.issues) console.log(`# issue: ${issue}`);
135
+ if (result.dryRun && (opts.run || !result.ok)) console.log(`# dry-run ${result.dryRun.status}: ${result.dryRun.path.join(' → ')}`);
136
+ }
137
+ if (!result.ok) process.exitCode = 1;
138
+ } catch (error) {
139
+ console.error(`graph wizard: ${error instanceof Error ? error.message : String(error)}`);
140
+ process.exitCode = 1;
141
+ }
142
+ });
143
+ graph.command('step <step>')
144
+ .description('그래프 마법사 단계 하나를 실행한다(graph run 의 cmd 노드가 부른다 · 마지막 줄 JSON {outcome})')
145
+ .option('--arg <text>', '단계 인자')
146
+ .option('--retries <n>', '실패하면 이 횟수만큼 다시 시도', '0')
147
+ .action(async (step: string, opts: { arg?: string; retries: string }) => {
148
+ const { runWizardStepWithRetries } = await import('../graph-wizard/steps.js');
149
+ const result = runWizardStepWithRetries(step, opts.arg, Number.parseInt(opts.retries, 10) || 0);
150
+ if (result.error) console.error(result.error);
151
+ console.log(JSON.stringify({ outcome: result.outcome, tries: result.tries, ...(result.text ? { text: result.text.slice(0, 20_000) } : {}), ...(result.error ? { error: result.error } : {}) }));
152
+ if (result.outcome === 'fail') process.exitCode = 1;
153
+ });
97
154
  graph.command('tick <file>')
98
155
  .description('Advance one graph run, resuming a pending decision or starting only when requested')
99
156
  .option('--start', 'Start a new run when the graph is idle')
@@ -0,0 +1,218 @@
1
+ // CGE-RUN — 편집기에서 «내 그래프»를 실행하고 노드별 상태를 읽는다.
2
+ // 실행은 `elanous graph run` 과 같은 범용 실행기(runGraph)다. 하니스(LLM) 런은 골 종류로만 그래프를 고르므로 여기서 다루지 않는다.
3
+ // 그래프와 레시피는 런마다 작업 폴더로 «복사»해서 돌린다 — 실행 중에 편집기가 파일을 바꿔도 이 런은 시작한 판으로 끝난다.
4
+ // ⛔ 레시피(실제로 도는 명령)는 «저장소»의 편집기 레시피(`graphs/demo/editor-recipes.yaml`)만 쓴다 — «mine» 폴더는 HTTP 로 쓸 수 있으므로
5
+ // 거기 레시피를 읽으면 «편집한 그래프 실행»이 «편집한 명령 실행»이 된다(TC 10-07 19:31). 그래프가 부르는 레시피가 그 목록에 없으면 시작 전에 거부한다.
6
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
7
+ import { randomBytes } from 'node:crypto';
8
+ import { join } from 'node:path';
9
+ import { parse as parseYaml } from 'yaml';
10
+ import { elanousStateRoot } from '../autopilot/state-paths.js';
11
+ import { debug } from '../debug/log.js';
12
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
13
+ import { jsonResponse } from '../nexus/api/json-response.js';
14
+ import { defaultGraphsDir } from '../self-implement/graph-templates.js';
15
+ import { runGraph, type GraphRunState } from './runner.js';
16
+ import { readWizardSteps, wizardRecipesFor } from '../graph-wizard/saved-steps.js';
17
+ import { stringify as stringifyYaml } from 'yaml';
18
+
19
+ const GRAPH_ID = /^[a-z0-9-]+$/;
20
+ const RUN_ID = /^ed-[a-z0-9]+-[a-f0-9]{6}$/;
21
+ /** 실행기가 받는 끝 노드 이름(runner.ts — `unsupported terminal node`). 미리 말해 준다. */
22
+ const RUNNABLE_TERMINALS = new Set(['done', 'failed']);
23
+
24
+ export interface GraphRunApiDeps {
25
+ mineDir?: string;
26
+ /** 편집기 실행이 쓰는 레시피 파일(저장소 것만) — 기본 `graphs/demo/editor-recipes.yaml`. */
27
+ recipesFile?: string;
28
+ root?: string;
29
+ run?: typeof runGraph;
30
+ now?: () => number;
31
+ }
32
+
33
+ /** 시작 전에 죽은 런(레시피 없음 등)은 원장 파일이 안 생긴다 — 그 이유를 여기 잠깐 들고 있다가 상태 조회에 돌려준다. */
34
+ const startFailures = new Map<string, { error: string; at: string }>();
35
+
36
+ const mineDirOf = (deps: GraphRunApiDeps) => deps.mineDir ?? join(elanousStateRoot(), 'graphs');
37
+ const rootOf = (deps: GraphRunApiDeps) => deps.root ?? effectiveInstanceRoot();
38
+
39
+ function decodeId(raw: string, pattern: RegExp): string | null {
40
+ try {
41
+ const id = decodeURIComponent(raw);
42
+ return pattern.test(id) ? id : null;
43
+ } catch { return null; }
44
+ }
45
+
46
+ /** 파일 이름이 아니라 선언된 graph_id 로 찾는다(graphs-api 와 같은 규칙). */
47
+ function findMine(dir: string, id: string): { file: string; doc: Record<string, unknown> } | null {
48
+ let names: string[];
49
+ try { names = readdirSync(dir).filter((name) => name.endsWith('.yaml') || name.endsWith('.yml')).sort(); }
50
+ catch { return null; }
51
+ for (const name of names) {
52
+ if (name === 'recipes.yaml') continue;
53
+ try {
54
+ const doc: unknown = parseYaml(readFileSync(join(dir, name), 'utf8'));
55
+ if (doc && typeof doc === 'object' && !Array.isArray(doc) && (doc as Record<string, unknown>).graph_id === id) {
56
+ return { file: join(dir, name), doc: doc as Record<string, unknown> };
57
+ }
58
+ } catch { continue; }
59
+ }
60
+ return null;
61
+ }
62
+
63
+ /** 되돌이(순환) 위의 노드가 max_visits 1 이면 두 번째 방문에서 예산 초과로 멈춘다 — 시작 전에 말한다. */
64
+ function loopVisitIssues(doc: Record<string, unknown>): string[] {
65
+ const next = new Map<string, Set<string>>();
66
+ for (const edge of Array.isArray(doc.edges) ? doc.edges : []) {
67
+ if (!edge || typeof edge !== 'object') continue;
68
+ const { from, to, map } = edge as Record<string, unknown>;
69
+ if (typeof from !== 'string') continue;
70
+ const targets = [...(typeof to === 'string' ? [to] : []),
71
+ ...(map && typeof map === 'object' ? Object.values(map as Record<string, unknown>).filter((v): v is string => typeof v === 'string') : [])];
72
+ for (const target of targets) (next.get(from) ?? next.set(from, new Set()).get(from)!).add(target);
73
+ }
74
+ const reaches = (start: string, goal: string): boolean => {
75
+ const seen = new Set<string>();
76
+ const stack = [...(next.get(start) ?? [])];
77
+ while (stack.length) {
78
+ const id = stack.pop()!;
79
+ if (id === goal) return true;
80
+ if (seen.has(id)) continue;
81
+ seen.add(id);
82
+ stack.push(...(next.get(id) ?? []));
83
+ }
84
+ return false;
85
+ };
86
+ const issues: string[] = [];
87
+ for (const node of Array.isArray(doc.nodes) ? doc.nodes : []) {
88
+ if (!node || typeof node !== 'object') continue;
89
+ const { node_id: id, max_visits: visits } = node as Record<string, unknown>;
90
+ if (typeof id === 'string' && (typeof visits !== 'number' || visits < 2) && reaches(id, id)) {
91
+ issues.push(`노드 '${id}' 는 되돌이 위에 있는데 max_visits 가 ${typeof visits === 'number' ? visits : '없음'} 이다 — 두 번째 방문에서 멈춘다 · 2 이상으로`);
92
+ }
93
+ }
94
+ return issues;
95
+ }
96
+
97
+ /** 실행기가 받지 않을 모양을 시작 «전»에 사람 말로. 빈 배열이면 돌릴 수 있다. */
98
+ export function runnableIssues(doc: Record<string, unknown>, allowedRecipes: ReadonlySet<string>): string[] {
99
+ const issues: string[] = [];
100
+ for (const node of Array.isArray(doc.nodes) ? doc.nodes : []) {
101
+ if (!node || typeof node !== 'object') continue;
102
+ const { node_id: nodeId, recipe } = node as Record<string, unknown>;
103
+ if (typeof recipe !== 'string' || recipe === 'none') continue;
104
+ if (recipe.startsWith('approval:')) { issues.push(`노드 '${String(nodeId)}' 의 승인 레시피 '${recipe}' 는 편집기 데모 실행에서 쓸 수 없다`); continue; }
105
+ const prefixed = /^cmd:(.*)$/.exec(recipe);
106
+ if (prefixed && !allowedRecipes.has(prefixed[1]!)) {
107
+ issues.push(`노드 '${String(nodeId)}' 의 레시피 '${recipe}' 는 편집기 실행 목록에 없다 — 쓸 수 있는 것: ${[...allowedRecipes].map((r) => `cmd:${r}`).join(' · ')}`);
108
+ }
109
+ }
110
+ // grow 는 매핑 안 된 결과에서 LLM 제안기를 부른다 — 데모 실행 범위 밖(하니스 LLM 런은 0.2.21).
111
+ if (doc.grow !== undefined) issues.push('grow(그래프 자라기)는 편집기 데모 실행에서 쓸 수 없다 — grow 줄을 지우고 저장하라');
112
+ issues.push(...loopVisitIssues(doc));
113
+ const terminals = Array.isArray(doc.terminal_nodes) ? doc.terminal_nodes.filter((t): t is string => typeof t === 'string') : [];
114
+ if (!terminals.length) issues.push('끝 노드가 없다 — done 노드를 잇고 끝으로 지정하라');
115
+ for (const t of terminals) if (!RUNNABLE_TERMINALS.has(t)) issues.push(`끝 노드 '${t}' 는 실행할 수 없다 — 끝 노드 이름은 done 또는 failed 여야 한다`);
116
+ return issues;
117
+ }
118
+
119
+ export interface GraphRunNodeView { nodeId: string; ok: boolean; executed: boolean; startedAt?: string; endedAt?: string; error?: string }
120
+ export interface GraphRunView {
121
+ graphId: string; runId: string; status: GraphRunState['status'] | 'starting';
122
+ startedAt?: string; finishedAt?: string; path: string[];
123
+ nodes: GraphRunNodeView[]; currentNode?: { nodeId: string; startedAt: string }; error?: string;
124
+ }
125
+
126
+ export function graphRunView(state: GraphRunState): GraphRunView {
127
+ return {
128
+ graphId: state.graphId, runId: state.runId, status: state.status,
129
+ ...(state.startedAt ? { startedAt: state.startedAt } : {}), ...(state.finishedAt ? { finishedAt: state.finishedAt } : {}),
130
+ path: state.path,
131
+ nodes: state.nodes.map((node) => ({
132
+ nodeId: node.nodeId, ok: node.ok, executed: node.executed,
133
+ ...(node.startedAt ? { startedAt: node.startedAt } : {}), ...(node.endedAt ? { endedAt: node.endedAt } : {}),
134
+ ...(node.error ? { error: node.error.slice(0, 300) } : {}),
135
+ })),
136
+ ...(state.currentNode ? { currentNode: state.currentNode } : {}),
137
+ };
138
+ }
139
+
140
+ /** POST /v1/graphs/<id>/run — 내 그래프만 실행한다(핵심 그래프는 복제해서 돌린다). 응답은 기다리지 않는다(202 ⊕ runId). */
141
+ export function handleGraphRunStart(rawId: string, deps: GraphRunApiDeps = {}): Response {
142
+ const id = decodeId(rawId, GRAPH_ID);
143
+ if (!id) return jsonResponse({ error: 'bad_request', reason: 'invalid graph id' }, 400);
144
+ const mine = findMine(mineDirOf(deps), id);
145
+ if (!mine) return jsonResponse({ error: 'not-found', id, reason: '내 그래프에만 실행이 있다 — 핵심 그래프는 복제해서 돌린다' }, 404);
146
+ const recipesFile = deps.recipesFile ?? join(defaultGraphsDir(), 'demo', 'editor-recipes.yaml');
147
+ let recipeText: string;
148
+ let allowed: Set<string>;
149
+ try {
150
+ recipeText = readFileSync(recipesFile, 'utf8');
151
+ const parsed: unknown = parseYaml(recipeText);
152
+ allowed = new Set(parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? Object.keys(parsed) : []);
153
+ // GRAPH-WIZARD-SAVE-RECIPES — a wizard graph's own steps (saved as a validated sidecar) become recipes here,
154
+ // generated by the server from the step library; they take precedence for the nodes that carry them.
155
+ const steps = readWizardSteps(mineDirOf(deps), id, readFileSync(mine.file, 'utf8'));
156
+ const generated = steps ? wizardRecipesFor(readFileSync(mine.file, 'utf8'), steps) : {};
157
+ if (Object.keys(generated).length) {
158
+ const base = parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : {};
159
+ const merged = { ...base, ...generated };
160
+ recipeText = stringifyYaml(merged);
161
+ allowed = new Set(Object.keys(merged));
162
+ debug.log('graphs.run', 'wizard-recipes', { id, nodes: Object.keys(generated) });
163
+ }
164
+ } catch {
165
+ return jsonResponse({ error: 'recipes-unavailable' }, 503);
166
+ }
167
+ const issues = runnableIssues(mine.doc, allowed);
168
+ if (issues.length) return jsonResponse({ error: 'not-runnable', id, issues }, 422);
169
+
170
+ const now = deps.now?.() ?? Date.now();
171
+ const runId = `ed-${now.toString(36)}-${randomBytes(3).toString('hex')}`;
172
+ const root = rootOf(deps);
173
+ const work = join(root, 'graph-run-work', id, runId);
174
+ try {
175
+ mkdirSync(work, { recursive: true });
176
+ copyFileSync(mine.file, join(work, 'graph.yaml'));
177
+ writeFileSync(join(work, 'recipes.yaml'), recipeText);
178
+ } catch (error) {
179
+ return jsonResponse({ error: 'run-workspace-failed', reason: error instanceof Error ? error.message.slice(0, 200) : 'unknown' }, 500);
180
+ }
181
+ debug.log('graphs.run', 'started', { id, runId });
182
+ void (deps.run ?? runGraph)(join(work, 'graph.yaml'), { runId, input: { source: 'editor' }, deps: { root } })
183
+ .then((state) => debug.log('graphs.run', 'finished', { id, runId, status: state.status, executed: state.executed }))
184
+ .catch((error: unknown) => {
185
+ const message = error instanceof Error ? error.message : String(error);
186
+ startFailures.set(runId, { error: message.slice(0, 300), at: new Date().toISOString() });
187
+ if (startFailures.size > 50) startFailures.delete(startFailures.keys().next().value!);
188
+ debug.log('graphs.run', 'failed', { id, runId, error: message.slice(0, 200) }, { level: 'warn' });
189
+ });
190
+ return jsonResponse({ id, runId, demo: true }, 202);
191
+ }
192
+
193
+ /** GET /v1/graphs/<id>/runs/<runId> — 원장 그대로(노드별 ok·시각 · 지금 노드). 원장이 아직 없으면 starting, 시작 전에 죽었으면 failed ⊕ 이유. */
194
+ export function handleGraphRunGet(rawId: string, rawRunId: string, deps: GraphRunApiDeps = {}): Response {
195
+ const id = decodeId(rawId, GRAPH_ID);
196
+ const runId = decodeId(rawRunId, RUN_ID);
197
+ if (!id || !runId) return jsonResponse({ error: 'bad_request', reason: 'invalid id' }, 400);
198
+ const file = join(rootOf(deps), 'graph-runs', id, `${runId}.json`);
199
+ let state: GraphRunState | null = null;
200
+ try { state = JSON.parse(readFileSync(file, 'utf8')) as GraphRunState; } catch { state = null; }
201
+ if (state && state.graphId === id && state.runId === runId) return jsonResponse(graphRunView(state));
202
+ const failed = startFailures.get(runId);
203
+ if (failed) return jsonResponse({ graphId: id, runId, status: 'failed', path: [], nodes: [], error: failed.error } satisfies GraphRunView);
204
+ if (!existsSync(join(rootOf(deps), 'graph-run-work', id, runId))) return jsonResponse({ error: 'not-found', id, runId }, 404);
205
+ return jsonResponse({ graphId: id, runId, status: 'starting', path: [], nodes: [] } satisfies GraphRunView);
206
+ }
207
+
208
+ const RUN_START = /^\/v1\/graphs\/([^/]+)\/run$/;
209
+ const RUN_GET = /^\/v1\/graphs\/([^/]+)\/runs\/([^/]+)$/;
210
+
211
+ /** http-server 가 인증 «뒤»에 부른다. 이 두 길이 아니면 null. */
212
+ export function handleGraphRunRoute(method: string, pathname: string, deps: GraphRunApiDeps = {}): Response | null {
213
+ const start = RUN_START.exec(pathname);
214
+ if (start && method === 'POST') return handleGraphRunStart(start[1]!, deps);
215
+ const get = RUN_GET.exec(pathname);
216
+ if (get && method === 'GET') return handleGraphRunGet(get[1]!, get[2]!, deps);
217
+ return null;
218
+ }
@@ -66,6 +66,12 @@ export interface GraphRunOptions {
66
66
  resumeGraphId?: string;
67
67
  fromNodeId?: string;
68
68
  useCurrentGraph?: boolean;
69
+ /**
70
+ * RELEASE-LEDGER-UNIVERSE — stamp every cmd: child with this run's ledger root (`ELANOUS_STATE_DIR`).
71
+ * Without it a child launched from a non-leader tree (`bun scripts/...` with cwd = that tree) re-resolves
72
+ * its own universe and lands in the tree-derived test universe while the run ledger is prod.
73
+ */
74
+ pinChildUniverse?: boolean;
69
75
  deps?: { root?: string; runBash?: BashRun; log?: (event: string, data: Record<string, unknown>) => void; processStartMs?: (pid: number) => number | null; growthProposer?: GrowthProposer; growthLLM?: (prompt: string) => Promise<string>; classifyGrowthRecipe?: (node: GraphNodeSpec, resolved: { command?: string; approval?: string }) => GrowthRecipeEffect; growthDecision?: GrowthDecisionDeps & { list?: (filters: { status: 'all' }) => DecisionEntry[] } };
70
76
  }
71
77
 
@@ -714,7 +720,11 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
714
720
  // state stamp so a cmd: child resolves its default config in the same universe.
715
721
  // The ignored config-dir environment variable must not appear to propagate the flag.
716
722
  delete env.ELANOUS_CONFIG_DIR;
717
- if (getElanousConfigDirOverride()) {
723
+ if (options.pinChildUniverse) {
724
+ // The run's own ledger root is the parent universe — the child writes where the run is recorded.
725
+ env.ELANOUS_STATE_DIR = root;
726
+ debug.log('graph-runner', 'child-universe-pinned', { graphId, runId, node: current, configDir: getElanousConfigDirOverride() ?? null, stateDir: env.ELANOUS_STATE_DIR, why: 'pinChildUniverse' });
727
+ } else if (getElanousConfigDirOverride()) {
718
728
  env.ELANOUS_STATE_DIR = effectiveInstanceRoot();
719
729
  debug.log('graph-runner', 'child-universe-pinned', { graphId, runId, node: current, configDir: getElanousConfigDirOverride(), stateDir: env.ELANOUS_STATE_DIR });
720
730
  }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * 마법사 «원형» — 사람이 말로 자주 시키는 일의 뼈대 셋. graphs/** 의 운영 템플릿(개발·출시 루프)은
3
+ * «모아서 요약해 보내기» 같은 말과 낱말이 안 겹쳐 엉뚱한 기반(lecture-note)을 골랐다(10-08 라이브 실측).
4
+ * 원형은 기반 후보 «맨 앞»에 서고, 키워드가 겹치는 만큼 점수를 얻는다.
5
+ */
6
+ export interface WizardArchetype { id: string; description: string; keywords: string[]; text: string }
7
+
8
+ export const WIZARD_ARCHETYPES: readonly WizardArchetype[] = [
9
+ {
10
+ id: 'wizard-collect-summarize-send',
11
+ description: '모아서 요약해 보내기 — 검색·수집 → 요약 → 텔레그램/알림 발송 (브리핑·다이제스트·동향)',
12
+ keywords: ['뉴스', '모아', '수집', '검색', '찾아', '요약', '정리', '보내', '알려', '텔레그램', '브리핑', '동향', '소식', 'news', 'digest', 'summary'],
13
+ text: `graph_id: wizard-collect-summarize-send
14
+ loop:
15
+ title: 모아서 요약해 보내기
16
+ description: 검색으로 모은 내용을 요약해 텔레그램으로 보낸다
17
+ trigger:
18
+ cron: "0 8 * * *"
19
+ version: 1
20
+ entry_node: collect
21
+ terminal_nodes: [done, failed]
22
+ nodes:
23
+ - { node_id: collect, kind: agent, recipe: 'cmd:collect', max_visits: 1 } # 수집 | web-search | 검색어
24
+ - { node_id: summarize, kind: agent, recipe: 'cmd:summarize', max_visits: 1 } # 요약 | summarize | 핵심 5줄 한국어
25
+ - { node_id: send, kind: agent, recipe: 'cmd:send', max_visits: 1 } # 텔레그램 발송 | telegram-send
26
+ - { node_id: done, kind: gate, recipe: none, max_visits: 1 } # 완료
27
+ - { node_id: failed, kind: gate, recipe: none, max_visits: 1 } # 실패
28
+ edges:
29
+ - { from: collect, on: outcome, map: { ok: summarize, fail: failed } }
30
+ - { from: summarize, on: outcome, map: { ok: send, fail: failed } }
31
+ - { from: send, on: outcome, map: { ok: done, fail: failed } }
32
+ `,
33
+ },
34
+ {
35
+ id: 'wizard-review-merge',
36
+ description: 'PR 리뷰 후 머지 — 리뷰 → must-fix 없으면 승인 뒤 머지 (있으면 멈추고 알림)',
37
+ keywords: ['pr', '리뷰', '머지', '병합', '풀리퀘', 'must', 'fix', 'review', 'merge'],
38
+ text: `graph_id: wizard-review-merge
39
+ loop:
40
+ title: PR 리뷰 후 머지
41
+ description: PR 을 리뷰하고 must-fix 가 없으면 머지한다
42
+ trigger:
43
+ events: [pr-opened]
44
+ version: 1
45
+ entry_node: review
46
+ terminal_nodes: [done, failed]
47
+ nodes:
48
+ - { node_id: review, kind: judge, recipe: 'cmd:review', max_visits: 1 } # PR 리뷰 | gh-pr-review
49
+ - { node_id: approve-merge, kind: hitl, recipe: 'approval:approve-merge', max_visits: 1 } # 머지 승인 | approval
50
+ - { node_id: merge, kind: git, recipe: 'cmd:merge', max_visits: 1 } # PR 머지 | gh-pr-merge
51
+ - { node_id: notify, kind: agent, recipe: 'cmd:notify', max_visits: 1 } # must-fix 알림 | notify-me | PR 에 must-fix 가 있어 머지하지 않았다
52
+ - { node_id: done, kind: gate, recipe: none, max_visits: 1 } # 완료
53
+ - { node_id: failed, kind: gate, recipe: none, max_visits: 1 } # 실패
54
+ edges:
55
+ - { from: review, on: outcome, map: { ok: approve-merge, must-fix: notify, fail: failed } }
56
+ - { from: approve-merge, on: outcome, map: { ok: merge, fail: failed } }
57
+ - { from: merge, on: outcome, map: { ok: done, fail: failed } }
58
+ - { from: notify, on: outcome, map: { ok: done, fail: failed } }
59
+ `,
60
+ },
61
+ {
62
+ id: 'wizard-research-approve-publish',
63
+ description: '조사해 정리하고 승인 뒤 게시 — 조사 → 표/초안 정리 → 사람 승인 → 게시',
64
+ keywords: ['조사', '가격', '경쟁', '표', '정리', '승인', '올려', '게시', '노션', '초안', '블로그', '보고서'],
65
+ text: `graph_id: wizard-research-approve-publish
66
+ loop:
67
+ title: 조사해 정리하고 승인 뒤 게시
68
+ description: 조사한 내용을 표로 정리하고 사람 승인 뒤 게시한다
69
+ trigger:
70
+ events: [manual]
71
+ version: 1
72
+ entry_node: research
73
+ terminal_nodes: [done, failed]
74
+ nodes:
75
+ - { node_id: research, kind: agent, recipe: 'cmd:research', max_visits: 1 } # 조사 | web-search | 조사 주제
76
+ - { node_id: tabulate, kind: agent, recipe: 'cmd:tabulate', max_visits: 1 } # 표로 정리 | llm | 결과를 마크다운 표로 정리
77
+ - { node_id: approve, kind: hitl, recipe: 'approval:approve', max_visits: 1 } # 게시 승인 | approval
78
+ - { node_id: publish, kind: agent, recipe: 'cmd:publish', max_visits: 1 } # 게시 | custom | 게시처에 올리기
79
+ - { node_id: done, kind: gate, recipe: none, max_visits: 1 } # 완료
80
+ - { node_id: failed, kind: gate, recipe: none, max_visits: 1 } # 실패
81
+ edges:
82
+ - { from: research, on: outcome, map: { ok: tabulate, fail: failed } }
83
+ - { from: tabulate, on: outcome, map: { ok: approve, fail: failed } }
84
+ - { from: approve, on: outcome, map: { ok: publish, fail: failed } }
85
+ - { from: publish, on: outcome, map: { ok: done, fail: failed } }
86
+ `,
87
+ },
88
+ ];