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
@@ -0,0 +1,168 @@
1
+ import { Database } from 'bun:sqlite';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+
6
+ import { elanousStateRoot } from '../../autopilot/state-paths.js';
7
+ import { debug } from '../../debug/log.js';
8
+ import { registerStandaloneLogSink } from '../../domains/standalone-log-sink.js';
9
+ import { LogStore, logsDbPath } from './log-store.js';
10
+
11
+ type HorizonStatus = 'present' | 'empty' | 'unreadable';
12
+ type Attribution = 'first-sample' | 'none' | 'attributed' | 'unattributed-loss';
13
+
14
+ export interface HorizonSample {
15
+ atMs: number;
16
+ oldestTsMs: number | null;
17
+ status: HorizonStatus;
18
+ spanHours: number | null;
19
+ advancedMs: number;
20
+ deletedEvents: number;
21
+ attribution: Attribution;
22
+ }
23
+
24
+ export type HorizonTick = HorizonSample & { outcome: 'ok' | 'fail' };
25
+
26
+ export interface HorizonWatchOptions { db?: string; state?: string }
27
+ export interface HorizonWatchDeps {
28
+ openStore?: (path: string) => Pick<LogStore, 'horizon' | 'queryAll' | 'close'>;
29
+ now?: () => number;
30
+ stateDir?: string;
31
+ }
32
+
33
+ function lastReadableSample(path: string): HorizonSample | null {
34
+ let content = '';
35
+ try { content = readFileSync(path, 'utf8'); }
36
+ catch (error) {
37
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
38
+ }
39
+ for (const line of content.trimEnd().split('\n').reverse()) {
40
+ if (!line) continue;
41
+ const sample = JSON.parse(line) as HorizonSample;
42
+ if (sample.status !== 'unreadable') return sample;
43
+ }
44
+ try { return JSON.parse(readFileSync(join(dirname(path), 'last-readable.json'), 'utf8')) as HorizonSample; }
45
+ catch (error) {
46
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null;
47
+ throw error;
48
+ }
49
+ }
50
+
51
+ function saveReadableCheckpoint(path: string, sample: HorizonSample): void {
52
+ const checkpoint = join(dirname(path), 'last-readable.json');
53
+ mkdirSync(dirname(path), { recursive: true });
54
+ const temporary = `${checkpoint}.${process.pid}.${randomUUID()}.tmp`;
55
+ try {
56
+ writeFileSync(temporary, JSON.stringify(sample) + '\n');
57
+ renameSync(temporary, checkpoint);
58
+ } finally { rmSync(temporary, { force: true }); }
59
+ }
60
+
61
+ function saveSample(path: string, sample: HorizonSample): void {
62
+ let lines: string[];
63
+ try { lines = readFileSync(path, 'utf8').trimEnd().split('\n').filter(Boolean); }
64
+ catch (error) {
65
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
66
+ lines = [];
67
+ }
68
+ mkdirSync(dirname(path), { recursive: true });
69
+ const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
70
+ try {
71
+ writeFileSync(temporary, [...lines.slice(-499), JSON.stringify(sample)].join('\n') + '\n');
72
+ renameSync(temporary, path);
73
+ } finally { rmSync(temporary, { force: true }); }
74
+ if (sample.status !== 'unreadable') saveReadableCheckpoint(path, sample);
75
+ }
76
+
77
+ /** Read the store only; samples live outside logs.db and observations go through debug sinks. */
78
+ export function runHorizonWatchTick(opts: HorizonWatchOptions = {}, deps: HorizonWatchDeps = {}): HorizonTick {
79
+ const path = join(deps.stateDir ?? opts.state ?? join(elanousStateRoot(), 'log-horizon'), 'samples.jsonl');
80
+ // Serialize the entire read/compare/append transaction across cron and manual processes.
81
+ // This lock database is in the sample state directory, never in logs.db.
82
+ mkdirSync(dirname(path), { recursive: true });
83
+ const lock = new Database(join(dirname(path), 'samples.lock.db'));
84
+ try {
85
+ lock.run('PRAGMA busy_timeout = 120000');
86
+ lock.run('BEGIN IMMEDIATE');
87
+ try {
88
+ return recordSample();
89
+ } finally {
90
+ lock.run('ROLLBACK');
91
+ }
92
+ } finally {
93
+ lock.close();
94
+ }
95
+
96
+ function recordSample(): HorizonTick {
97
+ const now = deps.now ?? Date.now;
98
+ // The tick clock is read *after* the horizon read (see below), so every `deleted` event logged before the
99
+ // horizon was observed has ts <= atMs. Windows are half-open (prev.atMs, atMs]: each event is counted once.
100
+ let atMs: number | undefined;
101
+ let oldestTsMs: number | null = null;
102
+ let status: HorizonStatus = 'unreadable';
103
+ let deletedEvents = 0;
104
+ let store: ReturnType<NonNullable<HorizonWatchDeps['openStore']>> | undefined;
105
+ let previous: HorizonSample | null = null;
106
+ try {
107
+ store = (deps.openStore ?? LogStore.openReadOnly)(opts.db ?? logsDbPath());
108
+ const horizon = store.horizon();
109
+ atMs = now();
110
+ status = horizon.status;
111
+ oldestTsMs = horizon.status === 'present' ? horizon.oldestTsMs : null;
112
+ previous = lastReadableSample(path);
113
+ if (previous) {
114
+ deletedEvents = store.queryAll({
115
+ exactCategories: ['log-store.retention'], events: ['deleted'], sinceMs: previous.atMs + 1, untilMs: atMs,
116
+ }).length;
117
+ }
118
+ } catch (error) {
119
+ debug.log('log-store.horizon', 'read-failed', { reason: String(error) }, { level: 'warn' });
120
+ status = 'unreadable';
121
+ oldestTsMs = null;
122
+ } finally { store?.close(); }
123
+ atMs ??= now();
124
+
125
+ const advancedMs = status === 'present' && previous?.status === 'present' && previous.oldestTsMs !== null
126
+ ? Math.max(0, oldestTsMs! - previous.oldestTsMs) : 0;
127
+ const attribution: Attribution = status === 'unreadable' ? 'none'
128
+ : !previous ? 'first-sample'
129
+ : advancedMs === 0 ? 'none'
130
+ : deletedEvents > 0 ? 'attributed' : 'unattributed-loss';
131
+ const sample: HorizonSample = {
132
+ atMs, oldestTsMs, status,
133
+ spanHours: oldestTsMs === null ? null : (atMs - oldestTsMs) / 3_600_000,
134
+ advancedMs, deletedEvents, attribution,
135
+ };
136
+ try { saveSample(path, sample); }
137
+ catch (error) {
138
+ debug.log('log-store.horizon', 'sample-write-failed', { reason: String(error) }, { level: 'warn' });
139
+ return { ...sample, outcome: 'fail' };
140
+ }
141
+ debug.log('log-store.horizon', 'sample', {
142
+ oldestTs: oldestTsMs === null ? null : new Date(oldestTsMs).toISOString(),
143
+ spanHours: sample.spanHours, advancedMs, deletedEvents, attribution,
144
+ }, { level: attribution === 'unattributed-loss' ? 'warn' : 'info' });
145
+ return { ...sample, outcome: status === 'unreadable' ? 'fail' : 'ok' };
146
+ }
147
+ }
148
+
149
+ if (import.meta.main) {
150
+ const args = process.argv.slice(2);
151
+ const opts: HorizonWatchOptions = {};
152
+ let json = false;
153
+ for (let i = 0; i < args.length; i++) {
154
+ const arg = args[i];
155
+ if (arg === '--json') json = true;
156
+ else if (arg === '--db' && args[i + 1]) opts.db = args[++i];
157
+ else if (arg === '--state' && args[i + 1]) opts.state = args[++i];
158
+ else { process.stderr.write(`Unknown or incomplete option: ${arg}\n`); process.exit(1); }
159
+ }
160
+ const sinkReady = await registerStandaloneLogSink('log-horizon');
161
+ // A sink failure must not suppress the sample: the store read (and an 'unreadable' record) still happens,
162
+ // but the tick cannot claim success because its observation never reached logs.db.
163
+ const tick = runHorizonWatchTick(opts);
164
+ const result = sinkReady ? tick : { ...tick, outcome: 'fail' as const, reason: 'log-sink-registration-failed' };
165
+ if (json) process.stdout.write(`${JSON.stringify(result)}\n`);
166
+ else process.stdout.write(`${result.outcome}: ${result.attribution} (${result.status})${sinkReady ? '' : ' · log-sink-registration-failed'}\n`);
167
+ if (result.outcome === 'fail') process.exitCode = 1;
168
+ }
@@ -17,7 +17,8 @@
17
17
  // severity 는 SCHEME(이벤트 접미사) → `level` 컬럼으로 물질화.
