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
@@ -21,8 +21,14 @@
21
21
  import type { RotationCandidate } from './codex-account-rotation.js';
22
22
  import type { ClaudePtyMaturity } from './claude-pty-maturity.js';
23
23
 
24
- /** 체인에 놓을 수 있는 칸. ⛔ 모르는 이름은 «조용히 건너뛰지 않고» 거부한다(오타 방어). */
25
- export const FALLBACK_STEPS = ['codex-rotate', 'grok', 'claude-pty'] as const;
24
+ /** 체인에 놓을 수 있는 칸. ⛔ 모르는 이름은 «조용히 건너뛰지 않고» 거부한다(오타 방어).
25
+ *
26
+ * ⭐ `codex-credits`(CODEX-CREDITS-STEP · 2026-10-10) — «마지막 수단»으로 codex 를 «선불 크레딧»으로 쓴다.
27
+ * 한도 정책이 `fallback`(크레딧 ✗)이면 회전은 찬 계정에 «머물지» 않고(`no-candidate`) 체인의 다음 칸(grok)으로 간다.
28
+ * 그 grok 마저 못 쓰면 갈 곳이 없었다 — 이 칸을 grok «뒤»에 두면 그때만 크레딧으로 돌아온다.
29
+ * ⛔ 첫 칸의 크레딧 금지(`codexQuotaPolicy`)는 그대로다 — 이 칸은 «체인이 여기까지 왔을 때»만 돈을 쓴다.
30
+ * ⛔ 기본 체인에는 «없다» — 돈이라 사람이 config 에 «명시»할 때만 켜진다. */
31
+ export const FALLBACK_STEPS = ['codex-rotate', 'grok', 'claude-pty', 'openrouter', 'codex-credits'] as const;
26
32
  export type FallbackStep = (typeof FALLBACK_STEPS)[number];
27
33
 
28
34
  /** 기본 체인 — ⛔⭐ **2026-08-20 에 `grok` 이 «기본»으로 들어왔다**(대표 지시).
@@ -78,6 +84,16 @@ export type FallbackDecision =
78
84
  | { readonly action: 'codex-rotate'; readonly to: RotationCandidate }
79
85
  /** 백엔드를 통째로 바꾼다. */
80
86
  | { readonly action: 'switch-backend'; readonly backend: 'grok' | 'claude' }
87
+ /** 명시한 유료 OpenRouter 모델로 전환한다. 호출부가 모델을 바꾸지 못하면 실행하지 않는다. */
88
+ | { readonly action: 'switch-backend'; readonly backend: 'openrouter'; readonly model: string }
89
+ /** codex 로 «돌아와» 선불 크레딧으로 계속한다 — 체인의 `codex-credits` 칸(마지막 수단 · 유료).
90
+ * `skipped` 는 «왜 앞 칸들을 못 썼나»(관측용 · 비밀 없음). */
91
+ | {
92
+ readonly action: 'codex-credits';
93
+ readonly skipped: readonly { readonly step: FallbackStep; readonly why: StayReason }[];
94
+ /** 크레딧으로 쓸 계정(잔액 많은 순 첫 계정) — 순수 판정은 비우고, 수집기(`resolveRunFallback`)가 채운다. */
95
+ readonly to?: RotationCandidate;
96
+ }
81
97
  /** 아무것도 안 한다 — 이유를 «값으로» 남긴다. */
82
98
  | { readonly action: 'stay'; readonly why: StayReason };
83
99
 
@@ -98,8 +114,12 @@ export type StayReason =
98
114
  | 'grok-unavailable'
99
115
  /** grok 자격은 있는데 «잔량이 소진»됐다 — 자격 부재와 «다른 값»이다. */
100
116
  | 'grok-exhausted'
117
+ /** 유료 OpenRouter 모델 또는 키가 없다. */
118
+ | 'openrouter-unavailable'
101
119
  /** claude PTY 의 최근 표본이 성숙 관문을 통과하지 못했거나 읽히지 않는다. */
102
- | 'claude-pty-immature';
120
+ | 'claude-pty-immature'
121
+ /** 체인에 `codex-credits` 가 있는데 크레딧 잔액이 «확인된» codex 계정이 없다(모름 포함 — 돈이라 fail-closed). */
122
+ | 'codex-credits-unavailable';
103
123
 
104
124
  type FallbackRunPosition =
105
125
  | { readonly currentCredentialRateLimited?: false; readonly currentStep?: FallbackStep }
