elanous 0.2.22 → 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 (705) 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-80ed511e02c81412.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/{aBi6EyMtLsrl7J8eH4kF7 → 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/log-horizon/log-horizon-watch.yaml +25 -0
  288. package/graphs/log-horizon/recipes.yaml +3 -0
  289. package/graphs/release/recipes.yaml +1 -1
  290. package/graphs/release/release-loop.yaml +6 -2
  291. package/graphs/release-rehearsal/recipes.yaml +12 -0
  292. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  293. package/package.json +4 -1
  294. package/scripts/bench-report.ts +82 -3
  295. package/scripts/ci-typecheck-changed.ts +10 -1
  296. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  297. package/scripts/lib/typecheck-ratchet.ts +51 -0
  298. package/scripts/openai-relay-server.ts +5 -1
  299. package/scripts/release-loop/docs-node.ts +258 -43
  300. package/scripts/release-loop/gate-method.ts +59 -0
  301. package/scripts/release-loop/gate-node.ts +73 -7
  302. package/scripts/release-loop/gate-wall.ts +208 -0
  303. package/scripts/release-loop/known-issues-node.ts +53 -8
  304. package/scripts/release-loop/publish-at.ts +14 -0
  305. package/scripts/release-loop/publish-node.ts +17 -2
  306. package/scripts/release-loop/resume-release.ts +34 -4
  307. package/scripts/release-loop/resume.ts +53 -0
  308. package/scripts/release-loop/shard-plan.ts +3 -11
  309. package/scripts/release-loop/tui-node-checks.ts +22 -0
  310. package/scripts/release-loop/unattended-release.ts +8 -1
  311. package/scripts/rhythm/daily.ts +51 -2
  312. package/scripts/rhythm/weekly.ts +3 -2
  313. package/scripts/tsc-main-safety-net.ts +189 -0
  314. package/scripts/usage-rollup.ts +8 -4
  315. package/src/acp/codex-plugins.ts +48 -6
  316. package/src/agent/monad-agent-turn.ts +67 -5
  317. package/src/agent/run-context.ts +10 -0
  318. package/src/agent/tool-profile.ts +28 -2
  319. package/src/agent-mission/acp-judge.ts +8 -2
  320. package/src/agent-mission/capabilities-cli.ts +16 -1
  321. package/src/agent-mission/driver.ts +1 -1
  322. package/src/agent-mission/pr-review-watch.ts +6 -2
  323. package/src/agent-mission/review-loop.ts +33 -5
  324. package/src/agent-substrate/acp-reviewer.ts +17 -8
  325. package/src/agent-substrate/pr-reviewer.ts +164 -28
  326. package/src/agent-substrate/review-intent.ts +6 -4
  327. package/src/agent-substrate/self-review-cli.ts +111 -16
  328. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  329. package/src/ask-user-question/pending-questions.ts +8 -2
  330. package/src/autopilot/build/llm-conflict-merge.ts +216 -12
  331. package/src/autopilot/codebase-grounding.ts +44 -0
  332. package/src/autopilot/llm-control-brain.ts +13 -1
  333. package/src/autopilot/mission-codebase-gate.ts +8 -77
  334. package/src/autopilot/pr-manager.ts +12 -3
  335. package/src/boot/acp-server.ts +4 -7
  336. package/src/boot/acp-socket-path.ts +7 -0
  337. package/src/briefing/brief-items.ts +21 -13
  338. package/src/chat/index.ts +12 -3
  339. package/src/cli/agent-cli.ts +20 -0
  340. package/src/cli/brief-cli.ts +27 -21
  341. package/src/cli/cli-user-error.ts +9 -2
  342. package/src/cli/log-event-names.ts +3 -0
  343. package/src/cli/logs-cli.ts +1 -0
  344. package/src/cli/mcp-login.ts +111 -37
  345. package/src/cli/plugin-cli.ts +21 -1
  346. package/src/cli/pod-cli.ts +26 -0
  347. package/src/cli/pr-cli.ts +30 -2
  348. package/src/cli/pr-land-overlap-evidence.ts +131 -0
  349. package/src/cli/release-cli.ts +53 -11
  350. package/src/cli/self-update.ts +173 -10
  351. package/src/cli/skills-cli.ts +12 -3
  352. package/src/cli/tasks-cli.ts +133 -27
  353. package/src/context-bus/context-first.ts +51 -2
  354. package/src/context-bus/context-now-surfaces.ts +13 -2
  355. package/src/context-bus/long-term-memory.ts +3 -1
  356. package/src/context-bus/nightly-condense.ts +3 -2
  357. package/src/core-turn/run-goal-loop.ts +86 -2
  358. package/src/dashboard/chat-fold.ts +20 -0
  359. package/src/dashboard/first-screen-band.ts +151 -1
  360. package/src/dashboard/index.ts +27 -5
  361. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
  362. package/src/dashboard/stale-install-check.ts +13 -2
  363. package/src/dashboard/turn-stream-formatter.ts +25 -0
  364. package/src/debug/log-diet.ts +159 -0
  365. package/src/debug/log.ts +52 -17
  366. package/src/display/coordinator.ts +25 -2
  367. package/src/domains/coo-admin-tool.ts +27 -0
  368. package/src/domains/cron-match.ts +1 -0
  369. package/src/domains/outbound-alert.ts +17 -6
  370. package/src/domains/release-tool.ts +119 -10
  371. package/src/domains/schedule-registry.ts +10 -7
  372. package/src/domains/schedule-runner.ts +1 -0
  373. package/src/elanous-config-dir.ts +2 -2
  374. package/src/elanous-daemon.ts +3 -3
  375. package/src/execution-loop/launch-gate.ts +1 -1
  376. package/src/expression/i18n/messages.en.ts +5 -0
  377. package/src/expression/i18n/messages.ja.ts +5 -0
  378. package/src/expression/i18n/messages.ko.ts +5 -0
  379. package/src/expression/i18n/messages.zh.ts +5 -0
  380. package/src/expression/i18n/types.ts +8 -0
  381. package/src/github/pr-labels.ts +1 -0
  382. package/src/graph-runner/runner.ts +54 -5
  383. package/src/harness/dispatch-backpressure.ts +259 -0
  384. package/src/harness/harness-cli-command.ts +107 -28
  385. package/src/harness/harness-seams.ts +2 -20
  386. package/src/harness/harness-substrate-default.ts +72 -1
  387. package/src/harness/nested-elanous-policy.ts +4 -2
  388. package/src/hq/fence-wrapper.ts +7 -0
  389. package/src/hq/hq.ts +33 -2
  390. package/src/hq/lease.ts +13 -0
  391. package/src/hq/seats.ts +114 -18
  392. package/src/index.ts +163 -64
  393. package/src/intake-plane/collect-github.ts +19 -1
  394. package/src/intake-plane/digest.ts +45 -20
  395. package/src/intake-plane/lens.ts +36 -8
  396. package/src/intelligence-map/model-alias.ts +6 -0
  397. package/src/intelligence-map/model-catalog.ts +41 -0
  398. package/src/knowledge/kgs/pack.ts +5 -2
  399. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  400. package/src/knowledge/tools/knowledge-query.ts +20 -2
  401. package/src/knowledge/write.ts +234 -2
  402. package/src/llm/bedrock-provider.ts +175 -0
  403. package/src/llm/bedrock.ts +345 -0
  404. package/src/llm/provider-credentials.ts +3 -1
  405. package/src/llm.ts +306 -35
  406. package/src/loops/budget.ts +150 -0
  407. package/src/loops/orchestrator/seat-share.ts +6 -49
  408. package/src/loops/orchestrator/traffic.ts +5 -81
  409. package/src/market/signed-index.ts +42 -0
  410. package/src/mcp/mcp-oauth.ts +136 -17
  411. package/src/model-tier/llm-tier-map.ts +48 -4
  412. package/src/models/prompts.ts +22 -1
  413. package/src/mss/logging/horizon-watch.ts +168 -0
  414. package/src/mss/logging/log-store.ts +204 -15
  415. package/src/native-tool-catalog.ts +1 -1
  416. package/src/nexus/api/consult-requests.ts +7 -10
  417. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  418. package/src/nexus/api/error-reports.ts +30 -8
  419. package/src/nexus/api/http-server.ts +8 -0
  420. package/src/nexus/api/loop-resources.ts +42 -0
  421. package/src/nexus/api/outbound-report.ts +8 -3
  422. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  423. package/src/nexus/index.ts +10 -0
  424. package/src/nexus/outbound/format.ts +2 -0
  425. package/src/nexus/outbound/router.ts +198 -13
  426. package/src/oauth/codex-account-rotation.ts +16 -18
  427. package/src/oauth/codex-account-store.ts +134 -5
  428. package/src/oauth/fallback-chain.ts +28 -6
  429. package/src/onboarding.ts +2 -1
  430. package/src/plugins/adapters/claude-package.ts +4 -12
  431. package/src/plugins/core/capability-policy.ts +141 -0
  432. package/src/plugins/core/host.ts +21 -8
  433. package/src/plugins/core/manifest.ts +19 -2
  434. package/src/plugins/core/trust-store.ts +15 -0
  435. package/src/plugins/core/types.ts +12 -0
  436. package/src/plugins/install/market-fetch.ts +68 -16
  437. package/src/plugins/install/plugin-install.ts +187 -16
  438. package/src/plugins/maker/plugin-maker.ts +25 -20
  439. package/src/plugins/maker/wizard-generate.ts +16 -2
  440. package/src/policy/llm-policy.ts +14 -1
  441. package/src/process/pid-liveness.ts +1 -1
  442. package/src/prompt-cache/openai.ts +10 -6
  443. package/src/prompt-cache/openrouter.ts +94 -0
  444. package/src/prompt-enhance/enhance.ts +46 -5
  445. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  446. package/src/prompt-library/universal-preamble.ts +2 -2
  447. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  448. package/src/registry/loader.ts +6 -1
  449. package/src/release-loop/checklist.ts +24 -9
  450. package/src/release-loop/feature-store.ts +3 -0
  451. package/src/release-loop/gate-shards.ts +48 -4
  452. package/src/release-loop/landed-to-green.ts +81 -0
  453. package/src/release-loop/light-rc.ts +11 -1
  454. package/src/release-loop/merged-pr-checklist.ts +10 -0
  455. package/src/release-loop/placement.ts +91 -22
  456. package/src/release-loop/rehearsal.ts +317 -0
  457. package/src/release-loop/release-schedule.ts +13 -1
  458. package/src/release-loop/rubric-types.ts +1 -0
  459. package/src/release-loop/rubric.ts +2 -2
  460. package/src/retro/daily.ts +23 -9
  461. package/src/seat-loop/seat-loop.ts +34 -1
  462. package/src/seat-loop/traffic-signal.ts +44 -0
  463. package/src/self-dev/ask-launch-flow.ts +2 -2
  464. package/src/self-dev/dev-cli.ts +67 -3
  465. package/src/self-dev/dev-pipeline.ts +4 -6
  466. package/src/self-dev/draft-residue.ts +463 -0
  467. package/src/self-dev/draft-sweep.ts +151 -10
  468. package/src/self-dev/draft-triage-rules.ts +27 -1
  469. package/src/self-dev/launch-preflight-text.ts +549 -0
  470. package/src/self-dev/launch-preflight.ts +10 -545
  471. package/src/self-dev/orchestrate-cli.ts +57 -2
  472. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  473. package/src/self-dev/orchestrate.ts +8 -135
  474. package/src/self-dev/review-provider-fallback.ts +115 -19
  475. package/src/self-dev/run-store.ts +1 -3
  476. package/src/self-dev/run-supervisor.ts +3 -22
  477. package/src/self-dev/run-types.ts +178 -0
  478. package/src/self-dev/shard-aggregate.ts +61 -13
  479. package/src/self-dev/shard-plan.ts +5 -1
  480. package/src/self-dev/shard-run.ts +23 -5
  481. package/src/self-dev/supervisor-verdict-edges.ts +2 -4
  482. package/src/self-implement/blocked-draft-policy.ts +3 -19
  483. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  484. package/src/self-implement/follow-up-goals.ts +114 -38
  485. package/src/self-implement/gate-baseline-reap.ts +157 -0
  486. package/src/self-implement/gate-baseline.ts +78 -16
  487. package/src/self-implement/gate-cli.ts +12 -2
  488. package/src/self-implement/gate-remote.ts +17 -6
  489. package/src/self-implement/goal-author.ts +24 -4
  490. package/src/self-implement/goal-digest.ts +19 -0
  491. package/src/self-implement/graph-overlay-condition.ts +4 -0
  492. package/src/self-implement/headless-elanous-driver.ts +11 -9
  493. package/src/self-implement/host-regate.ts +120 -29
  494. package/src/self-implement/l8-merge-queue.ts +67 -5
  495. package/src/self-implement/merge-train.ts +131 -0
  496. package/src/self-implement/off-diff-evidence.ts +9 -0
  497. package/src/self-implement/orchestrator.ts +133 -16
  498. package/src/self-implement/review-finding-recurrence.ts +28 -0
  499. package/src/self-implement/rework-policy.ts +2 -1
  500. package/src/self-implement/round-summary-card.ts +63 -0
  501. package/src/self-implement/run-ledger.ts +4 -3
  502. package/src/self-implement/run-step-projection.ts +147 -0
  503. package/src/self-implement/run-stop.ts +1 -1
  504. package/src/self-implement/seams.ts +36 -3
  505. package/src/self-implement/self-implement-cli.ts +3 -1
  506. package/src/self-implement/train-gate-remote.ts +158 -0
  507. package/src/session-runtime/index.ts +10 -1
  508. package/src/session-runtime/retry-api.ts +11 -1
  509. package/src/skills/gift-install.ts +119 -0
  510. package/src/skills/runner.ts +59 -2
  511. package/src/skills/skill-feedback.ts +31 -1
  512. package/src/skills/skill-tier.ts +1 -0
  513. package/src/smart-wizard/capability-index.ts +231 -0
  514. package/src/smart-wizard/rung.ts +74 -0
  515. package/src/steward/launch.ts +20 -9
  516. package/src/steward/triage.ts +4 -2
  517. package/src/storage/file-lock.ts +8 -1
  518. package/src/task-agent/actions.ts +4 -0
  519. package/src/task-agent/card-evidence.ts +59 -13
  520. package/src/task-agent/judge.ts +4 -3
  521. package/src/task-agent/land-worktree.ts +201 -0
  522. package/src/task-agent/live-move-history.ts +133 -0
  523. package/src/task-agent/live-moves.ts +106 -19
  524. package/src/task-agent/parent-host.ts +117 -8
  525. package/src/task-agent/rejudge-on-head.ts +297 -0
  526. package/src/task-agent/review-result-capture.ts +218 -0
  527. package/src/task-agent/shadow.ts +103 -7
  528. package/src/task-agent/task-hand.ts +136 -11
  529. package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
  530. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  531. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
  532. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  533. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
  534. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
  535. package/src/task-orchestrator/surfaces/pod-pool.ts +66 -14
  536. package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
  537. package/src/task-orchestrator/surfaces/self-implement.ts +6 -2
  538. package/src/telegram-service.ts +5 -1
  539. package/src/telegram.ts +17 -4
  540. package/src/time/format.ts +13 -4
  541. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  542. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  543. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  544. package/src/user-config.ts +132 -24
  545. package/src/ux-sim/slash-menu-frames.ts +168 -0
  546. package/src/version/packed-revision.json +1 -1
  547. package/src/web-terminal/preview-tap-registry.ts +5 -2
  548. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  549. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  550. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  551. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  552. package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  554. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  555. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  556. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  558. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  563. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  572. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  573. package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  586. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  594. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  599. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  601. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  605. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  610. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  615. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  616. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  618. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  619. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  627. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  630. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  640. package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  643. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  647. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  648. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  704. package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
  705. /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
@@ -10,6 +10,7 @@ import { dispatchOmniSearch } from '../../skills/tools/omni-search.js';
10
10
  import { runGraph } from '../../graph-runner/runner.js';
11
11
  import { parseGraphTemplateYaml } from '../../self-implement/graph-yaml.js';
12
12
  import { installPlugin } from '../install/plugin-install.js';
13
+ import { inspectPluginSecurity } from '../core/capability-policy.js';
13
14
  import { generateWizardFiles, type WizardResearchDraft } from './wizard-generate.js';
14
15
  import { bundleInstalledWizardPlugin, type MarketBundleResult } from './market-bundle.js';
15
16
 
@@ -127,7 +128,7 @@ export async function validatePluginDir(dir: string): Promise<string[]> {
127
128
  if (lstatSync(file).isSymbolicLink()) errors.push('안전하지 않은 plugin.json 링크');
128
129
  else manifest = JSON.parse(readFileSync(file, 'utf8'));
129
130
  }
130
- catch (error) { errors.push(`plugin.json 파싱 실패: ${String(error)}`); }
131
+ catch { errors.push('plugin.json 파싱 실패'); }
131
132
  const extension = isRecord(manifest) && isRecord(manifest.extensions) ? manifest.extensions['ai.elanous'] : undefined;
132
133
  const graphs = isRecord(extension) ? extension.graphs : undefined;
133
134
  if (isRecord(extension) && extension.contributes !== undefined) errors.push('extension contributes 덮어쓰기 금지');
@@ -143,69 +144,73 @@ export async function validatePluginDir(dir: string): Promise<string[]> {
143
144
  if (lstatSync(file).isSymbolicLink()) errors.push('안전하지 않은 recipes.yaml 링크');
144
145
  else recipes = parseYaml(readFileSync(file, 'utf8'));
145
146
  }
146
- catch (error) { errors.push(`recipes.yaml 파싱 실패: ${String(error)}`); }
147
+ catch { errors.push('recipes.yaml 파싱 실패'); }
147
148
  if (!isRecord(recipes)) errors.push('recipes.yaml 은 맵이어야 한다');
148
149
  else for (const [id, recipe] of Object.entries(recipes)) {
149
150
  if (!isRecord(recipe) ||
150
151
  (!(typeof recipe.command === 'string' && recipe.command.trim()) && !(typeof recipe.approval === 'string' && recipe.approval.trim())) ||
151
152
  (recipe.command !== undefined && (typeof recipe.command !== 'string' || !recipe.command.trim())) ||
152
153
  (recipe.approval !== undefined && (typeof recipe.approval !== 'string' || !recipe.approval.trim())) ||
153
- (recipe.timeout_ms !== undefined && (!Number.isSafeInteger(recipe.timeout_ms) || Number(recipe.timeout_ms) <= 0))) errors.push(`잘못된 recipe: ${id}`);
154
+ (recipe.timeout_ms !== undefined && (!Number.isSafeInteger(recipe.timeout_ms) || Number(recipe.timeout_ms) <= 0))) errors.push(`잘못된 recipe: ${/^[a-zA-Z0-9_-]+$/.test(id) ? id : 'invalid'}`);
154
155
  }