18
18
 
19
19
  import { Database } from 'bun:sqlite';
20
- import { mkdirSync } from 'node:fs';
20
+ import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmdirSync, rmSync, writeFileSync } from 'node:fs';
21
+ import { randomUUID } from 'node:crypto';
21
22
  import { elanousStateRoot } from '../../autopilot/state-paths.js';
22
23
  import { dirname, join } from 'node:path';
23
24
 
@@ -81,9 +82,13 @@ export interface LogStoreRetention {
81
82
  maxAgeDays: number;
82
83
  /** DB 상한(MB). 초과 시 오래된 행부터 삭제. 0 이하 = 크기 정리 안 함. 기본 500. */
83
84
  maxDbMb: number;
85
+ /** 🩸 LOGS-RETENTION-WINDOW-1(10-10): size-cap floor in hours — the size pass never deletes rows newer than
86
+ * this; when rows outside the floor are not enough it stops and logs `retention-floor-held`.
87
+ * 0 = legacy behaviour (oldest-first with no floor). Missing = 24. Age pass (`maxAgeDays`) is unaffected. */
88
+ minRetainHours?: number;
84
89
  }
85
90
 
86
- export const LOG_RETENTION_DEFAULTS: LogStoreRetention = { maxAgeDays: 7, maxDbMb: 500 };
91
+ export const LOG_RETENTION_DEFAULTS: LogStoreRetention = { maxAgeDays: 7, maxDbMb: 500, minRetainHours: 24 };
87
92
 
