elanous 0.2.29 → 0.2.32

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 (775) 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 → IVKr3AlRUVLKsw2fh7eXF}/_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-98b64172bc1efe77.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/69-0a2c8209c6d4a158.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
  94. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
  95. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
  110. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
  123. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/control/page-a27b1e5a0d1b308f.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/morning/page-32866485913d6a04.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-c219f2ed171131be.js} +1 -1
  163. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/term/page-04d00ae9b0890349.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.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 +7 -3
  279. package/graphs/context/nightly-condense.yaml +1 -0
  280. package/graphs/implement-loop.yaml +5 -0
  281. package/graphs/intake/intake-daily.yaml +8 -1
  282. package/graphs/intake/recipes.yaml +5 -0
  283. package/graphs/lecture/lecture-note.yaml +2 -2
  284. package/graphs/ops/harness-gc.yaml +1 -0
  285. package/graphs/release/recipes.yaml +3 -0
  286. package/graphs/release/release-loop.yaml +9 -5
  287. package/graphs/units/recipes.yaml +3 -0
  288. package/graphs/units/release-gate-recheck.yaml +15 -0
  289. package/package.json +2 -1
  290. package/scripts/check-native-tool-wiring.ts +3 -2
  291. package/scripts/ci-android-unit-tests.ts +16 -0
  292. package/scripts/ci-typecheck-changed.ts +63 -10
  293. package/scripts/coord-channel-watch.sh +22 -16
  294. package/scripts/coord-role-pack.ts +81 -2
  295. package/scripts/cron-run.ts +96 -3
  296. package/scripts/detect-test-interference.ts +38 -5
  297. package/scripts/gate-pr-cache.ts +65 -0
  298. package/scripts/gh-surface/capture.ts +126 -0
  299. package/scripts/gh-surface/gh +40 -0
  300. package/scripts/import-graph-scc.ts +38 -0
  301. package/scripts/install.ps1 +19 -0
  302. package/scripts/intake-social.ts +181 -0
  303. package/scripts/lecture-note/node.ts +71 -4
  304. package/scripts/lib/android-toolchain.ts +32 -0
  305. package/scripts/lib/deterministic-env.ts +62 -0
  306. package/scripts/lib/gate-test-env.ts +19 -0
  307. package/scripts/measure-goal-grounding-corpus.ts +2 -1
  308. package/scripts/measure-si-task-cpu.ts +143 -0
  309. package/scripts/ratchets/test-interference-patterns.allowlist.txt +255 -0
  310. package/scripts/ratchets/test-interference-patterns.ts +367 -0
  311. package/scripts/release-loop/cut-branch.ts +4 -3
  312. package/scripts/release-loop/export-check-node.ts +0 -1
  313. package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
  314. package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
  315. package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
  316. package/scripts/release-loop/gate-closure.ts +12 -8
  317. package/scripts/release-loop/gate-diff.ts +1 -1
  318. package/scripts/release-loop/gate-host-mirror.ts +66 -0
  319. package/scripts/release-loop/gate-node.ts +523 -75
  320. package/scripts/release-loop/gate-partial.ts +106 -9
  321. package/scripts/release-loop/gate-pr-cache.ts +66 -0
  322. package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
  323. package/scripts/release-loop/gate-r2-verdict.ts +189 -0
  324. package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
  325. package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
  326. package/scripts/release-loop/import-graph-scc-run.ts +54 -0
  327. package/scripts/release-loop/import-graph-scc.ts +215 -0
  328. package/scripts/release-loop/node-verdict.ts +2 -0
  329. package/scripts/release-loop/prepare-node.ts +102 -4
  330. package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
  331. package/scripts/release-loop/resume-release.ts +33 -4
  332. package/scripts/release-loop/resume.ts +13 -5
  333. package/scripts/release-loop/spawn-lane.ts +2 -19
  334. package/scripts/release-loop/tui-sim-node.ts +3 -2
  335. package/scripts/release-loop/unattended-release.ts +16 -0
  336. package/scripts/test-deterministic.ts +5 -61
  337. package/scripts/train-reach-grouping.ts +48 -0
  338. package/scripts/tsc-incremental-cache.ts +86 -0
  339. package/scripts/tsc-incremental-diagnostics.ts +76 -0
  340. package/scripts/tsc-main-safety-net.ts +2 -2
  341. package/src/acp/client.ts +4 -1
  342. package/src/acp/core-turn-bridge.ts +65 -8
  343. package/src/acp/elanous-extensions.ts +3 -0
  344. package/src/acp/server.ts +3 -0
  345. package/src/acp/tool-trace.ts +186 -11
  346. package/src/ad-pipeline/run.ts +4 -2
  347. package/src/agent/runner.ts +169 -3
  348. package/src/agent/self-ambient-cache.ts +156 -0
  349. package/src/agent/self-ambient.ts +8 -1
  350. package/src/agent/subagent-callable.ts +3 -2
  351. package/src/agent/task-notification.ts +5 -0
  352. package/src/agent-mission/review-loop.ts +6 -3
  353. package/src/agent-substrate/acp-implementer.ts +14 -2
  354. package/src/agent-substrate/pr-reviewer.ts +14 -0
  355. package/src/agent-substrate/self-review-cli.ts +30 -4
  356. package/src/ask-user-question/tool.ts +22 -0
  357. package/src/autopilot/build/llm-conflict-merge.ts +56 -10
  358. package/src/autopilot/pr-manager.ts +80 -7
  359. package/src/briefing/brief-items.ts +24 -22
  360. package/src/capture/frame-state-detect.ts +39 -0
  361. package/src/capture/tui-self-report.ts +149 -6
  362. package/src/chat/chat-cli.ts +10 -2
  363. package/src/chat/index.ts +138 -26
  364. package/src/chat/input-control-key.ts +5 -3
  365. package/src/chat/pickers/modal-runtime.ts +6 -0
  366. package/src/chat/pickers/modals.ts +8 -2
  367. package/src/chat/tool-interrupt-behavior.ts +38 -0
  368. package/src/chat/tool-render/dispatch.ts +5 -1
  369. package/src/chat/turn-typeahead.ts +75 -20
  370. package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
  371. package/src/cli/agent-cli.ts +41 -13
  372. package/src/cli/ask-bare.ts +1 -0
  373. package/src/cli/config-audit.ts +123 -0
  374. package/src/cli/decisions-cli.ts +80 -6
  375. package/src/cli/import-cli.ts +12 -0
  376. package/src/cli/log-event-names.ts +17 -0
  377. package/src/cli/mcp-login.ts +21 -5
  378. package/src/cli/msg-cli.ts +89 -0
  379. package/src/cli/pod-cli.ts +14 -3
  380. package/src/cli/pr-cli.ts +273 -81
  381. package/src/cli/pr-land-base-read.ts +34 -0
  382. package/src/cli/pr-land-heavy-remote.ts +82 -26
  383. package/src/cli/pr-land-overlap-evidence.ts +109 -11
  384. package/src/cli/pr-land-pod-shadow-job.ts +106 -0
  385. package/src/cli/pr-land-pod-shadow.ts +16 -3
  386. package/src/cli/pr-land-refusal.ts +20 -5
  387. package/src/cli/pr-land-virtual-rebase.ts +108 -0
  388. package/src/cli/pty-takeover-cli.ts +88 -14
  389. package/src/cli/release-cli.ts +80 -14
  390. package/src/cli/seat-cli.ts +138 -3
  391. package/src/cli/self-update.ts +5 -2
  392. package/src/cli/sim-cli.ts +18 -0
  393. package/src/cli/tasks-cli.ts +97 -19
  394. package/src/context-bus/context-first.ts +13 -0
  395. package/src/context-bus/context-now.ts +13 -2
  396. package/src/context-bus/ops-events.ts +79 -0
  397. package/src/control-plane/lease-holder.ts +12 -8
  398. package/src/control-plane/ledger.ts +163 -4
  399. package/src/control-plane/server.ts +91 -11
  400. package/src/core-turn/run-core-turn.ts +2 -0
  401. package/src/core-turn/run-goal-loop.ts +243 -3
  402. package/src/core-turn/seat-turn-cap.ts +79 -0
  403. package/src/core-turn/short-question.ts +38 -6
  404. package/src/core-turn/types.ts +6 -0
  405. package/src/dashboard/acp-active-model.ts +42 -1
  406. package/src/dashboard/acp-boot.ts +3 -0
  407. package/src/dashboard/background-jobs-status.ts +66 -0
  408. package/src/dashboard/index.ts +339 -657
  409. package/src/dashboard/input/agent-wake.ts +242 -0
  410. package/src/dashboard/input/chat-main-entry-runtime.ts +6 -1
  411. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
  412. package/src/dashboard/input/chat-main-session.ts +8 -1
  413. package/src/dashboard/input/chat-main-turn.ts +12 -3
  414. package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
  415. package/src/dashboard/input/external-input-host.ts +49 -9
  416. package/src/dashboard/input/internal-turn.ts +261 -0
  417. package/src/dashboard/input/mouse-wiring.ts +108 -11
  418. package/src/dashboard/input/seat-autowake.ts +318 -0
  419. package/src/dashboard/input/turn-steer-bridge.ts +70 -0
  420. package/src/dashboard/log-click-runtime.ts +118 -2
  421. package/src/dashboard/loop-scheduler.ts +72 -0
  422. package/src/dashboard/seat-boot-preamble.ts +18 -0
  423. package/src/dashboard/skill-runtime.ts +2 -0
  424. package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
  425. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
  426. package/src/dashboard/slash-runtime/index.ts +13 -0
  427. package/src/dashboard/turn-busy-teardown.ts +50 -0
  428. package/src/dashboard/turn-preamble.ts +116 -40
  429. package/src/dashboard/turn-session-layers.ts +4 -2
  430. package/src/dashboard/turn-start-segments.ts +222 -0
  431. package/src/decisions/decision-ledger.ts +45 -4
  432. package/src/discord-self-message.ts +4 -4
  433. package/src/display/prompt-row-owner.ts +146 -0
  434. package/src/display/resize-listener.ts +33 -2
  435. package/src/domains/release-tool.ts +18 -1
  436. package/src/field-note/transcribe.ts +17 -0
  437. package/src/fold-stack.ts +4 -2
  438. package/src/git-fs/index.ts +263 -36
  439. package/src/github/remote-call.ts +81 -0
  440. package/src/goals/registry.ts +46 -6
  441. package/src/goals/types.ts +7 -1
  442. package/src/graph-runner/runner.ts +1 -0
  443. package/src/grok/credential.ts +26 -0
  444. package/src/harness/gate-reserve.ts +87 -0
  445. package/src/harness/harness-clean.ts +2 -1
  446. package/src/harness/harness-cli-command.ts +52 -5
  447. package/src/harness/harness-gc.ts +2 -1
  448. package/src/harness/harness-incidents.ts +70 -20
  449. package/src/harness/harness-pod-dispatch.ts +87 -10
  450. package/src/harness/harness-queue.ts +68 -4
  451. package/src/harness/harness-stop.ts +4 -3
  452. package/src/harness/harness-substrate-default.ts +78 -7
  453. package/src/harness/harness-worktree-auto.ts +2 -1
  454. package/src/harness/harness-worktrees.ts +3 -2
  455. package/src/hooks/dispatch.ts +2 -1
  456. package/src/index.ts +156 -27
  457. package/src/input/external-input-queue.ts +64 -7
  458. package/src/intake-plane/slash.ts +14 -3
  459. package/src/keybindings.ts +4 -1
  460. package/src/llm/route-decision.ts +36 -0
  461. package/src/llm/tool-loop-steered-rejection.ts +41 -0
  462. package/src/llm-request-shape.ts +209 -0
  463. package/src/llm.ts +301 -283
  464. package/src/loops/consensus.ts +348 -0
  465. package/src/loops/msg-wake.ts +206 -4
  466. package/src/loops/observe.ts +19 -3
  467. package/src/loops/orchestrator/tick.ts +88 -12
  468. package/src/loops/orchestrator/traffic.ts +64 -1
  469. package/src/loops/registry.ts +30 -0
  470. package/src/market/signed-index.ts +14 -0
  471. package/src/maturity/feature-maturity.ts +1 -1
  472. package/src/mcp/mcp-oauth.ts +54 -5
  473. package/src/models/prompts.ts +28 -0
  474. package/src/msg/msg-sse-client.ts +223 -0
  475. package/src/msg/msg-store.ts +86 -2
  476. package/src/mss/logging/log-store.ts +225 -1
  477. package/src/mss/logging/render-categories.ts +5 -0
  478. package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
  479. package/src/nexus/api/http-server.ts +54 -15
  480. package/src/nexus/api/loop-resources.ts +19 -3
  481. package/src/nexus/api/ops-api.ts +11 -0
  482. package/src/nexus/daemon-thin-inventory.md +37 -0
  483. package/src/nexus/index.ts +70 -0
  484. package/src/nexus/state/state.ts +1 -0
  485. package/src/oauth/store.ts +32 -7
  486. package/src/onboarding/first-run.ts +28 -3
  487. package/src/ops/overview-cache.ts +16 -4
  488. package/src/ops/overview.ts +59 -2
  489. package/src/ops/resources.ts +82 -0
  490. package/src/plugins/maker/connector-maker.ts +41 -0
  491. package/src/plugins/maker/skill-maker.ts +42 -0
  492. package/src/pr-tool/census.ts +303 -0
  493. package/src/pr-tool/inflight-registry.ts +143 -0
  494. package/src/prompt-library/chat-conciseness.ts +13 -0
  495. package/src/prompt-library/universal-preamble.ts +10 -5
  496. package/src/pty-shell/pty-manifest.ts +12 -3
  497. package/src/pty-shell/tui-run-state.ts +34 -3
  498. package/src/release-loop/gate-host-reservation.ts +97 -0
  499. package/src/release-loop/landing-freeze.ts +5 -0
  500. package/src/release-loop/light-rc.ts +5 -2
  501. package/src/release-loop/placement.ts +92 -1
  502. package/src/release-loop/rehearsal-shard-plan.ts +149 -0
  503. package/src/release-loop/rehearsal.ts +73 -17
  504. package/src/repl/index.ts +20 -2
  505. package/src/seat-loop/seat-knowhow.ts +282 -0
  506. package/src/seat-loop/seat-loop.ts +41 -2
  507. package/src/seat-loop/traffic-signal.ts +5 -1
  508. package/src/self-dev/ask-launch-flow.ts +37 -3
  509. package/src/self-dev/decompose-compose-graph.ts +28 -27
  510. package/src/self-dev/decompose-proposal.ts +53 -38
  511. package/src/self-dev/decompose.ts +17 -0
  512. package/src/self-dev/dev-pipeline.ts +31 -2
  513. package/src/self-dev/draft-residue.ts +267 -33
  514. package/src/self-dev/draft-sweep.ts +59 -4
  515. package/src/self-dev/external-call-zero.ts +77 -0
  516. package/src/self-dev/launch-preflight-text.ts +6 -0
  517. package/src/self-dev/launch-preflight.ts +25 -3
  518. package/src/self-dev/local-supervisor-judge.ts +185 -0
  519. package/src/self-dev/run-supervisor.ts +229 -19
  520. package/src/self-dev/run-types.ts +20 -0
  521. package/src/self-dev/shard-aggregate.ts +13 -2
  522. package/src/self-dev/shard-plan.ts +56 -1
  523. package/src/self-dev/shard-run.ts +207 -12
  524. package/src/self-dev/spawn-lane-files.ts +19 -0
  525. package/src/self-implement/app-api-budget.ts +51 -11
  526. package/src/self-implement/config-gate.ts +2 -1
  527. package/src/self-implement/elanous-tui-spawn.ts +14 -0
  528. package/src/self-implement/expose-gate.ts +2 -1
  529. package/src/self-implement/follow-up-placement.ts +79 -0
  530. package/src/self-implement/gate-artifacts.ts +416 -0
  531. package/src/self-implement/gate-baseline.ts +96 -5
  532. package/src/self-implement/gate-cli.ts +207 -17
  533. package/src/self-implement/gate-remote.ts +136 -26
  534. package/src/self-implement/gate-scenario.ts +85 -0
  535. package/src/self-implement/goal-author.ts +160 -8
  536. package/src/self-implement/graph-authority.ts +38 -6
  537. package/src/self-implement/graph-overlay-condition.ts +92 -1
  538. package/src/self-implement/heal-triage.ts +79 -0
  539. package/src/self-implement/host-regate.ts +97 -7
  540. package/src/self-implement/orchestrator.ts +115 -134
  541. package/src/self-implement/pr-title.ts +123 -0
  542. package/src/self-implement/run-checkpoint.ts +235 -0
  543. package/src/self-implement/run-ledger.ts +162 -15
  544. package/src/self-implement/run-stop.ts +4 -3
  545. package/src/self-implement/run-ttl.ts +28 -4
  546. package/src/self-implement/seams.ts +2 -0
  547. package/src/self-implement/shadow-stage.ts +7 -6
  548. package/src/self-implement/stop-autoheal.ts +2 -1
  549. package/src/self-implement/train-gate-remote.ts +37 -8
  550. package/src/self-implement/train-reach-grouping.ts +157 -0
  551. package/src/self-implement/train-scenario-layers.ts +133 -0
  552. package/src/self-implement/uncommitted-work.ts +2 -0
  553. package/src/session/pending-input.ts +19 -0
  554. package/src/session/session-start.ts +224 -0
  555. package/src/session-runtime/index.ts +22 -267
  556. package/src/session-runtime/parallel-dispatch.ts +22 -5
  557. package/src/shell-runner/background-surface.ts +15 -5
  558. package/src/skills/tools/agent.ts +39 -6
  559. package/src/skills/tools/dev-harness.ts +6 -4
  560. package/src/skills/tools/list-dir.ts +11 -0
  561. package/src/skills/tools/schedule-wakeup.ts +408 -0
  562. package/src/skills/tools/shell.ts +246 -4
  563. package/src/status/bar.ts +26 -0
  564. package/src/steward/digest-delivery.ts +118 -0
  565. package/src/steward/hold-hygiene.ts +120 -0
  566. package/src/steward/resync-tick.ts +114 -23
  567. package/src/steward/ta-repair-event-collect.ts +158 -0
  568. package/src/steward/triage.ts +10 -0
  569. package/src/surface/shell-runner-boot.ts +5 -2
  570. package/src/task-agent/card-evidence.ts +25 -1
  571. package/src/task-agent/green-sweep.ts +8 -3
  572. package/src/task-agent/judge.ts +76 -0
  573. package/src/task-agent/land-queue.ts +79 -0
  574. package/src/task-agent/live-moves.ts +30 -9
  575. package/src/task-agent/postland-card.ts +5 -0
  576. package/src/task-agent/prelaunch-already-done.ts +98 -0
  577. package/src/task-agent/real-launch-guard.ts +37 -0
  578. package/src/task-agent/rejudge-on-head.ts +89 -12
  579. package/src/task-agent/remote-rejudge-bind.ts +28 -8
  580. package/src/task-agent/repair-cycle.ts +45 -7
  581. package/src/task-agent/repair-worker.ts +7 -0
  582. package/src/task-agent/run-identity.ts +200 -0
  583. package/src/task-agent/shadow.ts +50 -3
  584. package/src/task-agent/task-hand.ts +182 -5
  585. package/src/task-agent/train-landing.ts +77 -0
  586. package/src/task-agent/work-order.ts +104 -0
  587. package/src/task-orchestrator/surfaces/pod-command-job.ts +151 -37
  588. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
  589. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
  590. package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
  591. package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
  592. package/src/task-orchestrator/surfaces/pod-lease.ts +118 -6
  593. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +1 -1
  594. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
  595. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
  596. package/src/task-orchestrator/surfaces/pod-pool.ts +3 -1
  597. package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
  598. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +67 -0
  599. package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
  600. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
  601. package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
  602. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +525 -0
  603. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
  604. package/src/task-orchestrator/surfaces/pod-warm-worker-runner.ts +90 -0
  605. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +362 -0
  606. package/src/task-orchestrator/surfaces/self-implement-pod.ts +138 -19
  607. package/src/telegram.ts +2 -4
  608. package/src/tui/chat/execution-badge.ts +5 -1
  609. package/src/tui/input/pickers.ts +732 -0
  610. package/src/tui/input-lag-probe.ts +230 -0
  611. package/src/tui/slash/mission.ts +492 -0
  612. package/src/tui/slash/term.ts +877 -0
  613. package/src/tui-client/dashboard-session.ts +9 -0
  614. package/src/tui.ts +52 -0
  615. package/src/user-config/gemini-server-tools.ts +9 -0
  616. package/src/user-config.ts +53 -16
  617. package/src/util/spawn-sync-output.ts +7 -0
  618. package/src/ux-sim/fake-bin.ts +154 -0
  619. package/src/ux-sim/fake-clock.ts +36 -0
  620. package/src/ux-sim/headless-tui.ts +72 -0
  621. package/src/ux-sim/in-process-cli.ts +2 -1
  622. package/src/ux-sim/scenario.ts +255 -0
  623. package/src/ux-sim/temp-git-remote.ts +82 -0
  624. package/src/version/packed-revision.json +1 -1
  625. package/src/video-pipeline/recipes/vlog.ts +25 -7
  626. package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
  630. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
  632. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
  635. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
  636. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
  639. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
  641. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
  647. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
  651. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
  662. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
  668. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
  671. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
  672. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
  673. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
  676. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
  678. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
  679. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
  680. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
  682. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
  688. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
  695. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
  698. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
  703. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
  705. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/botlab/page-a5635eba0d73b84e.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9f92737b8766009a.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
  768. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
  774. package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +0 -1
  775. /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → IVKr3AlRUVLKsw2fh7eXF}/_ssgManifest.js +0 -0