155
156
  for (const graph of Array.isArray(graphs) ? graphs : []) {
156
157
  if (typeof graph !== 'string') continue;
157
158
  const file = inside(dir, graph);
158
- if (!file || !/^\.\/graphs\/[a-zA-Z0-9_-]+\.ya?ml$/.test(graph)) { errors.push(`안전하지 않은 graph 경로: ${graph}`); continue; }
159
+ if (!file || !/^\.\/graphs\/[a-zA-Z0-9_-]+\.ya?ml$/.test(graph)) { errors.push('안전하지 않은 graph 경로'); continue; }
159
160
  try {
160
- if (lstatSync(file).isSymbolicLink()) { errors.push(`안전하지 않은 graph 링크: ${graph}`); continue; }
161
+ if (lstatSync(file).isSymbolicLink()) { errors.push('안전하지 않은 graph 링크'); continue; }
161
162
  const parsed = parseGraphTemplateYaml(readFileSync(file, 'utf8'), file);
162
- errors.push(...parsed.errors.map(issue => `${issue.path}: ${issue.message}`));
163
+ errors.push(...parsed.errors.map(() => 'graph 정의 오류'));
163
164
  const template = parsed.template;
164
165
  if (!template) continue;
165
- if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(template.graphId)) errors.push(`잘못된 graph_id: ${template.graphId}`);
166
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(template.graphId)) errors.push('잘못된 graph_id');
166
167
  if (template.terminalNodes.length !== 2 || !template.terminalNodes.includes('done') || !template.terminalNodes.includes('failed')) errors.push('terminal_nodes 는 done, failed 이어야 한다');
