elanous 0.2.29 → 0.2.31

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 (709) 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/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{058a98ba.7eb28d5e6dc03565.js → 0bb0ff36.b8d418980951e5ba.js} +7 -7
  5. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +27 -0
  8. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +287 -0
  9. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +62 -0
  10. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{6013-2f769370d8b4c2c6.js → 1335-6731f392c35216eb.js} +3 -3
  12. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{8332.6f0f49df772e163b.js → 1654.32de4b324981a188.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +149 -0
  17. package/apps/pwa/out/_next/static/chunks/{8795.32573a185af18c7b.js → 1913.7cc6fb6055b1ed3f.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/{419.736c0d6f426249a7.js → 2001.6c7e0fd02190886c.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6767.1fcfc9b8be83975f.js → 2213.2ccbada92c33ea0f.js} +16 -16
  24. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{4759.1f76713aefb87db5.js → 2871.0bca6137343b3f76.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/{6776.06ff1e3b464cc607.js → 2898.fd781bc7cf01a7b7.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{1782-59db1b5aa06df38a.js → 2940-619bfd8ef337c611.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/{8471.8d2a8c74f09c36ff.js → 2985.39ccdecd36848b12.js} +4 -4
  31. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +115 -0
  32. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +64 -0
  33. package/apps/pwa/out/_next/static/chunks/{bc324b7c.02a09dd93f6a399b.js → 3267c0e6.d34854e7b3984a6e.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3278.2e5d15b53a4091c8.js +2 -0
  35. package/apps/pwa/out/_next/static/chunks/{7725-4f83d5541fbdb81b.js → 3541-ce3a5424ed5ad7f1.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +34 -0
  39. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/{46bd8bea.2f4b4099172fcdb7.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{1142.65d002789ab3af7d.js → 4174.92ed04922709ac9e.js} +2 -2
  43. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +36 -0
  45. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +286 -0
  49. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +77 -0
  50. package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +226 -0
  51. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +79 -0
  53. package/apps/pwa/out/_next/static/chunks/5173-233188df2f42c626.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/5307.60f2209e809bd627.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{3396-97b97928c49190c9.js → 5458-16cd7a2b51b74c8c.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/{3403.7199205e65124486.js → 5525.86debf231e181813.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9143.ff14585db1d275ff.js → 5543.a438b8ab5a13ea47.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +74 -0
  65. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +94 -0
  67. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{8398.73a19b39715eda04.js → 6092.a7f99e68b188ca66.js} +1 -1
  70. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/{5591.a35e7a217734a8b9.js → 6157.0c9af021de4fb31b.js} +2 -2
  72. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{7375.050ea0d72968e49f.js → 6433.fc573af22bbc9ab7.js} +17 -17
  75. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +90 -0
  77. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +32 -0
  78. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +104 -0
  80. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +24 -0
  85. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +93 -0
  86. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
  93. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
  94. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
  109. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
  121. package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-a5635eba0d73b84e.js → page-2ebb8fd59b9461f9.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0a07363b130182a1.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-521ee23ac8c0abfa.js} +1 -1
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-9f92737b8766009a.js → page-149dc1caba411bb9.js} +1 -1
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
  175. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
  183. package/apps/pwa/out/_next/static/css/{72becfd42807b50d.css → 3f5fc6f96e2cf7b2.css} +1 -1
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +23 -23
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +23 -23
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +23 -23
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +22 -22
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +22 -22
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +23 -23
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +22 -22
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +23 -23
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +23 -23
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +22 -22
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +23 -23
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +23 -23
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +23 -23
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +23 -23
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +22 -22
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +22 -22
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +23 -23
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +23 -23
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +23 -23
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +22 -22
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +22 -22
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +23 -23
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +23 -23
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +22 -22
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +22 -22
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +22 -22
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +23 -23
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +23 -23
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +22 -22
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +23 -23
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +23 -23
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +23 -23
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +23 -23
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +23 -23
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +22 -22
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +23 -23
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +23 -23
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +23 -23
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +23 -23
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +23 -23
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +23 -23
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +23 -23
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +23 -23
  277. package/bin/elanous.mjs +7 -3
  278. package/graphs/context/nightly-condense.yaml +1 -0
  279. package/graphs/intake/intake-daily.yaml +8 -1
  280. package/graphs/intake/recipes.yaml +5 -0
  281. package/graphs/lecture/lecture-note.yaml +2 -2
  282. package/graphs/ops/harness-gc.yaml +1 -0
  283. package/graphs/release/recipes.yaml +3 -0
  284. package/graphs/release/release-loop.yaml +9 -5
  285. package/graphs/units/recipes.yaml +3 -0
  286. package/graphs/units/release-gate-recheck.yaml +15 -0
  287. package/package.json +2 -1
  288. package/scripts/check-native-tool-wiring.ts +3 -2
  289. package/scripts/ci-android-unit-tests.ts +16 -0
  290. package/scripts/ci-typecheck-changed.ts +37 -9
  291. package/scripts/coord-channel-watch.sh +22 -16
  292. package/scripts/coord-role-pack.ts +81 -2
  293. package/scripts/cron-run.ts +96 -3
  294. package/scripts/detect-test-interference.ts +38 -5
  295. package/scripts/gate-pr-cache.ts +65 -0
  296. package/scripts/gh-surface/capture.ts +126 -0
  297. package/scripts/gh-surface/gh +40 -0
  298. package/scripts/import-graph-scc.ts +38 -0
  299. package/scripts/install.ps1 +19 -0
  300. package/scripts/intake-social.ts +181 -0
  301. package/scripts/lecture-note/node.ts +71 -4
  302. package/scripts/lib/android-toolchain.ts +32 -0
  303. package/scripts/lib/deterministic-env.ts +62 -0
  304. package/scripts/lib/gate-test-env.ts +19 -0
  305. package/scripts/measure-goal-grounding-corpus.ts +2 -1
  306. package/scripts/ratchets/test-interference-patterns.allowlist.txt +257 -0
  307. package/scripts/ratchets/test-interference-patterns.ts +367 -0
  308. package/scripts/release-loop/cut-branch.ts +4 -3
  309. package/scripts/release-loop/export-check-node.ts +0 -1
  310. package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
  311. package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
  312. package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
  313. package/scripts/release-loop/gate-closure.ts +12 -8
  314. package/scripts/release-loop/gate-diff.ts +1 -1
  315. package/scripts/release-loop/gate-host-mirror.ts +66 -0
  316. package/scripts/release-loop/gate-node.ts +523 -75
  317. package/scripts/release-loop/gate-partial.ts +106 -9
  318. package/scripts/release-loop/gate-pr-cache.ts +66 -0
  319. package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
  320. package/scripts/release-loop/gate-r2-verdict.ts +189 -0
  321. package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
  322. package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
  323. package/scripts/release-loop/import-graph-scc-run.ts +54 -0
  324. package/scripts/release-loop/import-graph-scc.ts +215 -0
  325. package/scripts/release-loop/node-verdict.ts +2 -0
  326. package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
  327. package/scripts/release-loop/resume-release.ts +33 -4
  328. package/scripts/release-loop/resume.ts +13 -5
  329. package/scripts/release-loop/spawn-lane.ts +2 -19
  330. package/scripts/release-loop/tui-sim-node.ts +3 -2
  331. package/scripts/release-loop/unattended-release.ts +16 -0
  332. package/scripts/test-deterministic.ts +5 -61
  333. package/scripts/train-reach-grouping.ts +48 -0
  334. package/scripts/tsc-incremental-cache.ts +86 -0
  335. package/scripts/tsc-incremental-diagnostics.ts +76 -0
  336. package/scripts/tsc-main-safety-net.ts +2 -2
  337. package/src/acp/client.ts +4 -1
  338. package/src/acp/core-turn-bridge.ts +50 -5
  339. package/src/ad-pipeline/run.ts +4 -2
  340. package/src/agent/runner.ts +169 -3
  341. package/src/agent/subagent-callable.ts +3 -2
  342. package/src/agent-mission/review-loop.ts +6 -3
  343. package/src/agent-substrate/acp-implementer.ts +14 -2
  344. package/src/agent-substrate/pr-reviewer.ts +12 -0
  345. package/src/agent-substrate/self-review-cli.ts +30 -4
  346. package/src/autopilot/pr-manager.ts +62 -7
  347. package/src/briefing/brief-items.ts +24 -22
  348. package/src/capture/tui-self-report.ts +15 -0
  349. package/src/chat/chat-cli.ts +10 -2
  350. package/src/chat/index.ts +77 -11
  351. package/src/chat/input-control-key.ts +5 -3
  352. package/src/chat/tool-interrupt-behavior.ts +38 -0
  353. package/src/chat/tool-render/dispatch.ts +5 -1
  354. package/src/chat/turn-typeahead.ts +75 -20
  355. package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
  356. package/src/cli/agent-cli.ts +41 -13
  357. package/src/cli/config-audit.ts +123 -0
  358. package/src/cli/decisions-cli.ts +80 -6
  359. package/src/cli/log-event-names.ts +7 -0
  360. package/src/cli/mcp-login.ts +21 -5
  361. package/src/cli/msg-cli.ts +88 -0
  362. package/src/cli/pr-cli.ts +214 -57
  363. package/src/cli/pr-land-heavy-remote.ts +2 -2
  364. package/src/cli/pr-land-overlap-evidence.ts +63 -9
  365. package/src/cli/pr-land-pod-shadow-job.ts +83 -0
  366. package/src/cli/pr-land-pod-shadow.ts +16 -3
  367. package/src/cli/pr-land-virtual-rebase.ts +108 -0
  368. package/src/cli/release-cli.ts +80 -14
  369. package/src/cli/seat-cli.ts +138 -3
  370. package/src/cli/self-update.ts +5 -2
  371. package/src/cli/tasks-cli.ts +97 -19
  372. package/src/context-bus/context-first.ts +13 -0
  373. package/src/context-bus/context-now.ts +13 -2
  374. package/src/context-bus/ops-events.ts +75 -0
  375. package/src/control-plane/lease-holder.ts +12 -8
  376. package/src/control-plane/ledger.ts +163 -4
  377. package/src/control-plane/server.ts +91 -11
  378. package/src/core-turn/run-core-turn.ts +1 -0
  379. package/src/core-turn/run-goal-loop.ts +222 -3
  380. package/src/core-turn/seat-turn-cap.ts +79 -0
  381. package/src/core-turn/short-question.ts +38 -6
  382. package/src/core-turn/types.ts +3 -0
  383. package/src/dashboard/acp-boot.ts +3 -0
  384. package/src/dashboard/index.ts +224 -615
  385. package/src/dashboard/input/chat-main-entry-runtime.ts +1 -1
  386. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
  387. package/src/dashboard/input/chat-main-session.ts +8 -1
  388. package/src/dashboard/input/chat-main-turn.ts +12 -3
  389. package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
  390. package/src/dashboard/input/external-input-host.ts +26 -0
  391. package/src/dashboard/input/internal-turn.ts +261 -0
  392. package/src/dashboard/input/seat-autowake.ts +318 -0
  393. package/src/dashboard/input/turn-steer-bridge.ts +70 -0
  394. package/src/dashboard/loop-scheduler.ts +72 -0
  395. package/src/dashboard/seat-boot-preamble.ts +18 -0
  396. package/src/dashboard/skill-runtime.ts +2 -0
  397. package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
  398. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
  399. package/src/dashboard/slash-runtime/index.ts +13 -0
  400. package/src/dashboard/turn-busy-teardown.ts +50 -0
  401. package/src/decisions/decision-ledger.ts +45 -4
  402. package/src/discord-self-message.ts +4 -4
  403. package/src/domains/release-tool.ts +18 -1
  404. package/src/field-note/transcribe.ts +17 -0
  405. package/src/github/remote-call.ts +81 -0
  406. package/src/goals/registry.ts +46 -6
  407. package/src/goals/types.ts +7 -1
  408. package/src/graph-runner/runner.ts +1 -0
  409. package/src/grok/credential.ts +26 -0
  410. package/src/harness/harness-clean.ts +2 -1
  411. package/src/harness/harness-cli-command.ts +52 -5
  412. package/src/harness/harness-gc.ts +2 -1
  413. package/src/harness/harness-incidents.ts +57 -20
  414. package/src/harness/harness-pod-dispatch.ts +87 -10
  415. package/src/harness/harness-queue.ts +53 -4
  416. package/src/harness/harness-stop.ts +4 -3
  417. package/src/harness/harness-substrate-default.ts +78 -7
  418. package/src/harness/harness-worktree-auto.ts +2 -1
  419. package/src/harness/harness-worktrees.ts +3 -2
  420. package/src/hooks/dispatch.ts +2 -1
  421. package/src/index.ts +152 -25
  422. package/src/input/external-input-queue.ts +33 -1
  423. package/src/intake-plane/slash.ts +14 -3
  424. package/src/keybindings.ts +4 -1
  425. package/src/llm/tool-loop-steered-rejection.ts +33 -0
  426. package/src/llm.ts +138 -19
  427. package/src/loops/consensus.ts +348 -0
  428. package/src/loops/msg-wake.ts +206 -4
  429. package/src/loops/observe.ts +19 -3
  430. package/src/loops/orchestrator/tick.ts +64 -10
  431. package/src/loops/orchestrator/traffic.ts +64 -1
  432. package/src/loops/registry.ts +30 -0
  433. package/src/market/signed-index.ts +14 -0
  434. package/src/mcp/mcp-oauth.ts +54 -5
  435. package/src/models/prompts.ts +28 -0
  436. package/src/msg/msg-sse-client.ts +223 -0
  437. package/src/msg/msg-store.ts +86 -2
  438. package/src/mss/logging/log-store.ts +225 -1
  439. package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
  440. package/src/nexus/api/http-server.ts +54 -15
  441. package/src/nexus/api/loop-resources.ts +19 -3
  442. package/src/nexus/api/ops-api.ts +11 -0
  443. package/src/nexus/daemon-thin-inventory.md +37 -0
  444. package/src/nexus/index.ts +70 -0
  445. package/src/nexus/state/state.ts +1 -0
  446. package/src/oauth/store.ts +32 -7
  447. package/src/onboarding/first-run.ts +28 -3
  448. package/src/ops/overview-cache.ts +16 -4
  449. package/src/ops/resources.ts +82 -0
  450. package/src/plugins/maker/connector-maker.ts +41 -0
  451. package/src/plugins/maker/skill-maker.ts +42 -0
  452. package/src/pr-tool/census.ts +288 -0
  453. package/src/prompt-library/chat-conciseness.ts +13 -0
  454. package/src/prompt-library/universal-preamble.ts +10 -5
  455. package/src/release-loop/gate-host-reservation.ts +97 -0
  456. package/src/release-loop/landing-freeze.ts +5 -0
  457. package/src/release-loop/light-rc.ts +5 -2
  458. package/src/release-loop/placement.ts +92 -1
  459. package/src/release-loop/rehearsal-shard-plan.ts +149 -0
  460. package/src/release-loop/rehearsal.ts +73 -17
  461. package/src/repl/index.ts +20 -2
  462. package/src/seat-loop/seat-knowhow.ts +282 -0
  463. package/src/seat-loop/seat-loop.ts +41 -2
  464. package/src/seat-loop/traffic-signal.ts +3 -0
  465. package/src/self-dev/ask-launch-flow.ts +24 -3
  466. package/src/self-dev/decompose-compose-graph.ts +28 -27
  467. package/src/self-dev/decompose-proposal.ts +53 -38
  468. package/src/self-dev/decompose.ts +17 -0
  469. package/src/self-dev/dev-pipeline.ts +31 -2
  470. package/src/self-dev/draft-residue.ts +24 -9
  471. package/src/self-dev/draft-sweep.ts +59 -4
  472. package/src/self-dev/external-call-zero.ts +77 -0
  473. package/src/self-dev/launch-preflight-text.ts +6 -0
  474. package/src/self-dev/launch-preflight.ts +25 -3
  475. package/src/self-dev/local-supervisor-judge.ts +185 -0
  476. package/src/self-dev/run-supervisor.ts +229 -19
  477. package/src/self-dev/run-types.ts +20 -0
  478. package/src/self-dev/shard-aggregate.ts +13 -2
  479. package/src/self-dev/shard-plan.ts +47 -0
  480. package/src/self-dev/shard-run.ts +112 -10
  481. package/src/self-dev/spawn-lane-files.ts +19 -0
  482. package/src/self-implement/app-api-budget.ts +51 -11
  483. package/src/self-implement/config-gate.ts +2 -1
  484. package/src/self-implement/expose-gate.ts +2 -1
  485. package/src/self-implement/gate-artifacts.ts +405 -0
  486. package/src/self-implement/gate-cli.ts +201 -16
  487. package/src/self-implement/gate-remote.ts +110 -25
  488. package/src/self-implement/gate-scenario.ts +85 -0
  489. package/src/self-implement/goal-author.ts +160 -8
  490. package/src/self-implement/graph-authority.ts +38 -6
  491. package/src/self-implement/graph-overlay-condition.ts +92 -1
  492. package/src/self-implement/heal-triage.ts +79 -0
  493. package/src/self-implement/host-regate.ts +61 -3
  494. package/src/self-implement/orchestrator.ts +14 -123
  495. package/src/self-implement/pr-title.ts +123 -0
  496. package/src/self-implement/run-checkpoint.ts +235 -0
  497. package/src/self-implement/run-ledger.ts +155 -10
  498. package/src/self-implement/run-stop.ts +4 -3
  499. package/src/self-implement/run-ttl.ts +28 -4
  500. package/src/self-implement/seams.ts +2 -0
  501. package/src/self-implement/shadow-stage.ts +7 -6
  502. package/src/self-implement/stop-autoheal.ts +2 -1
  503. package/src/self-implement/train-gate-remote.ts +37 -8
  504. package/src/self-implement/train-reach-grouping.ts +157 -0
  505. package/src/self-implement/train-scenario-layers.ts +133 -0
  506. package/src/self-implement/uncommitted-work.ts +2 -0
  507. package/src/session/pending-input.ts +19 -0
  508. package/src/session/session-start.ts +224 -0
  509. package/src/session-runtime/parallel-dispatch.ts +22 -5
  510. package/src/skills/tools/dev-harness.ts +6 -4
  511. package/src/skills/tools/shell.ts +1 -1
  512. package/src/steward/resync-tick.ts +114 -23
  513. package/src/steward/ta-repair-event-collect.ts +158 -0
  514. package/src/task-agent/card-evidence.ts +25 -1
  515. package/src/task-agent/green-sweep.ts +8 -3
  516. package/src/task-agent/judge.ts +76 -0
  517. package/src/task-agent/land-queue.ts +79 -0
  518. package/src/task-agent/live-moves.ts +30 -9
  519. package/src/task-agent/postland-card.ts +5 -0
  520. package/src/task-agent/prelaunch-already-done.ts +98 -0
  521. package/src/task-agent/real-launch-guard.ts +37 -0
  522. package/src/task-agent/rejudge-on-head.ts +89 -12
  523. package/src/task-agent/remote-rejudge-bind.ts +28 -8
  524. package/src/task-agent/repair-cycle.ts +45 -7
  525. package/src/task-agent/repair-worker.ts +7 -0
  526. package/src/task-agent/run-identity.ts +200 -0
  527. package/src/task-agent/shadow.ts +50 -3
  528. package/src/task-agent/task-hand.ts +158 -5
  529. package/src/task-agent/train-landing.ts +77 -0
  530. package/src/task-agent/work-order.ts +104 -0
  531. package/src/task-orchestrator/surfaces/pod-command-job.ts +88 -28
  532. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
  533. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
  534. package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
  535. package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
  536. package/src/task-orchestrator/surfaces/pod-lease.ts +20 -6
  537. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
  538. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
  539. package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
  540. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +63 -0
  541. package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
  542. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
  543. package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
  544. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
  545. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +208 -0
  546. package/src/task-orchestrator/surfaces/self-implement-pod.ts +132 -15
  547. package/src/telegram.ts +2 -4
  548. package/src/tui/input/pickers.ts +732 -0
  549. package/src/tui/slash/mission.ts +492 -0
  550. package/src/tui/slash/term.ts +877 -0
  551. package/src/tui-client/dashboard-session.ts +9 -0
  552. package/src/tui.ts +48 -0
  553. package/src/user-config/gemini-server-tools.ts +9 -0
  554. package/src/user-config.ts +53 -16
  555. package/src/util/spawn-sync-output.ts +7 -0
  556. package/src/ux-sim/fake-bin.ts +154 -0
  557. package/src/ux-sim/fake-clock.ts +36 -0
  558. package/src/ux-sim/headless-tui.ts +72 -0
  559. package/src/ux-sim/in-process-cli.ts +2 -1
  560. package/src/ux-sim/temp-git-remote.ts +82 -0
  561. package/src/version/packed-revision.json +1 -1
  562. package/src/video-pipeline/recipes/vlog.ts +25 -7
  563. package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
  567. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
  569. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
  572. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
  573. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
  576. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
  578. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
  584. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
  588. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
  599. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
  605. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
  608. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
  609. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
  610. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
  613. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
  615. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
  616. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
  617. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
  619. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
  625. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
  632. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
  635. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
  640. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
  642. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
  703. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
  709. /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
@@ -16,7 +16,7 @@ import { collectPodArtifacts } from './pod-artifact-return.js';
16
16
  import { getDefaultLogStore, type LogStore } from '../../mss/logging/log-store.js';
17
17
  import { podBunCacheVolume } from './pod-bun-cache.js';
18
18
  import { POD_JOB_TTL_AFTER_FINISHED_SECONDS } from './pod-lease.js';
19
- import { podHostDirsScript, podInstallSlotsVolume } from './pod-install-slots.js';
19
+ import { podHostDirsCheckScript, podInstallSlotsVolume, prepareHostDirsOnce, type HostDirsPrepResult, podHostDirsScript } from './pod-install-slots.js';
20
20
  import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, type PoolKubectl } from './pod-pool.js';
21
21
  import { podSkillsDigest, readSkillEnvFiles, resolvePodSkills } from './pod-skills.js';
22
22
  import { podSourceScript, type PodSource } from './pod-source-receive.js';
@@ -40,11 +40,18 @@ export const POD_LITE_IMAGE = 'elanous-harness-lite:local';
40
40
 
41
41
  export const POD_LITE_MEMORY_LIMIT = '2Gi';
42
42
 
43
+ /** W5 (10-15 #27801): where a memory-backed TMPDIR is mounted for release gate shards — the overlayfs `/tmp` made SQLite
44
+ * tests take 0.4~5s per turn (once 124s). tmpfs pages count against the container memory limit, so the caller's cap
45
+ * (`tmpfsSizeLimit`) stays small next to the 16Gi shard limit (request 6Gi). */
46
+ export const POD_TMPFS_MOUNT_PATH = '/tmp-mem';
47
+
43
48
  /** 요청은 한도를 넘을 수 없다(쿠버네티스가 Job 을 거부한다) — lite 2Gi 처럼 한도가 기본 요청보다 작으면 한도로 맞춘다. */
44
49
  /** The command Job container's CPU limit when the caller names none (GATE-SPEED A3①: unchanged default). */
45
50
  export const POD_COMMAND_CPU_LIMIT_DEFAULT = '4';
46
51
  /** 게이트 조각·pod-command 의 CPU 요청 기본 — 하니스 Pod(POD_CHILD_REQUESTS.cpu)와 따로 둔다(조각은 bun test 로 CPU 를 실제로 쓴다). */
47
52
  export const POD_COMMAND_CPU_REQUEST_DEFAULT = '1';
53
+ /** Gate and command Pods retain their measured 6Gi scheduler request; si-task admission uses its own size. */
54
+ export const POD_COMMAND_MEMORY_REQUEST_DEFAULT = '6Gi';
48
55
 
49
56
  /** Container CPU request/limit override. Omitted fields keep the defaults (request `POD_COMMAND_CPU_REQUEST_DEFAULT` · limit 4). */
50
57
  export interface PodCpu { request?: string; limit?: string }
@@ -93,9 +100,9 @@ export function parsePodCpu(value: unknown, label = 'cpu'): PodCpu | undefined {
93
100
 
94
101
  export function memoryRequestWithin(limit: string | undefined): string {
95
102
  const gi = (value: string | undefined) => { const m = /^(\d+)Gi$/.exec(value ?? ''); return m ? Number(m[1]) : null; };
96
- const request = gi(POD_CHILD_REQUESTS.memory);
103
+ const request = gi(POD_COMMAND_MEMORY_REQUEST_DEFAULT);
97
104
  const max = gi(limit);
98
- return request !== null && max !== null && request > max ? limit! : POD_CHILD_REQUESTS.memory;
105
+ return request !== null && max !== null && request > max ? limit! : POD_COMMAND_MEMORY_REQUEST_DEFAULT;
99
106
  }
100
107
 
101
108
  /** POD7 must-fix: the skill list alone can't tell a network-only job from one that needs ffmpeg/browser — so lite is
@@ -133,18 +140,24 @@ export function tailBytes(text: string, maxBytes: number): string {
133
140
  return `…[앞 ${bytes.length - maxBytes}바이트 생략]\n${cut.subarray(start).toString('utf8')}`;
134
141
  }
135
142
 
136
- /** The isolation probe: wait until the NetworkPolicy blocks the host/prod daemons, then run `onPass` (default `exit 0`). */
137
- function isolationGateScript(onPass = 'exit 0'): string {
138
- return `ok=0
139
- for i in $(seq 1 60); do
140
- if curl -s -m 1 -o /dev/null http://host.orb.internal:31415/health || curl -s -m 1 -o /dev/null http://core.elanous-prod:8080/; then ok=0; else ok=$((ok+1)); fi
141
- [ "$ok" -ge 3 ] && { echo "[gate] isolation enforced after \${i} probes"; ${onPass}; }
142
- sleep 0.5
143
- done
144
- echo "[gate] ISOLATION NOT ENFORCED within 30s"; exit 1`;
143
+ /**
144
+ * The isolation probe: wait until the NetworkPolicy blocks the host/prod daemons, then go on with the child shell.
145
+ * GATE-WARM-BOOT-NO-INIT (10-15) — this used to be the `isolation-gate` init container; it is now the child shell's first
146
+ * lines, before any credential is read. Same probes, same log lines, same exit 1 when isolation is not enforced in 30 s.
147
+ * Measured on node-b k3d (#27805): init 2 → 354 s · init 1 → 41 s · none → 1 s from Pod creation to the child start.
148
+ */
149
+ export function isolationGateLines(): string {
150
+ return `elanous_isolation_gate() {
151
+ local ok=0 i
152
+ for i in $(seq 1 60); do
153
+ if curl -s -m 1 -o /dev/null http://host.orb.internal:31415/health || curl -s -m 1 -o /dev/null http://core.elanous-prod:8080/; then ok=0; else ok=$((ok+1)); fi
154
+ [ "$ok" -ge 3 ] && { echo "[gate] isolation enforced after \${i} probes"; return 0; }
155
+ sleep 0.5
156
+ done
157
+ echo "[gate] ISOLATION NOT ENFORCED within 30s"; exit 1
158
+ }
159
+ elanous_isolation_gate || exit 1`;
145
160
  }
146
-
147
- const GATE = isolationGateScript();
148
161
 
149
162
  /** Export the command's log store into the existing outbox return channel without changing the command exit status. */
150
163
  const COMMAND_LOG_EXPORT = `if mkdir -p "$HOME/outbox/pod-logs" && elanous --test="$HOME/.elanous-test" logs --instance prod --since 12h --limit 20000 --json --json-data > "$HOME/outbox/pod-logs/logs.jsonl"; then
@@ -182,7 +195,7 @@ if [ -d "$HOME/outbox" ]; then
182
195
  else
183
196
  printf 'ELANOUS_POD_ARTIFACT_SKIPPED %s %s\\n' "$relative" "$size"
184
197
  fi
185
- done < <(find "$HOME/outbox" -type f -print0)
198
+ done < <(find "$HOME/outbox" -type f -print0 | while IFS= read -r -d '' f; do printf '%s\\t%s\\0' "$(( $(wc -c < "$f") ))" "$f"; done | LC_ALL=C sort -z -t $'\\t' -k1,1n -k2 | while IFS= read -r -d '' row; do printf '%s\\0' "\${row#*$'\\t'}"; done)
186
199
  fi`;
187
200
 
188
201
  export interface PodCommandJobInput {
@@ -208,9 +221,13 @@ export interface PodCommandJobInput {
208
221
  memoryLimit?: string;
209
222
  /** GATE-SPEED A3①: CPU request/limit override (release gate shards only). Omitted = request 1 / limit 4. */
210
223
  cpu?: PodCpu;
224
+ /** W5 — emptyDir{medium: Memory} sizeLimit mounted at {@link POD_TMPFS_MOUNT_PATH} ⊕ `TMPDIR` (release gate shards only). Omitted = image `/tmp`. */
225
+ tmpfsSizeLimit?: string;
211
226
  source?: PodSource;
212
227
  deadlineSeconds: number;
213
228
  runId?: string;
229
+ /** GATE-WARM-BOOT-NO-INIT fallback: the node-side hand-over did not run, so a root init container hands the hostPath dirs to uid 1000. */
230
+ hostDirsInit?: boolean;
214
231
  }
215
232
 
216
233
  function bashSingleQuote(value: string): string {
@@ -226,8 +243,11 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
226
243
  const grok = o.llm === 'grok';
227
244
  const bunCache = o.bunCache ? podBunCacheVolume(o.bunCache) : undefined;
228
245
  const installSlots = o.installSlots ? podInstallSlotsVolume(o.installSlots) : undefined;
229
- // hostPath directories the uid-1000 child writes: a root init container hands them over (DirectoryOrCreate is root 0755).
246
+ // hostPath directories the uid-1000 child writes. DirectoryOrCreate makes them root 0755, so runPodCommand hands them to
247
+ // uid 1000 once per node (prepareHostDirsOnce); the child only reports a directory it still cannot write.
230
248
  const hostDirMounts = [...(bunCache ? [bunCache.volumeMount] : []), ...(installSlots ? [installSlots.volumeMount] : [])];
249
+ const tmpfs = o.tmpfsSizeLimit?.trim() || undefined;
250
+ const tmpfsMounts = tmpfs ? [{ name: 'tmp-mem', mountPath: POD_TMPFS_MOUNT_PATH }] : [];
231
251
  const cpu = resolvePodCpu(o.cpu);
232
252
  const quotedArgs = o.command.map(bashSingleQuote).join(' ');
233
253
  const credLines = [
@@ -237,12 +257,14 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
237
257
  : []),
238
258
  ];
239
259
  const script = [
260
+ isolationGateLines(),
240
261
  'set -u',
241
262
  ...credLines,
242
263
  'curl -s -m 3 -o /dev/null http://host.orb.internal:31415/health && { echo "[pod] ISOLATION FAIL"; exit 3; }',
243
264
  ...(o.clone
244
265
  ? ['export GH_TOKEN="$(cat /creds/gh-token)" && gh auth setup-git', podSourceScript(o.source ?? { kind: 'default' }, o.repoUrl)]
245
266
  : ['mkdir -p ~/work && cd ~/work']),
267
+ ...(hostDirMounts.length ? [podHostDirsCheckScript(hostDirMounts)] : []),
246
268
  ...(bunCache ? [bunCache.shellPrefix] : []),
247
269
  `set -- ${quotedArgs}`,
248
270
  '"$@"',
@@ -270,14 +292,10 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
270
292
  spec: {
271
293
  restartPolicy: 'Never',
272
294
  securityContext: { runAsUser: 1000, fsGroup: 1000 },
273
- initContainers: [
274
- // GATE-WARM-BOOT (10-15): ONE init container. Each extra container cost minutes on a loaded k3d node (the measured
275
- // gap between a finished init script and the next container start), so the root host-dir hand-over runs inside
276
- // the isolation init after the probe passes instead of as a second `host-dirs` container.
277
- hostDirMounts.length
278
- ? { name: 'isolation-gate', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never', securityContext: { runAsUser: 0 }, command: ['bash', '-c'], args: [isolationGateScript(podHostDirsScript(hostDirMounts))], volumeMounts: hostDirMounts.map((mount) => ({ ...mount })) }
279
- : { name: 'isolation-gate', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never', command: ['bash', '-c'], args: [GATE] },
280
- ],
295
+ // Normal path: no init container. Fallback only when the node-side hand-over did not run (no member · prep failed).
296
+ ...(o.hostDirsInit && hostDirMounts.length ? { initContainers: [
297
+ { name: 'host-dirs', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never', securityContext: { runAsUser: 0 }, command: ['bash', '-c'], args: [podHostDirsScript(hostDirMounts)], volumeMounts: hostDirMounts.map((mount) => ({ ...mount })) },
298
+ ] } : {}),
281
299
  containers: [{
282
300
  name: 'child', image: o.image, imagePullPolicy: o.imagePullPolicy ?? 'Never',
283
301
  resources: { requests: { ...POD_CHILD_REQUESTS, cpu: cpu.request, memory: memoryRequestWithin(o.memoryLimit) }, limits: { memory: o.memoryLimit ?? '16Gi', cpu: cpu.limit } },
@@ -286,18 +304,21 @@ export function podCommandJobManifest(o: PodCommandJobInput): Record<string, unk
286
304
  ...(o.runId ? [{ name: 'ELANOUS_RUN_ID', value: o.runId }] : []),
287
305
  { name: 'ELANOUS_SUBSTRATE', value: 'pod' },
288
306
  { name: 'ELANOUS_POD_NAME', valueFrom: { fieldRef: { fieldPath: 'metadata.name' } } },
307
+ ...(tmpfs ? [{ name: 'TMPDIR', value: POD_TMPFS_MOUNT_PATH }] : []),
289
308
  ],
290
- ...(secretKeys || o.hostMirror || hostDirMounts.length ? { volumeMounts: [
309
+ ...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumeMounts: [
291
310
  ...(secretKeys ? [{ name: 'creds', mountPath: '/creds', readOnly: true }] : []),
292
311
  ...(o.hostMirror ? [{ name: 'host-mirror', mountPath: '/host-mirror', readOnly: true }] : []),
293
312
  ...hostDirMounts,
313
+ ...tmpfsMounts,
294
314
  ] } : {}),
295
315
  }],
296
- ...(secretKeys || o.hostMirror || hostDirMounts.length ? { volumes: [
316
+ ...(secretKeys || o.hostMirror || hostDirMounts.length || tmpfs ? { volumes: [
297
317
  ...(secretKeys ? [{ name: 'creds', secret: { secretName: `${o.name}-creds`, defaultMode: 0o400 } }] : []),
298
318
  ...(o.hostMirror ? [{ name: 'host-mirror', hostPath: { path: o.hostMirror, type: 'Directory' } }] : []),
299
319
  ...(bunCache ? [bunCache.volume] : []),
300
320
  ...(installSlots ? [installSlots.volume] : []),
321
+ ...(tmpfs ? [{ name: 'tmp-mem', emptyDir: { medium: 'Memory', sizeLimit: tmpfs } }] : []),
301
322
  ] } : {}),
302
323
  },
303
324
  },
@@ -374,6 +395,8 @@ export interface RunPodCommandOptions {
374
395
  memoryLimit?: string;
375
396
  /** GATE-SPEED A3①: CPU request/limit override — only the release gate passes it. Omitted = request 1 / limit 4. */
376
397
  cpu?: PodCpu;
398
+ /** W5 — memory-backed TMPDIR sizeLimit mounted at {@link POD_TMPFS_MOUNT_PATH}; only the release gate passes it. Omitted = image `/tmp`. */
399
+ tmpfsSizeLimit?: string;
377
400
  /** POD7: 호출부가 «네트워크 스킬만 쓰는 명령»이라고 말할 때만 lite 이미지 ⊕ 2Gi. */
378
401
  lite?: boolean;
379
402
  source?: PodSource;
@@ -398,6 +421,8 @@ export interface RunPodCommandOptions {
398
421
  seedMirror?: (o: { host: string; commit: string; cwd: string }) => Promise<MirrorSeedResult | undefined>;
399
422
  /** GATE-WARM-BOOT — the git tree the seed pushes from (default: the process cwd — the gate runs in the repo tree). */
400
423
  mirrorSeedCwd?: string;
424
+ /** GATE-WARM-BOOT-NO-INIT — hands the hostPath dirs to uid 1000 on the member's nodes (test seam · default {@link prepareHostDirsOnce}). */
425
+ prepareHostDirs?: (o: { member: PodPoolMember; hostPaths: readonly string[] }) => Promise<HostDirsPrepResult | undefined>;
401
426
  checkPool?: typeof checkPodPool;
402
427
  syncImages?: typeof syncPoolImages;
403
428
  imageCommit?: string | null;
@@ -417,6 +442,8 @@ export interface RunPodCommandOptions {
417
442
  /** GATE-POD-RESULT-MARKER — the child script's final line (`\n<marker> <token> rc=<n>\n`), printed after the artifact emit. */
418
443
  export const POD_RESULT_MARKER = '__ELANOUS_POD_DONE__';
419
444
  /** The marker bound to one launch (`token` = the launch's random id · the Job name when the manifest has no launch). */
445
+ /** Full-log re-reads after an early marker return before the artifacts count as lost (GATE-POD-RESULT-MARKER follow-up). */
446
+ export const POD_MARKER_LOG_RETRIES = 2;
420
447
  export function podResultMarker(token: string): string { return `${POD_RESULT_MARKER} ${token}`; }
421
448
 
422
449
  /** Split the child's logs into the command output (marker tail removed, bytes otherwise unchanged) and the marker rc (null = no marker for this token). */
@@ -563,6 +590,24 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
563
590
  .catch((error: unknown) => ({ host: member!.sshHost!, ok: false, ms: 0, detail: String(error).slice(0, 300) }));
564
591
  log('pod.command-job', 'mirror-seed', { host: member.sshHost, commit: options.source.sha, ok: seed?.ok ?? false, ms: seed?.ms ?? 0, ...(seed?.detail ? { detail: seed.detail } : {}) });
565
592
  }
593
+ // GATE-WARM-BOOT-NO-INIT (10-15): the hostPath dirs the uid-1000 child writes are handed over on the node itself, once per
594
+ // member·paths in this process (no init container). Best effort: a failure only logs; the child then falls back.
595
+ const hostDirPaths = [...(bunCache ? [bunCache] : []), ...(installSlots ? [installSlots] : [])];
596
+ const prepareHostDirs = options.prepareHostDirs ?? (options.kubectl ? undefined : prepareHostDirsOnce);
597
+ let hostDirsPrepared = false;
598
+ if (hostDirPaths.length) {
599
+ // Observed whether or not a hand-over runs: no member (nothing to reach) and an injected kubectl without a seam are skips.
600
+ if (!member) log('pod.command-job', 'host-dirs-prep', { ok: false, reason: 'no-pool-member', paths: hostDirPaths });
601
+ else if (!prepareHostDirs) log('pod.command-job', 'host-dirs-prep', { ok: false, reason: 'prep-disabled', paths: hostDirPaths });
602
+ else {
603
+ const prep = await prepareHostDirs({ member, hostPaths: hostDirPaths })
604
+ .catch((error: unknown) => ({ host: member!.sshHost ?? 'local', ok: false, ms: 0, detail: String(error).slice(0, 300) }));
605
+ hostDirsPrepared = prep?.ok === true;
606
+ log('pod.command-job', 'host-dirs-prep', { host: prep?.host ?? member.sshHost ?? 'local', ok: prep?.ok ?? false, ms: prep?.ms ?? 0, paths: hostDirPaths, ...(prep?.detail ? { detail: prep.detail } : {}) });
607
+ }
608
+ }
609
+ // Any path where the node-side hand-over did not succeed keeps the old in-Pod hand-over (review mf: uid 1000 could not write).
610
+ const hostDirsInit = hostDirPaths.length > 0 && !hostDirsPrepared;
566
611
  const ghToken = options.clone ? (options.ghToken ?? defaultGhToken)() : undefined;
567
612
  const secret = commandJobSecret({ name, namespace, launch, skills, skillEnvText, ...(grokAuth !== undefined ? { grokAuth } : {}), ...(ghToken !== undefined ? { ghToken } : {}) });
568
613
  if (secret) {
@@ -573,8 +618,9 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
573
618
  name, namespace, launch, image: imageRef ?? image,
574
619
  ...(imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
575
620
  repoUrl, command, skills, ...(options.returnLogs ? { returnLogs: true } : {}), ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
576
- ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), deadlineSeconds,
621
+ ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
577
622
  ...(options.runId ? { runId: options.runId } : {}),
623
+ ...(hostDirsInit ? { hostDirsInit: true } : {}),
578
624
  });
579
625
  kubectl(['-n', namespace, 'delete', 'job', '-l', own, '--ignore-not-found']);
580
626
  const applied = kubectl(['apply', '-f', '-'], JSON.stringify(manifest));
@@ -611,7 +657,21 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
611
657
  } else unreadableSince = null;
612
658
  await sleep(options.pollMs ?? 15_000);
613
659
  }
614
- const logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
660
+ let logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
661
+ // Marker path returns before the Job condition — a full-log read can hit the same transient window the tail read
662
+ // already survived (container log rotation · API hiccup). Retry it a little before calling the artifacts lost.
663
+ // A read that «succeeds» but stops before this launch's marker (empty · cut off) is incomplete too (review mf · #27842).
664
+ const fullLogIncomplete = (r: { status: number | null; stdout: string }) =>
665
+ r.status !== 0 || splitPodResultMarker(r.stdout.startsWith('\n') ? r.stdout : `\n${r.stdout}`, launch).rc === null;
666
+ for (let attempt = 1; markerRc !== null && fullLogIncomplete(logsResult) && attempt <= POD_MARKER_LOG_RETRIES; attempt++) {
667
+ log('pod.command-job', 'result-marker-log-retry', { job: name, attempt, ...(logsResult.status !== 0 ? { error: (logsResult.stderr ?? '').trim().slice(0, 200) } : { reason: 'marker-missing-in-full-log' }) });
668
+ await sleep(options.pollMs === undefined ? 1_000 : Math.min(options.pollMs, 1_000)); // ≤2 re-reads within ≈2s total
669
+ logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
670
+ }
671
+ // Still without this launch's marker after the retries: the artifacts are not trusted as complete (explicit failure).
672
+ if (markerRc !== null && logsResult.status === 0 && fullLogIncomplete(logsResult)) {
673
+ logsResult = { ...logsResult, status: 1, stderr: 'full log ended before this launch\'s result marker (incomplete after retries)' };
674
+ }
615
675
  const logsFailed = logsResult.status !== 0;
616
676
  const logs = logsFailed ? '' : splitPodResultMarker(logsResult.stdout, launch).logs;
617
677
  const artifactDir = artifactRoot;
@@ -6,7 +6,15 @@ export const STOP_CLASS_NO_LAUNCH = 'no-launch' as const;
6
6
  const CHILD_RESULT_KINDS = new Set(['self', 'external']);
7
7
 
8
8
  /** The dev child's terminal line nests the stage: {ok, kind, result:{stage, ok, node, outcome, …}}. Other JSON rows are not results. */
9
- export function nestedPodResult(row: Record<string, unknown>): { stage: string; ok: boolean; error?: string } | null {
9
+ export function nestedPodResult(row: Record<string, unknown>): {
10
+ stage: string;
11
+ ok: boolean;
12
+ error?: string;
13
+ reasonCode?: string;
14
+ checkName?: string;
15
+ targetPath?: string;
16
+ preflightChecks?: PreflightCheck[];
17
+ } | null {
10
18
  if (typeof row.kind !== 'string' || !CHILD_RESULT_KINDS.has(row.kind) || typeof row.ok !== 'boolean') return null;
11
19
  if (!row.result || typeof row.result !== 'object' || Array.isArray(row.result)) return null;
12
20
  const result = row.result as Record<string, unknown>;
@@ -18,28 +26,72 @@ export function nestedPodResult(row: Record<string, unknown>): { stage: string;
18
26
  ? (classification as Record<string, unknown>).classification : undefined;
19
27
  const reason = [result.node, result.outcome].filter((part): part is string => typeof part === 'string' && part.length > 0).join(' ');
20
28
  const error = [reason || (typeof result.error === 'string' ? result.error : ''), typeof detail === 'string' && detail ? detail : ''].filter(Boolean).join(' · ');
21
- return { stage: result.stage, ok: false, ...(error ? { error } : {}) };
29
+ // PREFLIGHT-RESULT-LINE: a nested preflight rejection carries its blockers under result.blockers — the same ledger fields as the flat row.
30
+ const blockers = result.stage === 'preflight-blocked' ? preflightBlockerText(result.blockers)
31
+ : { error: '', preflightChecks: [] as PreflightCheck[] };
32
+ return {
33
+ stage: result.stage,
34
+ ok: false,
35
+ ...(error || blockers.error ? { error: error || blockers.error } : {}),
36
+ ...(blockers.preflightChecks.length === 1 ? blockers.preflightChecks[0] : {}),
37
+ ...(blockers.preflightChecks.length > 1 ? { preflightChecks: blockers.preflightChecks } : {}),
38
+ };
22
39
  }
23
40
 
24
- /** One line naming each preflight blocker (`(대상 경로 0) — …`), or '' when the row carries none. */
25
- function preflightBlockerText(blockers: unknown): string {
26
- if (!Array.isArray(blockers)) return '';
27
- return blockers.flatMap((blocker) => {
28
- if (!blocker || typeof blocker !== 'object' || Array.isArray(blocker)) return [];
29
- const { name, detail } = blocker as Record<string, unknown>;
30
- const parts = [name, detail].filter((part): part is string => typeof part === 'string' && part.trim().length > 0).map((part) => part.trim().replace(/\s+/gu, ' '));
31
- return parts.length ? [parts.join(' — ')] : [];
32
- }).join(' · ');
41
+ function ledgerString(value: unknown): string {
42
+ return typeof value === 'string' && value.trim().length > 0 ? value : '';
43
+ }
44
+
45
+ type PreflightCheck = { reasonCode: string; checkName: string; targetPath?: string };
46
+
47
+ /** Keep each structured check paired with its own path; legacy blockers retain their name/detail diagnostic. */
48
+ function preflightBlockerText(blockers: unknown): { error: string; preflightChecks: PreflightCheck[] } {
49
+ if (!Array.isArray(blockers)) return { error: '', preflightChecks: [] };
50
+ const errors: string[] = [];
51
+ const preflightChecks: PreflightCheck[] = [];
52
+ for (const blocker of blockers) {
53
+ if (!blocker || typeof blocker !== 'object' || Array.isArray(blocker)) continue;
54
+ const record = blocker as Record<string, unknown>;
55
+ const reasonCode = ledgerString(record.reasonCode);
56
+ const checkName = ledgerString(record.checkName);
57
+ if (reasonCode && checkName) {
58
+ const targetPath = ledgerString(record.targetPath);
59
+ preflightChecks.push({ reasonCode, checkName, ...(targetPath ? { targetPath } : {}) });
60
+ errors.push(`${reasonCode} · ${checkName}`);
61
+ continue;
62
+ }
63
+ const parts = [record.name, record.detail]
64
+ .filter((part): part is string => typeof part === 'string' && part.trim().length > 0)
65
+ .map((part) => part.trim().replace(/\s+/gu, ' '));
66
+ if (parts.length) errors.push(parts.join(' — '));
67
+ }
68
+ return { error: errors.join(' · '), preflightChecks };
33
69
  }
34
70
 
35
71
  /** A child terminal row: the legacy flat form {stage, ok, error?} (no kind, or a child kind) or the nested dev result. Any other kind is not a result. */
36
- export function podTerminalRow(row: Record<string, unknown>): { stage: string; ok: boolean; error?: string } | null {
72
+ export function podTerminalRow(row: Record<string, unknown>): {
73
+ stage: string;
74
+ ok: boolean;
75
+ error?: string;
76
+ reasonCode?: string;
77
+ checkName?: string;
78
+ targetPath?: string;
79
+ preflightChecks?: PreflightCheck[];
80
+ } | null {
37
81
  if (typeof row.kind === 'string' && !CHILD_RESULT_KINDS.has(row.kind)) return null;
38
82
  if (typeof row.stage === 'string' && typeof row.ok === 'boolean') {
39
- if (typeof row.error === 'string') return { stage: row.stage, ok: row.ok, error: row.error };
40
- // PREFLIGHT-RESULT-LINE: `{kind:'self', ok:false, stage:'preflight-blocked', blockers}` carries its reason in the blockers, not in `error`.
41
- const blockers = row.ok === false && row.stage === 'preflight-blocked' ? preflightBlockerText(row.blockers) : '';
42
- return { stage: row.stage, ok: row.ok, ...(blockers ? { error: blockers } : {}) };
83
+ // PREFLIGHT-RESULT-LINE: preserve structured blockers even when an explicit error supplies the human-readable reason.
84
+ if (row.ok === false && row.stage === 'preflight-blocked') {
85
+ const blockers = preflightBlockerText(row.blockers);
86
+ return {
87
+ stage: row.stage,
88
+ ok: row.ok,
89
+ ...(typeof row.error === 'string' ? { error: row.error } : blockers.error ? { error: blockers.error } : {}),
90
+ ...(blockers.preflightChecks.length === 1 ? blockers.preflightChecks[0] : {}),
91
+ ...(blockers.preflightChecks.length > 1 ? { preflightChecks: blockers.preflightChecks } : {}),
92
+ };
93
+ }
94
+ return { stage: row.stage, ok: row.ok, ...(typeof row.error === 'string' ? { error: row.error } : {}) };
43
95
  }
44
96
  return nestedPodResult(row);
45
97
  }
@@ -64,9 +116,21 @@ export function classifyPodExit(input: {
64
116
  jobReason?: string | null;
65
117
  logs: string;
66
118
  result?: Record<string, unknown> | null;
67
- }): { class: PodExitClass; errorCode: string | null; containerReason: string | null; exitCode: number | null; jobReason: string | null; tail: string[] } {
119
+ }): {
120
+ class: PodExitClass;
121
+ errorCode: string | null;
122
+ containerReason: string | null;
123
+ exitCode: number | null;
124
+ jobReason: string | null;
125
+ tail: string[];
126
+ reasonCode?: string;
127
+ checkName?: string;
128
+ targetPath?: string;
129
+ preflightChecks?: PreflightCheck[];
130
+ noResultLine?: true;
131
+ } {
68
132
  const logLines = input.logs.split(/\r\n|\n|\r/u).map((line) => line.trim()).filter(Boolean);
69
- let terminalResult: { stage: string; ok: boolean; error?: string } | null = null;
133
+ let terminalResult: ReturnType<typeof podTerminalRow> = null;
70
134
  for (const line of logLines) {
71
135
  if (!line.startsWith('{')) continue;
72
136
  let parsed: unknown;
@@ -74,8 +138,8 @@ export function classifyPodExit(input: {
74
138
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
75
139
  terminalResult = podTerminalRow(parsed as Record<string, unknown>) ?? terminalResult;
76
140
  }
77
- if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
78
141
  const hasResultLine = terminalResult !== null;
142
+ if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
79
143
  const askReprompt = logLines.some((line) =>
80
144
  /^\[ask\](?!\s+\d+\)\s).*(?:implementation[_ -]?target|reprompt|re-prompt|되묻)/iu.test(line));
81
145
  // 파싱되는 JSON 줄(진행·결과 행)은 오류 «줄»로 세지 않는다 — tail 과 같은 기준.
@@ -116,6 +180,11 @@ export function classifyPodExit(input: {
116
180
  exitCode: input.containerExitCode ?? null,
117
181
  jobReason: input.jobReason ?? null,
118
182
  tail,
183
+ ...(terminalResult?.reasonCode ? { reasonCode: terminalResult.reasonCode } : {}),
184
+ ...(terminalResult?.checkName ? { checkName: terminalResult.checkName } : {}),
185
+ ...(terminalResult?.targetPath ? { targetPath: terminalResult.targetPath } : {}),
186
+ ...(terminalResult?.preflightChecks ? { preflightChecks: terminalResult.preflightChecks } : {}),
187
+ ...(!hasResultLine ? { noResultLine: true as const } : {}),
119
188
  };
120
189
  }
121
190
 
@@ -11,6 +11,7 @@
11
11
  // ⛔ 기본 꺼짐(opt-in): 옵션 → env `ELANOUS_POD_HOST_ACP_REVIEW` → config `llm.podHostAcpReview` 순.
12
12
  // 📌 남은 조각(②-b): 이 문이 켜진 런에서 Pod 안 api 리뷰를 «끄는» 것은 Pod 이미지 쪽 변경이라 따로 간다.
13
13
  import { spawnSync } from 'node:child_process';
14
+ import { SPAWN_SYNC_MAX_BUFFER } from '../../util/spawn-sync-output.js';
14
15
  import { debug } from '../../debug/log.js';
15
16
  import type { ReviewResult } from '../../agent-substrate/pr-reviewer.js';
16
17
  import type { SubscriptionReviewerSpec } from '../../user-config.js';
@@ -57,7 +58,7 @@ export interface PodHostAcpReviewDeps {
57
58
  }
58
59
 
59
60
  function defaultReadPr(prNumber: number, repoRoot: string): { headRefOid: string; title: string; body: string; diff: string } | undefined {
60
- const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000 });
61
+ const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
61
62
  if (view.status !== 0) return undefined;
62
63
  const diff = spawnSync('gh', ['pr', 'diff', String(prNumber)], { cwd: repoRoot, encoding: 'utf8', timeout: 120_000, maxBuffer: 64 * 1024 * 1024 });
63
64
  if (diff.status !== 0) return undefined;
@@ -14,6 +14,7 @@
14
14
  * 이미지는 표준판(elanous-harness)만 — 이 발사 경로는 lite 를 쓰지 않는다.
15
15
  */
16
16
  import { spawnSync } from 'node:child_process';
17
+ import { SPAWN_SYNC_MAX_BUFFER } from '../../util/spawn-sync-output.js';
17
18
  import { debug } from '../../debug/log.js';
18
19
  import { memberHasRegistry, registryImageRef, type RemoteRun } from './pod-pool.js';
19
20
 
@@ -71,7 +72,7 @@ export function memberPinRegistry(member: PodImageMember, source: Extract<PodIma
71
72
 
72
73
  /** 실제 조회 — 원격은 pod-pool 의 SSH 판정, 로컬은 이 기계의 docker/curl 로 조회한다. */
73
74
  export function podPoolImageLookup(run?: RemoteRun, localRun: (cmd: string, args: readonly string[]) => { status: number | null; stdout: string } = (cmd, args) => {
74
- const r = spawnSync(cmd, [...args], { encoding: 'utf8', timeout: 10_000 });
75
+ const r = spawnSync(cmd, [...args], { encoding: 'utf8', timeout: 10_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
75
76
  return { status: r.status, stdout: r.stdout ?? '' };
76
77
  }): {
77
78
  hasRegistry: (member: PodImageMember & { context: string }, registry: string) => boolean;
@@ -1,3 +1,5 @@
1
+ import { spawn } from 'node:child_process';
2
+
1
3
  // GATE-INSTALL-CACHE (0.2.20) — a node-wide throttle for the release-gate shards' `bun install`.
2
4
  //
3
5
  // Cause, measured on the 0.2.19 gate (`elanous logs --category release-loop.gate --event pod-shard --all --include-test`):
@@ -21,8 +23,8 @@ export const POD_INSTALL_SLOTS_HOST_PATH = '/var/lib/elanous/gate-install-slots'
21
23
  export const POD_INSTALL_SLOTS_DEFAULT = 4;
22
24
  export const POD_INSTALL_SLOTS_MOUNT = '/gate-install-slots';
23
25
 
24
- /** hostPath volume ⊕ mount for the tokens. `DirectoryOrCreate` makes a root-owned 0755 directory, so the Pod also needs
25
- * {@link podHostDirsScript} (the child runs as uid 1000). */
26
+ /** hostPath volume ⊕ mount for the tokens. `DirectoryOrCreate` makes a root-owned 0755 directory, so the node also needs
27
+ * {@link prepareHostDirsOnce} (the child runs as uid 1000). */
26
28
  export function podInstallSlotsVolume(hostPath: string = POD_INSTALL_SLOTS_HOST_PATH) {
27
29
  return {
28
30
  volume: { name: 'install-slots', hostPath: { path: hostPath, type: 'DirectoryOrCreate' } },
@@ -30,17 +32,125 @@ export function podInstallSlotsVolume(hostPath: string = POD_INSTALL_SLOTS_HOST_
30
32
  };
31
33
  }
32
34
 
33
- /**
34
- * The root shell that hands the mounted hostPath directories to the child's uid. Without it a `DirectoryOrCreate`
35
- * hostPath stays root:root 0755 and the child's `[ -w … ]` guard silently skips it (the Bun cache option was a no-op).
36
- * Never fails the Pod: an unchanged directory only means the child falls back (no cache · no throttle).
37
- * GATE-WARM-BOOT — it runs inside the Pod's single init container (after the isolation probe), not as a second one.
38
- */
35
+ // GATE-WARM-BOOT-NO-INIT (10-15) — the root hand-over of the hostPath directories left the Pod. It was an init container
36
+ // (`host-dirs`, then folded into `isolation-gate` by GATE-WARM-BOOT), and every init container cost a container
37
+ // transition on a loaded k3d node (#27805 on node-b: init 2 → 354 s · init 1 → 41 s · none → 1 s to the child start).
38
+ // The directories live on the node and outlive every Pod, so the hand-over is a node fact: done once per node from the
39
+ // pool host (`docker exec` into each k3d node container · idempotent `mkdir -p`/`chown`/`chmod`), and the child shell only
40
+ // reports a directory it still cannot write. Never fails the Pod: an unwritable directory means the child falls back
41
+ // (no cache · no throttle), exactly as before when the hand-over failed.
42
+
43
+ const SAFE_HOST_PATH = /^\/[A-Za-z0-9._/-]+$/;
44
+ const SAFE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
45
+ export const HOST_DIRS_PREP_LIMIT_MS = 30_000;
46
+
47
+ /** Child-shell line: report (never fail on) a mounted host directory the uid-1000 child cannot write. */
48
+ /** Root hand-over inside the Pod — only for runs whose hostPath dirs could not be prepared on the node (no pool member ·
49
+ * prep failed · prep disabled). Same lines the old `isolation-gate` init ran; it never fails the Pod. */
39
50
  export function podHostDirsScript(mounts: ReadonlyArray<{ mountPath: string }>): string {
40
51
  const paths = mounts.map((mount) => `'${mount.mountPath.replace(/'/g, `'\\''`)}'`).join(' ');
41
52
  return `for d in ${paths}; do mkdir -p "$d" && chown 1000:1000 "$d" && chmod 0775 "$d" || echo "[host-dirs] could not prepare $d"; done; exit 0`;
42
53
  }
43
54
 
55
+ export function podHostDirsCheckScript(mounts: ReadonlyArray<{ mountPath: string }>): string {
56
+ const paths = mounts.map((mount) => `'${mount.mountPath.replace(/'/g, `'\\''`)}'`).join(' ');
57
+ return `for d in ${paths}; do [ -d "$d" ] && [ -w "$d" ] || echo "[host-dirs] could not prepare $d (not writable by uid $(id -u) · node not prepared)"; done`;
58
+ }
59
+
60
+ /** Host-side shell (on the pool host): hand the node directories to uid 1000 in every k3d node container of `cluster`. */
61
+ export function podHostDirsNodeScript(o: { cluster: string; hostPaths: readonly string[] }): string {
62
+ if (!SAFE_NAME.test(o.cluster)) throw new Error(`invalid k3d cluster: ${o.cluster}`);
63
+ for (const path of o.hostPaths) if (!SAFE_HOST_PATH.test(path) || path.split('/').includes('..')) throw new Error(`invalid host dir: ${path}`);
64
+ const inner = `for d in ${o.hostPaths.join(' ')}; do mkdir -p "$d" && chown 1000:1000 "$d" && chmod 0775 "$d" || { echo "[host-dirs] could not prepare $d"; exit 1; }; done`;
65
+ return [
66
+ `nodes=$(docker ps --filter label=k3d.cluster=${o.cluster} --format '{{.Names}} {{.Label "k3d.role"}}' | awk '$2=="server"||$2=="agent"{print $1}')`,
67
+ `[ -n "$nodes" ] || { echo "[host-dirs] no k3d node for ${o.cluster}"; exit 2; }`,
68
+ 'rc=0',
69
+ `for n in $nodes; do docker exec "$n" sh -c '${inner}' || rc=1; done`,
70
+ 'exit $rc',
71
+ ].join('\n');
72
+ }
73
+
74
+ /** The member's current k3d server/agent container IDs, sorted — the node «generation» the hand-over memo is keyed by. */
75
+ export function podHostDirsNodeIdsScript(cluster: string): string {
76
+ if (!SAFE_NAME.test(cluster)) throw new Error(`invalid k3d cluster: ${cluster}`);
77
+ return `docker ps --no-trunc --filter label=k3d.cluster=${cluster} --format '{{.ID}} {{.Label "k3d.role"}}' | awk '$2=="server"||$2=="agent"{print $1}' | sort | tr '\\n' ' '`;
78
+ }
79
+
80
+ export interface HostDirsPrepResult { host: string; ok: boolean; ms: number; detail?: string }
81
+
82
+ type HostShell = (host: string | undefined, script: string, limitMs: number) => Promise<{ rc: number; output: string }>;
83
+
84
+ /**
85
+ * Bounded shell on the pool host (`ssh <host>`) or this machine (no host); never throws. At `limitMs` the whole process
86
+ * group is killed and the call returns rc 124 at once — a stuck `docker exec` grandchild holding the pipe must not keep
87
+ * the caller (and the Job launch behind it) waiting for `close`.
88
+ */
89
+ export function hostShellWithin(host: string | undefined, script: string, limitMs: number): Promise<{ rc: number; output: string }> {
90
+ const env = 'export PATH=/opt/homebrew/bin:/usr/local/bin:$HOME/.orbstack/bin:$PATH; ';
91
+ const [cmd, args] = host
92
+ ? ['ssh', ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=10', host, env + script]] as const
93
+ : ['bash', ['-c', env + script]] as const;
94
+ return new Promise((resolve) => {
95
+ let output = '';
96
+ let settled = false;
97
+ let timer: ReturnType<typeof setTimeout> | undefined;
98
+ const finish = (rc: number, text: string) => { if (!settled) { settled = true; clearTimeout(timer); resolve({ rc, output: text }); } };
99
+ let child: ReturnType<typeof spawn>;
100
+ try { child = spawn(cmd, [...args], { stdio: ['ignore', 'pipe', 'pipe'], detached: true }); }
101
+ catch (error) { resolve({ rc: 2, output: String(error) }); return; }
102
+ timer = setTimeout(() => {
103
+ try { if (child.pid) process.kill(-child.pid, 'SIGKILL'); else child.kill('SIGKILL'); } catch { child.kill('SIGKILL'); }
104
+ child.stdout?.destroy();
105
+ child.stderr?.destroy();
106
+ finish(124, `${output}\n[host-dirs] timed out after ${limitMs} ms`);
107
+ }, limitMs);
108
+ child.stdout?.on('data', (chunk) => { output += String(chunk); });
109
+ child.stderr?.on('data', (chunk) => { output += String(chunk); });
110
+ child.on('error', (error) => finish(2, `${output}\n${String(error)}`));
111
+ child.on('close', (code) => finish(code ?? 2, output));
112
+ });
113
+ }
114
+
115
+ const prepared = new Map<string, Promise<HostDirsPrepResult>>();
116
+
117
+ /**
118
+ * Hand `hostPaths` to uid 1000 on the member's k3d nodes once per (host, cluster, node generation, path) in this process — every shard Job
119
+ * on the same member awaits the same run, and a path already handed over (or in flight) is not run again even when it
120
+ * comes with a different companion path. A failure is not memoized (the next Job tries again) and never throws.
121
+ */
122
+ export async function prepareHostDirsOnce(o: { member: { sshHost?: string; k3dCluster: string }; hostPaths: readonly string[]; shell?: HostShell; limitMs?: number }): Promise<HostDirsPrepResult> {
123
+ const host = o.member.sshHost;
124
+ const label = host ?? 'local';
125
+ const start = Date.now();
126
+ const shell = o.shell ?? hostShellWithin;
127
+ // Node generation (review mf): a recreated cluster or a new agent has other container IDs, so a hand-over remembered for
128
+ // the old node set is not reused. Unreadable IDs → no memo at all (every path runs, success is not remembered).
129
+ const ids = await shell(host, podHostDirsNodeIdsScript(o.member.k3dCluster), o.limitMs ?? HOST_DIRS_PREP_LIMIT_MS)
130
+ .catch(() => ({ rc: 2, output: '' }));
131
+ const generation = ids.rc === 0 && ids.output.trim() ? ids.output.trim() : null;
132
+ const gen = generation ?? `unknown-${start}-${Math.random()}`;
133
+ const keyOf = (path: string) => `${label}\0${o.member.k3dCluster}\0${gen}\0${path}`;
134
+ const paths = [...new Set(o.hostPaths)].sort();
135
+ const fresh = paths.filter((path) => !prepared.has(keyOf(path)));
136
+ if (fresh.length) {
137
+ const run = (async (): Promise<HostDirsPrepResult> => {
138
+ const script = podHostDirsNodeScript({ cluster: o.member.k3dCluster, hostPaths: fresh });
139
+ const r = await shell(host, script, o.limitMs ?? HOST_DIRS_PREP_LIMIT_MS);
140
+ const ms = Date.now() - start;
141
+ return r.rc === 0 ? { host: label, ok: true, ms } : { host: label, ok: false, ms, detail: r.output.trim().slice(-300) || `rc=${r.rc}` };
142
+ })().catch((error: unknown) => ({ host: label, ok: false, ms: Date.now() - start, detail: String(error).slice(0, 300) }))
143
+ .then((result) => { if (!result.ok || generation === null) for (const path of fresh) prepared.delete(keyOf(path)); return result; });
144
+ for (const path of fresh) prepared.set(keyOf(path), run);
145
+ }
146
+ const results = await Promise.all(paths.map((path) => prepared.get(keyOf(path))!));
147
+ const failed = results.find((result) => !result.ok);
148
+ return failed ?? { host: label, ok: true, ms: Date.now() - start };
149
+ }
150
+
151
+ /** Test seam — forget the per-process hand-over memo. */
152
+ export function resetHostDirsPrepMemo(): void { prepared.clear(); }
153
+
44
154
  const int = (value: number, label: string) => {
45
155
  if (!Number.isSafeInteger(value) || value < 1) throw new Error(`invalid ${label}: ${value}`);
46
156
  return value;
@@ -66,7 +176,9 @@ export function installSlotScript(o: { dir?: string; slots: number; waitSeconds?
66
176
  ' if [ ! -d "$d" ] || [ ! -w "$d" ]; then echo "[gate] install-slot none (directory not writable)"; return 0; fi',
67
177
  ' while :; do',
68
178
  ` for n in $(seq 0 ${slots - 1}); do`,
69
- ' if mkdir "$d/slot-$n" 2>/dev/null; then',
179
+ // The token is taken by bash's own noclobber create (O_EXCL), not by `mkdir`: uutils coreutils `mkdir` (0.8 · wsl gate host)
180
+ // let two racing callers both succeed on one path (10-16 · 3 holders on 2 slots). A directory token left by an older shell still counts as held.
181
+ ' if (set -C; : > "$d/slot-$n") 2>/dev/null; then',
70
182
  ' install_slot="$d/slot-$n"',
71
183
  ' echo "[gate] install-slot $n waited $(( $(date +%s) - t0 ))s"; return 0',
72
184
  ' fi',