@@ -201,6 +201,7 @@ export class DashboardSession {
201
201
  dispatchTool: opts.dispatchTool,
202
202
  ...(opts.onTurnComplete ? { onTurnComplete: opts.onTurnComplete } : {}),
203
203
  ...(opts.resolveModel ? { resolveModel: opts.resolveModel } : {}),
204
+ ...(opts.resolveSeat ? { resolveSeat: opts.resolveSeat } : {}),
204
205
  ...(opts.resolveMaxToolTurns
205
206
  ? { resolveMaxToolTurns: opts.resolveMaxToolTurns }
206
207
  : {}),
@@ -467,6 +468,14 @@ export class DashboardSession {
467
468
  this.sessionId = newSessionId;
468
469
  }
469
470
 
471
+ /** TUI-H8 ② — `/session new` 이 백엔드(ACP) 세션까지 새로 받는다. 같은 연결에서 `session/new` 를 다시 불러
472
+ * 새 id 로 갈아탄다(종전엔 TUI 기록만 비우고 ACP sessionId 가 그대로였다 · #69). 새 id 를 돌려준다. */
473
+ async renew(cwd: string): Promise<string> {
474
+ const { sessionId } = await this.client.newSession({ cwd, mcpServers: [] });
475
+ this.sessionId = sessionId;
476
+ return sessionId;
477
+ }
478
+
470
479
  /** Send a single user prompt and await the turn's stopReason.
471
480
  * Streaming text deltas and tool / usage events are delivered via
472
481
  * the optional callbacks on `req`. */
package/src/tui.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  import chalk from 'chalk';
6
6
  import { StringDecoder } from 'node:string_decoder';
7
7
  import { perf } from './perf-counters.js';
8
+ import { noteInputLagKey, noteInputLagPaint } from './tui/input-lag-probe.js';
8
9
  import { debug } from './debug/log.js';
9
10
 
10
11
  // ── ANSI escape sequences ──
@@ -523,6 +524,12 @@ const _keyQueue: Key[] = [];
523
524
  export type KeyTraceSource = 'main' | 'stream' | 'input';
524
525
 
525
526
  let _keyTracer: ((key: Key, source: KeyTraceSource) => void) | null = null;
527
+ let _lastHumanKeyAt = 0;
528
+
529
+ /** 마지막으로 배달된 사람 키 시각(ms · 0 = 아직 없음) — 내부 턴 문(H2)의 조용창 판정에 쓴다. */
530
+ export function lastHumanKeyAt(): number {
531
+ return _lastHumanKeyAt;
532
+ }
526
533
 
527
534
  /** Install a tracer invoked with every dispatched Key. Set to null to
528
535
  * detach. Exceptions thrown by the tracer are swallowed so a broken
@@ -534,6 +541,8 @@ export function setKeyTracer(fn: ((key: Key, source: KeyTraceSource) => void) |
534
541
  /** Call the installed tracer, if any. Safe to invoke unconditionally —
535
542
  * becomes a noop when no tracer is registered. */
536
543
  export function traceKey(key: Key, source: KeyTraceSource): void {
544
+ // H2 내부 턴 문 — «마지막 사람 키» 시각. 빈 이름(readKey 취소·빈 깨움)·리스너 표지는 사람 키가 아니다.
545
+ if (key.name && !key.name.startsWith('listener-')) _lastHumanKeyAt = Date.now();
537
546
  if (!_keyTracer) return;
538
547
  try { _keyTracer(key, source); } catch { /* swallow — never break input */ }
539
548
  }
@@ -903,6 +912,7 @@ export function readKey(source: KeyTraceSource = 'main'): Promise<Key> {
903
912
  // split across chunk boundaries need a pending buffer that belongs
904
913
  // to this stream alone.
905
914
  const keys = _stdinParser.push(data);
915
+ if (keys.length > 0) noteInputLagKey(keys.length);
906
916
 
907
917
  // 2026-04-30 — also drain `_keyQueue` here so an `injectKey`
908
918
  // call that happened while `readKey` was already awaiting on
@@ -955,7 +965,9 @@ export function readKey(source: KeyTraceSource = 'main'): Promise<Key> {
955
965
  * §8.6 — "(A) auto-Enter via injectKey" approach. */
956
966
  export function injectKey(key: Key): boolean {
957
967
  if (!_raw) return false;
968
+ noteInputLagKey();
958
969
  _keyQueue.push(key);
970
+ _injectedKeys.add(key);
959
971
  // Wake any in-flight readKey awaiting on stdin by emitting an empty
960
972
  // chunk. The handler's queue-drain branch picks up the injected key
961
973
  // immediately.
@@ -965,6 +977,38 @@ export function injectKey(key: Key): boolean {
965
977
  return true;
966
978
  }
967
979
 
980
+ /** `injectKey` 로 들어온 키 표지 — `takeInjectedKeys` 가 stdin 잔여 키(readKey 몫)는 두고 주입 키만 꺼낸다. */
981
+ const _injectedKeys = new WeakSet<Key>();
982
+
983
+ /** ⭐ TUI-ESC-ABORT-TOOLS (2026-10-15) — 턴 중 스트리밍 리스너(`attachStreamingKeys`)가
984
+ * 바깥에서 주입된 키(`pty key` · 제어 IPC input-key → `injectKey`)를 받게 큐에서 꺼낸다.
985
+ * ⛔ readKey 가 걸려 있으면(`_cancelReadKey`) 큐는 그 readKey 의 몫이다 — 빈 배열을 돌려준다.
986
+ * ⛔ stdin 청크 잔여 키(readKey 가 넣은 것)는 건드리지 않는다. readKey 의 drain 동작은 그대로다. */
987
+ export function takeInjectedKeys(): Key[] {
988
+ if (_cancelReadKey || _keyQueue.length === 0) return [];
989
+ const taken: Key[] = [];
990
+ for (let i = 0; i < _keyQueue.length; ) {
991
+ const k = _keyQueue[i]!;
992
+ if (_injectedKeys.has(k)) {
993
+ taken.push(k);
994
+ _keyQueue.splice(i, 1);
995
+ } else {
996
+ i += 1;
997
+ }
998
+ }
999
+ // 같은 Key 객체가 두 번 주입될 수 있으므로 표지는 다 꺼낸 «뒤에» 지운다.
1000
+ for (const k of taken) _injectedKeys.delete(k);
1001
+ return taken;
1002
+ }
1003
+
1004
+ /** ⭐ H2 내부 턴 문 — 걸려 있는 readKey 를 «빈 키»로 깨운다(키를 만들지도 큐에 넣지도 않는다).
1005
+ * stdin 에 남은 바이트는 그대로 다음 readKey 몫이다. 걸린 readKey 가 없으면 false. */
1006
+ export function cancelPendingReadKey(): boolean {
1007
+ if (!_cancelReadKey) return false;
1008
+ _cancelReadKey();
1009
+ return true;
1010
+ }
1011
+
968
1012
  /** 아직 readKey 가 소비하지 않은 키 수 — 외부 입력 대기열이 «사용자 키보다 앞서» 끼어들지 않게 본다. */
969
1013
  export function pendingKeyCount(): number {
970
1014
  return _keyQueue.length;
@@ -997,6 +1041,13 @@ export function resetRenderCache(): void {
997
1041
  _lastFrameCols = 0;
998
1042
  }
999
1043
 
1044
+ /** True when the frame cache says `row` (0-based) currently shows
1045
+ * exactly `text` — a direct writer can skip repainting it. Invalidated
1046
+ * rows hold a sentinel that never matches. */
1047
+ export function renderCacheRowIs(row: number, text: string): boolean {
1048
+ return row >= 0 && row < _lastFrameLines.length && _lastFrameLines[row] === text;
1049
+ }
1050
+
1000
1051
  /** Invalidate a specific row in the frame cache without nuking the
1001
1052
  * whole thing. Callers that do direct stdout writes to a narrow
1002
1053
  * band (input prompt, cursor moves) use this instead of
@@ -1061,6 +1112,7 @@ export function render(lines: string[], opts: RenderOptions = {}): void {
1061
1112
  }
1062
1113
  perf.recordStdoutWrite(buf.length, true);
1063
1114
  perf.markDrawEnd();
1115
+ noteInputLagPaint();
1064
1116
 
1065
1117
  _lastFrameLines = lines.slice(0, lineCount);
1066
1118
  _lastFrameRows = rows;
@@ -0,0 +1,9 @@
1
+ export function parseGeminiServerTools(raw: unknown): { googleSearch?: boolean; codeExecution?: boolean; urlContext?: boolean } | undefined {
2
+ if (!raw || typeof raw !== 'object') return undefined;
3
+ const obj = raw as Record<string, unknown>;
4
+ const out: { googleSearch?: boolean; codeExecution?: boolean; urlContext?: boolean } = {};
5
+ if (obj.googleSearch === true) out.googleSearch = true;
6
+ if (obj.codeExecution === true) out.codeExecution = true;
7
+ if (obj.urlContext === true) out.urlContext = true;
8
+ return (Object.keys(out).length > 0) ? out : undefined;
9
+ }
@@ -71,6 +71,7 @@ import { migrateLegacyXdgUserConfig } from './storage/legacy-elanous-config-migr
71
71
  import { withFileLockSync } from './storage/file-lock.js';
72
72
  import { debug } from './debug/log.js';
73
73
  import { setConfigTimeZoneSource } from './time/format.js';
74
+ import { parseGeminiServerTools } from './user-config/gemini-server-tools.js';
74
75
  import type { FoldMode } from './log-entry.js';
75
76
  import {
76
77
  CLAUDE_PACKAGE_MISSING,
@@ -85,6 +86,7 @@ import {
85
86
  parseGroundingSources,
86
87
  type GroundingConfig,
87
88
  } from './grounding/sources.js';
89
+ import { parseSeatTurnCapConfig, type SeatTurnCapConfig } from './core-turn/seat-turn-cap.js';
88
90
 
89
91
  // ── SkillRouter (existing) ───────────────────────────────────────────
90
92
 
@@ -1544,6 +1546,8 @@ export function parseErrorReportsConfig(raw: unknown): ErrorReportsConfig | unde
1544
1546
 
1545
1547
  export interface ChatConfig {
1546
1548
  factQuestion: { maxToolTurns: number };
1549
+ /** TUI-SEAT-TURN-CAP — 자리 TUI goal loop 한정 core 턴 상한 덮어쓰기(기본값 = core-turn/seat-turn-cap.ts). 설정했을 때만 있다. */
1550
+ seatTurnCap?: Partial<SeatTurnCapConfig>;
1547
1551
  /** Short questions may receive a tool-free first reply. Default true. */
1548
1552
  fastPath: boolean;
1549
1553
  conciseness: ChatConcisenessConfig;
@@ -3656,6 +3660,8 @@ export interface OrchestratorLoopConfig {
3656
3660
  seatCaps: Record<OrchestratorSeat, number>;
3657
3661
  /** Max new delegations per tick; absent means no limit. */
3658
3662
  maxDelegatePerTick?: number;
3663
+ /** Dispatch placement preference and local concurrency lane. Defaults preserve the existing Pod preference and one local lane. */
3664
+ dispatch: { podTarget: number; localLane: number };
3659
3665
  /** Per-seat release gate; absent seats retain the spawn-budget default. */
3660
3666
  releaseGate?: Partial<Record<OrchestratorSeat, number>>;
3661
3667
  trafficMode: 'shadow' | 'live';
@@ -3673,7 +3679,7 @@ export interface OrchestratorLoopConfig {
3673
3679
  }
3674
3680
 
3675
3681
  export const ORCHESTRATOR_DEFAULTS: OrchestratorLoopConfig = {
3676
- mode: 'shadow', seatTrees: {}, seatCaps: { TC: 8, UX: 6, MK: 6, OP: 4 }, trafficMode: 'shadow', idleRequest: 'shadow', finishGate: 'shadow',
3682
+ mode: 'shadow', seatTrees: {}, seatCaps: { TC: 8, UX: 6, MK: 6, OP: 4 }, dispatch: { podTarget: 18, localLane: 1 }, trafficMode: 'shadow', idleRequest: 'shadow', finishGate: 'shadow',
3677
3683
  };
3678
3684
 
3679
3685
  export function parseOrchestratorLoopConfig(raw: unknown): OrchestratorLoopConfig {
@@ -3696,7 +3702,14 @@ export function parseOrchestratorLoopConfig(raw: unknown): OrchestratorLoopConfi
3696
3702
  }
3697
3703
  const mode = value.mode === 'off' || value.mode === 'live' ? value.mode : 'shadow';
3698
3704
  const maxDelegatePerTick = value.maxDelegatePerTick;
3699
- return { mode, seatTrees, seatCaps,
3705
+ const rawDispatch = value.dispatch && typeof value.dispatch === 'object' && !Array.isArray(value.dispatch)
3706
+ ? value.dispatch as Record<string, unknown> : {};
3707
+ const dispatch = { ...ORCHESTRATOR_DEFAULTS.dispatch };
3708
+ for (const field of ['podTarget', 'localLane'] as const) {
3709
+ const setting = rawDispatch[field];
3710
+ if (typeof setting === 'number' && Number.isSafeInteger(setting) && setting >= 0) dispatch[field] = setting;
3711
+ }
3712
+ return { mode, seatTrees, seatCaps, dispatch,
3700
3713
  ...(typeof maxDelegatePerTick === 'number' && Number.isSafeInteger(maxDelegatePerTick) && maxDelegatePerTick >= 0 ? { maxDelegatePerTick } : {}),
3701
3714
  ...(Object.keys(releaseGate).length ? { releaseGate } : {}),
3702
3715
  trafficMode: value.trafficMode === 'live' ? 'live' : 'shadow',
@@ -3792,8 +3805,10 @@ export interface GateRemoteConfig {
3792
3805
  host?: string;
3793
3806
  /** Local 1-min load average above which checks go remote (default 20). */
3794
3807
  loadThreshold?: number;
3795
- /** Concurrent heavy checks per remote host (default and ceiling 2 — config may only lower it). */
3808
+ /** Legacy default cap for hosts without an entry in hostCaps (1..2, default 2). */
3796
3809
  hostCap?: number;
3810
+ /** Per SSH host concurrent heavy-check slots (1..8); overrides hostCap for that host. */
3811
+ hostCaps?: Record<string, number>;
3797
3812
  /** Bare mirror on the host (default ~/mirror/elanous-agent.git — shared with the release gate). */
3798
3813
  mirror?: string;
3799
3814
  /** Seconds to wait for a free host slot before running locally (default 600). */
@@ -3811,6 +3826,12 @@ export function parseGateRemoteConfig(raw: unknown): GateRemoteConfig | undefine
3811
3826
  if (typeof v === 'number' && Number.isFinite(v) && v >= 0) out[key] = v;
3812
3827
  }
3813
3828
  if (typeof r.hostCap === 'number' && Number.isSafeInteger(r.hostCap) && r.hostCap > 0 && r.hostCap <= 2) out.hostCap = r.hostCap;
3829
+ if (r.hostCaps && typeof r.hostCaps === 'object' && !Array.isArray(r.hostCaps)) {
3830
+ const caps = Object.fromEntries(Object.entries(r.hostCaps).filter(([host, cap]) =>
3831
+ /^(?:[\w.-]+@)?[\w.-]+$/.test(host) && !host.startsWith('-') &&
3832
+ typeof cap === 'number' && Number.isSafeInteger(cap) && cap >= 1 && cap <= 8)) as Record<string, number>;
3833
+ if (Object.keys(caps).length) out.hostCaps = caps;
3834
+ }
3814
3835
  return Object.keys(out).length ? out : undefined;
3815
3836
  }
3816
3837
 
@@ -3871,7 +3892,7 @@ export interface UserConfig {
3871
3892
  guardian?: { mode?: 'shadow' | 'live'; /** Orphan CLI GC on the guardian tick: off = no ps collection, shadow (default) = evidence only, on = evidence then SIGTERM. */ orphanGc?: 'off' | 'shadow' | 'on' };
3872
3893
  /** Task-agent live move allow-list (`src/task-agent/live-moves.ts` validates its vocabulary).
3873
3894
  * Absent = env ELANOUS_TASK_AGENT_LIVE_MOVES, else none (pure shadow). */
3874
- taskAgent?: { liveMoves?: string[]; /** TA-REJUDGE-PERIODIC — steward tick runs `tasks rejudge --all` every N minutes (absent/0 = off). */ rejudgeEveryMinutes?: number; /** 1-minute load average above which that tick is skipped (default 60). */ rejudgeMaxLoad?: number; /** TA-REPAIR-TICK-CAP — new repair launches per `tasks rejudge --all` (default 3, 0 = none). */ repairMaxPerTick?: number; parentHost?: { host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number } | Array<{ host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number }> };
3895
+ taskAgent?: { liveMoves?: string[]; /** TA-REJUDGE-PERIODIC — steward tick runs `tasks rejudge --all` every N minutes (absent/0 = off). */ rejudgeEveryMinutes?: number; /** 1-minute load average above which that tick is skipped (default 60). */ rejudgeMaxLoad?: number; /** TA-REPAIR-TICK-CAP — new repair launches per `tasks rejudge --all` (default 3, 0 = none). */ repairMaxPerTick?: number; /** TA-LAND-AFTER-REVIEW — opt-in external queue adapter, never a direct merge command. */ landQueue?: { command: string; remote: string }; parentHost?: { host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number } | Array<{ host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number }> };
3875
3896
  events?: EventsConfig;
3876
3897
  /** GATE-REMOTE — see GateRemoteConfig. Absent = defaults (auto on · node-b · load 20 · cap 2). */
3877
3898
  gateRemote?: GateRemoteConfig;
@@ -3907,7 +3928,7 @@ export interface UserConfig {
3907
3928
  followUp?: 'shadow' | 'live';
3908
3929
  };
3909
3930
  /** ☸️ Pod 실행 칸 — `pool` = 기존 기본 풀(`컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트]` 쉼표 · 앞이 우선). harness 실행은 인자·ELANOUS_POD_POOL·harness.podPool 다음으로 읽는다. */
3910
- pod?: { pool?: string; /** 호스트 Git 미러 디렉터리 — Pod Job 에 읽기 전용으로 마운트한다. */ hostMirror?: string; /** 원격 그라운딩 엔드포인트(호스트 nexus · tailnet 주소) — Pod 가 토큰으로 «질의→인용»만 묻는다(P13). */ groundingUrl?: string; /** 읽기 전용 Pod lease 권장에 쓰는 계정별 동시 수. */ lease?: { perAccount?: number }; /** 실측 권고를 Pod 발사 기본값으로 쓸지 (기본 off). */ memory?: { adviseDefaults?: boolean }; /** 명령 Job 자식 로그(child.log) 상한 바이트. 양의 정수만. 넘으면 끝부분 우선. */ childLogMaxBytes?: number };
3931
+ pod?: { pool?: string; /** 호스트 Git 미러 디렉터리 — Pod Job 에 읽기 전용으로 마운트한다. */ hostMirror?: string; /** 원격 그라운딩 엔드포인트(호스트 nexus · tailnet 주소) — Pod 가 토큰으로 «질의→인용»만 묻는다(P13). */ groundingUrl?: string; /** 읽기 전용 Pod lease 권장에 쓰는 계정별 동시 수. */ lease?: { perAccount?: number }; /** 실측 권고를 Pod 발사 기본값으로 쓸지 (기본 off). */ memory?: { adviseDefaults?: boolean }; /** 명령 Job 자식 로그(child.log) 상한 바이트. 양의 정수만. 넘으면 끝부분 우선. */ childLogMaxBytes?: number; /** warm Pod 재사용 실전 손잡이(소비자별 · 기본 off · 문자 그대로 true 만). 판정 = pod-warm-switch.ts `decideWarmReuse` — 증거가 모자라면 flag 가 켜져도 off. */ warmReuse?: { gateRecheck?: boolean; land?: boolean; ta?: boolean; /** 연속 일치 표본 하한(양의 정수 · 기본 3). */ minMatchSamples?: number } };
3911
3932
  skillRouter: SkillRouterConfig;
3912
3933
  llm: LLMConfig;
3913
3934
  skills: SkillsConfig;
@@ -4195,7 +4216,21 @@ function parseTaskAgentConfig(raw: unknown): UserConfig['taskAgent'] {
4195
4216
  if (Number.isSafeInteger(repairMaxPerTick) && (repairMaxPerTick as number) >= 0) rejudge.repairMaxPerTick = repairMaxPerTick as number;
4196
4217
  else warnUserConfigDrop('taskAgent.repairMaxPerTick', `음이 아닌 정수가 아니다(${JSON.stringify(repairMaxPerTick)}) — 기본 3`);
4197
4218
  }
4198
- const extras = { ...rejudge, ...(parentHost ? { parentHost } : {}) };
4219
+ const queueRaw = (raw as Record<string, unknown>).landQueue;
4220
+ let landQueue: { command: string; remote: string } | undefined;
4221
+ if (queueRaw !== undefined) {
4222
+ if (queueRaw && typeof queueRaw === 'object' && !Array.isArray(queueRaw)
4223
+ && typeof (queueRaw as Record<string, unknown>).command === 'string'
4224
+ && isAbsolute((queueRaw as Record<string, string>).command)
4225
+ && typeof (queueRaw as Record<string, unknown>).remote === 'string'
4226
+ && /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test((queueRaw as Record<string, string>).remote)) {
4227
+ landQueue = { command: (queueRaw as Record<string, string>).command, remote: (queueRaw as Record<string, string>).remote };
4228
+ } else {
4229
+ warnUserConfigDrop('taskAgent.landQueue', '절대 command 경로와 유효한 remote 호스트가 필요 — 착지 fail-closed');
4230
+ landQueue = { command: '', remote: '' };
4231
+ }
4232
+ }
4233
+ const extras = { ...rejudge, ...(parentHost ? { parentHost } : {}), ...(landQueue ? { landQueue } : {}) };
4199
4234
  const liveMoves = (raw as Record<string, unknown>).liveMoves;
4200
4235
  if (liveMoves === undefined) return Object.keys(extras).length ? extras : undefined;
4201
4236
  // 설정이 «있으면» 환경 변수로 내려가지 않는다 — 배열이 아니면 빈 목록(fail-closed), 문자열 밖 항목은 글자로 바꿔 넘겨
@@ -5083,6 +5118,17 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
5083
5118
  return typeof lease.perAccount === 'number' && Number.isSafeInteger(lease.perAccount) && lease.perAccount > 0
5084
5119
  ? lease.perAccount : 4;
5085
5120
  })() },
5121
+ warmReuse: (() => {
5122
+ const warm = legacyPod.warmReuse && typeof legacyPod.warmReuse === 'object' && !Array.isArray(legacyPod.warmReuse)
5123
+ ? (legacyPod.warmReuse as Record<string, unknown>) : {};
5124
+ return {
5125
+ gateRecheck: warm.gateRecheck === true,
5126
+ land: warm.land === true,
5127
+ ta: warm.ta === true,
5128
+ minMatchSamples: typeof warm.minMatchSamples === 'number' && Number.isSafeInteger(warm.minMatchSamples) && warm.minMatchSamples > 0
5129
+ ? warm.minMatchSamples : 3,
5130
+ };
5131
+ })(),
5086
5132
  },
5087
5133
  harness: {
5088
5134
  edgeRail: (() => {
@@ -5452,6 +5498,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
5452
5498
  && Number.isSafeInteger(chatFactQuestion.maxToolTurns) && chatFactQuestion.maxToolTurns > 0
5453
5499
  ? chatFactQuestion.maxToolTurns : CHAT_DEFAULTS.factQuestion.maxToolTurns,
5454
5500
  },
5501
+ ...((): { seatTurnCap?: Partial<SeatTurnCapConfig> } => { const c = parseSeatTurnCapConfig(chat.seatTurnCap); return c ? { seatTurnCap: c } : {}; })(),
5455
5502
  fastPath: chat.fastPath === false || chat.fastPath === 'false' ? false : CHAT_DEFAULTS.fastPath,
5456
5503
  conciseness: {
5457
5504
  enabled: chatConciseness.enabled === false ? false : CHAT_CONCISENESS_DEFAULTS.enabled,
@@ -7078,16 +7125,6 @@ function parseMemoryJudge(raw: unknown): { enabled?: boolean; model?: string; cr
7078
7125
  return (out.enabled !== undefined || out.model !== undefined || out.crossRecall !== undefined) ? out : undefined;
7079
7126
  }
7080
7127
 
7081
- function parseGeminiServerTools(raw: unknown): { googleSearch?: boolean; codeExecution?: boolean; urlContext?: boolean } | undefined {
7082
- if (!raw || typeof raw !== 'object') return undefined;
7083
- const obj = raw as Record<string, unknown>;
7084
- const out: { googleSearch?: boolean; codeExecution?: boolean; urlContext?: boolean } = {};
7085
- if (obj.googleSearch === true) out.googleSearch = true;
7086
- if (obj.codeExecution === true) out.codeExecution = true;
7087
- if (obj.urlContext === true) out.urlContext = true;
7088
- return (Object.keys(out).length > 0) ? out : undefined;
7089
- }
7090
-
7091
7128
  function parseAnswerPriority(raw: unknown): 'cost' | 'balanced' | 'quality' | 'exhaustive' | undefined {
7092
7129
  return raw === 'cost' || raw === 'balanced' || raw === 'quality' || raw === 'exhaustive'
7093
7130
  ? raw
@@ -1,5 +1,12 @@
1
1
  import { spawnSync, type SpawnSyncOptionsWithStringEncoding } from 'node:child_process';
2
2
 
3
+ /**
4
+ * Default maxBuffer for harness · Pod · gate `spawnSync` calls that read child output.
5
+ * Node's 1 MiB default truncated `git ls-files` (1.54 MiB in W2b · 0.2.30 HARD #3) — same value as #28476.
6
+ * The ratchet `test/spawn-sync-max-buffer.test.ts` keeps new readers in those trees on an explicit maxBuffer.
7
+ */
8
+ export const SPAWN_SYNC_MAX_BUFFER = 16 * 1024 * 1024;
9
+
3
10
  /** Read command text completely or fail closed; never return a partial stdout. */
4
11
  export function spawnSyncText(
5
12
  cmd: string,
@@ -0,0 +1,154 @@
1
+ // Fake executables on PATH for tests whose code under test spawns an external CLI
2
+ // (grok · magick · tesseract · …) that a gate Pod does not have.
3
+ //
4
+ // The industry-standard shape is a «PATH shim»: a tiny shell script with the real
5
+ // name, placed first on PATH. This module only makes that shape shared, so tests
6
+ // stop hand-writing `writeFileSync + chmodSync` (MOCK-REVIEW R6 · MOCK-DEVICES-2 ⓑ).
7
+ //
8
+ // Bun resolves a child's executable from the PATH the process STARTED with when the
9
+ // call passes no `env`; `test/preload-child-env.ts` makes a later PATH change visible
10
+ // to such calls. Code that passes its own `env` must receive `fakeBins.env` (or a
11
+ // PATH built from `fakeBins.path()`).
12
+ //
13
+ // ⛔ This is not a simulator of the real tool: a spec only fixes stdout · stderr ·
14
+ // exit code · lifetime, and records argv. Behaviour of the real tool stays with
15
+ // tests that run where the tool exists.
16
+ import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
17
+ import { tmpdir } from 'node:os';
18
+ import { delimiter, join } from 'node:path';
19
+
20
+ export interface FakeBinSpec {
21
+ readonly stdout?: string;
22
+ readonly stderr?: string;
23
+ /** Exit code (default 0). */
24
+ readonly exitCode?: number;
25
+ /** Stay alive this long before exiting — for long-running daemons a test kills. */
26
+ readonly sleepSeconds?: number;
27
+ }
28
+
29
+ export interface FakeBinCall {
30
+ readonly name: string;
31
+ readonly argv: readonly string[];
32
+ }
33
+
34
+ export interface FakeBins {
35
+ /** Directory holding the fake executables. */
36
+ readonly dir: string;
37
+ /** Absolute path of one fake executable. */
38
+ bin(name: string): string;
39
+ /** PATH with the fake directory first (default base: the current PATH). */
40
+ path(base?: string): string;
41
+ /** `process.env` with the fake PATH, for code that passes its own `env`. */
42
+ readonly env: NodeJS.ProcessEnv;
43
+ /** Every recorded invocation, in order. */
44
+ calls(): FakeBinCall[];
45
+ /** Resolve once at least `count` invocations are recorded (a spawned child records asynchronously). */
46
+ waitForCalls(count: number, timeoutMs?: number): Promise<FakeBinCall[]>;
47
+ cleanup(): void;
48
+ }
49
+
50
+ const NAME = /^[A-Za-z0-9._+-]+$/;
51
+
52
+ function shellQuote(value: string): string {
53
+ return `'${value.replace(/'/g, `'\\''`)}'`;
54
+ }
55
+
56
+ function script(name: string, spec: FakeBinSpec, dataDir: string, logPath: string): string {
57
+ const lines = ['#!/bin/sh'];
58
+ // One record per call: name and each argv entry NUL-terminated (one printf), then an ASCII record
59
+ // separator \x1e (a second printf). `calls()` drops the unterminated tail, so a reader never sees half a record.
60
+ lines.push(`{ printf '%s\\0' ${shellQuote(name)} "$@"; printf '\\036'; } >> ${shellQuote(logPath)}`);
61
+ if (spec.stdout !== undefined) {
62
+ const file = join(dataDir, `${name}.stdout`);
63
+ writeFileSync(file, spec.stdout);
64
+ lines.push(`cat ${shellQuote(file)}`);
65
+ }
66
+ if (spec.stderr !== undefined) {
67
+ const file = join(dataDir, `${name}.stderr`);
68
+ writeFileSync(file, spec.stderr);
69
+ lines.push(`cat ${shellQuote(file)} >&2`);
70
+ }
71
+ const exitCode = spec.exitCode ?? 0;
72
+ if (spec.sleepSeconds !== undefined && spec.sleepSeconds > 0) {
73
+ const seconds = Math.ceil(spec.sleepSeconds);
74
+ // exit 0: `exec` so killing the fake kills the sleep itself. Any other code needs the shell to
75
+ // outlive the sleep; a fake killed mid-sleep then leaves `sleep` until `sleepSeconds` ends.
76
+ if (exitCode === 0) lines.push(`exec sleep ${seconds}`);
77
+ else lines.push(`sleep ${seconds}`);
78
+ }
79
+ lines.push(`exit ${exitCode}`);
80
+ return `${lines.join('\n')}\n`;
81
+ }
82
+
83
+ export function createFakeBins(specs: Readonly<Record<string, FakeBinSpec>>): FakeBins {
84
+ for (const name of Object.keys(specs)) {
85
+ if (!NAME.test(name) || name === '.' || name === '..') throw new Error(`fake-bin: invalid executable name ${JSON.stringify(name)}`);
86
+ }
87
+ const root = mkdtempSync(join(tmpdir(), 'ux-sim-fake-bin-'));
88
+ const dir = join(root, 'bin');
89
+ const dataDir = join(root, 'data');
90
+ const logPath = join(root, 'calls.log');
91
+ try {
92
+ mkdirSync(dir);
93
+ mkdirSync(dataDir);
94
+ writeFileSync(logPath, '');
95
+ for (const [name, spec] of Object.entries(specs)) {
96
+ const file = join(dir, name);
97
+ writeFileSync(file, script(name, spec, dataDir, logPath));
98
+ chmodSync(file, 0o755);
99
+ }
100
+ } catch (error) {
101
+ rmSync(root, { recursive: true, force: true });
102
+ throw error;
103
+ }
104
+ const path = (base = process.env.PATH ?? '') => (base ? `${dir}${delimiter}${base}` : dir);
105
+ return {
106
+ dir,
107
+ bin: (name) => join(dir, name),
108
+ path,
109
+ get env() {
110
+ return { ...process.env, PATH: path() };
111
+ },
112
+ calls() {
113
+ if (!existsSync(logPath)) return [];
114
+ // The segment after the last separator is either empty or a record still being written — never count it.
115
+ return readFileSync(logPath, 'utf8')
116
+ .split('\x1e')
117
+ .slice(0, -1)
118
+ .map((record) => {
119
+ const [name = '', ...argv] = record.split('\0').slice(0, -1);
120
+ return { name, argv };
121
+ });
122
+ },
123
+ async waitForCalls(count, timeoutMs = 5_000) {
124
+ const deadline = Date.now() + timeoutMs;
125
+ for (;;) {
126
+ const recorded = this.calls();
127
+ if (recorded.length >= count) return recorded;
128
+ if (Date.now() >= deadline) throw new Error(`fake-bin: expected ${count} call(s) within ${timeoutMs}ms, saw ${recorded.length}`);
129
+ await new Promise((resolve) => setTimeout(resolve, 20));
130
+ }
131
+ },
132
+ cleanup: () => rmSync(root, { recursive: true, force: true }),
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Put fake executables first on `process.env.PATH` for the duration of `run`,
138
+ * then restore PATH and remove the files — also when `run` throws.
139
+ */
140
+ export async function withFakeBins<T>(
141
+ specs: Readonly<Record<string, FakeBinSpec>>,
142
+ run: (fakeBins: FakeBins) => T | Promise<T>,
143
+ ): Promise<T> {
144
+ const fakeBins = createFakeBins(specs);
145
+ const previousPath = process.env.PATH;
146
+ process.env.PATH = fakeBins.path(previousPath ?? '');
147
+ try {
148
+ return await run(fakeBins);
149
+ } finally {
150
+ if (previousPath === undefined) delete process.env.PATH;
151
+ else process.env.PATH = previousPath;
152
+ fakeBins.cleanup();
153
+ }
154
+ }
@@ -0,0 +1,36 @@
1
+ // Bun's real test timer implementation, scoped so exceptions cannot leave
2
+ // Date or timers mocked for the next test. Use only in serial tests: timer
3
+ // replacement is process-global and does not affect child processes.
4
+ import { jest } from 'bun:test';
5
+
6
+ export interface SimClock {
7
+ tick(ms: number): void;
8
+ setTime(now: number | Date): void;
9
+ now(): number;
10
+ pendingTimers(): number;
11
+ }
12
+
13
+ let active = false;
14
+
15
+ export async function withSimClock<T>(now: number | Date, run: (clock: SimClock) => Promise<T> | T): Promise<T> {
16
+ if (active) throw new Error('sim clock is process-global; run scenarios serially');
17
+ active = true;
18
+ try {
19
+ jest.useFakeTimers({ now });
20
+ const clock: SimClock = {
21
+ tick(ms) {
22
+ if (!Number.isFinite(ms) || ms < 0) throw new Error('sim clock tick must be a nonnegative finite number');
23
+ jest.advanceTimersByTime(ms);
24
+ },
25
+ setTime(value) { jest.setSystemTime(value); },
26
+ now() { return Date.now(); },
27
+ pendingTimers() { return jest.getTimerCount(); },
28
+ };
29
+ return await run(clock);
30
+ }
31
+ finally {
32
+ jest.clearAllTimers();
33
+ jest.useRealTimers();
34
+ active = false;
35
+ }
36
+ }
@@ -0,0 +1,72 @@
1
+ // Capture the real dashboard/tui renderer at the stdout boundary, then let
2
+ // the already-installed xterm parser interpret its ANSI bytes. No child PTY.
3
+ import { Terminal } from '@xterm/headless';
4
+ import { renderDashboardFrame, type DashboardFrameInput } from '../dashboard/index.js';
5
+ import { resetRenderCache } from '../tui.js';
6
+
7
+ export interface HeadlessDashboardFrame {
8
+ lines: string[];
9
+ input: DashboardFrameInput;
10
+ }
11
+
12
+ export interface HeadlessDashboardSnapshot {
13
+ bytes: string;
14
+ lines: string[];
15
+ cursor: { row: number; col: number };
16
+ }
17
+
18
+ let capturing = false;
19
+
20
+ /** Serial-only: stdout and tui's frame cache are process globals. */
21
+ export async function simHeadlessDashboardFrames(
22
+ frames: readonly HeadlessDashboardFrame[],
23
+ size: { rows: number; cols: number } = { rows: 30, cols: 100 },
24
+ ): Promise<HeadlessDashboardSnapshot[]> {
25
+ if (capturing) throw new Error('headless TUI simulation is already capturing stdout');
26
+ if (size.rows < 1 || size.cols < 1) throw new Error('headless TUI size must be positive');
27
+ const terminal = new Terminal({ rows: size.rows, cols: size.cols, scrollback: 0, allowProposedApi: true });
28
+ capturing = true;
29
+ const stdout = process.stdout;
30
+ const originalWrite = stdout.write;
31
+ const originalRows = Object.getOwnPropertyDescriptor(stdout, 'rows');
32
+ const originalColumns = Object.getOwnPropertyDescriptor(stdout, 'columns');
33
+ const snapshots: HeadlessDashboardSnapshot[] = [];
34
+ try {
35
+ Object.defineProperty(stdout, 'rows', { configurable: true, value: size.rows });
36
+ Object.defineProperty(stdout, 'columns', { configurable: true, value: size.cols });
37
+ resetRenderCache();
38
+ for (const frame of frames) {
39
+ const chunks: string[] = [];
40
+ stdout.write = ((chunk: string | Uint8Array, encoding?: BufferEncoding | ((error?: Error | null) => void), callback?: (error?: Error | null) => void) => {
41
+ chunks.push(typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString());
42
+ const done = typeof encoding === 'function' ? encoding : callback;
43
+ done?.(null);
44
+ return true;
45
+ }) as typeof stdout.write;
46
+ try {
47
+ renderDashboardFrame(frame.lines, frame.input);
48
+ } finally {
49
+ stdout.write = originalWrite;
50
+ }
51
+ const bytes = chunks.join('');
52
+ await new Promise<void>((resolve) => terminal.write(bytes, resolve));
53
+ const buffer = terminal.buffer.active;
54
+ snapshots.push({
55
+ bytes,
56
+ lines: Array.from({ length: size.rows }, (_, row) =>
57
+ buffer.getLine(buffer.viewportY + row)?.translateToString(true) ?? ''),
58
+ cursor: { row: buffer.cursorY + 1, col: buffer.cursorX + 1 },
59
+ });
60
+ }
61
+ return snapshots;
62
+ } finally {
63
+ stdout.write = originalWrite;
64
+ if (originalRows) Object.defineProperty(stdout, 'rows', originalRows);
65
+ else Reflect.deleteProperty(stdout, 'rows');
66
+ if (originalColumns) Object.defineProperty(stdout, 'columns', originalColumns);
67
+ else Reflect.deleteProperty(stdout, 'columns');
68
+ resetRenderCache();
69
+ terminal.dispose();
70
+ capturing = false;
71
+ }
72
+ }
@@ -23,6 +23,7 @@ export interface InProcessCliOptions {
23
23
  type MutableCommand = {
24
24
  commands: MutableCommand[];
25
25
  name(): string;
26
+ aliases(): string[];
26
27
  _optionValues?: Record<string, unknown>;
27
28
  _optionValueSources?: Record<string, string>;
28
29
  args: string[];
@@ -35,7 +36,7 @@ function registeredCommandPath(root: MutableCommand, args: readonly string[]): s
35
36
  let command = root;
36
37
  for (const arg of args) {
37
38
  if (arg.startsWith('-')) break;
38
- const child = command.commands.find((candidate) => candidate.name() === arg);
39
+ const child = command.commands.find((candidate) => candidate.name() === arg || candidate.aliases().includes(arg));
39
40
  if (!child) break;
40
41
  path.push(arg);
41
42
  command = child;