88
93
  /** 스토어 OOM 백스톱 — 정책 상한이 아니다. 정책은 각 경계(HTTP·툴)가 갖는다. */
89
94
  export const STORE_SAFETY_MAX = 100_000;
@@ -360,22 +365,65 @@ export class LogStore {
360
365
  }
361
366
  if (policy.maxDbMb > 0) {
362
367
  const pageCount = (this.db.query('PRAGMA page_count').get() as { page_count: number }).page_count;
368
+ const freePages = (this.db.query('PRAGMA freelist_count').get() as { freelist_count: number }).freelist_count;
363
369
  const pageSize = (this.db.query('PRAGMA page_size').get() as { page_size: number }).page_size;
364
- const sizeMb = (pageCount * pageSize) / (1024 * 1024);
370
+ // 🩸 OBS-RET-RATCHET(2026-10-09): 빈 페이지까지 세면 VACUUM 없는 파일은 안 줄어든다 → 뜰 때마다 오래된 행 ≈5% 를
371
+ // 또 지우는 래칫이 됐다(운영 logs.db 528MB · 01:08Z 이전 행 소실). 상한은 «쓰는 페이지»로 잰다.
372
+ const sizeMb = ((pageCount - freePages) * pageSize) / (1024 * 1024);
365
373
  if (sizeMb > policy.maxDbMb) {
366
374
  // 초과분 비율만큼 오래된 행 삭제(대략 — 정밀 계산보다 반복 수렴 선호).
367
375
  const total = (this.db.query('SELECT COUNT(*) AS c FROM logs').get() as { c: number }).c;
368
376
  const dropCount = Math.max(1, Math.floor(total * Math.min(0.5, 1 - policy.maxDbMb / sizeMb)));
369
- const r = this.db.run(
370
- 'DELETE FROM logs WHERE id IN (SELECT id FROM logs ORDER BY ts_ms ASC LIMIT ?)',
371
- [dropCount],
372
- );
373
- deletedBySize = Number(r.changes ?? 0);
377
+ // 🩸 LOGS-RETENTION-WINDOW-1(10-10): prod write volume made this pass keep only ≈2h of rows, so evidence
378
+ // for incidents a few hours old read as «0 rows». Rows inside the floor are never size-deleted.
379
+ const floorHours = policy.minRetainHours ?? LOG_RETENTION_DEFAULTS.minRetainHours ?? 0;
380
+ if (floorHours > 0) {
381
+ const floorCutoff = Date.now() - floorHours * 3_600_000;
382
+ // Byte-weighted split (payload text + fixed per-row overhead) — row counts alone misjudge mixed row sizes.
383
+ const split = this.db.query(
384
+ `SELECT COALESCE(SUM(CASE WHEN ts_ms < ? THEN w ELSE 0 END), 0) AS outsideBytes, COALESCE(SUM(w), 0) AS allBytes
385
+ FROM (SELECT ts_ms, 64 + LENGTH(ts) + LENGTH(category) + LENGTH(event) + COALESCE(LENGTH(data), 0) AS w FROM logs)`,
386
+ ).get(floorCutoff) as { outsideBytes: number; allBytes: number };
387
+ const r = this.db.run(
388
+ 'DELETE FROM logs WHERE id IN (SELECT id FROM logs WHERE ts_ms < ? ORDER BY ts_ms ASC LIMIT ?)',
389
+ [floorCutoff, dropCount],
390
+ );
391
+ deletedBySize = Number(r.changes ?? 0);
392
+ // dropCount is capped at 50% per run; judge the floor against the full overshoot (by bytes) so a cap the
393
+ // floor can never reach is reported even when this run's capped batch was fully served from outside rows.
394
+ const neededShare = 1 - policy.maxDbMb / sizeMb;
395
+ const outsideShare = split.allBytes > 0 ? split.outsideBytes / split.allBytes : 0;
396
+ if (outsideShare < neededShare) {
397
+ debug.log('mss.logging', 'retention-floor-held', {
398
+ totalMb: Math.round(sizeMb * 10) / 10, maxTotalMb: policy.maxDbMb, floorHours,
399
+ neededShare: Math.round(neededShare * 1000) / 1000, outsideShare: Math.round(outsideShare * 1000) / 1000,
400
+ deletedRows: deletedBySize,
401
+ });
402
+ }
403
+ } else {
404
+ const r = this.db.run(
405
+ 'DELETE FROM logs WHERE id IN (SELECT id FROM logs ORDER BY ts_ms ASC LIMIT ?)',
406
+ [dropCount],
407
+ );
408
+ deletedBySize = Number(r.changes ?? 0);
409
+ }
374
410
  }
375
411
  }
412
+ if (deletedByAge > 0 || deletedBySize > 0) {
413
+ const oldest = (this.db.query('SELECT MIN(ts_ms) AS t FROM logs').get() as { t: number | null }).t;
414
+ debug.log('log-store.retention', 'deleted', { deletedByAge, deletedBySize, oldestTs: oldest === null ? null : new Date(oldest).toISOString() });
415
+ }
376
416
  return { deletedByAge, deletedBySize };