167
168
  const executionNodes = template.nodes.filter(node => !template.terminalNodes.includes(node.nodeId));
168
169
  if (executionNodes.length < 2) errors.push(`실행 노드는 2개 이상이어야 한다: ${executionNodes.length}개`);
169
170
  for (const node of template.nodes) {
170
171
  if (node.recipe.startsWith('cmd:')) {
171
172
  const id = node.recipe.slice(4);
172
- if (!isRecord(recipes) || !isRecord(recipes[id]) || recipes[id].approval !== undefined || typeof recipes[id].command !== 'string' || !recipes[id].command.trim()) errors.push(`recipe ${id} 없음`);
173
+ if (!isRecord(recipes) || !isRecord(recipes[id]) || recipes[id].approval !== undefined || typeof recipes[id].command !== 'string' || !recipes[id].command.trim()) errors.push(`recipe ${/^[a-zA-Z0-9_-]+$/.test(id) ? id : 'invalid'} 없음`);
173
174
  } else if (node.recipe.startsWith('approval:')) {
174
175
  const id = node.recipe.slice(9);
175
- if (!isRecord(recipes) || !isRecord(recipes[id]) || typeof recipes[id].approval !== 'string' || !recipes[id].approval.trim()) errors.push(`approval recipe ${id} 없음`);
176
- } else if (node.recipe !== 'none') errors.push(`지원하지 않는 recipe: ${node.recipe}`);
176
+ if (!isRecord(recipes) || !isRecord(recipes[id]) || typeof recipes[id].approval !== 'string' || !recipes[id].approval.trim()) errors.push(`approval recipe ${/^[a-zA-Z0-9_-]+$/.test(id) ? id : 'invalid'} 없음`);
177
+ } else if (node.recipe !== 'none') errors.push(`지원하지 않는 recipe: ${/^[a-zA-Z0-9_:-]+$/.test(node.recipe) ? node.recipe : 'invalid'}`);
177
178
  }
178
- } catch (error) { errors.push(`${graph} 파싱 실패: ${String(error)}`); }
179
+ } catch { errors.push('graph 파싱 실패'); }
179
180
  }