@@ -113,6 +133,10 @@ export type FallbackInput = {
113
133
  /** grok 자격이 «있나». ⛔ 「모른다」를 boolean 에 접지 마라 — 호출자가
114
134
  * `resolveGrokCredential() !== null` 로 확정해서 준다. */
115
135
  readonly grokAvailable: boolean;
136
+ /** `llm.openrouter.fallbackModel` — 기본 모델로의 유료 폴백은 허용하지 않는다. */
137
+ readonly openrouterFallbackModel?: string;
138
+ /** OpenRouter 키 존재 여부(키 값 자체는 판정·관측에 넣지 않는다). */
139
+ readonly openrouterAvailable?: boolean;
116
140
  /**
117
141
  * grok 이 «지금 쓸 수 있나» — ⛔ 자격(`grokAvailable`)과 «다른 축»이다.
118
142
  * 'usable' 쓸 수 있다(잔량 있음 · 무제한 · 임계 미만)
@@ -132,6 +156,11 @@ export type FallbackInput = {
132
156
  * ⛔ 이 함수는 config 를 읽지 않는다 — 호출자가 이 칸을 준다.
133
157
  */
134
158
  readonly stayOnResetCreditAvailable?: boolean;
159
+ /**
160
+ * 크레딧 잔액이 «확인된»(잔액 > 0 · 보유 ≠ false) codex 계정이 하나라도 있나 — `codex-credits` 칸만 읽는다.
161
+ * ⛔ 생략·false 는 그 칸을 «건너뛴다»(돈이라 「모른다」를 통과로 접지 않는다 — grok 의 unknown 통과와 «반대»).
162
+ */
163
+ readonly codexCreditsAvailable?: boolean;
135
164
  } & FallbackRunPosition;
136
165
 
137
166
  /**
@@ -154,11 +183,13 @@ export function decideFallback(input: FallbackInput): FallbackDecision {
154
183
  const {
155
184
  rotation, chain, currentStep, currentCredentialRateLimited = false,
156
185
  grokAvailable, grokQuota = 'unknown', claudePtyMaturity, stayOnResetCreditAvailable = false,
186
+ openrouterFallbackModel, openrouterAvailable = false, codexCreditsAvailable = false,
157
187
  } = input;
188
+ const openrouter = { model: openrouterFallbackModel, available: openrouterAvailable, codexCreditsAvailable };
158
189
 
159
190
  if (currentCredentialRateLimited) {
160
191
  if (currentStep === undefined) return { action: 'stay', why: 'chain-exhausted' };
161
- return stepAfter(chain, currentStep, grokAvailable, grokQuota, claudePtyMaturity, 'chain-exhausted');
192
+ return stepAfter(chain, currentStep, grokAvailable, grokQuota, claudePtyMaturity, openrouter, 'chain-exhausted');
162
193
  }
163
194
  if (rotation.reason === 'explicit') return { action: 'stay', why: 'explicit' };
164
195
  if (rotation.reason === 'not-reached' || (rotation.reason === 'credit-pace' && !('to' in rotation))) {
@@ -172,13 +203,13 @@ export function decideFallback(input: FallbackInput): FallbackDecision {
172
203
  // 회전이 답을 냈는데 체인이 codex-rotate 를 «빼» 놨다면 그 뜻을 존중하고
173
204
  // 다음 칸으로 간다(회전을 원치 않는 구성).
174
205
  if (chain.includes('codex-rotate')) return { action: 'codex-rotate', to: rotation.to };
175
- return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, 'chain-exhausted');
206
+ return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, openrouter, 'chain-exhausted');
176
207
  }
177
208
 
178
209
  // no-candidate | disabled | reset-credit-available(기본) — codex 축이 끝났다. 다음 칸을 본다.
179
210
  // ⛔ 다음 칸이 «없을 때»의 이름만 고른다. 진행(stepAfterCodex)은 그대로다.
180
211
  const fallbackWhy = stayReasonWhenCodexAxisEnds(rotation.reason === 'credit-pace' ? 'no-candidate' : rotation.reason);
181
- return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, fallbackWhy);
212
+ return stepAfterCodex(chain, grokAvailable, grokQuota, claudePtyMaturity, openrouter, fallbackWhy);
182
213
  }
183
214
 
184
215
  /** codex 축이 끝났는데 체인 다음 칸도 없을 때 머무는 이유.
@@ -192,14 +223,18 @@ export function stayReasonWhenCodexAxisEnds(
192
223
  return 'chain-exhausted';
193
224
  }
194
225
 
226
+ /** 칸 판정에 필요한 «나머지» 재료 — OpenRouter 모델·키, codex 크레딧 잔액 확인. */
227
+ type StepExtras = { readonly model?: string; readonly available: boolean; readonly codexCreditsAvailable?: boolean };
228
+
195
229
  function stepAfterCodex(
196
230
  chain: readonly FallbackStep[],
197
231
  grokAvailable: boolean,
198
232
  grokQuota: 'usable' | 'exhausted' | 'unknown',
199
233
  claudePtyMaturity: ClaudePtyMaturity | undefined,
234
+ openrouter: StepExtras,
200
235
  whyIfNone: StayReason,
201
236
  ): FallbackDecision {
202
- return stepAfter(chain, 'codex-rotate', grokAvailable, grokQuota, claudePtyMaturity, whyIfNone);
237
+ return stepAfter(chain, 'codex-rotate', grokAvailable, grokQuota, claudePtyMaturity, openrouter, whyIfNone);
203
238
  }
204
239
 
