elanous 0.2.22 → 0.2.24

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 (803) hide show
  1. package/NOTICE +7 -0
  2. package/README.md +32 -22
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_buildManifest.js +1 -1
  6. package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
  10. package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
  12. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
  13. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
  15. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
  24. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
  25. package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
  28. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
  36. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
  40. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
  53. package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
  57. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
  65. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
  70. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
  72. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
  74. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
  75. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
  79. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
  84. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
  85. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
  86. package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
  88. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
  91. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
  98. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
  100. package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
  101. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
  102. package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
  103. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
  106. package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
  111. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
  112. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
  113. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
  115. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
  117. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
  118. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
  121. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
  124. package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
  125. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/botlab/page-24282bf9f90031a5.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-c0ab229673a8b0eb.js} +1 -1
  134. package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1d809a87139dd024.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/outputs/page-b92caddb5c715f30.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
  180. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
  185. package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
  186. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
  187. package/apps/pwa/out/approvals/index.html +1 -1
  188. package/apps/pwa/out/approvals/index.txt +23 -23
  189. package/apps/pwa/out/autopilot/index.html +1 -1
  190. package/apps/pwa/out/autopilot/index.txt +23 -23
  191. package/apps/pwa/out/board/index.html +1 -1
  192. package/apps/pwa/out/board/index.txt +23 -23
  193. package/apps/pwa/out/botlab/index.html +1 -1
  194. package/apps/pwa/out/botlab/index.txt +22 -22
  195. package/apps/pwa/out/bots/index.html +1 -1
  196. package/apps/pwa/out/bots/index.txt +22 -22
  197. package/apps/pwa/out/ceo/index.html +1 -1
  198. package/apps/pwa/out/ceo/index.txt +23 -23
  199. package/apps/pwa/out/chat/index.html +1 -1
  200. package/apps/pwa/out/chat/index.txt +22 -22
  201. package/apps/pwa/out/consult/index.html +1 -1
  202. package/apps/pwa/out/consult/index.txt +23 -23
  203. package/apps/pwa/out/control/index.html +1 -1
  204. package/apps/pwa/out/control/index.txt +23 -23
  205. package/apps/pwa/out/decisions/index.html +1 -1
  206. package/apps/pwa/out/decisions/index.txt +22 -22
  207. package/apps/pwa/out/design-check/index.html +1 -1
  208. package/apps/pwa/out/design-check/index.txt +23 -23
  209. package/apps/pwa/out/editor/index.html +1 -1
  210. package/apps/pwa/out/editor/index.txt +24 -23
  211. package/apps/pwa/out/exec/index.html +1 -1
  212. package/apps/pwa/out/exec/index.txt +23 -23
  213. package/apps/pwa/out/field/index.html +1 -1
  214. package/apps/pwa/out/field/index.txt +23 -23
  215. package/apps/pwa/out/healthz +1 -1
  216. package/apps/pwa/out/index.html +1 -1
  217. package/apps/pwa/out/index.txt +22 -22
  218. package/apps/pwa/out/inside/index.html +1 -1
  219. package/apps/pwa/out/inside/index.txt +22 -22
  220. package/apps/pwa/out/intake/index.html +1 -1
  221. package/apps/pwa/out/intake/index.txt +23 -23
  222. package/apps/pwa/out/live/index.html +1 -1
  223. package/apps/pwa/out/live/index.txt +23 -23
  224. package/apps/pwa/out/live-run/index.html +1 -1
  225. package/apps/pwa/out/live-run/index.txt +24 -23
  226. package/apps/pwa/out/loops/index.html +1 -1
  227. package/apps/pwa/out/loops/index.txt +22 -22
  228. package/apps/pwa/out/market/index.html +1 -1
  229. package/apps/pwa/out/market/index.txt +22 -22
  230. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  231. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  232. package/apps/pwa/out/morning/index.html +1 -1
  233. package/apps/pwa/out/morning/index.txt +23 -23
  234. package/apps/pwa/out/observatory/index.html +1 -1
  235. package/apps/pwa/out/observatory/index.txt +23 -23
  236. package/apps/pwa/out/ops/checklist/index.html +1 -1
  237. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  238. package/apps/pwa/out/ops/release/index.html +1 -1
  239. package/apps/pwa/out/ops/release/index.txt +22 -22
  240. package/apps/pwa/out/ops/seats/index.html +1 -1
  241. package/apps/pwa/out/ops/seats/index.txt +22 -22
  242. package/apps/pwa/out/outputs/index.html +1 -1
  243. package/apps/pwa/out/outputs/index.txt +22 -22
  244. package/apps/pwa/out/reflection/index.html +1 -1
  245. package/apps/pwa/out/reflection/index.txt +23 -23
  246. package/apps/pwa/out/scheduler/index.html +1 -1
  247. package/apps/pwa/out/scheduler/index.txt +23 -23
  248. package/apps/pwa/out/sessions/index.html +1 -1
  249. package/apps/pwa/out/sessions/index.txt +22 -22
  250. package/apps/pwa/out/settings/devices/index.html +1 -1
  251. package/apps/pwa/out/settings/devices/index.txt +23 -23
  252. package/apps/pwa/out/settings/index.html +1 -1
  253. package/apps/pwa/out/settings/index.txt +23 -23
  254. package/apps/pwa/out/setup/done/index.html +1 -1
  255. package/apps/pwa/out/setup/done/index.txt +23 -23
  256. package/apps/pwa/out/setup/index.html +1 -1
  257. package/apps/pwa/out/setup/index.txt +23 -23
  258. package/apps/pwa/out/share/index.html +1 -1
  259. package/apps/pwa/out/share/index.txt +23 -23
  260. package/apps/pwa/out/showroom/index.html +1 -1
  261. package/apps/pwa/out/showroom/index.txt +22 -22
  262. package/apps/pwa/out/tasks/index.html +1 -1
  263. package/apps/pwa/out/tasks/index.txt +23 -23
  264. package/apps/pwa/out/term/index.html +1 -1
  265. package/apps/pwa/out/term/index.txt +23 -23
  266. package/apps/pwa/out/today/index.html +1 -1
  267. package/apps/pwa/out/today/index.txt +23 -23
  268. package/apps/pwa/out/trace/index.html +1 -1
  269. package/apps/pwa/out/trace/index.txt +23 -23
  270. package/apps/pwa/out/vault/index.html +1 -1
  271. package/apps/pwa/out/vault/index.txt +23 -23
  272. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  273. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  274. package/apps/pwa/out/workflows/index.html +1 -1
  275. package/apps/pwa/out/workflows/index.txt +23 -23
  276. package/apps/pwa/out/workspace/index.html +1 -1
  277. package/apps/pwa/out/workspace/index.txt +23 -23
  278. package/apps/pwa/out/worktrees/index.html +1 -1
  279. package/apps/pwa/out/worktrees/index.txt +23 -23
  280. package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
  281. package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
  282. package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
  283. package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
  284. package/catalog/models/openai/gpt-6-astra.yaml +6 -0
  285. package/catalog/models/openai/gpt-6-luna.yaml +6 -0
  286. package/catalog/models/openai/gpt-6-sol.yaml +6 -0
  287. package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
  288. package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
  289. package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
  290. package/catalog/providers/openrouter.yaml +2 -0
  291. package/graphs/implement-loop.yaml +31 -0
  292. package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
  293. package/graphs/log-horizon/recipes.yaml +3 -0
  294. package/graphs/ops/harness-gc.yaml +17 -0
  295. package/graphs/ops/recipes.yaml +3 -0
  296. package/graphs/overlays/README.md +1 -1
  297. package/graphs/overlays/stop-heal-ladder.yaml +105 -0
  298. package/graphs/release/recipes.yaml +1 -1
  299. package/graphs/release/release-loop.yaml +6 -2
  300. package/graphs/release-rehearsal/recipes.yaml +12 -0
  301. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  302. package/package.json +4 -1
  303. package/scripts/add-api-key.sh +1 -1
  304. package/scripts/bench-report.ts +82 -3
  305. package/scripts/ci-typecheck-changed.ts +80 -14
  306. package/scripts/fleet/bedrock-pod-secret.ts +122 -0
  307. package/scripts/fleet/node-setup-linux.sh +97 -0
  308. package/scripts/fleet/node-setup.sh +11 -0
  309. package/scripts/fleet/zai-pod-secret.ts +86 -0
  310. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  311. package/scripts/land-global-checks.ts +3 -0
  312. package/scripts/lib/typecheck-ratchet.ts +51 -0
  313. package/scripts/measure-log-diet-2.ts +213 -0
  314. package/scripts/measure-tsc-affected-roots.ts +289 -0
  315. package/scripts/openai-relay-server.ts +5 -1
  316. package/scripts/release-loop/docs-node.ts +258 -43
  317. package/scripts/release-loop/gate-executor.ts +28 -0
  318. package/scripts/release-loop/gate-method.ts +59 -0
  319. package/scripts/release-loop/gate-node.ts +335 -33
  320. package/scripts/release-loop/gate-wall.ts +208 -0
  321. package/scripts/release-loop/known-issues-node.ts +53 -8
  322. package/scripts/release-loop/publish-at.ts +14 -0
  323. package/scripts/release-loop/publish-node.ts +17 -2
  324. package/scripts/release-loop/resume-release.ts +40 -4
  325. package/scripts/release-loop/resume.ts +94 -0
  326. package/scripts/release-loop/shard-plan.ts +3 -11
  327. package/scripts/release-loop/tui-node-checks.ts +22 -0
  328. package/scripts/release-loop/unattended-release.ts +29 -7
  329. package/scripts/rhythm/daily.ts +51 -2
  330. package/scripts/rhythm/weekly.ts +3 -2
  331. package/scripts/tsc-baseline-cache.ts +147 -0
  332. package/scripts/tsc-main-safety-net.ts +189 -0
  333. package/scripts/usage-rollup.ts +64 -8
  334. package/src/acp/codex-plugins.ts +48 -6
  335. package/src/agent/monad-agent-turn.ts +67 -5
  336. package/src/agent/run-context.ts +20 -0
  337. package/src/agent/tool-profile.ts +28 -2
  338. package/src/agent-mission/acp-judge.ts +8 -2
  339. package/src/agent-mission/capabilities-cli.ts +16 -1
  340. package/src/agent-mission/driver.ts +19 -4
  341. package/src/agent-mission/pr-review-watch.ts +6 -2
  342. package/src/agent-mission/resource-ladder.ts +8 -3
  343. package/src/agent-mission/review-loop.ts +41 -7
  344. package/src/agent-substrate/acp-implementer.ts +139 -0
  345. package/src/agent-substrate/acp-reviewer.ts +17 -8
  346. package/src/agent-substrate/pr-reviewer.ts +191 -28
  347. package/src/agent-substrate/review-intent.ts +6 -4
  348. package/src/agent-substrate/self-review-cli.ts +155 -21
  349. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  350. package/src/ask-user-question/pending-questions.ts +8 -2
  351. package/src/autopilot/build/llm-conflict-merge.ts +216 -12
  352. package/src/autopilot/codebase-grounding.ts +44 -0
  353. package/src/autopilot/llm-control-brain.ts +13 -1
  354. package/src/autopilot/mission-codebase-gate.ts +8 -77
  355. package/src/autopilot/mission-critique.ts +18 -5
  356. package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
  357. package/src/autopilot/mission-trace.ts +12 -1
  358. package/src/autopilot/pr-manager.ts +12 -3
  359. package/src/autopilot/system-lookback-run.ts +16 -10
  360. package/src/bench/bench.ts +183 -0
  361. package/src/boot/acp-server.ts +4 -7
  362. package/src/boot/acp-socket-path.ts +7 -0
  363. package/src/briefing/brief-items.ts +21 -13
  364. package/src/budget/fetchers/grok.ts +15 -5
  365. package/src/budget/llm-cost.ts +37 -5
  366. package/src/budget/types.ts +8 -2
  367. package/src/budget/unified-usage.ts +88 -6
  368. package/src/chat/index.ts +12 -3
  369. package/src/cli/agent-cli.ts +20 -0
  370. package/src/cli/bench-cli.ts +34 -0
  371. package/src/cli/brief-cli.ts +27 -21
  372. package/src/cli/cli-user-error.ts +9 -2
  373. package/src/cli/guardian-cli.ts +26 -1
  374. package/src/cli/image-cli.ts +101 -0
  375. package/src/cli/log-event-names.ts +7 -0
  376. package/src/cli/logs-cli.ts +1 -0
  377. package/src/cli/mcp-login.ts +111 -37
  378. package/src/cli/plugin-cli.ts +21 -1
  379. package/src/cli/pod-cli.ts +26 -0
  380. package/src/cli/pr-cli.ts +90 -5
  381. package/src/cli/pr-land-overlap-evidence.ts +279 -0
  382. package/src/cli/release-cli.ts +63 -12
  383. package/src/cli/rfc-status.ts +52 -2
  384. package/src/cli/self-update.ts +277 -10
  385. package/src/cli/skills-cli.ts +12 -3
  386. package/src/cli/tasks-cli.ts +241 -30
  387. package/src/cli/usage-cli.ts +91 -8
  388. package/src/context-bus/context-first.ts +51 -2
  389. package/src/context-bus/context-now-surfaces.ts +13 -2
  390. package/src/context-bus/long-term-memory.ts +3 -1
  391. package/src/context-bus/nightly-condense.ts +3 -2
  392. package/src/core-turn/run-goal-loop.ts +87 -2
  393. package/src/dashboard/ad-run-setup-bindings.ts +279 -0
  394. package/src/dashboard/chat-fold.ts +20 -0
  395. package/src/dashboard/first-screen-band.ts +151 -1
  396. package/src/dashboard/index.ts +45 -281
  397. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
  398. package/src/dashboard/stale-install-check.ts +24 -2
  399. package/src/dashboard/turn-stream-formatter.ts +25 -0
  400. package/src/debug/log-diet.ts +190 -0
  401. package/src/debug/log.ts +70 -17
  402. package/src/display/coordinator.ts +25 -2
  403. package/src/domains/coo-admin-tool.ts +27 -0
  404. package/src/domains/cron-match.ts +1 -0
  405. package/src/domains/outbound-alert.ts +17 -6
  406. package/src/domains/release-tool.ts +158 -10
  407. package/src/domains/schedule-registry.ts +10 -7
  408. package/src/domains/schedule-runner.ts +1 -0
  409. package/src/elanous-config-dir.ts +2 -2
  410. package/src/elanous-daemon.ts +3 -3
  411. package/src/error-report/report.ts +21 -4
  412. package/src/execution-loop/launch-gate.ts +1 -1
  413. package/src/expression/i18n/messages.en.ts +5 -0
  414. package/src/expression/i18n/messages.ja.ts +5 -0
  415. package/src/expression/i18n/messages.ko.ts +5 -0
  416. package/src/expression/i18n/messages.zh.ts +5 -0
  417. package/src/expression/i18n/types.ts +8 -0
  418. package/src/github/pr-labels.ts +2 -0
  419. package/src/graph-runner/graph-cli.ts +42 -1
  420. package/src/graph-runner/runner.ts +218 -8
  421. package/src/grok/usage.ts +23 -2
  422. package/src/grounding/ref-index.ts +253 -0
  423. package/src/harness/dispatch-backpressure.ts +267 -0
  424. package/src/harness/harness-clean.ts +199 -78
  425. package/src/harness/harness-cli-command.ts +229 -35
  426. package/src/harness/harness-gc.ts +331 -0
  427. package/src/harness/harness-seams.ts +2 -20
  428. package/src/harness/harness-stop.ts +4 -2
  429. package/src/harness/harness-substrate-default.ts +214 -8
  430. package/src/harness/launch-registry.ts +6 -0
  431. package/src/harness/nested-elanous-policy.ts +4 -2
  432. package/src/harness/worktree-branch-prefix.ts +9 -0
  433. package/src/hq/fence-wrapper.ts +7 -0
  434. package/src/hq/fence.ts +187 -0
  435. package/src/hq/hq.ts +33 -2
  436. package/src/hq/lease.ts +13 -0
  437. package/src/hq/seats.ts +133 -21
  438. package/src/images/image-ledger.ts +179 -0
  439. package/src/index.ts +250 -69
  440. package/src/instance/child-scope.ts +32 -1
  441. package/src/instance/dev-project.ts +133 -0
  442. package/src/instance/resolve.ts +24 -0
  443. package/src/instance/spawn-elanous.ts +45 -0
  444. package/src/intake-plane/collect-github.ts +19 -1
  445. package/src/intake-plane/digest.ts +45 -20
  446. package/src/intake-plane/lens.ts +36 -8
  447. package/src/intake-plane/ref-prefetch.ts +110 -0
  448. package/src/intelligence-map/model-alias.ts +6 -0
  449. package/src/intelligence-map/model-catalog.ts +113 -0
  450. package/src/knowledge/kgs/pack.ts +5 -2
  451. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  452. package/src/knowledge/tools/knowledge-query.ts +20 -2
  453. package/src/knowledge/write.ts +234 -2
  454. package/src/llm/bedrock-eventstream.ts +215 -0
  455. package/src/llm/bedrock-provider.ts +248 -0
  456. package/src/llm/bedrock.ts +491 -0
  457. package/src/llm/openrouter-byok-cost.ts +96 -0
  458. package/src/llm/openrouter-deepseek.ts +151 -0
  459. package/src/llm/openrouter-upstream-pins.config.ts +25 -0
  460. package/src/llm/provider-credentials.ts +3 -1
  461. package/src/llm/zai-coding-plan.ts +700 -0
  462. package/src/llm.ts +383 -41
  463. package/src/loops/budget.ts +150 -0
  464. package/src/loops/checker.ts +148 -9
  465. package/src/loops/orchestrator/resync-shadow.ts +34 -7
  466. package/src/loops/orchestrator/seat-share.ts +6 -49
  467. package/src/loops/orchestrator/traffic.ts +5 -81
  468. package/src/market/signed-index.ts +42 -0
  469. package/src/maturity/feature-maturity.ts +2 -2
  470. package/src/mcp/mcp-oauth.ts +136 -17
  471. package/src/model-tier/llm-tier-map.ts +52 -4
  472. package/src/models/prompts.ts +23 -1
  473. package/src/mss/logging/horizon-watch.ts +168 -0
  474. package/src/mss/logging/log-store.ts +262 -26
  475. package/src/native-tool-catalog.ts +1 -1
  476. package/src/nexus/api/consult-requests.ts +7 -10
  477. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  478. package/src/nexus/api/error-reports.ts +30 -8
  479. package/src/nexus/api/http-server.ts +8 -0
  480. package/src/nexus/api/loop-resources.ts +42 -0
  481. package/src/nexus/api/missions.ts +73 -2
  482. package/src/nexus/api/ops-api.ts +18 -0
  483. package/src/nexus/api/outbound-report.ts +8 -3
  484. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  485. package/src/nexus/index.ts +17 -75
  486. package/src/nexus/outbound/format.ts +2 -0
  487. package/src/nexus/outbound/router.ts +198 -13
  488. package/src/nexus/tools-kind.ts +78 -0
  489. package/src/oauth/codex-account-rotation.ts +55 -20
  490. package/src/oauth/codex-account-store.ts +451 -23
  491. package/src/oauth/fallback-chain.ts +75 -15
  492. package/src/onboarding/first-run.ts +37 -18
  493. package/src/onboarding/web-first.ts +20 -2
  494. package/src/onboarding.ts +2 -1
  495. package/src/ops/machine-heartbeat.ts +185 -0
  496. package/src/ops/overview-cache.ts +175 -0
  497. package/src/ops/overview.ts +8 -0
  498. package/src/plugins/adapters/claude-package.ts +4 -12
  499. package/src/plugins/core/capability-policy.ts +141 -0
  500. package/src/plugins/core/host.ts +21 -8
  501. package/src/plugins/core/manifest.ts +19 -2
  502. package/src/plugins/core/trust-store.ts +15 -0
  503. package/src/plugins/core/types.ts +12 -0
  504. package/src/plugins/install/market-fetch.ts +68 -16
  505. package/src/plugins/install/plugin-install.ts +187 -16
  506. package/src/plugins/maker/plugin-maker.ts +25 -20
  507. package/src/plugins/maker/wizard-generate.ts +16 -2
  508. package/src/policy/llm-policy.ts +14 -1
  509. package/src/process/pid-liveness.ts +1 -1
  510. package/src/prompt-cache/openai.ts +13 -6
  511. package/src/prompt-cache/openrouter.ts +94 -0
  512. package/src/prompt-cache/types.ts +5 -0
  513. package/src/prompt-enhance/enhance.ts +69 -5
  514. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  515. package/src/prompt-library/universal-preamble.ts +2 -2
  516. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  517. package/src/registry/loader.ts +6 -1
  518. package/src/release-loop/checklist.ts +24 -9
  519. package/src/release-loop/feature-store.ts +3 -0
  520. package/src/release-loop/gate-shards.ts +48 -4
  521. package/src/release-loop/landed-to-green.ts +81 -0
  522. package/src/release-loop/light-rc.ts +11 -1
  523. package/src/release-loop/merged-pr-checklist.ts +10 -0
  524. package/src/release-loop/placement.ts +107 -23
  525. package/src/release-loop/rehearsal.ts +317 -0
  526. package/src/release-loop/release-schedule.ts +13 -1
  527. package/src/release-loop/rubric-types.ts +1 -0
  528. package/src/release-loop/rubric.ts +2 -2
  529. package/src/requirements/requirement-ledger.ts +536 -0
  530. package/src/retro/daily.ts +26 -12
  531. package/src/seat-loop/seat-loop.ts +66 -11
  532. package/src/seat-loop/traffic-signal.ts +44 -0
  533. package/src/self-dev/ask-launch-flow.ts +2 -2
  534. package/src/self-dev/dev-cli.ts +109 -11
  535. package/src/self-dev/dev-pipeline.ts +11 -8
  536. package/src/self-dev/draft-residue.ts +475 -0
  537. package/src/self-dev/draft-sweep.ts +254 -10
  538. package/src/self-dev/draft-triage-rules.ts +27 -1
  539. package/src/self-dev/graph-journey-route.ts +6 -0
  540. package/src/self-dev/launch-preflight-text.ts +549 -0
  541. package/src/self-dev/launch-preflight.ts +10 -545
  542. package/src/self-dev/orchestrate-cli.ts +82 -5
  543. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  544. package/src/self-dev/orchestrate.ts +49 -141
  545. package/src/self-dev/review-provider-fallback.ts +115 -19
  546. package/src/self-dev/run-store.ts +1 -3
  547. package/src/self-dev/run-supervisor.ts +190 -36
  548. package/src/self-dev/run-types.ts +191 -0
  549. package/src/self-dev/shard-aggregate.ts +61 -13
  550. package/src/self-dev/shard-plan.ts +5 -1
  551. package/src/self-dev/shard-run.ts +23 -5
  552. package/src/self-dev/supervisor-verdict-edges.ts +3 -4
  553. package/src/self-implement/blocked-draft-policy.ts +3 -19
  554. package/src/self-implement/budget-gate.ts +53 -13
  555. package/src/self-implement/child-context-composition.ts +139 -0
  556. package/src/self-implement/child-llm-preference.ts +13 -5
  557. package/src/self-implement/claude-acp-implement.ts +67 -0
  558. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  559. package/src/self-implement/flex-signals.ts +59 -0
  560. package/src/self-implement/follow-up-goals.ts +114 -38
  561. package/src/self-implement/frozen-merges.ts +8 -3
  562. package/src/self-implement/gate-baseline-reap.ts +157 -0
  563. package/src/self-implement/gate-baseline.ts +78 -16
  564. package/src/self-implement/gate-cli.ts +12 -2
  565. package/src/self-implement/gate-remote.ts +17 -6
  566. package/src/self-implement/goal-author-decompose.ts +10 -2
  567. package/src/self-implement/goal-author.ts +48 -13
  568. package/src/self-implement/goal-digest.ts +19 -0
  569. package/src/self-implement/graph-overlay-condition.ts +32 -0
  570. package/src/self-implement/graph-overlay-yaml.ts +41 -7
  571. package/src/self-implement/graph-templates.ts +33 -1
  572. package/src/self-implement/graph-yaml.ts +56 -0
  573. package/src/self-implement/headless-elanous-driver.ts +11 -9
  574. package/src/self-implement/heal-intake.ts +5 -1
  575. package/src/self-implement/host-regate.ts +120 -29
  576. package/src/self-implement/l8-merge-queue.ts +67 -5
  577. package/src/self-implement/merge-train.ts +131 -0
  578. package/src/self-implement/off-diff-evidence.ts +9 -0
  579. package/src/self-implement/orchestrator.ts +271 -25
  580. package/src/self-implement/review-finding-recurrence.ts +28 -0
  581. package/src/self-implement/rework-policy.ts +2 -1
  582. package/src/self-implement/round-summary-card.ts +63 -0
  583. package/src/self-implement/run-ledger.ts +4 -3
  584. package/src/self-implement/run-step-projection.ts +147 -0
  585. package/src/self-implement/run-stop.ts +1 -1
  586. package/src/self-implement/running-runs.ts +75 -5
  587. package/src/self-implement/seams.ts +83 -4
  588. package/src/self-implement/self-implement-cli.ts +12 -5
  589. package/src/self-implement/stop-autoheal.ts +69 -2
  590. package/src/self-implement/train-gate-remote.ts +158 -0
  591. package/src/session-runtime/index.ts +10 -1
  592. package/src/session-runtime/retry-api.ts +11 -1
  593. package/src/session-runtime/retry-policy.ts +2 -1
  594. package/src/skills/gift-install.ts +119 -0
  595. package/src/skills/runner.ts +59 -2
  596. package/src/skills/skill-feedback.ts +31 -1
  597. package/src/skills/skill-tier.ts +1 -0
  598. package/src/smart-wizard/capability-index.ts +231 -0
  599. package/src/smart-wizard/rung.ts +74 -0
  600. package/src/steward/launch.ts +22 -10
  601. package/src/steward/triage-budget.ts +62 -0
  602. package/src/steward/triage.ts +87 -24
  603. package/src/storage/file-lock.ts +8 -1
  604. package/src/task-agent/actions.ts +66 -5
  605. package/src/task-agent/card-evidence.ts +59 -13
  606. package/src/task-agent/completion-evidence.ts +5 -0
  607. package/src/task-agent/cover.ts +101 -3
  608. package/src/task-agent/judge.ts +20 -3
  609. package/src/task-agent/land-order-ledger.ts +95 -0
  610. package/src/task-agent/land-worktree.ts +201 -0
  611. package/src/task-agent/live-move-history.ts +219 -0
  612. package/src/task-agent/live-moves.ts +451 -34
  613. package/src/task-agent/parent-host.ts +117 -8
  614. package/src/task-agent/rejudge-on-head.ts +352 -0
  615. package/src/task-agent/review-prior-fix.ts +146 -0
  616. package/src/task-agent/review-result-capture.ts +218 -0
  617. package/src/task-agent/run-adopt.ts +136 -0
  618. package/src/task-agent/shadow.ts +154 -14
  619. package/src/task-agent/task-hand.ts +186 -14
  620. package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
  621. package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
  622. package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
  623. package/src/task-orchestrator/surfaces/pod-child-providers.ts +42 -0
  624. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  625. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +94 -7
  626. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  627. package/src/task-orchestrator/surfaces/pod-lease.ts +110 -17
  628. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +32 -3
  629. package/src/task-orchestrator/surfaces/pod-pool.ts +86 -18
  630. package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
  631. package/src/task-orchestrator/surfaces/self-implement-pod.ts +463 -50
  632. package/src/task-orchestrator/surfaces/self-implement.ts +25 -3
  633. package/src/telegram-service.ts +5 -1
  634. package/src/telegram.ts +17 -4
  635. package/src/time/format.ts +13 -4
  636. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  637. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  638. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  639. package/src/typecheck-ratchet.ts +1 -0
  640. package/src/user-config.ts +180 -32
  641. package/src/ux-sim/slash-menu-frames.ts +168 -0
  642. package/src/version/packed-revision.json +1 -1
  643. package/src/web-terminal/preview-tap-registry.ts +5 -2
  644. package/src/workflow-runtime/triggers/registry.ts +59 -0
  645. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  646. package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
  647. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  648. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  649. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  650. package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  652. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  653. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  654. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  656. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  661. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  670. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  671. package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  684. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  692. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  697. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  699. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  703. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  708. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  713. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  714. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  716. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  717. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  725. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  728. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  738. package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  741. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  745. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  746. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
  794. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
  795. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
  796. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  797. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  798. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  799. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  800. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  801. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  802. package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
  803. /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_ssgManifest.js +0 -0
