elanous 0.2.31 → 0.2.34

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 (715) 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/{LSXfY0u9QtfDbejY0Ukf_ → L04y73dlwKeTW-GetaTF3}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +79 -0
  5. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +94 -0
  8. package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 1644.35dd25240ae24e4b.js} +2 -2
  9. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 1895-60ed0e341c658bd4.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 2124.ed5bf480cea7f85b.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +23 -0
  13. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +115 -0
  15. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +8 -0
  16. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 2547.dd27303624cb4da8.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 2554.3b5e200f5f5cfcd6.js} +16 -16
  19. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 2987-30cf9c2eb7b8bdd5.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3541-ce3a5424ed5ad7f1.js → 3001-5a52788c813b6113.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +34 -0
  30. package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 3110.0a7065f25c841818.js} +17 -17
  31. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3121.779fafe3e44612c5.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 3414.172ad4ca2d9b08e8.js} +2 -2
  37. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{4745.67d6f99c245af3f7.js → 3498.cf2a15a8a9e5b926.js} +3 -3
  39. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +32 -0
  41. package/apps/pwa/out/_next/static/chunks/{5543.a438b8ab5a13ea47.js → 3837.722e053fb9f321ad.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +104 -0
  44. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +286 -0
  45. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +149 -0
  46. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +148 -0
  47. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +64 -0
  48. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +74 -0
  51. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → 4fa33ebd.21c1bd5b294496e6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 5014f970-22bef0b5210f7d60.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/{2112-e4efc21a6505d5bc.js → 5028-f0722e6114c313e7.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/{2898.fd781bc7cf01a7b7.js → 5249.96a848656b582a93.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +62 -0
  60. package/apps/pwa/out/_next/static/chunks/{9407.e49124dedf0f5e72.js → 5446.edf141cff9ef647d.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9002.e5658224e3dc1b6f.js → 5489.ec2dd1b5272a19dc.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 5576-82d3703636d5c4b9.js} +3 -3
  63. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 6086.913a69e6fa3e4a8b.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +77 -0
  76. package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 6740.43de73fc427c9fe2.js} +1 -1
  77. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +90 -0
  80. package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7005.1623d2aea78eb85f.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +287 -0
  87. package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 7431.3051e9b8a4372d2d.js} +2 -2
  88. package/apps/pwa/out/_next/static/chunks/{3583.a05e88cc8d594628.js → 7448.478958ffbbba0ac0.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +41 -0
  91. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +27 -0
  94. package/apps/pwa/out/_next/static/chunks/{9989.3694300e5f000b14.js → 7952.b192c31b6a0e00cc.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +36 -0
  97. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 8368.014caa8de2f5af34.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 8548.036c344973968847.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 9131-fce7256c4180c4a5.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +93 -0
  114. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +24 -0
  116. package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9550.d5f76828f972058c.js} +2 -2
  117. package/apps/pwa/out/_next/static/chunks/{2534.e85ae21ad0dac829.js → 9739.8d5f36ac67a3b236.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → 9a8cb466.cc9fc9e6e46038aa.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → 9b48c871.204d5d13e7809bd0.js} +7 -7
  123. package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → abb4b98b.163e0f56e84ae35d.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-0a07363b130182a1.js → page-398c0faa173203f7.js} +1 -1
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-df3445b207ceceab.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{ebc7d829.264a0bcb6c750b50.js → ffdc3a04.b9c23c1b28dd4a96.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +1 -0
  184. package/apps/pwa/out/_next/static/css/b5d88eba78a3d7bf.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 +23 -23
  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 +22 -22
  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 +26 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  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/bin/elanous.mjs +9 -2
  279. package/docs/goal-context/README.md +1 -0
  280. package/graphs/default-loop.yaml +20 -3
  281. package/graphs/document-loop.yaml +21 -2
  282. package/graphs/implement-loop.yaml +11 -0
  283. package/graphs/journey/SCENARIOS.md +33 -0
  284. package/graphs/journey/recipes.yaml +1 -0
  285. package/graphs/journey/ta-journey.yaml +84 -0
  286. package/graphs/journey/units/author/author.yaml +20 -0
  287. package/graphs/journey/units/author/recipes.yaml +2 -0
  288. package/graphs/journey/units/green/green.yaml +20 -0
  289. package/graphs/journey/units/green/recipes.yaml +2 -0
  290. package/graphs/journey/units/pr/pr.yaml +20 -0
  291. package/graphs/journey/units/pr/recipes.yaml +2 -0
  292. package/graphs/journey/units/remember/recipes.yaml +2 -0
  293. package/graphs/journey/units/remember/remember.yaml +20 -0
  294. package/graphs/operate-loop.yaml +21 -2
  295. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  296. package/graphs/release-rehearsal/recipes.yaml +1 -1
  297. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  298. package/graphs/research-loop.yaml +23 -2
  299. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  300. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  301. package/graphs/units/entry/entry.yaml +50 -0
  302. package/graphs/units/entry/recipes.yaml +14 -0
  303. package/graphs/units/harvest/harvest.yaml +25 -0
  304. package/graphs/units/harvest/recipes.yaml +4 -0
  305. package/graphs/units/land/land.yaml +45 -0
  306. package/graphs/units/land/recipes.yaml +3 -0
  307. package/graphs/units/recipes.yaml +7 -0
  308. package/graphs/units/recover.yaml +39 -0
  309. package/graphs/units/reflect/recipes.yaml +3 -0
  310. package/graphs/units/reflect/reflect.yaml +15 -0
  311. package/graphs/units/task-agent-recover-review.yaml +17 -0
  312. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  313. package/graphs/units/verbs/make-doc.yaml +34 -0
  314. package/graphs/units/verbs/recipes.yaml +33 -0
  315. package/graphs/units/verbs/verify.yaml +55 -0
  316. package/graphs/work/recipes.yaml +2 -0
  317. package/graphs/work/research-report.yaml +28 -0
  318. package/package.json +1 -1
  319. package/scripts/ci-typecheck-changed.ts +95 -17
  320. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  321. package/scripts/graph-harvest-unit.ts +22 -0
  322. package/scripts/graph-units/journey-stub.ts +6 -0
  323. package/scripts/graph-units/land-enqueue.ts +78 -0
  324. package/scripts/graph-units/recover-plan.ts +15 -0
  325. package/scripts/graph-units/reflect-node.ts +88 -0
  326. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  327. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  328. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  329. package/scripts/graph-units/verbs-envelope.ts +139 -0
  330. package/scripts/hq/standby-snapshot.ts +25 -0
  331. package/scripts/measure-si-task-cpu.ts +143 -0
  332. package/scripts/public-export.ts +43 -1
  333. package/scripts/ratchets/test-interference-patterns.allowlist.txt +0 -2
  334. package/scripts/ratchets/train-side-invariants.sh +45 -0
  335. package/scripts/release-loop/auto-approve-node.ts +30 -16
  336. package/scripts/release-loop/gate-closure.ts +5 -1
  337. package/scripts/release-loop/gate-diff.ts +1 -1
  338. package/scripts/release-loop/gate-node.ts +498 -31
  339. package/scripts/release-loop/gate-partial.ts +3 -3
  340. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  341. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  342. package/scripts/release-loop/gate-triage-node.ts +5 -2
  343. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  344. package/scripts/release-loop/known-issues-node.ts +77 -8
  345. package/scripts/release-loop/preflight.ts +93 -7
  346. package/scripts/release-loop/prepare-node.ts +102 -4
  347. package/scripts/release-loop/publish-node.ts +60 -9
  348. package/scripts/release-loop/resume-cap.ts +56 -0
  349. package/scripts/release-loop/resume-release.ts +114 -15
  350. package/scripts/release-loop/resume.ts +24 -1
  351. package/scripts/release-loop/tui-sim-node.ts +8 -2
  352. package/scripts/release-loop/unattended-release.ts +8 -2
  353. package/src/acp/core-turn-bridge.ts +36 -9
  354. package/src/acp/elanous-extensions.ts +3 -0
  355. package/src/acp/reasoning-thought-buffer.ts +45 -0
  356. package/src/acp/server.ts +3 -0
  357. package/src/acp/tool-trace.ts +186 -11
  358. package/src/agent/self-ambient-cache.ts +156 -0
  359. package/src/agent/self-ambient.ts +8 -1
  360. package/src/agent/task-notification.ts +5 -0
  361. package/src/agent-substrate/acp-reviewer.ts +52 -12
  362. package/src/agent-substrate/pr-reviewer.ts +3 -1
  363. package/src/agent-substrate/review-finding-key.ts +53 -0
  364. package/src/agent-substrate/self-review-cli.ts +126 -5
  365. package/src/ask-user-question/pending-questions.ts +1 -1
  366. package/src/ask-user-question/tool.ts +22 -0
  367. package/src/autopilot/build/llm-conflict-merge.ts +56 -10
  368. package/src/autopilot/pr-manager.ts +213 -46
  369. package/src/capture/frame-state-detect.ts +39 -0
  370. package/src/capture/tui-self-report.ts +134 -6
  371. package/src/chat/index.ts +61 -15
  372. package/src/chat/pickers/modal-runtime.ts +6 -0
  373. package/src/chat/pickers/modals.ts +8 -2
  374. package/src/chat/tool-render/dispatch.ts +62 -10
  375. package/src/cli/ask-bare.ts +1 -0
  376. package/src/cli/control-cli.ts +24 -7
  377. package/src/cli/guardian-cli.ts +10 -0
  378. package/src/cli/import-cli.ts +12 -0
  379. package/src/cli/light-entry-route.ts +35 -0
  380. package/src/cli/llm-detect-cli.ts +23 -1
  381. package/src/cli/log-event-names.ts +10 -0
  382. package/src/cli/msg-cli.ts +1 -0
  383. package/src/cli/pod-cli.ts +14 -3
  384. package/src/cli/pr-cli.ts +140 -41
  385. package/src/cli/pr-land-base-read.ts +36 -0
  386. package/src/cli/pr-land-heavy-remote.ts +81 -25
  387. package/src/cli/pr-land-overlap-evidence.ts +200 -18
  388. package/src/cli/pr-land-pod-shadow-job.ts +26 -3
  389. package/src/cli/pr-land-recovery.ts +64 -0
  390. package/src/cli/pr-land-refusal.ts +20 -5
  391. package/src/cli/pty-takeover-cli.ts +94 -19
  392. package/src/cli/release-cli.ts +120 -33
  393. package/src/cli/release-run-if-ready.ts +29 -28
  394. package/src/cli/release-single-flight.ts +178 -0
  395. package/src/cli/seat-cli.ts +37 -0
  396. package/src/cli/setup-cli.ts +40 -1
  397. package/src/cli/sim-cli.ts +18 -0
  398. package/src/cli/tasks-cli.ts +149 -5
  399. package/src/context-bus/ops-events.ts +6 -2
  400. package/src/control/control-status.ts +8 -3
  401. package/src/control-plane/ledger.ts +5 -3
  402. package/src/control-plane/server.ts +5 -3
  403. package/src/core-turn/run-core-turn.ts +1 -0
  404. package/src/core-turn/run-goal-loop.ts +21 -0
  405. package/src/core-turn/short-question.ts +5 -1
  406. package/src/core-turn/types.ts +3 -0
  407. package/src/dashboard/acp-active-model.ts +42 -1
  408. package/src/dashboard/background-jobs-status.ts +66 -0
  409. package/src/dashboard/index.ts +153 -111
  410. package/src/dashboard/input/agent-wake.ts +242 -0
  411. package/src/dashboard/input/chat-main-entry-runtime.ts +5 -0
  412. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  413. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  414. package/src/dashboard/input/external-input-host.ts +23 -9
  415. package/src/dashboard/input/mouse-wiring.ts +108 -11
  416. package/src/dashboard/input/seat-autowake.ts +56 -3
  417. package/src/dashboard/log-click-runtime.ts +118 -2
  418. package/src/dashboard/seat-boot-preamble.ts +1 -1
  419. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  420. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  421. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  422. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  423. package/src/dashboard/turn-preamble.ts +163 -41
  424. package/src/dashboard/turn-session-layers.ts +4 -2
  425. package/src/dashboard/turn-start-segments.ts +222 -0
  426. package/src/dashboard/turn-stream-formatter.ts +34 -1
  427. package/src/dashboard/turn-stream-runtime.ts +2 -0
  428. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  429. package/src/display/prompt-row-owner.ts +146 -0
  430. package/src/display/resize-listener.ts +33 -2
  431. package/src/domains/guardian-tick.ts +54 -2
  432. package/src/domains/outbound-alert.ts +3 -2
  433. package/src/extractors.ts +3 -1
  434. package/src/fold-stack.ts +4 -2
  435. package/src/git-fs/index.ts +263 -36
  436. package/src/git-fs/retry.ts +4 -0
  437. package/src/git-fs/runner.ts +2 -0
  438. package/src/graph-runner/runner.ts +114 -44
  439. package/src/grok/credential.ts +5 -0
  440. package/src/harness/gate-reserve.ts +87 -0
  441. package/src/harness/harness-cli-command.ts +39 -10
  442. package/src/harness/harness-incidents.ts +17 -0
  443. package/src/harness/harness-pod-dispatch.ts +38 -1
  444. package/src/harness/harness-queue.ts +15 -0
  445. package/src/harness/harness-salvage-cli.ts +14 -2
  446. package/src/index.ts +198 -12
  447. package/src/input/external-input-queue.ts +34 -9
  448. package/src/intake-plane/already-built-hint.ts +89 -0
  449. package/src/knowhow/pack.ts +199 -0
  450. package/src/light-cli.ts +95 -0
  451. package/src/llm/route-decision.ts +36 -0
  452. package/src/llm/tool-loop-steered-rejection.ts +8 -0
  453. package/src/llm-request-shape.ts +209 -0
  454. package/src/llm.ts +221 -276
  455. package/src/loops/budget.ts +95 -0
  456. package/src/loops/msg-wake.ts +8 -2
  457. package/src/loops/orchestrator/tick.ts +24 -2
  458. package/src/loops/orchestrator/traffic.ts +132 -1
  459. package/src/maturity/feature-maturity.ts +1 -1
  460. package/src/mss/logging/log-store.ts +4 -5
  461. package/src/mss/logging/render-categories.ts +5 -0
  462. package/src/nexus/api/graphs-api.ts +22 -3
  463. package/src/nexus/api/http-server.ts +1 -1
  464. package/src/nexus/api/ops-api.ts +12 -0
  465. package/src/oauth/claude-pty-maturity.ts +66 -0
  466. package/src/oauth/codex-access-mirror.ts +55 -0
  467. package/src/oauth/fallback-chain.ts +1 -1
  468. package/src/onboarding/first-run.ts +5 -3
  469. package/src/onboarding/non-interactive.ts +64 -13
  470. package/src/onboarding.ts +10 -2
  471. package/src/ops/overview-collect.ts +36 -1
  472. package/src/ops/overview.ts +70 -2
  473. package/src/pr-tool/census.ts +41 -8
  474. package/src/pr-tool/inflight-registry.ts +296 -0
  475. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  476. package/src/pty-shell/herdr-agent-report.ts +442 -0
  477. package/src/pty-shell/pty-control-ipc.ts +5 -5
  478. package/src/pty-shell/pty-manifest.ts +12 -3
  479. package/src/pty-shell/pty-write-outcome.ts +24 -6
  480. package/src/pty-shell/tui-run-state.ts +151 -6
  481. package/src/release-loop/checklist.ts +79 -5
  482. package/src/release-loop/feature-store.ts +19 -2
  483. package/src/release-loop/placement.ts +10 -3
  484. package/src/release-loop/rehearsal.ts +205 -25
  485. package/src/release-loop/rubric.ts +16 -2
  486. package/src/seat-loop/traffic-signal.ts +2 -1
  487. package/src/self-dev/ask-launch-flow.ts +13 -0
  488. package/src/self-dev/draft-residue.ts +243 -24
  489. package/src/self-dev/draft-sweep.ts +52 -3
  490. package/src/self-dev/graph-journey-nodes.ts +10 -6
  491. package/src/self-dev/graph-journey-route.ts +60 -6
  492. package/src/self-dev/orchestrate.ts +79 -3
  493. package/src/self-dev/run-supervisor.ts +107 -12
  494. package/src/self-dev/run-types.ts +5 -1
  495. package/src/self-dev/shard-plan.ts +11 -3
  496. package/src/self-dev/shard-run.ts +103 -10
  497. package/src/self-implement/elanous-tui-spawn.ts +14 -0
  498. package/src/self-implement/follow-up-placement.ts +79 -0
  499. package/src/self-implement/gate-artifacts.ts +15 -4
  500. package/src/self-implement/gate-baseline.ts +145 -10
  501. package/src/self-implement/gate-cli.ts +7 -2
  502. package/src/self-implement/gate-remote.ts +35 -6
  503. package/src/self-implement/goal-author-identity.ts +66 -0
  504. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  505. package/src/self-implement/goal-author.ts +4 -120
  506. package/src/self-implement/graph-overlay-yaml.ts +17 -2
  507. package/src/self-implement/graph-unit-flatten.ts +103 -0
  508. package/src/self-implement/graph-unit-resolver.ts +107 -0
  509. package/src/self-implement/graph-yaml.ts +151 -1
  510. package/src/self-implement/headless-elanous-driver.ts +1 -0
  511. package/src/self-implement/host-regate.ts +36 -4
  512. package/src/self-implement/knowhow-pack.ts +103 -0
  513. package/src/self-implement/orchestrator.ts +109 -11
  514. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  515. package/src/self-implement/review-mustfix-class.ts +203 -0
  516. package/src/self-implement/run-ledger.ts +16 -14
  517. package/src/self-implement/run-stop.ts +8 -2
  518. package/src/self-implement/seams.ts +32 -1
  519. package/src/self-implement/stop-autoheal.ts +25 -1
  520. package/src/session/chat.ts +27 -0
  521. package/src/session-runtime/index.ts +22 -267
  522. package/src/session-runtime/retry-policy.ts +2 -1
  523. package/src/shell-runner/background-surface.ts +15 -5
  524. package/src/skills/tools/agent.ts +39 -6
  525. package/src/skills/tools/list-dir.ts +11 -0
  526. package/src/skills/tools/schedule-wakeup.ts +457 -0
  527. package/src/skills/tools/shell.ts +245 -3
  528. package/src/status/bar.ts +26 -0
  529. package/src/steward/digest-delivery.ts +118 -0
  530. package/src/steward/hold-hygiene.ts +120 -0
  531. package/src/steward/release-day.ts +7 -3
  532. package/src/steward/triage.ts +47 -4
  533. package/src/surface/shell-runner-boot.ts +5 -2
  534. package/src/task-agent/harvest-unit.ts +141 -0
  535. package/src/task-agent/live-moves.ts +98 -12
  536. package/src/task-agent/parent-host.ts +93 -3
  537. package/src/task-agent/postland-card.ts +80 -1
  538. package/src/task-agent/rejudge-on-head.ts +112 -26
  539. package/src/task-agent/repair-branch-cas.ts +4 -1
  540. package/src/task-agent/repair-cycle.ts +16 -3
  541. package/src/task-agent/run-identity.ts +4 -3
  542. package/src/task-agent/shadow.ts +12 -2
  543. package/src/task-agent/task-hand.ts +76 -5
  544. package/src/task-agent/work-order-build.ts +22 -0
  545. package/src/task-orchestrator/surfaces/pod-account-broker.ts +39 -3
  546. package/src/task-orchestrator/surfaces/pod-command-job.ts +67 -12
  547. package/src/task-orchestrator/surfaces/pod-lease.ts +98 -0
  548. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +1 -1
  549. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  550. package/src/task-orchestrator/surfaces/pod-pool.ts +76 -18
  551. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +10 -6
  552. package/src/task-orchestrator/surfaces/pod-source-receive.ts +54 -4
  553. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +548 -0
  554. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +389 -0
  555. package/src/task-orchestrator/surfaces/pod-warm-worker-runner.ts +90 -0
  556. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +158 -3
  557. package/src/task-orchestrator/surfaces/self-implement-pod.ts +230 -43
  558. package/src/task-orchestrator/surfaces/self-implement.ts +83 -2
  559. package/src/tool-runtime/truncation-store.ts +4 -0
  560. package/src/tui/chat/execution-badge.ts +5 -1
  561. package/src/tui/input-lag-probe.ts +230 -0
  562. package/src/tui-client/dashboard-session.ts +10 -1
  563. package/src/tui.ts +4 -0
  564. package/src/user-config/coercion.ts +36 -0
  565. package/src/user-config.ts +18 -41
  566. package/src/ux-sim/scenario.ts +314 -0
  567. package/src/version/packed-revision.json +1 -1
  568. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  571. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  572. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  573. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  577. package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  579. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  580. package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  587. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  588. package/apps/pwa/out/_next/static/chunks/3267c0e6.d34854e7b3984a6e.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +0 -34
  591. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  595. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  599. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  600. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  602. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  605. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  610. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  612. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  619. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  620. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  622. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  627. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  628. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  635. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2ebb8fd59b9461f9.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/setup/page-521ee23ac8c0abfa.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-149dc1caba411bb9.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  706. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  713. package/apps/pwa/out/_next/static/css/3f5fc6f96e2cf7b2.css +0 -1
  714. package/src/cli/g6a-registration-probe.ts +0 -16
  715. /package/apps/pwa/out/_next/static/{LSXfY0u9QtfDbejY0Ukf_ → L04y73dlwKeTW-GetaTF3}/_ssgManifest.js +0 -0
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { closeSync, existsSync, openSync, readFileSync, writeFileSync, mkdirSync, rmSync } from 'node:fs';
2
+ import { closeSync, existsSync, openSync, readFileSync, writeFileSync, mkdirSync, renameSync, rmSync } from 'node:fs';
3
3
  import { launchModeOf, rescueAllows } from './rescue.js';
4
4
  import { join } from 'node:path';
5
5
  import { fetchLinearIssues } from '../connectors/linear.js';
@@ -24,6 +24,7 @@ import { CardStore } from '../task-cards/card-store.js';
24
24
  import { draftWithinBudget, triageWithinBudget } from './triage-budget.js';
25
25
  import { askSteward, classifyIssue, installedCapabilities, planIssues, ruleJudgment, unsafeReason, type ClassifiedIssue, type StewardAsk } from './triage-plan.js';
26
26
  import { failureAlertText, markStageStart, markStageEnd, readFailureStreak, shouldAlert, writeFailureStreak, type FailureStreak, type StewardStage } from './failure-streak.js';
27
+ import { briefVerdictChange } from './digest-delivery.js';
27
28
 
28
29
  export type Rung = 0 | 1 | 2 | 3 | 4 | 5 | 'hitl';
29
30
  /** `other` = the judge chose human review for a reason outside the four named ones (kept as HITL, never downgraded). */
@@ -56,6 +57,8 @@ export interface StewardDeps {
56
57
  judge?: (issue: TriageIssue, issues: TriageIssue[], tracks?: Record<string, string>) => Promise<unknown>;
57
58
  decide?: typeof emitDecision;
58
59
  sendDigest?: (text: string) => Promise<void>;
60
+ /** 흐름 판정 변화 브리핑 한 줄 발송(OVW-BRIEF) — 생략하면 킨드 `ops-report`(운영 봇)이 기본. */
61
+ sendBrief?: (text: string) => Promise<void>;
59
62
  now?: () => Date;
60
63
  root?: string;
61
64
  cardStore?: StewardCardDeps['store'];
@@ -325,13 +328,46 @@ function logStageFailure(root: string, stage: StewardStage, reason: string): voi
325
328
  }
326
329
  const SCHEDULE_CHECK_MS = 15 * 60_000;
327
330
 
331
+ /** Atomic marker write: stage the payload at `<marker>.tmp-<pid>`, then renameSync it into place so a
332
+ * crash mid-write never leaves a half-written marker for the next sync to trip over. */
333
+ export function writeScheduleCheckMarker(
334
+ marker: string,
335
+ at: Date,
336
+ write: (path: string, data: string) => void = writeFileSync,
337
+ ): void {
338
+ const tmp = `${marker}.tmp-${process.pid}`;
339
+ try {
340
+ write(tmp, JSON.stringify({ at: at.toISOString() }));
341
+ renameSync(tmp, marker);
342
+ } catch (error) {
343
+ try { rmSync(tmp, { force: true }); } catch { /* Preserve the write or rename error. */ }
344
+ throw error;
345
+ }
346
+ }
347
+
328
348
  /** Called by runStewardStage(sync) under its stage slot, never from the checker CLI. */
329
349
  async function checkStewardSchedules(root: string, settings: StewardSettings, deps: StewardDeps): Promise<void> {
330
350
  const now = (deps.now ?? (() => new Date()))();
331
351
  const marker = join(root, 'steward', 'schedule-check.json');
332
352
  let previous: { at?: string } = {};
333
- try { previous = JSON.parse(readFileSync(marker, 'utf8')) as typeof previous; }
334
- catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
353
+ try {
354
+ const parsed: unknown = JSON.parse(readFileSync(marker, 'utf8'));
355
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)
356
+ && (!('at' in parsed) || typeof parsed.at === 'string')) {
357
+ previous = parsed as typeof previous;
358
+ } else {
359
+ debug.log('steward.schedule-check', 'marker-recovered', { reason: 'invalid-marker-shape' });
360
+ }
361
+ }
362
+ catch (error) {
363
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') { /* first run in this window — previous stays {} */ }
364
+ else if (error instanceof SyntaxError) {
365
+ // Corrupt marker bytes self-heal: previous stays {} so this check runs now and the fresh
366
+ // writeScheduleCheckMarker below replaces the broken file. The recovery is observed.
367
+ debug.log('steward.schedule-check', 'marker-recovered', { reason: redactSecretText(String(error)) });
368
+ }
369
+ else throw error;
370
+ }
335
371
  const elapsed = now.getTime() - Date.parse(previous.at ?? '');
336
372
  if (Number.isFinite(elapsed) && elapsed >= 0 && elapsed < SCHEDULE_CHECK_MS) return;
337
373
  const inventory = deps.scheduleInventory ?? (() => {
@@ -375,7 +411,7 @@ async function checkStewardSchedules(root: string, settings: StewardSettings, de
375
411
  debug.log('steward.schedule-check', 'routing', { ownerRequests, opEscalations, recovered });
376
412
  }
377
413
  debug.log('steward.schedule-check', 'checked', { count: checked.length, findings: findings.length, mode: settings.mode });
378
- writeFileSync(marker, JSON.stringify({ at: now.toISOString() }));
414
+ writeScheduleCheckMarker(marker, now);
379
415
  }
380
416
 
381
417
  function readState(path: string): { issues: Record<string, string>; digestDay?: string } {
@@ -602,6 +638,13 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
602
638
  writeFileSync(path, JSON.stringify(state));
603
639
  digested = true;
604
640
  }
641
+ try {
642
+ await briefVerdictChange(root, { send: deps.sendBrief });
643
+ } catch (error) {
644
+ const message = `steward report: verdict brief failed: ${redactSecretText(error instanceof Error ? error.message : String(error))}`;
645
+ debug.log('steward.verdict-brief', 'failed', { error: message });
646
+ (deps.warn ?? console.warn)(message);
647
+ }
605
648
  const launched = readLaunchDecision(root);
606
649
  if (launched) logTickDecision(root, launched.verdict, launched.reason, launched.goalId);
607
650
  else if (outcomes.length || digested) logTickDecision(root, 'reported', outcomes.length ? `${outcomes.length} outcome(s) reported` : 'daily digest sent');
@@ -7,7 +7,7 @@ interface BackgroundSurfaceLike<Handle> {
7
7
 
8
8
  export interface DashboardShellRunnerBootDeps<Handle> {
9
9
  createBackgroundSurface: (deps: {
10
- onUpdate: (rollup: { running: number; backgrounded: number }) => void;
10
+ onUpdate: (rollup: { running: number; backgrounded: number; background: number }) => void;
11
11
  }) => BackgroundSurfaceLike<Handle>;
12
12
  initShellRegistry: (deps: {
13
13
  onRegister: (handle: Handle) => void;
@@ -19,7 +19,7 @@ export interface DashboardShellRunnerBootDeps<Handle> {
19
19
  registry: ShellRegistryLike<Handle>;
20
20
  fileEngine?: unknown;
21
21
  }): void;
22
- setLatestShellRollup: (rollup: { running: number; backgrounded: number }) => void;
22
+ setLatestShellRollup: (rollup: { running: number; backgrounded: number; background: number }) => void;
23
23
  }
24
24
 
25
25
  export function bootDashboardShellRunner<Handle>(
@@ -30,6 +30,9 @@ export function bootDashboardShellRunner<Handle>(
30
30
  deps.setLatestShellRollup({
31
31
  running: rollup.running,
32
32
  backgrounded: rollup.backgrounded,
33
+ // TUI-BG-JOB-VISIBILITY — turn-outliving jobs (bg mode ⊕ backgrounded).
34
+ // Required: guessing it from `backgrounded` would under-count running bg-mode jobs.
35
+ background: rollup.background,
33
36
  });
34
37
  },
35
38
  });
@@ -0,0 +1,141 @@
1
+ export type HarvestInput = {
2
+ ask?: unknown;
3
+ context?: unknown;
4
+ prior?: unknown;
5
+ };
6
+
7
+ export type ReviewInvocation = {
8
+ stdout: string;
9
+ stderr?: string;
10
+ exitCode: number | null;
11
+ };
12
+
13
+ export type HarvestResult = {
14
+ outcome: 'done' | 'rework' | 'needs-human' | 'failed';
15
+ result: Record<string, unknown>;
16
+ evidence: Record<string, unknown>;
17
+ };
18
+
19
+ type ReviewRecord = Record<string, unknown> & {
20
+ pr?: string | number;
21
+ reviewed?: boolean;
22
+ verdict?: string | null;
23
+ mustFix?: unknown;
24
+ model?: string;
25
+ headCommit?: string;
26
+ currentHeadCommit?: string;
27
+ };
28
+
29
+ function object(value: unknown): value is Record<string, unknown> {
30
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
31
+ }
32
+
33
+ function expectedHead(input: HarvestInput): string | undefined {
34
+ if (object(input.context) && typeof input.context.expectedHead === 'string' && input.context.expectedHead.trim()) return input.context.expectedHead.trim();
35
+ return undefined;
36
+ }
37
+
38
+ function normalizedPr(value: unknown): string | undefined {
39
+ const raw = typeof value === 'number' && Number.isSafeInteger(value) ? String(value) : typeof value === 'string' ? value.trim() : '';
40
+ const normalized = raw.replace(/^#/, '');
41
+ return /^\d+$/.test(normalized) ? normalized : undefined;
42
+ }
43
+
44
+ function previousAttempts(input: HarvestInput): number {
45
+ if (!object(input.prior)) return 0;
46
+ const result = object(input.prior.result) ? input.prior.result : input.prior;
47
+ const attempts = result.attempts;
48
+ return Number.isSafeInteger(attempts) && (attempts as number) >= 0 ? attempts as number : 0;
49
+ }
50
+
51
+ function parseReview(stdout: string): ReviewRecord | undefined {
52
+ try {
53
+ const parsed: unknown = JSON.parse(stdout.trim());
54
+ if (Array.isArray(parsed)) {
55
+ if (parsed.length !== 1) return undefined;
56
+ return object(parsed[0]) ? parsed[0] as ReviewRecord : undefined;
57
+ }
58
+ return object(parsed) ? parsed as ReviewRecord : undefined;
59
+ } catch {
60
+ return undefined;
61
+ }
62
+ }
63
+
64
+ export async function runHarvestUnit(
65
+ input: HarvestInput,
66
+ invokeReview: (args: { pr: string; intent: string }) => Promise<ReviewInvocation>,
67
+ ): Promise<HarvestResult> {
68
+ const attempts = previousAttempts(input) + 1;
69
+ const prValue = object(input.context) ? input.context.pr : undefined;
70
+ const pr = normalizedPr(prValue);
71
+ if (!pr) {
72
+ return { outcome: 'failed', result: { attempts, error: 'context.pr must identify one pull request' }, evidence: { pr: pr || null, attempts } };
73
+ }
74
+
75
+ const context = object(input.context) ? input.context : {};
76
+ const hasContextIntent = Object.prototype.hasOwnProperty.call(context, 'reviewIntent');
77
+ const intentValue = context.reviewIntent;
78
+ const intent = hasContextIntent
79
+ ? typeof intentValue === 'string' ? intentValue.trim() : ''
80
+ : typeof input.ask === 'string' ? input.ask.trim() : '';
81
+ if (!intent) {
82
+ return { outcome: 'failed', result: { attempts, error: hasContextIntent ? 'context.reviewIntent must be a non-empty string' : 'context.reviewIntent or ask is required' }, evidence: { pr, attempts } };
83
+ }
84
+ const expected = expectedHead(input);
85
+ if (!expected || !/^[0-9a-f]{40}$/i.test(expected)) {
86
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'expected PR head is required' }, evidence: { pr, attempts, expectedHead: expected ?? null } };
87
+ }
88
+
89
+ let invocation: ReviewInvocation;
90
+ try {
91
+ invocation = await invokeReview({ pr: pr.replace(/^#/, ''), intent });
92
+ } catch (error) {
93
+ const reason = error instanceof Error ? error.message : String(error);
94
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review could not be executed' }, evidence: { pr, attempts, error: reason } };
95
+ }
96
+
97
+ const review = parseReview(invocation.stdout);
98
+ if (!review || review.reviewed !== true || typeof review.headCommit !== 'string' || typeof review.currentHeadCommit !== 'string') {
99
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review result is missing or incomplete' }, evidence: {
100
+ pr, attempts, exitCode: invocation.exitCode, stderr: invocation.stderr ?? '', stdout: invocation.stdout.slice(0, 4000),
101
+ } };
102
+ }
103
+ if (normalizedPr(review.pr) !== pr) {
104
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review result belongs to a different pull request' }, evidence: {
105
+ pr, attempts, reviewedPr: review.pr ?? null, expectedHead: expected,
106
+ } };
107
+ }
108
+ if (invocation.exitCode !== 0) {
109
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review command exited unsuccessfully' }, evidence: {
110
+ pr, attempts, exitCode: invocation.exitCode, stderr: invocation.stderr ?? '',
111
+ } };
112
+ }
113
+ if (review.headCommit !== review.currentHeadCommit || (expected !== undefined && review.headCommit !== expected)) {
114
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review head is stale or differs from expected head' }, evidence: {
115
+ pr, attempts, expectedHead: expected ?? null, reviewedHead: review.headCommit, currentHead: review.currentHeadCommit,
116
+ } };
117
+ }
118
+ if (!['pass', 'warn', 'fail'].includes(review.verdict ?? '')) {
119
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review verdict is missing or invalid' }, evidence: {
120
+ pr, attempts, verdict: review.verdict ?? null, headCommit: review.headCommit,
121
+ } };
122
+ }
123
+ if (!Array.isArray(review.mustFix) || !review.mustFix.every(item => typeof item === 'string' && item.trim().length > 0)) {
124
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review mustFix field is invalid' }, evidence: { pr, attempts, headCommit: review.headCommit } };
125
+ }
126
+
127
+ const mustFix = review.mustFix as string[];
128
+ if ((review.verdict === 'fail' && mustFix.length === 0)
129
+ || ((review.verdict === 'pass' || review.verdict === 'warn') && mustFix.length > 0)) {
130
+ return { outcome: 'needs-human', result: { pr, attempts, reason: 'review verdict conflicts with mustFix findings' }, evidence: {
131
+ pr, attempts, verdict: review.verdict, mustFix, headCommit: review.headCommit,
132
+ } };
133
+ }
134
+ const evidence = {
135
+ pr, headCommit: review.headCommit, attempts, model: review.model ?? null, verdict: review.verdict ?? null,
136
+ reviewResultsJson: true, exitCode: invocation.exitCode,
137
+ };
138
+ return mustFix.length > 0
139
+ ? { outcome: 'rework', result: { pr, headCommit: review.headCommit, attempts, mustFix }, evidence }
140
+ : { outcome: 'done', result: { pr, headCommit: review.headCommit, attempts, mustFix: [] }, evidence };
141
+ }
@@ -22,7 +22,9 @@ import { debug } from '../debug/log.js';
22
22
  import { findGitDir } from '../git-fs/locate.js';
