elanous 0.2.21 → 0.2.23

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 (780) 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/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
  9. package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
  11. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
  12. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
  14. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
  23. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
  24. package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
  27. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
  35. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
  39. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
  52. package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
  56. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
  64. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
  69. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
  71. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
  73. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
  74. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
  78. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
  83. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
  84. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
  85. package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
  86. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
  87. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
  90. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
  97. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
  99. package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
  101. package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
  105. package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
  110. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
  111. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
  112. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
  114. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
  116. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
  117. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
  120. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
  123. package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/{page-111cabe4d1fd69ae.js → page-6168a7c43e6ef8f5.js} +1 -1
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
  184. package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +1 -0
  185. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
  186. package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
  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/graphs/catalog/catalog.yaml +1 -1
  288. package/graphs/drafts/recipes.yaml +2 -2
  289. package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
  290. package/graphs/log-horizon/recipes.yaml +3 -0
  291. package/graphs/release/recipes.yaml +1 -1
  292. package/graphs/release/release-loop.yaml +6 -2
  293. package/graphs/release-rehearsal/recipes.yaml +12 -0
  294. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  295. package/graphs/test-diet/recipes.yaml +3 -0
  296. package/graphs/test-diet/test-diet.yaml +3 -1
  297. package/package.json +4 -1
  298. package/scripts/bench-report.ts +82 -3
  299. package/scripts/ci-typecheck-changed.ts +10 -1
  300. package/scripts/f-session-monitor.ts +69 -0
  301. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  302. package/scripts/hq/standby-snapshot.ts +7 -3
  303. package/scripts/knowledge-compress.ts +11 -0
  304. package/scripts/lib/typecheck-ratchet.ts +51 -0
  305. package/scripts/nightly-docops.ts +90 -3
  306. package/scripts/openai-relay-server.ts +5 -1
  307. package/scripts/release-loop/docs-node.ts +258 -43
  308. package/scripts/release-loop/gate-method.ts +59 -0
  309. package/scripts/release-loop/gate-node.ts +73 -7
  310. package/scripts/release-loop/gate-wall.ts +208 -0
  311. package/scripts/release-loop/known-issues-node.ts +53 -8
  312. package/scripts/release-loop/publish-at.ts +14 -0
  313. package/scripts/release-loop/publish-node.ts +17 -2
  314. package/scripts/release-loop/resume-release.ts +34 -4
  315. package/scripts/release-loop/resume.ts +53 -0
  316. package/scripts/release-loop/shard-plan.ts +3 -11
  317. package/scripts/release-loop/tui-node-checks.ts +22 -0
  318. package/scripts/release-loop/unattended-release.ts +8 -1
  319. package/scripts/research-coo-admin-dates.ts +39 -0
  320. package/scripts/rhythm/daily.ts +51 -2
  321. package/scripts/rhythm/weekly.ts +3 -2
  322. package/scripts/skills/public-check.ts +7 -2
  323. package/scripts/smart-merge/resync-shadow.ts +5 -3
  324. package/scripts/test-diet/lib.ts +81 -1
  325. package/scripts/test-diet/node.ts +48 -2
  326. package/scripts/tsc-main-safety-net.ts +189 -0
  327. package/scripts/usage-rollup.ts +8 -4
  328. package/scripts/verify-coo-admin-evidence.ts +83 -0
  329. package/src/acp/client.ts +4 -2
  330. package/src/acp/codex-plugins.ts +48 -6
  331. package/src/agent/monad-agent-turn.ts +67 -5
  332. package/src/agent/run-context.ts +14 -0
  333. package/src/agent/tool-profile.ts +28 -2
  334. package/src/agent-env/profile.ts +25 -5
  335. package/src/agent-mission/acp-judge.ts +8 -2
  336. package/src/agent-mission/capabilities-cli.ts +16 -1
  337. package/src/agent-mission/driver.ts +27 -13
  338. package/src/agent-mission/pr-review-watch.ts +6 -2
  339. package/src/agent-mission/review-loop.ts +33 -5
  340. package/src/agent-mission/supervisor-metrics.ts +17 -2
  341. package/src/agent-substrate/acp-reviewer.ts +25 -9
  342. package/src/agent-substrate/pr-reviewer.ts +175 -32
  343. package/src/agent-substrate/review-intent.ts +106 -5
  344. package/src/agent-substrate/self-review-cli.ts +111 -16
  345. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  346. package/src/ask-user-question/pending-questions.ts +8 -2
  347. package/src/autopilot/build/llm-conflict-merge.ts +238 -20
  348. package/src/autopilot/codebase-grounding.ts +44 -0
  349. package/src/autopilot/llm-control-brain.ts +13 -1
  350. package/src/autopilot/mission-codebase-gate.ts +8 -77
  351. package/src/autopilot/pr-manager.ts +30 -11
  352. package/src/away/release-watch.ts +47 -8
  353. package/src/boot/acp-server.ts +4 -7
  354. package/src/boot/acp-socket-path.ts +7 -0
  355. package/src/briefing/brief-items.ts +123 -22
  356. package/src/chat/index.ts +13 -3
  357. package/src/cli/agent-cli.ts +20 -0
  358. package/src/cli/brief-cli.ts +46 -22
  359. package/src/cli/cli-user-error.ts +9 -2
  360. package/src/cli/config-classify.ts +83 -0
  361. package/src/cli/control-cli.ts +14 -0
  362. package/src/cli/decisions-cli.ts +26 -16
  363. package/src/cli/log-event-names.ts +3 -0
  364. package/src/cli/logs-cli.ts +1 -0
  365. package/src/cli/logs-model-input.ts +1 -1
  366. package/src/cli/mcp-login.ts +111 -37
  367. package/src/cli/plugin-cli.ts +21 -1
  368. package/src/cli/pod-cli.ts +26 -0
  369. package/src/cli/pr-cli.ts +94 -9
  370. package/src/cli/pr-land-overlap-evidence.ts +131 -0
  371. package/src/cli/release-cli.ts +74 -15
  372. package/src/cli/self-update.ts +173 -10
  373. package/src/cli/skills-cli.ts +12 -3
  374. package/src/cli/tasks-cli.ts +241 -28
  375. package/src/connectors/types.ts +6 -6
  376. package/src/context-bus/context-first.ts +51 -2
  377. package/src/context-bus/context-now-surfaces.ts +29 -0
  378. package/src/context-bus/coord-events.ts +32 -4
  379. package/src/context-bus/long-term-memory.ts +26 -7
  380. package/src/context-bus/nightly-condense.ts +170 -21
  381. package/src/control/control-status.ts +87 -0
  382. package/src/control-plane/light-member.ts +5 -3
  383. package/src/control-plane/member.ts +172 -7
  384. package/src/core-turn/run-goal-loop.ts +108 -3
  385. package/src/dashboard/chat-fold.ts +20 -0
  386. package/src/dashboard/first-screen-band.ts +151 -1
  387. package/src/dashboard/index.ts +27 -5
  388. package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -3
  389. package/src/dashboard/stale-install-check.ts +13 -2
  390. package/src/dashboard/turn-stream-formatter.ts +25 -0
  391. package/src/debug/log-diet.ts +159 -0
  392. package/src/debug/log.ts +52 -17
  393. package/src/decisions/decision-cards.ts +20 -1
  394. package/src/decisions/decision-ledger.ts +11 -8
  395. package/src/decisions/web-push-decision-cards.ts +19 -3
  396. package/src/discord-self-message.ts +2 -2
  397. package/src/display/coordinator.ts +25 -2
  398. package/src/domains/coo-admin-dates.evidence.json +876 -0
  399. package/src/domains/coo-admin-tool.ts +75 -14
  400. package/src/domains/cron-match.ts +1 -0
  401. package/src/domains/ops-status.ts +53 -0
  402. package/src/domains/outbound-alert.ts +41 -7
  403. package/src/domains/release-tool.ts +119 -10
  404. package/src/domains/schedule-registry.ts +10 -7
  405. package/src/domains/schedule-runner.ts +1 -0
  406. package/src/elanous-config-dir.ts +2 -2
  407. package/src/elanous-daemon.ts +3 -3
  408. package/src/exec-requests/planner.ts +6 -0
  409. package/src/execution-loop/launch-gate.ts +1 -1
  410. package/src/expression/i18n/messages.en.ts +5 -0
  411. package/src/expression/i18n/messages.ja.ts +5 -0
  412. package/src/expression/i18n/messages.ko.ts +5 -0
  413. package/src/expression/i18n/messages.zh.ts +5 -0
  414. package/src/expression/i18n/types.ts +8 -0
  415. package/src/github/pr-labels.ts +1 -0
  416. package/src/graph-kinds/registry.ts +6 -6
  417. package/src/graph-runner/graph-cli.ts +34 -2
  418. package/src/graph-runner/graph-run-api.ts +7 -0
  419. package/src/graph-runner/graph-tick.ts +73 -12
  420. package/src/graph-runner/runner.ts +94 -13
  421. package/src/graph-unify/wf-to-graph.ts +79 -0
  422. package/src/graph-wizard/generate.ts +34 -2
  423. package/src/graph-wizard/steps.ts +13 -0
  424. package/src/harness/dispatch-backpressure.ts +259 -0
  425. package/src/harness/harness-cli-command.ts +227 -50
  426. package/src/harness/harness-queue.ts +58 -14
  427. package/src/harness/harness-seams.ts +2 -20
  428. package/src/harness/harness-substrate-default.ts +72 -1
  429. package/src/harness/launch-advice.ts +23 -0
  430. package/src/harness/nested-elanous-policy.ts +4 -2
  431. package/src/hq/fence-wrapper.ts +7 -0
  432. package/src/hq/hq.ts +33 -2
  433. package/src/hq/lease.ts +13 -0
  434. package/src/hq/seats.ts +114 -18
  435. package/src/index.ts +199 -71
  436. package/src/intake-plane/collect-github.ts +19 -1
  437. package/src/intake-plane/digest.ts +45 -20
  438. package/src/intake-plane/lens.ts +36 -8
  439. package/src/intelligence-map/model-alias.ts +6 -0
  440. package/src/intelligence-map/model-catalog.ts +41 -0
  441. package/src/knowledge/conclusion-compress.ts +93 -0
  442. package/src/knowledge/kgs/pack.ts +5 -2
  443. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  444. package/src/knowledge/know-find.ts +9 -2
  445. package/src/knowledge/query.ts +20 -0
  446. package/src/knowledge/tools/knowledge-query.ts +20 -2
  447. package/src/knowledge/write.ts +234 -2
  448. package/src/llm/bedrock-provider.ts +175 -0
  449. package/src/llm/bedrock.ts +345 -0
  450. package/src/llm/provider-credentials.ts +3 -1
  451. package/src/llm.ts +332 -51
  452. package/src/loops/budget.ts +150 -0
  453. package/src/loops/neighbor-runtime.ts +88 -0
  454. package/src/loops/orchestrator/author-depth.ts +29 -11
  455. package/src/loops/orchestrator/overlap.ts +7 -1
  456. package/src/loops/orchestrator/resync-shadow.ts +1 -1
  457. package/src/loops/orchestrator/seat-share.ts +6 -49
  458. package/src/loops/orchestrator/tick.ts +35 -2
  459. package/src/loops/orchestrator/traffic.ts +6 -80
  460. package/src/loops/registry.ts +5 -0
  461. package/src/market/publish.ts +17 -1
  462. package/src/market/signed-index.ts +42 -0
  463. package/src/maturity/feature-maturity.ts +2 -1
  464. package/src/mcp/mcp-oauth.ts +136 -17
  465. package/src/model-tier/llm-tier-map.ts +48 -4
  466. package/src/models/prompts.ts +22 -1
  467. package/src/mss/logging/horizon-watch.ts +168 -0
  468. package/src/mss/logging/log-store.ts +204 -15
  469. package/src/mss/logging/redaction.ts +17 -0
  470. package/src/native-tool-catalog.ts +1 -1
  471. package/src/nexus/api/consult-requests.ts +7 -10
  472. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  473. package/src/nexus/api/draft-metrics.ts +22 -8
  474. package/src/nexus/api/error-reports.ts +30 -8
  475. package/src/nexus/api/graph-peer-edit.ts +77 -0
  476. package/src/nexus/api/graph-wizard-api.ts +9 -1
  477. package/src/nexus/api/graphs-api.ts +145 -7
  478. package/src/nexus/api/http-server.ts +101 -8
  479. package/src/nexus/api/loop-resources.ts +42 -0
  480. package/src/nexus/api/outbound-report.ts +8 -3
  481. package/src/nexus/api/plugins-market.ts +24 -0
  482. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  483. package/src/nexus/index.ts +13 -2
  484. package/src/nexus/outbound/format.ts +2 -0
  485. package/src/nexus/outbound/router.ts +198 -13
  486. package/src/oauth/claude-pty-maturity.ts +24 -0
  487. package/src/oauth/codex-account-rotation.ts +16 -18
  488. package/src/oauth/codex-account-store.ts +134 -5
  489. package/src/oauth/fallback-chain.ts +50 -15
  490. package/src/onboarding.ts +2 -1
  491. package/src/plugins/adapters/claude-package.ts +4 -12
  492. package/src/plugins/core/capability-policy.ts +141 -0
  493. package/src/plugins/core/host.ts +21 -8
  494. package/src/plugins/core/manifest.ts +19 -2
  495. package/src/plugins/core/trust-store.ts +15 -0
  496. package/src/plugins/core/types.ts +12 -0
  497. package/src/plugins/install/market-fetch.ts +68 -16
  498. package/src/plugins/install/plugin-install.ts +187 -16
  499. package/src/plugins/maker/market-bundle.ts +9 -0
  500. package/src/plugins/maker/plugin-maker.ts +32 -21
  501. package/src/plugins/maker/wizard-generate.ts +87 -9
  502. package/src/policy/llm-policy.ts +24 -6
  503. package/src/process/pid-liveness.ts +1 -1
  504. package/src/prompt-cache/openai.ts +10 -6
  505. package/src/prompt-cache/openrouter.ts +94 -0
  506. package/src/prompt-enhance/enhance.ts +46 -5
  507. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  508. package/src/prompt-library/universal-preamble.ts +2 -2
  509. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  510. package/src/registry/loader.ts +6 -1
  511. package/src/release-loop/checklist-board.ts +27 -0
  512. package/src/release-loop/checklist.ts +62 -9
  513. package/src/release-loop/feature-store.ts +3 -0
  514. package/src/release-loop/gate-shards.ts +48 -4
  515. package/src/release-loop/landed-to-green.ts +81 -0
  516. package/src/release-loop/light-rc.ts +11 -1
  517. package/src/release-loop/merged-pr-checklist.ts +10 -0
  518. package/src/release-loop/placement.ts +91 -22
  519. package/src/release-loop/rehearsal.ts +317 -0
  520. package/src/release-loop/release-schedule.ts +13 -1
  521. package/src/release-loop/rubric-types.ts +1 -0
  522. package/src/release-loop/rubric.ts +2 -2
  523. package/src/retro/daily.ts +23 -9
  524. package/src/seat-address/seat-address.ts +1 -0
  525. package/src/seat-loop/seat-loop.ts +208 -21
  526. package/src/seat-loop/seat-report.ts +29 -1
  527. package/src/seat-loop/traffic-signal.ts +44 -0
  528. package/src/self-dev/ask-launch-flow.ts +2 -2
  529. package/src/self-dev/dev-cli.ts +157 -11
  530. package/src/self-dev/dev-pipeline.ts +18 -1
  531. package/src/self-dev/draft-residue.ts +463 -0
  532. package/src/self-dev/draft-sweep.ts +195 -17
  533. package/src/self-dev/draft-triage-rules.ts +27 -1
  534. package/src/self-dev/launch-preflight-text.ts +549 -0
  535. package/src/self-dev/launch-preflight.ts +10 -545
  536. package/src/self-dev/orchestrate-cli.ts +57 -2
  537. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  538. package/src/self-dev/orchestrate.ts +9 -133
  539. package/src/self-dev/review-provider-fallback.ts +179 -0
  540. package/src/self-dev/run-store.ts +1 -3
  541. package/src/self-dev/run-supervisor.ts +8 -23
  542. package/src/self-dev/run-types.ts +178 -0
  543. package/src/self-dev/shard-aggregate.ts +61 -13
  544. package/src/self-dev/shard-plan.ts +5 -1
  545. package/src/self-dev/shard-run.ts +23 -5
  546. package/src/self-dev/supervisor-verdict-edges.ts +2 -4
  547. package/src/self-implement/blocked-draft-policy.ts +3 -19
  548. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  549. package/src/self-implement/follow-up-goals.ts +114 -38
  550. package/src/self-implement/gate-baseline-reap.ts +157 -0
  551. package/src/self-implement/gate-baseline.ts +78 -16
  552. package/src/self-implement/gate-cli.ts +12 -2
  553. package/src/self-implement/gate-remote.ts +17 -6
  554. package/src/self-implement/goal-author.ts +24 -4
  555. package/src/self-implement/goal-digest.ts +19 -0
  556. package/src/self-implement/graph-overlay-condition.ts +4 -0
  557. package/src/self-implement/harness-policy-gates.ts +7 -5
  558. package/src/self-implement/headless-elanous-driver.ts +11 -9
  559. package/src/self-implement/host-regate.ts +148 -43
  560. package/src/self-implement/l8-merge-queue.ts +147 -13
  561. package/src/self-implement/merge-train.ts +131 -0
  562. package/src/self-implement/off-diff-evidence.ts +9 -0
  563. package/src/self-implement/orchestrator.ts +201 -43
  564. package/src/self-implement/review-finding-recurrence.ts +28 -0
  565. package/src/self-implement/rework-policy.ts +2 -1
  566. package/src/self-implement/round-summary-card.ts +63 -0
  567. package/src/self-implement/run-ledger.ts +4 -3
  568. package/src/self-implement/run-step-projection.ts +147 -0
  569. package/src/self-implement/run-stop.ts +1 -1
  570. package/src/self-implement/seams.ts +41 -6
  571. package/src/self-implement/self-implement-cli.ts +6 -0
  572. package/src/self-implement/train-gate-remote.ts +158 -0
  573. package/src/session-runtime/index.ts +10 -1
  574. package/src/session-runtime/retry-api.ts +11 -1
  575. package/src/shell-env-bootstrap.ts +19 -4
  576. package/src/skills/gift-install.ts +119 -0
  577. package/src/skills/runner.ts +59 -2
  578. package/src/skills/skill-feedback.ts +31 -1
  579. package/src/skills/skill-tier.ts +1 -0
  580. package/src/smart-wizard/capability-index.ts +231 -0
  581. package/src/smart-wizard/rung.ts +74 -0
  582. package/src/steward/launch.ts +20 -9
  583. package/src/steward/triage.ts +29 -10
  584. package/src/storage/file-lock.ts +40 -4
  585. package/src/task-agent/actions.ts +4 -0
  586. package/src/task-agent/card-evidence.ts +59 -13
  587. package/src/task-agent/completion-evidence.ts +31 -3
  588. package/src/task-agent/cover.ts +61 -0
  589. package/src/task-agent/judge.ts +4 -3
  590. package/src/task-agent/land-worktree.ts +201 -0
  591. package/src/task-agent/live-move-history.ts +133 -0
  592. package/src/task-agent/live-moves.ts +222 -12
  593. package/src/task-agent/parent-host.ts +117 -8
  594. package/src/task-agent/rejudge-on-head.ts +297 -0
  595. package/src/task-agent/review-result-capture.ts +218 -0
  596. package/src/task-agent/shadow.ts +118 -7
  597. package/src/task-agent/task-hand.ts +138 -11
  598. package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
  599. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  600. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
  601. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  602. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
  603. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
  604. package/src/task-orchestrator/surfaces/pod-pool.ts +203 -28
  605. package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
  606. package/src/task-orchestrator/surfaces/self-implement.ts +11 -0
  607. package/src/telegram-commands.ts +8 -0
  608. package/src/telegram-project-command.ts +6 -0
  609. package/src/telegram-service.ts +5 -1
  610. package/src/telegram.ts +17 -4
  611. package/src/time/format.ts +13 -4
  612. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  613. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  614. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  615. package/src/typecheck-ratchet.ts +2 -1
  616. package/src/user-config.ts +167 -28
  617. package/src/ux-sim/slash-menu-frames.ts +168 -0
  618. package/src/version/packed-revision.json +1 -1
  619. package/src/web-terminal/preview-tap-registry.ts +5 -2
  620. package/src/workflow-runtime/executor.ts +24 -2
  621. package/src/workflow-runtime/triggers/registry.ts +27 -0
  622. package/src/workflow-runtime/triggers/schedule-source.ts +30 -3
  623. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  624. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  625. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  626. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  627. package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  629. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  630. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  631. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  633. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  638. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  647. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  648. package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  661. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  669. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  674. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  676. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  680. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  684. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  689. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  690. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  692. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  693. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  701. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  704. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  714. package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  717. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  721. package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  723. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/live/page-be8b4615c919e36c.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  779. package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +0 -1
  780. /package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@ import { ensureRunIdentity, getHarnessSpace, normalizeSpaceId } from './harness/
