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
@@ -41,6 +41,10 @@ import { attachLifecycleBridge } from '../signal/lifecycle-bridge.js';
41
41
  import { getChannelBus } from '../terminal-matrix/index.js';
42
42
  import type { ChannelBus } from '../terminal-matrix/channel-bus.js';
43
43
  import { startChildLivenessHeartbeat } from './child-liveness-heartbeat.js';
44
+ import {
45
+ SEAT_IDLE_NO_WORK_NOTICE, SEAT_TURN_CAP_CONTINUE_PROMPT, SEAT_TURN_CAP_TOOL_NOTICE,
46
+ isEmptyMailListResult, isIdleWaitCall, type SeatTurnCapConfig,
47
+ } from './seat-turn-cap.js';
44
48
 
45
49
  export {
46
50
  CHILD_LIVENESS_HEARTBEAT_ENV,
@@ -259,6 +263,37 @@ export function buildRejectedToolCompletionPrompt(rejectedTools: readonly string
259
263
  ].join('\n');
260
264
  }
261
265
 
266
+ /** TUI-GOAL-REPEAT-ANSWER(0.2.32) — goal loop 반복에서 모델이 이전 답을 다시 말할 때 화면에
267
+ * 같은 답이 두 번 그려지는 중복을 스트림 쪽에서 가려내는 «읽기-되돌림 인사(readback preface)»
268
+ * 문형. completion 판정의 readbackPreface(이 파일 하단 duplicate-answer 판정)와 같은 문형을
269
+ * 스트림 쪽에서도 쓴다 — 화면 중복 제거와 원장 중복 제거가 같은 모양을 같은 것으로 본다. 스트림은
270
+ * 문형이 한 글자씩 이어지는 중에도 판정해야 하므로(regex 전체 매칭이 아니라) 어구를 펼쳐둔 목록이다. */
271
+ const GOAL_REPEAT_READBACK_VERBS = [
272
+ '', '했습니다', '했지만', '해보니', '해 보니', '해봤지만', '해 봤지만', '했으나', '했는데',
273
+ ] as const;
274
+ const GOAL_REPEAT_READBACK_PHRASES: readonly string[] = [
275
+ '확인 결과',
276
+ ...GOAL_REPEAT_READBACK_VERBS.flatMap((verb) => (verb === ''
277
+ ? ['다시 확인', '방금 다시 확인']
278
+ : [`다시 확인${verb}`, `방금 다시 확인${verb}`])),
279
+ ];
280
+ /** preface 뒤에 올 수 있는 구분자(여백·콜론·마침표 등) — 답 앞에 붙은 만큼 통째로 뗀다. */
281
+ const GOAL_REPEAT_PREFACE_SEPS = /^[\s::,.!?。!?-]+/u;
282
+ /** TUI-GOAL-REPEAT-ANSWER — 스트림 쪽 답 비교 정규화: 여백 종류를 하나로 접고 끝여백을 뗀다. */
283
+ function goalRepeatStreamNormalize(text: string): string {
284
+ return text.replace(/\s+/gu, ' ').trim();
285
+ }
286
+
287
+ /** TUI-GOAL-REPEAT-ANSWER — «읽기-되돌림 인사(readback preface) ⊕ 답»에서 인사+구분자를 뗀 나머지(답
288
+ * 부분)를 돌려준다. 인사가 없으면 원문 그대로. 골 루프의 화면 중복 제거(스트림 대기·버림)와 브리지의
289
+ * 재표면화 판정(이미 그린 답인가)이 같은 문형을 같은 것으로 보게 하려고 내보낸다. */
290
+ export function stripGoalRepeatReadbackPreface(text: string): string {
291
+ for (const phrase of GOAL_REPEAT_READBACK_PHRASES) {
292
+ if (text.startsWith(phrase)) return text.slice(phrase.length).replace(GOAL_REPEAT_PREFACE_SEPS, '');
293
+ }
294
+ return text;
295
+ }
296
+
262
297
  export interface GoalLoopOptions {
263
298
  /** 목표 문구(관측·프레이밍용). 생략 시 마지막 user 메시지에서 추출. */
264
299
  objective?: string;
@@ -296,8 +331,22 @@ export interface GoalLoopOptions {
296
331
  * 최대 2번 재촉한다. 생략하면 harness role 이 executor 인 프로세스에서만 활성 provider 로 푼다.
297
332
  * null = 가드 꺼짐. 시험은 이 인자를 명시해 env 에 기대지 않는다. */
298
333
  intentStallProvider?: string | null;
334
+ /** TUI-H1-SEAT-GOALLOOP(#29 처방) — 자리 TUI 의 운영·읽기 지시를 goal loop 로 되돌린 턴에서만 참.
335
+ * update_goal(complete) 의 evidence 가 비었을 때 «증거 없음» 반려(재주입) 대신 그 턴의 (비지 않은) 답을 증거로 받아 끝낸다
336
+ * (10-14 OPT: 완료 선언 → 증거 부족 반려 → 재호출이 14회 · 사용자 답에 사과 문장). 시험 실패·거부된 도구 반려는 그대로다. */
337
+ lenientCompletionEvidence?: boolean;
338
+ /** TUI-SEAT-TURN-CAP — 자리 TUI 의 goal loop 에서만 준다(브리지가 route.reason 'seat-*' 로 판정). 없으면 상한·idle 판정 0(종전).
339
+ * ⓐ core 턴 1회당 도구 수·벽시계 상한 — 닿으면 넘는 도구는 실행하지 않고 «한 줄 진행 요약 ⊕ 턴 마감» 을 안내,
340
+ * 턴이 끝나면 stopReason 을 max_turns 로 두고 다음 반복으로 잇는다(반복 하드캡 maxIterations 는 그대로).
341
+ * ⓑ 같은 core 턴의 «새 항목 0» 우편 조회가 연속 idleEmptyMsgListLimit 번이면 «할 일 0» 으로 goal 을 완료한다(idle-no-work). */
342
+ seatTurnCap?: SeatTurnCapConfig & { seat: string };
343
+ /** Test seam — 벽시계(ms). 기본 Date.now. */
344
+ now?: () => number;
299
345
  }
300
346
 
347
+ /** TUI-SEAT-TURN-CAP — 상한·idle 안내 «뒤» 에도 도구 호출이 이만큼 넘게 오면 그 core 턴을 끝낸다. */
348
+ const SEAT_CAP_REFUSAL_BACKSTOP = 3;
349
+
301
350
  export type GoalLoopStopReason =
302
351
  | CoreTurnStopReason // aborted | error | end_turn | max_turns (마지막 turn 것)
303
352
  | 'goal_complete' // update_goal(complete)+evidence 로 완료 선언
@@ -348,6 +397,10 @@ function findRejectedToolCalls(newMessages: readonly LLMMessage[]): string[] {
348
397
  return [...rejected];
349
398
  }
350
399
 
400
+ /** `streamLLMWithTools` 의 빈 턴·예산 포기 경고(`buildNoFinalSynthesisNotice`) 문면 — 완료 판정 관측에서 «답 없음»으로 센다.
401
+ * 머리 표지만 보지 않고 런타임 문장까지 맞춰, 그 표지를 인용한 정상 답을 «경고»로 세지 않는다. */
402
+ const NO_FINAL_SYNTHESIS_NOTICE = /\[NO FINAL SYNTHESIS\] The model (?:stopped after repeated empty turns|used the available tool-loop turns without writing a plain-text answer)\./;
403
+
351
404
  /** 이 turn 의 새 메시지에서 마지막 `update_goal` 도구 호출을 찾아 구조화 종결 상태를
352
405
  * 반환한다. status 가 enum 밖이면 무시(null). evidence/reason 은 문자열만 수용. */
353
406
  function findGoalUpdate(
@@ -466,6 +519,8 @@ export async function runGoalLoop(
466
519
  const tools: LLMToolSpec[] = [...ctx.tools, updateGoalSpec];
467
520
 
468
521
  const noProgressLimit = opts.noProgressLimit ?? 2;
522
+ const now = opts.now ?? Date.now;
523
+ let seatCapHits = 0;
469
524
  let iterations = 0;
470
525
  let noProgress = 0;
471
526
  let blockedStreak = 0;
@@ -508,6 +563,20 @@ export async function runGoalLoop(
508
563
  ): GoalLoopResult => {
509
564
  if (terminalPublished) return result;
510
565
  terminalPublished = true;
566
+ // TUI-H1-GOALLOOP-EMPTY-TAIL — 완료 판정 한 줄: 목표가 닫혔나(goal-complete) · 사람에게 보일 답이 있나
567
+ // (answer-present) · 둘 다 아니다(none — 빈 답이거나 «[NO FINAL SYNTHESIS]» 경고가 최종 답).
568
+ try {
569
+ const finalTrimmed = result.finalText.trim();
570
+ const reason = result.goalComplete
571
+ ? 'goal-complete'
572
+ : finalTrimmed.length > 0 && !NO_FINAL_SYNTHESIS_NOTICE.test(finalTrimmed) ? 'answer-present' : 'none';
573
+ debug.log('goal.loop', 'completion-verdict', {
574
+ sessionId: ctx.sessionId, ...runAttribution,
575
+ iterations, reason, stopReason: result.stopReason, finalChars: result.finalText.length,
576
+ }, { level: 'info' });
577
+ } catch {
578
+ // Observability must not change the loop result.
579
+ }
511
580
  try {
512
581
  if (result.goalComplete) {
513
582
  publishGoalLifecycle(bus, 'complete', completePayload ?? {
@@ -632,6 +701,57 @@ export async function runGoalLoop(
632
701
  let iterUsageMissing = 0;
633
702
  let postToolSoftStop = false;
634
703
  const turnAbortController = new AbortController();
704
+ // TUI-SEAT-TURN-CAP — 이번 core 턴의 상한·idle 상태(반복마다 새로).
705
+ const seatCap = opts.seatTurnCap;
706
+ const turnStartedAt = now();
707
+ let seatTools = 0;
708
+ let seatClosing: 'tools' | 'wall' | 'idle' | null = null;
709
+ let seatRefusedAfterClose = 0;
710
+ let seatCapAborted = false;
711
+ let emptyMailStreak = 0;
712
+ // 벽시계는 «다음 도구 호출» 에서 잰다 — 도는 스트림·도구는 끊지 않는다(끊고 멈춤이 아니라 마감 안내).
713
+ // ⛔ 상한이 없으면(사람 TUI·하니스 자식) caller dispatcher 의 Promise 를 «그대로» 돌려준다 — async 로 감싸면
714
+ // 새 Promise 가 되어 caller-side dispatch 동일성 계약(core-turn-goal-loop.test)이 깨진다(열차 r19d 회귀).
715
+ // 기본 실행기는 `ctx.dispatchTool(...)` 를 «메서드로» 부른다 — 꺼내 담아 부르면 수신자(this)가 빠진다(리뷰 r5).
716
+ const seatDispatch = (
717
+ name: string, args: Record<string, unknown>, dctx: Parameters<CoreTurnContext['dispatchTool']>[2],
718
+ execute?: CoreTurnContext['dispatchTool'],
719
+ ): Promise<unknown> => {
720
+ const run: CoreTurnContext['dispatchTool'] = execute ?? ((n, a, c) => ctx.dispatchTool(n, a, c));
721
+ if (!seatCap) return run(name, args, dctx);
722
+ return seatCappedDispatch(seatCap, name, args, dctx, run);
723
+ };
724
+ const seatCappedDispatch = async (
725
+ cap: SeatTurnCapConfig, name: string, args: Record<string, unknown>,
726
+ dctx: Parameters<CoreTurnContext['dispatchTool']>[2], execute: CoreTurnContext['dispatchTool'],
727
+ ): Promise<unknown> => {
728
+ if (seatClosing === null && now() - turnStartedAt >= cap.maxWallMs) seatClosing = 'wall';
729
+ if (seatClosing === null && seatTools >= cap.maxTools) seatClosing = 'tools';
730
+ if (seatClosing !== null) {
731
+ seatRefusedAfterClose += 1;
732
+ // 받침 — 안내를 받고도 도구를 계속 부르면 이 core 턴만 끝낸다(goal loop 는 다음 반복으로 잇는다).
733
+ if (seatRefusedAfterClose > SEAT_CAP_REFUSAL_BACKSTOP) {
734
+ seatCapAborted = true;
735
+ turnAbortController.abort();
736
+ }
737
+ return { error: seatClosing === 'idle'
738
+ ? SEAT_IDLE_NO_WORK_NOTICE(cap.idleEmptyMsgListLimit)
739
+ : SEAT_TURN_CAP_TOOL_NOTICE(seatClosing, cap) };
740
+ }
741
+ seatTools += 1;
742
+ const result = await execute(name, args, dctx);
743
+ if (isEmptyMailListResult(name, result)) {
744
+ emptyMailStreak += 1;
745
+ if (emptyMailStreak >= cap.idleEmptyMsgListLimit) {
746
+ seatClosing = 'idle';
747
+ return { ...(result as Record<string, unknown>), notice: SEAT_IDLE_NO_WORK_NOTICE(cap.idleEmptyMsgListLimit) };
748
+ }
749
+ } else if (!isIdleWaitCall(name, args)) {
750
+ // 새 우편이 왔거나(비지 않은 조회) 다른 일을 했다 — «할 일 0» 연속이 끊긴다. 대기용 sleep 은 끊지 않는다.
751
+ emptyMailStreak = 0;
752
+ }
753
+ return result;
754
+ };
635
755
  const abortForCaller = () => turnAbortController.abort(ctx.signal.reason);
636
756
  if (ctx.signal.aborted) abortForCaller();
637
757
  else ctx.signal.addEventListener('abort', abortForCaller, { once: true });
@@ -639,6 +759,34 @@ export async function runGoalLoop(
639
759
  postToolSoftStop = true;
640
760
  turnAbortController.abort();
641
761
  };
762
+ // TUI-GOAL-REPEAT-ANSWER(0.2.32) — goal loop 반복에서 모델이 이전 iteration 의 답을
763
+ // 다시 말하면 화면에 같은 답이 두 번 그려진다(관측 2026-10-14 05:37). 원장 쪽 중복은
764
+ // 아래 completion 판정이 이미 접는다 — 이 검은 화면 push 만 담당한다: 이번 iteration 의
765
+ // 스트림이 «읽기-되돌림 인사(preface) ⊕ 이전 답»의 접두사로만 진행되는 동안 caller 의
766
+ // onText 로 흘리지 않고 대기하다, 갈라지는 순간(새 내용) 모은 걸 한 번에 흘린 뒤 그대로
767
+ // 흘린다. iteration 마감의 순수 중복 판정·버림은 onTurnComplete 에서 한다.
768
+ const previousFinalText = lastResult.finalText;
769
+ const goalRepeatPreviousAnswer = goalRepeatStreamNormalize(previousFinalText);
770
+ let goalRepeatWithheld = '';
771
+ let goalRepeatWithholding = goalRepeatPreviousAnswer.length > 0;
772
+ const goalRepeatStreamConsistent = (text: string): boolean => {
773
+ if (previousFinalText.startsWith(text)) return true;
774
+ const normalized = goalRepeatStreamNormalize(text);
775
+ if (goalRepeatPreviousAnswer.startsWith(normalized)) return true;
776
+ for (const phrase of GOAL_REPEAT_READBACK_PHRASES) {
777
+ if (phrase.startsWith(normalized)) return true;
778
+ if (!normalized.startsWith(phrase)) continue;
779
+ const rest = normalized.slice(phrase.length).replace(GOAL_REPEAT_PREFACE_SEPS, '');
780
+ if (goalRepeatPreviousAnswer.startsWith(rest)) return true;
781
+ }
782
+ return false;
783
+ };
784
+ const flushGoalRepeatWithheld = (full: string): void => {
785
+ if (goalRepeatWithheld === '') return;
786
+ const withheld = goalRepeatWithheld;
787
+ goalRepeatWithheld = '';
788
+ ctx.callbacks?.onText?.(withheld, full);
789
+ };
642
790
  const turnCtx: CoreTurnContext = {
643
791
  ...ctx,
644
792
  messages,
@@ -646,6 +794,11 @@ export async function runGoalLoop(
646
794
  signal: turnAbortController.signal,
647
795
  // 진입 시 한 번 정한 사람 문장을 매 라운드에 그대로 내린다(위 주석 참조).
648
796
  ...(surfaceUserText !== undefined ? { userText: surfaceUserText } : {}),
797
+ // TUI-GOAL-LOOP-FRICTION(#46·#63) — update_goal 은 도구 예산 거부를 받지 않고, 답과 함께 오면 그 턴으로 마감한다.
798
+ terminalToolNames: [...(ctx.terminalToolNames ?? []), UPDATE_GOAL_TOOL_NAME],
799
+ // TUI-H1-GOALLOOP-EMPTY-TAIL — 앞 iteration 의 답이 이미 화면에 있으면 «update_goal 만 → 빈 턴» 은 할 말이 없는
800
+ // 것이다 — 재촉·경고 없이 빈 답으로 끝내고 아래 완료 판정이 앞 답으로 마감한다(중복 접기와 같은 길).
801
+ ...(previousFinalText.trim().length > 0 ? { terminalPriorAnswerVisible: true } : {}),
649
802
  // update_goal 은 종결 신호 — 실 dispatcher 로 새지 않게 가로채 ack 만 돌려준다.
650
803
  dispatchTool: (name, args, dctx) => {
651
804
  dispatchCount += 1;
@@ -660,12 +813,34 @@ export async function runGoalLoop(
660
813
  // Observability must not prevent the selected tool from dispatching.
661
814
  }
662
815
  if (name === UPDATE_GOAL_TOOL_NAME) {
663
- return Promise.resolve({ ok: true, recorded: (args as { status?: unknown }).status ?? null });
816
+ const ack = () => Promise.resolve({ ok: true, recorded: (args as { status?: unknown }).status ?? null });
817
+ // TUI-SEAT-TURN-CAP — 진행 선언도 «다른 일» 이다: 빈 우편 조회 연속을 끊는다(리뷰 r1).
818
+ emptyMailStreak = 0;
819
+ // 완료 신호(complete)는 상한 «뒤» 에도 받고 도구로 세지 않는다 — 상한 안내가 바로 «마감하라» 이고,
820
+ // 종결 신호는 예산 거부를 받지 않는다(#28503 terminalToolNames 계약과 같은 방향). 그 밖의 진행 선언
821
+ // (in_progress·blocked)은 도구 한 번으로 세고 상한 뒤엔 같은 안내로 거부한다(리뷰 r2 — 61번 넘게 불러도 안 막히던 구멍).
822
+ if ((args as { status?: unknown }).status === 'complete') return ack();
823
+ return seatDispatch(name, args, dctx, ack);
664
824
  }
665
- return ctx.dispatchTool(name, args, dctx);
825
+ return seatDispatch(name, args, dctx);
666
826
  },
667
827
  callbacks: {
668
828
  ...ctx.callbacks,
829
+ // TUI-GOAL-REPEAT-ANSWER — 이번 iteration 의 스트림이 이전 답의 재방출로만 진행되는
830
+ // 동안은 caller 의 onText 로 흘리지 않고 대기한다(중복 후보). 갈라지는 순간 모은 걸
831
+ // 한 번에 흘리고 이후 그대로 흘린다. 빈 청크(라운드 경계·commit)는 상태와 무관하게
832
+ // 그대로 흘린다 — TUI 의 라운드 확정 신호를 끊지 않는다.
833
+ onText: (delta, full) => {
834
+ if (delta !== '' && goalRepeatWithholding) {
835
+ if (goalRepeatStreamConsistent(goalRepeatWithheld + delta)) {
836
+ goalRepeatWithheld += delta;
837
+ return;
838
+ }
839
+ goalRepeatWithholding = false;
840
+ flushGoalRepeatWithheld(full);
841
+ }
842
+ ctx.callbacks?.onText?.(delta, full);
843
+ },
669
844
  // OH8 후속 PR-2 — run_tests 결과를 캡처(last-wins). 텍스트 파싱이 아니라 구조체 ok 를 본다.
670
845
  onToolResult: (call) => {
671
846
  if (call.name === 'run_tests' && call.result && typeof call.result === 'object') {
@@ -706,6 +881,17 @@ export async function runGoalLoop(
706
881
  }
707
882
  },
708
883
  onTurnComplete: (msgs) => {
884
+ // TUI-GOAL-REPEAT-ANSWER — iteration 마감: 순수 중복이면(이전 답 ± preface 전부)
885
+ // 흴린 건 버린다 — 이전 답이 이미 화면에 그려져 있어 두 번째는 필요 없다. 아니면
886
+ // 모은 걸 한 번에 흘린 다음 마감을 넘긴다(브리지 재표면화 판정이 흘린 분량을 본다).
887
+ if (goalRepeatWithholding) {
888
+ goalRepeatWithholding = false;
889
+ const normalized = goalRepeatStreamNormalize(goalRepeatWithheld);
890
+ const pureRepeat = normalized === goalRepeatPreviousAnswer
891
+ || GOAL_REPEAT_READBACK_PHRASES.some((phrase) => normalized.startsWith(phrase)
892
+ && normalized.slice(phrase.length).replace(GOAL_REPEAT_PREFACE_SEPS, '') === goalRepeatPreviousAnswer);
893
+ if (!pureRepeat) flushGoalRepeatWithheld(normalized);
894
+ }
709
895
  turnNewMessages = msgs;
710
896
  ctx.callbacks?.onTurnComplete?.(msgs);
711
897
  },
@@ -732,12 +918,20 @@ export async function runGoalLoop(
732
918
  },
733
919
  };
734
920
 
735
- const previousFinalText = lastResult.finalText;
736
921
  try {
737
922
  lastResult = await runTurn(turnCtx);
738
923
  } finally {
739
924
  ctx.signal.removeEventListener('abort', abortForCaller);
740
925
  }
926
+ // TUI-SEAT-TURN-CAP — 상한·idle 안내 뒤 «정상 마감» 했거나 받침이 끊은 core 턴만 고쳐 읽는다.
927
+ // 사람 중단(caller signal)·error·auth_rejected 는 그대로 둔다 — 실제 오류를 상한으로 덮지 않는다(리뷰 r1).
928
+ const seatClosedTurn = seatCap !== undefined && !ctx.signal.aborted && seatClosing !== null
929
+ && (lastResult.stopReason === 'end_turn' || lastResult.stopReason === 'max_turns'
930
+ || (lastResult.stopReason === 'aborted' && seatCapAborted));
931
+ const seatCapHit = seatClosedTurn && (seatClosing === 'tools' || seatClosing === 'wall');
932
+ const seatIdleHit = seatClosedTurn && seatClosing === 'idle';
933
+ if (seatCapHit) lastResult = { ...lastResult, stopReason: 'max_turns' };
934
+ else if (seatIdleHit && lastResult.stopReason === 'aborted') lastResult = { ...lastResult, stopReason: 'end_turn' };
741
935
  messages.push(...turnNewMessages);
742
936
 
743
937
  const goalUpdate = findGoalUpdate(turnNewMessages);
@@ -757,6 +951,18 @@ export async function runGoalLoop(
757
951
  finalTextExcerpt: finalTextExcerpt.text, finalTextExcerptTruncated: finalTextExcerpt.truncated,
758
952
  }, { level: 'debug' });
759
953
 
954
+ // ①-0 #29 처방 — 자리 운영 턴은 빈 evidence 를 반려하지 않고 이 턴의 답을 증거로 받는다(관측 남김).
955
+ // 답도 비었으면 받을 증거가 없다 — 종전 반려(evidence required)로 그대로 간다.
956
+ const lenientAnswer = opts.lenientCompletionEvidence === true
957
+ ? boundReadableText(lastResult.finalText, 200).text.trim()
958
+ : '';
959
+ if (goalUpdate?.status === 'complete' && goalUpdate.evidence.trim().length === 0 && lenientAnswer.length > 0) {
960
+ goalUpdate.evidence = `(자리 운영 턴 — 답을 증거로 수용) ${lenientAnswer}`;
961
+ debug.log('goal.loop', 'complete-evidence-lenient', {
962
+ sessionId: ctx.sessionId, ...runAttribution, iterations, finalChars: lastResult.finalText.length,
963
+ }, { level: 'info' });
964
+ }
965
+
760
966
  // ① authoritative 완료 — update_goal(complete) + 비지 않은 evidence.
761
967
  if (goalUpdate?.status === 'complete') {
762
968
  if (goalUpdate.evidence.trim().length > 0) {
@@ -875,6 +1081,33 @@ export async function runGoalLoop(
875
1081
  });
876
1082
  }
877
1083
 
1084
+ // TUI-SEAT-TURN-CAP ⓑ — «할 일 0»(빈 우편 조회 연속): 이 반복을 완료로 보고 끝낸다(lenient · 대기는 H4/H5 몫).
1085
+ if (seatIdleHit && seatCap) {
1086
+ debug.log('goal.loop', 'idle-no-work', {
1087
+ sessionId: ctx.sessionId, ...runAttribution, seat: seatCap.seat, iteration: iterations,
1088
+ tools: seatTools, wallMs: now() - turnStartedAt, emptyMailStreak,
1089
+ }, { level: 'info' });
1090
+ return finish(
1091
+ { finalText: lastResult.finalText, iterations, stopReason: 'goal_complete', goalComplete: true },
1092
+ { summary: `idle-no-work — ${emptyMailStreak} consecutive empty mailbox checks (seat ${seatCap.seat})`, changedFiles: [] },
1093
+ );
1094
+ }
1095
+ // TUI-SEAT-TURN-CAP ⓐ — 도구·벽시계 상한으로 마감한 core 턴: 요약을 이어받아 다음 반복으로(하드캡이 이긴다).
1096
+ // ⛔ 빈 근거 complete 가 함께 온 턴은 여기서 잇지 않고 아래 «근거 없는 완료» 판정에 맡긴다(리뷰 r3) —
1097
+ // 적격 완료(lenient 답 수용)는 위 ① 에서 이미 끝났고, 남은 빈 근거 complete 는 종전 계약대로 근거를 다시 묻는다.
1098
+ if (seatCapHit && seatCap && goalUpdate?.status !== 'complete') {
1099
+ debug.log('goal.loop', 'seat-turn-cap', {
1100
+ sessionId: ctx.sessionId, ...runAttribution, seat: seatCap.seat, reason: seatClosing, iteration: iterations,
1101
+ tools: seatTools, wallMs: now() - turnStartedAt, maxTools: seatCap.maxTools, maxWallMs: seatCap.maxWallMs,
1102
+ backstopAborted: seatCapAborted, maxIterations,
1103
+ }, { level: 'info' });
1104
+ seatCapHits += 1;
1105
+ blockedStreak = 0;
1106
+ readbackStreak = 0;
1107
+ messages.push({ role: 'user', content: SEAT_TURN_CAP_CONTINUE_PROMPT });
1108
+ continue;
1109
+ }
1110
+
878
1111
  // Evidence-less completion is not authoritative; only retry after stop and terminal outcomes
879
1112
  // from this same turn have received priority.
880
1113
  if (goalUpdate?.status === 'complete') {
@@ -985,6 +1218,13 @@ export async function runGoalLoop(
985
1218
  }
986
1219
 
987
1220
  debug.log('goal.loop', 'max-iterations', { sessionId: ctx.sessionId, ...runAttribution, iterations }, { level: 'warn' });
1221
+ if (opts.seatTurnCap && seatCapHits > 0) {
1222
+ // 실패 시 누구에게(상한에 한 번이라도 닿은 런만 — 일반 하드캡 종료와 섞지 않는다 · 리뷰 r3) — 자리 TUI 가 반복 하드캡까지 다 쓰고 멈췄다: 자리 OP 가 보는 경고 이벤트.
1223
+ debug.log('goal.loop', 'seat-turn-cap-exhausted', {
1224
+ sessionId: ctx.sessionId, ...runAttribution, seat: opts.seatTurnCap.seat, iterations, maxIterations, capHits: seatCapHits,
1225
+ notify: 'seat-op',
1226
+ }, { level: 'warn' });
1227
+ }
988
1228
  return finish({ finalText: lastResult.finalText, iterations, stopReason: 'max_iterations', goalComplete: false });
989
1229
  } finally {
990
1230
  stopLivenessHeartbeat();
@@ -0,0 +1,79 @@
1
+ // TUI-SEAT-TURN-CAP(0.2.31 · OP #9266) — 자리 TUI 의 goal loop 에서만 쓰는 «한 core 턴» 상한 ⊕ «할 일 0» 판정.
2
+ //
3
+ // 배경(10-16 실측): H1(#28487)로 자리 TUI 운영 지시가 goal loop 를 타면서 «1턴 정지» 는 풀렸지만, 반대로 한 core 턴이
4
+ // 도구 121개·18분+ 이어졌다(운영 `llm.maxTurns.codex = null` = 무제한). 전역 config 는 하니스 자식까지 걸리므로
5
+ // 자리 TUI 한정 손잡이를 둔다. 또 일이 떨어진 뒤 빈 MsgList 를 연달아 부르며 턴 안에서 폴링했다(«할 일 0 = 완료» 신호 부재).
6
+ //
7
+ // ⛔ 이 모듈은 import 0 — user-config 가 파서를 가져다 쓴다(순환 없음).
8
+
9
+ export interface SeatTurnCapConfig {
10
+ /** core 턴 1회당 실행할 도구 수 상한. update_goal 진행 선언(in_progress·blocked)도 한 번으로 세고, 완료 신호(complete)만 뺀다.
11
+ * 넘는 호출은 실행하지 않는다. */
12
+ maxTools: number;
13
+ /** core 턴 1회당 벽시계 상한(ms). 넘으면 다음 도구 호출부터 실행하지 않는다. */
14
+ maxWallMs: number;
15
+ /** 같은 core 턴에서 «새 항목 0» 우편 조회(MsgList)가 연속 이만큼이면 «할 일 0» 으로 완료. */
16
+ idleEmptyMsgListLimit: number;
17
+ }
18
+
19
+ export const SEAT_TURN_CAP_DEFAULTS: SeatTurnCapConfig = {
20
+ maxTools: 60,
21
+ maxWallMs: 20 * 60_000,
22
+ idleEmptyMsgListLimit: 2,
23
+ };
24
+
25
+ function positiveInt(value: unknown): number | undefined {
26
+ return typeof value === 'number' && Number.isSafeInteger(value) && value > 0 ? value : undefined;
27
+ }
28
+
29
+ /** `chat.seatTurnCap` 원문을 읽는다. 객체가 아니거나 유효한 칸이 하나도 없으면 undefined(= 기본값). */
30
+ export function parseSeatTurnCapConfig(raw: unknown): Partial<SeatTurnCapConfig> | undefined {
31
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;
32
+ const r = raw as Record<string, unknown>;
33
+ const out: Partial<SeatTurnCapConfig> = {};
34
+ const maxTools = positiveInt(r.maxTools);
35
+ const maxWallMs = positiveInt(r.maxWallMs);
36
+ const idle = positiveInt(r.idleEmptyMsgListLimit);
37
+ if (maxTools !== undefined) out.maxTools = maxTools;
38
+ if (maxWallMs !== undefined) out.maxWallMs = maxWallMs;
39
+ if (idle !== undefined) out.idleEmptyMsgListLimit = idle;
40
+ return Object.keys(out).length > 0 ? out : undefined;
41
+ }
42
+
43
+ export function resolveSeatTurnCap(override: Partial<SeatTurnCapConfig> | undefined): SeatTurnCapConfig {
44
+ return { ...SEAT_TURN_CAP_DEFAULTS, ...(override ?? {}) };
45
+ }
46
+
47
+ /** 우편 조회 도구 이름(카탈로그 aliases). */
48
+ export const MAIL_LIST_TOOL_NAMES: ReadonlySet<string> = new Set(['MsgList', 'msg_list']);
49
+
50
+ /** 결과가 «새 항목 0» 인 우편 조회인가. 구조체 `count === 0` 만 본다(문자열·messages 길이 추정 없음 — 리뷰 r1). */
51
+ export function isEmptyMailListResult(name: string, result: unknown): boolean {
52
+ if (!MAIL_LIST_TOOL_NAMES.has(name)) return false;
53
+ if (!result || typeof result !== 'object') return false;
54
+ return (result as { count?: unknown }).count === 0;
55
+ }
56
+
57
+ /** 셸 도구 이름(카탈로그 aliases — RunShell·Bash 계열). */
58
+ export const SHELL_TOOL_NAMES: ReadonlySet<string> = new Set(['RunShell', 'run_shell', 'exec_argv', 'Bash', 'shell']);
59
+
60
+ /** 대기용 셸 호출(`sleep N`)인가 — 폴링 사이의 기다림은 «할 일 0» 연속을 끊지 않는다. 셸 도구에만 예외(리뷰 r2). */
61
+ export function isIdleWaitCall(name: string, args: unknown): boolean {
62
+ if (!SHELL_TOOL_NAMES.has(name)) return false;
63
+ if (!args || typeof args !== 'object') return false;
64
+ const command = (args as { command?: unknown }).command;
65
+ return typeof command === 'string' && /^\s*sleep\s+\d+(?:\.\d+)?[smh]?\s*;?\s*$/.test(command);
66
+ }
67
+
68
+ export const SEAT_TURN_CAP_TOOL_NOTICE = (reason: 'tools' | 'wall', cap: SeatTurnCapConfig): string =>
69
+ `SEAT TURN CAP — this core turn reached its ${reason === 'tools' ? `tool limit (${cap.maxTools} tools)` : `wall-clock limit (${Math.round(cap.maxWallMs / 60_000)} min)`}; this call was NOT run. `
70
+ + 'Do not call more tools in this turn. Write a one-line progress summary now (what is done · what remains) and end the turn; '
71
+ + 'the goal loop starts the next iteration and you continue the remaining work there.';
72
+
73
+ export const SEAT_IDLE_NO_WORK_NOTICE = (limit: number): string =>
74
+ `NO NEW WORK — ${limit} consecutive mailbox checks returned 0 new messages. Do not poll again in this turn. `
75
+ + 'Write a one-line status and end the turn; this goal is complete (waiting for new mail is handled outside the turn).';
76
+
77
+ export const SEAT_TURN_CAP_CONTINUE_PROMPT =
78
+ '앞 core 턴이 자리 턴 상한(도구 수 또는 벽시계)에 닿아 마감됐다. 위의 진행 요약을 이어받아 남은 일을 계속하라. '
79
+ + '다 끝났으면 update_goal(status:"complete", evidence) 로 마감하라.';
@@ -41,6 +41,10 @@ const WRITE_INTENT = /(?:(?:추가|작성|기록|반영|갱신|업데이트|개
41
41
  const DEBUG_INTENT = /(?:디버그|디버깅|에러|오류|크래시|깨져|깨짐|안\s*(?:돼|됨|되네|된다)|\b(?:debug|error|crash|broken|fails?|failing)\b)/i;
42
42
  const EXPLICIT_GOAL = /(?:^\/goal\b|목표\s*[::]|\bgoal\s*:)/i;
43
43
  const REPO_NOUN = /(?:코드|스크립트|소스|브랜치|서버|파일|레포|저장소|\bPR\b|\b(?:code|script|branch|server|file|repo)\b)/i;
44
+ // A named CLI command («(eln msg list --to OPT)» · «`git log`») or the seat mailbox is work the research
45
+ // allowlist cannot do (no RunShell · no MsgList) — it is a full-tool read, not the «조사» quick route
46
+ // (TUI-QUICK-ROUTE-EXPLICIT-CMD · 10-16 OPT: «우편 확인(eln msg list …) … 조사» answered «셸 도구가 없다»).
47
+ const EXPLICIT_COMMAND = /(?:(?<![\w-])(?:eln|elanous|git|gh)\s+[a-z][\w-]*|우편)/i;
44
48
 
45
49
  function writeDebugOrGoal(q: string): 'write-intent' | 'debug' | 'explicit-goal' | null {
46
50
  if (WRITE_INTENT.test(q)) return 'write-intent';
@@ -55,8 +59,23 @@ export interface TuiChatVerdict {
55
59
  goalLoop: boolean;
56
60
  }
57
61
 
58
- /** Request verbs a quick or read-only turn can carry out without writing to the repository. */
59
- const QUICK_REQUEST_VERBS = /^(?:보여|알려|확인해|찾아|찾아봐|조사해|검색해|정리해|요약해|바꿔|변경해|전환해|설정해|맞춰|수정해|고쳐|만들어|등록해|예약해|추가해|보내|설명해|읽어|읽어봐|살펴|살펴봐|훑어봐|비교해|분석해|검토해|평가해|제안해)$/;
62
+ /** 자리(무인) TUI 인가 — 호출부가 `detectSeatTui` 로 정한다. 없으면 사람 대화 TUI(종전 판정 그대로). */
63
+ export interface TuiChatContext extends ShortQuestionContext {
64
+ seat?: boolean;
65
+ }
66
+
67
+ // TUI-H1-SEAT-GOALLOOP — 자리 앞으로 온 «운영 지시» 꼴: 우편·오더 · 이름 있는 CLI 명령 · «OP 13:14:» 머리 · «계속 —» · «다음 행».
68
+ // (10-16 OPT 13:14 «OP 13:14: 계속 — draft 다음 행.» 이 읽기·분석 단일 턴으로 가 «다음 점검 13:20» 만 남기고 멈췄다.)
69
+ const SEAT_OPS_DIRECTIVE = /(?:우편|오더|(?<![\w-])(?:eln|elanous|git|gh)\s+[a-z][\w-]*|^\[?OP\s*\d{1,2}:\d{2}|(?:^|[\s::])계속(?:\s*[—–-]|\s*(?:해|하|진행)|[.!]?\s*$)|다음\s*행(?![가-힣]))/i;
70
+
71
+ /** 자리 운영 지시 꼴인가(인지 · 관측용으로도 내보낸다). */
72
+ export function isSeatOpsDirective(text: string): boolean {
73
+ return SEAT_OPS_DIRECTIVE.test(text.trim());
74
+ }
75
+
76
+ /** Request verbs a quick or read-only turn can carry out without writing to the repository.
77
+ * «봐줘·봐 줘·들여다봐줘» are reads (TUI-INITIATIVE-S ④ — «로그 좀 봐줘» used to fall to coding as request-verb). */
78
+ const QUICK_REQUEST_VERBS = /^(?:보여|알려|확인해|찾아|찾아봐|조사해|검색해|정리해|요약해|바꿔|변경해|전환해|설정해|맞춰|수정해|고쳐|만들어|등록해|예약해|추가해|보내|설명해|읽어|읽어봐|봐|봐봐|들여다봐|살펴|살펴봐|훑어봐|비교해|분석해|검토해|평가해|제안해)$/;
60
79
 
61
80
  /** True when the verb never appears, or each occurrence directly follows an allowed object. */
62
81
  function everyVerbTakes(text: string, verb: RegExp, object: RegExp): boolean {
@@ -66,8 +85,21 @@ function everyVerbTakes(text: string, verb: RegExp, object: RegExp): boolean {
66
85
  return true;
67
86
  }
68
87
 
69
- /** Write, debug, goal, mixed or attached requests retain the coding goal loop; a plain read question is one full-tool turn. */
70
- export function classifyTuiChatIntent(text: string, ctx: ShortQuestionContext = {}): TuiChatVerdict {
88
+ /** Write, debug, goal, mixed or attached requests retain the coding goal loop; a plain read question is one full-tool turn.
89
+ * A seat (unattended) TUI reverts #27531 for its work: a read/analysis turn (except a fast short question) and any
90
+ * operational directive (mail · order · named CLI command · «계속 —») ride the goal loop to completion evidence. */
91
+ export function classifyTuiChatIntent(text: string, ctx: TuiChatContext = {}): TuiChatVerdict {
92
+ const verdict = classifyTuiChatIntentBase(text, ctx);
93
+ // A fast short question («다음 행이 뭐야?») stays one turn even in a seat — only work rides the goal loop.
94
+ if (!ctx.seat || verdict.goalLoop || verdict.reason.startsWith('short-')) return verdict;
95
+ if (verdict.route === '읽기·분석') {
96
+ return { route: verdict.route, reason: `seat-${verdict.reason}`, goalLoop: true };
97
+ }
98
+ if (isSeatOpsDirective(text)) return { route: verdict.route, reason: `seat-ops-${verdict.reason}`, goalLoop: true };
99
+ return verdict;
100
+ }
101
+
102
+ function classifyTuiChatIntentBase(text: string, ctx: ShortQuestionContext): TuiChatVerdict {
71
103
  const q = text.trim();
72
104
  const coding = (reason: string): TuiChatVerdict => ({ route: '코딩·구현', reason, goalLoop: true });
73
105
  if (!q || ctx.hasAttachments) return coding(ctx.hasAttachments ? 'attachment' : 'empty');
@@ -86,8 +118,8 @@ export function classifyTuiChatIntent(text: string, ctx: ShortQuestionContext =
86
118
  // Debugging or a stated goal keeps the goal loop even on a quick-route word («오류 로그 요약» · «목표: 상태 요약»).
87
119
  if (DEBUG_INTENT.test(q)) return coding('debug');
88
120
  if (EXPLICIT_GOAL.test(q)) return coding('explicit-goal');
89
- // A repository noun, file path or code shape is no quick route; with no write, debug or goal intent it is a read.
90
- if (REPO_NOUN.test(q) || PATH_OR_CODE.test(q)) {
121
+ // A repository noun, file path, code shape or named command is no quick route; with no write, debug or goal intent it is a read.
122
+ if (REPO_NOUN.test(q) || PATH_OR_CODE.test(q) || EXPLICIT_COMMAND.test(q)) {
91
123
  const intent = writeDebugOrGoal(q);
92
124
  return intent ? coding(intent) : { route: '읽기·분석', reason: 'read-repo', goalLoop: false };
93
125
  }
@@ -155,6 +155,12 @@ export interface CoreTurnContext {
155
155
  * named tools (e.g. the PtyShell family driving a headless coding
156
156
  * agent) are actually being dispatched. Absent ⇒ no extension. */
157
157
  budgetGrant?: LLMOpts['budgetGrant'];
158
+ /** TUI-GOAL-LOOP-FRICTION — 종결 신호 도구 이름. `streamLLMWithTools` 의 `terminalToolNames` 로 그대로 간다
159
+ * (예산 거부 면제 · 신호뿐인 턴 ⊕ 답 = 마감). goal loop 가 `update_goal` 을 넣는다. */
160
+ terminalToolNames?: LLMOpts['terminalToolNames'];
161
+ /** TUI-H1-GOALLOOP-EMPTY-TAIL — 이 턴 «앞»에 사람에게 답을 이미 보였다. `streamLLMWithTools` 의
162
+ * `terminalPriorAnswerVisible` 로 그대로 간다(종결 신호 뒤 빈 턴 = 경고 없이 빈 답). goal loop 가 넣는다. */
163
+ terminalPriorAnswerVisible?: LLMOpts['terminalPriorAnswerVisible'];
158
164
  /** Optional model override (forwarded to `streamLLMWithTools`). */
159
165
  modelOverride?: string;
160
166
  }
@@ -6,7 +6,7 @@
6
6
 
7
7
  import { debug } from '../debug/log.js';
8
8
  import { effectiveReasoningLevel } from '../llm.js';
9
- import { recordCurrentRouteDecision, resolveRouteDecision, sessionModelPin } from '../llm/route-decision.js';
9
+ import { clearSurfaceRouteDecision, currentRouteDecision, recordCurrentRouteDecision, recordRouteExecution, resolveRouteDecision, sessionModelPin } from '../llm/route-decision.js';
10
10
  import { inspectActiveProvider } from '../provider-summary.js';
11
11
  import { getUserConfig } from '../user-config.js';
12
12
 
@@ -38,3 +38,44 @@ export function resolveDashboardActiveModel(userText: string): string | null {
38
38
  });
39
39
  return decision.model || null;
40
40
  }
41
+
42
+ /** 턴 사용량(ACP `elanous/ui/usage`)이 실어 온 «실제» 공급자·모델을 이 표면의 실행으로 적는다
43
+ * (TUI-MODEL-BADGE-ACTUAL · 10-16). 완료 배지가 결정과 다르면 «A → B» 로 보인다.
44
+ * 폴백(결정과 다른 모델)이면 관측 이벤트 `llm.route-decision` / `dashboard-executed-fallback` 를 «항상» 남긴다. */
45
+ export function recordDashboardTurnExecution(
46
+ usage: { model?: string; routeProvider?: string } | null | undefined,
47
+ /** 필수 — 세션 위치를 모르면(null) 적지 않는다(원격 사용량을 로컬 실행으로 꾸미지 않게). */
48
+ session: { remote: boolean } | null,
49
+ ): void {
50
+ // ⛔ 순서: 원격·세션 미상 판정(⊕ 비우기)을 model 검사보다 «먼저» 한다 — 사용량 봉투의 model 은 선택 칸이라,
51
+ // 모델 없는 원격 사용량이 먼저 반환하면 지난 로컬 턴의 «A → B» 가 남는다(r6 리뷰).
52
+ const model = usage?.model?.trim() || null;
53
+ if (session === null) {
54
+ // 짝을 모르는 턴 — 지난 턴의 결정·실행이 이 턴의 배지로 «다시» 보이지 않게 비운다.
55
+ clearSurfaceRouteDecision('dashboard');
56
+ debug.log('llm.route-decision', 'dashboard-executed-session-unknown', { model }, { level: 'warn' });
57
+ return;
58
+ }
59
+ // ⛔ 원격 데몬 세션은 적지 않는다 — 결정은 데몬 쪽에서 서므로 이 프로세스의 결정과 짝이 안 맞는다.
60
+ // 후속 칸 TUI-MODEL-BADGE-REMOTE.
61
+ if (session.remote) {
62
+ // 원격 턴은 로컬 결정과 짝이 없다 — 지난 로컬 턴의 «A → B» 가 이 턴의 배지로 다시 나오지 않게 비운다(r5 리뷰).
63
+ clearSurfaceRouteDecision('dashboard');
64
+ if (debug.enabled) debug.log('llm.route-decision', 'dashboard-executed-remote-skipped', { model });
65
+ return;
66
+ }
67
+ if (!model) return;
68
+ const provider = usage?.routeProvider?.trim() || undefined;
69
+ const decision = currentRouteDecision('dashboard');
70
+ // 결정이 없는 실행은 짝이 없다 — 적지 않는다.
71
+ if (!decision) return;
72
+ recordRouteExecution('dashboard', { model, ...(provider ? { provider } : {}) });
73
+ if (decision.model !== '' && decision.model !== model) {
74
+ debug.log('llm.route-decision', 'dashboard-executed-fallback', {
75
+ planned: { provider: decision.provider, model: decision.model },
76
+ actual: { provider: provider ?? null, model },
77
+ }, { level: 'warn' });
78
+ } else if (debug.enabled) {
79
+ debug.log('llm.route-decision', 'dashboard-executed', { provider: provider ?? null, model });
80
+ }
81
+ }
@@ -36,6 +36,7 @@ import {
36
36
  import type { AcpTransportConnection } from '../acp/transport/index.js';
37
37
  import { debug } from '../debug/log.js';
38
38
  import { recordDashboardToolCatalog } from './tool-catalog-observability.js';
39
+ import { detectSeatTui } from './seat-boot-preamble.js';
39
40
 
40
41
  type DashboardAcpBootBranch = 'remote-daemon' | 'in-process';
41
42
 
@@ -232,6 +233,8 @@ export async function bootDashboardAcpSession(
232
233
  const model = deps.getActiveModel({ userText });
233
234
  return model ?? undefined;
234
235
  },
236
+ // TUI-H1-SEAT-GOALLOOP — 자리(무인) TUI 면 운영 지시를 goal loop 로(사람 대화 TUI 는 종전 그대로).
237
+ resolveSeat: () => detectSeatTui(deps.getCwd())?.seat ?? null,
235
238
  ...(deps.agentName !== undefined ? { agentName: deps.agentName } : {}),
236
239
  ...(deps.agentVersion !== undefined ? { agentVersion: deps.agentVersion } : {}),
237
240
  ...(gateway