@@ -6,18 +6,21 @@
6
6
  // ⛔ 토큰 «값»은 어디에도 출력하지 않는다 — accountId 앞 8자만(R-LLM2).
7
7
 
8
8
  import { readFile } from 'node:fs/promises';
9
- import { join, resolve } from 'node:path';
9
+ import { mkdirSync, openSync, closeSync, unlinkSync, readFileSync, writeFileSync, statSync, renameSync } from 'node:fs';
10
+ import { dirname, join, resolve } from 'node:path';
11
+ import { consumeCodexResetCredits, listCodexResetCredits } from '../budget/codex-reset-credits.js';
12
+ import { codexCredentialRoot, readAvailabilityState, writeAvailabilityState } from '../budget/codex-reset-credit-state.js';
10
13
  import {
11
14
  DEFAULT_CODEX_ACCOUNT, codexStoreKey, accountNameFromStoreKey, isValidAccountName, isCodexStoreKey,
12
15
  resolveCodexAccount, effectiveCodexHome, type CodexHomeSource, type CodexAccountResolution,
13
16
  } from './codex-account.js';
14
- import { authStorePath, defaultCodexHome, listProviders, loadTokens, saveTokens } from './store.js';
17
+ import { authStorePath, defaultCodexHome, isUnderTestRunner, listProviders, loadTokens, saveTokens } from './store.js';
15
18
  import { readFreshAvailabilityState, quotaSignalDir, readQuotaSignal, readQuotaSignalCredits, readQuotaSignalUsedPercent, readQuotaSignalObservedAt, readQuotaSignalObservedAtRaw } from '../budget/codex-reset-credit-state.js';
