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
@@ -45,6 +45,7 @@ import type { PrereleaseKind } from '../../scripts/release-loop/release-version.
45
45
  import { releaseReadiness } from '../../scripts/release-loop/release-readiness.js';
46
46
  import { runReleaseIfReady } from './release-run-if-ready.js';
47
47
  import { formatPreflight, releasePreflight } from '../../scripts/release-loop/preflight.js';
48
+ import { defaultReleaseGraphRunsRoot, formatPublishProposal, measurePublishWindow, proposePublishAt, publishWindowWarning } from '../../scripts/release-loop/publish-window.js';
48
49
  import { autoStartScheduledRelease, type AutoStartDeferral } from '../release-loop/auto-start.js';
49
50
  import { landingFreezeMessage, LandingFrozenError, readLandingFreeze } from '../release-loop/landing-freeze.js';
50
51
  import { formatLightRc, runLightRc, type LightRcDeps } from '../release-loop/light-rc.js';
@@ -609,6 +610,8 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
609
610
  }
610
611
  return hqCliWriteAllowed(command, override, ledgerFenceDeps());
611
612
  };
613
+ // PUBLISH-TIME-FROM-GATE: the measured cut→publish window comes from the same ledger as the schedule (prod by default).
614
+ const publishMeasure = () => measurePublishWindow({ root: defaultReleaseGraphRunsRoot(scheduleLedgerRoot()) });
612
615
  schedule.command('list').option('--json', '결과 JSON').action((o: { json?: boolean }) => {
613
616
  const rows = listSchedules(scheduleLedgerRoot());
614
617
  if (o.json) console.log(JSON.stringify(rows));
@@ -618,15 +621,27 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
618
621
  .action((o: { version: string; json?: boolean }) => {
619
622
  const row = getSchedule(o.version, scheduleLedgerRoot());
620
623
  if (!row) throw new CliUserError(`없는 판 일정: ${o.version}`, '판 일정 등록: elanous release schedule set --version <v> --cut-at <iso> --land-by <iso>');
621
- if (o.json) console.log(JSON.stringify(row)); else console.log(formatSchedule(row));
624
+ const measure = publishMeasure();
625
+ const proposedPublishAt = proposePublishAt(row.cutAt, measure);
626
+ if (o.json) console.log(JSON.stringify({ ...row, proposedPublishAt, measuredPublishMedianSeconds: measure.medianSeconds, measuredPublishSamples: measure.samples.map(({ version, seconds }) => ({ version, seconds })) }));
627
+ else { console.log(formatSchedule(row)); console.log(formatPublishProposal(row.cutAt, measure)); }
622
628
  });
623
629
  schedule.command('set').requiredOption('--version <v>', '갱신할 판')
624
630
  .option('--cut-at <iso>', '오프셋 포함 컷 시각').option('--land-by <iso>', '오프셋 포함 착지 마감')
625
- .option('--freeze-from <iso>', '동결 시작').option('--freeze-until <iso>', '동결 종료').option('--json', '결과 JSON').option('--hq-override')
626
- .action((o: { version: string; cutAt?: string; landBy?: string; freezeFrom?: string; freezeUntil?: string; json?: boolean; hqOverride?: boolean }) => {
627
- if (o.cutAt === undefined && o.landBy === undefined && o.freezeFrom === undefined && o.freezeUntil === undefined) throw new CliUserError('갱신할 시각을 지정하라', '--cut-at <iso> 또는 --land-by <iso>');
631
+ .option('--freeze-from <iso>', '동결 시작').option('--freeze-until <iso>', '동결 종료')
632
+ .option('--publish-at <iso>', '오프셋 포함 발행 시각(실측 컷→발행 중앙값보다 짧으면 경고 · 제안은 schedule show)')
633
+ .option('--json', '결과 JSON').option('--hq-override')
634
+ .action((o: { version: string; cutAt?: string; landBy?: string; freezeFrom?: string; freezeUntil?: string; publishAt?: string; json?: boolean; hqOverride?: boolean }) => {
635
+ if (o.cutAt === undefined && o.landBy === undefined && o.freezeFrom === undefined && o.freezeUntil === undefined && o.publishAt === undefined) throw new CliUserError('갱신할 시각을 지정하라', '--cut-at <iso> 또는 --land-by <iso> 또는 --publish-at <iso>');
628
636
  if (!mayWriteLedger('release schedule set', Boolean(o.hqOverride), scheduleLedgerRoot())) return;
629
- const row = setSchedule(o.version, { cutAt: o.cutAt, landBy: o.landBy, freezeFrom: o.freezeFrom, freezeUntil: o.freezeUntil }, process.env.ELANOUS_TRACK || 'cli', scheduleLedgerRoot());
637
+ const row = setSchedule(o.version, { cutAt: o.cutAt, landBy: o.landBy, freezeFrom: o.freezeFrom, freezeUntil: o.freezeUntil, publishAt: o.publishAt }, process.env.ELANOUS_TRACK || 'cli', scheduleLedgerRoot());
638
+ // A stored publish time shorter than the measured median warns on stderr (one line) — --json stdout stays parseable.
639
+ if (row.publishAt && (o.publishAt !== undefined || o.cutAt !== undefined)) {
640
+ const measure = publishMeasure();
641
+ const warning = publishWindowWarning(row.cutAt, row.publishAt, measure);
642
+ debug.log('release.schedule', 'publish-window', { version: row.version, cutAt: row.cutAt, publishAt: row.publishAt, medianSeconds: measure.medianSeconds, samples: measure.samples.length, warned: warning !== null });
643
+ if (warning) console.error(warning);
644
+ }
630
645
  if (o.json) console.log(JSON.stringify(row)); else console.log(formatSchedule(row));
631
646
  });
632
647
  release.command('place <id>').description('칸의 우선순위·마감·용량으로 판 배치')
@@ -0,0 +1,78 @@
1
+ import { existsSync } from 'node:fs';
2
+ import type { Command } from 'commander';
3
+ import { LogStore, logsDbPath } from '../mss/logging/log-store.js';
4
+
5
+ type RetroFact = { store: string; at: string; category: string; event: string; kind: 'draft-birth' | 'draft-death' | 'stop-reason' | 'ta-outcome'; data: unknown };
6
+
7
+ const FACT_EVENTS = new Map<string, RetroFact['kind']>([
8
+ ['rework-blocked-draft-pr', 'draft-birth'],
9
+ ['lineage-supersede', 'draft-death'],
10
+ ['resolved', 'stop-reason'],
11
+ ['decision', 'stop-reason'],
12
+ ['action', 'ta-outcome'],
13
+ ['task-agent.action', 'ta-outcome'],
14
+ ]);
15
+
16
+ export function parseRetroSince(value: string, now = Date.now()): number {
17
+ const match = /^([1-9]\d*)([smhd])$/.exec(value);
18
+ if (!match) throw new Error('--since requires a positive duration (e.g. 24h)');
19
+ const duration = Number(match[1]) * ({ s: 1000, m: 60000, h: 3600000, d: 86400000 }[match[2]!] ?? 0);
20
+ if (!Number.isSafeInteger(duration) || !Number.isSafeInteger(now - duration)) throw new Error('--since duration is out of range');
21
+ return now - duration;
22
+ }
23
+
24
+ export function collectRetroFacts(sinceMs: number, targets: readonly { name: string; dbPath: string }[] = [{ name: 'current', dbPath: logsDbPath() }]): { facts: RetroFact[]; unavailable: string[] } {
25
+ const facts: RetroFact[] = [];
26
+ const unavailable: string[] = [];
27
+ const untilMs = Date.now();
28
+ for (const target of targets) {
29
+ if (!existsSync(target.dbPath)) { unavailable.push(target.name); continue; }
30
+ try {
31
+ const store = LogStore.openReadOnly(target.dbPath);
32
+ try {
33
+ let beforeId: number | undefined;
34
+ for (;;) {
35
+ const rows = store.query({ sinceMs, beforeId, limit: 1000 });
36
+ for (const row of rows) {
37
+ if (Date.parse(row.ts) > untilMs) continue;
38
+ const kind = FACT_EVENTS.get(row.event);
39
+ if (!kind || (row.event === 'resolved' && row.category !== 'self-dev.supervisor') || ((row.event === 'task-agent.action' || row.event === 'action') && row.category !== 'task-agent')) continue;
40
+ let data: unknown;
41
+ try { data = row.data === null ? null : JSON.parse(row.data); } catch { data = row.data; }
42
+ const record = data && typeof data === 'object' && !Array.isArray(data) ? data as Record<string, unknown> : {};
43
+ if (row.event === 'rework-blocked-draft-pr' && (row.category !== 'self-implement' || !Number.isInteger(record.number) || record.skipped || record.error)) continue;
44
+ if (row.event === 'lineage-supersede' && (row.category !== 'self-implement' || !Array.isArray(record.closed) || record.closed.length === 0)) continue;
45
+ if (row.event === 'resolved' && typeof record.stopReason !== 'string') continue;
46
+ if (row.event === 'decision' && (row.category !== 'self-dev.supervisor' || record.action !== 'stop' || typeof record.stopReason !== 'string')) continue;
47
+ if ((row.event === 'task-agent.action' || row.event === 'action') && (row.category !== 'task-agent' || typeof record.result !== 'string' || !record.result.trim())) continue;
48
+ facts.push({ store: target.name, at: row.ts, category: row.category, event: row.event, kind, data });
49
+ }
50
+ if (rows.length < 1000) break;
51
+ beforeId = rows.at(-1)!.id;
52
+ }
53
+ } finally { store.close(); }
54
+ } catch { unavailable.push(target.name); }
55
+ }
56
+ facts.sort((a, b) => b.at.localeCompare(a.at));
57
+ return { facts, unavailable };
58
+ }
59
+
60
+ export function registerRetroCommands(program: Command): void {
61
+ program.command('retro').description('Read-only retrospective facts from existing logs')
62
+ .command('facts').description('Draft births/deaths, stop reasons and task-agent outcomes')
63
+ .option('--since <duration>', 'Lookback duration', '24h')
64
+ .option('--json', 'JSON output')
65
+ .action((opts: { since: string; json?: boolean }) => {
66
+ try {
67
+ const sinceMs = parseRetroSince(opts.since);
68
+ const result = { since: new Date(sinceMs).toISOString(), ...collectRetroFacts(sinceMs) };
69
+ console.log(opts.json ? JSON.stringify(result) : [
70
+ `retro facts since ${result.since} · ${result.facts.length} facts · unavailable: ${result.unavailable.join(', ') || 'none'}`,
71
+ ...result.facts.map((fact) => `${fact.at} ${fact.kind} ${fact.category}.${fact.event} ${JSON.stringify(fact.data)}`),
72
+ ].join('\n'));
73
+ } catch (error) {
74
+ console.error(`retro facts: ${error instanceof Error ? error.message : String(error)}`);
75
+ process.exitCode = 2;
76
+ }
77
+ });
78
+ }
@@ -1,4 +1,6 @@
1
- import { readFileSync } from 'node:fs';
1
+ import { closeSync, mkdirSync, openSync, readFileSync, readSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { loadRunLedger as loadRunLedgerSync } from '../self-implement/run-ledger.js';
2
4
  import { join, resolve } from 'node:path';
3
5
  import { InvalidArgumentError, Option, type Command } from 'commander';
4
6
  import { debug } from '../debug/log.js';
@@ -8,7 +10,7 @@ import { checklistDevVersion } from '../release-loop/checklist.js';
8
10
  import { cardsBoard, countBoardTasks, INTERNAL_PACK_PROJECT, mergeBoards, releasePackBoard, type BoardNode } from '../task-agent/board.js';
9
11
  import type { Task } from '../task-orchestrator/types.js';
10
12
  import { cardPrNumber, COMPLETION_KINDS, handTask, nextMoveFor, readTaskAgentState, readTaskCard, taskAgentStatePath as taskStatePathDefault, shellQuote, TASK_CARD_PREFIX, TASK_SEATS, type CompletionKind, type TaskCard, type TaskLaunchContext, type TaskLaunchReceipt, type TaskLauncher, type TaskSeat } from '../task-agent/task-hand.js';
11
- import { refreshCardRunBinding, type CardRunEvidenceDeps } from '../task-agent/card-evidence.js';
13
+ import { readCardSalvageBranch, refreshCardRunBinding, type CardRunEvidenceDeps } from '../task-agent/card-evidence.js';
12
14
  import { advanceMission, handMission, MissionAdvanceError, openMissionIds, recordPieceRef, type AdvanceMissionResult, type MissionDecompose, type PieceEvidenceReader } from '../task-agent/mission.js';
13
15
 
14
16
  type TaskRow = Pick<Task, 'id' | 'title' | 'priority' | 'status' | 'createdAt' | 'approval' | 'generatedBy'>;
@@ -32,6 +34,10 @@ export interface TasksCliDeps {
32
34
  releaseBoard?: () => BoardNode[];
33
35
  /** `tasks show`·`advance` 의 런 근거 읽기(시험 주입) — 기본 = 런 원장(이 우주 ⊕ 연합) ⊕ 호스트 logs 의 Pod job-finished. */
34
36
  cardRunEvidence?: CardRunEvidenceDeps;
37
+ /** HARNESS-PARENT-ON-MSB1 — 원격 부모 카드의 원장 거울(시험 주입). 기본 = ssh 로 `<prodRoot>/remote-parents/<host>/run-ledger`. */
38
+ remoteLedgerMirror?: (card: TaskCard) => void;
39
+ /** `tasks parents` 의 낡은 부모 보고 의존(시험 주입). */
40
+ staleParents?: import('../task-agent/parent-host.js').StaleParentDeps;
35
41
  }
36
42
 
37
43
  /** `<조각id>=<값>` 반복 인자. */
@@ -82,14 +88,147 @@ export function taskLauncherArgv(configDir: string, args: readonly string[]): st
82
88
  return [ELANOUS_CLI_ENTRY, '--config-dir', configDir, ...args];
83
89
  }
84
90
 
85
- export async function defaultTaskLauncher(args: string[], cwd?: string, context?: TaskLaunchContext, deps: { spawn?: DetachedSpawn } = {}): Promise<void | TaskLaunchReceipt> {
91
+ /** STOP-RECORD launch-failed: 발사 직후 이 창 안에 자식이 비0 으로 끝나면 «발사 실패»로 본다. */
92
+ export const LAUNCH_EARLY_EXIT_WINDOW_MS = 3_000;
93
+
94
+ export interface DefaultTaskLauncherDeps {
95
+ spawn?: DetachedSpawn;
96
+ /** 조기 종료 감시 창(ms) — context(런 id)가 있을 때만 · 0 이면 감시하지 않는다(옛 동작). */
97
+ earlyExitWindowMs?: number;
98
+ /** 자식 stderr 를 받을 디렉토리(시험 주입). 기본 = `<tmpdir>/elanous-task-launch`. */
99
+ stderrDir?: string;
100
+ /** stop 줄 기록기(시험 주입). 기본 = 런 원장. */
101
+ writeStop?: import('../self-implement/run-ledger.js').RunLedgerWriter;
102
+ /** 이미 stop 이 있나(시험 주입). 기본 = 이 우주 런 원장 ⊕ 이 프로세스 기록. */
103
+ hasStop?: (runId: string) => boolean;
104
+ /** HARNESS-PARENT-ON-MSB1 — 원격 부모 대상(시험 주입). undefined = 설정·env 에서 푼다 · null = 끔. */
105
+ parentHost?: import('../task-agent/parent-host.js').ParentHostConfig | null;
106
+ /** 원격 ssh(시험 주입). */
107
+ ssh?: import('../task-agent/parent-host.js').SshRunner;
108
+ /** HQ 발사 동결(holdLaunches) 여부(시험 주입). */
109
+ launchHoldActive?: () => boolean;
110
+ /** HQ 판(시험 주입). */
111
+ localVersion?: string;
112
+ /** 원격 → 로컬 되돌림 알림(시험 주입). 기본 = stderr 한 줄. */
113
+ notice?: (line: string) => void;
114
+ }
115
+
116
+ /**
117
+ * HARNESS-PARENT-ON-MSB1 — 켜져 있고 발사 전 점검이 통과하면 원격(ssh)에서 부모를 띄운다(PR 까지만 · 병합은 HQ).
118
+ * 막히면 null — 호출부가 종전 로컬 발사로 간다(관측: task-agent parent-host-fallback).
119
+ */
120
+ async function tryRemoteParent(args: string[], cwd: string | undefined, context: TaskLaunchContext, deps: DefaultTaskLauncherDeps): Promise<TaskLaunchReceipt | null> {
121
+ const parentHostModule = await import('../task-agent/parent-host.js');
122
+ let target = deps.parentHost;
123
+ if (target === undefined) {
124
+ const { getUserConfig } = await import('../user-config.js');
125
+ let configured: Parameters<typeof parentHostModule.resolveParentHost>[0];
126
+ try { configured = getUserConfig().taskAgent?.parentHost; } catch { configured = undefined; }
127
+ target = parentHostModule.resolveParentHost(configured);
128
+ }
129
+ if (!target) return null;
130
+ const notice = deps.notice ?? ((line: string) => { try { process.stderr.write(`${line}\n`); } catch { /* ignore */ } });
131
+ const fallback = (gaps: string[], facts: Record<string, string> = {}): null => {
132
+ try { debug.log('task-agent', 'parent-host-fallback', { host: target!.host, runId: context.runId, gaps, facts }); } catch { /* fail-soft */ }
133
+ notice(`[parent-host] ${target!.host} 로 못 띄움 — 로컬 발사로 간다: ${gaps.join(' · ')}`);
134
+ return null;
135
+ };
136
+ if (cwd) return fallback(['project-target-is-local']);
137
+ let launchHoldActive = false;
138
+ try {
139
+ if (deps.launchHoldActive) launchHoldActive = deps.launchHoldActive();
140
+ else {
141
+ const { readLandingFreeze } = await import('../release-loop/landing-freeze.js');
142
+ const { prodInstanceRoot } = await import('../instance/resolve.js');
143
+ launchHoldActive = readLandingFreeze(prodInstanceRoot())?.holdLaunches === true;
144
+ }
145
+ } catch { launchHoldActive = true; /* 못 읽으면 막힌 것으로(fail-closed) */ }
146
+ const preflight = parentHostModule.preflightParentHost({ target, localVersion: deps.localVersion ?? parentHostModule.localElanousVersion(), launchHoldActive, ...(deps.ssh ? { ssh: deps.ssh } : {}) });
147
+ if (!preflight.ok) return fallback(preflight.gaps, preflight.facts);
148
+ try {
149
+ const launched = parentHostModule.launchRemoteParent(target, args, context.env, deps.ssh);
150
+ try { debug.log('task-agent', 'parent-host-launched', { host: target.host, runId: context.runId, pid: launched.pid, log: launched.log }); } catch { /* fail-soft */ }
151
+ return { runId: context.runId, parentHost: { host: target.host, ...(target.configDir ? { configDir: target.configDir } : {}), pid: launched.pid, log: launched.log } };
152
+ } catch (error) {
153
+ // «확실히 안 떴다»일 때만 로컬로 — 불확실(ssh 끊김 등)은 던져 카드를 launch-failed 로 남긴다(중복 발사 방지).
154
+ if (error instanceof parentHostModule.RemoteParentNotLaunchedError) return fallback([error.message]);
155
+ try { debug.log('task-agent', 'parent-host-launch-uncertain', { host: target.host, runId: context.runId, error: error instanceof Error ? error.message : String(error) }); } catch { /* fail-soft */ }
156
+ throw error;
157
+ }
158
+ }
159
+
160
+ /** stderr 파일의 첫 비어 있지 않은 줄(최대 4KB 만 읽는다 — 원 로그 꼬리를 싣지 않는다). */
161
+ function firstStderrLine(path: string): string {
162
+ try {
163
+ const fd = openSync(path, 'r');
164
+ try {
165
+ const buf = Buffer.alloc(4096);
166
+ const n = readSync(fd, buf, 0, buf.length, 0);
167
+ return buf.subarray(0, n).toString('utf8').split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0) ?? '';
168
+ } finally { closeSync(fd); }
169
+ } catch { return ''; }
170
+ }
171
+
172
+ export async function defaultTaskLauncher(args: string[], cwd?: string, context?: TaskLaunchContext, deps: DefaultTaskLauncherDeps = {}): Promise<void | TaskLaunchReceipt> {
173
+ if (context) {
174
+ const remote = await tryRemoteParent(args, cwd, context, deps);
175
+ if (remote) return remote;
176
+ }
86
177
  const spawn = deps.spawn ?? ((await import('node:child_process')).spawn as unknown as DetachedSpawn);
87
178
  const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
88
179
  const { prodInstanceRoot } = await import('../instance/resolve.js');
89
180
  const configDir = getElanousConfigDirOverride() ?? prodInstanceRoot();
90
- // TA-CARD-RUN-LINK: 런 id 를 자식 환경에 얹는다 — `harness say` 의 런(호스트 orchestrate)이 그 id 를 상속한다.
91
- await spawnDetachedConfirmed(spawn, process.execPath, taskLauncherArgv(configDir, args), SPAWN_CONFIRM_TIMEOUT_MS, cwd, context?.env);
92
- return context ? { runId: context.runId } : undefined;
181
+ const argv = taskLauncherArgv(configDir, args);
182
+ const window = context ? deps.earlyExitWindowMs ?? LAUNCH_EARLY_EXIT_WINDOW_MS : 0;
183
+ if (!context || window <= 0) {
184
+ // TA-CARD-RUN-LINK: 런 id 를 자식 환경에 얹는다 — `harness say` 의 런(호스트 orchestrate)이 그 id 를 상속한다.
185
+ await spawnDetachedConfirmed(spawn, process.execPath, argv, SPAWN_CONFIRM_TIMEOUT_MS, cwd, context?.env);
186
+ return context ? { runId: context.runId } : undefined;
187
+ }
188
+ // STOP-RECORD launch-failed: stdio 를 버리면 자식이 exit 2 로 죽어도 흔적이 0 이고 카드는 «launched» 로 남는다
189
+ // (ORCH-LIVE-1008). stderr 만 파일로 받고(파이프는 부모가 먼저 끝나면 자식을 EPIPE 로 죽인다), 짧은 창 안의 종료를 본다.
190
+ const stderrDir = deps.stderrDir ?? join(tmpdir(), 'elanous-task-launch');
191
+ mkdirSync(stderrDir, { recursive: true });
192
+ const stderrPath = join(stderrDir, `${context.runId}.stderr`);
193
+ // 'w' — 같은 runId 재발사가 지난 시도의 stderr 를 이번 cause 로 읽지 않게(리뷰 must-fix).
194
+ const fd = openSync(stderrPath, 'w');
195
+ let exited: Promise<{ code: number | null; signal: string | null }> | undefined;
196
+ const watched: DetachedSpawn = (command, spawnArgs, options) => {
197
+ const child = (spawn as unknown as (c: string, a: string[], o: unknown) => ReturnType<DetachedSpawn>)(command, spawnArgs, { ...options, stdio: ['ignore', 'ignore', fd] });
198
+ const emitter = child as unknown as { once?: (event: 'exit', listener: (code: number | null, signal: string | null) => void) => unknown };
199
+ exited = new Promise((done) => { emitter.once?.('exit', (code, signal) => done({ code, signal })); });
200
+ return child;
201
+ };
202
+ try {
203
+ await spawnDetachedConfirmed(watched, process.execPath, argv, SPAWN_CONFIRM_TIMEOUT_MS, cwd, context.env);
204
+ } finally {
205
+ try { closeSync(fd); } catch { /* the child keeps its own copy */ }
206
+ }
207
+ let timer: ReturnType<typeof setTimeout> | undefined;
208
+ const early = exited
209
+ ? await Promise.race([exited, new Promise<undefined>((done) => { timer = setTimeout(() => done(undefined), window); })])
210
+ : undefined;
211
+ if (timer) clearTimeout(timer);
212
+ if (early && early.code !== 0) {
213
+ const first = firstStderrLine(stderrPath);
214
+ const cause = `child rc=${early.code ?? early.signal ?? 'unknown'}${first ? `: ${first}` : ''}`;
215
+ const { boundRunStopCause, recordRunStop, runStopRecorded, RUN_STOP_EVENT } = await import('../self-implement/run-stop.js');
216
+ const hasStop = deps.hasStop ?? ((id: string) => {
217
+ if (runStopRecorded(id)) return true;
218
+ try { return (loadRunLedgerSync(id) ?? []).some((entry) => entry.event === RUN_STOP_EVENT); } catch { return false; }
219
+ });
220
+ // 자식이 같은 runId 로 이미 stop 을 썼으면 더하지 않는다(런마다 한 줄 · 리뷰 must-fix).
221
+ if (hasStop(context.runId)) throw new Error(`발사 직후 자식이 종료했다 — ${boundRunStopCause(cause)}`);
222
+ const entry = recordRunStop({
223
+ runId: context.runId, site: 'launch-failed', class: 'launch-failed',
224
+ cause,
225
+ evidenceRef: stderrPath,
226
+ nextMove: 'Fix the launch argv/config from the stderr evidence, then re-hand the card',
227
+ }, ...(deps.writeStop ? [deps.writeStop] : []));
228
+ // handTask 가 이 예외로 카드를 `launch-failed` 로 적는다(«launched» 로 남지 않게).
229
+ throw new Error(`발사 직후 자식이 종료했다 — ${String(entry.data.cause)}`);
230
+ }
231
+ return { runId: context.runId };
93
232
  }
94
233
 
95
234
  /** `spawn` 의 필요한 면만(시험 주입). */
@@ -131,6 +270,21 @@ export function spawnDetachedConfirmed(spawnFn: DetachedSpawn, command: string,
131
270
  });
132
271
  }
133
272
 
273
+ /** HARNESS-PARENT-ON-MSB1 — 카드가 원격 부모면 그 런 원장(⊕ Pod 자식)을 HQ 거울로 당긴다. 실패는 관측만(«없음»으로 읽히지 않게). */
274
+ async function mirrorRemoteCardLedger(cardId: string, deps: TasksCliDeps): Promise<void> {
275
+ let card: TaskCard | undefined;
276
+ try { card = readTaskCard(cardId, deps.taskStatePath); } catch { return; }
277
+ if (!card?.parentHost || !card.runId) return;
278
+ try {
279
+ if (deps.remoteLedgerMirror) { deps.remoteLedgerMirror(card); return; }
280
+ const { mirrorRemoteRunLedgers } = await import('../task-agent/parent-host.js');
281
+ const { prodInstanceRoot } = await import('../instance/resolve.js');
282
+ mirrorRemoteRunLedgers(card.parentHost, card.runId, prodInstanceRoot());
283
+ } catch (error) {
284
+ try { debug.log('task-agent', 'remote-ledger-mirror-failed', { card: cardId, host: card.parentHost.host, runId: card.runId, error: error instanceof Error ? error.message : String(error) }); } catch { /* fail-soft */ }
285
+ }
286
+ }
287
+
134
288
  function moveLine(card: TaskCard): string {
135
289
  const move = nextMoveFor(card);
136
290
  return `${move.kind}${move.command ? ` — elanous ${move.command.map(shellQuote).join(' ')}` : ''} (${move.reason})`;
@@ -365,6 +519,32 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
365
519
  }
366
520
  });