25
25
  // 그 import 자체가 첫 비동기 작업이 되어, 그것이 거부되면 가드 없이 끝난다(무인 리뷰 must-fix).
26
26
  // ⇒ «정적» import 로 올린다. 이 모듈은 부작용이 없어 부팅 비용이 사실상 0 이다.
27
27
  import { installDevCompletionGuard } from './self-dev/dev-completion-guard.js';
28
+ import { formatOrchestrateResultLine } from './self-dev/orchestrate-summary-line.js';
28
29
  import { buildOrchestrateDecomposePrepareArgs, normalizeOrchestrateRequest, splitOrchestrateGoalTexts } from './self-dev/self-orchestrate-runtime.js';
29
30
  import { CLI_ENTRANCE_BASELINE, evaluateCommandEntranceBaseline } from './self-dev/entrance-baseline.js';
30
31
  import { CLI_HARNESS_DOGFOOD_ENTRANCE, CLI_HARNESS_ORCHESTRATE_ENTRANCE, describeEntranceCommand, listEntrancesWithModelExposure, renderLaunchEntrances, summarizeEntrances, type EntranceId } from './self-dev/entrance-registry.js';
@@ -613,9 +614,10 @@ function buildHarnessAskSayDevCliSpec(
613
614
  input: { file: string },
614
615
  cliOpts: ReturnType<typeof harnessAskSayOptionsToDevCliOpts>,
615
616
  entranceId: EntranceId,
617
+ runId: string,
616
618
  ) {
617
619
  return {
618
- ...buildDevCliSpec(input, { kind: 'self' }, cliOpts, Object.keys(cliOpts), entranceId),
620
+ ...buildDevCliSpec(input, { kind: 'self' }, cliOpts, Object.keys(cliOpts), entranceId, undefined, undefined, runId),
619
621
  ...(cliOpts.json ? { humanReadableOutput: false } : {}),
620
622
  };
621
623
  }