16
19
  import { creditPaceStatus } from '../budget/codex-credit-pace.js';
17
20
  import { loadLlmPolicy } from '../policy/llm-policy.js';
18
21
  import { getUserConfig } from '../user-config.js';
19
22
  import {
20
- decideCodexRotation, observeRotation, applyRotation, readCodexAccountRotationConfig, rotatedChildEnv,
23
+ decideCodexRotation, observeRotation, applyRotation, readCodexAccountRotationConfig, rotatedChildEnv, creditCandidatesByBalance, CODEX_CREDIT_RESERVE_DEFAULT,
21
24
  codexAccountThresholdPercent,
22
25
  type RotationCandidate,
23
26
  } from './codex-account-rotation.js';
@@ -26,9 +29,11 @@ import { emitDecision } from '../live/detail-switch.js';
26
29
  import { debug } from '../debug/log.js';
27
30
  import {
28
31
  decideFallback, normalizeFallbackChain, grokQuotaFromUsageSnapshot,
29
- type FallbackDecision, type FallbackInput, type RotationOutcome,
32
+ type FallbackDecision, type FallbackInput, type FallbackStep, type RotationOutcome,
30
33
  } from './fallback-chain.js';
31
34
  import { resolveGrokCredential } from '../grok/credential.js';
35
+ import { getOpenRouterApiKey } from '../config.js';
36
+ import { lookupOpenRouterModelSpec } from '../model-tier/llm-tier-map.js';
32
37
  import { sendOutbound } from '../domains/outbound-alert.js';