367
521
 
522
+ tasks.command('parents')
523
+ .description('낡은 하니스 부모 보고(읽기 전용 · 죽이지 않는다) — 나이 ≥ N 시간이고 런 원장이 끝났거나(run-status) Pod 이 없는 `harness say|ask` 부모')
524
+ .option('--older-than <hours>', '나이 하한(시간)', '6')
525
+ .option('--no-pods', 'Pod 목록을 재지 않는다(원장 근거만)')
526
+ .option('--json', 'JSON 출력')
527
+ .action(async (opts: { olderThan: string; pods?: boolean; json?: boolean }) => {
528
+ const hours = Number(opts.olderThan);
529
+ if (!Number.isFinite(hours) || hours < 0) { out(`--older-than 는 0 이상 수다: ${opts.olderThan}`); process.exitCode = 1; return; }
530
+ const { staleHarnessParents } = await import('../task-agent/parent-host.js');
531
+ const injected = deps.staleParents ?? {};
532
+ const loadLedger = injected.loadLedger ?? ((runId: string) => loadRunLedgerSync(runId));
533
+ let podRuns = injected.podRuns;
534
+ let labelOf = injected.labelOf;
535
+ if (!podRuns && opts.pods !== false) {
536
+ const queue = await import('../harness/harness-queue.js');
537
+ podRuns = () => queue.readHarnessQueuePodRuns();
538
+ labelOf = queue.queueRunLabelValue;
539
+ }
540
+ const report = staleHarnessParents(hours, { ...injected, loadLedger, ...(podRuns ? { podRuns } : {}), ...(labelOf ? { labelOf } : {}) });
541
+ try { debug.log('task-agent', 'stale-parents', { olderThanHours: hours, scanned: report.scanned, stale: report.rows.length, podRunsMeasured: report.podRunsMeasured }); } catch { /* fail-soft */ }
542
+ if (opts.json) { out(JSON.stringify({ olderThanHours: hours, ...report })); return; }
543
+ out(`하니스 부모 ${report.scanned} · 나이 ≥ ${hours}h 중 낡음 후보 ${report.rows.length}${report.podRunsMeasured ? '' : ' · ⚠ Pod 목록 못 잼(원장 근거만)'} — 읽기 전용(죽이지 않는다)`);
544
+ out('pid\t나이h\t자리\t판\t런\t사유');
545
+ for (const row of report.rows) out([row.pid, row.ageHours, row.seat ?? '-', row.version ?? '-', row.runId ?? '-', row.reasons.join(',')].join('\t'));
546
+ });
547
+
368
548
  tasks.command('board')