180
181
  const visit = (path: string): void => {
181
182
  for (const entry of readdirSync(path, { withFileTypes: true })) {
182
183
  const file = join(path, entry.name);
183
- if (entry.isSymbolicLink() || (!entry.isDirectory() && !entry.isFile())) { errors.push(`안전하지 않은 파일: ${file}`); continue; }
184
+ if (entry.isSymbolicLink() || (!entry.isDirectory() && !entry.isFile())) { errors.push('안전하지 않은 파일'); continue; }
184
185
  if (entry.isDirectory()) visit(file);
185
186
  else if (/\.[cm]?[jt]sx?$/.test(entry.name)) {
186
187
  const source = readFileSync(file, 'utf8');
187
188
  for (const match of source.matchAll(/\b(?:import|export)\s*(?:[\s\S]*?\s+from\s*)?["']([^"']+)["']|\b(?:import|require)\s*\(\s*["']([^"']+)["']/g)) {
188
189
  const target = match[1] ?? match[2]!;
189
- if (/(?:^|\/)src\//.test(target) && (target.startsWith('/') || target.startsWith('.'))) errors.push(`src import 금지: ${file}: ${target}`);
190
+ if (/(?:^|\/)src\//.test(target) && (target.startsWith('/') || target.startsWith('.'))) errors.push('src import 금지');
190
191
  }
191
192
  }
192
193
  }
193
194
  };
194
- try { visit(dir); } catch (error) { errors.push(`파일 검사 실패: ${String(error)}`); }
195
+ try { visit(dir); } catch { errors.push('파일 검사 실패'); }
195
196
  try {
196
197
  const example = join(dir, 'examples', 'input.json');
197
198
  if (lstatSync(example).isSymbolicLink()) errors.push('안전하지 않은 examples/input.json 링크');
198
199
  else JSON.parse(readFileSync(example, 'utf8'));
199
- } catch (error) { errors.push(`examples/input.json 파싱 실패: ${String(error)}`); }
200
+ } catch { errors.push('examples/input.json 파싱 실패'); }
201
+ let security: ReturnType<typeof inspectPluginSecurity>;
202
+ try { security = inspectPluginSecurity(dir); }
203
+ catch { errors.push('보안 검사 실패'); return errors; }
204
+ if (security.scan === 'dangerous') errors.push(...security.findings.filter(f => f.level === 'dangerous').map(f => `보안 검사 차단: ${f.code}`));
200
205
  const step = join(dir, 'graphs', 'run-step.ts');
201
206
  try {
202
207
  if (!existsSync(step)) errors.push('run-step.ts 없음');
203
- else if (errors.some(error => error.startsWith('안전하지 않은 파일:'))) return errors;
208
+ else if (errors.some(error => error.startsWith('안전하지 않은 파일'))) return errors;
204
209
  else {
205
210
  const build = await Bun.build({ entrypoints: [step], target: 'bun' });
206
- if (!build.success) errors.push(...build.logs.map(log => `run-step.ts 문법 오류: ${log.message}`));
211
+ if (!build.success) errors.push('run-step.ts 문법 오류');
207
212
  }
208
- } catch (error) { errors.push(`run-step.ts 문법 오류: ${String(error)}`); }
213
+ } catch { errors.push('run-step.ts 문법 오류'); }
209
214
  return errors;
210
215
  }
211
216
 
