elanous 0.2.34 → 0.2.36

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 (802) 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/chunks/{abb4b98b.163e0f56e84ae35d.js → 053a429e.9a63436527cc751c.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +287 -0
  5. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +64 -0
  11. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +36 -0
  12. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +149 -0
  15. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 2683.c9773a0c589b031b.js} +4 -4
  20. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
  21. package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 275-02ea4c2a33980422.js} +3 -3
  22. package/apps/pwa/out/_next/static/chunks/{ffdc3a04.b9c23c1b28dd4a96.js → 2812ca6a.3b9f4a7a08885744.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
  26. package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.js → 2986.45d7652e4f13557e.js} +2 -2
  27. package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/{8817.61bb7ffbba502ecb.js → 3136.30aaaa5fa03662a3.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3148-98efd4869d660a87.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/{3498.cf2a15a8a9e5b926.js → 3155.2587a55196ecb394.js} +3 -3
  31. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{3103.84470c8445962f04.js → 3324.a09703033abcbd2f.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +8 -0
  36. package/apps/pwa/out/_next/static/chunks/3410.7f9af5ab77cbe65f.js +115 -0
  37. package/apps/pwa/out/_next/static/chunks/{3819.163d4777f0a597f6.js → 3538.a445e50bb359d068.js} +2 -2
  38. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +286 -0
  40. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.js → 3727.7949ccaacaa71242.js} +2 -2
  42. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3757-180308bc61021b05.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
  45. package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → 3a3d9966.cc4d4585a2708e7c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +104 -0
  51. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/{6740.43de73fc427c9fe2.js → 4286.b70c4520306817e8.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/4304.e9b2512834a9e23e.js +23 -0
  54. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{8548.036c344973968847.js → 4615.8525eb0add35eba6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/{3411-f87314c6c66ebc73.js → 5085-bce4904931767ca6.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +93 -0
  59. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/{3110.0a7065f25c841818.js → 528.38ce20ef8aa251ff.js} +16 -16
  61. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +122 -0
  62. package/apps/pwa/out/_next/static/chunks/{1644.35dd25240ae24e4b.js → 552.b7d061ad91eeac51.js} +2 -2
  63. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{3837.722e053fb9f321ad.js → 5711.957b095705c12560.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.js → 575.d929793a53f27c4b.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{7562.948255cbc3e79d33.js → 599.c39c571b6733f2a2.js} +2 -2
  70. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +79 -0
  71. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +27 -0
  84. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/{5446.edf141cff9ef647d.js → 6925.562d532110879886.js} +1 -1
  86. package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 6943.c6b24124853a47b2.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.js → 7481.39f7a4654907bf6e.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 771.c3cdb6c1f7f47c02.js} +16 -16
  92. package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{3121.779fafe3e44612c5.js → 7891.03f910124a737985.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +62 -0
  100. package/apps/pwa/out/_next/static/chunks/{9a8cb466.cc9fc9e6e46038aa.js → 873d6c12.09bd499f57171543.js} +1 -1
  101. package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.js → 8904.7d51af2dc033965c.js} +2 -2
  102. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +90 -0
  104. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +94 -0
  105. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.js → 9250-072df22eaadaa6b5.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +77 -0
  111. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{2547.dd27303624cb4da8.js → 9514.131c52cc75fe6439.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9f31e478.fefcbcd3c388ebc5.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/{page-4fb31eb476dcbad3.js → page-083747f1d4518f61.js} +1 -1
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → ceba0382.650712b56b85b582.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/da5ecc5c-b005ad8cac737d57.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +1 -0
  183. package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_buildManifest.js +1 -1
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +3 -2
  278. package/catalog/providers/opengateway.yaml +25 -0
  279. package/docs/goal-context/01-goal-authoring-checks.md +8 -0
  280. package/docs/goal-context/03-verification-menu.md +24 -0
  281. package/docs/goal-context/04-mock-scenarios.md +100 -0
  282. package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
  283. package/docs/goal-context/README.md +7 -0
  284. package/graphs/catalog/catalog.yaml +1 -1
  285. package/graphs/default-loop.yaml +63 -4
  286. package/graphs/document-loop.yaml +51 -3
  287. package/graphs/implement-loop.yaml +77 -4
  288. package/graphs/journey/ta-journey.yaml +11 -1
  289. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  290. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  291. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  292. package/graphs/operate-loop.yaml +51 -3
  293. package/graphs/release/recipes.yaml +6 -0
  294. package/graphs/release/release-loop.yaml +17 -4
  295. package/graphs/research-loop.yaml +137 -3
  296. package/graphs/test-diet/test-diet.yaml +3 -0
  297. package/graphs/wizard/recipes.yaml +44 -0
  298. package/graphs/wizard/wizard-loop.yaml +44 -0
  299. package/graphs/work/research-report.yaml +2 -0
  300. package/package.json +1 -1
  301. package/scripts/ci-typecheck-changed.ts +139 -5
  302. package/scripts/coord-role-pack.ts +19 -6
  303. package/scripts/first10-gate.ts +416 -0
  304. package/scripts/fleet/wsl-node-setup.sh +432 -0
  305. package/scripts/hq/standby-snapshot.ts +17 -12
  306. package/scripts/release-loop/docs-land-node.ts +21 -5
  307. package/scripts/release-loop/docs-node.ts +204 -8
  308. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  309. package/scripts/release-loop/gate-node.ts +427 -72
  310. package/scripts/release-loop/gate-partial.ts +65 -11
  311. package/scripts/release-loop/gate-radius-live.ts +177 -0
  312. package/scripts/release-loop/gate-radius-shadow.ts +1 -1
  313. package/scripts/release-loop/node-verdict.ts +14 -1
  314. package/scripts/release-loop/npm-publish-node.ts +66 -12
  315. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  316. package/scripts/release-loop/pwa-remote.ts +166 -0
  317. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  318. package/scripts/release-loop/resume-cap.ts +14 -34
  319. package/scripts/release-loop/resume-release.ts +78 -15
  320. package/scripts/release-loop/traffic-node.ts +59 -0
  321. package/scripts/release-loop/traffic-transition.ts +159 -0
  322. package/scripts/release-loop/unattended-release.ts +2 -0
  323. package/scripts/rhythm/daily.ts +137 -3
  324. package/scripts/test-diet/lib.ts +6 -1
  325. package/scripts/test-diet/node.ts +194 -13
  326. package/scripts/ux-sim.ts +92 -0
  327. package/skills/README.md +1 -0
  328. package/src/acp/core-turn-bridge.ts +48 -6
  329. package/src/agent/delegate-hint.ts +16 -0
  330. package/src/agent/runner.ts +82 -2
  331. package/src/agent/self-ambient-cache.ts +8 -0
  332. package/src/agent/task-notification.ts +56 -10
  333. package/src/agent/types.ts +4 -0
  334. package/src/agent-substrate/acp-reviewer.ts +39 -4
  335. package/src/agent-substrate/pr-reviewer.ts +72 -3
  336. package/src/agent-substrate/review-intent.ts +29 -2
  337. package/src/agent-substrate/review-observation.ts +3 -0
  338. package/src/agent-substrate/self-review-cli.ts +229 -28
  339. package/src/autopilot/mission-codebase-gate.ts +141 -12
  340. package/src/autopilot/pr-manager.ts +240 -41
  341. package/src/boot/daemon-tools/self-implement.ts +1 -0
  342. package/src/budget/run-usage-rollup.ts +1 -0
  343. package/src/budget/usage-outcomes.ts +8 -4
  344. package/src/capture/tui-self-report.ts +102 -0
  345. package/src/chat/goal-continue-verdict.ts +41 -0
  346. package/src/chat/index.ts +30 -6
  347. package/src/chat/internal-turn-origin.ts +1 -0
  348. package/src/chat/paste-fold.ts +86 -0
  349. package/src/chat/pickers/modal-runtime.ts +10 -27
  350. package/src/chat/tool-render/block.ts +32 -0
  351. package/src/chat/tool-render/dispatch.ts +2 -20
  352. package/src/chat/tool-render/result-text.ts +98 -0
  353. package/src/chat/turn-typeahead.ts +70 -7
  354. package/src/cli/agent-cli.ts +13 -2
  355. package/src/cli/config-audit.ts +119 -0
  356. package/src/cli/doctor-cli.ts +26 -1
  357. package/src/cli/guardian-cli.ts +10 -0
  358. package/src/cli/herdr-cli.ts +34 -0
  359. package/src/cli/light-entry-route.ts +50 -7
  360. package/src/cli/log-event-names.ts +2 -0
  361. package/src/cli/make-cli.ts +247 -11
  362. package/src/cli/msg-cli.ts +117 -3
  363. package/src/cli/pod-cli.ts +77 -3
  364. package/src/cli/pr-cli.ts +34 -18
  365. package/src/cli/pr-land-base-read.ts +11 -2
  366. package/src/cli/pr-land-heavy-remote.ts +6 -3
  367. package/src/cli/pr-land-overlap-evidence.ts +23 -4
  368. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  369. package/src/cli/pr-land-recovery.ts +117 -1
  370. package/src/cli/pty-takeover-cli.ts +8 -7
  371. package/src/cli/release-checklist-read-cli.ts +79 -0
  372. package/src/cli/release-cli.ts +92 -106
  373. package/src/cli/release-single-flight.ts +1 -1
  374. package/src/cli/remote-resolve.ts +1 -1
  375. package/src/cli/root-tui-entry.ts +48 -0
  376. package/src/cli/sim-cli.ts +22 -0
  377. package/src/cli/tasks-card-show.ts +162 -0
  378. package/src/cli/tasks-cli.ts +1065 -338
  379. package/src/cli/tasks-read-cli.ts +197 -0
  380. package/src/cli/usage-cli.ts +13 -11
  381. package/src/clipboard/history.ts +179 -13
  382. package/src/config.ts +8 -1
  383. package/src/core-turn/run-core-turn.ts +4 -2
  384. package/src/core-turn/run-goal-loop.ts +73 -16
  385. package/src/core-turn/types.ts +6 -1
  386. package/src/dashboard/chat/acp-chat.ts +8 -0
  387. package/src/dashboard/context/keys.ts +8 -31
  388. package/src/dashboard/index.ts +280 -59
  389. package/src/dashboard/input/agent-wake.ts +7 -1
  390. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
  391. package/src/dashboard/input/chat-main-slash-command.ts +4 -2
  392. package/src/dashboard/input/goal-continue.ts +210 -0
  393. package/src/dashboard/input/goal-interim.ts +2 -0
  394. package/src/dashboard/input/internal-turn.ts +2 -8
  395. package/src/dashboard/input/seat-autowake.ts +9 -7
  396. package/src/dashboard/input/turn-autoheal.ts +52 -0
  397. package/src/dashboard/render/theme-resolver.ts +33 -4
  398. package/src/dashboard/seat-boot-preamble.ts +132 -5
  399. package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
  400. package/src/dashboard/slash-runtime/dashboard-handlers.ts +3 -2
  401. package/src/dashboard/slash-runtime/model-choices.ts +15 -0
  402. package/src/dashboard/stale-install-check.ts +3 -99
  403. package/src/debug/batch-queue.ts +119 -0
  404. package/src/debug/tui-log-tag.ts +67 -0
  405. package/src/display/agent-surface.ts +7 -0
  406. package/src/domains/schedule-registry.ts +16 -2
  407. package/src/domains/standalone-log-sink.ts +15 -2
  408. package/src/esc-abort-gate.ts +69 -0
  409. package/src/git-fs/idle-refresh.ts +76 -0
  410. package/src/git-fs/index.ts +18 -7
  411. package/src/git-fs/worktree.ts +137 -5
  412. package/src/graph-kinds/registry.ts +2 -2
  413. package/src/graph-runner/graph-cli.ts +18 -0
  414. package/src/graph-runner/runner.ts +173 -21
  415. package/src/graph-wizard/generate.ts +108 -4
  416. package/src/graph-wizard/steps.ts +15 -0
  417. package/src/grok/credential.ts +10 -3
  418. package/src/grounding/proactive-ground.ts +86 -0
  419. package/src/harness/control-inbox.ts +49 -1
  420. package/src/harness/harness-cli-command.ts +163 -35
  421. package/src/harness/harness-incidents.ts +85 -1
  422. package/src/harness/launch-utterance-ledger.ts +208 -0
  423. package/src/harness/pod-control-send.ts +33 -5
  424. package/src/harness/self-send-remote.ts +69 -0
  425. package/src/harness/self-send-routing-guard.ts +6 -0
  426. package/src/harness/self-send-target.ts +4 -3
  427. package/src/impl-discipline/detector.ts +16 -4
  428. package/src/impl-discipline/system-prompt.ts +11 -0
  429. package/src/impl-discipline/types.ts +2 -2
  430. package/src/index.ts +822 -154
  431. package/src/input-core/context-key-runtime.ts +21 -0
  432. package/src/intake-plane/already-built-hint.ts +4 -2
  433. package/src/intake-plane/requirement-funnel.ts +29 -1
  434. package/src/light-cli.ts +32 -11
  435. package/src/llm/opengateway-models.ts +11 -0
  436. package/src/llm/provider-credentials.ts +14 -0
  437. package/src/llm/provider-detect.ts +8 -1
  438. package/src/llm/runtime-model-family.ts +2 -1
  439. package/src/llm-wellformed.ts +70 -0
  440. package/src/llm.ts +247 -59
  441. package/src/loops/msg-wake.ts +35 -39
  442. package/src/loops/orchestrator/inbox.ts +59 -11
  443. package/src/loops/orchestrator/knowhow-pack.ts +364 -0
  444. package/src/loops/orchestrator/tick.ts +5 -1
  445. package/src/maturity/feature-maturity.ts +1 -1
  446. package/src/model-tier/llm-tier-map.ts +15 -1
  447. package/src/models/prompts.ts +17 -2
  448. package/src/msg/msg-post-office.ts +116 -0
  449. package/src/mss/logging/log-store.ts +79 -22
  450. package/src/native-tool-catalog.ts +15 -1
  451. package/src/nexus/api/decisions-route.ts +38 -18
  452. package/src/nexus/api/graph-wizard-api.ts +20 -2
  453. package/src/nexus/api/loop-resources.ts +13 -1
  454. package/src/nexus/boot/register-mcp-clients.ts +263 -38
  455. package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
  456. package/src/oauth/codex.ts +7 -0
  457. package/src/onboarding/first-run.ts +37 -6
  458. package/src/onboarding/web-first.ts +43 -11
  459. package/src/ops/overview-collect.ts +30 -9
  460. package/src/ops/overview.ts +22 -9
  461. package/src/persona/loader.ts +11 -0
  462. package/src/persona/types.ts +8 -0
  463. package/src/pr-tool/census.ts +261 -27
  464. package/src/prompt-library/session-guidance.ts +14 -0
  465. package/src/provider-summary.ts +8 -0
  466. package/src/pty-shell/herdr-agent-report.ts +118 -9
  467. package/src/pty-shell/herdr-prompt.ts +266 -0
  468. package/src/pty-shell/pty-control-ipc.ts +151 -8
  469. package/src/pty-shell/pty-manifest.ts +7 -0
  470. package/src/pty-shell/pty-special-keys.ts +42 -2
  471. package/src/pty-shell/stale-install-check.ts +99 -0
  472. package/src/pty-shell/tui-run-state.ts +14 -2
  473. package/src/release-loop/auto-start.ts +20 -2
  474. package/src/release-loop/checklist.ts +100 -4
  475. package/src/release-loop/landed-but-yellow.ts +129 -5
  476. package/src/release-loop/light-rc.ts +1 -0
  477. package/src/release-loop/rehearsal.ts +37 -21
  478. package/src/repl/index.ts +192 -17
  479. package/src/repl/ops-msg-bridge.ts +32 -0
  480. package/src/seat-loop/knowhow-lint.ts +1 -1
  481. package/src/self-dev/ask-launch-flow.ts +44 -5
  482. package/src/self-dev/cli-help-text.ts +17 -0
  483. package/src/self-dev/decompose-proposal.ts +172 -20
  484. package/src/self-dev/decompose.ts +61 -0
  485. package/src/self-dev/dev-cli.ts +48 -12
  486. package/src/self-dev/dev-pipeline.ts +8 -2
  487. package/src/self-dev/draft-residue.ts +37 -1
  488. package/src/self-dev/draft-sweep.ts +137 -11
  489. package/src/self-dev/draft-triage-rules.ts +138 -0
  490. package/src/self-dev/fleet-reduce.ts +3 -2
  491. package/src/self-dev/glm-credential-guard.ts +77 -0
  492. package/src/self-dev/graph-front-nodes.ts +112 -0
  493. package/src/self-dev/graph-journey-nodes.ts +2 -0
  494. package/src/self-dev/graph-journey-route.ts +12 -2
  495. package/src/self-dev/harness-run-cli.ts +3 -15
  496. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  497. package/src/self-dev/orchestrate-cli.ts +68 -3
  498. package/src/self-dev/orchestrate.ts +116 -17
  499. package/src/self-dev/review-provider-fallback.ts +35 -1
  500. package/src/self-dev/run-supervisor.ts +55 -2
  501. package/src/self-dev/run-types.ts +1 -1
  502. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  503. package/src/self-dev/shard-aggregate.ts +42 -5
  504. package/src/self-dev/shard-run.ts +8 -1
  505. package/src/self-health/autoheal.ts +153 -0
  506. package/src/self-health/signatures.ts +6 -0
  507. package/src/self-implement/blocked-draft-policy.ts +20 -0
  508. package/src/self-implement/classify-shadow.ts +3 -7
  509. package/src/self-implement/device-first.ts +116 -0
  510. package/src/self-implement/doctor-visit.ts +257 -2
  511. package/src/self-implement/evidence-command-budget.ts +80 -0
  512. package/src/self-implement/gate-baseline.ts +56 -17
  513. package/src/self-implement/gate-cli.ts +1 -0
  514. package/src/self-implement/gate-remote.ts +31 -20
  515. package/src/self-implement/goal-author-cli.ts +1 -0
  516. package/src/self-implement/goal-author-decompose.ts +534 -45
  517. package/src/self-implement/goal-author.ts +282 -7
  518. package/src/self-implement/goal-elaborate.ts +449 -0
  519. package/src/self-implement/goal-refine.ts +273 -0
  520. package/src/self-implement/graph-overlay-yaml.ts +14 -3
  521. package/src/self-implement/graph-variant.ts +40 -6
  522. package/src/self-implement/headless-elanous-driver.ts +19 -3
  523. package/src/self-implement/off-diff-evidence.ts +58 -6
  524. package/src/self-implement/orchestrator.ts +370 -62
  525. package/src/self-implement/pod-warm-pool-profile.ts +1 -0
  526. package/src/self-implement/pwa-import-graph.ts +1 -1
  527. package/src/self-implement/rework-budget-judgment.ts +5 -8
  528. package/src/self-implement/rework-policy.ts +30 -0
  529. package/src/self-implement/run-ledger.ts +108 -0
  530. package/src/self-implement/run-stop.ts +10 -1
  531. package/src/self-implement/run-ttl.ts +38 -24
  532. package/src/self-implement/running-runs.ts +29 -1
  533. package/src/self-implement/scope-adjacency.ts +115 -0
  534. package/src/self-implement/seams.ts +187 -28
  535. package/src/self-implement/stop-autoheal.ts +87 -1
  536. package/src/self-implement/wiring-check.ts +358 -0
  537. package/src/session-runtime/index.ts +1 -1
  538. package/src/setup/llm-env-detect.ts +5 -0
  539. package/src/shell-env-bootstrap.ts +11 -4
  540. package/src/skills/runner.ts +4 -2
  541. package/src/skills/tools/agent.ts +408 -40
  542. package/src/skills/tools/msg-ask.ts +100 -0
  543. package/src/skills/tools/ops-ledger.ts +2 -1
  544. package/src/skills/tools/schedule-wakeup.ts +23 -4
  545. package/src/skills/tools/shell.ts +61 -6
  546. package/src/skills/tools/terminal-modal-inject.ts +1 -2
  547. package/src/skills/tools/terminal-modal.ts +10 -8
  548. package/src/skills/url-router.ts +41 -1
  549. package/src/smart-wizard/run.ts +66 -0
  550. package/src/status/bar.ts +34 -6
  551. package/src/status/status-provider-info.ts +37 -6
  552. package/src/steward/hold-hygiene.ts +24 -6
  553. package/src/steward/rejudge-tick.ts +10 -2
  554. package/src/steward/ta-repair-event-collect.ts +17 -6
  555. package/src/steward/triage-budget.ts +194 -0
  556. package/src/steward/triage.ts +20 -3
  557. package/src/task-agent/actions.ts +72 -2
  558. package/src/task-agent/green-sweep.ts +4 -0
  559. package/src/task-agent/land-queue.ts +21 -8
  560. package/src/task-agent/live-moves.ts +182 -10
  561. package/src/task-agent/mission.ts +30 -0
  562. package/src/task-agent/parent-host.ts +123 -3
  563. package/src/task-agent/rejudge-on-head.ts +15 -0
  564. package/src/task-agent/repair-cycle.ts +138 -32
  565. package/src/task-agent/repair-next-move.ts +31 -3
  566. package/src/task-agent/repair-outcomes.ts +29 -0
  567. package/src/task-agent/repair-worker.ts +14 -4
  568. package/src/task-agent/shadow.ts +48 -4
  569. package/src/task-agent/task-card-prefix.ts +2 -0
  570. package/src/task-agent/task-hand.ts +525 -57
  571. package/src/task-agent/task-parent-role-llm.ts +36 -0
  572. package/src/task-agent/tier-split.ts +196 -0
  573. package/src/task-agent/work-order-build.ts +2 -0
  574. package/src/task-agent/work-order.ts +3 -2
  575. package/src/task-orchestrator/generator-prompt.ts +60 -11
  576. package/src/task-orchestrator/surfaces/pod-account-broker.ts +42 -0
  577. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  578. package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
  579. package/src/task-orchestrator/surfaces/pod-command-job.ts +130 -11
  580. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
  581. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  582. package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
  583. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  584. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +19 -2
  585. package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
  586. package/src/task-orchestrator/surfaces/pod-provenance.ts +82 -0
  587. package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
  588. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
  589. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
  590. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
  591. package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
  592. package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
  593. package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
  594. package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
  595. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  596. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
  597. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +7 -0
  598. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +521 -40
  599. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
  600. package/src/task-orchestrator/surfaces/self-implement-pod.ts +759 -50
  601. package/src/task-orchestrator/surfaces/self-implement.ts +65 -2
  602. package/src/tool-runtime/index.ts +15 -2
  603. package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
  604. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  605. package/src/tty-foreground.ts +155 -0
  606. package/src/tui/README.md +2 -0
  607. package/src/tui/chat/background-job-status.ts +54 -0
  608. package/src/tui/chat/goal-interim.ts +173 -0
  609. package/src/tui/chat/log-view.ts +267 -0
  610. package/src/tui/chat/self-health-status.ts +232 -0
  611. package/src/tui/entry.ts +695 -0
  612. package/src/tui/input/composer.ts +151 -0
  613. package/src/tui/seat-mail-boot.ts +59 -0
  614. package/src/tui/slash/compact-command.ts +7 -0
  615. package/src/tui/slash/compact.ts +94 -0
  616. package/src/tui/slash/new-session.ts +35 -0
  617. package/src/tui/slash/resume.ts +75 -0
  618. package/src/tui-client/local-chat-turn.ts +282 -0
  619. package/src/tui-client/local-harness-command.ts +63 -0
  620. package/src/tui-client/local-provider-command.ts +184 -0
  621. package/src/tui-client/next-dashboard-runtime.ts +8 -0
  622. package/src/tui-client/next-loop-command.ts +70 -0
  623. package/src/tui-client/next-wakeup.ts +191 -0
  624. package/src/tui.ts +37 -0
  625. package/src/ui/modal-adapter.ts +2 -2
  626. package/src/user-config.ts +4 -2
  627. package/src/ux-sim/classic-tui-seat-scenarios.ts +516 -0
  628. package/src/ux-sim/cli-config-audit-device.ts +121 -0
  629. package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
  630. package/src/ux-sim/event-monkey.ts +379 -0
  631. package/src/ux-sim/fake-bin.ts +87 -7
  632. package/src/ux-sim/fake-herdr.ts +238 -0
  633. package/src/ux-sim/fake-llm.ts +111 -6
  634. package/src/ux-sim/fault-glm-no-credential.ts +116 -0
  635. package/src/ux-sim/fault-nextmove-dispatch.ts +367 -0
  636. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  637. package/src/ux-sim/fault-scope-escape-lift.ts +216 -0
  638. package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
  639. package/src/ux-sim/goal-device.ts +619 -0
  640. package/src/ux-sim/in-process-cli.ts +22 -5
  641. package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
  642. package/src/ux-sim/mock-authoring-first-run.ts +97 -0
  643. package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
  644. package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
  645. package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
  646. package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
  647. package/src/ux-sim/next-tui-seat-scenarios.ts +631 -0
  648. package/src/ux-sim/onboarding-first-run-device.ts +269 -0
  649. package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
  650. package/src/ux-sim/subagent-tools-device.ts +81 -0
  651. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
  652. package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
  653. package/src/version/packed-revision.json +1 -1
  654. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
  655. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
  658. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
  660. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
  662. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
  663. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/2987-30cf9c2eb7b8bdd5.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
  681. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
  682. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
  683. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
  684. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
  685. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
  688. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
  695. package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
  696. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
  708. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
  711. package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +0 -287
  717. package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
  722. package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
  725. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
  738. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
  740. package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/term/page-df3445b207ceceab.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
  794. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
  795. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
  796. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
  797. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
  798. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
  799. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
  800. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
  801. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
  802. /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
@@ -0,0 +1,516 @@
1
+ // N03 key-sequence scenarios for the classic TUI (bare `elanous` · dashboard) on the network-free fake LLM.
2
+ // Same contract as next-tui-seat-scenarios.ts: the TUI under test is whatever executable/entry is given
3
+ // (installed `elanous.mjs` or a tree's `bin/elanous.mjs`); this file only seeds the isolated universe
4
+ // through real store APIs, types keys, and reads the universe back through the same binary's `logs` CLI.
5
+ // ⛔ No production logic is reimplemented here — every judged behavior is the real TUI's.
6
+ //
7
+ // classic-400-heal TUI-400-AUTOHEAL-FALLBACK ① — fake LLM script `400,ok`: one 400 (history mismatch) → new session ⊕ summary → answer
8
+ // classic-400-exhausted TUI-400-AUTOHEAL-FALLBACK ③ — script `400,400,400`: the heal fails too, no fallback provider → one reason line · per-turn cap
9
+ // classic-seat-boot TUI-SESSION-BOOT — COORD_ID seat ⊕ seat-state dir ⊕ one unread mail → first-screen line ⊕ card-injected on the first turn
10
+ // ⊕ TUI-SEAT-MEMORY-RECALL: a hand handoff (HANDOFF-now.md) → one `memory-recall` hit (source · chars ≤ cap)
11
+ // classic-typing-lag TUI-TYPING-LAG-REST — keys typed right after Enter in a git repo cwd → echo complete ⊕ `tui.input-lag` turn-start/keystroke rows
12
+ // classic-paste TUI-PASTE-ECHO — short bracketed paste shows as typed · 50-line paste shows one placeholder ·
13
+ // the model receives the whole original text (fake LLM request capture)
14
+ // classic-goal-continue TURN-END-BEFORE-GOAL — every reply only promises («…진행하겠습니다.») → one goal-continue
15
+ // internal turn on its own · the identical second reply stops it (same-reply · no loop)
16
+ // classic-orphan-autostop TUI-ORPHAN-AUTO-RESUME-STOP — autowake seat (COORD_ID ⊕ seat-state/autowake ⊕ unread mail) ⊕ fake
17
+ // Codex orphan 400 every call → human turn fails · autowake turn fails the same call_id → one
18
+ // `tui.autowake terminal` · no autowake turn after it (a fresh mail too) · a human turn still answers
19
+ // classic-goal-interim TUI-GOAL-INTERIM-QUIET — every step ends with «아직 못 했다» (different per turn) → goal-continue
20
+ // runs to its cap · each continued step folds to one line · the «not done» paragraph shows once ·
21
+ // no internal input drawn with a user header
22
+ // classic-wakeup TUI-WAKEUP-DEFER-NOT-DROP — ScheduleWakeup(60s) ⊕ a human turn busy for ~2.5 min over the due time →
23
+ // NotIdle three times or more (the old code dropped after the second) · skipped 0 · then one internal turn
24
+ import { spawnSync } from 'node:child_process';
25
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
26
+ import { join, resolve } from 'node:path';
27
+ import { openMsgStore } from '../msg/msg-store.js';
28
+ import { SEAT_MEMORY_RECALL_MAX_CHARS, SEAT_MEMORY_RECALL_PREFIX } from '../dashboard/seat-boot-preamble.js';
29
+ import { AUTOHEAL_MAX_ATTEMPTS } from '../self-health/autoheal.js';
30
+ import { mockSeatPtySequence, type SeatPtySequenceEvidence, type SeatPtyStep } from './mock-seat-pty-sequence.js';
31
+ import {
32
+ TEST_FAKE_LLM_CAPTURE_ENV, TEST_FAKE_LLM_DELAY_MS_ENV, TEST_FAKE_LLM_DELAY_WHEN_ENV, TEST_FAKE_LLM_ENV,
33
+ TEST_FAKE_LLM_RESPONSE_ENV, TEST_FAKE_LLM_SCRIPT_ENV, TEST_FAKE_LLM_SCRIPT_SKIP_WHEN_ENV, TEST_FAKE_LLM_TOOL_CALL_ENV,
34
+ } from './fake-llm.js';
35
+ import { pasteFoldToken } from '../chat/paste-fold.js';
36
+ import { bracketedPaste, CLIP_TEXT, GOAL_CONTINUE_PLEDGE_REPLY, GOAL_INTERIM_NOT_DONE_REPLY, GOAL_INTERIM_TOOL_CALL, goalInterimScreenCounts, INTERNAL_TURN_USER_HEADER, clipboardShimPath, PASTE_LONG, PASTE_LONG_TOKEN, PASTE_SHORT, parseData, readLogs } from './next-tui-seat-scenarios.js';
37
+
38
+ export const CLASSIC_TUI_SCENARIOS = ['classic-400-heal', 'classic-400-exhausted', 'classic-seat-boot', 'classic-typing-lag', 'classic-wakeup', 'classic-goal-continue', 'classic-goal-interim', 'classic-paste', 'classic-orphan-autostop'] as const;
39
+ export type ClassicTuiScenario = (typeof CLASSIC_TUI_SCENARIOS)[number];
40
+
41
+ export interface ClassicTuiScenarioSpec {
42
+ scenario: ClassicTuiScenario;
43
+ /** Kept universe: config-dir = state-dir = HOME = cwd = this root. */
44
+ root: string;
45
+ executable: string;
46
+ entry: string;
47
+ expectedBinarySha256?: string;
48
+ }
49
+
50
+ export interface ClassicTuiScenarioResult {
51
+ scenario: ClassicTuiScenario;
52
+ universe: string;
53
+ run: SeatPtySequenceEvidence;
54
+ store: Record<string, unknown>;
55
+ logs: { command: string; rc: number | null; lines: string[]; eventCount: number; limit: number };
56
+ checks: Record<string, boolean>;
57
+ }
58
+
59
+ const REPLY = '[fake-llm] 답했습니다';
60
+ /** Env name the fake provider needs to count as «a provider» in the live TUI (llm.ts · isolated stages only). */
61
+ const FAKE_AS_PROVIDER_ENV = 'ELANOUS_TEST_FAKE_LLM_AS_PROVIDER';
62
+ /** The per-turn autoheal cap (TUI-400-AUTOHEAL-FALLBACK: «턴당 2회 상한») — the production constant, not a copy. */
63
+ const AUTOHEAL_CAP = AUTOHEAL_MAX_ATTEMPTS;
64
+
65
+ type Row = { category?: string; event?: string; data?: string };
66
+
67
+ const classicReady = (s: string) => s.includes('elanous | daemon') && s.includes('실행 ') && s.includes('❯');
68
+ const turnDone = (s: string) => /✔ 완료|✘ 실패/.test(s);
69
+
70
+ type CapturedRequest = { messages: Array<{ role: string; content: string | null }> };
71
+
72
+ /** The fake provider's request capture (`TEST_FAKE_LLM_CAPTURE_ENV`) — one JSONL row per model call, in call order. */
73
+ function readCapturedRequests(path: string): CapturedRequest[] {
74
+ if (!existsSync(path)) return [];
75
+ return readFileSync(path, 'utf8').split('\n').filter(Boolean).flatMap((line) => {
76
+ try { return [JSON.parse(line) as CapturedRequest]; } catch { return []; }
77
+ });
78
+ }
79
+
80
+ function rowsOf(logs: ClassicTuiScenarioResult['logs']): Row[] {
81
+ return logs.lines.map((l) => { try { return JSON.parse(l) as Row; } catch { return {}; } });
82
+ }
83
+
84
+ /** Every model call the TUI made went to the fake provider (and at least one was made). */
85
+ function onlyFake(rows: Row[]): boolean {
86
+ const calls = rows.filter((r) => r.category === 'llm.router' && r.event === 'streamLLMWithTools').map((r) => parseData<{ provider: string }>(r.data).provider);
87
+ return calls.length > 0 && calls.every((p) => p === 'test-fake-llm');
88
+ }
89
+
90
+ export async function runClassicTuiScenario(spec: ClassicTuiScenarioSpec): Promise<ClassicTuiScenarioResult> {
91
+ const root = resolve(spec.root);
92
+ mkdirSync(root, { recursive: true });
93
+ writeFileSync(join(root, 'config.json'), JSON.stringify({ onboarding: { completed: true }, errorReports: { enabled: false } }));
94
+ const env: Record<string, string> = {
95
+ ELANOUS_SESSION_ROOT: join(root, 'sessions'),
96
+ [TEST_FAKE_LLM_ENV]: '1',
97
+ [FAKE_AS_PROVIDER_ENV]: '1',
98
+ [TEST_FAKE_LLM_RESPONSE_ENV]: REPLY,
99
+ };
100
+ const base = {
101
+ executable: spec.executable,
102
+ args: [spec.entry, '--config-dir', '{root}', '--test-state-dir', '{root}'],
103
+ root,
104
+ rows: 30,
105
+ cols: 100,
106
+ ...(spec.expectedBinarySha256 ? { expectedBinarySha256: spec.expectedBinarySha256 } : {}),
107
+ ready: { label: 'boot', until: classicReady, timeoutMs: 90_000 },
108
+ // Ctrl+C tears down slower than the device's default window; `/exit` is the clean path.
109
+ quitKeys: '/exit\r',
110
+ exitTimeoutMs: 20_000,
111
+ };
112
+ const logCategories = 'llm.router,self-health.autoheal,dashboard.seat-boot,tui.input-lag,tui.wakeup,tui.autoturn,tui.paste,tui.goal-continue,tui.proactive,tui.goal-interim,tui.autowake';
113
+ const finish = (run: SeatPtySequenceEvidence, store: Record<string, unknown>, checks: (rows: Row[]) => Record<string, boolean>): ClassicTuiScenarioResult => {
114
+ const logs = readLogs({ root, executable: spec.executable, entry: spec.entry }, logCategories);
115
+ return { scenario: spec.scenario, universe: root, run, store, logs, checks: checks(rowsOf(logs)) };
116
+ };
117
+
118
+ if (spec.scenario === 'classic-400-heal' || spec.scenario === 'classic-400-exhausted') {
119
+ const heal = spec.scenario === 'classic-400-heal';
120
+ // The fake throws the real «No tool call found for function call output» 400 shape per script cell.
121
+ env[TEST_FAKE_LLM_SCRIPT_ENV] = heal ? '400,ok' : '400,400,400';
122
+ const steps: SeatPtyStep[] = [{ label: heal ? 'after 400 turn (healed)' : 'after 400 turn (exhausted)', text: '다시 해줘', until: turnDone }];
123
+ const run = await mockSeatPtySequence({ ...base, env, steps });
124
+ const after = run.frames.at(-1)?.screen ?? '';
125
+ return finish(run, { script: env[TEST_FAKE_LLM_SCRIPT_ENV] }, (rows): Record<string, boolean> => {
126
+ const ah = rows.filter((r) => r.category === 'self-health.autoheal');
127
+ const attempts = ah.filter((r) => r.event === 'attempt').map((r) => parseData<{ step: string; attempt: number; sessionRenewed: boolean }>(r.data));
128
+ const recovered = ah.filter((r) => r.event === 'recovered');
129
+ const exhausted = ah.filter((r) => r.event === 'exhausted').map((r) => parseData<{ attempts: number; reason: string }>(r.data));
130
+ if (heal) {
131
+ return {
132
+ before400Screen: !(run.frames[0]?.screen ?? '').includes('자동 회복'),
133
+ healLineOnScreen: after.includes('자동 회복: 새 세션'),
134
+ answeredAfterHeal: after.includes(REPLY) && after.includes('✔ 완료'),
135
+ attemptNewSession: attempts.length === 1 && attempts[0]?.step === 'new-session',
136
+ recoveredObserved: recovered.length === 1 && parseData<{ step: string }>(recovered[0]?.data).step === 'new-session',
137
+ sessionRenewed: attempts[0]?.sessionRenewed === true,
138
+ onlyFakeProvider: onlyFake(rows),
139
+ exitedClean: run.exitCode === 0,
140
+ };
141
+ }
142
+ return {
143
+ healLineOnScreen: after.includes('자동 회복: 새 세션'),
144
+ stopReasonOnScreen: /자동 회복 \d회 실패/.test(after),
145
+ failedTurnOnScreen: after.includes('✘ 실패') && !after.includes(REPLY),
146
+ exhaustedObserved: exhausted.length === 1,
147
+ // No fallback provider exists on this stage, so the cap stops after exactly one (new-session) attempt —
148
+ // asserted exactly so a regression that loops (or skips ①) is caught, and never above the production cap.
149
+ attemptsWithinCap: attempts.length === 1 && attempts[0]?.step === 'new-session' && Number(exhausted[0]?.attempts) === 1
150
+ && exhausted[0]?.reason === 'no-fallback-provider' && attempts.length <= AUTOHEAL_CAP,
151
+ noRecovered: recovered.length === 0,
152
+ onlyFakeProvider: onlyFake(rows),
153
+ exitedClean: run.exitCode === 0,
154
+ };
155
+ });
156
+ }
157
+
158
+ if (spec.scenario === 'classic-seat-boot') {
159
+ // Seat by COORD_ID (cwd = root has no /seats/<자리>) ⊕ the seat-state dir under the isolated HOME ⊕ one unread mail.
160
+ const seat = 'OP';
161
+ env.COORD_ID = seat;
162
+ const seatDir = join(root, 'elanous-hq', 'seat-state', seat);
163
+ mkdirSync(seatDir, { recursive: true });
164
+ writeFileSync(join(seatDir, 'HANDOFF.md'), '# HANDOFF (n03 classic-seat-boot)\n- 열린 일 하나\n');
165
+ // TUI-SEAT-MEMORY-RECALL — a hand handoff (HANDOFF-*.md) → the card carries one «직전 인계 회상» line.
166
+ const handoffPath = join(seatDir, 'HANDOFF-now.md');
167
+ writeFileSync(handoffPath, '# OP 이어받기 (n03 classic-seat-boot)\n열차 등록 확인부터 잇는다\n');
168
+ const capturePath = join(root, 'fake-llm-requests.jsonl');
169
+ env[TEST_FAKE_LLM_CAPTURE_ENV] = capturePath;
170
+ const msgPath = join(root, 'msg', 'messages.db');
171
+ mkdirSync(join(root, 'msg'), { recursive: true });
172
+ const store = openMsgStore(msgPath);
173
+ try { store.post({ from: 'TF', to: seat, body: 'n03 classic-seat-boot 안 읽은 우편 하나' }); } finally { store.close(); }
174
+ const steps: SeatPtyStep[] = [{ label: 'after first turn', text: '안녕', until: turnDone }];
175
+ const run = await mockSeatPtySequence({ ...base, env, steps });
176
+ const first = run.frames[0]?.screen ?? '';
177
+ const after = run.frames.at(-1)?.screen ?? '';
178
+ // The line the model actually received: the fake provider's request capture of the first turn (the TUI does not print the preamble).
179
+ const firstRequest = readCapturedRequests(capturePath)[0];
180
+ const recallLines = (firstRequest?.messages ?? [])
181
+ .filter((m) => m.role === 'system' && typeof m.content === 'string')
182
+ .flatMap((m) => String(m.content).split('\n'))
183
+ .filter((line) => line.startsWith(SEAT_MEMORY_RECALL_PREFIX));
184
+ const recallLine = recallLines[0] ?? null;
185
+ return finish(run, { seat, seatDir, msgPath, seededUnread: 1, handoffPath, capturePath, recallLine }, (rows) => {
186
+ const sb = rows.filter((r) => r.category === 'dashboard.seat-boot');
187
+ const injected = sb.filter((r) => r.event === 'card-injected').map((r) => parseData<{ seat: string; source: string; unread: number; chars: number }>(r.data));
188
+ const recalls = sb.filter((r) => r.event === 'memory-recall').map((r) => parseData<{ source: string | null; chars: number; hit: boolean }>(r.data));
189
+ return {
190
+ memoryRecallObserved: recalls.length === 1 && recalls[0]?.hit === true && recalls[0]?.source === handoffPath,
191
+ // First-turn system preamble (captured) carries exactly one recall line with the seeded title · first line · path, within the cap.
192
+ memoryRecallInFirstTurnPreamble: recallLines.length === 1 && recallLine !== null
193
+ && recallLine.includes('OP 이어받기 (n03 classic-seat-boot)') && recallLine.includes('열차 등록 확인부터 잇는다') && recallLine.includes(handoffPath),
194
+ memoryRecallWithinCap: recallLine !== null && recallLine.length <= SEAT_MEMORY_RECALL_MAX_CHARS && recallLine.length === Number(recalls[0]?.chars),
195
+ bootLineOnFirstScreen: first.includes(`🪪 ${seat} 자리 · 안 읽은 우편 1`),
196
+ cardInjectedObserved: injected.length >= 1 && injected[0]?.seat === seat && injected[0]?.source === 'coord-id' && Number(injected[0]?.chars) > 0,
197
+ cardUnreadMatchesSeed: injected[0]?.unread === 1,
198
+ // One card per conversation: the first-screen line and every turn share the same snapshot.
199
+ cardOncePerConversation: injected.length === 1,
200
+ firstTurnAnswered: after.includes(REPLY) && after.includes('✔ 완료'),
201
+ onlyFakeProvider: onlyFake(rows),
202
+ exitedClean: run.exitCode === 0,
203
+ };
204
+ });
205
+ }
206
+
207
+ if (spec.scenario === 'classic-orphan-autostop') {
208
+ // Autowake seat: COORD_ID ⊕ seat-state/<자리>/autowake ⊕ one unread mail, so the turn end would wake the seat.
209
+ const seat = 'OPT';
210
+ env.COORD_ID = seat;
211
+ const seatDir = join(root, 'elanous-hq', 'seat-state', seat);
212
+ mkdirSync(seatDir, { recursive: true });
213
+ writeFileSync(join(seatDir, 'autowake'), '');
214
+ const msgPath = join(root, 'msg', 'messages.db');
215
+ mkdirSync(join(root, 'msg'), { recursive: true });
216
+ const post = (body: string) => { const store = openMsgStore(msgPath); try { store.post({ from: 'TF', to: seat, body }); } finally { store.close(); } };
217
+ post('n03 classic-orphan-autostop 안 읽은 우편 하나');
218
+ // Every model call throws the Codex orphan 400 (autoheal's new-session try included) — except a human turn
219
+ // carrying the marker, which answers: the stop must not block a person.
220
+ const humanMarker = '사람 확인';
221
+ env[TEST_FAKE_LLM_SCRIPT_ENV] = Array(40).fill('400codex').join(',');
222
+ env[TEST_FAKE_LLM_SCRIPT_SKIP_WHEN_ENV] = humanMarker;
223
+ const wakeBanner = '↻ 자동 재개(autowake)';
224
+ const stopLine = '⏹ Codex 400 자동 재개 중단';
225
+ let wokeAt = 0;
226
+ let answeredAt = 0;
227
+ let freshPosted = false;
228
+ const wakeCount = (s: string) => s.split(wakeBanner).length - 1;
229
+ const steps: SeatPtyStep[] = [
230
+ { label: 'human turn fails', text: '이어서 해줘', until: turnDone, timeoutMs: 60_000 },
231
+ // Autowake waits out the 30s human-quiet window, opens one turn, it fails with the same call_id → terminal.
232
+ // The step waits for that autowake turn to end (not for the stop line) so a missing stop is a failed check, not a timeout.
233
+ {
234
+ label: 'autowake turn ended',
235
+ until: (s) => {
236
+ const at = s.lastIndexOf(wakeBanner);
237
+ if (at < 0 || !turnDone(s.slice(at))) return false;
238
+ if (wokeAt === 0) wokeAt = Date.now();
239
+ if (Date.now() < wokeAt + 2_000) return false; // let the stop notice land
240
+ if (!freshPosted) { post('n03 classic-orphan-autostop 새 우편'); freshPosted = true; }
241
+ return true;
242
+ },
243
+ timeoutMs: 120_000,
244
+ },
245
+ // A fresh mail changes the order fingerprint, then a human turn ends: without the stop, autowake would open again.
246
+ {
247
+ label: 'human turn answers', text: humanMarker,
248
+ until: (s) => {
249
+ const ok = s.includes(REPLY) && turnDone(s.slice(s.lastIndexOf(humanMarker)));
250
+ if (ok && answeredAt === 0) answeredAt = Date.now();
251
+ return ok;
252
+ },
253
+ timeoutMs: 60_000,
254
+ },
255
+ // Past the 30s human-quiet window — the old behaviour shows a second autowake banner here.
256
+ { label: 'still stopped', until: () => answeredAt > 0 && Date.now() >= answeredAt + 45_000, timeoutMs: 70_000 },
257
+ ];
258
+ const run = await mockSeatPtySequence({ ...base, env, steps });
259
+ const frame = (label: string) => run.frames.find((f) => f.label === label)?.screen ?? '';
260
+ const last = run.frames.at(-1)?.screen ?? '';
261
+ return finish(run, { seat, seatDir, msgPath, script: env[TEST_FAKE_LLM_SCRIPT_ENV], freshPosted }, (rows) => {
262
+ const aw = (event: string) => rows.filter((r) => r.category === 'tui.autowake' && r.event === event).map((r) => parseData<Record<string, unknown>>(r.data));
263
+ const terminal = aw('terminal');
264
+ const opened = aw('decided').filter((d) => d.opened === true);
265
+ const autoturns = rows.filter((r) => r.category === 'tui.autoturn' && r.event === 'opened')
266
+ .map((r) => parseData<{ origin: string }>(r.data)).filter((o) => o.origin === 'autowake');
267
+ return {
268
+ // Precondition: the binary's fake provider knows the `400codex` cell (older builds answer it as `ok`, and
269
+ // then every check below is «not measured», not a product verdict).
270
+ orphan400Injected: rows.some((r) => r.category === 'self-health.autoheal' && r.event === 'attempt'),
271
+ autowakeOpenedOnce: opened.length === 1 && autoturns.length === 1,
272
+ terminalLoggedOnce: terminal.length === 1 && terminal[0]?.callId === 'call_fake_llm' && terminal[0]?.errorKind === 'codex-orphan-tool-output-400',
273
+ stopLineOnScreen: frame('autowake turn ended').includes(stopLine),
274
+ // After the stop: the fresh mail ⊕ a human turn end ⊕ 45s quiet open no second autowake turn; the gate says why.
275
+ noAutowakeAfterTerminal: freshPosted && wakeCount(last) === 1 && aw('terminal-blocked').length >= 1,
276
+ humanInputStillWorks: frame('human turn answers').includes(REPLY),
277
+ onlyFakeProvider: onlyFake(rows),
278
+ exitedClean: run.exitCode === 0,
279
+ };
280
+ });
281
+ }
282
+
283
+ if (spec.scenario === 'classic-paste') {
284
+ // classic numbers pastes per input session (the prompt reopens after each turn), so the clipboard paste is #1 again.
285
+ const CLIP_TOKEN = pasteFoldToken(1, CLIP_TEXT);
286
+ const capturePath = join(root, 'fake-llm-requests.jsonl');
287
+ env[TEST_FAKE_LLM_CAPTURE_ENV] = capturePath;
288
+ const steps: SeatPtyStep[] = [
289
+ { label: 'short pasted', keys: bracketedPaste(PASTE_SHORT), until: (s) => s.includes(`❯ ${PASTE_SHORT}`) },
290
+ { label: 'cleared', keys: '\x15', until: (s) => !s.includes(`❯ ${PASTE_SHORT}`) },
291
+ { label: 'long pasted', keys: bracketedPaste(PASTE_LONG), until: (s) => s.includes(PASTE_LONG_TOKEN) },
292
+ { label: 'submitted', keys: '\r', until: turnDone, timeoutMs: 30_000 },
293
+ { label: 'ctrl+v', keys: '\x16', until: (s) => s.includes(CLIP_TOKEN) },
294
+ { label: 'clip submitted', keys: '\r', until: (s) => readCapturedRequests(capturePath).length >= 2 && turnDone(s.slice(s.lastIndexOf(CLIP_TOKEN) >= 0 ? s.lastIndexOf('clip-line-5') : 0)), timeoutMs: 30_000 },
295
+ ];
296
+ env.PATH = clipboardShimPath(root);
297
+ const run = await mockSeatPtySequence({ ...base, env, steps });
298
+ const screen = (label: string) => run.frames.find((f) => f.label === label)?.screen ?? '';
299
+ const requests = readCapturedRequests(capturePath);
300
+ const userOf = (i: number) => requests[i]?.messages.filter((m) => m.role === 'user').at(-1)?.content ?? '';
301
+ const lastUser = userOf(0);
302
+ const clipUser = userOf(1);
303
+ return finish(run, { capturePath, lastUserChars: String(lastUser).length }, (rows) => {
304
+ const paste = (event: string) => rows.filter((r) => r.category === 'tui.paste' && r.event === event).map((r) => parseData<{ lines: number; chars: number }>(r.data));
305
+ return {
306
+ shortEchoed: screen('short pasted').includes(`❯ ${PASTE_SHORT}`),
307
+ longPlaceholder: screen('long pasted').includes(PASTE_LONG_TOKEN) && !screen('long pasted').includes('paste-line-49'),
308
+ // The model's last user message carries every pasted line (first and last), not the placeholder.
309
+ // Whole text, contiguous: the classic turn prompt prefixes screen context, so «equals» is not the test — the
310
+ // full 699-char paste must appear unbroken (a dropped middle line fails), and no placeholder may leak (r1 must-fix).
311
+ modelGotWhole: String(lastUser).includes(PASTE_LONG) && !String(lastUser).includes('[붙여넣음'),
312
+ ctrlVPlaceholder: screen('ctrl+v').includes(CLIP_TOKEN),
313
+ // Ctrl+V with text (no image) on the clipboard: the model receives the clipboard text (was: «No image», nothing in).
314
+ ctrlVModelGotWhole: String(clipUser).includes(CLIP_TEXT) && !String(clipUser).includes('[붙여넣음'),
315
+ clipboardReadObserved: paste('clipboard-read').length === 1,
316
+ foldedObserved: paste('folded').length === 2 && paste('folded')[0]?.lines === 50 && paste('folded')[0]?.chars === 699,
317
+ expandedObserved: paste('expanded').length === 2,
318
+ onlyFakeProvider: onlyFake(rows),
319
+ exitedClean: run.exitCode === 0,
320
+ };
321
+ });
322
+ }
323
+
324
+ if (spec.scenario === 'classic-goal-continue') {
325
+ const reply = GOAL_CONTINUE_PLEDGE_REPLY;
326
+ env[TEST_FAKE_LLM_RESPONSE_ENV] = reply;
327
+ const banner = '↻ 자동 재개(goal-continue)';
328
+ const replies = (s: string) => s.split(reply).length - 1;
329
+ let settledAt = 0;
330
+ const steps: SeatPtyStep[] = [
331
+ { label: 'human turn', text: '영상 만들어줘', until: (s) => replies(s) >= 1 },
332
+ {
333
+ label: 'continued',
334
+ until: (s) => {
335
+ const ok = s.includes(banner) && replies(s) === 2 && turnDone(s.slice(s.lastIndexOf(banner)));
336
+ if (ok && settledAt === 0) settledAt = Date.now();
337
+ return ok;
338
+ },
339
+ timeoutMs: 60_000,
340
+ },
341
+ { label: 'no loop', until: (s) => settledAt > 0 && Date.now() >= settledAt + 25_000 && replies(s) === 2, timeoutMs: 40_000 },
342
+ ];
343
+ const run = await mockSeatPtySequence({ ...base, env, steps });
344
+ const last = run.frames.at(-1)?.screen ?? '';
345
+ const humanRoot = join(root, 'human-stop-case');
346
+ mkdirSync(humanRoot, { recursive: true });
347
+ writeFileSync(join(humanRoot, 'config.json'), JSON.stringify({ onboarding: { completed: true }, errorReports: { enabled: false } }));
348
+ const humanReply = '로그인이 필요합니다. 로그인해 주세요.';
349
+ const humanRun = await mockSeatPtySequence({
350
+ ...base, root: humanRoot,
351
+ env: { ...env, ELANOUS_SESSION_ROOT: join(humanRoot, 'sessions'), [TEST_FAKE_LLM_RESPONSE_ENV]: humanReply },
352
+ steps: [{ label: 'human-only action stops', text: '계정 상태 확인을 계속해줘', until: (s) => s.includes(humanReply) && turnDone(s), timeoutMs: 60_000 }],
353
+ });
354
+ const humanRows = rowsOf(readLogs({ root: humanRoot, executable: spec.executable, entry: spec.entry }, logCategories));
355
+ const remainingRoot = join(root, 'remaining-work-case');
356
+ mkdirSync(remainingRoot, { recursive: true });
357
+ writeFileSync(join(remainingRoot, 'config.json'), JSON.stringify({ onboarding: { completed: true }, errorReports: { enabled: false } }));
358
+ const remainingReply = '남은 작업: 자막 검증은 아직 완료되지 않았습니다.';
359
+ const remainingRun = await mockSeatPtySequence({
360
+ ...base, root: remainingRoot,
361
+ env: { ...env, ELANOUS_SESSION_ROOT: join(remainingRoot, 'sessions'), [TEST_FAKE_LLM_RESPONSE_ENV]: remainingReply },
362
+ steps: [{ label: 'remaining work continues', text: '요청한 자막 검증을 완료해줘', until: (s) => s.includes('↻ 자동 재개(goal-continue)') && s.split(remainingReply).length - 1 >= 2 && turnDone(s), timeoutMs: 60_000 }],
363
+ });
364
+ const remainingRows = rowsOf(readLogs({ root: remainingRoot, executable: spec.executable, entry: spec.entry }, logCategories));
365
+ return finish(run, { reply }, (rows) => {
366
+ const decided = rows.filter((r) => r.category === 'tui.goal-continue' && r.event === 'decided')
367
+ .map((r) => parseData<{ opened?: boolean; rejected?: boolean; reason: string }>(r.data));
368
+ const opened = rows.filter((r) => r.category === 'tui.autoturn' && r.event === 'opened').map((r) => parseData<{ origin: string }>(r.data));
369
+ const proactive = rows.filter((r) => r.category === 'tui.proactive' && r.event === 'continue').map((r) => parseData<{ reason: string }>(r.data));
370
+ return {
371
+ goalContinueOpenedOnce: decided.filter((d) => d.opened === true).length === 1,
372
+ classicTurnEndReachedProactiveJudge: proactive.some((d) => d.reason === 'pledge-without-result'),
373
+ classicHumanOnlyActionStops: humanRows.some((r) => r.category === 'tui.proactive' && r.event === 'stop-human' && parseData<{ reason: string }>(r.data).reason === 'human-action')
374
+ && !humanRun.frames.at(-1)?.screen.includes('↻ 자동 재개(goal-continue)'),
375
+ classicRemainingWorkContinues: remainingRows.some((r) => r.category === 'tui.proactive' && r.event === 'continue' && parseData<{ reason: string }>(r.data).reason === 'work-remaining')
376
+ && remainingRun.exitCode === 0,
377
+ internalTurnOrigin: opened.length === 1 && opened[0]?.origin === 'goal-continue',
378
+ bannerOnScreen: (run.frames.find((f) => f.label === 'continued')?.screen ?? '').includes(banner),
379
+ sameReplyStopped: decided.some((d) => d.rejected === true && d.reason === 'same-reply'),
380
+ noLoop: replies(last) === 2,
381
+ onlyFakeProvider: onlyFake(rows),
382
+ exitedClean: run.exitCode === 0,
383
+ };
384
+ });
385
+ }
386
+
387
+ if (spec.scenario === 'classic-goal-interim') {
388
+ env[TEST_FAKE_LLM_RESPONSE_ENV] = GOAL_INTERIM_NOT_DONE_REPLY;
389
+ env[TEST_FAKE_LLM_TOOL_CALL_ENV] = GOAL_INTERIM_TOOL_CALL;
390
+ const capLine = '골 이어가기 상한';
391
+ let settledAt = 0;
392
+ const steps: SeatPtyStep[] = [
393
+ { label: 'human turn', text: '영상 만들어줘', until: (s) => goalInterimScreenCounts(s).steps >= 1 },
394
+ {
395
+ // goal-continue stops at its consecutive cap (a «⏸ … 상한» line) after the last internal turn settles.
396
+ label: 'settled',
397
+ until: (s) => {
398
+ const ok = s.includes(capLine) && turnDone(s.slice(s.lastIndexOf('↻ 자동 재개')));
399
+ if (ok && settledAt === 0) settledAt = Date.now();
400
+ return ok;
401
+ },
402
+ timeoutMs: 90_000,
403
+ },
404
+ { label: 'quiet', until: () => settledAt > 0 && Date.now() >= settledAt + 12_000, timeoutMs: 30_000 },
405
+ ];
406
+ const run = await mockSeatPtySequence({ ...base, rows: 50, env, steps });
407
+ const last = goalInterimScreenCounts(run.frames.at(-1)?.screen ?? '');
408
+ return finish(run, { reply: GOAL_INTERIM_NOT_DONE_REPLY, last }, (rows) => {
409
+ const opened = rows.filter((r) => r.category === 'tui.goal-continue' && r.event === 'decided')
410
+ .map((r) => parseData<{ opened?: boolean }>(r.data)).filter((d) => d.opened === true).length;
411
+ const folded = rows.filter((r) => r.category === 'tui.goal-interim' && r.event === 'folded').length;
412
+ return {
413
+ continuedSeveral: opened >= 2,
414
+ everyStepOnScreen: last.steps === opened + 1,
415
+ notDoneAtMostOnce: last.notDone <= 1,
416
+ finalReportShown: last.notDone === 1,
417
+ foldedEachContinued: last.folded === opened && folded === opened,
418
+ noUserHeaderForInternal: run.frames.every((f) => !INTERNAL_TURN_USER_HEADER.test(f.screen)),
419
+ // The first turn's tool line survives the fold of that turn's reply (only the reply block folds).
420
+ toolLineKept: (run.frames.at(-1)?.screen ?? '').includes('ScheduleWakeup'),
421
+ onlyFakeProvider: onlyFake(rows),
422
+ exitedClean: run.exitCode === 0,
423
+ };
424
+ });
425
+ }
426
+
427
+ if (spec.scenario === 'classic-wakeup') {
428
+ // The first turn calls ScheduleWakeup(60s). 45s later a human turn starts that the fake keeps busy for 150s,
429
+ // so the due time and two more minute-retries all land inside it. Before the fix the scheduler dropped the
430
+ // wakeup after one retry (`skipped` ⊕ «놓침» line); now it keeps deferring and opens one turn once idle.
431
+ const banner = '↻ 자동 재개(scheduled): 점검';
432
+ env[TEST_FAKE_LLM_TOOL_CALL_ENV] = JSON.stringify({ when: '예약해줘', name: 'ScheduleWakeup', args: { delaySeconds: 60, reason: '점검' } });
433
+ env[TEST_FAKE_LLM_DELAY_MS_ENV] = '150000';
434
+ env[TEST_FAKE_LLM_DELAY_WHEN_ENV] = '긴 작업';
435
+ let scheduledAt = 0;
436
+ const steps: SeatPtyStep[] = [
437
+ {
438
+ label: 'scheduled', text: '60초 뒤 예약해줘',
439
+ until: (s) => {
440
+ const ok = s.includes('⏰ 예약 깨움') && turnDone(s);
441
+ if (ok && scheduledAt === 0) scheduledAt = Date.now();
442
+ return ok;
443
+ },
444
+ },
445
+ { label: 'before due', until: () => scheduledAt > 0 && Date.now() >= scheduledAt + 45_000, timeoutMs: 60_000 },
446
+ { label: 'busy over the due time', text: '긴 작업 하나', until: (s) => s.includes('긴 작업 하나') },
447
+ { label: 'woke', until: (s) => s.includes(banner) && turnDone(s.slice(s.lastIndexOf(banner))), timeoutMs: 600_000 },
448
+ // ↑ the classic turn prompt carries recent screen output, which still holds «긴 작업», so the fake delays the
449
+ // wake turn too (~150s) — the window covers busy remainder ⊕ minute retry ⊕ that second delay.
450
+ ];
451
+ const run = await mockSeatPtySequence({ ...base, env, steps });
452
+ const screens = run.frames.map((f) => f.screen).join('\n');
453
+ const after = run.frames.at(-1)?.screen ?? '';
454
+ return finish(run, { delaySeconds: 60, busyMs: 150_000 }, (rows) => {
455
+ const wake = (event: string) => rows.filter((r) => r.category === 'tui.wakeup' && r.event === event)
456
+ .map((r) => parseData<{ id: string; reason: string; retried?: boolean }>(r.data));
457
+ const rejected = wake('rejected').filter((r) => r.reason === 'NotIdle' || r.reason === 'HumanTyping');
458
+ const fired = wake('fired');
459
+ const opened = rows.filter((r) => r.category === 'tui.autoturn' && r.event === 'opened').map((r) => parseData<{ origin: string }>(r.data));
460
+ return {
461
+ scheduledOnce: wake('scheduled').length === 1,
462
+ // ≥ 3 busy refusals = due ⊕ two minute-retries — past the point where the old scheduler gave up.
463
+ deferredPastOldDrop: rejected.length >= 3 && rejected.every((r) => r.id === rejected[0]?.id),
464
+ notSkipped: wake('skipped').length === 0,
465
+ firedOnceAfterDefer: fired.length === 1 && fired[0]?.id === rejected[0]?.id && fired[0]?.retried === true,
466
+ internalTurnOpened: opened.length === 1 && opened[0]?.origin === 'scheduled',
467
+ noMissedLine: !screens.includes('예약 깨움 놓침'),
468
+ bannerOnScreen: after.includes(banner),
469
+ onlyFakeProvider: onlyFake(rows),
470
+ exitedClean: run.exitCode === 0,
471
+ };
472
+ });
473
+ }
474
+
475
+ // classic-typing-lag: cwd = a git repo with a few thousand tracked files so the turn-start git snapshot is real work.
476
+ const git = (...args: string[]) => spawnSync('git', ['-C', root, '-c', 'user.name=n03', '-c', 'user.email=n03@example.invalid', ...args], { encoding: 'utf8' });
477
+ if (git('init', '-q').status !== 0) throw new Error('N03 classic-typing-lag: git init failed');
478
+ const files = join(root, 'work');
479
+ mkdirSync(files, { recursive: true });
480
+ for (let i = 0; i < 2000; i++) writeFileSync(join(files, `f${i}.txt`), `${i}\n`);
481
+ writeFileSync(join(root, '.gitignore'), 'logs/\nsessions/\nmsg/\n*.db\n');
482
+ if (git('add', '-A').status !== 0 || git('commit', '-qm', 'seed').status !== 0) throw new Error('N03 classic-typing-lag: seed commit failed');
483
+ const typed = 'abcdefghijklmnopqrstuvwxyz0123';
484
+ const steps: SeatPtyStep[] = [
485
+ // Enter, then the next keys arrive while the turn starts (30ms apart, like a fast typist).
486
+ { label: 'typed while turn starts', chunks: ['타이핑 지연 측정', '\r', ...typed.split('')], gapMs: 30, until: (s) => s.includes(`❯ ${typed}`) && turnDone(s) },
487
+ // Send what was typed so the composer is empty again before `/exit` (otherwise `/exit` would append to it).
488
+ { label: 'typed text sent', keys: '\r', until: (s) => s.split(REPLY).length - 1 === 2 && turnDone(s) },
489
+ ];
490
+ const run = await mockSeatPtySequence({ ...base, env, steps });
491
+ const after = run.frames.find((f) => f.label === 'typed while turn starts')?.screen ?? '';
492
+ const logs = readLogs({ root, executable: spec.executable, entry: spec.entry }, logCategories);
493
+ const rows = rowsOf(logs);
494
+ const lag = rows.filter((r) => r.category === 'tui.input-lag' && r.event === 'measured').map((r) => parseData<{ phase: string; keyToPaintMs?: number; loopDelayMs?: { p99: number; max: number } }>(r.data));
495
+ const turnStart = lag.filter((l) => l.phase === 'turn-start');
496
+ const keys = lag.filter((l) => l.phase === 'keystroke' && typeof l.keyToPaintMs === 'number');
497
+ const store = {
498
+ trackedFiles: 2000,
499
+ typed,
500
+ // Rows without a measured value are left out (never shown as 0ms); none at all → null.
501
+ turnStartLoopDelayMaxMs: ((v) => (v.length ? Math.max(...v) : null))(turnStart.map((l) => l.loopDelayMs?.max).filter((n): n is number => typeof n === 'number')),
502
+ keystrokeRows: keys.length,
503
+ keyToPaintMaxMs: keys.length ? Math.max(...keys.map((l) => Number(l.keyToPaintMs))) : null,
504
+ };
505
+ return {
506
+ scenario: spec.scenario, universe: root, run, store, logs,
507
+ checks: {
508
+ typedEchoedComplete: after.includes(`❯ ${typed}`),
509
+ turnStartMeasured: turnStart.length >= 1,
510
+ keystrokeMeasured: keys.length >= 1,
511
+ turnAnswered: after.includes(REPLY),
512
+ onlyFakeProvider: onlyFake(rows),
513
+ exitedClean: run.exitCode === 0,
514
+ },
515
+ };
516
+ }
@@ -0,0 +1,121 @@
1
+ // ── CFG-STORE2-HISTORY-REVERT · config 감사 이력 장치 (ux-sim L2) ──
2
+ //
3
+ // 실 CLI(`src/index.ts` 의 `config` 명령 트리)를 «같은 격리 config 저장소» 위에서 여러 번 부른다.
4
+ // in-process-cli.ts 의 턴 하나는 자기 temp 뿌리를 만들고 지운다 — set → history → revert 한 바퀴는
5
+ // 같은 저장소·같은 감사 원장이 이어져야 하므로 이 장치는 stateRoot 를 소유하고 재사용한다
6
+ // (InProcessCliOptions.stateRoot · 정리는 dispose 가 한다).
7
+ //
8
+ // ⛔ 경계
9
+ // • 저장소는 이 장치의 temp 뿌리뿐이다 — 실제 ~/.elanous 를 건드리지 않는다(in-process-cli 격리 그대로).
10
+ // • 여기서 값을 «만들지» 않는다 — 값·감사 행은 실 CLI 의 set/unset/history/revert 가 만든 것만 관측한다.
11
+ // • 비밀 원문은 이 장치의 어떤 접근자도 새로 노출하지 않는다: 원장·stdout 을 그대로 돌려줄 뿐이다.
12
+
13
+ import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
14
+ import { tmpdir } from 'node:os';
15
+ import { join } from 'node:path';
16
+ import { readConfigHistory, type ConfigChangeRow } from '../cli/config-audit.js';
17
+ import { simInProcessCli } from './in-process-cli.js';
18
+
19
+ /** 장치가 실 CLI 에 넘긴 인자와 그 턴의 결과. */
20
+ export interface ConfigAuditTurn {
21
+ readonly args: readonly string[];
22
+ readonly exitCode: number;
23
+ readonly stdout: string;
24
+ readonly stderr: string;
25
+ }
26
+
27
+ /** 실 CLI `config` 명령 트리를 격리 HOME 위에서 돌리는 장치. */
28
+ export interface CliConfigAuditDevice {
29
+ /** 격리된 config 뿌리(= config.json 과 config-changes.db 가 사는 자리). */
30
+ readonly stateRoot: string;
31
+ /** 사용자 config 파일 자리. */
32
+ readonly configPath: string;
33
+ /** 감사 원장(config_changes) 파일 자리. */
34
+ readonly ledgerPath: string;
35
+ /** 임의 인자 한 턴 — 허용 목록 밖 명령은 장치가 거부한다. */
36
+ run(...args: string[]): Promise<ConfigAuditTurn>;
37
+ set(path: string, value: unknown): Promise<ConfigAuditTurn>;
38
+ unset(path: string): Promise<ConfigAuditTurn>;
39
+ history(path: string): Promise<ConfigAuditTurn>;
40
+ revert(path: string): Promise<ConfigAuditTurn>;
41
+ /** 그 키의 감사 행(시간 오름차순) — 실 CLI 가 남긴 원장 그대로. */
42
+ ledger(path: string): ConfigChangeRow[];
43
+ /** 저장된 config 에서 그 자리의 값(없으면 undefined). */
44
+ value(path: string): unknown;
45
+ /** 원장 파일 원문(비밀 원문 부재 검사용). */
46
+ ledgerText(): string;
47
+ /** 격리 뿌리 제거. 두 번 불러도 안전. */
48
+ dispose(): void;
49
+ }
50
+
51
+ const ALLOWED_PATHS: readonly (readonly string[])[] = [
52
+ ['config', 'set'],
53
+ ['config', 'unset'],
54
+ ['config', 'get'],
55
+ ['config', 'history'],
56
+ ['config', 'revert'],
57
+ ];
58
+
59
+ /** 점 표기 경로로 값 하나를 꺼낸다. */
60
+ function pick(root: unknown, path: string): unknown {
61
+ let node = root;
62
+ for (const segment of path.split('.').filter(Boolean)) {
63
+ if (node === null || typeof node !== 'object') return undefined;
64
+ node = (node as Record<string, unknown>)[segment];
65
+ }
66
+ return node;
67
+ }
68
+
69
+ /** CLI 인자 형태 — 문자열은 그대로(사용자 config 문법), 그 밖은 JSON. */
70
+ function argValue(value: unknown): string {
71
+ return typeof value === 'string' ? value : JSON.stringify(value);
72
+ }
73
+
74
+ /** 격리 config 저장소 + 감사 원장을 함께 들고 있는 장치를 만든다. */
75
+ export function createCliConfigAuditDevice(): CliConfigAuditDevice {
76
+ const stateRoot = mkdtempSync(join(tmpdir(), 'ux-sim-config-audit-'));
77
+ const configPath = join(stateRoot, 'config.json');
78
+ const ledgerPath = join(stateRoot, 'config-changes.db');
79
+
80
+ const run = async (...args: string[]): Promise<ConfigAuditTurn> => {
81
+ try {
82
+ const result = await simInProcessCli(args, { allowPaths: ALLOWED_PATHS, stateRoot });
83
+ return { args, exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
84
+ } catch (err) {
85
+ // 거부된 명령(허용 목록 밖·미등록 하위 명령)도 «한 턴» 이다 — 던지지 않고 실패 턴으로 돌려준다.
86
+ return { args, exitCode: 1, stdout: '', stderr: err instanceof Error ? err.message : String(err) };
87
+ }
88
+ };
89
+
90
+ const readConfig = (): Record<string, unknown> => {
91
+ try {
92
+ const parsed: unknown = JSON.parse(readFileSync(configPath, 'utf8'));
93
+ return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)
94
+ ? (parsed as Record<string, unknown>)
95
+ : {};
96
+ } catch {
97
+ return {};
98
+ }
99
+ };
100
+
101
+ return {
102
+ stateRoot,
103
+ configPath,
104
+ ledgerPath,
105
+ run,
106
+ set: (path, value) => run('config', 'set', path, argValue(value)),
107
+ unset: (path) => run('config', 'unset', path),
108
+ history: (path) => run('config', 'history', path),
109
+ revert: (path) => run('config', 'revert', path),
110
+ ledger: (path) => readConfigHistory(path, ledgerPath),
111
+ value: (path) => pick(readConfig(), path),
112
+ ledgerText: () => {
113
+ try {
114
+ return readFileSync(ledgerPath, 'utf8');
115
+ } catch {
116
+ return '';
117
+ }
118
+ },
119
+ dispose: () => rmSync(stateRoot, { recursive: true, force: true }),
120
+ };
121
+ }