369
549
  .description('보드 — 프로젝트 › 목표 › 이정표 › 과제. 과제 카드(project·goal·milestone)와 내부 팩(릴리스 체크리스트 = elanous › 판 › 칸)을 합쳐 읽는다(쓰지 않는다)')
370
550
  .option('--project <id>', '이 프로젝트만')
@@ -492,6 +672,8 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
492
672
  // 런 id 가 있으면 원장에서 골 id · PR 을 묶는다(찾았을 때만 적는다 · 실패는 그대로 보인다).
493
673
  const bindable = card?.pieces ? card.pieces : card ? [card.id] : [];
494
674
  for (const cardId of bindable) {
675
+ // HARNESS-PARENT-ON-MSB1: 원격 부모 런은 원장이 그 호스트에 있다 — HQ 거울로 먼저 당긴다(읽기 전용).
676
+ await mirrorRemoteCardLedger(cardId, deps);
495
677
  try { await refreshCardRunBinding(cardId, deps.taskStatePath ?? taskStatePathDefault(), deps.cardRunEvidence ?? {}); } catch (error) {
496
678
  // 근거 없음으로 보인다 — 원장 부재와 갈리게 실패는 남긴다.
497
679
  try { debug.log('task-agent', 'card-bind-failed', { card: cardId, via: 'show', error: error instanceof Error ? error.message : String(error) }); } catch { /* fail-soft */ }
@@ -523,8 +705,18 @@ export function registerTasksCommands(program: Command, deps: TasksCliDeps = {})
523
705
  }
524
706
  return;
525
707
  }
