elanous 0.2.28 → 0.2.29

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 (609) 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/{y1ltt7oCZxVpC6zVPhZ2O → cIpv5nU9AycwYWZI9H589}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{ab4d57c2.e90bc2cb31949045.js → 058a98ba.7eb28d5e6dc03565.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{4565-67e4c620597965c8.js → 1015-9cba22a5a4554797.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +8 -0
  9. package/apps/pwa/out/_next/static/chunks/{1516.83dd2c1b86b4e507.js → 1142.65d002789ab3af7d.js} +2 -2
  10. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +34 -0
  12. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1516.dfaceff3fd2d0e0d.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +286 -0
  16. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +24 -0
  17. package/apps/pwa/out/_next/static/chunks/1782-59db1b5aa06df38a.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{1743.563d3168e95825ef.js → 1852.7f7b53991fcb99ef.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +36 -0
  22. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +64 -0
  24. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{65ebff95.081daeff622d238e.js → 285adb1a.5654e605dddf86d2.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +115 -0
  31. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3160-95c96f4d2a21dd26.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +90 -0
  36. package/apps/pwa/out/_next/static/chunks/328bb3ab-6628a1114fe3fb3b.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{9917-9e26abc5f7772735.js → 3396-97b97928c49190c9.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/{6196.34d6b229079e9e28.js → 3403.7199205e65124486.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/419.736c0d6f426249a7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{6def8a8e.c81f9ca41028eccf.js → 425cfc4d.fb91158e3971c39f.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/{16e57f67.3ea19e893461e611.js → 46bd8bea.2f4b4099172fcdb7.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{5081.a240b63fad28663a.js → 4759.1f76713aefb87db5.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +94 -0
  54. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +62 -0
  60. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +27 -0
  63. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +104 -0
  64. package/apps/pwa/out/_next/static/chunks/{9974.e77b4ff4884557b3.js → 5591.a35e7a217734a8b9.js} +2 -2
  65. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +93 -0
  66. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/{5492-e05e26a033ba80d2.js → 6013-2f769370d8b4c2c6.js} +3 -3
  69. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +24 -0
  70. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +2 -0
  72. package/apps/pwa/out/_next/static/chunks/{5408.377c8c543635b81f.js → 6534.1ab00f370db7b105.js} +1 -1
  73. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +148 -0
  74. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +149 -0
  75. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +79 -0
  77. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/{8578.dff22d988cc2b106.js → 6767.1fcfc9b8be83975f.js} +16 -16
  79. package/apps/pwa/out/_next/static/chunks/6776.06ff1e3b464cc607.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{9311.24c8f5ea793253dd.js → 6853.cc5174a9dee59593.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +287 -0
  86. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/{94.4cfed21c0b781a06.js → 7375.050ea0d72968e49f.js} +16 -16
  92. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +77 -0
  94. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +74 -0
  97. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7725-4f83d5541fbdb81b.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8332.6f0f49df772e163b.js +23 -0
  102. package/apps/pwa/out/_next/static/chunks/{7483.ba01c6c209b81bba.js → 8398.73a19b39715eda04.js} +1 -1
  103. package/apps/pwa/out/_next/static/chunks/{2846.d6a433b8663819a5.js → 8471.8d2a8c74f09c36ff.js} +3 -3
  104. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +226 -0
  106. package/apps/pwa/out/_next/static/chunks/{5785-ea8d2c633b6688e3.js → 8767-2f6a634f5abeaa01.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +32 -0
  109. package/apps/pwa/out/_next/static/chunks/8795.32573a185af18c7b.js +41 -0
  110. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{4593.10f5b9bd702d4a6c.js → 9143.ff14585db1d275ff.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{4204.a409ab6250c0f6a8.js → 9907.49be0fcadaf214b5.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{973cbf1b.3bbcf2b41548eca7.js → a435ad95.577add051b4facb2.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-fa46d4588e8442c2.js → page-a5635eba0d73b84e.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/{page-66ad46ed0279feb9.js → page-86feb08080261a2f.js} +1 -1
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/{page-646b50f63b6fe732.js → page-8aaa6dedc4c10dfb.js} +1 -1
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/{page-6f131b51193a36f9.js → page-33bf667a5fb297bf.js} +1 -1
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-29900ed0011b2c83.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9f92737b8766009a.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{f4dfbfc0.a69fb12f854882aa.js → bc324b7c.02a09dd93f6a399b.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +122 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +1 -0
  183. package/apps/pwa/out/approvals/index.html +1 -1
  184. package/apps/pwa/out/approvals/index.txt +22 -22
  185. package/apps/pwa/out/autopilot/index.html +1 -1
  186. package/apps/pwa/out/autopilot/index.txt +22 -22
  187. package/apps/pwa/out/board/index.html +1 -1
  188. package/apps/pwa/out/board/index.txt +22 -22
  189. package/apps/pwa/out/botlab/index.html +1 -1
  190. package/apps/pwa/out/botlab/index.txt +21 -21
  191. package/apps/pwa/out/bots/index.html +1 -1
  192. package/apps/pwa/out/bots/index.txt +21 -21
  193. package/apps/pwa/out/ceo/index.html +1 -1
  194. package/apps/pwa/out/ceo/index.txt +22 -22
  195. package/apps/pwa/out/chat/index.html +1 -1
  196. package/apps/pwa/out/chat/index.txt +21 -21
  197. package/apps/pwa/out/consult/index.html +1 -1
  198. package/apps/pwa/out/consult/index.txt +22 -22
  199. package/apps/pwa/out/control/index.html +1 -1
  200. package/apps/pwa/out/control/index.txt +22 -22
  201. package/apps/pwa/out/decisions/index.html +1 -1
  202. package/apps/pwa/out/decisions/index.txt +21 -21
  203. package/apps/pwa/out/design-check/index.html +1 -1
  204. package/apps/pwa/out/design-check/index.txt +22 -22
  205. package/apps/pwa/out/editor/index.html +1 -1
  206. package/apps/pwa/out/editor/index.txt +22 -22
  207. package/apps/pwa/out/exec/index.html +1 -1
  208. package/apps/pwa/out/exec/index.txt +22 -22
  209. package/apps/pwa/out/field/index.html +1 -1
  210. package/apps/pwa/out/field/index.txt +22 -22
  211. package/apps/pwa/out/healthz +1 -1
  212. package/apps/pwa/out/index.html +1 -1
  213. package/apps/pwa/out/index.txt +21 -21
  214. package/apps/pwa/out/inside/index.html +1 -1
  215. package/apps/pwa/out/inside/index.txt +21 -21
  216. package/apps/pwa/out/intake/index.html +1 -1
  217. package/apps/pwa/out/intake/index.txt +22 -22
  218. package/apps/pwa/out/live/index.html +1 -1
  219. package/apps/pwa/out/live/index.txt +22 -22
  220. package/apps/pwa/out/live-run/index.html +1 -1
  221. package/apps/pwa/out/live-run/index.txt +22 -22
  222. package/apps/pwa/out/loops/index.html +1 -1
  223. package/apps/pwa/out/loops/index.txt +21 -21
  224. package/apps/pwa/out/market/index.html +1 -1
  225. package/apps/pwa/out/market/index.txt +21 -21
  226. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  227. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  228. package/apps/pwa/out/morning/index.html +1 -1
  229. package/apps/pwa/out/morning/index.txt +22 -22
  230. package/apps/pwa/out/observatory/index.html +1 -1
  231. package/apps/pwa/out/observatory/index.txt +22 -22
  232. package/apps/pwa/out/ops/checklist/index.html +1 -1
  233. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  234. package/apps/pwa/out/ops/release/index.html +1 -1
  235. package/apps/pwa/out/ops/release/index.txt +21 -21
  236. package/apps/pwa/out/ops/seats/index.html +1 -1
  237. package/apps/pwa/out/ops/seats/index.txt +21 -21
  238. package/apps/pwa/out/outputs/index.html +1 -1
  239. package/apps/pwa/out/outputs/index.txt +21 -21
  240. package/apps/pwa/out/reflection/index.html +1 -1
  241. package/apps/pwa/out/reflection/index.txt +22 -22
  242. package/apps/pwa/out/scheduler/index.html +1 -1
  243. package/apps/pwa/out/scheduler/index.txt +22 -22
  244. package/apps/pwa/out/sessions/index.html +1 -1
  245. package/apps/pwa/out/sessions/index.txt +21 -21
  246. package/apps/pwa/out/settings/devices/index.html +1 -1
  247. package/apps/pwa/out/settings/devices/index.txt +22 -22
  248. package/apps/pwa/out/settings/index.html +1 -1
  249. package/apps/pwa/out/settings/index.txt +22 -22
  250. package/apps/pwa/out/setup/done/index.html +1 -1
  251. package/apps/pwa/out/setup/done/index.txt +22 -22
  252. package/apps/pwa/out/setup/index.html +1 -1
  253. package/apps/pwa/out/setup/index.txt +22 -22
  254. package/apps/pwa/out/share/index.html +1 -1
  255. package/apps/pwa/out/share/index.txt +22 -22
  256. package/apps/pwa/out/showroom/index.html +1 -1
  257. package/apps/pwa/out/showroom/index.txt +21 -21
  258. package/apps/pwa/out/tasks/index.html +1 -1
  259. package/apps/pwa/out/tasks/index.txt +22 -22
  260. package/apps/pwa/out/term/index.html +1 -1
  261. package/apps/pwa/out/term/index.txt +22 -22
  262. package/apps/pwa/out/today/index.html +1 -1
  263. package/apps/pwa/out/today/index.txt +22 -22
  264. package/apps/pwa/out/trace/index.html +1 -1
  265. package/apps/pwa/out/trace/index.txt +22 -22
  266. package/apps/pwa/out/vault/index.html +1 -1
  267. package/apps/pwa/out/vault/index.txt +22 -22
  268. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  269. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  270. package/apps/pwa/out/workflows/index.html +1 -1
  271. package/apps/pwa/out/workflows/index.txt +22 -22
  272. package/apps/pwa/out/workspace/index.html +1 -1
  273. package/apps/pwa/out/workspace/index.txt +22 -22
  274. package/apps/pwa/out/worktrees/index.html +1 -1
  275. package/apps/pwa/out/worktrees/index.txt +22 -22
  276. package/graphs/release/release-loop.yaml +6 -2
  277. package/package.json +1 -1
  278. package/plugins/agent-team/agents/research.md +1 -0
  279. package/scripts/ci-typecheck-changed.ts +3 -2
  280. package/scripts/coord-channel-watch.sh +26 -6
  281. package/scripts/coord-role-pack.ts +143 -0
  282. package/scripts/lib/morning-report-options.ts +41 -0
  283. package/scripts/pr-land-extra-remote-gates.ts +49 -0
  284. package/scripts/release-loop/gate-batch-safe.ts +23 -0
  285. package/scripts/release-loop/gate-history.ts +422 -0
  286. package/scripts/release-loop/gate-node.ts +310 -46
  287. package/scripts/release-loop/gate-triage-node.ts +190 -0
  288. package/scripts/release-loop/spawn-lane.ts +68 -0
  289. package/scripts/release-loop/tui-node-checks.ts +23 -0
  290. package/scripts/release-loop/version-node.ts +62 -4
  291. package/scripts/test-deterministic.ts +41 -12
  292. package/scripts/usage-rollup.ts +11 -3
  293. package/src/acp/core-turn-bridge.ts +98 -22
  294. package/src/acp/elanous-extensions.ts +2 -0
  295. package/src/acp/server.ts +2 -0
  296. package/src/agent/ref-grounding.ts +18 -0
  297. package/src/agent-substrate/pr-reviewer.ts +29 -21
  298. package/src/budget/pty-usage-reemit.ts +7 -0
  299. package/src/budget/run-usage-rollup.ts +9 -0
  300. package/src/budget/usage-daily-store.ts +98 -0
  301. package/src/capture/tui-self-report.ts +22 -4
  302. package/src/chat/index.ts +31 -10
  303. package/src/chat/pickers/modal-runtime.ts +1 -0
  304. package/src/chat/pickers/modals.ts +3 -1
  305. package/src/chat/turn-typeahead.ts +123 -16
  306. package/src/cli/dashboard-name-flag.ts +48 -0
  307. package/src/cli/doctor-cli.ts +80 -0
  308. package/src/cli/log-event-names.ts +12 -0
  309. package/src/cli/msg-cli.ts +45 -2
  310. package/src/cli/pr-cli.ts +382 -105
  311. package/src/cli/pr-land-heavy-remote.ts +233 -0
  312. package/src/cli/pr-land-overlap-evidence.ts +104 -5
  313. package/src/cli/pty-takeover-cli.ts +125 -16
  314. package/src/cli/release-cli.ts +44 -2
  315. package/src/cli/remote-resolve.ts +2 -1
  316. package/src/cli/seat-cli.ts +26 -16
  317. package/src/cli/tasks-cli.ts +8 -2
  318. package/src/cli/usage-cli.ts +146 -12
  319. package/src/cli/usage-daily-cli.ts +84 -0
  320. package/src/context-bus/context-now.ts +82 -5
  321. package/src/core-turn/auth-rejected-notice.ts +41 -0
  322. package/src/core-turn/run-core-turn.ts +13 -2
  323. package/src/core-turn/run-goal-loop.ts +17 -1
  324. package/src/core-turn/short-question.ts +45 -12
  325. package/src/core-turn/types.ts +7 -0
  326. package/src/dashboard/acp-active-model.ts +40 -0
  327. package/src/dashboard/auto-compact-runtime.ts +2 -0
  328. package/src/dashboard/boot-banner.ts +80 -0
  329. package/src/dashboard/dashboard-status-lines.ts +11 -0
  330. package/src/dashboard/detail-viewer-runtime.ts +15 -2
  331. package/src/dashboard/event-loop-stall-monitor.ts +4 -0
  332. package/src/dashboard/goal-loop-thinking.ts +16 -0
  333. package/src/dashboard/hitl-boot.ts +9 -4
  334. package/src/dashboard/index.ts +228 -387
  335. package/src/dashboard/input/chat-main-entry-runtime.ts +2 -0
  336. package/src/dashboard/input/chat-main-log-actions.ts +4 -0
  337. package/src/dashboard/input/chat-main-log-command.ts +12 -1
  338. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +172 -3
  339. package/src/dashboard/input/chat-main-session.ts +6 -2
  340. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  341. package/src/dashboard/input/chat-main-turn.ts +2 -1
  342. package/src/dashboard/input/compact-prepass-recovery.ts +97 -0
  343. package/src/dashboard/input/dashboard-chord-actions.ts +10 -1
  344. package/src/dashboard/input/dashboard-chord-runtime.ts +2 -0
  345. package/src/dashboard/input/external-input-host.ts +45 -0
  346. package/src/dashboard/input/log-fold-binding.ts +18 -0
  347. package/src/dashboard/input/mouse-wiring.ts +17 -4
  348. package/src/dashboard/input/turn-steer-bridge.ts +94 -0
  349. package/src/dashboard/log-click-runtime.ts +5 -3
  350. package/src/dashboard/running-build-status.ts +74 -0
  351. package/src/dashboard/seat-boot-preamble.ts +113 -0
  352. package/src/dashboard/seat-local-instructions.ts +305 -0
  353. package/src/dashboard/slash-runtime/dashboard-handlers.ts +100 -28
  354. package/src/dashboard/slash-runtime/model-choices.ts +35 -0
  355. package/src/dashboard/term-slash-runtime.ts +15 -0
  356. package/src/dashboard/turn-preamble.ts +30 -2
  357. package/src/dashboard/turn-session-layers.ts +176 -0
  358. package/src/dashboard/turn-stream-formatter.ts +14 -6
  359. package/src/dashboard/turn-stream-presentation-applier.ts +8 -0
  360. package/src/domains/release-tool.ts +8 -9
  361. package/src/domains/surface-events.ts +4 -1
  362. package/src/domains/watch-default-scheduler.ts +8 -9
  363. package/src/fold-stack.ts +24 -1
  364. package/src/git-fs/dirty.ts +32 -4
  365. package/src/git-fs/index.ts +43 -1
  366. package/src/graph-runner/runner.ts +1 -0
  367. package/src/harness/harness-gc.ts +32 -5
  368. package/src/index.ts +14 -1
  369. package/src/input/external-input-queue.ts +219 -0
  370. package/src/interactive-terminal-modal.ts +13 -0
  371. package/src/llm/route-decision.ts +25 -0
  372. package/src/llm-stream-retry-display.ts +59 -0
  373. package/src/llm.ts +253 -55
  374. package/src/log-entry.ts +3 -3
  375. package/src/log-pane/search.ts +29 -4
  376. package/src/loops/agent-reply.ts +256 -0
  377. package/src/loops/budget.ts +37 -7
  378. package/src/loops/loop-cli.ts +3 -2
  379. package/src/loops/msg-address.ts +57 -0
  380. package/src/loops/msg-wake.ts +282 -0
  381. package/src/loops/orchestrator/inbox.ts +60 -3
  382. package/src/loops/orchestrator/tick.ts +24 -4
  383. package/src/loops/registry.ts +42 -4
  384. package/src/memory.ts +20 -5
  385. package/src/native-tool-catalog.ts +125 -0
  386. package/src/nexus/api/http-server.ts +5 -0
  387. package/src/nexus/api/ops-api.ts +2 -0
  388. package/src/nexus/api/project-autopsy.ts +127 -0
  389. package/src/nexus/api/terminals.ts +3 -0
  390. package/src/nexus/api/workflow-approvals.ts +2 -0
  391. package/src/nexus/onboarding/first-boot-wizard.ts +56 -2
  392. package/src/oauth/codex-account-store.ts +15 -3
  393. package/src/oauth/codex-billing-route.ts +31 -0
  394. package/src/ops/overview-collect.ts +19 -2
  395. package/src/panes/log-pane.ts +67 -8
  396. package/src/persona/presets.ts +44 -0
  397. package/src/plugins/maker/wizard-generate.ts +6 -4
  398. package/src/preview/terminal.ts +14 -1
  399. package/src/prompt-cache/types.ts +2 -0
  400. package/src/prompt-enhance/enhance.ts +24 -8
  401. package/src/prompt-library/universal-preamble.ts +273 -56
  402. package/src/pty-shell/pty-control-ipc.ts +4 -1
  403. package/src/pty-shell/pty-manifest.ts +77 -5
  404. package/src/pty-shell/registry.ts +19 -2
  405. package/src/pty-shell/tui-run-state.ts +253 -0
  406. package/src/release-loop/light-rc.ts +28 -3
  407. package/src/release-loop/rehearsal.ts +1 -1
  408. package/src/render.ts +5 -1
  409. package/src/seat-loop/seat-report.ts +42 -2
  410. package/src/self-dev/run-supervisor.ts +71 -5
  411. package/src/self-dev/shard-aggregate.ts +2 -0
  412. package/src/self-dev/shard-run.ts +23 -2
  413. package/src/self-health/signatures.ts +132 -0
  414. package/src/self-implement/doctor-visit.ts +118 -0
  415. package/src/self-implement/gate-cli.ts +11 -2
  416. package/src/self-implement/goal-author-decompose.ts +80 -16
  417. package/src/self-implement/goal-author.ts +114 -72
  418. package/src/self-implement/goal-authoring-grounding.ts +1 -1
  419. package/src/self-implement/goal-file-name.ts +65 -0
  420. package/src/self-implement/ground-goal.ts +2 -1
  421. package/src/self-implement/host-regate.ts +14 -0
  422. package/src/self-implement/review-mustfix-class.ts +115 -0
  423. package/src/self-implement/run-ledger.ts +111 -7
  424. package/src/self-implement/running-runs.ts +10 -6
  425. package/src/self-implement/self-implement-runtime.ts +32 -0
  426. package/src/session/pending-input.ts +62 -11
  427. package/src/session-runtime/index.ts +7 -1
  428. package/src/skills/tools/ops-ledger.ts +707 -0
  429. package/src/skills/tools/persistent-grounding.ts +47 -7
  430. package/src/skills/tools/shell.ts +117 -1
  431. package/src/status/bar.ts +32 -2
  432. package/src/status/status-provider-info.ts +58 -0
  433. package/src/task-agent/rejudge-on-head.ts +4 -1
  434. package/src/task-agent/remote-rejudge-bind.ts +34 -5
  435. package/src/task-agent/repair-cycle.ts +13 -0
  436. package/src/task-orchestrator/surfaces/kubectl-transient-retry.ts +51 -0
  437. package/src/task-orchestrator/surfaces/pod-command-job.ts +63 -7
  438. package/src/task-orchestrator/surfaces/pod-install-slots.ts +6 -11
  439. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +76 -0
  440. package/src/task-orchestrator/surfaces/self-implement-pod.ts +107 -33
  441. package/src/terminal/session-registry.ts +6 -0
  442. package/src/thinking-line.ts +12 -3
  443. package/src/tool-runtime/index.ts +4 -0
  444. package/src/tool-runtime/ops-ledger-runtimes.ts +84 -0
  445. package/src/tool-runtime/ref-consult-runtime.ts +17 -2
  446. package/src/tool-runtime/run-shell-runtime.ts +4 -1
  447. package/src/tool-runtime/self-cognition-runtimes.ts +5 -1
  448. package/src/tui.ts +5 -0
  449. package/src/user-config.ts +54 -6
  450. package/src/ux-sim/fake-llm.ts +29 -0
  451. package/src/ux-sim/in-process-cli.ts +175 -0
  452. package/src/version/packed-revision.json +1 -1
  453. package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +0 -36
  458. package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +0 -148
  460. package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/1454-29d1d773d5996a49.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +0 -27
  467. package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +0 -24
  472. package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +0 -32
  475. package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +0 -34
  477. package/apps/pwa/out/_next/static/chunks/3259-86f3be56e43eaf6a.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +0 -287
  482. package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/4084.15ecaf4240bd9e77.js +0 -286
  487. package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +0 -8
  492. package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +0 -104
  494. package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +0 -149
  496. package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/599-56f2c0a5cc4a7295.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +0 -23
  506. package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +0 -77
  510. package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +0 -64
  512. package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +0 -2
  514. package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +0 -62
  522. package/apps/pwa/out/_next/static/chunks/7752.5cbdd0b433c54af9.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/8085-1e5fce59500a2cc2.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +0 -226
  531. package/apps/pwa/out/_next/static/chunks/83a80514-b897b64df43ce108.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +0 -93
  533. package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +0 -24
  534. package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +0 -115
  537. package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +0 -41
  539. package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +0 -74
  540. package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +0 -94
  541. package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +0 -90
  545. package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +0 -79
  549. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/decisions/page-256ffd365d32e100.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e0de78ae7b99f01c.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/exec/page-4c741eb760f2f77c.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/field/page-e9ba98f5f1440a21.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/intake/page-2f6f303fa114ec24.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/live/page-ced0bcfc6542b3fc.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/live-run/page-bb1f05cd51c38944.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-f736324afa2117c1.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/not-found-435f5e2faf02bc01.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/observatory/page-497e0eedf20e7890.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a8d28fdf995e16ea.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/page-66a67eb19ebd976b.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c71267e7681da982.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-cb249e81ed339318.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/settings/page-781cfc5114e097da.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-478157214db6a023.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/setup/page-86141f12cf090b7f.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/share/page-7256c73bb1c36751.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/today/page-979d318a534e92da.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/workflows/page-601fb77340e63c9a.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-11bf9e5725a72c22.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/e117f801.e92bf10242653497.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +0 -122
  599. package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +0 -1
  605. package/src/dashboard/bench-slash-runtime.ts +0 -40
  606. package/src/dashboard/input/search-modal-router.ts +0 -9
  607. package/src/dashboard/modals/pane-key-router.ts +0 -27
  608. package/src/dashboard/view-slash-runtime.ts +0 -48
  609. /package/apps/pwa/out/_next/static/{y1ltt7oCZxVpC6zVPhZ2O → cIpv5nU9AycwYWZI9H589}/_ssgManifest.js +0 -0
@@ -35,7 +35,8 @@
35
35
  // Core really can run headless.
36
36
 
37
37
  import type { LLMMessage, LLMToolSpec, ContentBlock } from '../llm.js';
38
- import { debug } from '../debug/log.js';
38
+ import { debug, redactSecretText } from '../debug/log.js';
39
+ import { CoreTurnAuthRejectedError } from '../core-turn/auth-rejected-notice.js';
39
40
  import {
40
41
  runCoreTurn,
41
42
  runGoalLoop,
@@ -49,20 +50,25 @@ import type { AcpServerOptions, AcpTurnContext } from './server.js';
49
50
  import { acpToolDenialResult } from './tool-approval.js';
50
51
  import { readOriginSessionMeta } from './origin-session-meta.js';
51
52
  import { isFactQuestion } from './fact-question.js';
52
- import { classifyTuiChatIntent, type TuiChatRoute } from '../core-turn/short-question.js';
53
+ import { classifyTuiChatIntent, formatTuiRouteLine, type TuiChatRoute } from '../core-turn/short-question.js';
53
54
  import { HARNESS_ROLE_ENV } from '../harness/harness-space.js';
54
55
 
55
56
  const FACT_QUESTION_INSTRUCTION = '사실·최신 정보 질문이다. WebSearch 를 1~2회 쓰고 검색 결과(제목·스니펫·URL)로 답하라. 출처 링크를 붙여라. 셸·브라우저·파일 도구는 검색 결과로 부족할 때만. 도구 예산에 닿으면 지금까지 근거로 답하고 끝에 «더 찾아볼까요?»를 붙여라.';
56
57
 
58
+ // 읽기·분석 keeps every tool (it reads files and state) and only leaves the goal loop.
59
+ type QuickTuiRoute = Exclude<TuiChatRoute, '코딩·구현' | '읽기·분석'>;
60
+
57
61
  // An allowlist, not a denylist: a new repository writer cannot slip into a quick turn.
58
- const QUICK_TOOLS: Record<Exclude<TuiChatRoute, '코딩·구현'>, readonly string[]> = {
62
+ // memory_recall is read-only and on every quick route: the self-access discipline (agent/self-ambient.ts) tells
63
+ // every turn to recall before judging, so a route without it asked for a tool it could not call (TUI-SEAT-MEMORY-SCOPE).
64
+ const QUICK_TOOLS: Record<QuickTuiRoute, readonly string[]> = {
59
65
  '조회': ['decisions_pending', 'ops_seats', 'ops_status', 'release_status', 'logs_query', 'context_now', 'memory_recall', 'Read'],
60
- '설정 변경': ['DashboardConfigGet', 'DashboardConfigSet', 'LlmListAvailableModels', 'prompt_getRuntimeConfig', 'prompt_setRuntimeConfig', 'view_getConfig', 'view_applyRuntimeConfig', 'view_saveConfig'],
61
- '조사': ['WebSearch', 'OmniSearch', 'Grep', 'Glob', 'Read', 'fact_check'],
62
- '상시 일': ['schedule_manage', 'schedule_list', 'schedule_create', 'schedule_update', 'session_manage', 'ops_status'],
66
+ '설정 변경': ['DashboardConfigGet', 'DashboardConfigSet', 'LlmListAvailableModels', 'prompt_getRuntimeConfig', 'prompt_setRuntimeConfig', 'view_getConfig', 'view_applyRuntimeConfig', 'view_saveConfig', 'memory_recall'],
67
+ '조사': ['WebSearch', 'OmniSearch', 'Grep', 'Glob', 'Read', 'fact_check', 'memory_recall'],
68
+ '상시 일': ['schedule_manage', 'schedule_list', 'schedule_create', 'schedule_update', 'session_manage', 'ops_status', 'memory_recall'],
63
69
  };
64
70
 
65
- export function toolsForTuiRoute(tools: readonly LLMToolSpec[], route: Exclude<TuiChatRoute, '코딩·구현'>): LLMToolSpec[] {
71
+ export function toolsForTuiRoute(tools: readonly LLMToolSpec[], route: QuickTuiRoute): LLMToolSpec[] {
66
72
  const preferred = QUICK_TOOLS[route];
67
73
  return preferred.flatMap((name) => tools.filter((tool) => tool.name === name));
68
74
  }
@@ -155,6 +161,10 @@ export function acpApprovalGatedDispatch(
155
161
  };
156
162
  }
157
163
 
164
+ /** 사용자 답에서 뺀 검증 보충을 로그에 남길 때 한 조각의 글자 수 — 로그 저장의 문자열 상한
165
+ * (`compactForLog` stringMax 256)보다 작아야 조각이 저장 중에 안 잘린다(리뷰 r4). */
166
+ const FINAL_SUPPLEMENT_LOG_CHUNK = 240;
167
+
158
168
  /** Extract the trailing assistant message text from runCoreTurn's
159
169
  * `newMessages` array. emitTurnComplete (src/llm.ts:3835) appends
160
170
  * `{role:'assistant', content:[{type:'text', text:finalAssistantText}]}`
@@ -223,7 +233,7 @@ export function bridgeCoreTurnToAcp(
223
233
  hasAttachments: turnCtx.promptBlocks?.some((block) => block.type !== 'text') ?? false,
224
234
  })
225
235
  : { route: '코딩·구현' as const, reason: harness ? 'harness' : 'legacy', goalLoop: true };
226
- const tools = !route.goalLoop && route.route !== '코딩·구현'
236
+ const tools = !route.goalLoop && route.route !== '코딩·구현' && route.route !== '읽기·분석'
227
237
  ? toolsForTuiRoute(availableTools, route.route)
228
238
  : availableTools;
229
239
  if (deps.tuiRouting) {
@@ -231,12 +241,27 @@ export function bridgeCoreTurnToAcp(
231
241
  // Only a quick route is announced: a coding turn's transcript stays exactly as before (preservation).
232
242
  // Awaited so the route line precedes the answer; a failed write is observed, not fatal to the turn.
233
243
  if (!route.goalLoop) {
234
- try { await turnCtx.push(`라우팅: ${route.route}\n`); }
244
+ try { await turnCtx.push(formatTuiRouteLine(route.route)); }
235
245
  catch (error) { debug.log('chat.route', 'push-failed', { route: route.route, error: String(error) }); }
236
246
  }
237
247
  }
238
248
  const modelOverride = deps.resolveModel?.({ sessionId: turnCtx.sessionId, userText: turnCtx.userText });
239
- const factQuestion = isFactQuestion(turnCtx.userText);
249
+ // Tier 2 arming(config-gated·2026-07-19 goal-exec → 아크4 전-family) — llm.goalLoop.enabled
250
+ // 면 across-turn goal loop(runGoalLoop)로 감싸 목표 완료(update_goal 증거게이트)까지 지속·
251
+ // continuation 재주입. **family 무관**(runGoalLoop 프롬프트·update_goal 툴 전부 provider-generic·
252
+ // 백스톱=max-iter·spin·blocked-3strike·context-pressure). 그 외엔 단일 turn(runCoreTurn).
253
+ // 하드코딩 기본 ON 아님 — config 로 아밍(안전).
254
+ const goalLoopCfg = getUserConfig().llm.goalLoop;
255
+ const armGoalLoop = goalLoopCfg?.enabled === true && route.goalLoop;
256
+ // 사실 질문 예산은 «단일 턴» 전용이다 — goal loop 와 겹치면 예산을 다 쓴 뒤에도 루프가 계속 재촉해
257
+ // 매 continuation 이 «Tool budget reached» 로 거부되고, 모델은 그것을 도구 장애로 읽어 blocked 를 남긴다
258
+ // (10-14 13:48 운영 TUI OP: route short-question·goalLoop ⊕ factQuestion → 소진 뒤 헛호출 7회).
259
+ const factShaped = isFactQuestion(turnCtx.userText);
260
+ const factQuestion = factShaped && !armGoalLoop;
261
+ if (factShaped && armGoalLoop) {
262
+ try { debug.log('chat.turn', 'fact-budget-skipped', { reason: 'goal-loop-armed', route: route.route }); }
263
+ catch { /* observation cannot interrupt a turn */ }
264
+ }
240
265
  const explicitMaxToolTurns = deps.resolveMaxToolTurns?.({ sessionId: turnCtx.sessionId });
241
266
  const maxToolTurns = explicitMaxToolTurns ?? (factQuestion ? getUserConfig().chat.factQuestion.maxToolTurns : undefined);
242
267
  const turnMessages: LLMMessage[] = factQuestion
@@ -262,15 +287,12 @@ export function bridgeCoreTurnToAcp(
262
287
  // `delta=''` (synthesizedText lost to ACP). The dashboard never
263
288
  // saw the substantive answer — only the streamed narration.
264
289
  let streamedTextSum = '';
265
- // Tier 2 arming(config-gated·2026-07-19 goal-exec → 아크4 전-family) — llm.goalLoop.enabled
266
- // 면 across-turn goal loop(runGoalLoop)로 감싸 목표 완료(update_goal 증거게이트)까지 지속·
267
- // continuation 재주입. **family 무관**(runGoalLoop 프롬프트·update_goal 툴 전부 provider-generic·
268
- // 백스톱=max-iter·spin·blocked-3strike·context-pressure). 그 외엔 단일 turn(runCoreTurn).
269
- // 하드코딩 기본 ON 아님 — config 로 아밍(안전). turnFamily 는 관측용으로만 유지.
270
- const goalLoopCfg = getUserConfig().llm.goalLoop;
290
+ // 런타임이 최종 답 꼬리에 붙인 검증 보충(변경 파일·검증 최신성·루프 마감 상태 — goal loop 내부 판정).
291
+ // 사용자 답에서는 빼고 로그로 보낸다(TUI 결함 #25). 코어 턴이 끝날 때마다(goal loop 반복 경계) 비운다.
292
+ let finalSupplement: { answer: string; supplement: string; finalText: string } | null = null;
293
+ // turnFamily 는 관측용으로만 유지(goal loop 아밍 판정은 위 사실 질문 판정 앞에서 한다).
271
294
  const turnModel = modelOverride ?? getUserConfig().llm.model;
272
295
  const turnFamily = getModelFamily(turnModel);
273
- const armGoalLoop = goalLoopCfg?.enabled === true && route.goalLoop;
274
296
  if (armGoalLoop) {
275
297
  // 관측 — 어느 family/모델에서 across-turn goal-loop 가 아밍됐나(전-family 개방 검증).
276
298
  debug.log('goal.loop', 'arm', { family: turnFamily, model: turnModel });
@@ -326,7 +348,7 @@ export function bridgeCoreTurnToAcp(
326
348
  return approvedDispatch(name, args, dispatchCtx);
327
349
  }
328
350
  : approvedDispatch;
329
- await runTurnDispatch({
351
+ const dispatchResult = await runTurnDispatch({
330
352
  sessionId: turnCtx.sessionId,
331
353
  ...(originSessionId ? { originSessionId } : {}),
332
354
  ...(turnCtx.userText ? { userText: turnCtx.userText } : {}),
@@ -338,7 +360,11 @@ export function bridgeCoreTurnToAcp(
338
360
  ...(maxToolTurns !== undefined ? { maxToolTurns } : {}),
339
361
  ...((!factQuestion || explicitMaxToolTurns !== undefined) && deps.budgetGrant !== undefined ? { budgetGrant: deps.budgetGrant } : {}),
340
362
  callbacks: {
341
- onText: (delta) => {
363
+ onText: (delta, full) => {
364
+ // ⛔ 검증 보충이 붙은 최종 답의 재방출(`onText('', 답+보충)`)은 흘리지 않는다 — 빈 청크를 TUI 는
365
+ // «확정(commit)»으로 읽어 이미 그린 답을 굳히고, 아래 onTurnComplete 재표면화가 같은 답을
366
+ // «한 번 더» 그렸다(TUI 결함 #25 · 10-14 18:36 OPT). 답 표시는 onTurnComplete 가 정한다.
367
+ if (delta === '' && finalSupplement !== null && full === finalSupplement.finalText) return;
342
368
  // Fire-and-forget: ACP `push` is async but the core-turn
343
369
  // contract is synchronous onText. Chunks are delivered in
344
370
  // order because `sessionUpdate` is serialized per-
@@ -353,6 +379,7 @@ export function bridgeCoreTurnToAcp(
353
379
  // callers see today. Fire-and-forget for the same reason
354
380
  // onText is: callbacks are synchronous, `turnCtx.push*` is
355
381
  // async, ordering is preserved by the SDK.
382
+ onFinalAnswerSupplement: (info) => { finalSupplement = info; },
356
383
  onToolCall: (call) => {
357
384
  if (!factQuestion || maxToolTurns === undefined || maxToolTurns <= 0) {
358
385
  toolCallCount += 1;
@@ -362,7 +389,8 @@ export function bridgeCoreTurnToAcp(
362
389
  void turnCtx.pushToolCall(call);
363
390
  },
364
391
  onToolResult: (call) => { void turnCtx.pushToolResult(call); },
365
- onUsage: (usage) => { void turnCtx.pushUsage(usage); },
392
+ // 턴 모델(라우팅 결과)을 실어 보낸다 — 대시보드 턴 지표가 설정 모델로 ctx·단가를 잡지 않게.
393
+ onUsage: (usage) => { void turnCtx.pushUsage({ ...usage, model: usage.model ?? turnModel }); },
366
394
  // Codex Responses API reasoning summary stream. Currently
367
395
  // surfaced via forensic only (debug.log) — acts as the
368
396
  // "did the model actually emit reasoning?" verification
@@ -438,8 +466,15 @@ export function bridgeCoreTurnToAcp(
438
466
  visibleFinalText !== null
439
467
  && visibleFinalText.length > 0
440
468
  && streamedTextSum.endsWith(visibleFinalText);
469
+ // ⭐ 최종 답 = 모델 답 ⊕ 런타임 검증 보충이면 사용자에겐 «모델 답»만 보인다 — 보충은 로그로(#25).
470
+ // 대화 이력(completedMessages)엔 그대로 남아 다음 턴 맥락은 바뀌지 않는다.
471
+ const supplement = finalSupplement !== null && finalAssistantText === finalSupplement.finalText
472
+ ? finalSupplement
473
+ : null;
474
+ finalSupplement = null;
441
475
  const needsReSurface =
442
- visibleFinalText !== null
476
+ supplement === null
477
+ && visibleFinalText !== null
443
478
  && visibleFinalText !== streamedTextSum
444
479
  && !synthesisAlreadyStreamed
445
480
  && !originalFinalStreamed;
@@ -452,9 +487,34 @@ export function bridgeCoreTurnToAcp(
452
487
  && visibleFinalText.startsWith(streamedTextSum),
453
488
  endsWithStreamedTail: synthesisAlreadyStreamed,
454
489
  needsReSurface,
490
+ supplementChars: supplement?.supplement.length ?? 0,
455
491
  });
456
492
  }
457
- if (originalFinalStreamed) {
493
+ if (supplement !== null) {
494
+ const answerStreamed = supplement.answer.length > 0 && streamedTextSum.trimEnd().endsWith(supplement.answer);
495
+ try {
496
+ // 보충 «전체»를 남긴다 — 한 행이 저장 전에 잘리지 않게 조각(part/parts)으로 나눈다(리뷰 r3·r4).
497
+ const redacted = redactSecretText(supplement.supplement);
498
+ const parts = Math.max(1, Math.ceil(redacted.length / FINAL_SUPPLEMENT_LOG_CHUNK));
499
+ for (let part = 0; part < parts; part += 1) {
500
+ debug.log('acp.turn', 'final-supplement-withheld', {
501
+ sessionId: turnCtx.sessionId,
502
+ answerChars: supplement.answer.length,
503
+ answerStreamed,
504
+ supplementChars: supplement.supplement.length,
505
+ part: part + 1,
506
+ parts,
507
+ supplement: redacted.slice(part * FINAL_SUPPLEMENT_LOG_CHUNK, (part + 1) * FINAL_SUPPLEMENT_LOG_CHUNK),
508
+ });
509
+ }
510
+ } catch { /* observation cannot interrupt a turn */ }
511
+ if (!answerStreamed && supplement.answer.length > 0) {
512
+ void turnCtx.push('');
513
+ void turnCtx.push(needsFollowup ? `${supplement.answer}${followupSuffix}` : supplement.answer);
514
+ } else if (needsFollowup) {
515
+ void turnCtx.push(followupSuffix);
516
+ }
517
+ } else if (originalFinalStreamed) {
458
518
  void turnCtx.push(followupSuffix);
459
519
  } else if (needsReSurface) {
460
520
  // Emit a clear-then-replace pair so clients that follow
@@ -476,6 +536,22 @@ export function bridgeCoreTurnToAcp(
476
536
  },
477
537
  },
478
538
  });
539
+ // ⭐ 인증 거절은 코어 턴이 «던지지 않고» 돌려준다 — 여기서 안 읽으면 서버는 end_turn 을 내고
540
+ // TUI 엔 «✔ 완료»만 남는다(TUI 결함 #22). 던져서 실패 경로(prompt-failed · 오류 줄)로 보낸다.
541
+ const stopReason = (dispatchResult as { stopReason?: unknown } | null | undefined)?.stopReason;
542
+ if (stopReason === 'auth_rejected') {
543
+ const rawError = (dispatchResult as { errorMessage?: unknown }).errorMessage;
544
+ const error = new CoreTurnAuthRejectedError(typeof rawError === 'string' ? rawError : undefined);
545
+ try {
546
+ debug.log('acp.turn', 'auth-rejected', {
547
+ sessionId: turnCtx.sessionId,
548
+ model: turnModel,
549
+ goalLoop: armGoalLoop,
550
+ error: error.rawMessage.slice(0, 300),
551
+ }, { level: 'warn' });
552
+ } catch { /* observation cannot interrupt a turn */ }
553
+ throw error;
554
+ }
479
555
  } finally {
480
556
  clearInterval(poll);
481
557
  }
@@ -79,6 +79,8 @@ export interface ElanousUiUsagePayload {
79
79
  /** Opaque correlation id. Dashboard uses `turn:<epoch>` per turn. */
80
80
  id: string;
81
81
  provider?: 'anthropic' | 'openai';
82
+ /** 그 턴이 실제로 요청한 모델(라우팅 결과 — 설정 모델과 다를 수 있다). */
83
+ model?: string;
82
84
  inputTokens?: number;
83
85
  outputTokens?: number;
84
86
  cacheReadInputTokens?: number;
package/src/acp/server.ts CHANGED
@@ -837,6 +837,7 @@ export interface AcpTurnContext {
837
837
  * didn't advertise `elanous.ui.usage` in its ClientCapabilities. */
838
838
  pushUsage: (usage: {
839
839
  provider?: 'anthropic' | 'openai';
840
+ model?: string;
840
841
  inputTokens?: number;
841
842
  outputTokens?: number;
842
843
  cacheReadInputTokens?: number;
@@ -1837,6 +1838,7 @@ function wireAcpConnection(
1837
1838
  const payload: ElanousUiUsagePayload = {
1838
1839
  id: `turn:${Date.now()}`,
1839
1840
  ...(usage.provider !== undefined ? { provider: usage.provider } : {}),
1841
+ ...(usage.model !== undefined ? { model: usage.model } : {}),
1840
1842
  ...(usage.inputTokens !== undefined ? { inputTokens: usage.inputTokens } : {}),
1841
1843
  ...(usage.outputTokens !== undefined ? { outputTokens: usage.outputTokens } : {}),
1842
1844
  ...(usage.cacheReadInputTokens !== undefined
@@ -18,6 +18,23 @@ import { debug } from '../debug/log.js';
18
18
  /** 로컬 참조 루트(기본 ~/source/ref). 다른 환경엔 없으면 무동작(graceful). */
19
19
  export const DEFAULT_REFERENCE_ROOTS = [join(homedir(), 'source', 'ref')];
20
20
 
21
+ // 대표 2026-10-14 — 비공개 소스(Claude Code 사본) 통로 차단. Claude Code 는 공개 계약(code.claude.com)만 본다.
22
+ // ref 루트 아래 디렉터리가 실존해도 이 이름이면 그라운딩·조회 대상에서 뺀다(대소문자·`_`/`-` 변형 포함).
23
+ const NON_PUBLIC_REFERENCE_PATTERN = /^claude[-_]?code[-_]?(?:fork|src|source|leak|leaked)$/i;
24
+
25
+ /** 공개 계약이 아닌 참조 사본 이름인가. `owner/repo` 꼴이면 마지막 칸으로 본다. */
26
+ export function isNonPublicReferenceName(name: string): boolean {
27
+ const last = name.trim().replace(/\/+$/, '').split('/').pop() ?? '';
28
+ return NON_PUBLIC_REFERENCE_PATTERN.test(last);
29
+ }
30
+
31
+ /** 거부 판정 ⊕ 관측 한 줄. 거부면 true. */
32
+ export function denyNonPublicReference(name: string): boolean {
33
+ if (!isNonPublicReferenceName(name)) return false;
34
+ try { debug.log('ref.grounding', 'denied', { name, reason: 'non-public-source' }); } catch { /* fail-soft */ }
35
+ return true;
36
+ }
37
+
21
38
  function expandTilde(p: string): string {
22
39
  return p.startsWith('~') ? join(homedir(), p.slice(1)) : p;
23
40
  }
@@ -91,6 +108,7 @@ export function localRefGroundingDigest(taskText: string, roots: string[] = DEFA
91
108
  if (!existsSync(root)) continue;
92
109
  for (const token of tokens) {
93
110
  if (seen.has(token)) continue;
111
+ if (denyNonPublicReference(token)) { seen.add(token); continue; }
94
112
  try {
95
113
  const path = join(root, token);
96
114
  if (statSync(path).isDirectory()) { found.push({ path, root, token }); seen.add(token); }
@@ -652,6 +652,9 @@ export function buildReviewPrompt(
652
652
  * `none of the tests …`. 표지 낱말로 시작하는 실제 블로커를 지우면 PASS/WARN 리뷰에서 블로커가 사라진다. */
653
653
  const NONE_WORD = String.raw`(?:없음|해당\s*없음|n\/a|none|nothing)`;
654
654
  const BARE_SENTINEL = new RegExp(String.raw`^${NONE_WORD}\s*[.。]?$`, 'i');
655
+ const DASH_ONLY_SENTINEL = /^[([(【]\s*[-—–]\s*[)\])】]$/;
656
+ // 목록 항목의 바깥 `- `와 별개로, 리뷰어가 괄호 안에도 장식 대시를 둘 수 있다: `- (- 없음 -)`.
657
+ const DASH_WRAPPED_BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*(?:[-—–]+\s*)?${NONE_WORD}\s*(?:[-—–]+\s*)?[)\])】]$`, 'i');
655
658
  const BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*${NONE_WORD}(?:\s*[—–\-:.,;·]\s*([^)\])】]*))?\s*[)\])】]$`, 'i');
656
659
  // ⭐ 설명 «전체»가 「지적 없음」 한 문장일 때만 — 일부만 맞아도 접으면 `(none: no blockers are checked because …)` 같은 지적이 사라진다.
657
660
  const NO_FINDING_REMARK = new RegExp([
@@ -662,41 +665,38 @@ const NO_FINDING_REMARK = new RegExp([
662
665
  String.raw`^수용\s*기준(?:을|이)?\s*(?:(?:모두|전부)\s*)?충족(?:함|됨|했다|합니다)?[.。]?$`,
663
666
  String.raw`^(?:all\s+)?acceptance\s+criteria\s+(?:are\s+)?(?:all\s+)?met\.?$`,
664
667
  ].join('|'), 'i');
665
- // REVIEW-MUSTFIX-NONE-SENTINEL 후속 — GLM 이 괄호 안에 «무소견 머리 + 긴 근거»를 쓴다(10-11 TC `pr land` 가 `review-must-fix-1` 로 거부):
666
- // `(없음 — 수용기준 충족: 머리말에 … 반영됨 …)` · `(없음 — 수용기준 3항 모두 충족: … (\`'failed'\` 반환) · …)`(근거 안에 괄호가 또 있다).
667
- // ⭐ 길이 무관 0 은 «머리»가 무소견 서술이고 바로 구분자가 올 때만 — 머리가 결함 서술이면(`(없음 — 하지만 X 가 깨진다)`) 지적으로 남긴다.
668
- // ⛔ 근거에 역접·미충족(`하지만`·`다만`·`미충족`·`but`·`except`·`not met` …)이 있으면 보수적으로 지적으로 남긴다.
669
- const LONG_BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*${NONE_WORD}\s*[—–\-:·]\s*([\s\S]+?)\s*[)\])】]$`, 'i');
670
- const NO_FINDING_HEAD = new RegExp('^(?:' + [
671
- String.raw`수용\s*기준(?:\s*\d+\s*(?:항|개|건)(?:목)?)?(?:을|이)?\s*(?:(?:모두|전부)\s*)?충족(?:함|됨|했다|합니다)?`,
672
- String.raw`(?:all\s+)?acceptance\s+criteria\s+(?:are\s+)?(?:all\s+)?met`,
673
- String.raw`must-?fix\s*(?:항목)?(?:은|는|이|가)?\s*(?:없(?:음|다|습니다)|0\s*건)`,
674
- String.raw`(?:no|zero)\s+(?:blocking\s+)?(?:blockers?|must-?fix(?:es)?)(?:\s+found)?`,
675
- String.raw`(?:(?:블로커|차단)\s*)?(?:수준의?\s*)?(?:결함|블로커)(?:은|는|이|가)?\s*(?:발견되지\s*않(?:음|았(?:다|습니다)?)|없(?:음|다|습니다))`,
676
- ].join('|') + String.raw`)\s*(?:[::—–\-·,;.。(]|$)`, 'i');
677
- const LONG_REMARK_DISSENT = /하지만|그러나|다만|(?<![가-힣])단(?:,|\s)|미\s*충족|불\s*충족|충족하지|충족되지|\bbut\b|\bhowever\b|\bexcept\b|\balthough\b|\bnot\s+(?:yet\s+)?met\b|\bunmet\b/i;
678
- /** 괄호 안이 «없음 + 구분자 + 무소견 머리 …» 인가 — 길이 무관(근거 안 괄호도 허용). `isNoneSentinelFinding` 의 갈래. */
668
+ // OP #3173 — 설명은 의미 추정하지 않는다. 실측으로 무소견임을 확인한 문장만 등록한다.
669
+ // 문법 밖 `없음 — 설명`은 실제 결함일 수 있으므로 mustFix에 남긴다.
670
+ const LONG_BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*(?:[-—–]+\s*)?${NONE_WORD}\s*[—–\-:·]\s*([\s\S]+?)\s*[)\])】]$`, 'i');
671
+ const KNOWN_NO_FINDING_REMARKS = new Set([
672
+ // #27349 저장 JSON의 실제 무소견 문구.
673
+ '문서 전용 변경이고 의도된 산출물이 실제로 존재하며 배선 누락·죽은 코드·Goodhart 해당 없음',
674
+ ]);
675
+ /** 괄호 안 `없음` 뒤 설명이 닫힌 무소견 문법에 정확히 들어가는가. */
679
676
  function isLongNoFindingBracket(text: string): boolean {
680
677
  const m = LONG_BRACKETED_SENTINEL.exec(text.trim());
681
678
  if (!m) return false;
682
679
  const remark = m[1]!.trim();
683
- return NO_FINDING_HEAD.test(remark) && !LONG_REMARK_DISSENT.test(remark);
680
+ const bareRemark = remark.replace(/\s*[-—–]+\s*$/, '').trim();
681
+ return NO_FINDING_REMARK.test(bareRemark) || KNOWN_NO_FINDING_REMARKS.has(bareRemark);
684
682
  }
685
683
  /** must-fix 항목이 «지적 없음» 표지인가 — must-fix 를 세는 자리는 전부 `parseReviewResult` 를 거친다
686
684
  * (`self review --json` 의 `mustFix` → TA `parseReviewResultOutput` → `pr land --overlap-evidence` 의 `review-must-fix-N`).
687
685
  * ⭐ export — `parseReviewResultOutput` 가 «같은» 판정으로 저장된 결과의 표지 줄을 다시 접는다(PR-LAND-MUSTFIX-NONE · 복제 금지). */
688
686
  export function isNoneSentinelFinding(finding: string): boolean {
689
687
  const text = finding.trim();
690
- if (BARE_SENTINEL.test(text)) return true;
691
- const bracketed = BRACKETED_SENTINEL.exec(text);
688
+ if (/^[-—–]+$/.test(text)) return true;
689
+ const markerText = text.replace(/^[—–-]+\s*|\s*[—–-]+$/g, '').trim();
690
+ if (markerText && (BARE_SENTINEL.test(markerText) || DASH_ONLY_SENTINEL.test(markerText) || DASH_WRAPPED_BRACKETED_SENTINEL.test(markerText))) return true;
691
+ const bracketed = BRACKETED_SENTINEL.exec(markerText);
692
692
  if (bracketed) {
693
693
  const remark = bracketed[1]?.trim();
694
694
  if (!remark || NO_FINDING_REMARK.test(remark)) return true;
695
695
  }
696
- return isLongNoFindingBracket(text);
696
+ return isLongNoFindingBracket(markerText);
697
697
  }
698
698
 
699
- /** critic 응답 파싱 → ReviewResult. 순수함수. VERDICT + MUST-FIX/SHOULD-FIX/REQUIREMENTS 섹션 분해.
699
+ /** critic 응답 파싱 → ReviewResult. VERDICT + MUST-FIX/SHOULD-FIX/REQUIREMENTS 섹션 분해.
700
700
  * verdict=FAIL 인데 must-fix 미기재면 첫 finding 을 must 로 승격(블로커 근거 보존). */
701
701
  /** ⭐ `VERDICT: PASS|WARN|FAIL` 판정 줄 — `parseReviewResult` 와 `reviewedResultFromRaw` 가 «같은» 정규식을 쓴다(존재 판정이 갈리면 안 된다). */
702
702
  const VERDICT_LINE = /VERDICT:\s*(PASS|WARN|FAIL)/i;
@@ -709,6 +709,7 @@ export function parseReviewResult(text: string): ReviewResult {
709
709
  const shouldFix: string[] = [];
710
710
  const requirements: string[] = [];
711
711
  let fallbackFinding: string | undefined;
712
+ let droppedNonePlaceholders = 0;
712
713
  let section: 'must' | 'should' | 'requirements' | null = null;
713
714
  for (const l of lines) {
714
715
  if (/^MUST-?FIX/i.test(l)) { section = 'must'; continue; }
@@ -718,12 +719,19 @@ export function parseReviewResult(text: string): ReviewResult {
718
719
  if (l.startsWith('- ')) {
719
720
  const f = l.slice(2).trim();
720
721
  if (!f) continue;
721
- if (section === 'must') { if (!isNoneSentinelFinding(f)) mustFix.push(f); }
722
- else if (section === 'should') shouldFix.push(f);
722
+ if (section === 'must') {
723
+ if (isNoneSentinelFinding(f)) droppedNonePlaceholders++;
724
+ else mustFix.push(f);
725
+ } else if (section === 'should') shouldFix.push(f);
723
726
  else if (section === 'requirements') requirements.push(f);
724
727
  else fallbackFinding ??= f;
725
728
  }
726
729
  }
730
+ if (droppedNonePlaceholders > 0) {
731
+ try {
732
+ debug.log('review.parse', 'none-placeholder-dropped', { count: droppedNonePlaceholders });
733
+ } catch { /* observation must not change parsed review data */ }
734
+ }
727
735
  if (verdict === 'fail' && mustFix.length === 0) {
728
736
  const first = shouldFix.shift() ?? fallbackFinding;
729
737
  mustFix.push(first ?? 'PR 리뷰 FAIL — 재작업 필요(구체 지적 미파싱).');
@@ -12,6 +12,10 @@ export interface PtyUsageReemitOpts {
12
12
  readonly workdir: string;
13
13
  /** Codex session UUID observed from this child PTY; empty when unavailable (emit nothing). */
14
14
  readonly sessionId: string;
15
+ /** Caller-observed metadata only. Never infer a Codex account from CODEX_HOME. */
16
+ readonly role?: string;
17
+ readonly stage?: string;
18
+ readonly account?: string;
15
19
  /** Child start time: do not attribute older sessions in a shared CODEX_HOME to this child. */
16
20
  readonly sinceMs?: number;
17
21
  /** Override the dedup ledger location in isolated tests. */
@@ -40,6 +44,9 @@ export function reemitPtyUsage(opts: PtyUsageReemitOpts): number {
40
44
  if (Number(insert.run(home, turn.turnId).changes) === 0) continue;
41
45
  debug.log('llm.usage', 'llm-usage', {
42
46
  runId: opts.runId,
47
+ ...(opts.role !== undefined ? { role: opts.role } : {}),
48
+ ...(opts.stage !== undefined ? { stage: opts.stage } : {}),
49
+ ...(opts.account !== undefined ? { account: opts.account } : {}),
43
50
  substrate: 'pty',
44
51
  site: 'pty-rollup:codex',
45
52
  turnId: turn.turnId,
@@ -16,6 +16,15 @@ export interface RunUsageInput {
16
16
  cost?: { kind?: string; usd?: number; apiEquivalentUsd?: number } | null;
17
17
  }
18
18
 
19
+ /** A returned Pod raw usage row is covered only by a measured rollup from the same Job. */
20
+ export function excludeCoveredPodRawRows<T extends { origin?: unknown; podJob?: unknown; job?: unknown; site?: unknown; measured?: unknown }>(rows: readonly T[]): T[] {
21
+ const rolledUpJobs = new Set(rows.flatMap((row) =>
22
+ typeof row.job === 'string' && row.job.length > 0
23
+ && typeof row.site === 'string' && row.site.startsWith('pod-rollup:')
24
+ && row.site !== 'pod-rollup:missing' && row.measured !== false ? [row.job] : []));
25
+ return rows.filter((row) => row.origin !== 'pod' || typeof row.podJob !== 'string' || !rolledUpJobs.has(row.podJob));
26
+ }
27
+
19
28
  export interface RunUsageRow {
20
29
  runId: string;
21
30
  role?: string;
@@ -0,0 +1,98 @@
1
+ /** Read-only UTC usage buckets from the portion of logs.db still retained. */
2
+ import { existsSync } from 'node:fs';
3
+ import { LogStore, logsDbPath, type LogStoreRow } from '../mss/logging/log-store.js';
4
+
5
+ type Metrics = {
6
+ calls: number; inputTokens: number; outputTokens: number; cacheReadInputTokens: number;
7
+ cacheCreationInputTokens: number; reasoningOutputTokens: number; usdKnown: number;
8
+ unknownCostCalls: number; includedCalls: number; apiEquivalentUsd: number;
9
+ };
10
+ const ZERO: Metrics = { calls: 0, inputTokens: 0, outputTokens: 0, cacheReadInputTokens: 0,
11
+ cacheCreationInputTokens: 0, reasoningOutputTokens: 0, usdKnown: 0, unknownCostCalls: 0,
12
+ includedCalls: 0, apiEquivalentUsd: 0 };
13
+ const FIELDS = Object.keys(ZERO) as Array<keyof Metrics>;
14
+ const finite = (value: unknown): number => typeof value === 'number' && Number.isFinite(value) ? value : 0;
15
+ const nonnegativeOr = (value: unknown, fallback: number): number =>
16
+ typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;
17
+ const label = (value: unknown): string => typeof value === 'string' && value.length > 0 ? value : '(none)';
18
+ const obj = (value: unknown): Record<string, unknown> | null => value && typeof value === 'object' && !Array.isArray(value)
19
+ ? value as Record<string, unknown> : null;
20
+
21
+ function metrics(data: Record<string, unknown>): Metrics {
22
+ const cost = obj(data.cost);
23
+ const calls = nonnegativeOr(data.calls, 1);
24
+ const kind = cost?.kind;
25
+ return {
26
+ calls, inputTokens: finite(data.inputTokens), outputTokens: finite(data.outputTokens),
27
+ cacheReadInputTokens: finite(data.cacheReadInputTokens), cacheCreationInputTokens: finite(data.cacheCreationInputTokens),
28
+ reasoningOutputTokens: finite(data.reasoningOutputTokens),
29
+ usdKnown: kind === 'known' || kind === 'actual' || kind === 'partial' ? finite(cost?.usd) : 0,
30
+ unknownCostCalls: kind === 'unknown' || kind === 'partial' ? nonnegativeOr(cost?.unknownCostCalls, calls)
31
+ : kind === 'known' || kind === 'actual' || kind === 'included' ? 0 : calls,
32
+ includedCalls: kind === 'included' ? nonnegativeOr(cost?.includedCalls, calls) : finite(cost?.includedCalls),
33
+ apiEquivalentUsd: finite(cost?.apiEquivalentUsd),
34
+ };
35
+ }
36
+
37
+ function classify(row: LogStoreRow): { kind: 'host'; data: Record<string, unknown> } | { kind: 'pod' } | { kind: 'unclassified' } {
38
+ let data: Record<string, unknown> | null = null;
39
+ try { data = obj(JSON.parse(row.data ?? '')); } catch { /* unreadable payload stays unmeasured */ }
40
+ if (!data) return { kind: 'unclassified' };
41
+ if (data.origin === 'pod' || typeof data.podJob === 'string' || data.substrate === 'pod'
42
+ || typeof data.site === 'string' && data.site.startsWith('pod-rollup:')) return { kind: 'pod' };
43
+ if (data.measured === false) return { kind: 'unclassified' };
44
+ return { kind: 'host', data };
45
+ }
46
+
47
+ export interface DailyUsageRow extends Metrics {
48
+ day: string; hour: string; role: string; stage: string; account: string; model: string;
49
+ billingProvider: string; billing: string; site: string; hostId: string;
50
+ }
51
+ export interface UsageDailyRead {
52
+ rows: DailyUsageRow[];
53
+ podObservedRows: number;
54
+ unclassifiedRows: number;
55
+ sourceMaxId: number;
56
+ }
57
+
58
+ /** Query every llm.usage event in bounded pages. No database or retention writes occur. */
59
+ export function readUsageDaily(path = logsDbPath(), sinceDay?: string): UsageDailyRead | null {
60
+ if (!existsSync(path)) return null;
61
+ const logs = LogStore.openReadOnly(path);
62
+ try {
63
+ const upper = logs.maxId();
64
+ const groups = new Map<string, DailyUsageRow>();
65
+ let afterId = 0;
66
+ let podObservedRows = 0;
67
+ let unclassifiedRows = 0;
68
+ const sinceMs = sinceDay === undefined ? undefined : Date.parse(`${sinceDay}T00:00:00Z`);
69
+ while (afterId < upper) {
70
+ const page = logs.query({ exactCategories: ['llm.usage'], sinceMs, afterId, limit: 1000 });
71
+ if (!page.length) break;
72
+ for (const row of page) {
73
+ if (row.id > upper) break;
74
+ const classified = classify(row);
75
+ if (classified.kind === 'pod') { podObservedRows++; continue; }
76
+ if (classified.kind === 'unclassified') { unclassifiedRows++; continue; }
77
+ const { data } = classified;
78
+ const hour = new Date(row.ts_ms).toISOString().slice(0, 13);
79
+ const day = hour.slice(0, 10);
80
+ const dimensions = [label(data.role), label(data.stage), label(data.account), label(data.model),
81
+ label(data.billingProvider ?? data.provider), label(data.billing), label(data.site), label(data.hostId ?? row.host_id)];
82
+ const key = JSON.stringify([hour, ...dimensions]);
83
+ let value = groups.get(key);
84
+ if (!value) {
85
+ const [role, stage, account, model, billingProvider, billing, site, hostId] = dimensions;
86
+ value = { day, hour, role: role!, stage: stage!, account: account!, model: model!, billingProvider: billingProvider!,
87
+ billing: billing!, site: site!, hostId: hostId!, ...ZERO };
88
+ groups.set(key, value);
89
+ }
90
+ const delta = metrics(data);
91
+ for (const field of FIELDS) value[field] += delta[field];
92
+ }
93
+ afterId = page.at(-1)!.id;
94
+ }
95
+ return { rows: [...groups.values()].sort((a, b) => a.hour.localeCompare(b.hour)),
96
+ podObservedRows, unclassifiedRows, sourceMaxId: upper };
97
+ } finally { logs.close(); }
98
+ }
@@ -42,7 +42,9 @@ import {
42
42
  upsertPtyManifest, updatePtyManifestFrame, touchLivePtyManifest, markPtyManifestClosed, removePtyManifest,
43
43
  } from '../pty-shell/pty-manifest.js';
44
44
  import { writeHarnessScreen } from '../harness/harness-screen.js';
45
+ import { startTuiRunStateRecorder } from '../pty-shell/tui-run-state.js';
45
46
  import { debug } from '../debug/log.js';
47
+ import { routeExternalInput, type ExternalInputRoute } from '../input/external-input-queue.js';
46
48
 
47
49
  export interface TuiFrameObserverCfg {
48
50
  surfaceId: string;
@@ -99,6 +101,8 @@ export interface TuiControlTargetDeps {
99
101
  splitKeys?: (input: string) => Key[];
100
102
  /** The foreground terminal's real size; `undefined` when it cannot be known (stdout is not a TTY). */
101
103
  dims?: () => { readonly cols: number; readonly rows: number } | undefined;
104
+ /** 외부 주입 라우터 — 글 한 줄을 사용자 버퍼에 섞지 않고 별도 대기열로 돌린다(`input/external-input-queue`). */
105
+ routeExternal?: (chars: string) => ExternalInputRoute;
102
106
  }
103
107
 
104
108
  function stdoutDims(): { cols: number; rows: number } | undefined {
@@ -116,6 +120,7 @@ export function createTuiControlTarget(surfaceId: string, deps: TuiControlTarget
116
120
  const inject = deps.injectKey ?? injectKey;
117
121
  const parse = deps.splitKeys ?? splitKeys;
118
122
  const dims = deps.dims ?? stdoutDims;
123
+ const routeExternal = deps.routeExternal ?? routeExternalInput;
119
124
  let alive = true;
120
125
  let accessMode: PtyAccessMode = 'write';
121
126
  let transitionPolicy: PtyTransitionPolicy = 'open';
@@ -135,6 +140,8 @@ export function createTuiControlTarget(surfaceId: string, deps: TuiControlTarget
135
140
  isAlive: () => alive,
136
141
  canWrite: (actor: PtyWriteActor = 'human') => resolveWriteDecision(accessMode, actor).allow,
137
142
  write(chars: string): void {
143
+ // ⭐ 이 write 는 «바깥»(제어 IPC)에서만 온다 — 키보드와 섞이기 전에 라우터가 먼저 가른다.
144
+ if (routeExternal(chars) !== 'passthrough') return;
138
145
  const keys = parse(chars);
139
146
  if (!keys.length || !keys.every(inject)) throw new Error('tui-input-undelivered');
140
147
  },
@@ -145,11 +152,13 @@ export function createTuiControlTarget(surfaceId: string, deps: TuiControlTarget
145
152
 
146
153
  export interface TuiSelfReportDeps {
147
154
  surfaceId?: string;
155
+ /** `elanous --name <name>` — 자기 manifest 행 별명. `pty list`·`pty snapshot <name>` 이 이것으로 부른다. */
156
+ nickname?: string;
148
157
  throttleMs?: number;
149
158
  now?: () => number;
150
159
  register?: (fn: ((lines: readonly string[], dims: { rows: number; cols: number }) => void) | null) => void;
151
160
  publishFrame?: (frame: SelfReportFrame) => void;
152
- registerRow?: (surfaceId: string, now: number) => void;
161
+ registerRow?: (surfaceId: string, now: number, nickname?: string) => void;
153
162
  writeFrame?: (surfaceId: string, text: string, now: number) => void;
154
163
  /** B(harness-screens 파일) sink — `elanous self screen` 이 읽는 substrate.
155
164
  * 자식 harness 발행과 대칭(tmux 없이 L2 대시보드 자기 화면 관측). */
@@ -174,6 +183,8 @@ export interface TuiSelfReportDeps {
174
183
  startControlPoller?: () => (() => void);
175
184
  reportControlInitFailure?: (stage: TuiControlInitStage, error: unknown) => void;
176
185
  reportControlCleanupFailure?: (stage: TuiControlCleanupStage, error: unknown) => void;
186
+ /** 행 등록 직후 실행 판 ⊕ 턴(idle) 기록을 연다 — `elanous pty state` 가 읽는다. 반환 = 정리. */
187
+ startRunState?: (surfaceId: string) => (() => void);
177
188
  }
178
189
 
179
190
  export type TuiControlInitStage = 'create-target' | 'register-target' | 'start-poller' | 'publish-manifest';
@@ -235,7 +246,9 @@ export function startTuiSelfReport(deps: TuiSelfReportDeps = {}): () => void {
235
246
  initDisposers.push({ stage: 'stop-poller', dispose: stopControlPoller });
236
247
  controlInitStage = 'publish-manifest';
237
248
  initDisposers.push({ stage: 'rollback-manifest', dispose: () => rollbackRow(surfaceId) });
238
- registerRow(surfaceId, now());
249
+ const nickname = deps.nickname?.trim() || undefined;
250
+ registerRow(surfaceId, now(), nickname);
251
+ if (nickname) debug.log('pty.rename', 'tui-launch-name', { ptyId: surfaceId, nickname });
239
252
  } catch (error) {
240
253
  for (let disposer = initDisposers.pop(); disposer; disposer = initDisposers.pop()) {
241
254
  try { disposer.dispose(); } catch (cleanupError) {
@@ -246,6 +259,10 @@ export function startTuiSelfReport(deps: TuiSelfReportDeps = {}): () => void {
246
259
  return () => {};
247
260
  }
248
261
  const activeControlTarget = controlTarget;
262
+ let stopRunState: () => void = () => {};
263
+ // 행 등록을 갈아 끼운 호출자(시험)는 실 manifest 를 안 건드린다 — 기본 녹음기는 기본 행 등록과 짝일 때만.
264
+ const startRunState = deps.startRunState ?? (deps.registerRow ? () => () => {} : startTuiRunStateRecorder);
265
+ try { stopRunState = startRunState(surfaceId); } catch { /* fail-soft — recorder logs its own write failures */ }
249
266
  const driveTicks = deps.driveTicks ?? ((tick, ms) => {
250
267
  const t = setInterval(tick, ms);
251
268
  (t as { unref?: () => void }).unref?.();
@@ -320,6 +337,7 @@ export function startTuiSelfReport(deps: TuiSelfReportDeps = {}): () => void {
320
337
  try { stopSource(); } catch { /* fail-soft — unregisters observer / clears tick timer */ }
321
338
  try { mirror?.stop(); } catch { /* fail-soft — restores stdout.write */ }
322
339
  clearInterval(hb);
340
+ try { stopRunState(); } catch { /* fail-soft */ }
323
341
  try { markClosed(surfaceId, now()); } catch { /* fail-soft */ }
324
342
  try { activeControlTarget?.deactivate(); } catch { /* fail-soft */ }
325
343
  try { stopControlPoller(); } catch { /* fail-soft */ }
@@ -357,8 +375,8 @@ function defaultPublishFrame(frame: SelfReportFrame): void {
357
375
  publishSelfReportFrame(getChannelBus(), frame);
358
376
  }
359
377
 
360
- function defaultRegisterRow(surfaceId: string, now: number): void {
361
- upsertPtyManifest({ id: surfaceId, kind: 'tui', cmd: 'elanous', startedAt: now, now });
378
+ function defaultRegisterRow(surfaceId: string, now: number, nickname?: string): void {
379
+ upsertPtyManifest({ id: surfaceId, kind: 'tui', ...(nickname ? { nickname } : {}), cmd: 'elanous', startedAt: now, now });
362
380
  }
363
381
 
364
382
  function defaultWriteFrame(surfaceId: string, text: string, now: number): void {