377
417
  }
378
418
 
419
+ /** Reclaim a bounded number of free pages after retention; legacy databases with auto_vacuum=NONE remain unchanged. */
420
+ reclaimFreePages(): void {
421
+ const mode = (this.db.query('PRAGMA auto_vacuum').get() as { auto_vacuum: number }).auto_vacuum;
422
+ if (mode !== 2) return;
423
+ const free = (this.db.query('PRAGMA freelist_count').get() as { freelist_count: number }).freelist_count;
424
+ if (free > 0) this.db.run(`PRAGMA incremental_vacuum(${Math.min(free, 128)})`);
425
+ }
426
+
379
427
  /**
380
428
  * ⛔⭐⭐⭐ **이 스토어에 «실제로 뜬» 카테고리와 그 수**(2026-08-19 · `OBS-T122`).
381
429
  *
@@ -658,6 +706,12 @@ export class LogStore {
658
706
  return (this.db.query('SELECT COUNT(*) AS c FROM logs').get() as { c: number }).c;
659
707
  }
660
708
 
709
+ /** Earliest retained event timestamp, regardless of insertion order. No schema or row writes. */
710
+ horizon(): { status: 'present'; oldestTsMs: number } | { status: 'empty' } {
711
+ const { oldestTsMs } = this.db.query('SELECT MIN(ts_ms) AS oldestTsMs FROM logs').get() as { oldestTsMs: number | null };
712
+ return oldestTsMs === null ? { status: 'empty' } : { status: 'present', oldestTsMs };
713
+ }
714
+
661
715
  close(): void {
662
716
  try { this.db.close(); } catch { /* noop */ }
663
717
  }
@@ -850,28 +904,163 @@ export class StoreSink implements LogSink {
850
904
  }
851
905
  }
852
906
 