526
- if (opts.json) out(JSON.stringify({ card, nextMove: nextMoveFor(card) }));
527
- else for (const line of taskCardLines(card)) out(line);
708
+ // DRAFT-NOT-ARCHIVE: 멈춘 런이 draft PR 대신 남긴 수확 가지(원장 `salvaged`). 못 읽었으면 «못 읽음»(⛔ 없음 아님).
709
+ let salvage: Awaited<ReturnType<typeof readCardSalvageBranch>> = { salvageBranch: null };
710
+ try { salvage = await readCardSalvageBranch(card, deps.cardRunEvidence ?? {}); }
711
+ catch (error) { salvage = { salvageBranch: null, readErrors: [error instanceof Error ? error.message : String(error)] }; }
712
+ const salvageUnread = !salvage.salvageBranch && !!salvage.readErrors?.length;
713
+ if (opts.json) out(JSON.stringify({ card, nextMove: nextMoveFor(card), salvageBranch: salvage.salvageBranch, ...(salvageUnread ? { salvageBranchUnread: true } : {}) }));
714
+ else {
715
+ for (const line of taskCardLines(card)) out(line);
716
+ if (card.parentHost) out(`부모 호스트: ${card.parentHost.host}${card.parentHost.pid ? ` (pid ${card.parentHost.pid})` : ''} · PR 까지만 — 병합은 HQ${card.parentHost.log ? ` · 로그 ${card.parentHost.host}:${card.parentHost.log}` : ''}`);
717
+ if (salvage.salvageBranch) out(`수확 가지: ${salvage.salvageBranch} (draft PR 대신)`);
718
+ else if (salvageUnread) out('수확 가지: 못 읽음(원장 읽기 실패)');
719
+ }
528
720
  return;