205
240
  function stepAfter(
@@ -208,22 +243,39 @@ function stepAfter(
208
243
  grokAvailable: boolean,
209
244
  grokQuota: 'usable' | 'exhausted' | 'unknown',
210
245
  claudePtyMaturity: ClaudePtyMaturity | undefined,
246
+ openrouter: StepExtras,
211
247
  whyIfNone: StayReason,
212
248
  ): FallbackDecision {
213
249
  const idx = currentStep === undefined ? -1 : chain.indexOf(currentStep);
214
250
  const rest = idx === -1 ? chain : chain.slice(idx + 1);
215
251
  let unavailableWhy: StayReason | undefined;
252
+ // `codex-credits` 칸이 «왜 앞 칸을 못 썼나»를 값으로 남긴다(관측 — 비밀 없음).
253
+ const skipped: { step: FallbackStep; why: StayReason }[] = [];
254
+ const skip = (step: FallbackStep, why: StayReason): void => { unavailableWhy = why; skipped.push({ step, why }); };
216
255
  for (const step of rest) {
256
+ if (step === 'codex-credits') {
257
+ // ⛔ 크레딧은 돈이다 — 잔액이 «확인된» 계정이 없으면 건너뛴다(「모른다」는 통과가 «아니다»).
258
+ if (openrouter.codexCreditsAvailable !== true) { skip(step, 'codex-credits-unavailable'); continue; }
259
+ return { action: 'codex-credits', skipped };
260
+ }
261
+ if (step === 'openrouter') {
262
+ const model = openrouter.model?.trim();
263
+ if (!openrouter.available || !model || !/^openrouter\/[^/\s]+\/[^\s]+$/.test(model)) {
264
+ skip(step, 'openrouter-unavailable');
265
+ continue;
266
+ }
267
+ return { action: 'switch-backend', backend: 'openrouter', model };
268
+ }
217
269
  if (step === 'grok') {
218
270
  // 자격 부재와 소진은 다른 값이다. 다음 칸이 있으면 그 칸을 살핀다.
219
- if (!grokAvailable) { unavailableWhy = 'grok-unavailable'; continue; }
271
+ if (!grokAvailable) { skip(step, 'grok-unavailable'); continue; }
220
272
  // 「모른다」는 통과시킨다 — 못 읽었다고 갈 곳을 없애지 않는다.
221
- if (grokQuota === 'exhausted') { unavailableWhy = 'grok-exhausted'; continue; }
273
+ if (grokQuota === 'exhausted') { skip(step, 'grok-exhausted'); continue; }
222
274
  return { action: 'switch-backend', backend: 'grok' };
223
275
  }
224
276
  if (step === 'claude-pty') {
225
277
  // 미성숙·못 읽음은 «건너뛴다» — 뒤에 다른 칸이 있으면 그 칸을 본다(없으면 이 사유로 머문다).
226
- if (claudePtyMaturity?.mature !== true) { unavailableWhy = 'claude-pty-immature'; continue; }
278
+ if (claudePtyMaturity?.mature !== true) { skip(step, 'claude-pty-immature'); continue; }
227
279
  return { action: 'switch-backend', backend: 'claude' };
228
280
  }
229
281
  }
@@ -236,7 +288,11 @@ export function describeFallback(decision: FallbackDecision): string {
236
288
  case 'codex-rotate':
237
289
  return `codex 계정 전환 → ${decision.to.name}`;
238
290
  case 'switch-backend':
239
- return `백엔드 전환 → ${decision.backend} (구독)`;
291
+ return decision.backend === 'openrouter'
292
+ ? `백엔드 전환 → openrouter (${decision.model} · API 과금)`
293
+ : `백엔드 전환 → ${decision.backend} (구독)`;
294
+ case 'codex-credits':
295
+ return `codex 크레딧으로 계속 (마지막 칸 · 선불 크레딧 과금${decision.skipped.length ? ` · 건너뜀 ${decision.skipped.map((s) => `${s.step}:${s.why}`).join(', ')}` : ''})`;
240
296
  case 'stay':
241
297
  return `전환 없음 (${decision.why})`;
242
298
  }
@@ -273,24 +329,28 @@ export function grokQuotaFromCreditAxis(axis: {
273
329
  /**
274
330
  * budget 스냅샷 → 폴백 판정이 쓰는 세 값.
275
331
  *
276
- * ⭐ 공급자가 「리밋이 찼다」고 «말한» 것을 우리 산술보다 «먼저» 본다
332
+ * ⭐ 공급자가 「리밋이 찼다」고 «말한» 것을 weekly window 산술보다 «먼저» 본다
277
333
  * (`UsageSnapshot.rateLimitReached` 주석의 그 권위를 그대로 따른다).
278
334
  * ⛔ 스냅샷이 없거나 판단할 재료가 없으면 `'unknown'` 이다 — 「소진」으로 접지 «않는다».
279
335
  * ⛔ 이 함수는 «네트워크를 안 친다» — 이미 채워진 캐시를 받는다.
280
336
  */
281
337
  export function grokQuotaFromUsageSnapshot(snapshot: {
282
338
  readonly rateLimitReached?: string;
339
+ readonly windows?: readonly { readonly kind: string; readonly remainingPercent: number }[];
283
340
  readonly credits?: { readonly hasCredits?: boolean; readonly unlimited?: boolean };
284
341
  } | null | undefined): 'usable' | 'exhausted' | 'unknown' {
285
342
  if (!snapshot) return 'unknown';
286
- // ⛔ 공급자 판정이 이긴다 — 우리가 used >= limit 로 추론하지 않는다.
343
+ // ⛔ 공급자 판정이 이긴다 — 주간 창 판정보다 앞선다.
287
344
  if (typeof snapshot.rateLimitReached === 'string' && snapshot.rateLimitReached.length > 0) return 'exhausted';
345
+ const weekly = snapshot.windows?.find((window) => window.kind === 'weekly');
346
+ if (weekly && Number.isFinite(weekly.remainingPercent) && weekly.remainingPercent >= 0 && weekly.remainingPercent <= 100) {
347
+ return weekly.remainingPercent === 0 ? 'exhausted' : 'usable';
348
+ }
288
349
  const credits = snapshot.credits;
289
350
  if (!credits) return 'unknown';
290
351
  if (credits.unlimited === true) return 'usable';
291
352
  // ⛔⭐ `hasCredits` 는 브랜드마다 «다른 것»을 뜻할 수 있다 — grok 은 「선불 잔액이 있나」다.
292
- // ⇒ 사용률 창(rateLimitReached)이 이미 위에서 판정을 냈고, 여기 오면 그 신호가 «없다».
293
- // 그러면 hasCredits=false 하나로 「소진」을 단정하지 «않는다» — 「모른다」가 정직하다.
353
+ // ⇒ 주간 quota 창이 없으면 hasCredits=false 하나로 「소진」을 단정하지 «않는다» — 「모른다」가 정직하다.
294
354
  if (credits.hasCredits === true) return 'usable';
295
355
  return 'unknown';
296
356
  }
@@ -13,21 +13,34 @@ export interface FirstRunDeps {
13
13
  path?: string;
14
14
  detectProviders?: () => Promise<DetectedProvider[]>;
15
15
  isTTY?: boolean;
16
- chooseProvider?: () => Promise<LLMProviderName | null>;
16
+ chooseProvider?: (detected: readonly LLMProviderName[]) => Promise<LLMProviderName | null>;
17
17
  print?: (message: string) => void;
18
18
  saveConfig?: (config: UserConfig, path: string) => void;
19
19
  }
20
20
 
21
- async function chooseProvider(): Promise<LLMProviderName | null> {
21
+ const CHOICE_BASE: readonly LLMProviderName[] = ['openai-codex', 'grok', 'anthropic'];
22
+ const CHOICE_LABEL: Partial<Record<LLMProviderName, string>> = { 'openai-codex': 'Codex', grok: 'Grok', anthropic: 'Claude' };
23
+ const SUBSCRIPTION_PRIORITY = ['openai-codex', 'grok', 'anthropic', 'gemini', 'openai', 'openrouter'] as const;
24
+
25
+ /** Menu order: detected subscriptions first (in priority order), then the remaining base choices. */
26
+ export function orderProviderChoices(detected: readonly LLMProviderName[] = []): LLMProviderName[] {
27
+ return [...detected, ...CHOICE_BASE.filter((name) => !detected.includes(name))];
28
+ }
29
+
30
+ async function chooseProvider(detected: readonly LLMProviderName[] = []): Promise<LLMProviderName | null> {
31
+ const choices = orderProviderChoices(detected);
32
+ const menu = choices.map((name, i) => `${i + 1} ${CHOICE_LABEL[name] ?? name}`).join(', ');
22
33
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
23
34
  try {
24
- const answer = (await rl.question('Choose LLM (1 Codex, 2 Grok, 3 Claude; Enter to cancel): ')).trim();
25
- return ({ '1': 'openai-codex', '2': 'grok', '3': 'anthropic' } as Record<string, LLMProviderName>)[answer] ?? null;
35
+ const answer = (await rl.question(`Choose LLM (${menu}; Enter to cancel): `)).trim();
36
+ return choices[Number(answer) - 1] ?? null;
26
37
  } finally {
27
38
  rl.close();
28
39
  }
29
40
  }
30
41
 
42
+ const detectionLabel = (provider: string) => `${provider === 'openai-codex' ? 'codex' : provider} 구독`;
43
+
31
44
  export async function runFirstRun(deps: FirstRunDeps = {}): Promise<{
32
45
  outcome: 'ready' | 'needs-llm' | 'cancelled'; provider?: string; inputs: number;
33
46
  }> {
@@ -50,21 +63,31 @@ export async function runFirstRun(deps: FirstRunDeps = {}): Promise<{
50
63
  : undefined;
51
64
  const configured = existing && existing.source !== 'none'
52
65
  ? cfg.llm.provider : undefined;
53
- const picked = (['openai-codex', 'grok', 'claude-code', 'anthropic', 'gemini', 'openai', 'openrouter'] as const)
54
- .find((name) => providers.includes(name));
55
- let provider: LLMProviderName | null | undefined = configured ??
56
- (picked === 'claude-code' ? 'anthropic' : picked as LLMProviderName | undefined);
66
+ // claude-code is detected but has no subscription path in elanous: mapping it to the 'anthropic'
67
+ // API-key provider would save a provider whose first call fails for a subscription-only user.
68
+ const usable = SUBSCRIPTION_PRIORITY.filter((name) => providers.includes(name));
69
+ const detectionLine = (outcome: string) => `감지: ${providers.map(detectionLabel).join(' · ')} → ${outcome}`;
70
+ const needsLlm = (inputs: number, extra: string[] = []) => {
71
+ print('eln setup llm 으로 고르세요');
72
+ for (const line of extra) print(line);
73
+ observe('needs-llm', inputs);
74
+ return { outcome: 'needs-llm' as const, inputs };
75
+ };
76
+ let provider: LLMProviderName | null | undefined = configured ?? (usable.length === 1 ? usable[0] : undefined);
77
+ if (!configured && provider) print(detectionLine(provider));
57
78
  let inputs = 0;
58
79
  if (!provider) {
80
+ if (providers.length > 0) {
81
+ print(detectionLine(usable.length === 0
82
+ ? 'claude-code 구독은 구독으로 쓸 수 있는 경로가 없어 자동 선택하지 않음'
83
+ : '둘 이상 감지되어 고르세요'));
84
+ }
59
85
  if ((deps.isTTY ?? process.stdin.isTTY) !== true) {
60
- print('eln setup llm 으로 고르세요');
61
86
  // FIRST-CHAT-NONTTY — bare `elanous` with no TTY gets the same one-line next step as the other entrances.
62
- print(unattendedNextStepLine());
63
- observe('needs-llm', 0);
64
- return { outcome: 'needs-llm', inputs: 0 };
87
+ return needsLlm(0, [unattendedNextStepLine()]);
65
88
  }
66
89
  inputs = 1;
67
- provider = await (deps.chooseProvider ?? chooseProvider)();
90
+ provider = await (deps.chooseProvider ?? chooseProvider)(usable);
68
91
  if (!provider) return { outcome: 'cancelled', inputs };
69
92
  observe('chosen', inputs);
70
93
  }
@@ -74,11 +97,7 @@ export async function runFirstRun(deps: FirstRunDeps = {}): Promise<{
74
97
  baseProvider: cfg.llm.provider, baseApiKey: cfg.llm.apiKey,
75
98
  })
76
99
  : undefined;
77
- if (inputs === 1 && credential?.source === 'none') {
78
- print('eln setup llm 으로 고르세요');
79
- observe('needs-llm', inputs);
80
- return { outcome: 'needs-llm', inputs };
81
- }
100
+ if (inputs === 1 && credential?.source === 'none') return needsLlm(inputs);
82
101
  (deps.saveConfig ?? saveUserConfig)({
83
102
  ...cfg,
84
103
  llm: { ...cfg.llm, provider,
@@ -15,6 +15,8 @@ export interface WebFirstSetupDeps {
15
15
  /** Whether a person is at a terminal (stdin TTY). Without one the web path only uses a daemon that is already up. */
16
16
  isTty?: boolean;
17
17
  terminal?: boolean;
18
+ /** Bare first run never starts or waits for a missing daemon; explicit setup retains web launch. */
19
+ startIfMissing?: boolean;
18
20
  startedAt?: number;
19
21
  showNexus?: () => Promise<NexusShowResult>;
20
22
  startDaemon?: () => Promise<BgLaunchResult>;
@@ -67,9 +69,13 @@ export async function runWebFirstSetup(deps: WebFirstSetupDeps): Promise<'link-s
67
69
  let shown: NexusShowResult | undefined;
68
70
  try { shown = await show(); } catch { /* A missing daemon may make inspection fail. */ }
69
71
  const running = shown?.status === 'unregistered' || (shown?.status === 'registered' && shown.instance?.alive === true);
72
+ if (deps.startIfMissing === false && !running) {
73
+ print('오프라인 모드');
74
+ observe('fallback', 'offline');
75
+ return 'fallback';
76
+ }
70
77
  // A script, pipe or CI run never starts a daemon on its own: without a terminal the web path
71
- // only uses a daemon that already answers health once. (install.sh runs first setup with
72
- // stdin on /dev/tty, so the install → web path still starts one.)
78
+ // only uses a daemon that already answers health once.
73
79
  if ((deps.isTty ?? (process.stdin.isTTY === true)) !== true) {
74
80
  const rest = running ? shown?.urls?.rest.loopback : undefined;
75
81
  const up = rest && shown?.urls?.pwa.loopback
@@ -78,6 +84,12 @@ export async function runWebFirstSetup(deps: WebFirstSetupDeps): Promise<'link-s
78
84
  }
79
85
  const deadline = Date.now() + STARTUP_TIMEOUT_MS;
80
86
  if (!running || !shown?.urls?.pwa.loopback) {
87
+ if (deps.startIfMissing === false) {
88
+ print('오프라인 모드');
89
+ observe('fallback', 'offline');
90
+ return 'fallback';
91
+ }
92
+ print('웹 셋업을 위해 데몬을 시작합니다.');
81
93
  let launch: BgLaunchResult;
82
94
  try {
83
95
  launch = await (deps.startDaemon ?? (() => runBgLaunch({ out: { log: () => {}, error: () => {} } })))();
@@ -98,9 +110,15 @@ export async function runWebFirstSetup(deps: WebFirstSetupDeps): Promise<'link-s
98
110
  }
99
111
  }
100
112
  } catch { /* A daemon may not have published its URLs yet. */ }
113
+ if (deps.startIfMissing === false) break;
101
114
  const remaining = deadline - Date.now();
102
115
  if (remaining > 0) await Bun.sleep(Math.min(200, remaining));
103
116
  }
117
+ if (!healthy && deps.startIfMissing === false) {
118
+ print('오프라인 모드');
119
+ observe('fallback', 'offline');
120
+ return 'fallback';
121
+ }
104
122
  if (!healthy) return fallback(running ? 'daemon-health-unavailable' : 'daemon-health-timeout');
105
123
 
106
124
  if (!shown?.urls?.pwa.loopback) return fallback('daemon-unavailable');
package/src/onboarding.ts CHANGED
@@ -51,6 +51,7 @@ import { DiscordBot } from './discord.js';
51
51
  import { pickCodexAuthMode, pickCodexModel } from './codex/setup.js';
52
52
  import { getInventory, resolveBaseUrl } from './llm/local-manager/manager.js';
53
53
  import { getMessages, format as i18nFormat } from './expression/i18n/index.js';
54
+ import { messagesEn } from './expression/i18n/messages.en.js';
54
55
  import type {
55
56
  ChoiceOption,
56
57
  ChooseOpts,
@@ -1562,7 +1563,7 @@ export async function runOnboarding(opts: RunWizardOpts = {}): Promise<UserConfi
1562
1563
  io.print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
1563
1564
  io.print(` ${m.setupComplete}`);
1564
1565
  // ER1 — first-run consent notice (default on · 대표 10-01): what is sent and how to turn it off.
1565
- io.print(' 오류가 나면 운영팀에 자동으로 알립니다(오류 내용·버전·무작위 설치 ID — 이름·메일 없이). 끄기: elanous config set errorReports.enabled false');
1566
+ io.print(` ${m.setupErrorReportNotice ?? messagesEn.setupErrorReportNotice}`);
1566
1567
  io.print(` Provider : ${marked.llm.provider}${marked.llm.model ? ` (${marked.llm.model})` : ''}`);
1567
1568
  // EN5 — show what the loader will actually read (resolveSkillSources), not the raw preset fields.
1568
1569
  const skillSources = resolveSkillSources(marked).filter((source) => source.enabled);
@@ -0,0 +1,185 @@
1
+ import { writeFileSync, mkdirSync, existsSync, readFileSync, renameSync } from 'node:fs';
2
+ import { basename, join } from 'node:path';
3
+ import { createHash, randomUUID } from 'node:crypto';
4
+ import { CardStore } from '../task-cards/card-store.js';
5
+ import { debug, redactSecretText } from '../debug/log.js';
6
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
7
+ import { recordRunExit, readRunExits } from '../harness/harness-incidents.js';
8
+ import { notifyOwners } from '../loops/checker.js';
9
+ import { bunVersion, cliFingerprint, gcTools, orphanCandidates, type FenceGcDeps } from '../hq/fence.js';
10
+
11
+ export interface MachineHeartbeatDeps extends FenceGcDeps {
12
+ root?: string;
13
+ now?: Date;
14
+ record?: typeof recordRunExit;
15
+ log?: typeof debug.log;
16
+ publish?: typeof notifyOwners;
17
+ card?: (command: string, day: string, evidencePaths: string[], root: string) => void;
18
+ version?: (pid: number, run: (binary: string, args: string[]) => string) => string;
19
+ /** How long the same tree must stay at the same CPU across guardian ticks before it is called stalled. */
20
+ stallMs?: number;
21
+ /** off = collect nothing · shadow (default) = candidates, evidence file and observation only · on = evidence, then SIGTERM. */
22
+ mode?: OrphanGcMode;
23
+ }
24
+
25
+ export type OrphanGcMode = 'off' | 'shadow' | 'on';
26
+
27
+ /** A tree is «stalled» only when an earlier tick saw the very same tree at the very same CPU this long ago.
28
+ * One in-tick second is not enough: Linux `ps time` has whole-second resolution and I/O waits burn no CPU. */
29
+ export const ORPHAN_STALL_MS = 10 * 60_000;
30
+ /** `shadowEvidenced`: shadow already wrote this tree's evidence once — later shadow ticks skip it (no lsof/sample, no new file). */
31
+ type StallWatch = Record<string, { since: string; cpu: number; tree: string; shadowEvidenced?: true }>;
32
+
33
+ function readStallWatch(path: string): StallWatch {
34
+ if (!existsSync(path)) return {};
35
+ const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'));
36
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as StallWatch : {};
37
+ }
38
+
39
+ /** One cause card per command/day, with incident files as attachments in the incidents section. */
40
+ export function publishOrphanCauseCard(command: string, day: string, paths: string[], root: string): void {
41
+ const store = new CardStore(root);
42
+ try {
43
+ const hash = createHash('sha256').update(command).digest('hex').slice(0, 24);
44
+ const card = store.createCard({ goalId: `orphan-cli-${day}-${hash}`, title: `TC 원인 조사: ${redactSecretText(command)}` });
45
+ for (const path of paths) store.appendSection(card.id, { key: `incidents:${basename(path).replaceAll('.', '-')}`, owner: 'TC',
46
+ content: `증거: incidents/${basename(path)}\n가설(미확정): bun fs.watch 등 상주 핸들이 CLI 종료를 막음` });
47
+ } finally { store.close(); }
48
+ }
49
+
50
+ /** Run on the local guardian tick; an observation failure never authorizes termination. */
51
+ export async function runMachineHeartbeat(schedules: readonly { command: string; cron: string }[], deps: MachineHeartbeatDeps = {}): Promise<{ collected: number; terminated: number; cards: number }> {
52
+ const mode = deps.mode ?? 'shadow';
53
+ if (mode === 'off') return { collected: 0, terminated: 0, cards: 0 };
54
+ const tools = gcTools(deps);
55
+ const now = deps.now ?? new Date();
56
+ const root = deps.root ?? effectiveInstanceRoot();
57
+ const timeZone = deps.timeZone;
58
+ const stallMs = deps.stallMs ?? ORPHAN_STALL_MS;
59
+ const watchPath = join(root, 'ops', 'orphan-cli-watch.json');
60
+ // An unreadable watch never authorizes termination: start over and only observe this tick.
61
+ let watch: StallWatch;
62
+ try { watch = readStallWatch(watchPath); } catch { watch = {}; }
63
+ const nextWatch: StallWatch = {};
64
+ const stalled: ReturnType<typeof orphanCandidates> = [];
65
+ const first = tools.snapshot();
66
+ await tools.sleep(1_000);
67
+ const second = tools.snapshot();
68
+ let collected = 0;
69
+ let terminated = 0;
70
+ let cards = 0;
71
+ let alreadyEvidenced = 0;
72
+ const logDecision = (): void => {
73
+ try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'decision', { mode, candidates: stalled.length, collected, alreadyEvidenced, killed: terminated }); } catch { /* observe only */ }
74
+ };
75
+ for (const candidate of orphanCandidates(first, second, schedules, now, timeZone)) {
76
+ const key = `${candidate.process.pid}:${candidate.process.ppid}:${candidate.process.command}`;
77
+ const cpu = Math.round(candidate.tree.reduce((total, row) => total + row.cpuSeconds, 0) * 100) / 100;
78
+ const tree = candidate.tree.map(row => `${row.pid}:${row.cpuSeconds}`).join(',');
79
+ const seen = watch[key];
80
+ const elapsed = seen ? now.getTime() - Date.parse(seen.since) : NaN;
81
+ // Same tree, same CPU, and the process is at least as old as the watch (not a reused PID).
82
+ if (!seen || seen.cpu !== cpu || seen.tree !== tree || !(elapsed >= 0) || candidate.process.ageSeconds * 1000 + 2_000 < elapsed) {
83
+ nextWatch[key] = { since: now.toISOString(), cpu, tree };
84
+ continue;
85
+ }
86
+ nextWatch[key] = seen;
87
+ if (elapsed < stallMs) continue;
88
+ // Shadow never ends the tree, so the same hang stays stalled: evidence it once, not on every tick.
89
+ if (mode !== 'on' && seen.shadowEvidenced) { alreadyEvidenced++; continue; }
90
+ stalled.push(candidate);
91
+ }
92
+ try {
93
+ mkdirSync(join(root, 'ops'), { recursive: true });
94
+ const tmp = `${watchPath}.${process.pid}.tmp`;
95
+ writeFileSync(tmp, JSON.stringify(nextWatch), { mode: 0o600 });
96
+ renameSync(tmp, watchPath);
97
+ } catch (error) {
98
+ // Without a durable watch the next tick cannot prove a stall either — observe only.
99
+ try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'observation-failed', { stage: 'stall-watch', error: redactSecretText(String(error)) }); } catch { /* observe only */ }
100
+ logDecision();
101
+ return { collected, terminated, cards };
102
+ }
103
+ const writeWatch = (): void => {
104
+ mkdirSync(join(root, 'ops'), { recursive: true });
105
+ const tmp = `${watchPath}.${process.pid}.tmp`;
106
+ writeFileSync(tmp, JSON.stringify(nextWatch), { mode: 0o600 });
107
+ renameSync(tmp, watchPath);
108
+ };
109
+ let shadowMarked = false;
110
+ for (const candidate of stalled) {
111
+ // Recheck the whole tree after slow diagnostics. A new child or CPU progress invalidates the decision.
112
+ let evidence: { command: string; ageSeconds: number; periodMinutes: number; pid: number; tree: number[]; lsof: string; sample: string; bunVersion: string; at: string };
113
+ try {
114
+ evidence = {
115
+ command: candidate.process.command, ageSeconds: candidate.process.ageSeconds, periodMinutes: candidate.periodMinutes, pid: candidate.process.pid,
116
+ tree: candidate.tree.map(row => row.pid),
117
+ lsof: tools.run('lsof', ['-p', candidate.tree.map(row => row.pid).join(',')]),
118
+ sample: tools.run('sample', [String(candidate.process.pid), '1']),
119
+ bunVersion: (deps.version ?? bunVersion)(candidate.process.pid, tools.run), at: now.toISOString(),
120
+ };
121
+ const latest = tools.snapshot();
122
+ const found = orphanCandidates(second, latest, schedules, now, timeZone).find(row => row.process.pid === candidate.process.pid);
123
+ if (!found || found.tree.length !== candidate.tree.length || found.tree.some(row => !candidate.tree.some(old => old.pid === row.pid))) continue;
124
+ // File + existing incident ledger + logs are committed before any signal is delivered.
125
+ const path = join(root, 'incidents', `orphan-cli-${now.getTime()}-${candidate.process.pid}-${randomUUID().slice(0, 8)}.json`);
126
+ mkdirSync(join(root, 'incidents'), { recursive: true });
127
+ const safe = JSON.stringify(evidence, (_key, value) => typeof value === 'string' ? redactSecretText(value) : value);
128
+ writeFileSync(path, safe, { flag: 'wx', mode: 0o600 });
129
+ const fingerprint = redactSecretText(cliFingerprint(candidate.process.command));
130
+ (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', mode === 'on' ? 'evidence-before-termination' : 'shadow-evidence', {
131
+ path, command: redactSecretText(evidence.command), ageSeconds: evidence.ageSeconds, periodMinutes: evidence.periodMinutes, pid: evidence.pid,
132
+ tree: evidence.tree, lsof: redactSecretText(evidence.lsof), sample: redactSecretText(evidence.sample), bunVersion: evidence.bunVersion,
133
+ });
134
+ collected++;
135
+ if (mode !== 'on') {
136
+ const key = `${candidate.process.pid}:${candidate.process.ppid}:${candidate.process.command}`;
137
+ if (nextWatch[key]) { nextWatch[key] = { ...nextWatch[key]!, shadowEvidenced: true }; shadowMarked = true; }
138
+ continue;
139
+ }
140
+ // Children first: do not leave the stuck parent holding resources while descendants outlive it.
141
+ const signalFailures: Array<{ pid: number; error: string }> = [];
142
+ for (const row of [...found.tree].reverse()) {
143
+ try { tools.kill(row.pid); } catch (error) { signalFailures.push({ pid: row.pid, error: redactSecretText(String(error)) }); }
144
+ }
145
+ // The run-exit row records what the signals actually did, written after they were sent: SIGTERM only when every
146
+ // signal landed, otherwise no signal and the failures beside the evidence path. The evidence file and log above
147
+ // were committed before any signal. Either way the hang counts toward the cause card below.
148
+ (deps.record ?? recordRunExit)({ runId: `orphan-cli-${candidate.process.pid}-${randomUUID()}`, reason: `orphan-cli:${fingerprint}`, status: null,
149
+ signal: signalFailures.length === 0 ? 'SIGTERM' : null, at: now.toISOString(), pid: candidate.process.pid, entrance: 'guardian-tick',
150
+ lastLines: [path, ...signalFailures.map((failure) => `termination-failed pid=${failure.pid}: ${failure.error}`)] }, root);
151
+ if (signalFailures.length > 0) {
152
+ (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'termination-failed', { path, pid: candidate.process.pid, failures: signalFailures });
153
+ } else terminated++;
154
+ const day = new Date(now.getTime() + 9 * 3_600_000).toISOString().slice(0, 10);
155
+ // One hang is one process: the same PID recorded on several ticks (its SIGTERM did not take) counts once.
156
+ const byPid = new Map<number, ReturnType<typeof readRunExits>[number]>();
157
+ for (const row of readRunExits(root)) {
158
+ if (row.reason !== `orphan-cli:${fingerprint}` || typeof row.pid !== 'number') continue;
159
+ if (new Date(Date.parse(row.at) + 9 * 3_600_000).toISOString().slice(0, 10) !== day) continue;
160
+ if (!byPid.has(row.pid)) byPid.set(row.pid, row);
161
+ }
162
+ const same = [...byPid.values()];
163
+ if (same.length >= 3) {
164
+ const paths = same.flatMap(row => row.lastLines ?? []).filter(file => existsSync(file));
165
+ if (paths.length < 3) {
166
+ (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'cause-card-evidence-missing', { command: redactSecretText(candidate.process.command), count: same.length, evidence: paths.length });
167
+ continue;
168
+ }
169
+ const reason = `원인 카드: ${fingerprint} · 하루 ${same.length}회 매달림 · 증거 ${paths.join(' , ')} · 가설(미확정): bun fs.watch 등 상주 핸들이 CLI 종료를 막음`;
170
+ (deps.card ?? publishOrphanCauseCard)(fingerprint, day, paths, root);
171
+ cards += (deps.publish ?? notifyOwners)([{ id: `orphan-cli:${fingerprint}`, owner: 'TC', enabled: true, registered: true, state: 'failing', reason }], { root, now });
172
+ }
173
+ } catch (error) {
174
+ try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'observation-failed', { pid: candidate.process.pid, error: redactSecretText(String(error)) }); } catch { /* log failure must not kill a process */ }
175
+ }
176
+ }
177
+ if (shadowMarked) {
178
+ // A lost mark only means one more evidence file next tick — never a signal.
179
+ try { writeWatch(); } catch (error) {
180
+ try { (deps.log ?? debug.log.bind(debug))('ops.orphan-cli', 'observation-failed', { stage: 'shadow-mark', error: redactSecretText(String(error)) }); } catch { /* observe only */ }
181
+ }
182
+ }
183
+ logDecision();
184
+ return { collected, terminated, cards };
185
+ }