907
+ const RETENTION_INTERVAL_MS = 6 * 3600 * 1000;
908
+ type RetentionLockOwner = { token: string; pid: number; start: string | null };
909
+
910
+ /** PID reuse must not let a new process inherit a dead process's ownership. */
911
+ function processStart(pid: number): string | null {
912
+ try {
913
+ const stat = readFileSync(`/proc/${pid}/stat`, 'utf8');
914
+ return stat.slice(stat.lastIndexOf(')') + 2).split(' ')[19] ?? null;
915
+ } catch { return null; }
916
+ }
917
+
918
+ function ownerDead(owner: RetentionLockOwner): boolean {
919
+ if (!Number.isSafeInteger(owner.pid) || owner.pid <= 0) return false;
920
+ try {
921
+ process.kill(owner.pid, 0);
922
+ const currentStart = processStart(owner.pid);
923
+ if (owner.start !== null && currentStart !== null && owner.start !== currentStart) return true;
924
+ // A zombie still answers kill(pid, 0), but can no longer run retention.
925
+ try {
926
+ const stat = readFileSync(`/proc/${owner.pid}/stat`, 'utf8');
927
+ return stat.slice(stat.lastIndexOf(')') + 2).startsWith('Z ');
928
+ } catch { return false; }
929
+ } catch (error) {
930
+ return (error as NodeJS.ErrnoException).code === 'ESRCH';
931
+ }
932
+ }
933
+
934
+ /** Only the guard row can authorize removal. A pre-publication temp file belongs to its row's token. */
935
+ function removeRetentionLockDirectory(lockPath: string, token: string, interrupted: boolean): void {
936
+ if (!existsSync(lockPath)) return;
937
+ const marker = join(lockPath, 'owner');
938
+ const temporaryName = `owner.${token}.tmp`;
939
+ if (readdirSync(lockPath).some((name) => name !== 'owner' && name !== temporaryName)) {
940
+ throw new Error('retention lock has unknown entries');
941
+ }
942
+ if (existsSync(marker)) {
943
+ const published = readFileSync(marker, 'utf8');
944
+ if (published !== token && !(interrupted && token.startsWith(published))) {
945
+ throw new Error('retention lock owner changed');
946
+ }
947
+ rmSync(marker);
948
+ }
949
+ rmSync(join(lockPath, temporaryName), { force: true });
950
+ rmdirSync(lockPath);
951
+ }
952
+
953
+ /** The SQLite guard serializes stale-lock recovery and ownership changes, including process death mid-acquisition. */
954
+ function acquireRetentionLock(lockPath: string): (() => void) | null {
955
+ const guard = new Database(`${lockPath}.db`);
956
+ const token = randomUUID();
957
+ let handedOff = false;
958
+ try {
959
+ guard.run('PRAGMA busy_timeout = 100');
960
+ guard.run('CREATE TABLE IF NOT EXISTS owner (slot INTEGER PRIMARY KEY CHECK(slot = 1), token TEXT NOT NULL, pid INTEGER NOT NULL, start TEXT)');
961
+ let acquired = false;
962
+ guard.run('BEGIN IMMEDIATE');
963
+ try {
964
+ const previous = guard.query('SELECT token, pid, start FROM owner WHERE slot = 1').get() as RetentionLockOwner | null;
965
+ if (previous && !ownerDead(previous)) return null;
966
+ if (existsSync(lockPath)) {
967
+ // A pre-guard lock has no provable owner: never remove it.
968
+ if (!previous) return null;
969
+ try { removeRetentionLockDirectory(lockPath, previous.token, true); }
970
+ catch { return null; }
971
+ }
972
+ guard.run('INSERT OR REPLACE INTO owner (slot, token, pid, start) VALUES (1, ?, ?, ?)', [token, process.pid, processStart(process.pid)]);
973
+ guard.run('COMMIT');
974
+ acquired = true;
975
+ } finally {
976
+ if (!acquired) guard.run('ROLLBACK');
977
+ }
978
+ // The ownership row is committed before mkdir: a crash in this gap is recoverable too.
979
+ try {
980
+ mkdirSync(lockPath);
981
+ const temporary = join(lockPath, `owner.${token}.tmp`);
982
+ writeFileSync(temporary, token, { flag: 'wx' });
983
+ renameSync(temporary, join(lockPath, 'owner'));
984
+ } catch (error) {
985
+ guard.run('BEGIN IMMEDIATE');
986
+ try {
987
+ // Keep the ownership row if cleanup fails: the next process can then
988
+ // prove who left the directory behind and recover it after this PID dies.
989
+ removeRetentionLockDirectory(lockPath, token, true);
990
+ guard.run('DELETE FROM owner WHERE slot = 1 AND token = ?', [token]);
991
+ guard.run('COMMIT');
992
+ } catch { guard.run('ROLLBACK'); }
993
+ throw error;
994
+ }
995
+ handedOff = true;
996
+ return () => {
997
+ try {
998
+ guard.run('BEGIN IMMEDIATE');
999
+ try {
1000
+ const current = guard.query('SELECT token FROM owner WHERE slot = 1').get() as { token: string } | null;
1001
+ if (current?.token === token) {
1002
+ removeRetentionLockDirectory(lockPath, token, false);
1003
+ guard.run('DELETE FROM owner WHERE slot = 1 AND token = ?', [token]);
1004
+ }
1005
+ guard.run('COMMIT');
1006
+ } catch (error) { guard.run('ROLLBACK'); throw error; }
1007
+ } finally { guard.close(); }
1008
+ };
1009
+ } finally { if (!handedOff) guard.close(); }
1010
+ }
1011
+
1012
+ /** A shared stamp prevents short-lived non-owner processes from repeatedly pruning the same DB. */
1013
+ function runStampedRetention(store: LogStore, retention: LogStoreRetention, owner: boolean): void {
1014
+ const stampPath = `${store.path}.retention.stamp`;
1015
+ const lockPath = `${store.path}.retention.lock`;
1016
+ const isFresh = (): boolean => {
1017
+ try {
1018
+ const age = Date.now() - Number(readFileSync(stampPath, 'utf8'));
1019
+ return age >= 0 && age < RETENTION_INTERVAL_MS;
1020
+ } catch { return false; }
1021
+ };
1022
+ if (!owner && isFresh()) return;
1023
+ const release = acquireRetentionLock(lockPath);
1024
+ if (!release) return;
1025
+ try {
1026
+ if (!owner && isFresh()) return;
1027
+ store.enforceRetention(retention);
1028
+ try { store.reclaimFreePages(); }
1029
+ catch (error) { debug.log('log-store.retention', 'reclaim-failed', { reason: error instanceof Error ? error.message : String(error) }); }
1030
+ const temporary = `${stampPath}.${process.pid}.${randomUUID()}.tmp`;
1031
+ try {
1032
+ writeFileSync(temporary, String(Date.now()));
1033
+ renameSync(temporary, stampPath);
1034
+ } finally { rmSync(temporary, { force: true }); }
1035
+ } finally { release(); }
1036
+ }
1037
+
853
1038
  /** 부팅 1줄 등록 헬퍼 — 데몬/TUI/러너가 자기 surface 를 선언하고 스토어
854
1039
  * 싱크를 단다. retention 은 호출측이 config 에서 읽어 전달(user-config
855
- * 순환 의존 회피). 반환 = unregister(테스트용) 또는 null(store 불가). */
1040
+ * 순환 의존 회피). 반환 = unregister(테스트용) 또는 null(store 불가).
1041
+ * nexus owns the periodic job unless the caller explicitly opts in. */
856
1042
  export function registerLogStoreSink(
857
1043
  registerSink: (sink: LogSink) => () => void,
858
1044
  surface: string,
859
1045
  retention: LogStoreRetention = LOG_RETENTION_DEFAULTS,
1046
+ opts: { retentionOwner?: boolean } = {},
860
1047
  ): (() => void) | null {
861
1048
  const store = getDefaultLogStore();
862
1049
  if (!store) return null;
863
1050
  const sink = new StoreSink(store, surface, { installExitHandlers: true });
864
1051
  const off = registerSink(sink);
865
1052
  try { nestDepth.observeNestAtBoot(); } catch { /* fail-soft — 관측 실패가 싱크 등록을 막지 않는다. */ }
866
- // 보존정책 — 부팅 직후 1회(디퍼) + 6시간 주기. 실패는 조용히.
1053
+ const owner = opts.retentionOwner ?? surface === 'nexus';
867
1054
  const runRetention = (): void => {
868
- try { store.enforceRetention(retention); } catch { /* fail-soft */ }
1055
+ try { runStampedRetention(store, retention, owner); }
1056
+ catch (error) { debug.log('log-store.retention', 'failed', { reason: error instanceof Error ? error.message : String(error) }); }
869
1057
  };
870
- setImmediate(runRetention);
871
- const h = setInterval(runRetention, 6 * 3600 * 1000);
872
- (h as unknown as { unref?: () => void }).unref?.();
1058
+ const startup = setImmediate(runRetention);
1059
+ const h = owner ? setInterval(runRetention, RETENTION_INTERVAL_MS) : null;
1060
+ (h as unknown as { unref?: () => void } | null)?.unref?.();
873
1061
  return () => {
874
- clearInterval(h);
1062
+ clearImmediate(startup);
1063
+ if (h) clearInterval(h);
875
1064
  sink.close();
876
1065
  off();
877
1066
  };
@@ -93,3 +93,20 @@ export function redactLogRecord(rec: LogRecord, opts: RedactOpts = {}): LogRecor
93
93
  const mask = opts.mask ?? defaultMask;
94
94
  return { ...rec, data: redactValue(rec.data, keyBlock, mask, new WeakSet()) };
95
95
  }
