elanous 0.2.37 → 0.2.38

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 (588) 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/{8kITumG9GAZ1LwT9POrAR → RrjXTwz-urRAbChP1bX02}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{2002-a43a3f380df873ec.js → 1026-44010f405704050c.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +27 -0
  6. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{7424.c0fe2a595d4232b5.js → 1632.7d87f998e714bede.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/{4937-28d437999b77c9dd.js → 1923-5c1695332240246a.js} +1 -1
  13. package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +148 -0
  14. package/apps/pwa/out/_next/static/chunks/2104.70e086d5174a4736.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +93 -0
  18. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +104 -0
  19. package/apps/pwa/out/_next/static/chunks/{3199.6a1a9b0e6cd01dc6.js → 2415.738b777642a02233.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/{1262.a89bb27a5b2f844e.js → 3086.fb14b60ce98b53d3.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/3124-561f7f037943cde2.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +24 -0
  31. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{2283.edd9627b7bdfb546.js → 3291.f6c1005387d514bd.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +36 -0
  34. package/apps/pwa/out/_next/static/chunks/{6877-84d47b7e85d0c41e.js → 3341-f09b9efbd7a82f70.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +287 -0
  38. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/{6680.6a693c28aae4cd19.js → 3528.e4b8ab70d339f965.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +94 -0
  45. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4199-f7c6eb40cd0322f8.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +32 -0
  57. package/apps/pwa/out/_next/static/chunks/{4036.d54e55e1ebf5acdc.js → 4804.6012b5cd33c22792.js} +2 -2
  58. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +79 -0
  60. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +74 -0
  63. package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{6819.be5c9c4d67f22922.js → 5203.51e5d8b5f1dcfe53.js} +16 -16
  65. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/{757-4fbaf50942b8c424.js → 5255-1b60d50eabe9f057.js} +1 -1
  67. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +286 -0
  68. package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{7867.e8725745ddd1d940.js → 5307.d7328020227880c2.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +8 -0
  73. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{5046.7fd5cbd859299448.js → 5638.107314dc479e2f37.js} +1 -1
  75. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6142.913b44e260a3f925.js +64 -0
  80. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6493.27ad77de7aac7966.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/{1224.2ceca6c180d5130b.js → 7000.28157393caaf5343.js} +1 -1
  88. package/apps/pwa/out/_next/static/chunks/{6745-5a63492933959dd9.js → 7161-8f22db3ec5ed005e.js} +3 -3
  89. package/apps/pwa/out/_next/static/chunks/{2479-fe7e188bd9402d14.js → 7311-60a7ea80d23c7521.js} +1 -1
  90. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{5952.294fc574a8625184.js → 7488.966b116789f3d41a.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/7524.ce973525d30b3d52.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +77 -0
  95. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{6252.240578f10952e091.js → 7628.6b16863ac3972333.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{1746.3563617ea64023a3.js → 7954.4f7a8832663ee979.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{4931.95cc6dbd230774ca.js → 8019.21ca554a821dad01.js} +16 -16
  102. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{2375.bf364c85dbb6f085.js → 8487.291666583bebe640.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{4383.18e5c54db3a22c88.js → 8879.ac06755bcf3e44a1.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +149 -0
  111. package/apps/pwa/out/_next/static/chunks/{9151.a2c51e93f9156dae.js → 8911.bf5e712acb25fb6c.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/{58edce7d.f1b0c72acf13b123.js → 8994d93e.33ba491f95345fc2.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/{5f6af561-f90b7a67f4f75d13.js → 89d6c04f-6b8ab341748e468a.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +41 -0
  115. package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +226 -0
  116. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +24 -0
  117. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +2 -0
  121. package/apps/pwa/out/_next/static/chunks/{de8446d3.31b73eb239fecd7b.js → 9fe1b809.738da85c8b17e3fb.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-866aac5ff226a7f3.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/{page-5c112c6d7c33656e.js → page-c348a3959c5b5fc6.js} +1 -1
  140. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-88a1edbff62eaf1d.js → page-d1d1210f99f620ae.js} +1 -1
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/{page-b9af2ac1c4737ce8.js → page-7f569e533ddeecba.js} +1 -1
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/{page-fb9e639c107f5f72.js → page-a9d9a3e66459c1e0.js} +1 -1
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{709a918c.4fd3b4e2a32cb4e3.js → b7459770.6539b11860eb8a9c.js} +7 -7
  174. package/apps/pwa/out/_next/static/chunks/{d9815f84.4918f682a45a8502.js → b7478fef.5917716286213fcc.js} +3 -3
  175. package/apps/pwa/out/_next/static/chunks/{4337e36d.f42c3b391b3d8f20.js → bb6987f9.3647e1a23b0e3217.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/de8b930d.d94c0f42acf807fc.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{8c58d09b.e8724a299658d86f.js → eaad0cba.771200940c529df7.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +1 -0
  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/graphs/release/recipes.yaml +9 -0
  278. package/graphs/release/release-loop.yaml +26 -18
  279. package/package.json +1 -1
  280. package/scripts/ask-op-inbox-once.ts +17 -0
  281. package/scripts/brand/check.ts +13 -4
  282. package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
  283. package/scripts/gate-0226-failure-census.ts +39 -0
  284. package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
  285. package/scripts/provision-export-redactions.ts +15 -0
  286. package/scripts/public-copy-lint.ts +122 -0
  287. package/scripts/public-export.ts +69 -2
  288. package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
  289. package/scripts/ratchets/train-side-invariants.sh +7 -1
  290. package/scripts/release-loop/cut-branch.ts +61 -12
  291. package/scripts/release-loop/gate-node.ts +161 -25
  292. package/scripts/release-loop/gate-partial.ts +82 -3
  293. package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
  294. package/scripts/release-loop/gate-radius-live.ts +4 -2
  295. package/scripts/release-loop/resume-cap.ts +2 -1
  296. package/scripts/release-loop/resume-release.ts +297 -8
  297. package/scripts/release-loop/resume.ts +13 -5
  298. package/scripts/release-loop/traffic-node.ts +12 -4
  299. package/scripts/release-loop/traffic-transition.ts +53 -13
  300. package/scripts/release-loop/version-node.ts +29 -4
  301. package/scripts/ux-sim.ts +1 -1
  302. package/scripts/video-pipeline.ts +2 -2
  303. package/src/acp/core-turn-bridge.ts +6 -1
  304. package/src/agent/run-context.ts +1 -1
  305. package/src/agent/task-notification.ts +3 -1
  306. package/src/agent-substrate/review-observation.ts +10 -0
  307. package/src/agent-substrate/self-review-cli.ts +195 -27
  308. package/src/auto-research/question-ladder-contract.ts +137 -0
  309. package/src/auto-research/research-turn.ts +134 -0
  310. package/src/autopilot/discovery/doc-lint.ts +1 -1
  311. package/src/bots/screen-probe.ts +1 -1
  312. package/src/capture/tui-self-report.ts +10 -2
  313. package/src/chat/index.ts +1 -0
  314. package/src/chat/tool-render/dispatch.ts +8 -1
  315. package/src/cli/guardian-cli.ts +3 -1
  316. package/src/cli/intake-cli.ts +48 -12
  317. package/src/cli/lesson-cli.ts +69 -9
  318. package/src/cli/pr-land-overlap-evidence.ts +38 -5
  319. package/src/cli/pr-land-refusal.ts +1 -1
  320. package/src/cli/pty-takeover-cli.ts +58 -5
  321. package/src/cli/release-checklist-read-cli.ts +5 -2
  322. package/src/cli/release-cli.ts +47 -9
  323. package/src/cli/review-carry.ts +77 -0
  324. package/src/cli/self-update.ts +1 -1
  325. package/src/cli/tasks-card-show.ts +31 -1
  326. package/src/cli/tasks-cli.ts +62 -23
  327. package/src/cli/tasks-read-cli.ts +13 -5
  328. package/src/context-bus/context-now.ts +86 -2
  329. package/src/core-turn/run-core-turn.ts +9 -2
  330. package/src/core-turn/types.ts +3 -0
  331. package/src/dashboard/index.ts +18 -17
  332. package/src/dashboard/input/terminal-modal-router.ts +8 -159
  333. package/src/dashboard/side-basic-runtime.ts +61 -0
  334. package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -0
  335. package/src/dashboard/term-slash-runtime.ts +2 -0
  336. package/src/dashboard/turn-preamble.ts +28 -4
  337. package/src/domains/guardian-tick.ts +9 -0
  338. package/src/git-fs/watcher.ts +27 -22
  339. package/src/git-fs/worktree.ts +19 -3
  340. package/src/graph-runner/graph-grow.ts +37 -9
  341. package/src/graph-runner/runner.ts +17 -2
  342. package/src/grok/credential.ts +107 -36
  343. package/src/hq/fence-wrapper.ts +1 -1
  344. package/src/hq/transfer.ts +1 -1
  345. package/src/index.ts +44 -14
  346. package/src/intake-plane/collect-telegram-saved.ts +54 -5
  347. package/src/interactive-terminal-modal.ts +3 -0
  348. package/src/keybindings.ts +17 -22
  349. package/src/llm/provider-credentials.ts +1 -1
  350. package/src/llm-tool-schema.ts +20 -0
  351. package/src/llm.ts +81 -11
  352. package/src/loops/orchestrator/inbox-once.ts +28 -0
  353. package/src/loops/orchestrator/inbox.ts +130 -1
  354. package/src/loops/orchestrator/tick.ts +6 -3
  355. package/src/maturity/feature-maturity.ts +1 -0
  356. package/src/nexus/api/channel-ask-op.ts +96 -0
  357. package/src/nexus/api/discord-trigger-bot.ts +28 -1
  358. package/src/nexus/api/telegram-trigger-bot.ts +24 -0
  359. package/src/nexus/api/terminals.ts +28 -6
  360. package/src/patents/ledger.ts +18 -1
  361. package/src/preview/terminal.ts +4 -2
  362. package/src/prompt-cache/anthropic.ts +2 -0
  363. package/src/prompt-enhance/enhance.ts +5 -0
  364. package/src/pty-shell/pty-manifest.ts +16 -2
  365. package/src/release-loop/gate-shards.ts +61 -0
  366. package/src/release-loop/light-rc.ts +7 -4
  367. package/src/release-loop/rehearsal.ts +1 -1
  368. package/src/repl/index.ts +10 -0
  369. package/src/research/axis-fanout.ts +133 -0
  370. package/src/research/edge-decision.ts +88 -0
  371. package/src/research/output-router.ts +127 -0
  372. package/src/research-bridge/format.ts +16 -1
  373. package/src/research-bridge/index.ts +1 -0
  374. package/src/research-bridge/invoke.ts +41 -5
  375. package/src/self-dev/decompose.ts +45 -9
  376. package/src/self-dev/draft-residue.ts +221 -2
  377. package/src/self-dev/draft-sweep.ts +29 -16
  378. package/src/self-dev/orchestrate.ts +1 -0
  379. package/src/self-dev/run-supervisor.ts +22 -7
  380. package/src/self-dev/shard-run.ts +260 -3
  381. package/src/self-implement/comment-only-source.ts +54 -0
  382. package/src/self-implement/doctor-visit.ts +25 -0
  383. package/src/self-implement/gate-artifacts.ts +2 -2
  384. package/src/self-implement/gate-baseline.ts +44 -9
  385. package/src/self-implement/gate-cli.ts +151 -86
  386. package/src/self-implement/gate-failure-signature.ts +44 -0
  387. package/src/self-implement/gate-remote.ts +2 -0
  388. package/src/self-implement/goal-author.ts +74 -3
  389. package/src/self-implement/goal-doc/section.ts +22 -0
  390. package/src/self-implement/goal-supervisor-fill.ts +38 -4
  391. package/src/self-implement/knowhow-pack.ts +120 -7
  392. package/src/self-implement/l8-merge-queue.ts +198 -32
  393. package/src/self-implement/off-diff-evidence.ts +23 -0
  394. package/src/self-implement/orchestrator.ts +55 -12
  395. package/src/self-implement/pod-inplace-worktree.ts +82 -0
  396. package/src/self-implement/pod-warm-pool-profile.ts +2 -2
  397. package/src/self-implement/premise-review.ts +7 -5
  398. package/src/self-implement/run-ledger.ts +258 -0
  399. package/src/self-implement/seams.ts +33 -10
  400. package/src/self-implement/self-implement-cli.ts +26 -2
  401. package/src/session/channel-ask-op-envelope.ts +36 -0
  402. package/src/session/channel-op-reply-route.ts +200 -0
  403. package/src/session/chat.ts +3 -0
  404. package/src/session/index.ts +2 -0
  405. package/src/session-runtime/index.ts +9 -22
  406. package/src/skills/runner.ts +7 -3
  407. package/src/skills/tools/dev-harness.ts +2 -2
  408. package/src/skills/tools/schedule-wakeup.ts +1 -6
  409. package/src/status/bar.ts +3 -3
  410. package/src/storage/file-lock.ts +17 -4
  411. package/src/task-agent/adopt-pr.ts +63 -2
  412. package/src/task-agent/evidence-command-normalize.ts +42 -0
  413. package/src/task-agent/export-redactions-provision.ts +43 -0
  414. package/src/task-agent/parent-host.ts +59 -12
  415. package/src/task-agent/repair-cycle.ts +67 -8
  416. package/src/task-agent/repair-worker.ts +37 -1
  417. package/src/task-agent/task-hand.ts +98 -10
  418. package/src/task-agent/tier-split.ts +37 -3
  419. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +31 -4
  420. package/src/task-orchestrator/surfaces/pod-pool.ts +27 -4
  421. package/src/task-orchestrator/surfaces/self-implement-pod.ts +126 -48
  422. package/src/task-orchestrator/surfaces/self-implement.ts +33 -2
  423. package/src/terminal/session-registry.ts +1 -0
  424. package/src/terminal/terminal-modal-router.ts +156 -0
  425. package/src/tool-hints/gate.ts +6 -4
  426. package/src/tool-hints/signals.ts +33 -1
  427. package/src/tui/chat/background-job-status.ts +8 -2
  428. package/src/tui/entry.ts +469 -31
  429. package/src/tui/sidetab/attach.ts +304 -0
  430. package/src/tui/sidetab/list.ts +176 -0
  431. package/src/tui/sidetab/nl-tool.ts +136 -0
  432. package/src/tui/slash/resume-command.ts +23 -0
  433. package/src/tui/slash/resume.ts +3 -23
  434. package/src/tui/slash/term-next.ts +2 -1
  435. package/src/tui-client/local-chat-turn.ts +29 -8
  436. package/src/user-config.ts +11 -2
  437. package/src/ux-sim/fake-llm.ts +11 -5
  438. package/src/ux-sim/next-tui-seat-scenarios.ts +53 -1
  439. package/src/version/packed-revision.json +1 -1
  440. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +0 -32
  451. package/apps/pwa/out/_next/static/chunks/2318-450e75d07605b8fe.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +0 -148
  454. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +0 -27
  458. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/3578.4e9f9948a9a6f2f4.js +0 -2
  463. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +0 -36
  465. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +0 -226
  467. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +0 -287
  468. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/4313.76f232c304a15bde.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/4725-34bed25720cc326b.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +0 -24
  477. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +0 -104
  479. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +0 -93
  486. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +0 -74
  487. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +0 -149
  490. package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +0 -41
  493. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +0 -24
  496. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/7c5ed21f-f286708e57cf88f7.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +0 -8
  508. package/apps/pwa/out/_next/static/chunks/8080-40d781e7704d3671.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +0 -77
  510. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +0 -286
  513. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +0 -79
  517. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +0 -94
  525. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +0 -64
  527. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/live/page-3337c6a1328c2674.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/morning/page-1e5da297557d2354.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/term/page-ac2c1e6169cfce57.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +0 -1
  586. package/scripts/migrate-monad-to-elanous.ts +0 -195
  587. package/scripts/rebrand-elanous.ts +0 -242
  588. /package/apps/pwa/out/_next/static/{8kITumG9GAZ1LwT9POrAR → RrjXTwz-urRAbChP1bX02}/_ssgManifest.js +0 -0
@@ -26,7 +26,7 @@
26
26
  // 「Using auth.json for API Access」 절이 유일한 문서다. ⇒ 조용히 깨질 수 있으니
27
27
  // 호출자는 실패를 fail-soft 로 접고 API 키 경로로 떨어질 수 있어야 한다.
28
28
 
29
- import { chmodSync, existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
29
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
30
30
  import { homedir } from 'node:os';
31
31
  import { join } from 'node:path';
32
32
 
@@ -98,6 +98,7 @@ export interface GrokCredential {
98
98
  interface GrokAuthScope {
99
99
  key?: unknown;
100
100
  expires_at?: unknown;
101
+ refresh_token?: unknown;
101
102
  user_id?: unknown;
102
103
  }
103
104
 
@@ -112,7 +113,7 @@ export function grokAuthFilePath(home: string = homedir()): string {
112
113
  * 키가 다르다(실측: 이 기계는 `https://auth.x.ai::<uuid>`). 그래서 «훑는다». */
113
114
  function readSubscriptionToken(
114
115
  path: string,
115
- ): { token: string; expiresAt: string | null; userId: string | null } | null {
116
+ ): { token: string; expiresAt: string | null; userId: string | null; scopeName: string } | null {
116
117
  if (!existsSync(path)) return null;
117
118
  let parsed: unknown;
118
119
  try {
@@ -120,9 +121,15 @@ function readSubscriptionToken(
120
121
  } catch {
121
122
  return null;
122
123
  }
124
+ return selectSubscriptionToken(parsed);
125
+ }
126
+
127
+ function selectSubscriptionToken(
128
+ parsed: unknown,
129
+ ): { token: string; expiresAt: string | null; userId: string | null; scopeName: string } | null {
123
130
  if (!parsed || typeof parsed !== 'object') return null;
124
131
 
125
- type SubscriptionToken = { token: string; expiresAt: string | null; userId: string | null; ms: number };
132
+ type SubscriptionToken = { token: string; expiresAt: string | null; userId: string | null; scopeName: string; ms: number };
126
133
  let best: SubscriptionToken | null = null;
127
134
  let hqMirror: SubscriptionToken | null = null;
128
135
  for (const [scopeName, scope] of Object.entries(parsed as Record<string, unknown>)) {
@@ -135,13 +142,14 @@ function readSubscriptionToken(
135
142
  token: s.key,
136
143
  expiresAt,
137
144
  userId: typeof s.user_id === 'string' ? s.user_id : null,
145
+ scopeName,
138
146
  ms: Number.isNaN(ms) ? Number.NEGATIVE_INFINITY : ms,
139
147
  };
140
148
  if (scopeName === 'https://auth.x.ai::hq-mirror') hqMirror = cand;
141
149
  if (best === null || cand.ms > best.ms) best = cand;
142
150
  }
143
- const selected = hqMirror ?? best;
144
- return selected ? { token: selected.token, expiresAt: selected.expiresAt, userId: selected.userId } : null;
151
+ const selected = hqMirror && (best === null || hqMirror.ms >= best.ms) ? hqMirror : best;
152
+ return selected ? { token: selected.token, expiresAt: selected.expiresAt, userId: selected.userId, scopeName: selected.scopeName } : null;
145
153
  }
146
154
 
147
155
  /** 호스트 발급 문이 응답에 실을 access. user id 는 반환하지 않는다. */
@@ -158,6 +166,14 @@ export function readGrokSubscriptionExpiry(home?: string): string | null {
158
166
  return readSubscriptionToken(grokAuthFilePath(home))?.expiresAt ?? null;
159
167
  }
160
168
 
169
+ /** Read the current selected scope for a host-side launch snapshot. */
170
+ export function readSelectedGrokScope(home?: string): { scopeName: string; key: string; expiresAt: string | null; userId: string | null; hasRefreshToken: boolean } | null {
171
+ const selected = readSelectedScope(grokAuthFilePath(home));
172
+ if (!selected) return null;
173
+ return { scopeName: selected.scopeName, key: selected.token, expiresAt: selected.expiresAt,
174
+ userId: selected.userId, hasRefreshToken: Boolean(selected.refreshToken) };
175
+ }
176
+
161
177
  /** 프록시 필수 헤더. ⛔ `x-grok-client-version` 을 빼면 426 이다(실측). */
162
178
  export function grokSubscriptionHeaders(opts: {
163
179
  model?: string;
@@ -366,23 +382,58 @@ export function resolveGrokCredential(opts: ResolveGrokCredentialOpts = {}): Gro
366
382
 
367
383
  /** 갱신 유도 결과. ⛔ 「갱신됐다」와 «안 됐다»와 «못 했다»를 다른 값으로. */
368
384
  export type GrokRefreshOutcome = 'refreshed' | 'unchanged' | 'failed' | 'no-credential';
385
+ const grokSubscriptionRefreshesInProgress = new Set<string>();
369
386
 
370
387
  /** 토큰의 만료 시각만 뽑는다(비교용). ⛔ 토큰 값은 안 낸다. */
371
- function readExpiresAt(path: string): string | null {
372
- if (!existsSync(path)) return null;
388
+ function readSelectedScope(path: string): { token: string; expiresAt: string | null; refreshToken: string | null; scopeName: string; userId: string | null } | null {
373
389
  try {
374
- const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
375
- if (!parsed || typeof parsed !== 'object') return null;
376
- let latest: string | null = null;
377
- for (const scope of Object.values(parsed as Record<string, unknown>)) {
378
- if (!scope || typeof scope !== 'object') continue;
379
- const raw = (scope as GrokAuthScope).expires_at;
380
- if (typeof raw === 'string' && (latest === null || raw > latest)) latest = raw;
390
+ const parsed = JSON.parse(readFileSync(path, 'utf-8')) as Record<string, unknown>;
391
+ const selected = selectSubscriptionToken(parsed);
392
+ if (!selected) return null;
393
+ const scope = parsed[selected.scopeName];
394
+ if (!scope || typeof scope !== 'object' || Array.isArray(scope)) return null;
395
+ const value = scope as GrokAuthScope;
396
+ if (value.key !== selected.token) return null;
397
+ return {
398
+ token: selected.token,
399
+ expiresAt: selected.expiresAt,
400
+ refreshToken: typeof value.refresh_token === 'string' && value.refresh_token.trim() ? value.refresh_token : null,
401
+ scopeName: selected.scopeName,
402
+ userId: selected.userId,
403
+ };
404
+ } catch { return null; }
405
+ }
406
+
407
+ function acquireGrokRefreshFileLock(path: string, timeoutMs: number): (() => void) | null {
408
+ const lock = `${path}.refresh-lock`;
409
+ const deadline = Date.now() + timeoutMs;
410
+ mkdirSync(join(path, '..'), { recursive: true });
411
+ while (Date.now() <= deadline) {
412
+ try {
413
+ mkdirSync(lock, { mode: 0o700 });
414
+ writeFileSync(join(lock, 'owner'), `${process.pid} ${Date.now()}`, { mode: 0o600, flag: 'wx' });
415
+ return () => { try { rmSync(lock, { recursive: true, force: true }); } catch { /* best effort */ } };
416
+ } catch {
417
+ try {
418
+ const owner = readFileSync(join(lock, 'owner'), 'utf8').trim().split(/\s+/);
419
+ const pid = Number(owner[0]);
420
+ const started = Number(owner[1]);
421
+ let alive = false;
422
+ if (Number.isSafeInteger(pid) && pid > 0) {
423
+ try { process.kill(pid, 0); alive = true; } catch (error) { alive = (error as NodeJS.ErrnoException).code === 'EPERM'; }
424
+ }
425
+ // The holder may outlive this waiter's timeout; only a dead PID is stale.
426
+ if (!alive && Number.isFinite(started) && Date.now() - started > 30_000) rmSync(lock, { recursive: true, force: true });
427
+ } catch {
428
+ // A crash between mkdir and writing owner leaves no PID to inspect.
429
+ // Give a live creator time to finish, then recover the orphan directory.
430
+ try { if (Date.now() - statSync(lock).mtimeMs > 30_000) rmSync(lock, { recursive: true, force: true }); }
431
+ catch { /* another process may be creating or removing the lock */ }
432
+ }
433
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
381
434
  }
382
- return latest;
383
- } catch {
384
- return null;
385
435
  }
436
+ return null;
386
437
  }
387
438
 
388
439
  /**
@@ -412,30 +463,51 @@ export function refreshGrokSubscriptionToken(
412
463
  timeoutMs?: number;
413
464
  /** ⛔ 테스트 심 — 실 바이너리 없이 계약을 문다. */
414
465
  execImpl?: (cmd: string, args: string[], timeoutMs: number) => void;
466
+ /** Require a non-empty refresh token on the selected access scope before launching the CLI. */
467
+ requireRefreshToken?: boolean;
468
+ requiredValidityMs?: number;
469
+ nowMs?: number;
415
470
  } = {},
416
471
  ): GrokRefreshOutcome {
417
472
  const path = grokAuthFilePath(opts.home);
418
- const before = readExpiresAt(path);
419
- if (before === null && !existsSync(path)) return 'no-credential';
420
-
473
+ const selected = readSelectedScope(path);
474
+ if (!selected) return 'no-credential';
475
+ if (opts.requireRefreshToken && !selected.refreshToken) return 'no-credential';
476
+ // A nested refresh for the same auth file observes the outer call's result later.
477
+ if (grokSubscriptionRefreshesInProgress.has(path)) return 'unchanged';
478
+ grokSubscriptionRefreshesInProgress.add(path);
479
+ const releaseLock = acquireGrokRefreshFileLock(path, opts.timeoutMs ?? 20_000);
480
+ if (!releaseLock) { grokSubscriptionRefreshesInProgress.delete(path); return 'failed'; }
421
481
  try {
482
+ const current = readSelectedScope(path);
483
+ if (!current || current.scopeName !== selected.scopeName) return 'no-credential';
484
+ if (opts.requireRefreshToken && !current.refreshToken) return 'no-credential';
485
+ // Only the Pod preflight supplies a validity target. An explicit refresh call still invokes the CLI.
486
+ const expiresMs = current.expiresAt ? Date.parse(current.expiresAt) : NaN;
487
+ if (opts.requiredValidityMs !== undefined && Number.isFinite(expiresMs)
488
+ && expiresMs - (opts.nowMs ?? Date.now()) >= opts.requiredValidityMs) return 'unchanged';
422
489
  const timeoutMs = opts.timeoutMs ?? 20_000;
423
- if (opts.execImpl) {
424
- opts.execImpl(opts.grokPath ?? 'grok', ['models'], timeoutMs);
425
- } else {
426
- const { execFileSync } = require('node:child_process') as typeof import('node:child_process');
427
- execFileSync(opts.grokPath ?? 'grok', ['models'], {
428
- timeout: timeoutMs,
429
- stdio: ['ignore', 'ignore', 'ignore'],
430
- });
431
- }
432
- } catch {
433
- return 'failed';
490
+ try {
491
+ if (opts.execImpl) {
492
+ opts.execImpl(opts.grokPath ?? 'grok', ['models'], timeoutMs);
493
+ } else {
494
+ const { execFileSync } = require('node:child_process') as typeof import('node:child_process');
495
+ execFileSync(opts.grokPath ?? 'grok', ['models'], {
496
+ timeout: timeoutMs,
497
+ stdio: ['ignore', 'ignore', 'ignore'],
498
+ });
499
+ }
500
+ } catch { return 'failed'; }
501
+ const after = readSelectedScope(path);
502
+ if (!after) return 'no-credential';
503
+ const afterMs = after?.expiresAt ? Date.parse(after.expiresAt) : NaN;
504
+ return after?.scopeName === current.scopeName && Number.isFinite(afterMs)
505
+ && (!Number.isFinite(expiresMs) || afterMs > expiresMs)
506
+ ? 'refreshed' : 'unchanged';
507
+ } finally {
508
+ releaseLock();
509
+ grokSubscriptionRefreshesInProgress.delete(path);
434
510
  }
435
-
436
- const after = readExpiresAt(path);
437
- // ⛔ 「돌았다」가 아니라 「만료가 «앞으로» 갔다」를 본다.
438
- return after !== null && after !== before ? 'refreshed' : 'unchanged';
439
511
  }
440
512
 
441
513
  // ── ⭐ 「접힌」 자격 해석 — 호출자가 «기억할 것»을 0 으로 ────────────────────────
@@ -492,7 +564,6 @@ export function isGrokSubscriptionExpiring(
492
564
 
493
565
  /** 구독 만료 상태 — 칸 CRED-EXPIRY-REFRESH 기준 창. 이 안에 만료가 오면 갱신 후보다. */
494
566
  export const GROK_EXPIRY_SOON_WINDOW_MS = 2 * 60 * 60 * 1000;
495
-
496
567
  /** 만료 상태 셋 — ⛔ boolean 으로 접으면 「모름」과 «여유»가 «같은 값»이 된다. */
497
568
  export type GrokSubscriptionExpiryState = 'healthy' | 'expiring' | 'unknown';
498
569
 
@@ -17,7 +17,7 @@ export function renderHqFenceWrapper({ entry, configDir, bun, logFile }: { entry
17
17
  if (!isAbsolute(bun)) throw new Error(`hq-fence: bun must be an absolute path: ${bun}`);
18
18
  const log = logFile ?? join(configDir, 'logs', 'hq-fence.log');
19
19
  return `#!/bin/sh
20
- # Arbiter (cloud-vm) outage: retain the lease, do not promote; hq fence owns that decision.
20
+ # Arbiter outage: retain the lease, do not promote; hq fence owns that decision.
21
21
  ENTRY=${quote(entry)}
22
22
  CONFIG_DIR=${quote(configDir)}
23
23
  # cron has no PATH for bun — the absolute path was resolved when this wrapper was installed.
@@ -17,7 +17,7 @@ export interface TransferDeps {
17
17
  journalDir: string;
18
18
  }
19
19
 
20
- const aliases: Record<string, string[]> = { mbp: ['mbp', 'MacBookProM5'], node-b: ['node-b', 'MacStudioB1'] };
20
+ const aliases: Record<string, string[]> = { mbp: ['mbp', 'MacBookProM5'], 'node-b': ['node-b', 'MacStudioB1'] };
21
21
  const valid = (alias: string, holder: string) => aliases[alias]?.includes(holder) ?? false;
22
22
  const leaseCommand = (action: 'release' | 'acquire', expected?: { holder: string; generation: number }) =>
23
23
  `elanous hq lease ${action}${expected ? ` --expected-holder '${expected.holder}' --expected-generation ${expected.generation}` : ''} --json`;
package/src/index.ts CHANGED
@@ -4736,6 +4736,7 @@ selfCmd
4736
4736
  .option('--base <ref>', '커밋됐지만 PR 없는 변경의 비교 기준(ref...HEAD)')
4737
4737
  .option('--pr <number>', '열린 PR 번호에서 gh pr view files로 변경 파일을 읽는다')
4738
4738
  .option('--shards [number]', '메모리 예산에 맞춰 시험을 별도 프로세스로 분할한다 (기본 2)')
4739
+ .option('--shard-concurrency <number>', '동시에 실행할 조각 묶음 수 (1–4, 기본 3)')
4739
4740
  .option('--fixed-shard-distribution', '--shards N 과 함께만: RSS 사전 측정 없이 정렬된 파일을 N 조각에 라운드로빈 고정 배정한다(opt-in · 메모리 보증 아님 · 조각 타임아웃/OOM = unmeasured)')
4740
4741
  .option('--include-importers', '변경 모듈을 가져오는 importer 시험도 실행한다 (기본 caller 한도 밖까지)')
4741
4742
  .option('--remote [host]', 'GATE-REMOTE — 같은 커밋을 원격 호스트(기본 config gateRemote.host=node-b)에서 돌리고 결과만 가져온다(깨끗한 트리 · --pr 은 로컬)')
@@ -4745,9 +4746,10 @@ selfCmd
4745
4746
  .option('--shard-id <id>', 'GATE-REMOTE-SHARD-PLAN — 조각 id(예: <orchestration-id>/shard-2). 원격 명령줄에 그대로 실린다')
4746
4747
  .option('--shard-position <n>', 'GATE-REMOTE-SHARD-PLAN — 조각 위치(1부터 정수). 원격 명령줄에 그대로 실린다')
4747
4748
  .option('--shard-plan <path>', 'GATE-REMOTE-SHARD-PLAN — 조각 계획 파일 경로. 주면 원격 명령줄에 --shard-plan 으로 실린다')
4748
- .action(async (opts: { changed?: boolean; base?: string; pr?: string; shards?: string | boolean; fixedShardDistribution?: boolean; includeImporters?: boolean; remote?: string | boolean; local?: boolean; artifactDir?: string; orchestrationId?: string; shardId?: string; shardPosition?: string; shardPlan?: string }) => {
4749
+ .action(async (opts: { changed?: boolean; base?: string; pr?: string; shards?: string | boolean; shardConcurrency?: string; fixedShardDistribution?: boolean; includeImporters?: boolean; remote?: string | boolean; local?: boolean; artifactDir?: string; orchestrationId?: string; shardId?: string; shardPosition?: string; shardPlan?: string }) => {
4749
4750
  if (!opts.changed && opts.shards === undefined) { ui.error('self gate requires --changed or --shards'); process.exitCode = 2; return; }
4750
4751
  if (opts.fixedShardDistribution && opts.shards === undefined) { ui.error('self gate: --fixed-shard-distribution requires --shards <n>'); process.exitCode = 2; return; }
4752
+ if (opts.shardConcurrency !== undefined && (!/^[1-4]$/.test(opts.shardConcurrency))) { ui.error('self gate: --shard-concurrency must be 1–4'); process.exitCode = 2; return; }
4751
4753
  if (opts.artifactDir !== undefined && !opts.artifactDir.trim()) { ui.error('self gate: --artifact-dir needs a non-empty directory'); process.exitCode = 2; return; }
4752
4754
  const shardIdentityFlags = [opts.orchestrationId, opts.shardId, opts.shardPosition].filter((value) => value !== undefined).length;
4753
4755
  if (shardIdentityFlags !== 0 && shardIdentityFlags !== 3) { ui.error('self gate: --orchestration-id, --shard-id and --shard-position are used as a set'); process.exitCode = 2; return; }
@@ -4763,11 +4765,11 @@ selfCmd
4763
4765
  const shards = opts.shards === undefined ? undefined : opts.shards === true ? 2 : Number(opts.shards);
4764
4766
  let ranLocal = false;
4765
4767
  let remoteArtifacts: { dir: string; fetch?: { ok: true; summaryPath: string; junitFiles: string[]; remoteDirKept: boolean } | { ok: false; reason: string } } | { unsupported: true } | undefined;
4766
- const runLocal = () => {
4768
+ const runLocal = async () => {
4767
4769
  ranLocal = true;
4768
4770
  try {
4769
- const { runSelfGateCli } = require('./self-implement/gate-cli.js') as typeof import('./self-implement/gate-cli.js');
4770
- const result = runSelfGateCli(process.cwd(), { base: opts.base, pr: opts.pr, shards, ...(opts.fixedShardDistribution ? { fixedShardDistribution: true } : {}), includeImporterTests: !!opts.includeImporters, ...(opts.artifactDir !== undefined ? { artifactDir: opts.artifactDir } : {}) });
4771
+ const { runSelfGateCliAsync } = require('./self-implement/gate-cli.js') as typeof import('./self-implement/gate-cli.js');
4772
+ const result = await runSelfGateCliAsync(process.cwd(), { base: opts.base, pr: opts.pr, shards, ...(opts.shardConcurrency !== undefined ? { shardConcurrency: Number(opts.shardConcurrency) } : {}), ...(opts.fixedShardDistribution ? { fixedShardDistribution: true } : {}), includeImporterTests: !!opts.includeImporters, ...(opts.artifactDir !== undefined ? { artifactDir: opts.artifactDir } : {}) });
4771
4773
  console.log(result.lines.join('\n'));
4772
4774
  return result.exitCode;
4773
4775
  } catch (error) {
@@ -4798,7 +4800,7 @@ selfCmd
4798
4800
  // origin/main is pinned to this machine's origin/main on the host; any other base is passed as its resolved sha.
4799
4801
  const remoteArgv = (sha: (ref: string) => string) => {
4800
4802
  const argv = remoteSelfGateArgv({
4801
- changed: opts.changed, base: opts.base, shards, fixedShardDistribution: opts.fixedShardDistribution,
4803
+ changed: opts.changed, base: opts.base, shards, shardConcurrency: opts.shardConcurrency === undefined ? undefined : Number(opts.shardConcurrency), fixedShardDistribution: opts.fixedShardDistribution,
4802
4804
  includeImporters: opts.includeImporters,
4803
4805
  // A measured commit without this option rejects it (exit ≠ 0) — read as not passed, never as a silent measured run.
4804
4806
  artifactDir: remoteArtifacts && 'dir' in remoteArtifacts ? remoteArtifacts.dir : undefined,
@@ -4837,7 +4839,7 @@ selfCmd
4837
4839
  const reason = error instanceof Error ? error.message : String(error);
4838
4840
  if (opts.local) {
4839
4841
  ui.error(`self gate dispatch failed: ${reason}`);
4840
- process.exitCode = runLocal();
4842
+ process.exitCode = await runLocal();
4841
4843
  } else {
4842
4844
  ui.error(opts.remote !== undefined
4843
4845
  ? `self gate remote unmeasured — ${reason.replace(/\s+/g, ' ').trim()}`
@@ -12230,11 +12232,20 @@ const realContinueSessionLookup: ContinueSessionLookup = {
12230
12232
  activeSessionId: () => getActiveSessionId(),
12231
12233
  };
12232
12234
 
12235
+ const realNextTuiContinueSessionLookup: ContinueSessionLookup = {
12236
+ projectIdForCwd: (cwd) => suggestProjectForFolder(cwd)?.id ?? null,
12237
+ latestForProject: (projectId) => listSessions({ limit: 1, projectId, source: 'tui' })[0]?.id ?? null,
12238
+ latestGlobal: () => listSessions({ limit: 1, source: 'tui' })[0]?.id ?? null,
12239
+ activeSessionId: () => {
12240
+ const id = getActiveSessionId();
12241
+ return id && (loadSession(id) as unknown as { source?: string } | null)?.source === 'tui' ? id : null;
12242
+ },
12243
+ };
12244
+
12233
12245
  /**
12234
12246
  * TUI-CONTINUE-SESSION (0.2.35) — `--continue`(id 없는 `--resume`)의 «최근 세션» 을 cwd 기준으로
12235
12247
  * 먼저 좁힌다: cwd 가 속한 프로젝트(`primaryFolder` 또는 그 하위 디렉토리)의 최신 세션 id.
12236
- * 매칭 프로젝트가 없거나 그 프로젝트에 세션이 하나도 없으면 전역 최신으로 폴백한다 —
12237
- * 프로젝트와 무관한 디렉토리·화면의 이어가기 동작은 종전 그대로다.
12248
+ * 프로젝트가 없거나 그 프로젝트에 세션이 없으면 전역 최신으로 폴백한다.
12238
12249
  */
12239
12250
  export function latestSessionIdForContinue(
12240
12251
  cwd: string = process.cwd(),
@@ -12245,6 +12256,26 @@ export function latestSessionIdForContinue(
12245
12256
  return localId ?? lookup.latestGlobal();
12246
12257
  }
12247
12258
 
12259
+ /** Next TUI only: resume a project TUI session, never an automation or cross-project session. */
12260
+ export function latestNextTuiSessionIdForContinue(
12261
+ cwd: string = process.cwd(),
12262
+ lookup: ContinueSessionLookup = realNextTuiContinueSessionLookup,
12263
+ ): string | null {
12264
+ const projectId = lookup.projectIdForCwd(cwd);
12265
+ return projectId ? lookup.latestForProject(projectId) : lookup.latestGlobal();
12266
+ }
12267
+
12268
+ /** Keep the source-filtered session selection scoped to the Next TUI entry. */
12269
+ export function latestRootSessionIdForContinue(
12270
+ tuiEntry: 'classic' | 'next',
12271
+ cwd: string = process.cwd(),
12272
+ lookup?: ContinueSessionLookup,
12273
+ ): string | null {
12274
+ return tuiEntry === 'next'
12275
+ ? latestNextTuiSessionIdForContinue(cwd, lookup ?? realNextTuiContinueSessionLookup)
12276
+ : latestSessionIdForContinue(cwd, lookup ?? realContinueSessionLookup);
12277
+ }
12278
+
12248
12279
  /**
12249
12280
  * cwd 가 프로젝트 안이면 활성 표지보다 cwd 프로젝트의 최신 세션 선택을 우선한다.
12250
12281
  * 프로젝트 밖에서는 종전처럼 활성 표지가 전역 최신보다 우선한다.
@@ -12501,17 +12532,16 @@ async function main(): Promise<void> {
12501
12532
  // 우선순위: `--resume <id>` > `--continue`·id 없는 `--resume`(최신) > (폐기 예정) ELANOUS_RESUME_SESSION.
12502
12533
  // ⛔ 명시 인자가 있으면 환경변수가 이기지 않는다(TUI-H8 r1 must-fix).
12503
12534
  const { resolveLatestSessionId, resolveRootResumeSessionId } = await import('./session/session-start.js');
12535
+ const continueLookup = tuiEntry === 'next' ? realNextTuiContinueSessionLookup : realContinueSessionLookup;
12504
12536
  const rootResume = resolveRootResumeSessionId({
12505
12537
  ...(resumeFromFlag !== undefined ? { flagId: resumeFromFlag } : {}),
12506
12538
  continueLatest,
12507
12539
  // 명시 인자가 있으면 env 를 «읽지도» 않는다(폐기 경고가 명시 이어하기에 섞이지 않게).
12508
12540
  readEnvId: () => readDeprecatedEnvForResume('ELANOUS_RESUME_SESSION').value ?? null,
12509
12541
  latest: () => resolveLatestSessionId({
12510
- // TUI-CONTINUE-SESSION (0.2.35) — 활성 표지가 «다른 프로젝트» 세션이면 버리고 cwd 기준으로 고른다.
12511
- activeSessionId: () => activeSessionIdForContinue(),
12512
- // TUI-CONTINUE-SESSION (0.2.35) — «지금 이 디렉토리» 의 프로젝트 최근 세션을 먼저 본다.
12513
- // 그 프로젝트에 세션이 없으면 종전대로 전역 최신으로 폴백(다른 화면 동작 보존).
12514
- latestSessionId: () => latestSessionIdForContinue(),
12542
+ // Next TUI는 사람 TUI 세션만 이어가고, classic dashboard의 기존 선택은 보존한다.
12543
+ activeSessionId: () => activeSessionIdForContinue(process.cwd(), continueLookup),
12544
+ latestSessionId: () => latestRootSessionIdForContinue(tuiEntry),
12515
12545
  // TUI-H8-FOLLOW ① — 활성 표지가 사라진 세션이면 최신 세션으로(#28509 리뷰 should-fix).
12516
12546
  sessionExists: (id) => loadSession(id) !== null,
12517
12547
  }),
@@ -12714,7 +12744,7 @@ async function main(): Promise<void> {
12714
12744
  return;
12715
12745
  }
12716
12746
  const { showNextTui } = await import('./tui/entry.js');
12717
- await showNextTui({ resumeSessionId });
12747
+ await showNextTui({ resumeSessionId, sidetabMode: getUserConfig().tui?.sidetab ?? 'collapsed' });
12718
12748
  bootTimer.phase('show-next');
12719
12749
  bootTimer.done();
12720
12750
  } else {
@@ -37,7 +37,50 @@ function writeSavedCursor(root: string, lastId: number): void {
37
37
  writeFileSync(cursorFile(root), JSON.stringify({ lastId, at: new Date().toISOString() }) + '\n');
38
38
  }
39
39
 
40
- export interface CollectSavedResult { cursorBefore: number; cursorAfter: number; messages: number; raws: number; dryRun: boolean; ingest?: IngestResult }
40
+ export interface CollectSavedResult {
41
+ cursorBefore: number;
42
+ cursorAfter: number;
43
+ /** fetch 가 돌려준 «저장된 메시지» 수 — 커서 이후 읽은 것. */
44
+ messages: number;
45
+ /** 그중 savedMessageToRaws 가 0줄로 버린 메시지 수(빈 몸통) — «필터» 축. */
46
+ droppedByFilter: number;
47
+ /** 원장에 넣으려고 만든 입력 줄 수 — «원장 입력» 축. messages 와 다른 값이다. */
48
+ raws: number;
49
+ dryRun: boolean;
50
+ ingest?: IngestResult;
51
+ }
52
+
53
+ /** «메시지 0»·«원장 입력 0» 의 까닭 — 필터로 비었는지 다른 주체가 이미 가져갔는지 갈라 읽는다. */
54
+ export type SavedCollectDiagnosis = 'new-items' | 'no-new-messages' | 'filtered-out' | 'already-consumed';
55
+
56
+ export function diagnoseSavedCollect(res: CollectSavedResult): SavedCollectDiagnosis {
57
+ // 원장 입력이 있고 새로/합쳐 들어간 것이 있으면 정상 흡수다(dry-run 은 넣을 예정).
58
+ if (res.raws > 0 && (!res.ingest || res.ingest.added + res.ingest.merged > 0)) return 'new-items';
59
+ if (res.messages === 0) return 'no-new-messages';
60
+ if (res.droppedByFilter === res.messages) return 'filtered-out';
61
+ return 'already-consumed';
62
+ }
63
+
64
+ /** 사람이 읽는 한 덩이 — «메시지 0» 과 «원장 입력 0» 을 다른 줄로 갈라 보여준다. */
65
+ export function renderCollectTelegramSavedResult(res: CollectSavedResult): string {
66
+ const lines = [
67
+ `텔레그램 저장된 메시지: 읽음 ${res.messages} · 필터로 버림 ${res.droppedByFilter} · 원장 입력 ${res.raws} · 커서 ${res.cursorBefore} → ${res.cursorAfter}${res.dryRun ? ' (dry-run · 안 씀)' : ''}`,
68
+ ];
69
+ if (res.ingest) lines.push(`원장: 새 ${res.ingest.added} · 합침 ${res.ingest.merged} · 이미 끝난 것 ${res.ingest.seen} · 버림 ${res.ingest.skipped}`);
70
+ const diagnosis = diagnoseSavedCollect(res);
71
+ if (diagnosis === 'no-new-messages') {
72
+ lines.push(`메시지 0 — 커서 ${res.cursorBefore} 이후 새 저장 메시지가 없다${res.cursorBefore > 0 ? ' (커서는 이미 다른 주체가 넘겼을 수 있다)' : ''}`);
73
+ } else if (diagnosis === 'filtered-out') {
74
+ lines.push(`원장 입력 0 은 필터 때문이다 — 링크·메모 문장이 없는 빈 메시지 ${res.droppedByFilter}건`);
75
+ } else if (diagnosis === 'already-consumed') {
76
+ lines.push(`원장 입력 ${res.raws} · 새 0 — 같은 항목을 다른 주체(queue)가 이미 가져갔다 (이미 끝난 것 ${res.ingest?.seen ?? 0})`);
77
+ } else if (res.dryRun) {
78
+ lines.push(`원장에 들어갈 것 ${res.raws}건 (dry-run — 쓰지 않았다)`);
79
+ } else {
80
+ lines.push(`원장에 새 것 ${res.ingest?.added ?? 0}건이 들어갔다`);
81
+ }
82
+ return lines.join('\n');
83
+ }
41
84
 
42
85
  /**
43
86
  * 커서 이후 메시지를 한 번에 최대 max 개 읽어 원장에 넣고 커서를 옮긴다.
@@ -47,15 +90,21 @@ export interface CollectSavedResult { cursorBefore: number; cursorAfter: number;
47
90
  export async function collectTelegramSaved(root: string, fetch: FetchSavedMessages, opts: { max: number; dryRun?: boolean }): Promise<CollectSavedResult> {
48
91
  const cursorBefore = readSavedCursor(root);
49
92
  const messages = await fetch(cursorBefore, opts.max);
50
- const raws = messages.flatMap(savedMessageToRaws);
93
+ const rowsPerMessage = messages.map(savedMessageToRaws);
94
+ const raws = rowsPerMessage.flat();
95
+ const droppedByFilter = rowsPerMessage.filter((rows) => rows.length === 0).length;
51
96
  const cursorAfter = messages.reduce((mx, m) => Math.max(mx, m.id), cursorBefore);
52
- const result: CollectSavedResult = { cursorBefore, cursorAfter, messages: messages.length, raws: raws.length, dryRun: !!opts.dryRun };
97
+ const result: CollectSavedResult = { cursorBefore, cursorAfter, messages: messages.length, droppedByFilter, raws: raws.length, dryRun: !!opts.dryRun };
53
98
  if (!opts.dryRun) {
54
99
  result.ingest = ingestIntakeItems(root, 'telegram-saved', raws);
55
100
  if (cursorAfter > cursorBefore) writeSavedCursor(root, cursorAfter);
56
101
  }
57
- // ⛔ 본문·링크는 싣지 않는다 — 커서와 건수만.
58
- debug.log('intake.collect', 'telegram-saved', { cursorBefore, cursorAfter, messages: messages.length, raws: raws.length, dryRun: !!opts.dryRun });
102
+ // ⛔ 본문·링크는 싣지 않는다 — 커서와 건수만. 두 축(메시지·원장 입력)을 따로 남겨 사흘 0 을 갈라 읽게.
103
+ debug.log('intake.collect', 'telegram-saved', {
104
+ cursorBefore, cursorAfter, messages: messages.length, droppedByFilter, raws: raws.length,
105
+ ...(result.ingest ? { added: result.ingest.added, merged: result.ingest.merged, seen: result.ingest.seen, skipped: result.ingest.skipped } : {}),
106
+ diagnosis: diagnoseSavedCollect(result), dryRun: !!opts.dryRun,
107
+ });
59
108
  return result;
60
109
  }
61
110
 
@@ -55,6 +55,8 @@ export interface InteractiveTerminalModalSpec {
55
55
  * of a plain local shell. Empty default keeps the legacy behaviour. */
56
56
  shellArgs?: readonly string[];
57
57
  env?: Record<string, string>;
58
+ /** Remove captured login-shell environment keys after composition. */
59
+ unsetEnv?: readonly string[];
58
60
  /** Ghostty-compatible terminfo name. Defaults via PreviewTerminal
59
61
  * to xterm-256color. */
60
62
  termName?: string;
@@ -212,6 +214,7 @@ export function createInteractiveTerminalModal(
212
214
  shell: spec.shell,
213
215
  shellArgs: spec.shellArgs,
214
216
  env: spec.env,
217
+ unsetEnv: spec.unsetEnv,
215
218
  termName: spec.termName,
216
219
  useRegistry: spec.useRegistry,
217
220
  registryKind: spec.registryKind,
@@ -54,32 +54,27 @@ export const KEYBINDINGS: KeyBinding[] = [
54
54
  { keys: ['Ctrl+K', 'Ctrl+ㅏ'], action: 'Open SSH remote picker', context: 'global', note: 'FU-1 — registerKeyBinding({handler})' },
55
55
  { keys: ['Ctrl+P', 'Ctrl+ㅔ'], action: 'Open finder (file picker)', context: 'global', note: 'FU-1 — registerKeyBinding({handler})' },
56
56
  { keys: ['Ctrl+M', 'Ctrl+ㅡ'], action: 'Arm pane-modal chord (1 s window; next letter opens deferred pane)', context: 'global', note: 'FU-1 — coordinator chord, SHORTCUT_TABLE' },
57
- { keys: ['Ctrl+B', 'Ctrl+ㅠ'], action: 'Arm virtual-window chord (1 s window; see §14)', context: 'global', note: 'FU-2 — coordinator chord' },
58
- { keys: ['Ctrl+B w'], action: 'Focus working-dir browser', context: 'global', note: 'tmux-style prefix chord' },
59
- { keys: ['Ctrl+B o'], action: 'Focus Obsidian browser', context: 'global' },
60
- { keys: ['Ctrl+B s'], action: 'Reopen scratchpad (pane-browse) · Enter sync mode (chat input) — A3', context: 'global', note: 'input-focus route added P5 / unified in C1' },
61
- { keys: ['Ctrl+B g'], action: 'Exit sync/control mode → general (chat input)', context: 'global', note: 'P5 input-focus only' },
62
- { keys: ['Ctrl+B S'], action: 'Focus sessions sidebar', context: 'global', note: 'ST4 — jumps focus to the leadColumn session list' },
63
- { keys: ['Ctrl+B n'], action: 'Next VW / advance to next session + focus sidebar', context: 'global', note: 'ST4 + VW chord — context gated' },
64
- { keys: ['Ctrl+B p'], action: 'Prev VW / retreat to previous session + focus sidebar', context: 'global', note: 'ST4 + VW chord — context gated' },
65
- { keys: ['Ctrl+B 0'], action: 'Open window picker (VW chord)', context: 'global', note: 'FU-2' },
66
- { keys: ['Ctrl+B 1'], action: 'Switch to VW 1 (Ctrl+1 also works)', context: 'global', note: 'FU-2 — also 2..9' },
67
- { keys: ['Ctrl+B c'], action: 'New virtual window — terminal (pane-browse) · Enter control mode (chat input)', context: 'global', note: 'FU-2 + P5 input-focus chord overlay' },
68
- { keys: ['Ctrl+B t'], action: 'Toggle modal ↔ virtual-window session', context: 'global', note: 'FU-2' },
69
- { keys: ['Ctrl+B x'], action: 'Close focused pane (VW chord)', context: 'global', note: 'FU-2' },
70
- { keys: ['Ctrl+B Shift+X'], action: 'Close whole window (VW chord)', context: 'global', note: 'FU-2 — Shift+X dispatch fixed' },
71
- { keys: ['Ctrl+B %', 'Ctrl+B s'], action: 'Horizontal split', context: 'global', note: 'FU-2' },
72
- { keys: ['Ctrl+B "', 'Ctrl+B v'], action: 'Vertical split', context: 'global', note: 'FU-2' },
73
- { keys: ['Ctrl+B ?'], action: 'Open VW chord help popup (transient modal, 8 s)', context: 'global', note: 'FU-2 — upgraded from chatLines' },
74
- { keys: ['Ctrl+B z'], action: 'Toggle zoom on focused pane (fullscreen within VW)', context: 'global', note: 'VW-U5' },
75
- { keys: ['Ctrl+B Tab'], action: 'Focus last pane (alt-tab within VW)', context: 'global', note: 'VW-U5' },
76
- { keys: ['Ctrl+B R'], action: 'Rename foreground window (input modal)', context: 'global', note: 'VW-B1 — tmux `,` 는 prev 이라 R 사용' },
77
- { keys: ['Ctrl+B A'], action: 'Rename focused pane (VW-local override, empty clears)', context: 'global', note: 'VW-B2' },
57
+ { keys: ['Ctrl+B'], action: 'Background running child tasks (while streaming; turn continues)', context: 'global' },
58
+ { keys: ['Ctrl+X', 'Ctrl+ㅌ'], action: 'Arm dashboard pane chord (1 s window)', context: 'pane' },
59
+ { keys: ['Ctrl+X Ctrl+W'], action: 'Focus working-dir browser', context: 'global', note: 'pane-browse chord' },
60
+ { keys: ['Ctrl+X Ctrl+O'], action: 'Focus Obsidian browser', context: 'global', note: 'pane-browse chord' },
61
+ { keys: ['Ctrl+X Ctrl+S'], action: 'Reopen scratchpad (pane-browse)', context: 'global' },
62
+ { keys: ['Ctrl+X s'], action: 'Enter sync mode (chat input)', context: 'input' },
63
+ { keys: ['Ctrl+X g'], action: 'Exit sync/control mode → general (chat input)', context: 'input' },
64
+ { keys: ['Ctrl+X S'], action: 'Focus sessions sidebar', context: 'pane' },
65
+ { keys: ['Ctrl+X n'], action: 'Advance to next session + focus sidebar', context: 'pane' },
66
+ { keys: ['Ctrl+X p'], action: 'Retreat to previous session + focus sidebar', context: 'pane' },
67
+ { keys: ['Ctrl+X c'], action: 'Enter control mode (chat input)', context: 'input' },
68
+ { keys: ['Ctrl+X x'], action: 'Close focused pane', context: 'pane' },
69
+ { keys: ['Ctrl+X z'], action: 'Toggle log zoom', context: 'pane' },
70
+ { keys: ['Ctrl+X t'], action: 'Open preview terminal', context: 'pane' },
71
+ { keys: ['Ctrl+X e'], action: 'Toggle preview terminal expansion', context: 'pane' },
72
+ { keys: ['Ctrl+X f'], action: 'Toggle all log folds', context: 'pane' },
78
73
  { keys: ['Alt+N', 'Alt+ㅜ'], action: 'Next virtual window (fast-switch, no chord)', context: 'global', note: 'VW-U2 — guarded by list().length>1' },
79
74
  { keys: ['Alt+P', 'Alt+ㅔ'], action: 'Prev virtual window (fast-switch, no chord)', context: 'global', note: 'VW-U2' },
80
75
  { keys: ['Alt+1..9'], action: 'Switch directly to Nth virtual window', context: 'global', note: 'VW-U2 — guarded by list().length>1' },
81
76
  { keys: ['Alt+0'], action: 'Open window picker (fast, no chord)', context: 'global', note: 'VW-U2' },
82
- { keys: ['Ctrl+B b'], action: 'Toggle notification bell modal', context: 'global', note: 'NT5 — open/close bell modal with unread + error filter' },
77
+ { keys: ['Ctrl+X b'], action: 'Toggle notification bell modal', context: 'pane', note: 'NT5 — open/close bell modal with unread + error filter' },
83
78
  { keys: ['Ctrl+Shift+V', 'Ctrl+Shift+ㅍ'], action: 'Enter Voice mode (Space hold push-to-talk · Esc to exit)', context: 'global', note: 'PR-S1V.4 — voice-input-host · kitty >3u on entry · brand prefix routing' },
84
79
  { keys: ['Alt+S', 'Alt+ㄴ'], action: 'Toggle continuous voice-chat mode (real-time STT + auto-TTS · ESC or chord again to exit)', context: 'global', note: '2026-05-03 — moved from Alt+R to free R for reasoning cycle (V/D/R mnemonic)' },
85
80
  { keys: ['Alt+R', 'Alt+ㄱ'], action: 'Cycle reasoning level (off → low → medium → high → xhigh). Codex / Claude reasoning models only — no-op on grok/gemini', context: 'global', note: '2026-05-03 — provider-agnostic ReasoningLevel cycle, same effect as `/reasoning` slash. V/D/R mnemonic: V=voice control (Ctrl+Shift+V), D=batch dictation (Space-longpress), R=reasoning' },
@@ -209,7 +209,7 @@ export function resolveProviderCredential(input: ResolveCredentialInput): Resolv
209
209
  // 목표 provider 의 엔드포인트 — 키와 **같은 규율**로 rotation 에서만 가져온다(10R).
210
210
  // 전환이면 옛 baseUrl 은 틀린 주소이므로, rotation 에 명시가 없으면 undefined(provider 기본).
211
211
  // ⛔⭐ local 은 «런 단위 env»(`LOCAL_LLM_URL`)가 config rotation 을 이긴다 — `ELANOUS_LLM_PROVIDER` 가 config 를 이기는 것과 같은 규칙(BACKLOG B13).
212
- // 🩸 2026-09-25: 부모에 `LOCAL_LLM_URL=<node-b 경유>` 를 줬는데 rotation 의 `local → localhost:1234` 가 이겨 자식이 «호스트»
212
+ // 🩸 2026-09-25: 부모에 `LOCAL_LLM_URL=<원격 프록시>` 를 줬는데 rotation 의 `local → localhost:1234` 가 이겨 자식이 «호스트»
213
213
  // LM Studio 로 갔다. Pod(config 없음)에선 안 드러났다.
214
214
  const envEndpoint = provider === 'local' ? env.LOCAL_LLM_URL?.trim() : undefined;
215
215
  const endpoint = envEndpoint || rotation?.find((r) => r.provider === provider && typeof r.baseUrl === 'string' && r.baseUrl.trim().length > 0)?.baseUrl?.trim();
@@ -27,6 +27,26 @@ export function sanitizeToolSchemaForGrok(schema: unknown): unknown {
27
27
  return output;
28
28
  }
29
29
 
30
+ /** Anthropic-backed Claude APIs reject top-level JSON Schema composition on tool inputs.
31
+ * Check every tool before serialization so a newly introduced tool cannot turn a whole
32
+ * Claude request into a 400 and trigger an unnoticed provider fallback. Nested schemas
33
+ * remain valid and are deliberately not inspected here. */
34
+ export function assertNoTopLevelToolSchemaCombinators(
35
+ tools: readonly { name: string; parameters: unknown }[] | undefined,
36
+ ): void {
37
+ if (!tools?.length) return;
38
+ const combinators = ['anyOf', 'oneOf', 'allOf'] as const;
39
+ const invalid = tools.flatMap((tool) => {
40
+ if (!tool.parameters || typeof tool.parameters !== 'object' || Array.isArray(tool.parameters)) return [];
41
+ const schema = tool.parameters as Record<string, unknown>;
42
+ const found = combinators.filter((key) => Object.prototype.hasOwnProperty.call(schema, key));
43
+ return found.length ? [`${tool.name} (${found.join(', ')})`] : [];
44
+ });
45
+ if (invalid.length) {
46
+ throw new Error(`Claude tool schema has unsupported top-level composition: ${invalid.join('; ')}`);
47
+ }
48
+ }
49
+
30
50
  /** OpenRouter model ids may include the provider prefix; callers can pass
31
51
  * either the catalog id or the already-normalized wire id. */
32
52
  export function isOpenRouterGrokModel(model: string): boolean {