@@ -661,6 +663,7 @@ async function runDevAskFromAskFile(askPath: string, opts: HarnessAskSayChildLlm
661
663
  { file: flowResult.goalFile },
662
664
  cliOpts,
663
665
  CLI_HARNESS_ASK_ENTRANCE.id,
666
+ identity.runId,
664
667
  ),
665
668
  ...(pieceFeature === undefined ? {} : { input: { text: pieceFeature } }),
666
669
  ...(base === undefined ? {} : { base }),
@@ -765,6 +768,7 @@ async function runDevAskFromGoalFile(goalPath: string, opts: HarnessAskSayChildL
765
768
  { file: goalPath },
766
769
  cliOpts,
767
770
  CLI_HARNESS_ASK_ENTRANCE.id,
771
+ identity.runId,
768
772
  ),
769
773
  runId: identity.runId,
770
774
  runIdSource: identity.source,
@@ -868,6 +872,7 @@ async function runDevSayFromWords(
868
872
  { file: flowResult.goalFile },
869
873
  cliOpts,
870
874
  entrance,
875
+ identity.runId,
871
876
  ),
872
877
  runId: identity.runId,
873
878
  runIdSource: identity.source,
@@ -1069,6 +1074,17 @@ fenceWrapperCmd.command('alert <reason>').description('HQ 울타리 실패를
1069
1074
  hqFenceAlert(reason, { root, outcomeDir: fenceOutcomeDir(_joinPath(root, 'hq', 'local.json')) });
1070
1075
  } catch (error) { console.error(`hq fence-wrapper alert: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
1071
1076
  });
1077
+ fenceWrapperCmd.command('record <role> <rc>').description('가벼운 울타리(FENCE-LIGHT)가 돌린 잡의 rc 를 역할별 연속 실패 기록에 남김')
1078
+ .action(async (role: string, rc: string) => {
1079
+ try {
1080
+ const { FENCE_ROLES } = await import('./hq/hq.js');
1081
+ if (!(FENCE_ROLES as readonly string[]).includes(role)) throw new Error(`unknown role: ${role}`);
1082
+ if (!/^\d{1,3}$/.test(rc)) throw new Error(`rc must be 0-255: ${rc}`);
1083
+ const { fenceOutcomeDir, recordFenceOutcome } = await import('./hq/fence-outcomes.js');
1084
+ const { getElanousConfigDir } = await import('./elanous-config-dir.js');
1085
+ recordFenceOutcome(fenceOutcomeDir(_joinPath(getElanousConfigDir(), 'hq', 'local.json')), role, Number(rc));
1086
+ } catch (error) { console.error(`hq fence-wrapper record: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
1087
+ });
1072
1088
  hqCmd.command('fence-audit').description('운영 crontab 의 HQ 울타리 밖 쓰기 잡 목록과 감싼 줄 제안(읽기 전용)')
1073
1089
  .option('--json', 'JSON 출력')