529
721
  }
530
722
  try {
@@ -769,6 +769,15 @@ export function clearEscAbortToolState(toolState: EscAbortToolState): void {
769
769
  toolState.activeToolNamesByCallId.clear();
770
770
  }
771
771
 
772
+ export function activeEscHarnessSpace(
773
+ toolState: EscAbortToolState,
774
+ spacesByCallId: ReadonlyMap<string, string>,
775
+ ): string | null {
776
+ const active = [...toolState.activeToolNamesByCallId].filter(([, name]) =>
777
+ (SELF_IMPLEMENT_TOOL_NAMES as readonly string[]).includes(name));
778
+ return active.length === 1 ? spacesByCallId.get(active[0]![0]) ?? null : null;
779
+ }
780
+
772
781
  /** Reset per-turn ESC tool tracking before a new stream runtime begins. */
773
782
  export function createDashboardTurnStreamRuntimeEscBoundary(toolState: EscAbortToolState): void {
774
783
  clearEscAbortToolState(toolState);
@@ -1324,6 +1333,8 @@ import {
1324
1333
  PULSE_HALF_PERIOD_MS,
1325
1334
  } from '../agent-activity-hud.js';
1326
1335
  import { DASHBOARD_CLARIFICATION_REQUEST, consumeStreamingTopModalEscape, createEscAbortGate, createHarnessEscHint, routeStreamingEscapeKey } from '../esc-abort-gate.js';
1336
+ import { enqueueSoftStop, readSoftStopRequestStatus } from '../harness/control-inbox.js';
1337
+ import { setSelfImplementSoftStopSpaceObserver } from '../self-implement/self-implement-runtime.js';
1327
1338
  import { createViEditor, type ViEditorHandle } from '../vi-editor.js';
1328
1339
  import { launchEditor, canLaunchEditor } from '../editor-launcher.js';
1329
1340
  import { createSshPickerModal } from '../ssh/ssh-picker-modal.js';
@@ -6700,6 +6711,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
6700
6711
  * this function is invoked.
6701
6712
  */
6702
6713
  const escAbortToolState = createEscAbortToolState();
6714
+ const escHarnessSpacesByCallId = new Map<string, string>();
6715
+ setSelfImplementSoftStopSpaceObserver((callId, spaceId) => {
6716
+ const toolName = escAbortToolState.activeToolNamesByCallId.get(callId);
6717
+ if (toolName && (SELF_IMPLEMENT_TOOL_NAMES as readonly string[]).includes(toolName)) {
6718
+ escHarnessSpacesByCallId.set(callId, spaceId);
6719
+ }
6720
+ });
6703
6721
  let clarificationModalId: string | null = null;
6704
6722
 
6705
6723
  const attachChatStreamingKeys = (abortCtrl: AbortController): () => void => {
@@ -6713,6 +6731,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
6713
6731
  // so the user can make an informed call.
6714
6732
  let abortGateModalId: string | null = null;
6715
6733
  const showHarnessEscHint = createHarnessEscHint((line) => pushChatLine(line));
6734
+ let stoppedHarnessSpace: string | null = null;
6735
+ const activeHarnessSpace = (): string | null => activeEscHarnessSpace(escAbortToolState, escHarnessSpacesByCallId);
6716
6736
  const escGate = createEscAbortGate({
6717
6737
  abortCtrl,
6718
6738
  getRunningCount: () => getEscAbortRunningCount(escAbortToolState),
@@ -6726,14 +6746,25 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
6726
6746
  requestRedraw: () => draw(),
6727
6747
  getTheme: () => currentThemeTokens(),
6728
6748
  getWaitingTargetNames: () => getEscAbortWaitingToolNames(escAbortToolState),
6749
+ shouldAbortImmediately: () => activeHarnessSpace() !== null,
6729
6750
  onAbortPending: ({ targets }) => {
6730
- if (!showHarnessEscHint(targets)) {
6751
+ const spaceId = activeHarnessSpace();
6752
+ if (spaceId) {
6753
+ try {
6754
+ enqueueSoftStop(spaceId);
6755
+ if (readSoftStopRequestStatus(spaceId).status !== 'present') throw new Error('soft-stop marker not persisted');
6756
+ stoppedHarnessSpace = spaceId;
6757
+ pushChatLine(' ⏹ 멈췄다 — 해당 하니스 런에 중단 요청을 보냈습니다.');
6758
+ } catch {
6759
+ pushChatLine(' ⚠ 하니스 런 중단 요청을 보내지 못했습니다. /harness runs 에서 확인해 주세요.');
6760
+ }
6761
+ } else if (!showHarnessEscHint(targets)) {
6731
6762
  pushChatLine(` ⏳ 중단 요청됨 — ${formatEscAbortWaitingTargets(targets)} 종료를 기다리는 중입니다.`);
6732
6763
  }
6733
6764
  chatScrollOffset = -1;
6734
6765
  },
6735
6766
  onAbortRepeat: ({ repeat, targets }) => {
6736
- if (!showHarnessEscHint(targets)) {
6767
+ if (!stoppedHarnessSpace && !showHarnessEscHint(targets)) {
6737
6768
  pushChatLine(` ⏳ ESC 재시도 ${repeat}회 — ${formatEscAbortWaitingTargets(targets)} 종료를 기다리는 중입니다.`);
6738
6769
  }
6739
6770
  chatScrollOffset = -1;
@@ -7251,7 +7282,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
7251
7282
  return () => {
7252
7283
  cleanup();
7253
7284
  escGate.dispose();
7254
- settleEscAbortPendingLines(chatLines, chatLinesStartIndex);
7285
+ if (!stoppedHarnessSpace) settleEscAbortPendingLines(chatLines, chatLinesStartIndex);
7255
7286
  userScrolledDuringStream = false;
7256
7287
  streamingInFlight = false;
7257
7288
  };
@@ -15674,6 +15705,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
15674
15705
  pushChatLine,
15675
15706
  draw,
15676
15707
  signal: acpTurnRef.abortCtrl?.signal ?? new AbortController().signal,
15708
+ toolCallId: ctx?.callId,
15677
15709
  // ⛔⭐ 폴백은 `''` 가 아니라 `undefined` 다 — 「안 넘김」과 「말했는데 어휘가 없음」은 «다른 값»이다.
15678
15710
  // harnessMentionState(session-runtime 소비처)는 `undefined → 'absent'` · `'' → 'not-matched'` 로
15679
15711
  // 가른다. `?? ''` 로 접으면 그 둘이 같은 값이 되고, 그것이 2026-08-06 에 「TUI 가 하니스에게
@@ -15695,9 +15727,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
15695
15727
  ptyDashboardOn:
15696
15728
  uc.shell.allowDashboardPty === true && (acpPtyAvailable?.() ?? false),
15697
15729
  getToolRuntime: (toolName) => runtime.getToolRuntime(toolName),
15698
- dispatchToolRuntime: (toolName, input) =>
15730
+ dispatchToolRuntime: (toolName, input, toolCallId) =>
15699
15731
  runtime.dispatchToolByName(toolName, input, {
15700
15732
  surface: 'tui',
15733
+ toolCallId,
15701
15734
  signal: acpTurnRef.abortCtrl?.signal,
15702
15735
  // ⭐ Agent-family context. Without these two the sub-agent runs
15703
15736
  // text-only (see getTools above). `agentDispatchTool` routes the
@@ -19171,6 +19204,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
19171
19204
  createTurnStreamRuntime: (initialAssistantStart) => {
19172
19205
  latestTurnUsage = undefined;
19173
19206
  createDashboardTurnStreamRuntimeEscBoundary(escAbortToolState);
19207
+ escHarnessSpacesByCallId.clear();
19174
19208
  liveTypeaheadEchoes.length = 0;
19175
19209
  const toolRendering = {
19176
19210
  ...getUserConfig().chat.rendering.tool,
@@ -19225,6 +19259,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
19225
19259
  const toolCall = call as DashboardTurnStreamCall;
19226
19260
  turnStreamRuntime.onToolResult(toolCall);
19227
19261
  settleEscAbortToolCall(escAbortToolState, toolCall);
19262
+ escHarnessSpacesByCallId.delete(toolCall.id);
19228
19263
  },
19229
19264
  };
19230
19265
  },
@@ -19524,6 +19559,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
19524
19559
  closeDashboardTui();
19525
19560
  throw err;
19526
19561
  } finally {
19562
+ setSelfImplementSoftStopSpaceObserver(null);
19527
19563
  if (tuiSeatAskTimer) clearInterval(tuiSeatAskTimer);
19528
19564
  }
19529
19565
  }
@@ -1505,15 +1505,16 @@ export function buildDashboardSlashRegistry(nowDeps?: ContextNowDeps, decideLedg
1505
1505
 
1506
1506
  registry.register(['help', '?'], (_args, ctx) => {
1507
1507
  const { cols, rows } = termSize();
1508
+ // The transient modal paints only height - 2 content rows and does not scroll.
1509
+ // The builder adds columns to fit that budget; only when it still overflows, use the scrollable chat log.
1510
+ const minHeight = Math.min(6, Math.max(3, rows - 2));
1511
+ const modalContentRows = Math.max(minHeight, Math.min(rows - 4, Math.floor(rows * 0.7))) - 2;
1508
1512
  const lines = buildEssentialHelpLines({
1509
1513
  names: registry.names(),
1510
1514
  descriptions: SLASH_COMMANDS,
1511
1515
  width: Math.max(1, Math.floor(cols * 0.7) - 2),
1516
+ maxRows: modalContentRows,
1512
1517
  });
1513
- // The transient modal paints only height - 2 content rows and does not scroll.
1514
- // When the catalog outgrows it, use the scrollable chat log instead of hiding keys.
1515
- const minHeight = Math.min(6, Math.max(3, rows - 2));
1516
- const modalContentRows = Math.max(minHeight, Math.min(rows - 4, Math.floor(rows * 0.7))) - 2;
1517
1518
  if (ctx.showHelpModal && lines.length <= modalContentRows) {
1518
1519
  ctx.showHelpModal({ title: 'Dashboard help', lines });
1519
1520
  } else {