23
23
  import { getUserConfig, userConfigPath } from '../user-config.js';
24
24
  import type { DetachedSpawn } from '../cli/tasks-cli.js';
25
- import { LIVE_MOVE_HISTORY_EVENT, taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
25
+ import { LIVE_MOVE_HISTORY_EVENT, shellQuote, taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
26
+ import { reconcileHandMergedCard } from './postland-card.js';
27
+ import { resolveParentHosts, type ParentHostConfig } from './parent-host.js';
26
28
  import { LIVE_RETRY_MOVES } from './judge.js';
27
29
  import { decisionCardGrounds, decisionRaiseArgs, type DecisionCardEvidence, type NextAction } from './actions.js';
28
30
  import { pendingReviewResults, reviewResultPath, TA_REVIEW_COMPLETION_CARD_ENV, TA_REVIEW_COMPLETION_RESULT_ENV, TA_REVIEW_COMPLETION_STATE_ENV } from './review-result-capture.js';
@@ -83,6 +85,8 @@ export interface LiveMoveDeps {
83
85
  priorDiff?: PriorDiffReader;
84
86
  /** Fresh PR head and draft flag for landing; separate from the unchanged review lookup. */
85
87
  landPrHead?: (pr: number, cwd: string) => Promise<(PrHeadView & { isDraft: boolean }) | null>;
88
+ /** TA-CARD-MERGE-RECONCILE — MERGED PR 의 merge SHA·base·mergedAt 관측(시험 주입 · 기본 = `gh pr view`). */
89
+ handMergePr?: (pr: number, cwd: string) => Promise<HandMergePrView | null>;
86
90
  /** One existing pr land operation; inject in tests instead of invoking the CLI. */
87
91
  /** TA-REJUDGE-ON-HEAD — `opts.overlapEvidence` 가 있으면 `pr land --overlap-evidence <file>` 로 넘긴다(없으면 종전 인자). */
88
92
  land?: (pr: number, head: string, cwd: string, opts?: { overlapEvidence?: string }) => Promise<{ status: number; stdout: string; stderr?: string }>;
@@ -208,25 +212,44 @@ export function liveReviewArgs(entry: string, configDir: string, pr: number, int
208
212
  return [resolve(entry), '--config-dir', configDir, 'self', 'review', String(pr), '--json', '--intent', intent];
209
213
  }
210
214
 
215
+ /** Use the configured node-b checkout for heavy TA workers; absence of parentHost preserves the legacy local path. */
216
+ export function configuredMsb1Worker(): ParentHostConfig | null {
217
+ const setting = getUserConfig().taskAgent?.parentHost;
218
+ if (setting === undefined) return null;
219
+ const target = resolveParentHosts(setting, {} as NodeJS.ProcessEnv).find((entry) => entry.host === 'node-b');
220
+ if (!target) throw new Error('taskAgent.parentHost configured without a valid node-b worker');
221
+ return target;
222
+ }
223
+
224
+ export function remoteTaWorkerCommand(target: ParentHostConfig, args: readonly string[]): string {
225
+ const entry = target.elanous ? shellQuote(target.elanous) : '$HOME/.local/share/elanous/bin/elanous';
226
+ const configDir = target.configDir ? shellQuote(target.configDir) : '$HOME/.elanous';
227
+ return `cd ${shellQuote(target.cwd)} && ${entry} --config-dir ${configDir} ${args.map(shellQuote).join(' ')}`;
228
+ }
229
+
211
230
  /**
212
231
  * 지금 도는 진입점으로 같은 우주의 리뷰를 떼어 띄운다 — 기다리지 않는다(결과는 self review 자기 관측에 남는다).
213
232
  * TA-REVIEW-RESULT-CAPTURE — `resultPath` 가 있으면 자식 stdout(`--json` 결과)만 그 파일로 받는다(stdin·stderr 는 종전대로 버린다 ·
214
233
  * 파이프가 아니라 파일 — 부모가 먼저 끝나도 자식이 EPIPE 로 죽지 않는다). 없으면 종전과 같다(stdio ignore).
215
234
  * `opts` 는 시험 몫(spawn·진입점·우주) — 기본은 실물.
216
235
  */
217
- export async function defaultRequestReview(pr: number, intent: string, cwd?: string, opts: { spawn?: DetachedSpawn; entry?: string; configDir?: string; resultPath?: string; cardId?: string; statePath?: string } = {}): Promise<void> {
236
+ export async function defaultRequestReview(pr: number, intent: string, cwd?: string, opts: { spawn?: DetachedSpawn; entry?: string; configDir?: string; resultPath?: string; cardId?: string; statePath?: string; remote?: ParentHostConfig | null } = {}): Promise<void> {
218
237
  const { spawnDetachedConfirmed, ELANOUS_CLI_ENTRY } = await import('../cli/tasks-cli.js');
219
238
  const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
220
239
  const { effectiveInstanceRoot } = await import('../instance/resolve.js');
221
240
  const configDir = opts.configDir ?? getElanousConfigDirOverride() ?? effectiveInstanceRoot();
222
241
  const base = opts.spawn ?? (spawn as unknown as DetachedSpawn);
242
+ const remote = opts.remote === undefined ? (opts.spawn ? null : configuredMsb1Worker()) : opts.remote;
223
243
  const args = liveReviewArgs(opts.entry ?? ELANOUS_CLI_ENTRY, configDir, pr, intent);
224
244
  const completionEnv = opts.resultPath && opts.cardId && opts.statePath ? {
225
245
  [TA_REVIEW_COMPLETION_CARD_ENV]: opts.cardId,
226
246
  [TA_REVIEW_COMPLETION_STATE_ENV]: opts.statePath,
227
247
  [TA_REVIEW_COMPLETION_RESULT_ENV]: opts.resultPath,
228
248
  } : undefined;
229
- if (!opts.resultPath) { await spawnDetachedConfirmed(base, process.execPath, args, undefined, cwd); return; }
249
+ const workerCommand = remote ? remoteTaWorkerCommand(remote, ['self', 'review', String(pr), '--json', '--model', 'gpt-6-sol', '--intent', intent]) : null;
250
+ const command = remote ? 'ssh' : process.execPath;
251
+ const workerArgs = remote ? ['-T', '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=5', remote.host, workerCommand!] : args;
252
+ if (!opts.resultPath) { await spawnDetachedConfirmed(base, command, workerArgs, undefined, cwd); return; }
230
253
  let fd: number;
231
254
  try {
232
255
  mkdirSync(dirname(opts.resultPath), { recursive: true });
@@ -234,13 +257,13 @@ export async function defaultRequestReview(pr: number, intent: string, cwd?: str
234
257
  } catch (error) {
235
258
  // 결과 파일을 못 열어도 리뷰는 막지 않는다(종전처럼 stdio ignore) — 회수는 상한 뒤 «no result» 줄로 드러난다.
236
259
  try { debug.log('task-agent', 'review-result-file-open-failed', { pr, resultPath: opts.resultPath, reason: (error instanceof Error ? error.message : String(error)).slice(-300) }, { level: 'warn' }); } catch { /* fail-soft */ }
237
- await spawnDetachedConfirmed(base, process.execPath, args, undefined, cwd);
260
+ await spawnDetachedConfirmed(base, command, workerArgs, undefined, cwd);
238
261
  return;
239
262
  }
240
263
  const toFile: DetachedSpawn = (command, spawnArgs, options) =>
241
264
  (base as unknown as (c: string, a: string[], o: unknown) => ReturnType<DetachedSpawn>)(command, spawnArgs, { ...options, stdio: ['ignore', fd, 'ignore'] });
242
265
  try {
243
- await spawnDetachedConfirmed(toFile, process.execPath, args, undefined, cwd, completionEnv);
266
+ await spawnDetachedConfirmed(toFile, command, workerArgs, undefined, cwd, remote ? undefined : completionEnv);
244
267
  } finally {
245
268
  try { closeSync(fd); } catch { /* the child keeps its own copy */ }
246
269
  }
@@ -296,6 +319,35 @@ export async function defaultLandPrHead(pr: number, cwd: string): Promise<(PrHea
296
319
  } catch { return null; }
297
320
  }
298
321
 
322
+ /** TA-CARD-MERGE-RECONCILE — 손수 병합된 PR 의 정산 관측값(merge SHA 가 main 조상 검증의 재료). */
323
+ export interface HandMergePrView {
324
+ state: string;
325
+ url?: string;
326
+ baseRefName?: string;
327
+ mergedAt?: string;
328
+ mergeCommit?: string;
329
+ }
330
+
331
+ export async function defaultHandMergePr(pr: number, cwd: string): Promise<HandMergePrView | null> {
332
+ const view = (env: NodeJS.ProcessEnv) => runGh(['pr', 'view', String(pr), '--json', 'state,url,baseRefName,mergedAt,mergeCommit'], { env, cwd });
333
+ let out = view(process.env);
334
+ if (out.status !== 0) {
335
+ const noProxy = { ...process.env };
336
+ for (const key of ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy']) delete noProxy[key];
337
+ out = view(noProxy);
338
+ }
339
+ if (out.status !== 0) return null;
340
+ try {
341
+ const value = JSON.parse(out.stdout) as { state?: unknown; url?: unknown; baseRefName?: unknown; mergedAt?: unknown; mergeCommit?: { oid?: unknown } | null };
342
+ if (typeof value.state !== 'string') return null;
343
+ return { state: value.state,
344
+ ...(typeof value.url === 'string' && value.url ? { url: value.url } : {}),
345
+ ...(typeof value.baseRefName === 'string' && value.baseRefName ? { baseRefName: value.baseRefName } : {}),
346
+ ...(typeof value.mergedAt === 'string' && value.mergedAt ? { mergedAt: value.mergedAt } : {}),
347
+ ...(typeof value.mergeCommit?.oid === 'string' && /^[a-f0-9]{40}$/i.test(value.mergeCommit.oid) ? { mergeCommit: value.mergeCommit.oid } : {}) };
348
+ } catch { return null; }
349
+ }
350
+
299
351
  /**
300
352
  * REVIEW-CONVERGE-PRIOR-FIX — `prior` 는 같은 PR 의 두 번째 이후 리뷰에만 온다: «직전 반영분»에 직전 머리 범위·diff·must-fix 를,
301
353
  * 범위 경계에 «바뀌지 않은 줄의 새 must-fix 는 근거 줄» 한 줄을 붙인다. 없으면(첫 리뷰) 종전 문면 바이트 그대로.
@@ -402,7 +454,7 @@ export async function executeLiveReview(
402
454
  * (`executeLiveLand` ctx `gateAt` = 그 재게이트 요청 시각)에만 이 시도는 «소비됨»으로 빠진다. judgement·infra 와 섞이지 않는다.
403
455
  */
404
456
  export const LAND_ATTEMPTS_PER_HEAD_ON_INFRA = 2;
405
- export type LandFailureClass = 'infra' | 'judgement' | 'base-stale';
457
+ export type LandFailureClass = 'infra' | 'judgement' | 'base-stale' | 'recovery';
406
458
 
407
459
  /** `pr land` 출력 줄 → 인프라 사유. ⛔ 줄 «전체»가 맞아야 한다 — 비슷한 문면을 넓게 받지 않는다. */
408
460
  export const LAND_INFRA_OUTPUT_REASONS: ReadonlyArray<{ reason: string; line: RegExp }> = [
@@ -422,6 +474,8 @@ const LAND_INFRA_CONSEQUENCE_LINES: ReadonlyArray<{ of: string; line: RegExp }>
422
474
  ];
423
475
  /** REJUDGE base-stale — 겹침 증거의 게이트 base 가 낡았고 그 사이 착지가 PR 파일을 건드렸다(`pr land` · #26060 문면). */
424
476
  const LAND_BASE_STALE_LINE = /^✗ overlap-evidence: (base-stale-overlap: .*)$/;
477
+ const LAND_RECOVER_REVIEW = /^✗ (?:ancestor-auto|overlap-evidence): (?:review-missing|review-not-reviewed|review-error|review-no-result|review-unreadable|review-pr-mismatch|review-head-mismatch|review-path-not-for-this-pr-head|review-verdict-null|review-must-fix-unknown)(?:\b|$)/;
478
+ const LAND_RECOVER_BUSY = /^✗ heavy-remote: (?:원격|병합 직전 원격|node-b) 게이트 gate-host-busy(?:\b|\s|$)/;
425
479
  /** base-stale 에 «딸려 나오는» 줄 — 증거가 거절되면 `pr land` 가 이어서 낸다(그 줄만 있으면 판정 거절로 세지 않는다). */
426
480
  const LAND_BASE_STALE_CONSEQUENCE_LINES: readonly RegExp[] = [/^✗ expected-head: overlap merge approval unavailable for the reviewed head$/];
427
481
  /** 실패가 아닌 ✗ 줄 — `pr land` 가 «계속합니다»로 넘어간다(판정에 쓰지 않는다). */
@@ -464,6 +518,10 @@ export function classifyLandFailure(outcome: { status: number; stdout?: string;
464
518
  if (hit) infra.add(hit.reason); else unlisted.push(line);
465
519
  }
466
520
  const judged = unlisted.filter((line) => !LAND_INFRA_CONSEQUENCE_LINES.some((entry) => infra.has(entry.of) && entry.line.test(line)));
521
+ if (judged.length === 1 && !infra.size) {
522
+ if (LAND_RECOVER_REVIEW.test(judged[0]!)) return { class: 'recovery', reason: 'review-missing' };
523
+ if (LAND_RECOVER_BUSY.test(judged[0]!)) return { class: 'recovery', reason: 'gate-host-busy' };
524
+ }
467
525
  // REJUDGE base-stale — 거절 줄이 base-stale-overlap(⊕ 딸린 줄) «뿐»이고 인프라 사유가 없을 때만. 하나라도 다른 ✗ 줄이 섞이면 judgement(fail-closed).
468
526
  const stale = judged.map((line) => LAND_BASE_STALE_LINE.exec(line)?.[1]).find((reason): reason is string => !!reason);
469
527
  if (stale && !infra.size && judged.every((line) => LAND_BASE_STALE_LINE.test(line) || LAND_BASE_STALE_CONSEQUENCE_LINES.some((re) => re.test(line)))) {
@@ -520,7 +578,20 @@ function observeLandWorktreeCreateCapped(deps: LiveMoveDeps, data: { card: strin
520
578
  /** 같은 머리에 한 번 더 시도해도 되나 — 앞 시도가 «전부» 끝났고(ok:false) «전부» infra 이고 상한 밑일 때만. */
521
579
  function landRetryAllowed(prior: readonly LandAttempt[]): boolean {
522
580
  return prior.length > 0 && prior.length < LAND_ATTEMPTS_PER_HEAD_ON_INFRA
523
- && prior.every((entry) => entry.ok === false && (entry.class === 'infra' || legacyMissingTscRuntime(entry)));
581
+ && prior.every((entry) => entry.ok === false && (entry.class === 'infra' || entry.class === 'recovery' || legacyMissingTscRuntime(entry)));
582
+ }
583
+
584
+ function recoveryAdmissionReady(card: TaskCard, prior: readonly LandAttempt[], pr: number, head: string, nowMs = Date.now()): boolean {
585
+ const last = prior.at(-1);
586
+ if (last?.class !== 'recovery') return true;
587
+ if (last.reason === 'gate-host-busy') return nowMs >= Date.parse(last.at) + 30_000
588
+ && (card.history ?? []).some((event) => event.event === 'rejudge-on-head' && event.kind === 'land'
589
+ && event.effect === 'recover-wait-retry' && event.pr === pr && event.head?.toLowerCase() === head.toLowerCase()
590
+ && Date.parse(event.at) >= Date.parse(last.at));
591
+ if (last.reason === 'review-missing') return (card.reviewRequests ?? []).some((request) => request.pr === pr
592
+ && request.head.toLowerCase() === head.toLowerCase() && Date.parse(request.at) >= Date.parse(last.at) && !request.error)
593
+ && !pendingReviewResults(card).some((request) => request.pr === pr && request.head.toLowerCase() === head.toLowerCase());
594
+ return false;
524
595
  }
525
596
 
526
597
  /** A previous release classified a missing node interpreter as judgement; only that exact recorded shape may be reopened. */
@@ -541,8 +612,9 @@ export function openLandAttempts<T extends Pick<LandAttempt, 'at' | 'class'>>(pr
541
612
  }
542
613
 
543
614
  /** 카드의 이 PR·머리에 인프라 재시도가 남았나(재판정 틱이 «머리 그대로»여도 land 단계까지 가게). */
544
- export function landRetryPending(card: Pick<TaskCard, 'landAttempts'>, pr: number, head: string): boolean {
545
- return landRetryAllowed((card.landAttempts ?? []).filter(sameHeadOf(pr, head)));
615
+ export function landRetryPending(card: TaskCard, pr: number, head: string): boolean {
616
+ const attempts = (card.landAttempts ?? []).filter(sameHeadOf(pr, head));
617
+ return landRetryAllowed(attempts) && recoveryAdmissionReady(card, attempts, pr, head);
546
618
  }
547
619
 
548
620
  export const LAND_RETRY_ON_INFRA_EVENT = 'land-retry-on-infra';
@@ -575,7 +647,21 @@ export async function executeLiveLand(
575
647
  let view: (PrHeadView & { isDraft: boolean }) | null;
576
648
  try { view = await (deps.landPrHead ?? defaultLandPrHead)(pr, cwd); } catch { view = null; }
577
649
  if (!view || !/^[0-9a-f]{40}$/i.test(view.head)) return reject(card.id, `PR #${pr} head unknown`, reviewRepo);
578
- if (view.state !== 'OPEN') return reject(card.id, `PR #${pr} is ${view.state}`, reviewRepo);
650
+ if (view.state !== 'OPEN') {
651
+ // TA-CARD-MERGE-RECONCILE — 실패 카드에 묶인 PR을 사람이 손수 병합한 경우만 이 자리에서 정산한다; 정산이 아니면 종전 거절 그대로.
652
+ if (view.state === 'MERGED') {
653
+ let hand: HandMergePrView | null = null;
654
+ try { hand = await (deps.handMergePr ?? defaultHandMergePr)(pr, cwd); } catch { hand = null; }
655
+ if (hand?.mergeCommit) {
656
+ const settled = reconcileHandMergedCard({ number: pr, url: hand.url ?? view.url ?? '', headRefOid: view.head, state: 'MERGED',
657
+ baseRefName: hand.baseRefName ?? 'main', mergedAt: hand.mergedAt ?? '', mergeCommit: hand.mergeCommit },
658
+ cwd, deps.statePath ? { statePath: deps.statePath } : {});
659
+ if (settled.outcome === 'reconciled')
660
+ return withRepo(observe(deps, { kind, card: card.id, ok: true, executed: true, detail: `PR #${pr} 손 병합 정산 — card ${settled.status} (merge ${settled.mergeSha.slice(0, 12)})` }));
661
+ }
662
+ }
663
+ return reject(card.id, `PR #${pr} is ${view.state}`, reviewRepo);
664
+ }
579
665
  if (view.isDraft !== false) return reject(card.id, `PR #${pr} is draft or draft status unknown`, reviewRepo);
580
666
  if (ctx.produced?.prUrl && (!view.url || view.url.trim().replace(/\/+$/, '').toLowerCase() !== ctx.produced.prUrl.trim().replace(/\/+$/, '').toLowerCase())) {
581
667
  return reject(card.id, `PR #${pr} URL mismatches run evidence`, reviewRepo);
@@ -622,7 +708,7 @@ export async function executeLiveLand(
622
708
  }
623
709
  }
624
710
  prior = openLandAttempts((current.landAttempts ?? []).filter(sameHeadOf(pr, view!.head)), ctx.gateAt);
625
- if (prior.length && !landRetryAllowed(prior)) return undefined;
711
+ if (prior.length && (!landRetryAllowed(prior) || !recoveryAdmissionReady(current, prior, pr, view!.head, (deps.now ?? (() => new Date()))().getTime()))) return undefined;
626
712
  claimed = true;
627
713
  return { ...current, landAttempts: [...(current.landAttempts ?? []), { pr, head: view!.head, at }] };
628
714
  });
@@ -721,7 +807,7 @@ export async function executeLiveLand(
721
807
  detail = (error instanceof Error ? error.message : String(error)).slice(-300);
722
808
  failure = classifyLandFailure({ thrown: detail });
723
809
  }
724
- const retryAllowed = failure?.class === 'infra' && attempt < LAND_ATTEMPTS_PER_HEAD_ON_INFRA;
810
+ const retryAllowed = (failure?.class === 'infra' || failure?.class === 'recovery') && attempt < LAND_ATTEMPTS_PER_HEAD_ON_INFRA;
725
811
  // 인프라 실패로 재시도가 남으면 주기 표시도 푼다 — 같은 주기 id(재판정 틱의 `rejudge:<card>:<head>`)가 그 한 번을 막지 않게.
726
812
  if (retryAllowed && cycle) landedCycles.delete(cycle);
727
813
  if (worktree && queueConfig && ok) {
@@ -16,6 +16,8 @@ import { createHash } from 'node:crypto';
16
16
  import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
17
17
  import { join, resolve } from 'node:path';
18
18
  import { debug } from '../debug/log.js';
19
+ import { memoryQuantityBytes } from '../task-orchestrator/surfaces/pod-lease.js';
20
+ import { parsePodPool } from '../task-orchestrator/surfaces/pod-pool.js';
19
21
  import { shellQuote } from './task-hand.js';
20
22
 
21
23
  /** `taskAgent.parentHost` 설정 칸. */
@@ -42,6 +44,11 @@ const DEFAULT_REMOTE_ELANOUS = '$HOME/.local/share/elanous/bin/elanous';
42
44
  const DEFAULT_REMOTE_CONFIG_DIR = '$HOME/.elanous';
43
45
  const HOST_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]{0,127}$/;
44
46
 
47
+ /** Missing child-provider metadata keeps the established Pod default: the HQ Codex mirror is needed. */
48
+ export function shouldInstallRemoteCodexAccess(effectiveChildProvider: string | undefined): boolean {
49
+ return effectiveChildProvider === undefined || effectiveChildProvider === 'openai-codex';
50
+ }
51
+
45
52
  /**
46
53
  * 켜졌나 — env 가 이긴다(`off`·`0`·빈 값이면 끔). env 가 호스트를 주면 나머지 칸(cwd 등)은 설정에서 받는다.
47
54
  * cwd 가 없으면 켜지지 않는다(어디서 띄울지 모르는 원격 발사는 하지 않는다).
@@ -74,6 +81,50 @@ export function resolveParentHosts(config: ParentHostSetting | undefined, env: N
74
81
 
75
82
  /** Capacity sample is read on the host before launch. Unknown or saturated capacity is not a positive weight. */
76
83
  export interface ParentHostCapacity { approvalHeadroom: number; load: number }
84
+
85
+ export interface ParentHostPodFit {
86
+ state: 'fits' | 'never-fits' | 'unmeasured';
87
+ memoryLimit: string;
88
+ requiredBytes: number | null;
89
+ allocatableBytes: number | null;
90
+ reason: string;
91
+ }
92
+
93
+ /** Read node allocatable memory only. This preflight never creates a probe Pod. */
94
+ export function readParentHostPodFit(target: ParentHostConfig, memoryLimit: string, ssh: SshRunner = defaultSshRunner): ParentHostPodFit {
95
+ const requiredBytes = memoryQuantityBytes(memoryLimit);
96
+ const unknown = (reason: string, allocatableBytes: number | null = null): ParentHostPodFit =>
97
+ ({ state: 'unmeasured', memoryLimit, requiredBytes, allocatableBytes, reason });
98
+ if (requiredBytes === null || requiredBytes <= 0) return unknown('memory-limit-unreadable');
99
+ // Without an explicit pool, the remote current kubectl context may be unrelated to the launched Job.
100
+ if (!target.podPool) return unknown('pod-pool-unset');
101
+ let members: ReturnType<typeof parsePodPool>;
102
+ try { members = parsePodPool(target.podPool); }
103
+ catch { return unknown('pod-pool-unreadable'); }
104
+ if (!members.length) return unknown('pod-pool-empty');
105
+ let maximum = 0;
106
+ let unreadable = false;
107
+ for (const member of members) {
108
+ let result: ReturnType<SshRunner>;
109
+ try { result = ssh(target.host, `kubectl --context ${shellQuote(member.context)} get nodes -o json`, 15_000); }
110
+ catch { unreadable = true; continue; }
111
+ if (result.status !== 0) { unreadable = true; continue; }
112
+ try {
113
+ const parsed = JSON.parse(result.stdout) as { items?: Array<{ status?: { allocatable?: { memory?: unknown } } }> };
114
+ if (!Array.isArray(parsed.items) || parsed.items.length === 0) { unreadable = true; continue; }
115
+ for (const node of parsed.items) {
116
+ const raw = node?.status?.allocatable?.memory;
117
+ const bytes = typeof raw === 'string' ? memoryQuantityBytes(raw) : null;
118
+ if (bytes === null || bytes <= 0) { unreadable = true; continue; }
119
+ maximum = Math.max(maximum, bytes);
120
+ }
121
+ } catch { unreadable = true; }
122
+ }
123
+ if (maximum >= requiredBytes) return { state: 'fits', memoryLimit, requiredBytes, allocatableBytes: maximum, reason: 'node-allocatable-fits' };
124
+ if (unreadable || maximum === 0) return unknown('node-allocatable-unmeasured', maximum || null);
125
+ return { state: 'never-fits', memoryLimit, requiredBytes, allocatableBytes: maximum, reason: 'memory-never-fits' };
126
+ }
127
+
77
128
  const CAPACITY_MARKER = '__ELANOUS_PARENT_CAPACITY__';
78
129
  const APPROVAL_MARKER = '__ELANOUS_PARENT_APPROVALS__';
79
130
  const LOAD_MARKER = '__ELANOUS_PARENT_LOAD__';
@@ -170,10 +221,12 @@ export function remoteLaunchScript(target: ParentHostConfig, args: readonly stri
170
221
  }
171
222
 
172
223
  /** ssh 실행기(시험 주입). */
173
- export type SshRunner = (host: string, script: string, timeoutMs: number) => { status: number | null; stdout: string; stderr: string };
224
+ export type SshRunner = (host: string, script: string, timeoutMs: number, stdin?: string) => { status: number | null; stdout: string; stderr: string };
174
225
 
175
- export const defaultSshRunner: SshRunner = (host, script, timeoutMs) => {
176
- const result = spawnSync('ssh', ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=8', '-o', 'ControlPath=none', host, script], { encoding: 'utf8', timeout: timeoutMs, maxBuffer: 32 * 1024 * 1024 });
226
+ export const defaultSshRunner: SshRunner = (host, script, timeoutMs, stdin) => {
227
+ const result = spawnSync('ssh', ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=8', '-o', 'ControlPath=none', host, script], {
228
+ encoding: 'utf8', timeout: timeoutMs, maxBuffer: 32 * 1024 * 1024, ...(stdin !== undefined ? { input: stdin } : {}),
229
+ });
177
230
  return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? (result.error ? String(result.error) : '') };
178
231
  };
179
232
 
@@ -302,6 +355,43 @@ export function launchRemoteParent(target: ParentHostConfig, args: readonly stri
302
355
  throw new Error(`원격 부모 발사 결과 불확실(${target.host} · rc=${result.status}) — 중복을 피해 로컬로 다시 띄우지 않는다 · 원격에서 ELANOUS_RUN_ID=${env.ELANOUS_RUN_ID ?? '?'} 를 확인: ${(result.stderr.trim().split('\n').pop() || '').slice(0, 160)}`);
303
356
  }
304
357
 
358
+ /** Install access-only Codex copies over SSH stdin; credentials never enter argv, shell text, or logs. */
359
+ export function installRemoteCodexAccess(target: ParentHostConfig, mirror: { elanousAuth: string; codexAuth: string; account?: string }, ssh: SshRunner = defaultSshRunner): void {
360
+ let elanous: { version?: number; providers?: Record<string, Record<string, unknown>> };
361
+ let codex: { auth_mode?: string; tokens?: Record<string, unknown> };
362
+ try {
363
+ elanous = JSON.parse(mirror.elanousAuth) as typeof elanous;
364
+ codex = JSON.parse(mirror.codexAuth) as typeof codex;
365
+ } catch { throw new Error('invalid local Codex access mirror'); }
366
+ const provider = elanous.providers?.['openai-codex'];
367
+ const elanousTokens = provider?.tokens as Record<string, unknown> | undefined;
368
+ const codexTokens = codex.tokens;
369
+ if (!Number.isSafeInteger(elanous.version) || Number(elanous.version) < 1
370
+ || typeof elanousTokens?.accessToken !== 'string' || !elanousTokens.accessToken || elanousTokens.refreshToken !== '' || elanousTokens.refresh_token !== ''
371
+ || codex.auth_mode !== 'chatgpt'
372
+ || typeof codexTokens?.access_token !== 'string' || !codexTokens.access_token || codexTokens.refresh_token !== '' || codexTokens.refreshToken !== '')
373
+ throw new Error('Codex access mirror must contain a versioned store, auth mode, access tokens, and empty refresh tokens');
374
+
375
+ const account = mirror.account ?? 'default';
376
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(account)) throw new Error('invalid Codex mirror account name');
377
+
378
+ const payload = JSON.stringify({ elanousVersion: elanous.version, provider, codexAuth: codex, account, storeKey: account === 'default' ? 'openai-codex' : `openai-codex:${account}` });
379
+ const configDir = remotePath(target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR);
380
+ // HQ owns token metadata; the remote keeps only the selected named Codex credential in managed account homes.
381
+ const code = [
382
+ 'const fs=require("node:fs"),path=require("node:path"),os=require("node:os");',
383
+ 'const payload=JSON.parse(fs.readFileSync(0,"utf8"));',
384
+ 'const read=(file)=>{try{return JSON.parse(fs.readFileSync(file,"utf8"))}catch{return {}}};',
385
+ 'const write=(file,value)=>{const temp=file+"."+process.pid+".tmp";try{fs.writeFileSync(temp,JSON.stringify(value),{mode:0o600});fs.chmodSync(temp,0o600);fs.renameSync(temp,file)}catch(error){try{fs.unlinkSync(temp)}catch{};throw error}};',
386
+ 'const elanousFile=path.join(process.argv[1],"auth.json"),configDir=path.dirname(elanousFile);fs.mkdirSync(configDir,{recursive:true,mode:0o700});',
387
+ 'const elanous=read(elanousFile);if(typeof elanous.version!=="number")elanous.version=payload.elanousVersion;elanous.providers={...(elanous.providers||{})};const defaultHome=path.join(os.homedir(),".codex"),managedAccounts=path.join(configDir,"codex-accounts");for(const key of Object.keys(elanous.providers)){if(key.startsWith("openai-codex:"))delete elanous.providers[key]}fs.rmSync(managedAccounts,{recursive:true,force:true});fs.rmSync(path.join(configDir,"remote-codex-mirror.json"),{force:true});',
388
+ 'const accountHome=payload.account==="default"?defaultHome:path.join(configDir,"codex-accounts",payload.account),tokens={...(payload.provider.tokens||{}),refreshToken:"",refresh_token:""};const upsert=(key,codexHome)=>{const current=elanous.providers[key]||{};elanous.providers[key]={...current,...payload.provider,codexHome,chatGPT:{...(current.chatGPT||{}),...(payload.provider.chatGPT||{})},tokens}};upsert("openai-codex",defaultHome);if(payload.storeKey!=="openai-codex")upsert(payload.storeKey,accountHome);write(elanousFile,elanous);',
389
+ 'const incoming=payload.codexAuth;const installCodex=(home)=>{const file=path.join(home,"auth.json");fs.mkdirSync(home,{recursive:true,mode:0o700});const current=read(file),merged={...current,...incoming};merged.auth_mode=incoming.auth_mode;if(Object.prototype.hasOwnProperty.call(incoming,"last_refresh"))merged.last_refresh=incoming.last_refresh;else delete merged.last_refresh;merged.tokens={...(incoming.tokens||{}),refresh_token:"",refreshToken:""};write(file,merged)};installCodex(defaultHome);if(accountHome!==defaultHome)installCodex(accountHome);',
390
+ ].join('');
391
+ const result = ssh(target.host, `umask 077; mkdir -p ${configDir} "$HOME/.codex" && bun -e ${shellQuote(code)} ${configDir}`, 20_000, payload);
392
+ if (result.status !== 0) throw new Error(`remote Codex access mirror failed (ssh rc=${result.status ?? 'unknown'})`);
393
+ }
394
+
305
395
  // ── 관측: 원격 런 원장 거울 ─────────────────────────────────────────────────────────────
306
396
 
307
397
  const RUN_ID_RE = /^run-[A-Za-z0-9_-]{4,64}$/;