1074
1090
  .action(async (opts: { json?: boolean }) => {
@@ -1271,9 +1287,10 @@ marketCmd.command('publish').description('Publish a local signed marketplace ind
1271
1287
  .option('--source-sha <sha>', 'Git source commit')
1272
1288
  .option('--source-base <path>', 'Git source plugin base directory')
1273
1289
  .option('--bundle-root <dir>', 'Root that extensions["ai.elanous"].bundle paths resolve against (usually the repository root)')
1290
+ .option('--keep-existing', 'Carry over previous index entries whose name has no folder under --dir (unchanged entry and archive)')
1274
1291
  .option('--json', 'JSON result')
1275
1292
  .action(async (opts: { dir: string; out: string; key: string; keyId: string; marketName: string; displayName: string;
1276
- sourceRepo?: string; sourceSha?: string; sourceBase?: string; bundleRoot?: string; json?: boolean }) => {
1293
+ sourceRepo?: string; sourceSha?: string; sourceBase?: string; bundleRoot?: string; keepExisting?: boolean; json?: boolean }) => {
1277
1294
  try {
1278
1295
  const sourceOptions = [opts.sourceRepo, opts.sourceSha, opts.sourceBase];
1279
1296
  if (sourceOptions.some(Boolean) && !sourceOptions.every(Boolean)) throw new Error('source-repo, source-sha and source-base must be provided together');
@@ -1282,12 +1299,14 @@ marketCmd.command('publish').description('Publish a local signed marketplace ind
1282
1299
  market: { name: opts.marketName, displayName: opts.displayName },
1283
1300
  key: { keyId: opts.keyId, privateKeyPem: readFileSync(opts.key, 'utf8') },
1284
1301
  ...(opts.bundleRoot ? { bundleRoot: opts.bundleRoot } : {}),
1302
+ ...(opts.keepExisting ? { keepExisting: true } : {}),
1285
1303
  ...(opts.sourceRepo && opts.sourceSha && opts.sourceBase
1286
1304
  ? { source: { repoUrl: opts.sourceRepo, sha: opts.sourceSha, basePath: opts.sourceBase } } : {}),
1287
1305
  });
1288
1306
  if (opts.json) await writeStdoutJson(JSON.stringify(result) + '\n');
1289
1307
  else {
1290
- console.log(`Published ${result.published.length} plugins (sequence ${result.sequence}); skipped ${result.skipped.length}`);
1308
+ console.log(`Published ${result.published.length} plugins (sequence ${result.sequence}); skipped ${result.skipped.length}` +
1309
+ (opts.keepExisting ? `; kept ${result.kept.length}` : ''));
1291
1310
  for (const warning of result.warnings) console.warn(`⚠ ${warning.dir}: ${warning.graph} uses recipes it does not ship (${warning.recipes.join(', ')}) — third-party graphs should use their own recipes.yaml or custom nodes`);
1292
1311
  }
1293
1312
  for (const item of result.skipped) {
@@ -1677,7 +1696,7 @@ telegramCmd
1677
1696
  const { spawnSync } = await import('node:child_process');
1678
1697
  const result = installTelegramService(file, getUserConfig().telegram.poller, process.getuid?.() ?? 0, {
1679
1698
  exists: fs.existsSync, readFile: (p) => fs.readFileSync(p, 'utf8'), writeFile: (p, t) => fs.writeFileSync(p, t),
1680
- mkdir: (p) => fs.mkdirSync(p, { recursive: true }), rename: fs.renameSync,
1699
+ mkdir: (p) => fs.mkdirSync(p, { recursive: true }), rename: fs.renameSync, chmod: fs.chmodSync,
1681
1700
  run: (c, a) => { const r = spawnSync(c, a, { encoding: 'utf8' }); return { status: r.status, stderr: r.stderr ?? String(r.error ?? '') }; },
1682
1701
  });
1683
1702
  debug.log('telegram.service', 'install', { ok: result.ok, path: result.path, backup: result.backup, steps: result.steps, reason: result.reason });
@@ -3477,8 +3496,10 @@ coordCmd.command('event').command('record')
3477
3496
  .requiredOption('--header <line>', '채널 글 첫 줄')
3478
3497
  .option('--url <url>', '채널 코멘트 URL')
3479
3498
  .action(async (opts: { seat: string; header: string; url?: string }) => {
3480
- const { parseCoordHeader, recordCoordEvent } = await import('./context-bus/coord-events.js');
3481
- recordCoordEvent({ ...parseCoordHeader(opts.seat, opts.header), url: opts.url || null });
3499
+ const { parseCoordHeader, recordCoordEvent, mirrorCoordDecision } = await import('./context-bus/coord-events.js');
3500
+ const input = { ...parseCoordHeader(opts.seat, opts.header), url: opts.url || null, at: new Date().toISOString() };
3501
+ try { recordCoordEvent(input); }
3502
+ finally { mirrorCoordDecision(input); }
3482
3503
  });
3483
3504
  coordCmd.command('events')
3484
3505
  .option('--since <ISO|2h>', '조회 시작', '2h')
@@ -4692,7 +4713,7 @@ const selfOrchestrateCmd = selfCmd
4692
4713
  .option('--no-pod-rebuild', 'pod: 이미지 판(elanous.commit)이 HEAD 와 달라도 다시 굽지 않는다 — 측정은 «이미지 판»을 잰다')
4693
4714
  .option('--pod-pass-env <keys>', 'pod: 호스트 env 에서 Pod 로 넘길 키(쉼표) — 예 OPENROUTER_API_KEY,ANTHROPIC_API_KEY(벤치마크 과금 경로)')
4694
4715
  .option('--bench-arms <spec>', 'pod 벤치마크: 골 1개를 팔마다 «라벨 한 줄만 다르게» 복제해 동시에 — "id=provider[:model][@KEY+KEY];…" (예 codex=openai-codex;or-kimi=openrouter:openrouter/moonshotai/kimi-k3@OPENROUTER_API_KEY) · --auto-merge 거부 · RFC fleet 슈퍼바이저 §A3')
4695
- .addOption(new Option('--child-llm-provider <id>', 'pod: 구현 자식 LLM provider(openai-codex|grok) — 하니스 --child-llm-provider 가 이 자리로 온다(10-05)').hideHelp())
4716
+ .addOption(new Option('--child-llm-provider <id>', 'pod: 구현 자식 LLM provider(openai-codex|grok|openrouter|anthropic) — 하니스 --child-llm-provider 가 이 자리로 온다(10-05)').hideHelp())
4696
4717
  .addOption(new Option('--child-llm-model <id>', 'pod: 구현 자식 LLM model(--child-llm-provider 와 함께)').hideHelp())
4697
4718
  .addOption(new Option('--child-llm-effort <level>', 'pod: 구현 자식 추론 노력(--child-llm-provider 와 함께)').hideHelp())
4698
4719
  .option('--help-all', '모든 orchestrate 옵션 표시')
@@ -4870,7 +4891,9 @@ const selfOrchestrateCmd = selfCmd
4870
4891
  if (substrate === 'pod') {
4871
4892
  const { podSelfImplementSpawn, podSubstrateReady, defaultKubectl } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
4872
4893
  const poolMod = await import('./task-orchestrator/surfaces/pod-pool.js');
4873
- const poolSpec = poolMod.resolvePodPoolSpec((opts as { podPool?: string }).podPool);
4894
+ const { harnessLaunchPolicyConfig } = await import('./harness/harness-substrate-default.js');
4895
+ const launchPolicy = harnessLaunchPolicyConfig();
4896
+ const poolSpec = poolMod.resolvePodPoolSpec((opts as { podPool?: string }).podPool, process.env, () => launchPolicy.harness?.podPool ?? launchPolicy.pod?.pool);
4874
4897
  let pool: import('./task-orchestrator/surfaces/pod-pool.js').PodPoolScheduler | undefined;
4875
4898
  let poolMembers: import('./task-orchestrator/surfaces/pod-pool.js').PodPoolMember[] = [];
4876
4899
  let ready: { ok: boolean; reason: string };
@@ -4889,41 +4912,82 @@ const selfOrchestrateCmd = selfCmd
4889
4912
  }
4890
4913
  if (!ready.ok) { ui.error(`--substrate pod: ${ready.reason}`); process.exit(2); }
4891
4914
  // ⛔ Pod 의 elanous 는 이미지 판이다 — HEAD 와 다르면 다시 굽는다(BACKLOG E6 · 09-25 세 판이 옛 판을 쟀다).
4892
- const { podImageFreshness } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
4893
- // ☸️ 풀이 «원격 노드뿐»이면 이 기계의 이미지는 아무도 안 쓴다 — 로컬 판정·굽기를 건너뛰고 기준 판 = HEAD 로 노드 동기화만 한다.
4894
- // 🩸 2026-09-26 실측: 원격 전용 풀인데 로컬 이미지가 없다고 로컬에서 굽다가 로컬 클러스터(elanous-h1)가 없어 런이 시작도 전에 죽었다.
4895
- const remoteOnlyPool = poolMembers.length > 0 && poolMembers.every((m) => Boolean(m.sshHost));
4896
- const headCommit = remoteOnlyPool ? ((await import('./git-fs/runner.js')).runGitCommand(process.cwd(), ['rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim() || null) : null;
4897
- let image = remoteOnlyPool
4898
- ? { imageCommit: headCommit, headCommit, fresh: true, reason: 'remote-only pool — 노드 쪽에서 맞춘다' }
4899
- : podImageFreshness();
4900
- if (!image.fresh) {
4901
- if ((opts as { podRebuild?: boolean }).podRebuild === false) {
4902
- ui.warn(`--substrate pod: 이미지가 낡았다(${image.reason}) — --no-pod-rebuild 라 그대로 쓴다. 측정은 «이미지 판»을 잰다.`);
4903
- } else {
4904
- if (!opts.json) ui.info(`[pod] 이미지 다시 굽기 — ${image.reason} (~1분)`);
4905
- const { spawnSync } = await import('node:child_process');
4906
- const { runGitCommand } = await import('./git-fs/runner.js');
4907
- const top = runGitCommand(process.cwd(), ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).stdout.trim() || process.cwd();
4908
- // bun 1.4 applies the 1 MiB default maxBuffer: a docker build log past it kills the child (ENOBUFS · status null).
4909
- const b = spawnSync('bash', [`${top}/docker/harness/build.sh`], { encoding: 'utf8', timeout: 900_000, maxBuffer: 64 * 1024 * 1024 });
4910
- if (b.status !== 0) { ui.error(`--substrate pod: 이미지 굽기 실패 rc=${b.status}${b.error ? ` (${(b.error as NodeJS.ErrnoException).code ?? b.error.message})` : ''}: ${(b.stdout + b.stderr).slice(-400)}`); process.exit(2); }
4911
- image = podImageFreshness();
4915
+ const { podImageFreshness, rebuildLocalPodImageOnce } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
4916
+ type PodPoolMemberT = import('./task-orchestrator/surfaces/pod-pool.js').PodPoolMember;
4917
+ let remoteOnlyPool = false;
4918
+ // 종전 경로(HEAD 비교·굽기·노드 동기화). IMAGE-ONE-SOURCE: 기준값이 없으면 전 멤버로 «그대로» 부른다.
4919
+ const podHeadImagePath = async (members: readonly PodPoolMemberT[]) => {
4920
+ // ☸️ 풀이 «원격 노드뿐»이면 이 기계의 이미지는 아무도 안 쓴다 — 로컬 판정·굽기를 건너뛰고 기준 판 = HEAD 로 노드 동기화만 한다.
4921
+ // 🩸 2026-09-26 실측: 원격 전용 풀인데 로컬 이미지가 없다고 로컬에서 굽다가 로컬 클러스터(elanous-h1)가 없어 런이 시작도 전에 죽었다.
4922
+ remoteOnlyPool = members.length > 0 && members.every((m) => Boolean(m.sshHost));
4923
+ const headCommit = remoteOnlyPool ? ((await import('./git-fs/runner.js')).runGitCommand(process.cwd(), ['rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim() || null) : null;
4924
+ let image = remoteOnlyPool
4925
+ ? { imageCommit: headCommit, headCommit, fresh: true, reason: 'remote-only pool — 노드 쪽에서 맞춘다' }
4926
+ : podImageFreshness();
4927
+ if (!image.fresh) {
4928
+ if ((opts as { podRebuild?: boolean }).podRebuild === false) {
4929
+ ui.warn(`--substrate pod: 이미지가 낡았다(${image.reason}) — --no-pod-rebuild 라 그대로 쓴다. 측정은 «이미지 판»을 잰다.`);
4930
+ } else {
4931
+ const rebuilt = await rebuildLocalPodImageOnce({ initialImage: image,
4932
+ onBuild: (reason) => { if (!opts.json) ui.info(`[pod] 이미지 다시 굽기 — ${reason} (~1분)`); },
4933
+ onWait: () => { if (!opts.json) ui.info('[pod] 이미지 굽기 대기 — 같은 호스트의 다른 부모가 굽는 중'); },
4934
+ });
4935
+ if (rebuilt.action === 'failed') { ui.error(rebuilt.error ?? '--substrate pod: 이미지 굽기 실패'); process.exit(2); }
4936
+ image = rebuilt.image;
4937
+ }
4938
+ }
4939
+ debug.log('self-implement.pod', 'image-freshness', { ...image });
4940
+ // ☸️ 원격 노드도 «같은 판»이어야 한다 — 다르면 보내서 넣는다. 못 맞춘 노드는 풀에서 뺀다.
4941
+ const synced: PodPoolMemberT[] = [];
4942
+ if (pool) {
4943
+ // ⭐ 노드들을 «동시에» — 노드 쪽 빌드(바뀐 층만) 1순위 · 실패하면 통째 전송.
4944
+ const { podSkillsDigest, resolvePodSkills } = await import('./task-orchestrator/surfaces/pod-skills.js');
4945
+ const syncs = await poolMod.syncPoolImages(members, 'elanous-harness:local', image.imageCommit, { localSkillsDigest: podSkillsDigest(resolvePodSkills().skills).digest });
4946
+ for (const m of members) {
4947
+ const r = syncs.get(m.context)!;
4948
+ debug.log('self-implement.pod', 'pool-image-sync', { context: m.context, ...r });
4949
+ if (r.ok) synced.push(r.imageRef ? { ...m, imageRef: r.imageRef } : m); else ui.warn(`[pod-pool] ${m.context} 뺌 — 이미지 판을 못 맞췄다: ${r.detail}`);
4950
+ if (!opts.json && (r.action === 'shipped' || r.action === 'built')) ui.info(`[pod-pool] ${m.context} 이미지 ${r.action === 'built' ? '노드 쪽 빌드' : '보냄'} ${r.detail} · ${Math.round(r.ms / 1000)}초`);
4951
+ }
4912
4952
  }
4953
+ return { image, synced };
4954
+ };
4955
+ // 🧷 IMAGE-ONE-SOURCE: 운영 config `harness.imageCommit` 이 있으면 레지스트리를 가진 멤버는 굽지 않고 기준 이미지(커밋 태그)를 당긴다.
4956
+ const imageSourceMod = await import('./task-orchestrator/surfaces/pod-image-source.js');
4957
+ let podImageCfg: { harness?: { imageCommit?: unknown } } | undefined = undefined;
4958
+ // ⛔ 설정을 못 읽으면 «기준값 없음»으로 읽지 않는다 — 기준값이 있었을 수 있으니 굽지 않고 멈춘다.
4959
+ try { podImageCfg = (await import('./user-config.js')).getUserConfig(); } catch (e) {
4960
+ ui.error(`--substrate pod: 운영 config 를 못 읽어 기준 이미지(harness.imageCommit) 여부를 모른다 — 굽지 않고 멈춘다: ${(e as Error).message}`);
4961
+ debug.log('self-implement.pod', 'image-source', { kind: null, ref: null, headCommit: null, waitedMs: 0, outcome: 'config-unreadable', error: (e as Error).message });
4962
+ process.exit(2);
4913
4963
  }
4914
- debug.log('self-implement.pod', 'image-freshness', { ...image });
4915
- // ☸️ 원격 노드도 «같은 판»이어야 한다 — 다르면 보내서 넣는다. 못 맞춘 노드는 풀에서 뺀다.
4964
+ const pinWaitSec = process.env.ELANOUS_POD_IMAGE_PIN_WAIT_SEC?.trim() ? Number(process.env.ELANOUS_POD_IMAGE_PIN_WAIT_SEC) : Number.NaN;
4965
+ const preparedImage = await imageSourceMod.preparePodImage({
4966
+ cfg: podImageCfg,
4967
+ members: poolMembers,
4968
+ headPath: podHeadImagePath,
4969
+ ...imageSourceMod.podPoolImageLookup(),
4970
+ ...(Number.isFinite(pinWaitSec) && pinWaitSec >= 0 ? { maxWaitMs: pinWaitSec * 1000 } : {}),
4971
+ onWait: (pending, waitedMs) => { if (!opts.json) ui.info(`[pod] 기준 이미지 대기 — ${pending.map((m) => m.context).join(',')} 레지스트리에 아직 없다 (${Math.round(waitedMs / 1000)}초)`); },
4972
+ });
4973
+ // ref = 멤버가 «실제로» 당기는(또는 찾던) 이미지 ref 집합 — 기준 이미지 · 못 찾은 기준 이미지 · 종전 경로 멤버의 imageRef 또는 elanous-harness:local.
4974
+ const usedImageRefs = [...new Set([...preparedImage.pinned.map((m) => m.imageRef), ...preparedImage.missing.map((x) => x.ref), ...(preparedImage.head ? (pool ? preparedImage.head.synced.map((m) => m.imageRef ?? 'elanous-harness:local') : ['elanous-harness:local']) : [])])];
4975
+ if (preparedImage.source.kind === 'pinned') {
4976
+ const pinnedHead = (await import('./git-fs/runner.js')).runGitCommand(process.cwd(), ['rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim() || null;
4977
+ imageSourceMod.logPinnedImageSource(preparedImage, { ref: usedImageRefs.join(', '), headCommit: pinnedHead });
4978
+ if (preparedImage.outcome === 'pinned-missing') { ui.error(imageSourceMod.podImageMissingMessage([...new Set(preparedImage.missing.map((x) => x.ref))].join(', '))); process.exit(2); }
4979
+ for (const x of preparedImage.missing) ui.warn(`[pod-pool] ${x.member.context} 뺌 — ${imageSourceMod.podImageMissingMessage(x.ref)}`);
4980
+ } else {
4981
+ debug.log('self-implement.pod', 'image-source', { kind: 'head', ref: usedImageRefs.join(', ') || null, headCommit: preparedImage.head?.image.headCommit ?? null, waitedMs: 0, outcome: 'head' });
4982
+ }
4983
+ const pinnedOnly = preparedImage.head === null && preparedImage.source.kind === 'pinned';
4984
+ if (pinnedOnly) remoteOnlyPool = true;
4985
+ const image = preparedImage.head?.image
4986
+ ?? { imageCommit: preparedImage.source.kind === 'pinned' ? preparedImage.source.commit : null, headCommit: null, fresh: true, reason: 'pinned — 레지스트리 기준 이미지' };
4916
4987
  if (pool) {
4917
- const synced: typeof poolMembers = [];
4918
- // ⭐ 노드들을 «동시에» — 노드 쪽 빌드(바뀐 층만) 1순위 · 실패하면 통째 전송.
4919
- const { podSkillsDigest, resolvePodSkills } = await import('./task-orchestrator/surfaces/pod-skills.js');
4920
- const syncs = await poolMod.syncPoolImages(poolMembers, 'elanous-harness:local', image.imageCommit, { localSkillsDigest: podSkillsDigest(resolvePodSkills().skills).digest });
4921
- for (const m of poolMembers) {
4922
- const r = syncs.get(m.context)!;
4923
- debug.log('self-implement.pod', 'pool-image-sync', { context: m.context, ...r });
4924
- if (r.ok) synced.push(r.imageRef ? { ...m, imageRef: r.imageRef } : m); else ui.warn(`[pod-pool] ${m.context} 뺌 — 이미지 판을 못 맞췄다: ${r.detail}`);
4925
- if (!opts.json && (r.action === 'shipped' || r.action === 'built')) ui.info(`[pod-pool] ${m.context} 이미지 ${r.action === 'built' ? '노드 쪽 빌드' : '보냄'} ${r.detail} · ${Math.round(r.ms / 1000)}초`);
4926
- }
4988
+ const ok = new Set([...preparedImage.pinned.map((m) => m.context), ...(preparedImage.head?.synced ?? []).map((m) => m.context)]);
4989
+ const byContext = new Map<string, PodPoolMemberT>([...(preparedImage.head?.synced ?? []), ...preparedImage.pinned].map((m) => [m.context, m]));
4990
+ const synced = poolMembers.filter((m) => ok.has(m.context)).map((m) => byContext.get(m.context)!);
4927
4991
  if (synced.length === 0) { ui.error('--substrate pod: 이미지를 맞춘 풀 노드가 없다'); process.exit(2); }
4928
4992
  pool = new poolMod.PodPoolScheduler(synced);
4929
4993
  poolMembers = synced;
@@ -4934,7 +4998,7 @@ const selfOrchestrateCmd = selfCmd
4934
4998
  const explicitPodAccount = (opts as { podAccount?: string }).podAccount;
4935
4999
  let accountBroker: (() => string) | undefined;
4936
5000
  let rotationAccounts: readonly string[] | undefined;
4937
- let podProvider: 'openai-codex' | 'grok' = 'openai-codex';
5001
+ let podProvider: import('./task-orchestrator/surfaces/pod-child-providers.js').PodChildProvider = 'openai-codex';
4938
5002
  let grokApiKeyOptIn = false;
4939
5003
  {
4940
5004
  // 10-05 PODPROVIDER: refuse child choices this Pod launch cannot honour instead of dropping them.
@@ -4944,8 +5008,8 @@ const selfOrchestrateCmd = selfCmd
4944
5008
  ? 'pod: --child-llm-model/--child-llm-effort 는 --child-llm-provider 와 함께'
4945
5009
  : named && benchArms
4946
5010
  ? 'pod: --child-llm-provider 는 --bench-arms 와 함께 못 쓴다(팔마다 모델이 하나다)'
4947
- : named === 'grok' && explicitPodAccount
4948
- ? 'pod: --child-llm-provider grok 은 --pod-account 와 함께 못 쓴다(그것은 codex 계정을 고정한다)'
5011
+ : (named === 'grok' || named === 'openrouter' || named === 'anthropic') && explicitPodAccount
5012
+ ? `pod: --child-llm-provider ${named} 은 --pod-account 와 함께 못 쓴다(그것은 codex 계정을 고정한다)`
4949
5013
  : undefined;
4950
5014
  if (refuse) { ui.error(refuse); debug.log('self-implement.pod', 'child-provider-refused', { provider: named ?? null, reason: refuse }); process.exit(2); }
4951
5015
  }
@@ -4953,13 +5017,15 @@ const selfOrchestrateCmd = selfCmd
4953
5017
  const { inspectCodexRotation } = await import('./oauth/codex-account-store.js');
4954
5018
  const { planPodProvider, makePodAccountBroker } = await import('./task-orchestrator/surfaces/pod-account-broker.js');
4955
5019
  const { resolveGrokCredential } = await import('./grok/credential.js');
4956
- const { getUserConfig } = await import('./user-config.js');
4957
5020
  const { defaultGrokModel } = await import('./grok/models.js');
4958
- grokApiKeyOptIn = getUserConfig().harness?.pod?.grokApiKeyOptIn === true;
5021
+ grokApiKeyOptIn = launchPolicy.harness?.pod?.grokApiKeyOptIn === true;
4959
5022
  const credential = resolveGrokCredential();
4960
5023
  const { resolveCodexQuotaPolicy, codexPolicyAllowsCredits, codexPolicyAllowsFallback } = await import('./oauth/codex-quota-policy.js');
4961
- const resolvedQuota = resolveCodexQuotaPolicy(getUserConfig().llm);
5024
+ const resolvedQuota = resolveCodexQuotaPolicy(launchPolicy.llm);
4962
5025
  const quotaPolicy = resolvedQuota.policy;
5026
+ const { normalizeFallbackChain } = await import('./oauth/fallback-chain.js');
5027
+ const fallbackEnabled = codexPolicyAllowsFallback(quotaPolicy)
5028
+ && normalizeFallbackChain(launchPolicy.llm?.fallbackChain).chain.includes('grok');
4963
5029
  // POL1 — say which policy this launch uses and where it came from; warn when a test universe disagrees with production.
4964
5030
  const { effectiveInstanceRoot, prodInstanceRoot } = await import('./instance/resolve.js');
4965
5031
  const root = effectiveInstanceRoot();
@@ -4979,7 +5045,7 @@ const selfOrchestrateCmd = selfCmd
4979
5045
  // GROK-OPTIONAL (10-05): an expiring grok subscription the host cannot refresh is dropped from the chain here,
4980
5046
  // so the launch goes on with codex instead of dying later in hostGrokCredentials.
4981
5047
  let grokSubscriptionUsable = credential?.kind === 'subscription';
4982
- if (grokSubscriptionUsable && codexPolicyAllowsFallback(quotaPolicy)) {
5048
+ if (grokSubscriptionUsable && fallbackEnabled) {
4983
5049
  const { podGrokSubscriptionUsable, podGrokSkippedLine } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
4984
5050
  const grokCheck = podGrokSubscriptionUsable();
4985
5051
  if (!grokCheck.usable) {
@@ -4990,41 +5056,61 @@ const selfOrchestrateCmd = selfCmd
4990
5056
  // 10-05 PODPROVIDER: a launch that named the child provider gets it, or is refused — never a silent codex.
4991
5057
  const namedChild = (opts as { childLlmProvider?: string }).childLlmProvider?.trim();
4992
5058
  const { podNamedChildProvider, podFallbackCredentials, podGrokSubscriptionUsable: namedGrokUsable } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
5059
+ const { readFileSync: readPodKeyFile } = await import('node:fs');
5060
+ const { homedir: podHome } = await import('node:os');
5061
+ const { join: podJoin } = await import('node:path');
5062
+ let openrouterKeyPresent = Boolean(process.env.OPENROUTER_API_KEY?.trim());
5063
+ if (namedChild === 'openrouter' && !openrouterKeyPresent) {
5064
+ try { openrouterKeyPresent = Boolean(readPodKeyFile(podJoin(podHome(), '.cache', 'openrouter_api_key'), 'utf8').trim()); } catch { /* missing host cache */ }
5065
+ }
5066
+ // POD-ANTHROPIC-PROVIDER — 제품 자격 해석(`getAnthropicApiKey` · 키 캐시 → env)으로 «있나»만 본다(값은 안 싣는다).
5067
+ const anthropicKeyPresent = namedChild === 'anthropic' && Boolean((await import('./config.js')).getAnthropicApiKey()?.trim());
4993
5068
  const namedChildDecision = podNamedChildProvider(namedChild, {
4994
5069
  grokSubscription: namedChild === 'grok' && credential?.kind === 'subscription' && (grokSubscriptionUsable || namedGrokUsable().usable),
4995
5070
  grokApiKey: credential?.kind === 'api_key' && grokApiKeyOptIn,
4996
- });
5071
+ openrouterKey: openrouterKeyPresent,
5072
+ anthropicKey: anthropicKeyPresent,
5073
+ }, (opts as { childLlmModel?: string }).childLlmModel);
4997
5074
  if (namedChildDecision.refuse) { ui.error(namedChildDecision.refuse); debug.log('self-implement.pod', 'child-provider-refused', { provider: namedChild, reason: namedChildDecision.refuse }); process.exit(2); }
4998
5075
  // A named codex child must stay codex — the plan may not fall back to grok (post-review must-fix).
4999
5076
  const namedCodex = namedChildDecision.provider === 'openai-codex';
5000
- const plan: import('./task-orchestrator/surfaces/pod-account-broker.js').PodProviderPlan = namedChildDecision.provider === 'grok'
5077
+ const plan: import('./task-orchestrator/surfaces/pod-account-broker.js').PodProviderPlan | null = namedChildDecision.provider === 'openrouter' || namedChildDecision.provider === 'anthropic' ? null : namedChildDecision.provider === 'grok'
5001
5078
  ? { provider: 'grok', excluded: [], grokSubscriptionEligible: credential?.kind === 'subscription' }
5002
5079
  : planPodProvider({
5003
5080
  codexCandidates: inspectCodexRotation().candidates,
5004
5081
  // Per-account caps (대표 default:97) override the Pod default cap — without them default was dropped at 60%.
5005
- thresholdPercentByAccount: getUserConfig().llm?.codexAccountRotationThresholdPercentByAccount,
5082
+ thresholdPercentByAccount: launchPolicy.llm?.codexAccountRotationThresholdPercentByAccount,
5006
5083
  // 대표 한도 정책 한 값(`llm.codexQuotaPolicy`) — 크레딧·폴백을 같이 정한다.
5007
5084
  creditsAllowed: codexPolicyAllowsCredits(quotaPolicy),
5008
5085
  ...podFallbackCredentials(namedChildDecision.provider, {
5009
- grokSubscription: codexPolicyAllowsFallback(quotaPolicy) && grokSubscriptionUsable,
5010
- grokApiKey: codexPolicyAllowsFallback(quotaPolicy) && credential?.kind === 'api_key',
5086
+ grokSubscription: fallbackEnabled && grokSubscriptionUsable,
5087
+ grokApiKey: fallbackEnabled && credential?.kind === 'api_key',
5011
5088
  }),
5012
5089
  grokApiKeyOptIn,
5013
5090
  });
5014
- if (plan.provider === null) { ui.error(`pod: 쓸 codex 계정이 없다 — ${plan.reasons.join(' · ')}${namedCodex ? ' · child provider 를 openai-codex 로 지정해 grok 으로 넘기지 않는다' : ''} · 계정을 명시하려면 --pod-account <이름>`); process.exit(2); }
5015
- podProvider = plan.provider;
5016
- if (plan.provider === 'openai-codex') {
5091
+ if (plan?.provider === null) { ui.error(`pod: 쓸 codex 계정이 없다 — ${plan.reasons.join(' · ')}${namedCodex ? ' · child provider 를 openai-codex 로 지정해 grok 으로 넘기지 않는다' : ''} · 계정을 명시하려면 --pod-account <이름>`); process.exit(2); }
5092
+ podProvider = namedChildDecision.provider === 'openrouter' || namedChildDecision.provider === 'anthropic' ? namedChildDecision.provider : plan!.provider!;
5093
+ if (plan?.provider === 'openai-codex') {
5017
5094
  accountBroker = makePodAccountBroker({ usable: plan.accounts, excluded: plan.excluded });
5018
5095
  rotationAccounts = plan.accounts;
5019
5096
  debug.log('self-implement.pod', 'account-plan', { usable: plan.accounts, excluded: plan.excluded });
5020
5097
  { const { emitDecision } = await import('./live/detail-switch.js');
5021
5098
  emitDecision({ kind: 'ROUTE', what: `Pod 계정 배분 ${plan.accounts.join(' → ')}`, reason: plan.excluded.length ? `뺌 ${plan.excluded.map((x) => `${x.name}(${x.why})`).join(', ')}` : '모든 계정 여유', purpose: plan.creditAccounts ? '구독 잔량 0 — 정책상 크레딧으로 병렬 조각을 돌린다' : '병렬 조각이 한 계정에 몰리지 않게 잔량 순으로 돌려 준다', phase: 'dispatch', target: `Pod ${plan.accounts.length}계정`, paths: plan.accounts.length + plan.excluded.length }); }
5022
5099
  if (!opts.json) ui.info(`[pod] 계정 배분(잔량 순 · 돌려 가며): ${plan.accounts.join(' → ')}${plan.creditAccounts ? ' · 💳 크레딧(구독 잔량 0 · 허가됨)' : ''}${plan.excluded.length ? ` · 뺌 ${plan.excluded.map((x) => `${x.name}(${x.why})`).join(', ')}` : ''}`);
5100
+ } else if (namedChildDecision.provider === 'openrouter') {
5101
+ const model = (opts as { childLlmModel?: string }).childLlmModel!.trim();
5102
+ debug.log('self-implement.pod', 'provider-named', { provider: 'openrouter', model, openrouterKeyPresent: true });
5103
+ if (!opts.json) ui.info(`[pod] child provider = openrouter(모델 ${model}) — 발사 인자로 지정됨`);
5104
+ } else if (namedChildDecision.provider === 'anthropic') {
5105
+ const model = (opts as { childLlmModel?: string }).childLlmModel?.trim() || null;
5106
+ // ⓔ 과금 관측 — anthropic 은 API 키 과금(구독 아님). 새 예산 체계는 없다 · 관측 한 줄만.
5107
+ debug.log('self-implement.pod', 'provider-named', { provider: 'anthropic', model, anthropicKeyPresent: true, billing: 'api-key' });
5108
+ if (!opts.json) ui.info(`[pod] child provider = anthropic(모델 ${model ?? '기본'}) — 발사 인자로 지정됨 · 💳 API 키 과금(구독 아님)`);
5023
5109
  } else if (namedChildDecision.provider === 'grok') {
5024
5110
  const model = (opts as { childLlmModel?: string }).childLlmModel?.trim() || defaultGrokModel().id;
5025
5111
  debug.log('self-implement.pod', 'provider-named', { provider: 'grok', model, credential: credential?.kind ?? null });
5026
5112
  if (!opts.json) ui.info(`[pod] child provider = grok(모델 ${model}) — 발사 인자로 지정됨`);
5027
- } else {
5113
+ } else if (plan) {
5028
5114
  const model = defaultGrokModel().id;
5029
5115
  debug.log('self-implement.pod', 'provider-fallback', { from: 'openai-codex', to: 'grok', excluded: plan.excluded, model });
5030
5116
  { const { emitDecision } = await import('./live/detail-switch.js');
@@ -5032,7 +5118,7 @@ const selfOrchestrateCmd = selfCmd
5032
5118
  if (!opts.json) ui.info(`[pod] 쓸 codex 계정 없음(${plan.excluded.map((x) => `${x.name}: ${x.why}`).join(' · ')}) → grok 으로(모델 ${model})`);
5033
5119
  }
5034
5120
  }
5035
- const passEnv = podProvider === 'grok' ? requestedPassEnv.filter((key) => !grokKeyNames.includes(key)) : requestedPassEnv;
5121
+ const passEnv = podProvider === 'grok' ? requestedPassEnv.filter((key) => !grokKeyNames.includes(key)) : podProvider === 'openrouter' ? [...new Set([...requestedPassEnv, 'OPENROUTER_API_KEY'])] : podProvider === 'anthropic' ? [...new Set([...requestedPassEnv, 'ANTHROPIC_API_KEY'])] : requestedPassEnv;
5036
5122
  const podSourceSpec = (opts as { podSource?: string }).podSource;
5037
5123
  let podSource: import('./task-orchestrator/surfaces/pod-source-receive.js').PodSource | undefined;
5038
5124
  if (podSourceSpec) {
@@ -5054,7 +5140,7 @@ const selfOrchestrateCmd = selfCmd
5054
5140
  const childFlags = opts as { childLlmProvider?: string; childLlmModel?: string; childLlmEffort?: string };
5055
5141
  const podChildLlm = childFlags.childLlmProvider?.trim() ? { childProviderExplicit: true, ...(childFlags.childLlmModel?.trim() ? { childModel: childFlags.childLlmModel.trim() } : {}), ...(childFlags.childLlmEffort?.trim() ? { childEffort: childFlags.childLlmEffort.trim() } : {}) } : {};
5056
5142
  if (childFlags.childLlmProvider?.trim()) debug.log('self-implement.pod', 'child-provider-named', { provider: childFlags.childLlmProvider.trim(), model: childFlags.childLlmModel ?? null, podProvider });
5057
- const podBase = { hostSupervised: opts.supervise === true, ...podChildLlm, ...(remoteOnlyPool ? { imageCommit: image.imageCommit } : {}), account: podProvider === 'grok' ? 'grok' : explicitPodAccount ?? 'team', ...(accountBroker ? { accountBroker, rotationAccounts } : {}), ...(podProvider === 'grok' ? { provider: 'grok' as const, grokApiKeyOptIn } : {}), passEnv, ...(pool ? { pool } : {}), ...((opts as { podSkillEnv?: boolean }).podSkillEnv ? { skillEnv: true } : {}), ...(podSource ? { source: podSource } : {}) };
5143
+ const podBase = { hostSupervised: opts.supervise === true, ...podChildLlm, ...(remoteOnlyPool ? { imageCommit: image.imageCommit } : {}), account: podProvider === 'grok' ? 'grok' : podProvider === 'openrouter' ? 'openrouter' : podProvider === 'anthropic' ? 'anthropic' : explicitPodAccount ?? 'team', ...(accountBroker ? { accountBroker, rotationAccounts } : {}), ...(podProvider === 'grok' ? { provider: 'grok' as const, grokApiKeyOptIn } : podProvider === 'openrouter' ? { provider: 'openrouter' as const } : podProvider === 'anthropic' ? { provider: 'anthropic' as const } : {}), passEnv, ...(pool ? { pool } : {}), ...((opts as { podSkillEnv?: boolean }).podSkillEnv ? { skillEnv: true } : {}), ...(podSource ? { source: podSource } : {}) };
5058
5144
  if (benchArms) {
5059
5145
  const { benchPodSpawn } = await import('./task-orchestrator/surfaces/self-implement-pod.js');
5060
5146
  podSpawn = benchPodSpawn(benchArms, podBase);
@@ -5065,7 +5151,7 @@ const selfOrchestrateCmd = selfCmd
5065
5151
  ? poolMembers.map(({ context }) => ({ context, namespace: 'elanous-test' }))
5066
5152
  : [{ context: defaultKubectl(['config', 'current-context']).stdout.trim(), namespace: 'elanous-test' }];
5067
5153
  // ⭐ 팔 선언은 «runId 가 붙는» 이 줄에 싣는다 — 위의 `bench-arms` 줄은 runId 해석 «전»이라 비어 있다(09-25 실측) · 보고서(scripts/bench-report.ts)가 이 줄로 잇는다.
5068
- debug.log('self-dev.orchestrate', 'substrate', { substrate, account: podProvider === 'grok' ? 'grok' : (opts as { podAccount?: string }).podAccount ?? 'team', passEnv, context: ready.reason, imageCommit: image.imageCommit, imageFresh: image.fresh, ...(benchArms ? { benchArms: benchArms.map((a) => ({ id: a.id, provider: a.provider, model: a.model ?? null, modelSource: a.modelSource ?? null, passEnv: a.passEnv })) } : {}) });
5154
+ debug.log('self-dev.orchestrate', 'substrate', { substrate, account: podProvider === 'grok' ? 'grok' : podProvider === 'openrouter' ? 'openrouter' : (opts as { podAccount?: string }).podAccount ?? 'team', passEnv, context: ready.reason, imageCommit: image.imageCommit, imageFresh: image.fresh, ...(benchArms ? { benchArms: benchArms.map((a) => ({ id: a.id, provider: a.provider, model: a.model ?? null, modelSource: a.modelSource ?? null, passEnv: a.passEnv })) } : {}) });
5069
5155
  } else if (substrate !== 'local') {
5070
5156
  ui.error(`--substrate: local | pod (받은 값: ${substrate})`); process.exit(2);
5071
5157
  }
@@ -5137,11 +5223,7 @@ const selfOrchestrateCmd = selfCmd
5137
5223
  const incomplete = results.length - done;
5138
5224
  console.log([
5139
5225
  `[self-dev] 완료 — ${done}/${results.length} done${promoted ? ` · ${promoted} PR 승격` : ''}${incomplete ? ` · 이어서: elanous self orchestrate <goals> --resume ${runId}` : ''}`,
5140
- ...results.map((r) => {
5141
- const icon = r.status === 'done' ? '✅' : r.status === 'cancelled' ? '⛔' : '❌';
5142
- const disp = r.merged ? ` → merged ${r.prUrl}` : r.prUrl ? ` → PR ${r.prUrl}` : r.stage ? ` [${r.stage}]` : '';
5143
- return ` ${icon} ${r.status} · ${r.feature.slice(0, 56)}${disp}${r.error ? ` — ${r.error.code}${r.error.code === 'pod-job-failed' ? `: ${r.error.message}` : ''}` : ''}`;
5144
- }),
5226
+ ...results.map(formatOrchestrateResultLine),
5145
5227
  ].join('\n'));
5146
5228
  await reportRun(results);
5147
5229
  if (outcome.exitCode !== 0) process.exit(outcome.exitCode); // seam 이 done<total→1 매핑(원 규약 보존)
@@ -5684,12 +5766,19 @@ selfCmd
5684
5766
  const { streamLLM } = await import('./llm.js');
5685
5767
  const { registerStandaloneLogSink } = await import('./domains/standalone-log-sink.js');
5686
5768
  const { debug } = await import('./debug/log.js');
5687
- const { runSelfReviewCliCommand, reviewerContextArgs } = await import('./agent-substrate/self-review-cli.js');
5769
+ const { runSelfReviewCliCommand, reviewerContextArgs, selfReviewJsonLine } = await import('./agent-substrate/self-review-cli.js');
5770
+ const { subscriptionReviewerAvailability } = await import('./self-dev/review-provider-fallback.js');
5771
+ const { makeLazyAcpReviewLLM: makeRoleAcpReviewLLM } = await import('./agent-substrate/acp-reviewer.js');
5688
5772
  const contextOrder = reviewerContextArgs(process.argv.slice(2));
5689
5773
  const configuredAcpBackend = getUserConfig().acp.reviewBackend;
5774
+ // ⭐ Same reviewer row the harness reads (`dev-pipeline` → `resolveSubscriptionReviewer`).
5775
+ // The seam decides whether it applies (only without an explicit reviewer flag).
5776
+ const { loadLlmPolicy, resolveSubscriptionReviewer } = await import('./policy/llm-policy.js');
5777
+ const roleReviewerSelection = resolveSubscriptionReviewer(loadLlmPolicy(), getUserConfig().roleLlm);
5690
5778
  const { results } = await runSelfReviewCliCommand(prArgs, {
5691
5779
  ...opts,
5692
5780
  ...(configuredAcpBackend ? { configuredAcpBackend } : {}),
5781
+ ...(roleReviewerSelection ? { roleReviewer: roleReviewerSelection.spec } : {}),
5693
5782
  ...(contextOrder.length > 0 ? { contextOrder } : {}),
5694
5783
  }, {
5695
5784
  gh: (args, timeoutMs) => {
@@ -5726,6 +5815,20 @@ selfCmd
5726
5815
  return made(prompt, images);
5727
5816
  };
5728
5817
  },
5818
+ // ⭐ Role-config ACP lane: the harness's subscription guard (subscription ⊕ usage cap ⊕ proxy URL),
5819
+ // then the claude ACP adapter with that scrubbed env. Unavailable = a reason code, never a throw.
5820
+ makeRoleReviewerLlm: (spec, o) => {
5821
+ // Defensive: the seam is only called with a resolved `roleReviewer`, so this is unreachable today.
5822
+ if (!roleReviewerSelection) return { reason: 'role-reviewer-unconfigured' };
5823
+ const availability = subscriptionReviewerAvailability(spec, roleReviewerSelection.cap, process.env);
5824
+ if (!availability.spawn) return { reason: availability.reason ?? 'subscription reviewer unavailable' };
5825
+ const spawn = availability.spawn;
5826
+ // handshakeTimeoutMs left to the adapter default (min(timeoutMs, 60s)) — the harness lane passes none either.
5827
+ return {
5828
+ backend: 'claude',
5829
+ llm: makeRoleAcpReviewLLM({ cwd: process.cwd(), backend: 'claude', backendSpec: spawn.backendSpec, env: spawn.env, timeoutMs: o.timeoutMs }),
5830
+ };
5831
+ },
5729
5832
  registerSink: async (surface) => { await registerStandaloneLogSink(surface); },
5730
5833
  log: (event, data, o) => debug.log('self-review', event, data, o ?? {}),
5731
5834
  info: (t) => ui.info(t),
@@ -5734,7 +5837,7 @@ selfCmd
5734
5837
  now: () => Date.now(),
5735
5838
  envModel: () => process.env.ELANOUS_PR_REVIEW_MODEL,
5736
5839
  });
5737
- if (opts.json) await writeStdoutJson(JSON.stringify(results.length === 1 ? results[0] : results) + '\n');
5840
+ if (opts.json) await writeStdoutJson(selfReviewJsonLine(results));
5738
5841
  });
5739
5842
 
5740
5843
  selfCmd
@@ -6987,7 +7090,7 @@ const selfDevCmd = program
6987
7090
  .option('--no-commit', 'external+pty: 완료 시 자동 commit 생략')
6988
7091
  .option('--deliverable <hint>', 'external+pty: 산출물 유형 힌트')
6989
7092
  .option('--screens <dir>', 'external+pty: 스크린 캡처 디렉토리')
6990
- .option('--json', 'hold 결과를 한 줄 JSON으로 · --hold 전용')
7093
+ .option('--json', 'hold 결과 또는 self --ask/--say 전제 검사 중단을 한 줄 JSON으로 출력 (--target 경로도 유지)')
6991
7094
  // ⭐ 역할별 LLM — 「한 번 정하고 아래로는 인자로만」(RFC-role-scoped-llm-selection-2026-08-18 §4e).
6992
7095
  // ⛔ 모르는 역할·provider·tier 는 «거부»한다 — 110차에 `--acp-backend` 가 조용히 무시돼
6993
7096
  // API 로 새어 나간 것이 이 플래그가 fail-closed 인 이유다.
@@ -7040,8 +7143,8 @@ const selfDevCmd = program
7040
7143
 
7041
7144
  // ⭐ 여기부터가 「가드가 덮는 구간」이다 — 위로 올릴 것은 아무것도 없다.
7042
7145
  const invokedAsDrive = command.parent?.args[0] === 'drive';
7043
- if (opts.json === true && opts.hold !== true && (opts.target === undefined || opts.backend !== 'self' || opts.elanous === true || opts.implement === true || opts.goal !== undefined || opts.plan === true || opts.ask !== undefined || opts.say !== undefined || opts.attach !== undefined)) {
7044
- console.error('❌ --json은 --hold 전용입니다');
7146
+ if (opts.json === true && opts.hold !== true && (opts.backend !== 'self' || opts.elanous === true || opts.implement === true || opts.goal !== undefined || opts.plan === true || opts.attach !== undefined || (opts.target === undefined && opts.ask === undefined && opts.say === undefined))) {
7147
+ console.error('❌ --json은 --hold, self --target 또는 self --ask/--say 전제 검사 중단 전용입니다');
7045
7148
  completionGuard.conclude();
7046
7149
  process.exit(2);
7047
7150
  }
@@ -7223,6 +7326,10 @@ const selfDevCmd = program
7223
7326
  askAuthoredFile = flowResult.goalFile;
7224
7327
  if (flowResult.kind === 'stopped-by-preflight') {
7225
7328
  releaseAuthoringLease();
7329
+ if (opts.json) {
7330
+ const terminalResult = { kind: 'self', ok: false, stage: 'preflight-blocked', blockers: flowResult.blockers };
7331
+ await writeStdoutJson(`${JSON.stringify(terminalResult)}\n`);
7332
+ }
7226
7333
  completionGuard.conclude();
7227
7334
  process.exit(1);
7228
7335
  }
@@ -7316,9 +7423,10 @@ const selfDevCmd = program
7316
7423
  if (!opts.json && !invokedAsDrive && explicitOptions.includes('backend') && executor.kind === 'external') {
7317
7424
  console.error(`[dev] 외부 backend 미션의 자기 명령은 \`elanous agent-mission mission\` 입니다; 대응 명령: elanous agent-mission mission --backend ${executor.backend}`);
7318
7425
  }
7426
+ await devCli.ensureOpenRouterChildModelLive(devOpts.childLlmProvider, devOpts.childLlmModel);
7319
7427
  let spec = invokedAsDrive
7320
- ? devCli.buildDriveAliasDevSpec(hasText ? textParts.join(' ') : undefined, devOpts, devCli.explicitDevOptionNames(command))
7321
- : buildDevCliSpec(input, executor, devOpts, devCli.explicitDevOptionNames(command));
7428
+ ? devCli.buildDriveAliasDevSpec(hasText ? textParts.join(' ') : undefined, devOpts, devCli.explicitDevOptionNames(command), devRunId)
7429
+ : buildDevCliSpec(input, executor, devOpts, devCli.explicitDevOptionNames(command), 'cli-dev-ask', undefined, undefined, devRunId);
7322
7430
  if (!opts.json && spec.notice) console.error(spec.notice);
7323
7431
  // 역할별 LLM은 현재 프로세스 설정이다. self-mission 구현 자식에 전달되지 않는 조합은 위 검증이 먼저 거부한다.
7324
7432
  if (Array.isArray(opts.roleLlm) && opts.roleLlm.length > 0) {
@@ -7819,6 +7927,26 @@ configCmd
7819
7927
  if (report.prodStatus !== 'ok') process.exit(1);
7820
7928
  });
7821
7929
 
7930
+ configCmd
7931
+ .command('classify')
7932
+ .description('읽기 전용 — 운영 config 잎의 자리(기본값·기계 사실·비밀·운영 정책)와 덮어쓰기 수 (CFG-CLASSIFY)')
7933
+ .option('--json', '잎 전체를 JSON 으로 출력 (비밀 값 제외)')
7934
+ .action(async (o: { json?: boolean }) => {
7935
+ const { getElanousConfigDir } = await import('./elanous-config-dir.js');
7936
+ const { readUniverseConfig } = await import('./cli/config-drift.js');
7937
+ const { classifyConfig, renderClassify } = await import('./cli/config-classify.js');
7938
+ const { buildUserConfig } = await import('./user-config.js');
7939
+ const prod = readUniverseConfig(getElanousConfigDir(), []);
7940
+ if (prod.status !== 'ok' || !prod.raw) {
7941
+ console.error(`config classify — config 못 읽음(${prod.status}${prod.error ? `: ${prod.error}` : ''})`);
7942
+ process.exitCode = 1;
7943
+ return;
7944
+ }
7945
+ const report = classifyConfig(prod.raw, buildUserConfig('/nonexistent/elanous-config-drift/config.json') as unknown as Record<string, unknown>);
7946
+ if (o.json) await (await import('./cli/stdout-flush.js')).writeStdoutFully(JSON.stringify(report, null, 2));
7947
+ else console.log(renderClassify(report));
7948
+ });
7949
+
7822
7950
  configCmd
7823
7951
  .command('explain <key>')
7824
7952
  .description('읽기 전용 — 운영 값 ⊕ 출처 층 ⊕ 파생 시험 우주별 값 (CFG-STORE1)')
@@ -41,6 +41,7 @@ export interface GithubStarRepo {
41
41
 
42
42
  /** 질의 하나 → 저장소 목록. 실제 구현은 `gh api` · 시험은 가짜. */
43
43
  export type SearchGithubRepos = (query: string, perQuery: number) => Promise<GithubStarRepo[]>;
44
+ export type FetchGithubReadme = (fullName: string) => Promise<string>;
44
45
 
45
46
  export interface StarSnapshot { day: string; repo: string; stars: number }
46
47
 
@@ -175,6 +176,8 @@ export interface CollectGithubOpts {
175
176
  now?: () => Date;
176
177
  /** 등록 원천이 질의 하나만 수집할 때; 생략 시 관심 질의 전부 (최대 10개). */
177
178
  queries?: readonly string[];
179
+ /** 상위 세 저장소의 README 텍스트를 가져온다. 생략 시 gh api 사용. */
180
+ fetchReadme?: FetchGithubReadme;
178
181
  }
179
182
 
180
183
  /**
@@ -218,11 +221,21 @@ export async function collectGithubStars(
218
221
  ...(surge.baselineDays !== undefined ? { baselineDays: surge.baselineDays } : {}),
219
222
  };
220
223
  }).sort((a, b) => (b.starsPerDay ?? -Infinity) - (a.starsPerDay ?? -Infinity) || b.stars - a.stars);
224
+ const readmes = new Map<string, string>();
225
+ if (!opts.dryRun) {
226
+ for (const row of repos.slice(0, 3)) {
227
+ try {
228
+ readmes.set(row.repo, `README:\n${(await (opts.fetchReadme ?? ghApiFetchReadme)(row.repo)).slice(0, 1_500)}`);
229
+ } catch {
230
+ readmes.set(row.repo, 'README 미상');
231
+ }
232
+ }
233
+ }
221
234
  const raws: RawIntakeItem[] = repos.map((row) => ({
222
235
  url: row.url,
223
236
  title: row.title,
224
237
  // 모든 행 첫 줄에 라이선스: SPDX · 확인된 부재는 «없음» · 응답이 알려 주지 않으면 «미상»(없음으로 읽지 않는다).
225
- text: `라이선스: ${row.license ?? '미상'}\n${row.text}`,
238
+ text: `라이선스: ${row.license ?? '미상'}\n${readmes.has(row.repo) ? `${readmes.get(row.repo)}\n` : ''}${row.text}`,
226
239
  signals: {
227
240
  stars: row.stars,
228
241
  ...(row.starsDelta !== undefined ? { starsDelta: row.starsDelta } : {}),
@@ -274,6 +287,11 @@ export function reposFromGhSearchItems(items: GhSearchItem[], perQuery: number):
274
287
  return repos.slice(0, perQuery);
275
288
  }
276
289
 
290
+ /** GitHub README raw 응답 — API 실패는 호출자가 해당 저장소의 «미상»으로 격리한다. */
291
+ export const ghApiFetchReadme: FetchGithubReadme = async (fullName) => execFileSync('gh', [
292
+ 'api', `repos/${fullName}/readme`, '-H', 'Accept: application/vnd.github.raw+json',
293
+ ], { encoding: 'utf8', timeout: 30_000, maxBuffer: 2 * 1024 * 1024 });
294
+
277
295
  /** `gh api search/repositories` 를 `sort=stars` 로 한 번 부른다. */
278
296
  export const ghApiSearchRepos: SearchGithubRepos = async (query, perQuery) => {
279
297
  const perPage = Math.min(100, Math.max(1, perQuery));