96
+
97
+ /** Pre-bundle knowledge-pack DLP. Reasons are fixed labels, never source text or secret values.
98
+ * This is separate from the opt-in log masking path above. */
99
+ const KNOWLEDGE_PACK_DLP_RULES: ReadonlyArray<{ reason: string; pattern: RegExp }> = [
100
+ { reason: 'secret-value', pattern: /-----BEGIN (?:[A-Z0-9_-]+ )?PRIVATE KEY(?: BLOCK)?-----|\bBearer\s+[A-Za-z0-9._~+/-]{12,}={0,2}\b|\b(?:sk-[A-Za-z0-9_-]{16,}|xai-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,}|xox[baprs]-[A-Za-z0-9-]{12,}|(?:AKIA|ASIA|ABIA|ACCA)[A-Z2-7]{16}|AIza[A-Za-z0-9_-]{35})\b|\b(?:api[_-]?key|secret[_-]?key|access[_-]?token|private[_-]?key|token)['"]?\s*[=:]\s*['"]?[A-Za-z0-9_./+~-]{16,}/iu },
101
+ // A key that names a password/secret makes ANY assigned value secret: short or punctuated values count too.
102
+ // Schema flags (`"secret": true`) are not values.
103
+ { reason: 'secret-value', pattern: /\b(?:password|passwd|pwd|passphrase|client[_-]?secret|secret)['"]?\s*[=:]\s*(?!(?:true|false|null)\b)(?:"[^"\n]+"|'[^'\n]+'|[^\s'",;{}\[\]]{4,})/iu },
104
+ { reason: 'personal-information', pattern: /\b01[016789]-?\d{3,4}-?\d{4}\b|\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b|\b\d{6}-[1-8]\d{6}\b/iu },
105
+ { reason: 'internal-identifier', pattern: /(?:사번|사내\s*식별자|내부\s*식별자|employee[_ -]?id|internal[_ -]?id)\s*(?:[:=]|\s)\s*[A-Za-z0-9][A-Za-z0-9_-]{3,}/iu },
106
+ { reason: 'sales-confidential', pattern: /영업\s*기밀|(?:sales\s+confidential|confidential\s+sales|영업\s*비밀)/iu },
107
+ ];
108
+
109
+ export function scanKnowledgePackDlp(text: string): string[] {
110
+ const reasons = KNOWLEDGE_PACK_DLP_RULES.filter(({ pattern }) => pattern.test(text)).map(({ reason }) => reason);
111
+ return [...new Set(reasons)];
112
+ }
@@ -9,7 +9,7 @@ import type { VerifierSpec } from './verifier/types.js';
9
9
  import type { GuardianSpec } from './guardian/types.js';
10
10
  import { ptyAvailable } from './pty-shell/registry.js';
11
11
  import { krFlowAvailable } from './skills/tools/kr-flow.js';
12
- import { SELF_COGNITION_MCP_CATALOG_ENTRIES } from './tool-runtime/self-cognition-runtimes.js';
12
+ import { SELF_COGNITION_MCP_CATALOG_ENTRIES } from './tool-runtime/self-cognition-catalog.js';
13
13
  import { SKILLS_LIST_DESCRIPTION } from './onboarding/entry-hints.js';
14
14
 
15
15
  export type { NativeToolHost } from './tool-surface.js';
@@ -2,7 +2,7 @@ import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, re
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { dirname, join } from 'node:path';
4
4
  import { debug } from '../../debug/log.js';
5
- import { routeOutbound } from '../outbound/router.js';
5
+ import { sendTelegramReport } from '../../telegram-report.js';
6
6
  import { getUserConfig } from '../../user-config.js';
7
7
  import { effectiveInstanceRoot } from '../../instance/resolve.js';
8
8
  import { jsonResponse } from './json-response.js';
@@ -23,7 +23,7 @@ interface ConsultRequest {
23
23
  export interface ConsultRequestsDeps {
24
24
  root?: () => string;
25
25
  now?: () => string;
26
- /** Owner alert. Default = the daemon's own in-process router (the same one `/v1/outbound` uses).
26
+ /** Owner alert. Default = the daemon's in-process Telegram sender (operations role only).
27
27
  * ⛔ Never `sendOutbound` here: it is a synchronous curl to this very daemon's `/v1/outbound`, so inside the
28
28
  * daemon it blocks the event loop until it times out (~25 s · `unreachable`) and the alert is lost (CS1 · 10-01). */
29
29
  send?: (text: string, kind: string) => unknown;
@@ -88,9 +88,9 @@ export async function handleConsultRequests(req: Request, deps: ConsultRequestsD
88
88
  if (!body || typeof body !== 'object' || Array.isArray(body)) return rejected('body');
89
89
  const input = body as Record<string, unknown>;
90
90
  for (const field of ['name', 'contact'] as const) {
91
- if (typeof input[field] !== 'string' || !input[field].trim()) return rejected(field);
91
+ if (typeof input[field] !== 'string' || !input[field].trim() || input[field].length > (field === 'name' ? 256 : 512)) return rejected(field);
92
92
  }
93
- if (input.org !== undefined && (typeof input.org !== 'string' || !input.org.trim())) return rejected('org');
93
+ if (input.org !== undefined && (typeof input.org !== 'string' || !input.org.trim() || input.org.length > 256)) return rejected('org');
94
94
  if (input.kind !== 'company' && input.kind !== 'personal') return rejected('kind');
95
95
  if (input.interest !== 'A' && input.interest !== 'B') return rejected('interest');
96
96
  if (input.consent !== true) return rejected('consent');
@@ -114,15 +114,12 @@ export async function handleConsultRequests(req: Request, deps: ConsultRequestsD
114
114
  const alert = `📮 상담 문의 ${entry.receiptId} · ${entry.name}(${entry.kind === 'personal' ? '개인' : (entry.org ?? '회사')}) · 관심 ${entry.interest}\n앱에서 보기`;
115
115
  // Fire and forget — the receipt is already on disk; the answer must not wait for the channel.
116
116
  void Promise.resolve()
117
- .then(() => (deps.send ?? notifyInProcess)(alert, 'alert'))
117
+ .then(() => (deps.send ?? notifyInProcess)(alert, 'ops-alert'))
118
118
  .catch((error: unknown) => { debug.log('consult.request', 'notify-failed', { receiptId: entry.receiptId, reason: error instanceof Error ? error.message : String(error) }); });
119
119
  return jsonResponse({ receiptId: entry.receiptId, receivedAt: entry.receivedAt }, 202);
120
120
  }
121
121
 
122
122
  async function notifyInProcess(text: string, kind: string): Promise<void> {
123
- const result = await routeOutbound(getUserConfig(), { text, markdown: false, kind });
124
- debug.log('consult.request', result.delivered ? 'notified' : 'notify-failed', {
125
- delivered: result.delivered,
126
- channels: result.channels.map((channel) => `${channel.type}:${channel.ok ? 'ok' : 'fail'}`),
127
- });
123
+ const delivered = await sendTelegramReport(getUserConfig(), text, { markdown: false, kind });
124
+ debug.log('consult.request', delivered ? 'notified' : 'notify-failed', { delivered, channels: [`telegram:${delivered ? 'ok' : 'fail'}`] });
128
125
  }
@@ -36,6 +36,7 @@ import { parseDiscordEndpoint, isOwnInstanceEndpoint } from '../../session/sessi
36
36
  import { createDiscordStreamSink } from '../../session/streaming/discord-stream-sink.js';
37
37
  import { splitForDiscord } from '../../discord.js';
38
38
  import { formatForDiscord } from '../../discord-markdown.js';
39
+ import { receiveChannelEvent } from '../outbound/router.js';
39
40
 
40
41
  export interface NexusDiscordTriggerBotOpts {
41
42
  /** Bot token (without `Bot ` prefix). Production reads
@@ -109,11 +110,13 @@ export function createDiscordTriggerLogger(
109
110
  * (`src/discord.ts:160-172` comment) so the wire is a near-identity
110
111
  * with `raw` carrying the full gateway payload for debugging. */
111
112
  export function toDiscordEvent(tap: DcTriggerEvent): DiscordEvent {
113
+ const envelope = receiveChannelEvent('discord', tap);
114
+ if (!envelope || envelope instanceof Promise) throw new Error('discord connector cannot normalize accepted tap');
112
115
  return {
113
116
  kind: tap.kind,
114
- channel: tap.channel,
115
- user: tap.user,
116
- body: tap.body,
117
+ channel: envelope.channel ?? tap.channel,
118
+ user: envelope.senderId ?? tap.user,
119
+ body: envelope.text,
117
120
  raw: tap,
118
121
  };
119
122
  }
@@ -1,6 +1,8 @@
1
1
  import { join } from 'node:path';
2
2
  import { debug } from '../../debug/log.js';
3
- import type { DraftMetrics } from '../../self-dev/draft-sweep.js';
3
+ import type { DraftMetrics, OverlapMetrics } from '../../self-dev/draft-sweep.js';
4
+
5
+ export type CeoDraftMetrics = DraftMetrics & { readonly overlap: OverlapMetrics | null };
4
6
 
5
7
  /**
6
8
  * DRAFT-METRIC — CEO view source. Opening the page must never trigger a GitHub read:
@@ -14,7 +16,7 @@ export type DraftMetricsState = 'measuring' | 'ready' | 'unavailable';
14
16
  export interface DraftMetricsSnapshot {
15
17
  /** measuring = no value yet and a collection is running · unavailable = no value and the last collection failed. */
16
18
  readonly state: DraftMetricsState;
17
- readonly metrics: DraftMetrics | null;
19
+ readonly metrics: CeoDraftMetrics | null;
18
20
  /** When the served value was collected (ISO). null without a value. */
19
21
  readonly measuredAt: string | null;
20
22
  /** A background collection is in flight. */
@@ -24,7 +26,7 @@ export interface DraftMetricsSnapshot {
24
26
  }
25
27
 
26
28
  export interface DraftMetricsSourceOptions {
27
- readonly collect?: () => Promise<DraftMetrics>;
29
+ readonly collect?: () => Promise<CeoDraftMetrics>;
28
30
  readonly ttlMs?: number;
29
31
  readonly failureRetryMs?: number;
30
32
  readonly now?: () => number;
@@ -43,17 +45,29 @@ function isMetrics(value: unknown): value is DraftMetrics {
43
45
  && nullableNumber('oldestAgeHours') && nullableNumber('conversion48h');
44
46
  }
45
47
 
46
- /** Parses the CLI's single JSON line; anything else is a failed collection, never a zero. */
47
- export function parseDraftMetricsOutput(stdout: string): DraftMetrics {
48
+ function isOverlapMetrics(value: unknown): value is OverlapMetrics {
49
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
50
+ const row = value as Record<string, unknown>;
51
+ const count = (key: string) => row[key] === null || (Number.isInteger(row[key]) && (row[key] as number) >= 0);
52
+ const nullableNumber = (key: string) => row[key] === null || (typeof row[key] === 'number' && Number.isFinite(row[key]) && (row[key] as number) >= 0);
53
+ return ['launches24h', 'launched', 'unmeasured', 'linked', 'autoLanded', 'salvaged', 'salvageUnmeasured'].every(count)
54
+ && typeof row.sourceIncomplete === 'boolean' && nullableNumber('secondSiblingMedianHours')
55
+ && (row.autoRate === null || (typeof row.autoRate === 'number' && Number.isFinite(row.autoRate) && row.autoRate >= 0 && row.autoRate <= 1));
56
+ }
57
+
58
+ /** Parses the CLI's single JSON line; malformed draft values fail, malformed overlap is unmeasured. */
59
+ export function parseDraftMetricsOutput(stdout: string): CeoDraftMetrics {
48
60
  const line = stdout.trim().split('\n').reverse().find((text) => text.trim().startsWith('{'));
49
61
  if (!line) throw new Error('draft metrics: no JSON output');
50
62
  const parsed: unknown = JSON.parse(line);
51
63
  if (!isMetrics(parsed)) throw new Error('draft metrics: malformed output');
52
64
  const { inventory, oldestAgeHours, needsOwner, converted48h, cohort48h, conversion48h } = parsed;
53
- return { inventory, oldestAgeHours, needsOwner, converted48h, cohort48h, conversion48h };
65
+ const candidate = (parsed as DraftMetrics & { overlap?: unknown }).overlap;
66
+ return { inventory, oldestAgeHours, needsOwner, converted48h, cohort48h, conversion48h,
67
+ overlap: isOverlapMetrics(candidate) ? candidate : null };
54
68
  }
55
69
 
56
- async function collectViaCli(): Promise<DraftMetrics> {
70
+ async function collectViaCli(): Promise<CeoDraftMetrics> {
57
71
  const root = join(import.meta.dir, '../../..');
58
72
  const proc = Bun.spawn(['bun', join(root, 'bin/elanous.mjs'), 'harness', 'drafts', 'metrics', '--json'], {
59
73
  cwd: root, stdout: 'pipe', stderr: 'pipe',
@@ -75,7 +89,7 @@ export function createDraftMetricsSource(options: DraftMetricsSourceOptions = {}
75
89
  const ttl = options.ttlMs ?? DRAFT_METRICS_TTL_MS;
76
90
  const retry = options.failureRetryMs ?? DRAFT_METRICS_FAILURE_RETRY_MS;
77
91
  const now = options.now ?? Date.now;
78
- let value: { metrics: DraftMetrics; at: number } | null = null;
92
+ let value: { metrics: CeoDraftMetrics; at: number } | null = null;
79
93
  let failure: { reason: string; at: number } | null = null;
80
94
  let inFlight: Promise<void> | null = null;
81
95