@@ -359,7 +364,7 @@ export async function makePlugin({ request, draftFile, name, parentDir, run, mar
359
364
  const step = async (stage: keyof MakePluginResult['timings'], action: () => void | Promise<void>): Promise<void> => {
360
365
  const start = performance.now();
361
366
  try { await action(); }
362
- finally { const ms = Math.round(performance.now() - start); timings[stage] = ms; debug.log('plugin.maker', stage, { ms, errors: result.errors }); }
367
+ finally { const ms = Math.round(performance.now() - start); timings[stage] = ms; debug.log('plugin.maker', stage, { ms, errors: redactSecrets(result.errors) }); }
363
368
  };
364
369
  try {
365
370
  emit('request', request);
@@ -461,7 +466,7 @@ export async function makePlugin({ request, draftFile, name, parentDir, run, mar
461
466
  }
462
467
  } catch (error) {
463
468
  result.status = 'failed';
464
- result.errors.push(error instanceof Error ? error.message : String(error));
469
+ result.errors.push(redactSecretText(error instanceof Error ? error.message : String(error)));
465
470
  } finally {
466
471
  emit('done', result.status, { errors: result.errors });
467
472
  }
@@ -10,6 +10,7 @@ export interface WizardResearchDraft {
10
10
  credentials?: Array<{ name: string }>;
11
11
  }>;
12
12
  skill?: { description: string; instructions: string; requires?: string[] };
13
+ requires?: { knowledgePacks?: string[] };
13
14
  }
14
15
 
15
16
  const SLUG = /^[a-z0-9][a-z0-9-]{1,31}$/;
@@ -46,9 +47,16 @@ export function generateWizardFiles(dir: string, slug: string, draft: WizardRese
46
47
  if (!Array.isArray(requires) || requires.some(resource => typeof resource !== 'string' || !knownResources.has(resource))) {
47
48
  throw new Error('wizard requires must reference existing resource ids');
48
49
  }
50
+ if (draft.requires !== undefined && (!draft.requires || typeof draft.requires !== 'object' || Array.isArray(draft.requires) ||
51
+ Object.keys(draft.requires).some(key => key !== 'knowledgePacks') ||
52
+ (draft.requires.knowledgePacks !== undefined && (!Array.isArray(draft.requires.knowledgePacks) ||
53
+ draft.requires.knowledgePacks.some(pack => typeof pack !== 'string' || !pack.trim()))))) {
54
+ throw new Error('wizard knowledge packs must be non-empty names');
55
+ }
49
56
  const manifestPath = join(dir, 'plugin.json');
50
57
  const existing = existsSync(manifestPath) ? JSON.parse(readFileSync(manifestPath, 'utf8')) as {
51
- name: string; description?: string; extensions: { 'ai.elanous': { connectors?: unknown[]; graphs?: string[]; researchDraft?: boolean } };
58
+ name: string; description?: string; requires?: { knowledgePacks?: string[]; [key: string]: unknown };
59
+ extensions: { 'ai.elanous': { connectors?: unknown[]; graphs?: string[]; researchDraft?: boolean } };
52
60
  } : undefined;
53
61
  if (existing && (existing.name !== slug || !existing.extensions?.['ai.elanous'])) {
54
62
  throw new Error('wizard scaffold name or extension mismatch');
@@ -69,9 +77,13 @@ export function generateWizardFiles(dir: string, slug: string, draft: WizardRese
69
77
  throw new Error('wizard cannot replace existing scaffold connectors');
70
78
  }
71
79
  const manifest = existing ?? { name: slug, version: '0.1.0', description: draft.description,
80
+ requires: undefined as { knowledgePacks?: string[]; [key: string]: unknown } | undefined,
72
81
  extensions: { 'ai.elanous': { graphs: [`./graphs/${slug}.yaml`],
73
82
  capabilities: ['fs:workdir', 'proc:bun', 'proc:elanous'], connectors: [] as unknown[], researchDraft: true } } };
74
83
  if (options.regenerate) manifest.description = draft.description;
84
+ if (draft.requires?.knowledgePacks !== undefined) {
85
+ manifest.requires = { ...manifest.requires, knowledgePacks: [...new Set(draft.requires.knowledgePacks)] };
86
+ }
75
87
  manifest.extensions['ai.elanous'].connectors = connectors;
76
88
  manifest.extensions['ai.elanous'].researchDraft = true;
77
89
 
@@ -125,7 +137,8 @@ export function listWizardDrafts(parent: string): Array<{ name: string; descript
125
137
  const skillPath = join(skillDir, 'SKILL.md');
126
138
  if (lstatSync(manifestPath).isSymbolicLink() || lstatSync(skillDir).isSymbolicLink() || lstatSync(skillPath).isSymbolicLink()) return [];
127
139
  const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as {
128
- name?: string; description?: string; extensions?: { 'ai.elanous'?: { researchDraft?: boolean; connectors?: Array<{ id: string; fields: Array<{ name: string }> }> } } };
140
+ name?: string; description?: string; requires?: { knowledgePacks?: string[] };
141
+ extensions?: { 'ai.elanous'?: { researchDraft?: boolean; connectors?: Array<{ id: string; fields: Array<{ name: string }> }> } } };
129
142
  if (manifest.name !== entry.name || manifest.extensions?.['ai.elanous']?.researchDraft !== true) return [];
130
143
  const skill = readFileSync(skillPath, 'utf8');
131
144
  const parts = /^---\n([\s\S]*?)---\n\n([\s\S]*)$/.exec(skill);
@@ -134,6 +147,7 @@ export function listWizardDrafts(parent: string): Array<{ name: string; descript
134
147
  return [{ name: entry.name, description: manifest.description, draft: {
135
148
  description: manifest.description,
136
149
  connectors: manifest.extensions['ai.elanous'].connectors?.map(connector => ({ id: connector.id, credentials: connector.fields.map(field => ({ name: field.name })) })) ?? [],
150
+ ...(manifest.requires?.knowledgePacks !== undefined ? { requires: { knowledgePacks: manifest.requires.knowledgePacks } } : {}),
137
151
  skill: { description: meta.description ?? manifest.description, instructions: parts[2]!.trimEnd(), requires: meta.requires ?? [] },
138
152
  } }];
139
153
  } catch { return []; }
@@ -4,7 +4,7 @@ import { isScalar, parseDocument } from 'yaml';
4
4
  import { getElanousConfigDir } from '../elanous-config-dir.js';
5
5
  import { DEFAULT_FALLBACK_CHAIN, isFallbackStep, type FallbackStep } from '../oauth/fallback-chain.js';
6
6
  import { isCodexQuotaPolicy } from '../oauth/codex-quota-policy.js';
7
- import { DEFAULT_BUDGET_GATE_MAX_USED_PERCENT, MODEL_ROLES, RUNTIME_LLM_PROVIDER_NAMES, parseRoleLlmEntry, parseSubscriptionReviewerSpec, type RoleLlmConfig } from '../user-config.js';
7
+ import { DEFAULT_BUDGET_GATE_MAX_USED_PERCENT, MODEL_ROLES, RUNTIME_LLM_PROVIDER_NAMES, parseRoleLlmEntry, parseSubscriptionReviewerSpec, type RoleLlmConfig, type SubscriptionReviewerSpec } from '../user-config.js';
8
8
 
9
9
  export interface LlmPolicy {
10
10
  version: 1;
@@ -164,6 +164,19 @@ function removeExpired(input: Obj, now: Date, warnings: string[], prefix = ''):
164
164
  }
165
165
  }
166
166
 
167
+ /**
168
+ * The reviewer ACP lane (`roleLlm.reviewer`) and its usage cap, resolved once for every caller.
169
+ * The harness (`dev-pipeline`) and `elanous self review` read the same policy row, so the two
170
+ * reviewers cannot drift apart on which config selects the subscription reviewer.
171
+ */
172
+ export function resolveSubscriptionReviewer(
173
+ loaded: LoadedLlmPolicy,
174
+ userRoleLlm?: RoleLlmConfig,
175
+ ): { spec: SubscriptionReviewerSpec; cap: number } | undefined {
176
+ const spec = loaded.policy.roles.reviewer ?? userRoleLlm?.reviewer;
177
+ return spec ? { spec, cap: loaded.policy.caps.claude.harness } : undefined;
178
+ }
179
+
167
180
  export function loadLlmPolicy(opts: LoadLlmPolicyOptions = {}): LoadedLlmPolicy {
168
181
  const configDir = opts.configDir ?? getElanousConfigDir();
169
182
  const path = opts.path ?? join(configDir, 'policy', 'llm.yaml');
@@ -14,7 +14,6 @@
14
14
  * ⚠️ 이 판정은 «같은 호스트»에서만 뜻이 있다 — pid 는 호스트 지역 값이다.
15
15
  * 락처럼 호스트가 섞이는 소비자는 호스트를 «먼저» 가른 뒤 이걸 부른다.
16
16
  */
17
- import { debug } from '../debug/log.js';
18
17
 
19
18
  /** ⛔ 두 값이 아니라 «셋»이다 — 「살아 있는데 내가 못 건드린다」는 별도의 사실이다.
20
19
  * 그것을 `alive` 나 `dead` 어느 쪽으로도 접지 않는 것이 이 타입의 존재 이유다. */
@@ -58,6 +57,7 @@ export function pidLiveness(pid: number): PidLiveness {
58
57
  if (verdict === 'alive-not-mine') {
59
58
  // ⛔ 「살아 있는데 남의 것」은 조용히 지나가면 안 된다 — 🅢 요청(2026-09-20):
60
59
  // 원장에 «대상 pid 와 소유자 축»이 남아야 A 구간(남의 트리에서 도는 자식)과 닿는다.
60
+ const { debug } = require('../debug/log.js') as { debug: { log: (category: string, event: string, data: Record<string, unknown>) => void } };
61
61
  debug.log('process.liveness', 'kill-refused', { pid, myUid: myUid(), errno });
62
62
  observer?.({ pid, liveness: verdict, myUid: myUid(), errno });
63
63
  }
@@ -35,7 +35,8 @@ export function parseOpenAIUsage(event: unknown): LLMUsage | null {
35
35
  const r = raw as {
36
36
  prompt_tokens?: number;
37
37
  completion_tokens?: number;
38
- prompt_tokens_details?: { cached_tokens?: number };
38
+ /** OpenRouter 는 캐시 쓰기를 `cache_write_tokens` 로 싣는다(Anthropic 상류 · OR-ANTHROPIC-CACHE). */
39
+ prompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };
39
40
  completion_tokens_details?: { reasoning_tokens?: number };
40
41
  /** Kimi(Moonshot) — 최상위에 싣는다. */
41
42
  cached_tokens?: number;
@@ -50,14 +51,17 @@ export function parseOpenAIUsage(event: unknown): LLMUsage | null {
50
51
  // 캐시 단가로 또 한 번 매겨진다(BACKLOG C4 · opencode openai-chat.ts · hermes normalize_usage 와 같은 처리).
51
52
  const cached = [r.prompt_tokens_details?.cached_tokens, r.cached_tokens, r.prompt_cache_hit_tokens]
52
53
  .find((v): v is number => typeof v === 'number');
53
- if (typeof r.prompt_tokens === 'number') out.inputTokens = Math.max(0, r.prompt_tokens - (cached ?? 0));
54
+ // OR-ANTHROPIC-CACHE — OpenRouter(Anthropic 상류)의 캐시 «쓰기»도 prompt_tokens 에 포함돼 온다 → 새 입력에서 빼고
55
+ // cacheCreationInputTokens 로 옮긴다(Anthropic 규약). 칸이 없으면(OpenAI·Grok·DeepSeek …) 종전과 같다.
56
+ const written = typeof r.prompt_tokens_details?.cache_write_tokens === 'number' ? r.prompt_tokens_details.cache_write_tokens : undefined;
57
+ if (typeof r.prompt_tokens === 'number') out.inputTokens = Math.max(0, r.prompt_tokens - (cached ?? 0) - (written ?? 0));
54
58
  if (typeof r.completion_tokens === 'number') out.outputTokens = r.completion_tokens;
55
- if (cached !== undefined) {
56
- out.cacheReadInputTokens = cached;
59
+ if (cached !== undefined || written !== undefined) {
60
+ out.cacheReadInputTokens = cached ?? 0;
57
61
  // OpenAI caches are free-on-hit and rolled into prompt_tokens for
58
62
  // creation — we set creation to 0 so metrics math (hit-rate) works
59
- // uniformly across providers.
60
- out.cacheCreationInputTokens = 0;
63
+ // uniformly across providers. OpenRouter→Anthropic reports writes.
64
+ out.cacheCreationInputTokens = written ?? 0;
61
65
  }
62
66
  // Reasoning tokens — OpenAI o1/o3, qwen 3.6 (LM Studio surfaces this
63
67
  // even though qwen calls it `reasoning_content` rather than the
@@ -0,0 +1,94 @@
1
+ // OR-ANTHROPIC-CACHE (2026-10-10) — OpenRouter 경유 Anthropic·Moonshot(Kimi) 호출의 프롬프트 캐시 중단점.
2
+ //
3
+ // OpenRouter 는 OpenAI 꼴 본문을 받아 상류(Anthropic·Moonshot)로 옮긴다. 이 두 계열은 «요청이 청해야»
4
+ // 캐시를 쓴다 — 본문에 `cache_control` 이 없으면 적중 0 이다(10-10 벤치: Haiku·Sonnet 5.5 팔 cachedInput 0).
5
+ //
6
+ // 배치(참고 구현 대조):
7
+ // - opencode `provider/transform.ts` applyCaching — system 앞 2 ⊕ 비-system 끝 2 (상한 4).
8
+ // - hermes `agent/prompt_caching.py` envelope layout — OpenRouter 는 «content 파트»의 cache_control 만 따른다.
9
+ // · role:tool 의 «최상위» cache_control 은 OpenRouter 에서 조용히 멎는다 → 파트에만 단다(OpenRouter 가
10
+ // tool_result 블록으로 옮긴다).
11
+ // · content 가 비거나 null 인 assistant(순수 tool_calls)는 중단점을 낭비하므로 건너뛴다.
12
+ // · Kimi(moonshotai/*) 도 같은 envelope 꼴로 적중 1% → 97% (hermes #25970).
13
+ // - tools: 따로 표시하지 않는다. Anthropic 접두 순서가 tools → system → messages 라 system 끝 중단점이
14
+ // 도구 정의까지 덮는다. hermes 도 tools 배열 표시는 «직접 Anthropic» 경로에만 쓴다.
15
+ //
16
+ // ⛔ 순수 함수 — 입력 배열·메시지를 고치지 않고 바뀐 메시지만 새로 만든다.
17
+
18
+ /** Anthropic 상한. */
19
+ export const OPENROUTER_MAX_CACHE_BREAKPOINTS = 4;
20
+
21
+ export type OpenRouterCacheFamily = 'anthropic' | 'moonshotai';
22
+
23
+ /** wire 모델(`anthropic/claude-haiku-5.5`)이 캐시 중단점 대상인가. 대상이 아니면 null. */
24
+ export function openRouterPromptCacheFamily(wireModel: string): OpenRouterCacheFamily | null {
25
+ if (wireModel.startsWith('anthropic/')) return 'anthropic';
26
+ if (wireModel.startsWith('moonshotai/')) return 'moonshotai';
27
+ return null;
28
+ }
29
+
30
+ type WireMessage = Record<string, unknown>;
31
+ type CacheMarker = { type: 'ephemeral'; ttl?: '1h' };
32
+
33
+ function isMarkablePart(part: unknown): boolean {
34
+ // 텍스트 파트에만 단다 — image_url 파트 위 cache_control 의 OpenRouter 전달은 확인하지 않았다(보수).
35
+ return !!part && typeof part === 'object' && (part as { type?: unknown }).type === 'text';
36
+ }
37
+
38
+ function canCarryMarker(msg: WireMessage): boolean {
39
+ const content = msg.content;
40
+ if (typeof content === 'string') return content.length > 0;
41
+ if (Array.isArray(content) && content.length > 0) return isMarkablePart(content[content.length - 1]);
42
+ return false;
43
+ }
44
+
45
+ function withMarker(msg: WireMessage, marker: CacheMarker): WireMessage {
46
+ const content = msg.content;
47
+ if (typeof content === 'string') {
48
+ return { ...msg, content: [{ type: 'text', text: content, cache_control: { ...marker } }] };
49
+ }
50
+ const parts = (content as Array<Record<string, unknown>>).slice();
51
+ parts[parts.length - 1] = { ...parts[parts.length - 1], cache_control: { ...marker } };
52
+ return { ...msg, content: parts };
53
+ }
54
+
55
+ export interface OpenRouterCachePlan {
56
+ messages: WireMessage[];
57
+ /** 실제로 단 중단점 수(0~4). */
58
+ breakpoints: number;
59
+ systemBreakpoints: number;
60
+ tailBreakpoints: number;
61
+ }
62
+
63
+ /** system 앞 2 ⊕ 비-system 끝 2 (합 ≤ 4) 의 마지막 텍스트 파트에 `cache_control` 을 단다.
64
+ * `ttl:'1h'` 은 anthropic 계열에만 싣는다(Moonshot 의 1h 계층은 확인하지 않았다 → 기본 5m). */
65
+ export function applyOpenRouterCacheControl(
66
+ messages: readonly WireMessage[],
67
+ opts: { family: OpenRouterCacheFamily; ttl?: '5m' | '1h' },
68
+ ): OpenRouterCachePlan {
69
+ const marker: CacheMarker = opts.family === 'anthropic' && opts.ttl === '1h'
70
+ ? { type: 'ephemeral', ttl: '1h' }
71
+ : { type: 'ephemeral' };
72
+ const out = messages.slice();
73
+ let systemBreakpoints = 0;
74
+ for (let i = 0; i < out.length && systemBreakpoints < 2; i++) {
75
+ if (out[i]!.role !== 'system') continue;
76
+ if (!canCarryMarker(out[i]!)) continue;
77
+ out[i] = withMarker(out[i]!, marker);
78
+ systemBreakpoints++;
79
+ }
80
+ const remaining = Math.min(2, OPENROUTER_MAX_CACHE_BREAKPOINTS - systemBreakpoints);
81
+ const tail: number[] = [];
82
+ for (let i = out.length - 1; i >= 0 && tail.length < remaining; i--) {
83
+ const m = out[i]!;
84
+ if (m.role === 'system') continue;
85
+ if (canCarryMarker(m)) tail.push(i);
86
+ }
87
+ for (const i of tail) out[i] = withMarker(out[i]!, marker);
88
+ return {
89
+ messages: out,
90
+ breakpoints: systemBreakpoints + tail.length,
91
+ systemBreakpoints,
92
+ tailBreakpoints: tail.length,
93
+ };
94
+ }
@@ -16,6 +16,7 @@ import { streamLLM, type LLMMessage } from '../llm.js';
16
16
  import { debug } from '../debug/log.js';
17
17
  import type { LLMUsage } from '../prompt-cache/types.js';
18
18
  import { llmUsageCostFields } from '../budget/llm-cost.js';
19
+ import { getUserConfig, resolveRoleLlm, type UserConfig } from '../user-config.js';
19
20
 
20
21
  function logLlmUsage(model: string, usage: LLMUsage): void {
21
22
  try {
@@ -97,6 +98,8 @@ export interface EnhanceOpts {
97
98
  */
98
99
  checklistUse?: ChecklistUse;
99
100
  reasoningEffort?: 'low' | 'medium' | 'high';
101
+ /** 호출자의 저작 시점 config. 생략 시 현재 사용자 설정을 읽는다. */
102
+ config?: UserConfig;
100
103
  /** 산출물 유형 힌트(선택) — 예: 'PPT 발표덱', 'PLAN 문서'. 제약 문구 조정. */
101
104
  deliverableHint?: string;
102
105
  /** Optional usage observer for the caller's authoring phase; missing usage stays unknown. */
@@ -115,6 +118,8 @@ export interface EnhanceOpts {
115
118
  * ⭐ 새 LLM 경로를 만들지 않는다 — 이 모듈이 이미 그 자리의 유일한 LLM 단계다.
116
119
  */
117
120
  groundedFacts?: readonly string[];
121
+ /** Clock seam for the first-token observation (ms epoch); defaults to `Date.now`. */
122
+ now?: () => number;
118
123
  }
119
124
 
120
125
  const FENCE = '```';
@@ -129,8 +134,29 @@ function askMarkerCount(ask: string): number {
129
134
  return (ask.match(/(?:^|\s)(?:불변식|경계|판정\s*신호|invariant|boundary|decision\s+signal)\s*:/gi) ?? []).length;
130
135
  }
131
136
 
132
- const defaultModel = (): string =>
133
- process.env.ELANOUS_PROMPT_ENHANCE_MODEL || process.env.ELANOUS_PR_REVIEW_MODEL || tierModel('better');
137
+ type EnhanceSelectionSource = 'opts' | 'env' | 'config-role' | 'default';
138
+
139
+ /** Select the authoring knobs independently; a planning effort alone cannot change the model. */
140
+ export function selectEnhanceLlm(
141
+ opts: Pick<EnhanceOpts, 'model' | 'reasoningEffort' | 'config'> = {},
142
+ env: NodeJS.ProcessEnv = process.env,
143
+ ): { model: string; effort: 'low' | 'medium' | 'high'; modelSource: EnhanceSelectionSource; effortSource: EnhanceSelectionSource } {
144
+ const config = opts.config ?? getUserConfig();
145
+ const planning = config.roleLlm?.planning;
146
+ const configuredModel = opts.model === undefined && !env.ELANOUS_PROMPT_ENHANCE_MODEL
147
+ && planning && (planning.model || planning.tier || planning.provider)
148
+ ? resolveRoleLlm('planning', { config, overrides: {} }).model : undefined;
149
+ const modelSource: EnhanceSelectionSource = opts.model !== undefined ? 'opts'
150
+ : env.ELANOUS_PROMPT_ENHANCE_MODEL ? 'env'
151
+ : configuredModel !== undefined ? 'config-role' : 'default';
152
+ const model = opts.model ?? (env.ELANOUS_PROMPT_ENHANCE_MODEL || configuredModel || env.ELANOUS_PR_REVIEW_MODEL || tierModel('better'));
153
+ const envEffort = env.ELANOUS_PROMPT_ENHANCE_EFFORT;
154
+ const validEnvEffort = envEffort === 'low' || envEffort === 'medium' || envEffort === 'high' ? envEffort : undefined;
155
+ const effortSource: EnhanceSelectionSource = opts.reasoningEffort !== undefined ? 'opts'
156
+ : validEnvEffort !== undefined ? 'env'
157
+ : planning?.effort !== undefined ? 'config-role' : 'default';
158
+ return { model, effort: opts.reasoningEffort ?? validEnvEffort ?? planning?.effort ?? 'high', modelSource, effortSource };
159
+ }
134
160
 
135
161
  /** 스캐폴드 생성 LLM 시스템 프롬프트 — 가산·원문불가침 규율. */
136
162
  const enhanceSystem = (deliverableHint?: string, wantsScqa = false, checklistUse: ChecklistUse = 'coverage-gate'): string =>
@@ -332,7 +358,10 @@ export async function enhancePrompt(raw: string, opts: EnhanceOpts = {}): Promis
332
358
  return { original, enhanced, checklist: [], verbatimPreserved: true, enhancedBy: 'fallback', model: null };
333
359
  }
334
360
 
335
- const model = opts.model ?? defaultModel();
361
+ // Selected only when an LLM call will actually be attempted — the disabled path never records a selection.
362
+ const { model, effort, modelSource, effortSource } = selectEnhanceLlm(opts);
363
+ debug.log('prompt-enhance.model', 'selected', { model, effort, modelSource, effortSource });
364
+
336
365
  let goal = '';
337
366
  let constraints: string[] = [];
338
367
  let checklist: string[] = [];
@@ -367,9 +396,21 @@ export async function enhancePrompt(raw: string, opts: EnhanceOpts = {}): Promis
367
396
  ].join('\n'),
368
397
  },
369
398
  ];
370
- const rawOut = await streamLLM(messages, () => {}, {
399
+ // ⭐ OPENROUTER-OPTIMIZE G13 — 첫 토큰까지 걸린 시간(TTFT)을 호출마다 «한 번» 남긴다.
400
+ // 총 소요만으로는 「대기(큐·라우팅)」와 「생성」을 못 가른다. 본문은 싣지 않는다(길이도 안 싣는다).
401
+ // ⚠️ 첫 «텍스트» 델타까지다 — 추론(reasoning) 토큰을 먼저 내는 모델은 그 생성 시간도 여기 들어간다
402
+ // (순수 대기·라우팅 시간으로 읽지 않는다).
403
+ const now = opts.now ?? Date.now;
404
+ const requestStartedAt = now();
405
+ let firstTokenLogged = false;
406
+ const onChunk = (delta: string): void => {
407
+ if (firstTokenLogged || delta.length === 0) return;
408
+ firstTokenLogged = true;
409
+ debug.log('prompt-enhance.stream', 'first-token', { model, ttftMs: Math.max(0, now() - requestStartedAt) });
410
+ };
411
+ const rawOut = await streamLLM(messages, onChunk, {
371
412
  model,
372
- reasoningEffort: opts.reasoningEffort ?? 'high',
413
+ reasoningEffort: effort,
373
414
  onUsage: (usage) => {
374
415
  logLlmUsage(model, usage);
375
416
  try { opts.onUsage?.(usage); } catch { /* usage observation must not change enhancement */ }
@@ -31,6 +31,7 @@ export const FAMILY_PROBE_MODEL_IDS: Readonly<Record<Exclude<ModelFamily, 'other
31
31
  grok: 'grok-4.7',
32
32
  gemini: 'gemini-3-pro',
33
33
  local: 'local:qwen',
34
+ 'open-weight': 'openrouter/z-ai/glm-5.3',
34
35
  };
35
36
 
36
37
  export interface FamilyPromptCoverage {
@@ -32,11 +32,11 @@ import { buildGrokFamilyAddendum } from './grok-family-addendum.js';
32
32
  import { buildSessionGuidanceAddendum } from './session-guidance.js';
33
33
  import { getHarnessSpace } from '../harness/harness-space.js';
34
34
 
35
- export const PROJECT_ANCHOR_MAX_CHARS = 32 * 1024;
35
+ export const PROJECT_ANCHOR_MAX_CHARS = 36 * 1024; // 10-10 증액(32K→36K) — 줄이기는 AGENTS-CLAUDE-DIET(0.2.24)
36
36
  /** «lean» 예산(BACKLOG L2 · 2026-09-25) — 로컬 모델 구현 자식은 매 턴 이것을 prefill 한다.
37
37
  * 📏 09-25 node-b 기록 프록시: 시스템 50,068자 중 AGENTS.md 앵커 ~32K · 트리 ~8K 가 상위 둘이었다.
38
38
  * ⭐ 켜는 법: env `ELANOUS_PROMPT_BUDGET=lean` — 하니스 구현 자식 spawn 이 child provider 가 local 일 때 준다.
39
- * ⛔ API 모델 경로의 기본(32K·8K)은 그대로다 — 잘 도는 것을 바꾸지 않는다. */
39
+ * ⛔ API 모델 경로의 기본(36K·8K)은 그대로다 — 잘 도는 것을 바꾸지 않는다. */
40
40
  export const PROJECT_ANCHOR_LEAN_MAX_CHARS = 8 * 1024;
41
41
  export const PROJECT_TREE_LEAN_MAX_CHARS = 2 * 1024;
42
42
  function promptBudgetLean(): boolean { return process.env.ELANOUS_PROMPT_BUDGET?.trim() === 'lean'; }
@@ -0,0 +1,122 @@
1
+ // OR-MODEL-NAMESPACE (대표 2026-10-10 «OpenRouter 로 Claude 계열이 안 도는 이유를 먼저 고쳐라»).
2
+ //
3
+ // S: 구현 자식 모델 해석(`resolveImplementationChildModel`)은 `openrouter/<vendor>/<model>` 을 호스트의
4
+ // `discovery-snapshot.json` 에 «있는 id» 로만 받는다.
5
+ // C: 스냅숏은 갱신이 멎으면 늙는다(09-23 판) — 그 뒤 OpenRouter 에 올라온 모델(claude-haiku-5.5 등)은
6
+ // «있는데도» 거부된다. 거부 사유는 「없다」지만 사실은 「우리 스냅숏이 모른다」다.
7
+ // A: 스냅숏에 없을 때만 공개 `/api/v1/models` 를 «한 번» 묻는다(기존 `openrouterSource` 재사용 · 키 불요).
8
+ // 있으면 그 항목을 스냅숏에 합치고 카탈로그를 다시 읽는다. 없으면 지금처럼 거부.
9
+ // ⛔ 네트워크 실패·시간 초과는 «거부»(fail-closed) — 「확인 못 함」을 「있다」로 접지 않는다.
10
+
11
+ import { mkdirSync, renameSync, writeFileSync } from 'node:fs';
12
+ import { dirname } from 'node:path';
13
+ import { debug } from '../../debug/log.js';
14
+ import { isolatedCatalogTestUniverse, reloadCatalog } from '../loader.js';
15
+ import { defaultDiscoveryCachePath, readDiscoveryCache, type DiscoverySnapshot } from './cache.js';
16
+ import { openrouterSource } from './sources/openrouter.js';
17
+ import type { DiscoveredModel } from './types.js';
18
+
19
+ export const OPENROUTER_LIVE_RESOLVE_TIMEOUT_MS = 10_000;
20
+ export const OPENROUTER_SNAPSHOT_STALE_DAYS = 7;
21
+ const NAMESPACED_OPENROUTER_ID = /^openrouter\/([^/\s]+\/[^/\s]+)$/;
22
+ const DAY_MS = 24 * 60 * 60 * 1000;
23
+
24
+ /** 이 프로세스에서 라이브로 확인한 id — 스냅숏 쓰기가 실패해도 같은 프로세스의 재해석은 통과시킨다. */
25
+ const liveVerified = new Set<string>();
26
+
27
+ export function isLiveVerifiedOpenRouterModel(id: string): boolean {
28
+ return liveVerified.has(id);
29
+ }
30
+
31
+ export function __resetOpenRouterLiveResolveForTests(): void {
32
+ liveVerified.clear();
33
+ }
34
+
35
+ /** `openrouter/<vendor>/<model>` → `<vendor>/<model>`(스냅숏·OpenRouter 의 id). 형식이 아니면 undefined. */
36
+ export function upstreamOpenRouterId(id: string): string | undefined {
37
+ return NAMESPACED_OPENROUTER_ID.exec(id)?.[1];
38
+ }
39
+
40
+ /** 카탈로그 로더가 «접는» 스냅숏 경로. 시험 런타임에서 명시 경로가 없으면 undefined(실 `~/.elanous` 를 안 건드린다). */
41
+ export function foldSnapshotPath(): string | undefined {
42
+ const explicit = process.env.ELANOUS_CATALOG_DISCOVERY_SNAPSHOT?.trim();
43
+ if (explicit) return explicit;
44
+ if (isolatedCatalogTestUniverse()) return undefined;
45
+ return defaultDiscoveryCachePath();
46
+ }
47
+
48
+ export function snapshotAgeDays(snapshot: DiscoverySnapshot | null, now: number = Date.now()): number | undefined {
49
+ if (!snapshot?.generatedAt) return undefined;
50
+ const t = Date.parse(snapshot.generatedAt);
51
+ if (!Number.isFinite(t)) return undefined;
52
+ return Math.max(0, Math.floor((now - t) / DAY_MS));
53
+ }
54
+
55
+ export function readFoldSnapshotAgeDays(now: number = Date.now()): number | undefined {
56
+ const path = foldSnapshotPath();
57
+ return path ? snapshotAgeDays(readDiscoveryCache({ cachePath: path }), now) : undefined;
58
+ }
59
+
60
+ function persistMergedModel(path: string, model: DiscoveredModel, now: number): boolean {
61
+ try {
62
+ const existing = readDiscoveryCache({ cachePath: path });
63
+ const snapshot: DiscoverySnapshot = existing ?? {
64
+ version: 1,
65
+ generatedAt: new Date(now).toISOString(),
66
+ sources: [],
67
+ models: [],
68
+ };
69
+ if (!snapshot.models.some((m) => m.provider === 'openrouter' && m.id === model.id)) {
70
+ snapshot.models.push(model);
71
+ }
72
+ mkdirSync(dirname(path), { recursive: true });
73
+ const tmp = `${path}.${process.pid}.tmp`;
74
+ writeFileSync(tmp, JSON.stringify(snapshot, null, 2), 'utf-8');
75
+ renameSync(tmp, path);
76
+ return true;
77
+ } catch {
78
+ return false;
79
+ }
80
+ }
81
+
82
+ export type OpenRouterLiveLookup =
83
+ | { found: true; id: string; merged: DiscoveredModel; persisted: boolean; snapshotAgeDays?: number }
84
+ | { found: false; id: string; error?: string; snapshotAgeDays?: number };
85
+
86
+ /** 스냅숏에 없는 `openrouter/<vendor>/<model>` 을 공개 `/models` 에 «한 번» 묻는다.
87
+ * found → 스냅숏에 합치고(가능하면) 카탈로그를 다시 읽는다. error → 확인 못 함(호출자가 거부). */
88
+ export async function liveLookupOpenRouterModel(
89
+ id: string,
90
+ opts: { fetchImpl?: typeof fetch; timeoutMs?: number; now?: () => number; persist?: boolean } = {},
91
+ ): Promise<OpenRouterLiveLookup> {
92
+ const now = opts.now ?? Date.now;
93
+ const path = foldSnapshotPath();
94
+ const ageDays = path ? snapshotAgeDays(readDiscoveryCache({ cachePath: path }), now()) : undefined;
95
+ const age = ageDays !== undefined ? { snapshotAgeDays: ageDays } : {};
96
+ const upstream = upstreamOpenRouterId(id);
97
+ if (!upstream) {
98
+ debug.log('registry.discovery', 'child-model-live-resolve', { id, found: false, ...age, error: 'not-namespaced' });
99
+ return { found: false, id, error: 'not-namespaced', ...age };
100
+ }
101
+ const result = await openrouterSource.run({
102
+ timeoutMs: opts.timeoutMs ?? OPENROUTER_LIVE_RESOLVE_TIMEOUT_MS,
103
+ ...(opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}),
104
+ now,
105
+ });
106
+ if (!result.ok) {
107
+ const error = result.error ?? 'unknown';
108
+ debug.log('registry.discovery', 'child-model-live-resolve', { id, found: false, ...age, error });
109
+ return { found: false, id, error, ...age };
110
+ }
111
+ const merged = result.models.find((m) => m.id === upstream);
112
+ if (!merged) {
113
+ debug.log('registry.discovery', 'child-model-live-resolve', { id, found: false, ...age });
114
+ return { found: false, id, ...age };
115
+ }
116
+ liveVerified.add(id);
117
+ // ⚠️ 잠금 없는 read-modify-write — discovery 크론과 같은 순간이면 한쪽 쓰기가 사라질 수 있다(감시 항목 · 다음 조회가 다시 합친다).
118
+ const persisted = path && opts.persist !== false ? persistMergedModel(path, merged, now()) : false;
119
+ if (persisted) reloadCatalog();
120
+ debug.log('registry.discovery', 'child-model-live-resolve', { id, found: true, ...age, persisted });
121
+ return { found: true, id, merged, persisted, ...age };
122
+ }
@@ -385,13 +385,18 @@ function buildCatalog(): Catalog {
385
385
  };
386
386
  }
387
387
 
388
+ /** 시험 런타임(NODE_ENV=test)은 카탈로그 스냅숏을 기본 경로에서 접지 않는다 — 이 판정을 쓰는 쪽(자식 모델 형식 검사)과 공유한다. */
389
+ export function isolatedCatalogTestUniverse(): boolean {
390
+ return process.env.NODE_ENV === 'test';
391
+ }
392
+
388
393
  /** 폴드할 스냅숏을 고른다. ⛔ 시험 런타임은 preload 가 config-dir 를 격리하지 않아 실제
389
394
  * `~/.elanous/discovery-snapshot.json` 을 읽게 되므로(=기계마다 다른 카탈로그), 경로를 «명시»했을
390
395
  * 때만 접는다. 운영은 기본 경로를 읽고, 없으면 «모른다»(null) — 접을 것이 없을 뿐 오류가 아니다. */
391
396
  function loadFoldSnapshot(): DiscoverySnapshot | null {
392
397
  const explicit = process.env.ELANOUS_CATALOG_DISCOVERY_SNAPSHOT?.trim();
393
398
  if (explicit) return readDiscoveryCache({ cachePath: explicit });
394
- if (process.env.NODE_ENV === 'test') return null;
399
+ if (isolatedCatalogTestUniverse()) return null;
395
400
  return readDiscoveryCache();
396
401
  }
397
402