33
38
 
34
39
  type CodexAccountOutboundSender = (text: string, kind?: string) => boolean;
@@ -47,7 +52,7 @@ export function _setCodexAccountOutboundSenderForTesting(sender: CodexAccountOut
47
52
  /** ⛔⭐ 정적 import 로 읽는다 — 종전 `require()` 는 ESM 에서 «정의되지 않을 수 있고», 그러면
48
53
  * fail-soft 가 삼켜 ***config false 가 영영 무시된다***(리뷰 should-fix: 노브가 no-op 이 된다).
49
54
  * ⚠️ 순환 없음을 확인했다 — user-config 는 oauth 를 안 끌어온다. */
50
- type RotationConfig = { llm?: { codexAccountRotation?: boolean; codexAccountAlerts?: boolean; codexAccountRotationThresholdPercent?: unknown; codexAccountRotationThresholdPercentByAccount?: Readonly<Record<string, unknown>>; codexCreditsAllowed?: boolean; codexQuotaPolicy?: unknown; fallbackChain?: unknown } };
55
+ type RotationConfig = { llm?: { codexCreditReserve?: unknown; codexAccountRotation?: boolean; codexAccountAlerts?: boolean; codexAccountRotationThresholdPercent?: unknown; codexAccountRotationThresholdPercentByAccount?: Readonly<Record<string, unknown>>; codexCreditsAllowed?: boolean; codexResetAutoConsumePerDay?: number; codexQuotaPolicy?: unknown; fallbackChain?: unknown; openrouter?: { fallbackModel?: unknown } } };
51
56
 
52
57
  function readUserConfig(): RotationConfig {
53
58
  return getUserConfig();
@@ -254,6 +259,64 @@ function codexCreditsAllowedFromConfig(): boolean {
254
259
  return codexPolicyAllowsCredits(codexQuotaPolicyFromConfig());
255
260
  }
256
261
 
262
+ /** SUBSCRIPTION-EXHAUST-REROUTE — 크레딧 예비분 기본. 10-11 운영 실측: 잔액 29,401 · 하루 소모 25,132 → 2,000 ≈ 하루 소모의 8%
263
+ * (폴백이 서는 동안 계정을 0 으로 만들지 않는 몫). `llm.codexCreditReserve` 로 바꾼다(0 = 잔액 0 일 때만 넘김). */
264
+ export const DEFAULT_CODEX_CREDIT_RESERVE = CODEX_CREDIT_RESERVE_DEFAULT;
265
+ /** 예비분 넘김의 OpenRouter 모델(설정 `llm.openrouter.fallbackModel` 이 없을 때) — 대표 라우팅 «중» 시작 모델. */
266
+ export const CREDIT_RESERVE_OPENROUTER_MODEL = 'openrouter/z-ai/glm-5.3';
267
+
268
+ /** `llm.codexCreditReserve` — 유효하지 않거나 못 읽으면 기본(크레딧은 돈이라 예비분을 지킨다). */
269
+ export function codexCreditReserveFromConfig(): number {
270
+ try {
271
+ const raw = configReader().llm?.codexCreditReserve;
272
+ return typeof raw === 'number' && Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_CODEX_CREDIT_RESERVE;
273
+ } catch { return DEFAULT_CODEX_CREDIT_RESERVE; }
274
+ }
275
+
276
+ /** grok 자격 «존재» 판독 — 테스트 격리 심(실 자격을 안 읽게). */
277
+ let grokCredentialPresent: () => boolean = () => resolveGrokCredential() !== null;
278
+ export function _setGrokCredentialPresentForTesting(fn: (() => boolean) | null): void {
279
+ grokCredentialPresent = fn ?? (() => resolveGrokCredential() !== null);
280
+ }
281
+
282
+ /** 회전 판정이 쓸 크레딧 허가와 그 출처.
283
+ * - `policy` 정책이 credits(옛 codexCreditsAllowed=true) — 종전 그대로.
284
+ * - `chain-step` CODEX-CREDITS-STEP: 정책은 fallback 이지만 체인이 `codex-credits` 칸에 «닿는다»
285
+ * (앞 칸 grok 등을 지금 못 쓰고 · 잔액 확인된 계정이 있다) ⇒ 이번 판정만 크레딧 계정을 고른다.
286
+ * - `none` 크레딧 ✗(`why` = 칸을 못 쓴 이유 · 칸이 없으면 생략).
287
+ * ⛔ 칸 판정은 `decideFallback` 를 그대로 부른다 — 체인 의미를 여기서 다시 짓지 않는다. 이 판독은 네트워크를 안 친다. */
288
+ type RotationCreditsGrant =
289
+ | { readonly allowed: true; readonly via: 'policy' }
290
+ | { readonly allowed: true; readonly via: 'chain-step'; readonly skipped: readonly { readonly step: FallbackStep; readonly why: string }[]; readonly creditAccountCount: number }
291
+ | { readonly allowed: false; readonly via: 'none'; readonly why?: string };
292
+
293
+ function rotationCreditsGrant(candidates: readonly RotationCandidate[]): RotationCreditsGrant {
294
+ const policy = codexQuotaPolicyFromConfig();
295
+ if (codexPolicyAllowsCredits(policy)) return { allowed: true, via: 'policy' };
296
+ if (!codexPolicyAllowsFallback(policy)) return { allowed: false, via: 'none' };
297
+ try {
298
+ const { chain } = normalizeFallbackChain(configReader().llm?.fallbackChain);
299
+ if (!chain.includes('codex-credits')) return { allowed: false, via: 'none' };
300
+ const creditAccountCount = codexCreditAccountNames(candidates, codexCreditReserveFromConfig()).length;
301
+ const fallbackModel = configReader().llm?.openrouter?.fallbackModel;
302
+ const decision = decideFallback({
303
+ rotation: { reason: 'no-candidate' },
304
+ chain,
305
+ grokAvailable: grokCredentialPresent(),
306
+ grokQuota: readCachedGrokQuota(),
307
+ ...(chain.includes('openrouter') ? {
308
+ openrouterFallbackModel: typeof fallbackModel === 'string' ? fallbackModel : undefined,
309
+ openrouterAvailable: Boolean(getOpenRouterApiKey()?.trim()),
310
+ } : {}),
311
+ codexCreditsAvailable: creditAccountCount > 0,
312
+ });
313
+ if (decision.action === 'codex-credits') return { allowed: true, via: 'chain-step', skipped: decision.skipped, creditAccountCount };
314
+ return { allowed: false, via: 'none', why: decision.action === 'stay' ? decision.why : `earlier-step:${decision.action === 'switch-backend' ? decision.backend : decision.action}` };
315
+ } catch {
316
+ return { allowed: false, via: 'none', why: 'chain-unreadable' };
317
+ }
318
+ }
319
+
257
320
  function buildRotationCandidates(path: string, now: number, env: NodeJS.ProcessEnv = process.env): RotationCandidate[] {
258
321
  return listCodexAccountsInStore(path)
259
322
  .map((row) => {
@@ -272,12 +335,13 @@ function buildRotationCandidates(path: string, now: number, env: NodeJS.ProcessE
272
335
  storeKey: row.storeKey,
273
336
  home,
274
337
  reached: readQuotaSignal(now, home),
338
+ resetCreditAvailability: resetCreditAvailability(home, now),
275
339
  ...(usedPercent === undefined ? {} : { usedPercent }),
276
340
  ...(credits.balance === undefined ? {} : { creditBalance: credits.balance }),
277
341
  ...(credits.hasCredits === undefined ? {} : { hasCredits: credits.hasCredits }),
278
- };
342
+ } satisfies RotationCandidate;
279
343
  })
280
- .filter((c): c is RotationCandidate => c !== null);
344
+ .filter((c): c is NonNullable<typeof c> => c !== null);
281
345
  }
282
346
 
283
347
  function rotationCreditPace(candidates: readonly RotationCandidate[], now: number) {
@@ -359,7 +423,7 @@ function codexAccountAlertsEnabled(): boolean {
359
423
  }
360
424
  }
361
425
 
362
- function notifyCodexAccountEvent(event: 'rotation' | 'reset-credit-consumed', details: Record<string, unknown>, text: string): void {
426
+ function notifyCodexAccountEvent(event: 'rotation' | 'reset-credit-consumed' | 'credit-spend-start', details: Record<string, unknown>, text: string): boolean {
363
427
  // ⛔ 끄더라도 «조용히» 사라지지 않는다 — 「왜 알림이 안 오나」를 나중에 로그로 답할 수 있어야 한다.
364
428
  if (!codexAccountAlertsEnabled()) {
365
429
  debug.log('oauth.codex-account', 'outbound-suppressed', {
@@ -368,20 +432,106 @@ function notifyCodexAccountEvent(event: 'rotation' | 'reset-credit-consumed', de
368
432
  knob: 'llm.codexAccountAlerts',
369
433
  ...details,
370
434
  });
371
- return;
435
+ return false;
372
436
  }
373
- const attempt = () => {
437
+ try {
374
438
  const delivered = codexAccountOutboundSender(text, 'alert');
375
439
  debug.log('oauth.codex-account', 'outbound', { event, delivered, ...details });
376
- };
377
- try {
378
- attempt();
440
+ return delivered;
379
441
  } catch (error) {
380
442
  debug.log('oauth.codex-account', 'outbound-failed', {
381
443
  event,
382
444
  message: error instanceof Error ? error.message : String(error),
383
445
  ...details,
384
446
  }, { level: 'warn' });
447
+ return false;
448
+ }
449
+ }
450
+
451
+ /** 크레딧 알림 잠금 — 이식 가능한 `wx` 잠금 파일(⛔ `flock(1)` 은 macOS 운영 호스트에 «없다» — mbp·node-b 실측 10-11).
452
+ * 기다림 상한을 넘기거나 오래된(죽은 소유자) 잠금이면 «알림을 잃지 않는 쪽»으로 간다:
453
+ * 오래된 잠금은 걷고, 상한을 넘기면 잠금 없이 보낸다(최악은 같은 날 중복 1통 — 누락보다 낫다). */
454
+ const CREDIT_SPEND_ALERT_LOCK_STALE_MS = 60_000;
455
+ let creditSpendAlertLockWaitMs = 5_000;
456
+ /** 시험 전용 — 기다림 상한을 줄인다(null = 기본 5초). */
457
+ export function _setCreditSpendAlertLockWaitMsForTesting(ms: number | null): void {
458
+ creditSpendAlertLockWaitMs = ms ?? 5_000;
459
+ }
460
+
461
+ function sleepSync(ms: number): void {
462
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
463
+ }
464
+
465
+ /** 잠갔으면 true(호출자가 풀어야 한다) · 상한을 넘겨 잠금 없이 가면 false. */
466
+ function acquireCreditSpendAlertLock(path: string, account: string): boolean {
467
+ const deadline = Date.now() + creditSpendAlertLockWaitMs;
468
+ for (;;) {
469
+ try {
470
+ const fd = openSync(path, 'wx');
471
+ try { writeFileSync(fd, String(process.pid)); } finally { closeSync(fd); }
472
+ return true;
473
+ } catch (error) {
474
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
475
+ }
476
+ try {
477
+ if (Date.now() - statSync(path).mtimeMs > CREDIT_SPEND_ALERT_LOCK_STALE_MS) {
478
+ debug.log('oauth.codex-account', 'credit-spend-alert-lock-stale', { account });
479
+ try { unlinkSync(path); } catch { /* 다른 소유자가 먼저 걷었다 */ }
480
+ continue;
481
+ }
482
+ } catch { continue; /* 그 사이 풀렸다 */ }
483
+ if (Date.now() >= deadline) {
484
+ debug.log('oauth.codex-account', 'credit-spend-alert-lock-timeout', { account, waitMs: creditSpendAlertLockWaitMs }, { level: 'warn' });
485
+ return false;
486
+ }
487
+ sleepSync(50);
488
+ }
489
+ }
490
+
491
+ /** UTC 일자별 성공한 계정 알림만 기록한다. 잠근 채 발송하여 동시 런도 중복 발송하지 않는다. */
492
+ function notifyCreditSpendStart(
493
+ account: string,
494
+ reason: 'credits-allowed' | 'credit-pace',
495
+ usage: readonly RotationCandidate[],
496
+ now: number,
497
+ counterPath: string,
498
+ ): void {
499
+ const day = new Date(now).toISOString().slice(0, 10);
500
+ const lockPath = `${counterPath}.lock`;
501
+ let locked = false;
502
+ try {
503
+ mkdirSync(dirname(counterPath), { recursive: true });
504
+ locked = acquireCreditSpendAlertLock(lockPath, account);
505
+ let accounts: string[] = [];
506
+ try {
507
+ const parsed = JSON.parse(readFileSync(counterPath, 'utf8')) as { day?: unknown; accounts?: unknown };
508
+ if (parsed.day === day && Array.isArray(parsed.accounts)) {
509
+ accounts = parsed.accounts.filter((value): value is string => typeof value === 'string');
510
+ }
511
+ } catch (error) {
512
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
513
+ }
514
+ if (accounts.includes(account)) {
515
+ debug.log('oauth.codex-account', 'credit-spend-alert-skipped', { account, reason: 'already-alerted-today' });
516
+ return;
517
+ }
518
+ const usageSummary = usage.map((candidate) => `${candidate.name}=${formatUsedPercent(candidate.usedPercent)}`).join(', ') || 'unknown';
519
+ if (!notifyCodexAccountEvent('credit-spend-start', { account, reason, day },
520
+ `💳 Codex credits in use\naccount: ${account}\nreason: ${reason}\nusage: ${usageSummary}`)) return;
521
+ const tempPath = `${counterPath}.${process.pid}.${Date.now()}.tmp`;
522
+ try {
523
+ writeFileSync(tempPath, `${JSON.stringify({ day, accounts: [...accounts, account] })}\n`, 'utf8');
524
+ renameSync(tempPath, counterPath);
525
+ } finally {
526
+ try { unlinkSync(tempPath); } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
527
+ }
528
+ debug.log('oauth.codex-account', 'credit-spend-start', { account, reason, day }, { level: 'warn' });
529
+ } catch (error) {
530
+ debug.log('oauth.codex-account', 'credit-spend-alert-failed', {
531
+ account, message: error instanceof Error ? error.message : String(error),
532
+ }, { level: 'warn' });
533
+ } finally {
534
+ if (locked) { try { unlinkSync(lockPath); } catch { /* 이미 없다 */ } }
385
535
  }
386
536
  }
387
537
 
@@ -506,6 +656,8 @@ export function inspectCodexRotation(
506
656
  readonly candidateCount: number | undefined;
507
657
  readonly accountThresholds: ReturnType<typeof decideCodexRotation>['accountThresholds'];
508
658
  readonly to: string | undefined;
659
+ /** SUBSCRIPTION-EXHAUST-REROUTE — 크레딧 예비분에 닿아 `no-candidate` 가 됐을 때만 있다. */
660
+ readonly creditReserveHit?: { readonly balance: number; readonly reserve: number };
509
661
  } {
510
662
  const path = deps.storePath ?? authStorePath();
511
663
  const now = deps.now ?? Date.now();
@@ -526,7 +678,7 @@ export function inspectCodexRotation(
526
678
  const rawThreshold = rotationThresholdFromConfig();
527
679
  const thresholdPercentByAccount = rotationThresholdsByAccountFromConfig();
528
680
  const decision = decideCodexRotation({
529
- current, explicit, enabled, disabledProvenance: rotationConfig.state, currentReached, currentUsedPercent, accountOrder: accountOrderFromConfig(), resetCreditAvailability: resetCreditAvailability(currentHome, now), thresholdPercent: rawThreshold, thresholdPercentByAccount, creditsAllowed: codexCreditsAllowedFromConfig(), ...currentCredits, candidates, creditPace: rotationCreditPace(candidates, now),
681
+ current, explicit, enabled, disabledProvenance: rotationConfig.state, currentReached, currentUsedPercent, accountOrder: accountOrderFromConfig(), resetCreditAvailability: resetCreditAvailability(currentHome, now), thresholdPercent: rawThreshold, thresholdPercentByAccount, creditsAllowed: rotationCreditsGrant(candidates).allowed, creditReserve: codexCreditReserveFromConfig(), ...currentCredits, candidates, creditPace: rotationCreditPace(candidates, now),
530
682
  });
531
683
  // ⛔⭐ 나이는 «만료돼도» 낸다 — 「65분 전」과 「3일 전」은 다른 진단이다(리뷰 must-fix).
532
684
  const observedAtByHome: Record<string, number> = {};
@@ -548,6 +700,7 @@ export function inspectCodexRotation(
548
700
  candidates, observedAtByHome, freshByHome,
549
701
  knownAccountCount: listCodexAccountsInStore(path).length,
550
702
  reason: decision.reason, candidateCount: decision.candidateCount, accountThresholds: decision.accountThresholds, to: decision.to?.name,
703
+ ...(decision.creditReserveHit ? { creditReserveHit: decision.creditReserveHit } : {}),
551
704
  };
552
705
  }
553
706
 
@@ -556,7 +709,7 @@ export function resolveCodexAccountForRun(
556
709
  /** ⛔ 「설정을 우회하는 노브」를 두지 않는다(리뷰 must-fix) — 종전 `rotationEnabled` 는
557
710
  * 아무도 안 주면서 «config 를 덮을 수 있는» 인자였다. 그런 인자는 수용 기준을 스스로 깬다.
558
711
  * ⊕ `now` 도 아무도 안 주는 죽은 계약이라 지웠다. 남는 것은 «테스트 격리»뿐이다. */
559
- deps: { readonly storePath?: string } = {},
712
+ deps: { readonly storePath?: string; readonly counterPath?: string } = {},
560
713
  ): CodexAccountResolution {
561
714
  // ⛔ 「이름만 주고 홈을 안 준」 경우를 정본 기록으로 메운다 — 안 그러면 조용히 default 로 떨어지고
562
715
  // 관측은 `explicit` 이라 말한다(2026-08-11 72차 실측).
@@ -613,6 +766,7 @@ export function resolveCodexAccountForRun(
613
766
  const currentSignalAttributable = signalAttributableToAccount(currentHomeInfo);
614
767
 
615
768
  const creditPace = rotationCreditPace(candidates, now);
769
+ const creditsGrant = rotationCreditsGrant(candidates);
616
770
  const decision = decideCodexRotation({
617
771
  current,
618
772
  explicit,
@@ -624,11 +778,13 @@ export function resolveCodexAccountForRun(
624
778
  resetCreditAvailability: resetCreditAvailability(currentHome, now),
625
779
  thresholdPercent: rotationThresholdFromConfig(),
626
780
  thresholdPercentByAccount: rotationThresholdsByAccountFromConfig(),
627
- creditsAllowed: codexCreditsAllowedFromConfig(),
781
+ creditsAllowed: creditsGrant.allowed,
782
+ creditReserve: codexCreditReserveFromConfig(),
628
783
  ...currentCreditsInput(currentSignalAttributable ? currentHome : undefined, now),
629
784
  candidates,
630
785
  creditPace,
631
786
  });
787
+ observeCodexCreditsStep(creditsGrant, decision, current.name);
632
788
  debug.log('codex.rotation', 'credit-pace', {
633
789
  active: creditPace.active,
634
790
  todaySpent: creditPace.todaySpent,
@@ -636,6 +792,17 @@ export function resolveCodexAccountForRun(
636
792
  to: decision.reason === 'credit-pace' ? decision.to?.name ?? current.name : decision.to?.name,
637
793
  });
638
794
  observeRotation(decision, current.name);
795
+ // 발송 의무는 이 실행 경로에서 잠금 해제까지 기다린 뒤 하루 카운터에 기록한다.
796
+ if ((decision.reason === 'credits-allowed' || decision.reason === 'credit-pace') && !deps.counterPath && isUnderTestRunner(process.env)) {
797
+ // 시험 러너 가드(autoConsume 의 test-runtime-guard 와 같은 관용구) — 카운터를 주입 안 한 시험이 실제 카운터·송신기에 닿지 않는다.
798
+ debug.log('oauth.codex-account', 'credit-spend-alert-skipped', { account: decision.to?.name ?? current.name, reason: 'test-runtime-guard' });
799
+ } else if (decision.reason === 'credits-allowed' || decision.reason === 'credit-pace') {
800
+ notifyCreditSpendStart(decision.to?.name ?? current.name, decision.reason, candidates, now,
801
+ deps.counterPath ?? join(codexCredentialRoot(), 'budget', 'codex-credit-spend-alert.json'));
802
+ }
803
+ // 순서 ② — 구독 남은 계정이 없고 리셋권이 있으면 «스스로 1개» 쓴다(일일 상한 · 비동기 · 이번 호출은 종전대로 머문다).
804
+ // ⛔ 판정이 `reset-credit-available` 일 때만 닿는다 — 구독 남은 계정이 있으면(rotated) 여기 안 온다.
805
+ if (decision.reason === 'reset-credit-available') void autoConsumeCodexResetCredit({ storePath: path });
639
806
  const resolved = applyRotation(current, decision);
640
807
  if (resolved.source === 'rotated') {
641
808
  notifyCodexAccountEventWithUsage('rotation', path, now,
@@ -658,6 +825,111 @@ export function resolveCodexAccountForRun(
658
825
  return resolved;
659
826
  }
660
827
 
828
+ /** 리셋권 자동 소비 결과 — 소비했거나, 왜 안 했는지(관측 `reset-consume-skipped` 와 같은 이유). */
829
+ export type CodexResetAutoConsumeOutcome =
830
+ | { readonly consumed: true; readonly account: string; readonly expiresAt: string | null; readonly todayCount: number; readonly redecision?: string }
831
+ | { readonly consumed: false; readonly reason: 'disabled' | 'daily-cap-reached' | 'test-runtime-guard' | 'in-flight' | 'lock-held' | 'no-available-credit' | 'consume-failed' | 'error'; readonly detail?: string };
832
+
833
+ export interface CodexResetAutoConsumeDeps {
834
+ readonly storePath?: string;
835
+ readonly now?: number;
836
+ /** ⛔ 테스트는 «반드시» 가짜를 준다 — 안 주면 실물이고, 테스트 러너 안에서는 실물을 «부르지 않는다». */
837
+ readonly consume?: typeof consumeCodexResetCredits;
838
+ readonly list?: typeof listCodexResetCredits;
839
+ /** 일일 카운터 파일(테스트 격리). 기본 = 자격 뿌리 `budget/codex-reset-auto-consume.json`. */
840
+ readonly counterPath?: string;
841
+ readonly env?: NodeJS.ProcessEnv;
842
+ }
843
+
844
+ /** `llm.codexResetAutoConsumePerDay` — 기본 1 · 0 이면 끔 · 못 읽으면 기본. */
845
+ function resetAutoConsumePerDayFromConfig(): number {
846
+ try {
847
+ const v = (configReader().llm as { codexResetAutoConsumePerDay?: unknown } | undefined)?.codexResetAutoConsumePerDay;
848
+ return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 ? v : 1;
849
+ } catch { return 1; }
850
+ }
851
+
852
+ function readAutoConsumeCount(path: string, day: string): number {
853
+ try {
854
+ const parsed = JSON.parse(readFileSync(path, 'utf8')) as { day?: unknown; count?: unknown };
855
+ return parsed.day === day && typeof parsed.count === 'number' && Number.isFinite(parsed.count) ? parsed.count : 0;
856
+ } catch { return 0; }
857
+ }
858
+
859
+ let autoConsumeInFlight = false;
860
+
861
+ /**
862
+ * 순서 ② «리셋권» — 만료가 가장 이른 계정의 리셋권을 «하나» 쓴다. ⛔ 되돌릴 수 없다.
863
+ * ⛔ 소비는 기존 `consumeCodexResetCredits` 한 연산뿐이다(새 API 경로 없음).
864
+ * ⛔ 하루 상한(UTC 일) — 소비 «전»에 칸을 잡는다(실패해도 그날 칸은 쓴 것으로 센다: 되돌릴 수 없는 일은 덜 하는 쪽).
865
+ * 성공 → `codex.rotation reset-consumed` ⊕ 소비 알림 ⊕ 판정을 한 번 다시 돈다(조회 전용).
866
+ * 실패·상한 → `codex.rotation reset-consume-skipped { reason }` — 호출부는 종전대로 크레딧 단계로 간다.
867
+ */
868
+ export async function autoConsumeCodexResetCredit(deps: CodexResetAutoConsumeDeps = {}): Promise<CodexResetAutoConsumeOutcome> {
869
+ const skip = (reason: Extract<CodexResetAutoConsumeOutcome, { consumed: false }>['reason'], extra: Record<string, unknown> = {}): CodexResetAutoConsumeOutcome => {
870
+ debug.log('codex.rotation', 'reset-consume-skipped', { reason, ...extra });
871
+ return { consumed: false, reason, ...(typeof extra.detail === 'string' ? { detail: extra.detail } : {}) };
872
+ };
873
+ const cap = resetAutoConsumePerDayFromConfig();
874
+ if (cap <= 0) return skip('disabled', { cap });
875
+ const now = deps.now ?? Date.now();
876
+ const day = new Date(now).toISOString().slice(0, 10);
877
+ const counterPath = deps.counterPath ?? join(codexCredentialRoot(), 'budget', 'codex-reset-auto-consume.json');
878
+ const before = readAutoConsumeCount(counterPath, day);
879
+ if (before >= cap) return skip('daily-cap-reached', { cap, todayCount: before });
880
+ // ⛔⭐ 되돌릴 수 없는 실물 소비를 테스트가 «절대» 못 부르게 — 가짜를 안 줬고 테스트 러너면 멈춘다.
881
+ if ((!deps.consume || !deps.list) && isUnderTestRunner(deps.env ?? process.env)) return skip('test-runtime-guard');
882
+ const consume = deps.consume ?? consumeCodexResetCredits;
883
+ const list = deps.list ?? listCodexResetCredits;
884
+ if (autoConsumeInFlight) return skip('in-flight');
885
+ const lockPath = `${counterPath}.lock`;
886
+ let lockFd: number | undefined;
887
+ autoConsumeInFlight = true;
888
+ try {
889
+ mkdirSync(dirname(counterPath), { recursive: true });
890
+ try { lockFd = openSync(lockPath, 'wx'); } catch {
891
+ // 죽은 프로세스가 남긴 잠금(10분 넘음)은 걷고 한 번만 다시 잡는다 — 안 그러면 자동 소비가 영영 꺼진다.
892
+ try { if (now - statSync(lockPath).mtimeMs > 10 * 60_000) { unlinkSync(lockPath); lockFd = openSync(lockPath, 'wx'); } } catch { /* */ }
893
+ if (lockFd === undefined) return skip('lock-held');
894
+ }
895
+ // 다른 프로세스가 방금 썼을 수 있다 — 잠근 «뒤»에 다시 센다.
896
+ const locked = readAutoConsumeCount(counterPath, day);
897
+ if (locked >= cap) return skip('daily-cap-reached', { cap, todayCount: locked });
898
+ const path = deps.storePath ?? authStorePath();
899
+ let earliest: { name: string; home: string; expiresAt: string | null; expiresMs: number } | undefined;
900
+ for (const candidate of buildRotationCandidates(path, now, deps.env ?? process.env)) {
901
+ if (!candidate.home) continue;
902
+ const listed = await list({ authFilePath: join(candidate.home, 'auth.json'), env: { CODEX_HOME: candidate.home } as unknown as NodeJS.ProcessEnv });
903
+ if (!listed.ok) continue;
904
+ for (const credit of listed.value.credits) {
905
+ if (credit.status !== 'available' || credit.redeemed_at) continue;
906
+ const ms = credit.expires_at ? Date.parse(credit.expires_at) : Number.POSITIVE_INFINITY;
907
+ const expiresMs = Number.isFinite(ms) || ms === Number.POSITIVE_INFINITY ? ms : Number.POSITIVE_INFINITY;
908
+ if (!earliest || expiresMs < earliest.expiresMs) earliest = { name: candidate.name, home: candidate.home, expiresAt: credit.expires_at, expiresMs };
909
+ }
910
+ }
911
+ if (!earliest) return skip('no-available-credit');
912
+ const todayCount = locked + 1;
913
+ writeFileSync(counterPath, `${JSON.stringify({ day, count: todayCount, lastAccount: earliest.name, at: new Date(now).toISOString() })}\n`, 'utf8');
914
+ const result = await consume({ authFilePath: join(earliest.home, 'auth.json'), env: { CODEX_HOME: earliest.home } as unknown as NodeJS.ProcessEnv });
915
+ if (!result.ok) return skip('consume-failed', { account: earliest.name, kind: result.kind, detail: result.message.slice(0, 200), todayCount });
916
+ const previous = readAvailabilityState(earliest.home);
917
+ const remaining = typeof previous === 'number' ? Math.max(0, previous - 1) : undefined;
918
+ if (remaining !== undefined) { try { writeAvailabilityState(remaining, earliest.home); } catch { /* 관측 갱신 실패는 소비를 되돌리지 않는다 */ } }
919
+ debug.log('codex.rotation', 'reset-consumed', { account: earliest.name, expiresAt: earliest.expiresAt, todayCount });
920
+ notifyCodexResetCreditConsumed({ name: earliest.name }, remaining, { storePath: path, now });
921
+ // 판정을 한 번 다시 돈다 — 조회 전용(관측·고정 없음). 다음 런 판정이 그 계정을 구독으로 고른다.
922
+ let redecision: string | undefined;
923
+ try { redecision = inspectCodexRotation(deps.env ?? process.env, { storePath: path }).reason; } catch { /* 재판정 실패는 소비 결과를 바꾸지 않는다 */ }
924
+ return { consumed: true, account: earliest.name, expiresAt: earliest.expiresAt, todayCount, ...(redecision ? { redecision } : {}) };
925
+ } catch (error) {
926
+ return skip('error', { detail: error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200) });
927
+ } finally {
928
+ if (lockFd !== undefined) { try { closeSync(lockFd); } catch { /* */ } try { unlinkSync(lockPath); } catch { /* */ } }
929
+ autoConsumeInFlight = false;
930
+ }
931
+ }
932
+
661
933
  /**
662
934
  * ⛔⭐⭐⭐⭐⭐ **회전한 계정을 «자식 env»로만 내려보낸다** (2026-08-07 · 크레딧 유출 차단).
663
935
  *
@@ -731,6 +1003,65 @@ export function listCodexAccountsInStore(storePath?: string): StoredCodexAccount
731
1003
  * ⛔ 실패는 삼키되 «조용히»는 아니다 — 못 정했으면 그 사실을 관측에 남기고 `stay` 로 답한다.
732
1004
  * (판정이 못 돌아서 백엔드가 안 뜨는 일은 없어야 한다.)
733
1005
  */
1006
+ /** CODEX-CREDITS-STEP 관측 — 회전이 «구독이 다 찬» 판정에 닿았을 때만(크레딧으로 갔든 · 칸을 못 써 건너뛰었든) 한 줄.
1007
+ * ⛔ 비밀·홈 경로를 넣지 않는다(계정 이름 · 이유 · 건너뛴 칸). */
1008
+ function observeCodexCreditsStep(
1009
+ grant: RotationCreditsGrant,
1010
+ decision: { readonly reason: string; readonly to?: RotationCandidate; readonly accountThresholds?: readonly { readonly name: string; readonly status: string }[] },
1011
+ currentName: string,
1012
+ ): void {
1013
+ if (grant.via === 'policy') return;
1014
+ // 회전이 «크레딧 계정»으로 옮겼나 — 고른 계정의 구독 창이 이미 찼으면 크레딧 회전이다(구독 회전과 가른다).
1015
+ const toStatus = decision.to ? decision.accountThresholds?.find((row) => row.name === decision.to!.name)?.status : undefined;
1016
+ const creditRotation = decision.reason === 'rotated' && (toStatus === 'reached' || toStatus === 'threshold-reached');
1017
+ if (grant.via === 'chain-step' && (decision.reason === 'credits-allowed' || creditRotation)) {
1018
+ debug.log('oauth.fallback-chain', 'codex-credits-step', {
1019
+ site: 'rotation', outcome: 'credits', rotationReason: decision.reason, from: currentName, to: decision.to?.name ?? currentName,
1020
+ skipped: grant.skipped, creditAccountCount: grant.creditAccountCount,
1021
+ }, { level: 'warn' });
1022
+ } else if (grant.via === 'none' && decision.reason === 'no-candidate' && grant.why === 'codex-credits-unavailable') {
1023
+ debug.log('oauth.fallback-chain', 'codex-credits-step', {
1024
+ site: 'rotation', outcome: 'skipped', rotationReason: decision.reason, why: grant.why,
1025
+ });
1026
+ }
1027
+ }
1028
+
1029
+ /** 크레딧 잔액이 «확인된» codex 계정 이름(잔액 > 0 · 보유 ≠ false · 홈을 안다). 잔액을 모르면 넣지 않는다 — 돈이라 fail-closed.
1030
+ * (budget-gate `codexCreditCandidate` 와 같은 자.) */
1031
+ export function codexCreditAccountNames(candidates: readonly RotationCandidate[], reserve = 0): string[] {
1032
+ return creditCandidatesByBalance(candidates, reserve).map((c) => c.name);
1033
+ }
1034
+
1035
+ /** 명시 계정 «자신»의 크레딧 잔액이 확인되나(잔액 > 0 · 보유 ≠ false) — 신호를 귀속 못 하면 후보 목록의 같은 이름 줄. */
1036
+ function explicitAccountHasCredits(snapshot: {
1037
+ readonly current: { readonly name: string };
1038
+ readonly candidates: readonly RotationCandidate[];
1039
+ readonly currentCreditBalance?: number;
1040
+ readonly currentHasCredits?: boolean;
1041
+ }, reserve = 0): boolean {
1042
+ const self = snapshot.candidates.find((c) => c.name === snapshot.current.name);
1043
+ const balance = snapshot.currentCreditBalance ?? self?.creditBalance;
1044
+ const has = snapshot.currentHasCredits ?? self?.hasCredits;
1045
+ return typeof balance === 'number' && Number.isFinite(balance) && balance > reserve && has !== false;
1046
+ }
1047
+
1048
+ /** 명시 계정 자신을 후보 모양으로 — 홈을 모르면 없다(그때는 호스트 홈 그대로). */
1049
+ function explicitAccountCandidate(snapshot: {
1050
+ readonly current: { readonly name: string; readonly storeKey: string };
1051
+ readonly currentHome?: string;
1052
+ readonly candidates: readonly RotationCandidate[];
1053
+ }): RotationCandidate | undefined {
1054
+ const self = snapshot.candidates.find((c) => c.name === snapshot.current.name && c.home.length > 0);
1055
+ if (self) return self;
1056
+ const home = snapshot.currentHome?.trim();
1057
+ return home ? { name: snapshot.current.name, storeKey: snapshot.current.storeKey, home, reached: undefined } : undefined;
1058
+ }
1059
+
1060
+ /** 잔액이 가장 많은(확인된) 계정 — 크레딧 칸이 실제로 쓸 계정. */
1061
+ function richestCreditCandidate(candidates: readonly RotationCandidate[], reserve = 0): RotationCandidate | undefined {
1062
+ return creditCandidatesByBalance(candidates, reserve)[0];
1063
+ }
1064
+
734
1065
  export function resolveRunFallback(
735
1066
  env: NodeJS.ProcessEnv = process.env,
736
1067
  deps: {
@@ -738,6 +1069,10 @@ export function resolveRunFallback(
738
1069
  readonly grokAvailable?: boolean;
739
1070
  /** ⛔ grok «잔량» seam — 안 주면 재지 «않고» 'unknown' 이다(이 판정은 네트워크를 안 친다). */
740
1071
  readonly grokQuota?: 'usable' | 'exhausted' | 'unknown';
1072
+ /** OpenRouter 키 «존재» seam(테스트 격리) — 안 주면 `getOpenRouterApiKey()` 로 잰다. 키 값은 기록하지 않는다. */
1073
+ readonly openrouterAvailable?: boolean;
1074
+ /** codex 크레딧 잔액 «확인» seam — 안 주면 회전 후보의 크레딧 신호(잔액 > 0 · 보유 ≠ false)로 잰다. */
1075
+ readonly codexCreditsAvailable?: boolean;
741
1076
  } & Pick<FallbackInput, 'currentStep' | 'currentCredentialRateLimited'> = {},
742
1077
  ): FallbackDecision {
743
1078
  try {
@@ -773,19 +1108,62 @@ export function resolveRunFallback(
773
1108
  // ⛔ grok 가용성은 «호출자가 확정»해서 줄 수 있다(테스트 격리). 안 주면 여기서 잰다.
774
1109
  // ⛔ «가용성 판정»이라 갱신을 유도하지 않는다 — 「자격이 있나」만 묻지 「지금 쓸 수 있나」를 묻지 않는다.
775
1110
  // (쓸 수 있는지는 실제 요청 경로가 접힌 해석으로 확인한다.)
776
- const grokAvailable = deps.grokAvailable ?? resolveGrokCredential() !== null;
1111
+ const grokAvailable = deps.grokAvailable ?? grokCredentialPresent();
777
1112
  // ⛔ 「지금 쓸 수 있나」는 «자격과 다른 축»이다. 안 주면 'unknown' — 그리고 unknown 은 «통과»다.
778
1113
  // ⇒ 「모르고 갔다」와 「알고 갔다」가 관측에서 갈린다(아래 grokQuota).
779
1114
  const grokQuota = deps.grokQuota ?? readCachedGrokQuota();
780
- const fallbackBase = { rotation, chain, grokAvailable, grokQuota };
1115
+ const fallbackModel = configReader().llm?.openrouter?.fallbackModel;
1116
+ // SUBSCRIPTION-EXHAUST-REROUTE — 크레딧 예비분에 닿은 «넘김»은 OpenRouter 가 먼저다(대표 OP 10-11: grok 이 아니다).
1117
+ // 운영 체인 `['codex-rotate','grok']` 에는 openrouter 칸이 없다 ⇒ 이 경로에만 codex 바로 뒤에 openrouter 를 끼운다
1118
+ // (나머지 칸은 그 뒤 · 키가 없으면 종전 체인으로). 모델은 `llm.openrouter.fallbackModel`, 없으면 «중» 기본 glm-5.3.
1119
+ // ⛔ 정책이 within-quota 면 체인 밖으로 안 나간다(종전 규칙 그대로).
1120
+ const reserveHit = snapshot.creditReserveHit;
1121
+ const reserveReroute = reserveHit !== undefined && codexPolicyAllowsFallback(quotaPolicy);
1122
+ const effectiveChain: readonly FallbackStep[] = reserveReroute
1123
+ ? ['codex-rotate', 'openrouter', ...chain.filter((step) => step !== 'codex-rotate' && step !== 'openrouter')]
1124
+ : chain;
1125
+ const openrouterFallbackModel = typeof fallbackModel === 'string' && fallbackModel.trim()
1126
+ ? fallbackModel
1127
+ : reserveReroute ? CREDIT_RESERVE_OPENROUTER_MODEL : undefined;
1128
+ const openrouterAvailable = effectiveChain.includes('openrouter')
1129
+ && (deps.openrouterAvailable ?? Boolean(getOpenRouterApiKey()?.trim()));
1130
+ // CODEX-CREDITS-STEP — 체인에 그 칸이 있을 때만 잰다(없으면 판정이 안 읽는다). 잔액을 «모르면» 없다고 본다(돈 · fail-closed).
1131
+ // ⛔ 사람이 계정을 «명시»했으면 그 계정의 잔액만 본다 — 다른 계정 잔액으로 칸을 열고 명시 계정으로 쏘면 fail-closed 가 깨진다.
1132
+ const explicitAccount = snapshot.reason === 'explicit';
1133
+ const creditReserve = codexCreditReserveFromConfig();
1134
+ const creditAccounts = !effectiveChain.includes('codex-credits') ? []
1135
+ : explicitAccount ? (explicitAccountHasCredits(snapshot, creditReserve) ? [snapshot.current.name] : [])
1136
+ : codexCreditAccountNames(snapshot.candidates, creditReserve);
1137
+ const codexCreditsAvailable = effectiveChain.includes('codex-credits') && (deps.codexCreditsAvailable ?? creditAccounts.length > 0);
1138
+ const fallbackBase = { rotation, chain: effectiveChain, grokAvailable, grokQuota, openrouterFallbackModel, openrouterAvailable, codexCreditsAvailable };
781
1139
  const fallbackInput: FallbackInput = deps.currentCredentialRateLimited === true && deps.currentStep
782
1140
  ? { ...fallbackBase, currentStep: deps.currentStep, currentCredentialRateLimited: true }
783
1141
  : { ...fallbackBase, ...(deps.currentStep ? { currentStep: deps.currentStep } : {}) };
784
- const decision = decideFallback(fallbackInput);
1142
+ const judged = decideFallback(fallbackInput);
1143
+ // CODEX-CREDITS-STEP — 칸에 닿았으면 «어느 계정 크레딧으로» 갈지도 정한다(잔액 많은 순 · 홈을 안다).
1144
+ // 런타임 재시도(grok 429)는 회전을 다시 거치지 않으므로 여기서 계정을 실어 보내야 자식이 그 계정으로 뜬다.
1145
+ // ⛔ 사람이 계정을 «명시»했으면(explicit) 계정을 바꾸지 않는다 — 의도가 이긴다(그 계정 그대로 크레딧).
1146
+ // 명시 계정이면 «그 계정»의 홈을 싣는다 — 계정은 안 바꾸되, 잔액을 확인한 계정과 발사 홈이 갈리지 않게.
1147
+ const creditTo = judged.action !== 'codex-credits' ? undefined
1148
+ : explicitAccount ? explicitAccountCandidate(snapshot)
1149
+ : richestCreditCandidate(snapshot.candidates, creditReserve);
1150
+ const decision: FallbackDecision = judged.action === 'codex-credits' && creditTo ? { ...judged, to: creditTo } : judged;
1151
+ if (reserveHit) {
1152
+ debug.log('llm.codex', 'credit-reserve-hit', {
1153
+ balance: reserveHit.balance, reserve: reserveHit.reserve,
1154
+ next: decision.action === 'switch-backend' ? decision.backend : decision.action === 'codex-rotate' ? 'codex-rotate' : decision.action === 'codex-credits' ? 'codex-credits' : `stay:${decision.why}`,
1155
+ ...(decision.action === 'switch-backend' && decision.backend === 'openrouter' ? { model: decision.model } : {}),
1156
+ openrouterAvailable, rerouted: reserveReroute,
1157
+ }, { level: 'warn' });
1158
+ }
1159
+ // tier-map 칸(가격·창 근거) — 유료 전환은 «무슨 값으로 가는지»를 관측에 남긴다. 미등록이면 'unregistered'.
1160
+ const openrouterSpec = decision.action === 'switch-backend' && decision.backend === 'openrouter'
1161
+ ? lookupOpenRouterModelSpec(decision.model) : undefined;
785
1162
 
786
1163
  debug.log('oauth.fallback-chain', 'decide', {
787
1164
  rotationReason: rotation.reason,
788
- chain, usedDefault, quotaPolicy,
1165
+ chain: effectiveChain, usedDefault, quotaPolicy,
1166
+ ...(reserveHit ? { creditReserveHit: true } : {}),
789
1167
  rotationResult: rotation.reason,
790
1168
  // ⛔⭐ 「안 줬다」를 «false 로 접지 않는다»(무인 리뷰 must-fix · UNKNOWN-DEFAULT).
791
1169
  // 호출자가 이 값을 생략하면 그것은 「한도가 아니었다」가 «아니라» ***「안 쟀다」***다.
@@ -793,20 +1171,70 @@ export function resolveRunFallback(
793
1171
  credentialRateLimited: fallbackInput.currentCredentialRateLimited === undefined
794
1172
  ? 'unknown'
795
1173
  : fallbackInput.currentCredentialRateLimited === true,
796
- selectedChainStep: decision.action === 'codex-rotate' ? 'codex-rotate' : decision.action === 'switch-backend' ? decision.backend : null,
1174
+ selectedChainStep: decision.action === 'codex-rotate' ? 'codex-rotate' : decision.action === 'switch-backend' ? decision.backend : decision.action === 'codex-credits' ? 'codex-credits' : null,
797
1175
  ...(dropped.length > 0 ? { droppedSteps: dropped } : {}),
798
1176
  grokAvailable,
799
1177
  grokQuota,
1178
+ ...(effectiveChain.includes('openrouter') ? { openrouterAvailable, openrouterModelConfigured: Boolean(openrouterFallbackModel?.trim()) } : {}),
800
1179
  action: decision.action,
801
1180
  ...(decision.action === 'switch-backend' ? { backend: decision.backend } : {}),
1181
+ ...(decision.action === 'switch-backend' && decision.backend === 'openrouter'
1182
+ ? { model: decision.model, modelSpec: openrouterSpec ? `${openrouterSpec.label} · ${openrouterSpec.rationale}` : 'unregistered' }
1183
+ : {}),
802
1184
  ...(decision.action === 'stay' ? { why: decision.why } : {}),
803
1185
  ...(decision.action === 'codex-rotate' ? { to: decision.to.name } : {}),
804
1186
  });
805
- if (decision.action === 'switch-backend') {
1187
+ // 칸에 «닿았나» — 판정이 체인을 걸었고(한도 오류 재시도 · codex 축이 끝남) 그 걸음이 칸을 지났나.
1188
+ // 최종 결정과 무관하다: 칸을 건너뛰고 뒤 칸으로 갔든, 뒤 칸까지 못 써 머물렀든 도달은 도달이다.
1189
+ const selectedStep: FallbackStep | undefined = decision.action === 'switch-backend'
1190
+ ? (decision.backend === 'claude' ? 'claude-pty' : decision.backend) : undefined;
1191
+ const walked = fallbackInput.currentCredentialRateLimited === true
1192
+ || rotation.reason === 'no-candidate' || rotation.reason === 'disabled' || rotation.reason === 'reset-credit-available'
1193
+ || ('to' in rotation && !chain.includes('codex-rotate'));
1194
+ const walkStart = fallbackInput.currentCredentialRateLimited === true ? fallbackInput.currentStep : 'codex-rotate';
1195
+ const walkIdx = walkStart === undefined ? -1 : chain.indexOf(walkStart);
1196
+ const walkRest = walkIdx === -1 ? chain : chain.slice(walkIdx + 1);
1197
+ const reachedCredits = walked && walkRest.includes('codex-credits')
1198
+ && (selectedStep === undefined || walkRest.indexOf('codex-credits') < walkRest.indexOf(selectedStep));
1199
+ if (reachedCredits && decision.action !== 'codex-credits') {
1200
+ // 칸에 «닿았지만» 잔액 확인된 계정이 없어 못 썼다 — 실패한 도달도 이유와 함께 남긴다.
1201
+ debug.log('oauth.fallback-chain', 'codex-credits-step', {
1202
+ site: 'chain', outcome: 'skipped', why: 'codex-credits-unavailable', next: selectedStep ?? null, rotationReason: rotation.reason, quotaPolicy, chain,
1203
+ grokAvailable, grokQuota, currentStep: fallbackInput.currentStep ?? null,
1204
+ credentialRateLimited: fallbackInput.currentCredentialRateLimited === true,
1205
+ });
1206
+ }
1207
+ if (decision.action === 'codex-credits') {
1208
+ // ⭐ 체인이 «마지막 칸»(유료)에 닿을 때마다 한 줄 — 왜 앞 칸들을 못 썼나를 값으로(비밀·홈 경로 없음).
1209
+ debug.log('oauth.fallback-chain', 'codex-credits-step', {
1210
+ site: 'chain', outcome: 'credits',
1211
+ to: decision.to?.name ?? null,
1212
+ rotationReason: rotation.reason,
1213
+ quotaPolicy,
1214
+ chain,
1215
+ skipped: decision.skipped,
1216
+ grokAvailable,
1217
+ grokQuota,
1218
+ currentStep: fallbackInput.currentStep ?? null,
1219
+ credentialRateLimited: fallbackInput.currentCredentialRateLimited === true,
1220
+ creditAccountCount: deps.codexCreditsAvailable === undefined ? creditAccounts.length : 'seam',
1221
+ }, { level: 'warn' });
1222
+ emitDecision({
1223
+ kind: 'ROUTE',
1224
+ what: '공급자 codex(크레딧) — 체인 마지막 칸',
1225
+ reason: `회전 ${rotation.reason} · 정책 ${quotaPolicy} · 건너뜀 ${decision.skipped.map((x) => `${x.step}:${x.why}`).join(', ') || '없음'}${fallbackInput.currentCredentialRateLimited ? ' · 한도 오류' : ''}`,
1226
+ purpose: '구독·grok 이 모두 막혀 선불 크레딧으로 작업을 이어 간다',
1227
+ target: 'openai-codex(credits)',
1228
+ paths: chain.length,
1229
+ });
1230
+ } else if (decision.action === 'switch-backend') {
1231
+ const openrouterNote = decision.backend === 'openrouter'
1232
+ ? ` · API 과금 ${decision.model} (${openrouterSpec ? `${openrouterSpec.label} · ${openrouterSpec.rationale}` : 'tier-map 미등록'})`
1233
+ : '';
806
1234
  emitDecision({
807
1235
  kind: 'ROUTE',
808
1236
  what: `공급자 전환 codex → ${decision.backend}`,
809
- reason: `회전 ${rotation.reason} · 정책 ${quotaPolicy}${fallbackInput.currentCredentialRateLimited ? ' · 한도 오류' : ''}`,
1237
+ reason: `회전 ${rotation.reason} · 정책 ${quotaPolicy}${openrouterNote}${fallbackInput.currentCredentialRateLimited ? ' · 한도 오류' : ''}`,
810
1238
  purpose: '작업을 멈추지 않고 이어 간다',
811
1239
  target: decision.backend,
812
1240
  paths: chain.length,