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
@@ -6,7 +6,7 @@
6
6
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
7
7
  import { join } from 'path';
8
8
  import { fileURLToPath } from 'node:url';
9
- import { createStaleInstallCheck, readCurrentInstalledCommit, readDashboardBootCommit, STALE_INSTALL_CHECK_INTERVAL_MS, versionedDashboardInstallDir } from './stale-install-check.js';
9
+ import { createStaleInstallCheck, formatStaleInstallNotice, readCurrentInstalledCommit, readDashboardBootCommit, STALE_INSTALL_CHECK_INTERVAL_MS, versionedDashboardInstallDir } from './stale-install-check.js';
10
10
  import { spawn, spawnSync } from 'node:child_process';
11
11
  import { $ } from 'bun';
12
12
  import { LOCAL_SKILLS_DIR, SERVICE_NAMES, DATA_DIR, OBSIDIAN_VAULT } from '../config.js';
@@ -896,7 +896,7 @@ import { inspectActiveProvider } from '../provider-summary.js';
896
896
  import { activeCodexAccountView } from '../oauth/codex-account-store.js';
897
897
  import { buildDashboardStatusLines } from './dashboard-status-lines.js';
898
898
  import { readSlashContextNow, seatsNowLine } from '../context-bus/context-now-surfaces.js';
899
- import { buildFirstScreenBand } from './first-screen-band.js';
899
+ import { buildFirstScreenBand, resolveTuiDaemonLink, type TuiDaemonLink } from './first-screen-band.js';
900
900
  import { runNexusShow, type NexusShowResult } from '../cli/nexus-show.js';
901
901
  import {
902
902
  workingDirSegment, sessionCwdSegment, modelSegment, gitSegment,
@@ -2128,15 +2128,22 @@ export function renderDashboardFirstScreenBand(input: {
2128
2128
  readonly draw: () => void;
2129
2129
  readonly observe: (data: { daemon: boolean; hasPwa: boolean; hasTailnet: boolean }) => void;
2130
2130
  readonly show?: () => Promise<Pick<NexusShowResult, 'status' | 'urls'>>;
2131
+ readonly daemonLink?: () => Promise<TuiDaemonLink>;
2131
2132
  }): Promise<void> {
2132
2133
  if (input.history.some((message) => message.role !== 'system')) return Promise.resolve();
2133
- const band = buildFirstScreenBand({ width: input.width, daemon: false });
2134
+ const band = buildFirstScreenBand({ width: input.width, daemon: false, link: { status: 'checking' } });
2134
2135
  input.lines.unshift(...band);
2136
+ const daemonLink = input.daemonLink ?? resolveTuiDaemonLink;
2137
+ const linkPending = Promise.resolve().then(() => daemonLink()).catch((): TuiDaemonLink => ({ status: 'error', stage: 'health' })).then((link) => {
2138
+ if (input.lines[0] !== band[0]) return;
2139
+ input.lines[0] = buildFirstScreenBand({ width: input.width, daemon: false, link })[0]!;
2140
+ try { input.draw(); } catch { /* screen may have closed */ }
2141
+ });
2135
2142
  const show = input.show ?? (() => runNexusShow({ format: 'json', out: { log: () => {}, error: () => {} } }));
2136
2143
  const observe = (data: { daemon: boolean; hasPwa: boolean; hasTailnet: boolean }): void => {
2137
2144
  try { input.observe(data); } catch { /* observation cannot interrupt the transcript */ }
2138
2145
  };
2139
- return Promise.resolve().then(show).then((result) => {
2146
+ const pwaPending = Promise.resolve().then(show).then((result) => {
2140
2147
  const daemon = result.status !== 'absent';
2141
2148
  const pwa = result.urls?.pwa;
2142
2149
  const hasPwa = !!pwa;
@@ -2148,6 +2155,7 @@ export function renderDashboardFirstScreenBand(input: {
2148
2155
  }).catch(() => {
2149
2156
  observe({ daemon: false, hasPwa: false, hasTailnet: false });
2150
2157
  });
2158
+ return Promise.all([linkPending, pwaPending]).then(() => {});
2151
2159
  }
2152
2160
 
2153
2161
  export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<DashboardAction> {
@@ -4361,13 +4369,27 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
4361
4369
  now: Date.now,
4362
4370
  });
4363
4371
  if (versionDir) {
4372
+ let staleNoticeIndex = -1;
4373
+ let staleNoticeLine: string | undefined;
4374
+ let staleNoticeCount = 0;
4364
4375
  const checkInstall = (): void => {
4365
4376
  const result = staleInstallCheck.check();
4366
4377
  debug.log('dashboard.version', 'install-check', {
4367
4378
  state: result.state, bootCommit: result.bootCommit, installedCommit: result.installedCommit,
4368
4379
  });
4369
4380
  if (staleInstallCheck.shouldNotify(result)) {
4370
- chatLines.push(C.warning(`elanous 가 새 판으로 바뀌었다 (${result.bootCommit!.slice(0, 7)} → ${result.installedCommit!.slice(0, 7)}) · TUI 를 다시 띄워라`));
4381
+ staleNoticeCount++;
4382
+ const notice = C.warning(formatStaleInstallNotice(result, staleNoticeCount));
4383
+ if (chatLines[staleNoticeIndex] !== staleNoticeLine || staleNoticeLine === undefined) {
4384
+ staleNoticeIndex = staleNoticeLine === undefined ? -1 : chatLines.indexOf(staleNoticeLine);
4385
+ }
4386
+ if (staleNoticeIndex < 0) {
4387
+ chatLines.push(notice);
4388
+ staleNoticeIndex = chatLines.length - 1;
4389
+ } else {
4390
+ chatLines[staleNoticeIndex] = notice;
4391
+ }
4392
+ staleNoticeLine = notice;
4371
4393
  chatScrollOffset = -1;
4372
4394
  try { draw(); } catch { /* TUI torn down */ }
4373
4395
  }
@@ -343,7 +343,7 @@ import { terminalModalRouter } from '../input/terminal-modal-router.js';
343
343
  import { termSize, stripAnsi } from '../../tui.js';
344
344
  import { SLASH_COMMANDS } from '../../chat/index.js';
345
345
  import { buildEssentialHelpLines } from './help-from-registry.js';
346
- import { HUMAN_MODEL_WORDS, MODEL_CODE_NAMES, modelChangeLine, modelOverviewLines, resolveModelChoice } from './model-choices.js';
346
+ import { HUMAN_MODEL_WORDS, MODEL_CODE_NAMES, humanWordForModel, modelChangeLine, modelOverviewLines, resolveModelChoice } from './model-choices.js';
347
347
  import type { FoldMode } from '../../log-entry.js';
348
348
  import { resolveDashboardChatMainLogCommand } from '../input/chat-main-log-command.js';
349
349
  import {
@@ -395,6 +395,8 @@ import { dispatchTerminalModalObserve } from '../../skills/tools/terminal-modal.
395
395
  import { SlashCommandRegistry } from './registry.js';
396
396
  import { cronSecondDueAt, filterLoopRows, formatLoopsTable, localLoopRows, type LoopsTableRow } from './loops-table.js';
397
397
  import { loopCronVerdict } from '../../loops/verdict.js';
398
+ import { checklistBoardSlash } from '../../release-loop/checklist-board.js';
399
+ import type { Checklist } from '../../release-loop/checklist.js';
398
400
  import { executeImmediateDashboardSlash } from '../input/slash-executor.js';
399
401
  import {
400
402
  buildContextSlashCommand,
@@ -1046,6 +1048,8 @@ export interface DashboardSlashContext {
1046
1048
 
1047
1049
  /** Test seam for the local read-only loop and cron registry. */
1048
1050
  loopsLocalRows?: (now: Date) => LoopsTableRow[];
1051
+ /** Test seam for the read-only release checklist. */
1052
+ checklistRead?: (version: string) => Checklist;
1049
1053
 
1050
1054
  sessionSlash: {
1051
1055
  /** opts.remote — when the dashboard is attached to a remote daemon. */
@@ -1467,6 +1471,11 @@ export function buildDashboardSlashRegistry(nowDeps?: ContextNowDeps, decideLedg
1467
1471
  ctx.setChatScrollOffset(-1);
1468
1472
  });
1469
1473
 
1474
+ registry.register('board', (args, ctx) => {
1475
+ for (const line of checklistBoardSlash(args, ctx.checklistRead).split('\n')) ctx.pushChatLine(line);
1476
+ ctx.setChatScrollOffset(-1);
1477
+ });
1478
+
1470
1479
  registry.register('wish', (args, ctx) => {
1471
1480
  const text = args.join(' ').trim();
1472
1481
  if (!text) {
@@ -6188,8 +6197,10 @@ export function buildDashboardSlashRegistry(nowDeps?: ContextNowDeps, decideLedg
6188
6197
  const curModel = curCfg.llm.model;
6189
6198
  const curReasoning = effectiveReasoningLevel(curCfg.llm, curProvider, curModel);
6190
6199
  if (!arg) {
6191
- const [now, codes] = modelOverviewLines(curProvider, curModel, curReasoning);
6192
- ctx.chatLines.push(now);
6200
+ const [, codes] = modelOverviewLines(curProvider, curModel, curReasoning);
6201
+ // A model outside the 빠름/보통/깊음 map (codename or custom) says so explicitly instead of dropping the tier slot.
6202
+ const tierName = humanWordForModel(curProvider, curModel, curReasoning) ?? '단계 밖';
6203
+ ctx.chatLines.push(`지금: ${curModel?.trim() || '기본 모델'} (${tierName} · 생각 ${curReasoning}) · 고르기: /model ${HUMAN_MODEL_WORDS.join(' | ')}`);
6193
6204
  ctx.chatLines.push(ctx.muted(codes));
6194
6205
  ctx.setChatScrollOffset(-1);
6195
6206
  return;
@@ -12,6 +12,11 @@ export type StaleInstallResult = {
12
12
 
13
13
  export const STALE_INSTALL_CHECK_INTERVAL_MS = 60_000;
14
14
 
15
+ export function formatStaleInstallNotice(result: StaleInstallResult, notifiedCount: number): string {
16
+ const message = `새 판이 깔렸습니다 (부팅 판 ${result.bootCommit!.slice(0, 7)} → 지금 ${result.installedCommit!.slice(0, 7)}) · TUI 를 다시 띄우면 새 판으로 돕니다`;
17
+ return notifiedCount >= 2 ? `${message} · 이 TUI 가 뜬 뒤 ${notifiedCount}번째 새 판` : message;
18
+ }
19
+
15
20
  /** Identify the immutable installed version containing this module, never the session cwd. */
16
21
  export function versionedDashboardInstallDir(
17
22
  codeRoot: string,
@@ -21,8 +26,14 @@ export function versionedDashboardInstallDir(
21
26
  const packageRoot = realpathSync(codeRoot);
22
27
  if (basename(packageRoot) !== 'elanous' || basename(dirname(packageRoot)) !== 'node_modules') return undefined;
23
28
  const versionDir = dirname(dirname(packageRoot));
24
- if (dirname(versionDir) !== resolve(installRoot, 'versions')) return undefined;
25
- return versionDir;
29
+ let canonicalInstallRoot: string;
30
+ try { canonicalInstallRoot = realpathSync(installRoot); }
31
+ catch { canonicalInstallRoot = resolve(installRoot); }
32
+ if (dirname(versionDir) !== join(canonicalInstallRoot, 'versions')) return undefined;
33
+ const requestedVersionDir = dirname(dirname(resolve(codeRoot)));
34
+ return dirname(requestedVersionDir) === resolve(installRoot, 'versions')
35
+ && realpathSync(requestedVersionDir) === versionDir
36
+ ? requestedVersionDir : versionDir;
26
37
  } catch {
27
38
  return undefined;
28
39
  }
@@ -20,6 +20,7 @@ import type { ToolRenderModel } from '../chat/tool-render/types.js';
20
20
  import { toolOperationKind, type FoldMode } from '../log-entry.js';
21
21
  import { stripAnsi } from '../tui.js';
22
22
  import type { TurnStreamPresentationEvent } from './turn-stream-presentation-applier.js';
23
+ import { buildFoldedTailLine, splitNoSynthesisTail } from './chat-fold.js';
23
24
 
24
25
  /** Drop leading/trailing blank (whitespace-only, ANSI-stripped) rows
25
26
  * from a rendered assistant block. Codex-family models frequently
@@ -181,6 +182,7 @@ export function createTurnStreamFormatter(
181
182
  const toolArgsByCallId = new Map<string, Record<string, unknown>>();
182
183
  const nonGenericCallIds = new Set<string>();
183
184
  let toolCallCount = 0;
185
+ let noSynthesisTailCount = 0;
184
186
 
185
187
  const emitAssistantBlock = (): void => {
186
188
  deps.thinking.update('Streaming');
@@ -219,6 +221,29 @@ export function createTurnStreamFormatter(
219
221
  }
220
222
  if (chunk === '') {
221
223
  // Path 2 — authoritative replacement (W5-E/F/G force-synthesis).
224
+ const split = splitNoSynthesisTail(accumulated);
225
+ if (split) {
226
+ perRoundText = split.head;
227
+ emitAssistantBlock();
228
+ closeRound();
229
+ deps.emit({ type: 'assistant.commit' });
230
+ const callId = `no-synthesis-tail-${++noSynthesisTailCount}`;
231
+ const expandedLines = trimBlankEdges(
232
+ deps.formatResponse(split.tail, deps.termCols() - 6, deps.wrapOpts),
233
+ ).map(deps.text);
234
+ const collapsedLines = [buildFoldedTailLine(expandedLines.length)];
235
+ if (debug.enabled) {
236
+ debug.log('dashboard.chat.stream', 'formatter.noSynthesisTail.folded', {
237
+ callId,
238
+ headLen: split.head.length,
239
+ tailLen: split.tail.length,
240
+ expandedLineCount: expandedLines.length,
241
+ });
242
+ }
243
+ deps.emit({ type: 'tool.appendBlock', callId, lines: collapsedLines, args: {} });
244
+ deps.emit({ type: 'tool.replaceBlock', callId, collapsedLines, expandedLines });
245
+ return;
246
+ }
222
247
  perRoundText = accumulated;
223
248
  } else {
224
249
  // Path 3 — streaming delta. accumulated 무시 (cross-turn fullText).
@@ -0,0 +1,159 @@
1
+ import type { DebugEvent } from './log.js';
2
+
3
+ export const LOG_DIET_WINDOW_MS = 60_000;
4
+
5
+ export const LOG_DIET_KEYS: Readonly<Record<string, 'repeat' | 'consecutive'>> = {
6
+ 'watchdog/activity': 'consecutive',
7
+ 'user-config.llm/provider-resolved': 'repeat',
8
+ 'hitl.card-bridge/skipped': 'repeat',
9
+ 'input.cursor.claim/chat-main': 'repeat',
10
+ 'tox.loop/waiting-capacity': 'repeat',
11
+ 'tox.loop/tick': 'repeat',
12
+ };
13
+
14
+ export interface LogDietSummary {
15
+ category: string;
16
+ event: string;
17
+ count: number;
18
+ windowMs: number;
19
+ firstSuppressedAt: string;
20
+ lastSuppressedAt: string;
21
+ runId?: string;
22
+ sessionId?: string;
23
+ }
24
+
25
+ type Policy = 'repeat' | 'consecutive';
26
+ type DietRecord = Pick<DebugEvent, 'category' | 'event' | 'data' | 'level' | 'session_id' | 'runId'>;
27
+
28
+ interface Stream {
29
+ category: string;
30
+ event: string;
31
+ runId?: string;
32
+ sessionId?: string;
33
+ value: string;
34
+ lastEmittedAt: number;
35
+ count: number;
36
+ firstSuppressedAt?: string;
37
+ lastSuppressedAt?: string;
38
+ }
39
+
40
+ /** Canonicalize objects (not arrays) so payload property insertion order is not an identity. */
41
+ function stableValue(value: unknown): string {
42
+ const seen = new WeakSet<object>();
43
+ return JSON.stringify(value, (_key, item: unknown) => {
44
+ if (typeof item === 'bigint') return `${item}n`;
45
+ if (item && typeof item === 'object') {
46
+ if (seen.has(item)) return '<circular>';
47
+ seen.add(item);
48
+ if (Array.isArray(item)) return item;
49
+ return Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b)));
50
+ }
51
+ return item;
52
+ }) ?? 'undefined';
53
+ }
54
+
55
+ export class LogDietGuard {
56
+ private readonly windowMs: number;
57
+ private readonly now: () => number;
58
+ private readonly keys: Readonly<Record<string, Policy>>;
59
+ private readonly maxStreams: number;
60
+ private readonly disabled: boolean;
61
+ private readonly streams = new Map<string, Stream>();
62
+
63
+ constructor(opts: { windowMs?: number; now?: () => number; keys?: Readonly<Record<string, Policy>>; maxStreams?: number } = {}) {
64
+ this.windowMs = opts.windowMs ?? LOG_DIET_WINDOW_MS;
65
+ this.now = opts.now ?? Date.now;
66
+ this.keys = opts.keys ?? LOG_DIET_KEYS;
67
+ this.maxStreams = Math.max(1, opts.maxStreams ?? 2000);
68
+ this.disabled = process.env.ELANOUS_LOG_DIET === 'off';
69
+ }
70
+
71
+ private summary(stream: Stream): LogDietSummary | undefined {
72
+ if (!stream.count) return undefined;
73
+ return {
74
+ category: stream.category,
75
+ event: stream.event,
76
+ count: stream.count,
77
+ windowMs: this.windowMs,
78
+ firstSuppressedAt: stream.firstSuppressedAt!,
79
+ lastSuppressedAt: stream.lastSuppressedAt!,
80
+ ...(stream.runId !== undefined ? { runId: stream.runId } : {}),
81
+ ...(stream.sessionId !== undefined ? { sessionId: stream.sessionId } : {}),
82
+ };
83
+ }
84
+
85
+ admit(rec: DietRecord): { pass: boolean; summaries: LogDietSummary[] } {
86
+ const policy = this.keys[`${rec.category}/${rec.event}`];
87
+ if (this.disabled || !policy || rec.category === 'log.diet'
88
+ || rec.level === 'warn' || rec.level === 'error' || rec.level === 'critical') {
89
+ return { pass: true, summaries: [] };
90
+ }
91
+
92
+ const runId = rec.runId ?? (rec.data && typeof rec.data === 'object' && !Array.isArray(rec.data)
93
+ ? (rec.data as Record<string, unknown>).runId : undefined);
94
+ const sessionId = rec.session_id;
95
+ let value: string;
96
+ try {
97
+ value = stableValue([stableValue(rec.data), rec.level ?? 'debug', sessionId, runId]);
98
+ } catch {
99
+ return { pass: true, summaries: [] }; // Logging must remain fail-open for unusual payloads.
100
+ }
101
+ const key = stableValue(policy === 'repeat'
102
+ ? [rec.category, rec.event, value]
103
+ : [rec.category, rec.event, sessionId, runId]);
104
+ const time = this.now();
105
+ const summaries: LogDietSummary[] = [];
106
+ const stream = this.streams.get(key);
107
+ if (stream) {
108
+ this.streams.delete(key); // Evict the least recently observed flow.
109
+ this.streams.set(key, stream);
110
+ if ((policy === 'repeat' || stream.value === value) && time - stream.lastEmittedAt < this.windowMs) {
111
+ stream.count++;
112
+ const at = new Date(time).toISOString();
113
+ stream.firstSuppressedAt ??= at;
114
+ stream.lastSuppressedAt = at;
115
+ return { pass: false, summaries };
116
+ }
117
+ const pending = this.summary(stream);
118
+ if (pending) summaries.push(pending);
119
+ stream.count = 0;
120
+ stream.firstSuppressedAt = undefined;
121
+ stream.lastSuppressedAt = undefined;
122
+ stream.value = value;
123
+ stream.lastEmittedAt = time;
124
+ return { pass: true, summaries };
125
+ }
126
+
127
+ if (this.streams.size >= this.maxStreams) {
128
+ const oldestKey = this.streams.keys().next().value!;
129
+ const oldest = this.streams.get(oldestKey)!;
130
+ const pending = this.summary(oldest);
131
+ if (pending) summaries.push(pending);
132
+ this.streams.delete(oldestKey);
133
+ }
134
+ this.streams.set(key, { category: rec.category, event: rec.event,
135
+ ...(typeof runId === 'string' ? { runId } : {}),
136
+ ...(sessionId !== undefined ? { sessionId } : {}),
137
+ value, lastEmittedAt: time, count: 0 });
138
+ return { pass: true, summaries };
139
+ }
140
+
141
+ /** Emit pending counts without reopening the current sample windows. */
142
+ flushPending(): LogDietSummary[] {
143
+ const summaries: LogDietSummary[] = [];
144
+ for (const stream of this.streams.values()) {
145
+ const pending = this.summary(stream);
146
+ if (pending) summaries.push(pending);
147
+ stream.count = 0;
148
+ stream.firstSuppressedAt = undefined;
149
+ stream.lastSuppressedAt = undefined;
150
+ }
151
+ return summaries;
152
+ }
153
+
154
+ drain(): LogDietSummary[] {
155
+ const summaries = this.flushPending();
156
+ this.streams.clear();
157
+ return summaries;
158
+ }
159
+ }
package/src/debug/log.ts CHANGED
@@ -81,8 +81,7 @@ import { redactLogRecord } from '../mss/logging/redaction.js';
81
81
  import { isRenderCategory } from '../mss/logging/render-categories.js';
82
82
  import type { LogSource, LogLevel } from '../mss/logging/record.js';
83
83
  import { cleanupLogDir } from '../mss/logging/retention.js';
84
- import { createStderrSinkFromFlags } from '../mss/logging/sinks/stderr-sink.js';
85
- import { createOtelGenAISinkFromFlags } from '../mss/logging/sinks/otel-genai-sink.js';
84
+ import { LogDietGuard, type LogDietSummary } from './log-diet.js';
86
85
 
87
86
  /** DebugEvent is the legacy shape. Pre-MSS callers only read/write
88
87
  * `ts` / `category` / `event` / `data`. MSS M2.1 adds four optional
@@ -285,6 +284,7 @@ class DebugLog {
285
284
  private readonly _ringSink = new RingSink(500);
286
285
  private readonly _mirrorSink = new MirrorSink(formatLine);
287
286
  private readonly _extraSinks: LogSink[] = [];
287
+ private _logDietGuard: LogDietGuard | null = new LogDietGuard();
288
288
  private readonly _redactEnabled: boolean;
289
289
 
290
290
  constructor() {
@@ -550,8 +550,20 @@ class DebugLog {
550
550
  return this._ringSink.events().map(formatLine).join('\n');
551
551
  }
552
552
 
553
+ /** Replace the guard for isolated sink tests; return the previous guard. */
554
+ setLogDietGuard(guard: LogDietGuard | null): LogDietGuard | null {
555
+ const previous = this._logDietGuard;
556
+ this._logDietGuard = guard;
557
+ return previous;
558
+ }
559
+
560
+ private emitLogDietSummaries(summaries: LogDietSummary[]): void {
561
+ for (const summary of summaries) this.log('log.diet', 'suppressed', summary);
562
+ }
563
+
553
564
  /** Force any buffered events to disk immediately. */
554
565
  flush(): void {
566
+ if (this._logDietGuard) this.emitLogDietSummaries(this._logDietGuard.flushPending());
555
567
  this._fileSink.flush();
556
568
  this._chatFileSink.flush();
557
569
  for (const sink of this._extraSinks) {
@@ -600,6 +612,12 @@ class DebugLog {
600
612
  // when off).
601
613
  if (this._redactEnabled) rec = redactLogRecord(rec) as DebugEvent;
602
614
 
615
+ if (this._logDietGuard) {
616
+ const decision = this._logDietGuard.admit(rec);
617
+ this.emitLogDietSummaries(decision.summaries);
618
+ if (!decision.pass) return;
619
+ }
620
+
603
621
  // Ring buffer — always populated when at least one sink is live so
604
622
  // `/debug tail` shows activity even when the file write failed.
605
623
  this._ringSink.emit(rec);
@@ -767,7 +785,18 @@ function safeStringSlice(value: string, limit: number, fromEnd = false): string
767
785
  /** Format a single event as a compact one-line string. Long payloads
768
786
  * get truncated at ~400 chars so the chat mirror doesn't flood the
769
787
  * log pane on a big LLM response. */
788
+ let configTimeZoneRegistrationLoaded = false;
789
+
770
790
  export function formatLine(ev: DebugEvent): string {
791
+ // Standalone logger consumers can format before application bootstrap. Load
792
+ // the config owner once on demand without a static or type import edge.
793
+ if (!configTimeZoneRegistrationLoaded) {
794
+ try {
795
+ const configModulePath: string = '../user-config.js';
796
+ require(configModulePath);
797
+ configTimeZoneRegistrationLoaded = true;
798
+ } catch { /* config unavailable during startup — formatter falls back to env/OS */ }
799
+ }
771
800
  const time = formatClock(ev.ts, { millis: true }); // 사용자 시간대 HH:MM:SS.mmm
772
801
  const head = `[${time}] [${ev.category}] ${ev.event}`;
773
802
  if (ev.data === undefined) return head;
@@ -905,6 +934,8 @@ const SECRET_TEXT_RULES: readonly { readonly id: string; readonly re: RegExp; re
905
934
  { id: 'generic-api-key', re: /\b(api[_-]?key|secret|password|passwd|token|credential)\b(\s*[:=]\s*)["']?[^\s"',;)]{4,}/gi, to: '$1$2***' },
906
935
  // 환경변수 형태 `OPENROUTER_API_KEY=…` — 위 규칙은 `_API_KEY` 앞에 단어 경계가 없어 못 잡는다. 값에 글자가 있어야 한다(`MAX_TOKEN=4096` 은 그대로).
907
936
  { id: 'env-secret', re: /\b([A-Z][A-Z0-9]*_(?:[A-Z0-9]+_)*(?:API_KEY|TOKEN|SECRET|PASSWORD|ACCESS_KEY))(\s*[:=]\s*)["']?(?=[^\s"',;)]*[A-Za-z])[^\s"',;)]{8,}/g, to: '$1$2***' },
937
+ // BEDROCK-PROVIDER — `AWS_BEARER_TOKEN_BEDROCK=…` 은 이름이 TOKEN 으로 «끝나지» 않아 위 규칙이 못 잡는다.
938
+ { id: 'aws-bedrock-bearer-env', re: /\b(AWS_BEARER_TOKEN_BEDROCK)(\s*[:=]\s*)["']?[^\s"',;)]{8,}/g, to: '$1$2***' },
908
939
  // Authorization 헤더(로그에서 흔하다).
909
940
  { id: 'authorization-header', re: /\b(Bearer|Basic)\s+[A-Za-z0-9._~+/-]{8,}={0,2}/gi, to: '$1 ***' },
910
941
  ];
@@ -959,19 +990,23 @@ export function redactSecrets<T>(obj: T): T {
959
990
  /** The singleton. Import as `debug` from this module. */
960
991
  export const debug = new DebugLog();
961
992
 
962
- // MSS M2.2 Phase A2 — opt-in stderr mirror. Default off, so this is a
963
- // no-op unless `MSS_STDERR_SINK=1` is set in the environment. Kept as
964
- // the only "extra sink" wire point baked into the debug module; future
965
- // sinks should register themselves from their consuming subsystem
966
- // rather than being listed here, so this stays small.
967
- try {
968
- const stderrSink = createStderrSinkFromFlags(getFlags());
969
- if (stderrSink) debug.registerSink(stderrSink);
970
- } catch { /* flag-parse failure must not block the rest of the tracer */ }
971
-
972
- // PLAN §4.6 / Arc 2.2 — opt-in OTel GenAI sink. Default off; wire only
973
- // when `MSS_OTEL_ENDPOINT` is set so a missing collector is silent.
993
+ // Optional sinks register synchronously after the singleton exists, before
994
+ // its first caller can log. Non-literal require keeps their type graph out of
995
+ // the foundation and avoids losing records during asynchronous import.
974
996
  try {
975
- const otelSink = createOtelGenAISinkFromFlags(getFlags());
976
- if (otelSink) debug.registerSink(otelSink);
977
- } catch { /* flag-parse / sink-init failure must not block the tracer */ }
997
+ const flags = getFlags();
998
+ if (flags.stderrSink) {
999
+ try {
1000
+ const sinkModulePath: string = '../mss/logging/sinks/stderr-sink.js';
1001
+ const sink = require(sinkModulePath).createStderrSinkFromFlags(flags) as LogSink | null;
1002
+ if (sink) debug.registerSink(sink);
1003
+ } catch { /* one optional sink must not block the other */ }
1004
+ }
1005
+ if (flags.otelEndpoint) {
1006
+ try {
1007
+ const sinkModulePath: string = '../mss/logging/sinks/otel-genai-sink.js';
1008
+ const sink = require(sinkModulePath).createOtelGenAISinkFromFlags(flags) as LogSink | null;
1009
+ if (sink) debug.registerSink(sink);
1010
+ } catch { /* optional sink must not block the tracer */ }
1011
+ }
1012
+ } catch { /* flag-parse failure must not block the tracer */ }
@@ -34,7 +34,9 @@ export function isIrreversible(entry: Pick<DecisionEntry, 'category'>): boolean
34
34
  return IRREVERSIBLE.has(entry.category);
35
35
  }
36
36
 
37
- const kst = (at: string) => new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }).format(new Date(at));
37
+ const kst = (at: string) => Number.isFinite(Date.parse(at))
38
+ ? new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }).format(new Date(at))
39
+ : '읽을 수 없음';
38
40
 
39
41
  /** The card opens with a short pitch; the full question and choice buttons remain below it. */
40
42
  export function renderCardText(e: DecisionEntry, extra: { note?: string; confirm?: string } = {}): string {
@@ -101,6 +103,7 @@ interface CardState {
101
103
  * deploy); they stay reachable through `/decisions`. */
102
104
  since?: string;
103
105
  cards: Record<string, { refs: CardRef[]; closed?: boolean; remindedAt?: string; note?: string; attempts?: number; noSubscribers?: boolean }>;
106
+ deferred?: Record<string, true>;
104
107
  testOriginQuestions?: Record<string, true>;
105
108
  }
106
109
 
@@ -113,6 +116,10 @@ export interface DecisionCardServiceOptions {
113
116
  /** Where this platform keeps which card it sent (one file per platform — the two bots may run in different processes). */
114
117
  statePath?: string;
115
118
  now?: () => Date;
119
+ /** Optional gate for new-card delivery. Omit to send every eligible open decision. */
120
+ sendFilter?: (entry: DecisionEntry, now: Date) => boolean;
121
+ /** Label recorded in the `push-deferred` observation when `sendFilter` holds a decision back. */
122
+ deferredReason?: (entry: DecisionEntry, now: Date) => string;
116
123
  /** Tell the seat that raised it. Default: none (observed only). */
117
124
  replyToRaiser?: (entry: DecisionEntry, via: CardPlatform) => Promise<void>;
118
125
  }
@@ -223,6 +230,18 @@ export class DecisionCardService {
223
230
  const card = state.cards[e.id];
224
231
  if (e.status === 'open' && (!card || (platform === 'webpush' && !card.refs.length && (card.attempts ?? 0) < WEBPUSH_MAX_SEND_ATTEMPTS))
225
232
  && e.options.length >= 2 && e.raisedAt !== undefined && e.raisedAt >= state.since) {
233
+ if (this.opts.sendFilter) {
234
+ const now = this.now();
235
+ if (!this.opts.sendFilter(e, now)) {
236
+ if (!state.deferred?.[e.id]) {
237
+ (state.deferred ??= {})[e.id] = true;
238
+ dirty = true;
239
+ debug.log(platform === 'webpush' ? 'decisions.webpush' : 'decisions.telegram', 'push-deferred',
240
+ { ...(platform === 'webpush' ? {} : { platform }), id: e.id, urgency: this.opts.deferredReason?.(e, now) ?? 'filtered' });
241
+ }
242
+ continue;
243
+ }
244
+ }
226
245
  if (platform === 'webpush' && !chats.length) {
227
246
  if (!card?.noSubscribers) {
228
247
  state.cards[e.id] = { ...(card ?? { refs: [] }), noSubscribers: true };
@@ -5,6 +5,8 @@ import { readPendingQuestionAnswer, readPendingQuestions, writePendingQuestionAn
5
5
  import { debug, redactSecretText } from '../debug/log.js';
6
6
  import { createVersionResolver, type VersionOptions, type Versions } from '../directives/version-at.js';
7
7
  import { getUserConfig } from '../user-config.js';
8
+ import { registeredSeats, resolveSeat } from '../seat-address/seat-address.js';
9
+ import { isSeatId } from '../seat-dispatch/seat-questions.js';
8
10
 
9
11
  export type DecisionCategory = 'secret' | 'publish' | 'money' | 'security' | 'scope' | 'irreversible' | 'other';
10
12
  /** Old track letters (S·T·F·O) stay readable; seat names (OP·MK·TC·UX) are the current identities. */
@@ -53,7 +55,8 @@ export class DecisionAnswerDeliveryError extends Error {
53
55
  }
54
56
  }
55
57
  const CATEGORIES: readonly string[] = ['secret', 'publish', 'money', 'security', 'scope', 'irreversible', 'other'];
56
- const TRACKS: readonly string[] = ['S', 'T', 'F', 'O', 'OP', 'MK', 'TC', 'UX'];
58
+ const isDecisionTrack = (value: string): boolean => registeredSeats().some(({ id, alias }) => value === id || value === alias);
59
+ const isRegisteredSeat = (value: string): boolean => isSeatId(value) && resolveSeat(value)?.id === value;
57
60
 
58
61
  function required(value: string, name: string): string {
59
62
  if (typeof value !== 'string' || !value.trim()) throw new Error(`${name} is required`);
@@ -88,7 +91,7 @@ function validate(input: RaiseInput, historical = false): RaiseInput {
88
91
  const title = safe(single(input.title, 'title'));
89
92
  if (!CATEGORIES.includes(input.category)) throw new Error('invalid category');
90
93
  if (!input.raisedBy?.agent) throw new Error('raisedBy.agent is required');
91
- if (input.raisedBy.track && !TRACKS.includes(input.raisedBy.track)) throw new Error('invalid track');
94
+ if (input.raisedBy.track && !isDecisionTrack(input.raisedBy.track)) throw new Error('invalid track');
92
95
  const s = scqaField(input.scqa.s, 's');
93
96
  const c = scqaField(input.scqa.c, 'c');
94
97
  const q = input.scqa.q?.trim() ? scqaField(input.scqa.q, 'q') : undefined;
@@ -117,7 +120,7 @@ function validate(input: RaiseInput, historical = false): RaiseInput {
117
120
  if (input.crossCheck !== undefined && !Array.isArray(input.crossCheck)) throw new Error('cross-check must be a list');
118
121
  const crossCheck = input.crossCheck?.map(check => {
119
122
  const seat = single(check.seat, 'cross-check seat');
120
- if (!['OP', 'MK', 'TC', 'UX'].includes(seat)) throw new Error('invalid cross-check seat');
123
+ if (!isRegisteredSeat(seat)) throw new Error('invalid cross-check seat');
121
124
  return { seat, at: utc(check.at), note: safe(single(check.note, 'cross-check note')) };
122
125
  });
123
126
  const crossCheckSkipped = input.crossCheckSkipped === undefined ? undefined : safe(single(input.crossCheckSkipped, 'cross-check skipped reason'));
@@ -242,7 +245,7 @@ export class DecisionLedger {
242
245
  /** Delegated decisions are already made: they share the append-only ledger, never the owner's open-card state machine. */
243
246
  recordSeatDecision(input: SeatDecisionInput): SeatDecisionRecord {
244
247
  const seat = input.seat;
245
- if (!['OP', 'MK', 'TC', 'UX'].includes(seat)) throw new Error('invalid seat');
248
+ if (!isRegisteredSeat(seat)) throw new Error('invalid seat');
246
249
  const title = safe(single(input.title, 'title'));
247
250
  const decision = safe(single(input.decision, 'decision'));
248
251
  const delegation = safe(single(input.delegation, 'delegation'));
@@ -263,7 +266,7 @@ export class DecisionLedger {
263
266
  }
264
267
  seatReport(filters: { since?: string; seat?: Seat } = {}): SeatDecisionRecord[] {
265
268
  const since = filters.since === undefined ? undefined : utc(filters.since);
266
- if (filters.seat && !['OP', 'MK', 'TC', 'UX'].includes(filters.seat)) throw new Error('invalid seat');
269
+ if (filters.seat && !isRegisteredSeat(filters.seat)) throw new Error('invalid seat');
267
270
  return this.events().filter((event): event is Extract<Event, { type: 'seat-recorded' }> => event.type === 'seat-recorded')
268
271
  .map(event => event.entry)
269
272
  .filter(entry => (!since || (entry.recordedAt ?? entry.decidedAt ?? '') >= since) && (!filters.seat || entry.seat === filters.seat))
@@ -307,7 +310,7 @@ export class DecisionLedger {
307
310
  if (!by || (by.kind !== 'human' && by.kind !== 'auto')) throw new Error('decidedBy is required');
308
311
  if (by.kind === 'auto') {
309
312
  single(by.delegation, 'delegation'); single(by.agent, 'agent');
310
- if (by.track && !TRACKS.includes(by.track)) throw new Error('invalid track');
313
+ if (by.track && !isDecisionTrack(by.track)) throw new Error('invalid track');
311
314
  by = { ...by, agent: safe(single(by.agent, 'agent')), delegation: safe(single(by.delegation, 'delegation')) };
312
315
  }
313
316
  return this.locked(() => {
@@ -424,7 +427,7 @@ export class DecisionLedger {
424
427
  if (choice ? !clean.options.some(o => o.key === choice) : clean.options.length !== 0) throw new Error(`option not found: ${choice}`);
425
428
  if (by.kind === 'auto') {
426
429
  single(by.agent, 'agent'); single(by.delegation, 'delegation');
427
- if (by.track && !TRACKS.includes(by.track)) throw new Error('invalid track');
430
+ if (by.track && !isDecisionTrack(by.track)) throw new Error('invalid track');
428
431
  by = { ...by, agent: safe(single(by.agent, 'agent')), delegation: safe(single(by.delegation, 'delegation')) };
429
432
  }
430
433
  const cleanNote = safe(single(note, 'note'));
@@ -449,7 +452,7 @@ export class DecisionLedger {
449
452
  completeRecorded(id: string, choice: string | undefined, by: DecisionActor, note: string, sourceOptions: DecisionOption[]): DecisionEntry {
450
453
  if (by.kind === 'auto') {
451
454
  single(by.agent, 'agent'); single(by.delegation, 'delegation');
452
- if (by.track && !TRACKS.includes(by.track)) throw new Error('invalid track');
455
+ if (by.track && !isDecisionTrack(by.track)) throw new Error('invalid track');
453
456
  by = { ...by, agent: safe(single(by.agent, 'agent')), delegation: safe(single(by.delegation, 'delegation')) };
454
457
  }
455
458
  const cleanNote = safe(single(note, 'note'));
@@ -1,8 +1,24 @@
1
1
  import { debug } from '../debug/log.js';
2
2
  import { listSubscriptions } from '../web-push/subscriptions.js';
3
3
  import { sendPushToAll } from '../web-push/sender.js';
4
- import { type CardTransport, type CardView } from './decision-cards.js';
5
- import { DecisionLedger } from './decision-ledger.js';
4
+ import { isIrreversible, type CardTransport, type CardView } from './decision-cards.js';
5
+ import { DecisionLedger, type DecisionEntry } from './decision-ledger.js';
6
+
7
+ /** How close a deadline must be for an otherwise reversible decision to ring the phone. */
8
+ export const WEB_PUSH_URGENT_WINDOW_MS = 24 * 3600_000;
9
+
10
+ export type WebPushUrgency = 'irreversible' | 'due-soon' | 'not-urgent' | 'due-unreadable';
11
+
12
+ /** Web push rings only for urgent decisions; an unreadable deadline is its own value (fail open, never folded into not-urgent). */
13
+ export function webPushUrgency(entry: DecisionEntry, now: Date): WebPushUrgency {
14
+ if (isIrreversible(entry)) return 'irreversible';
15
+ if (entry.dueAt !== undefined) {
16
+ const due = Date.parse(entry.dueAt);
17
+ if (!Number.isFinite(due)) return 'due-unreadable';
18
+ if (due - now.getTime() <= WEB_PUSH_URGENT_WINDOW_MS) return 'due-soon';
19
+ }
20
+ return 'not-urgent';
21
+ }
6
22
 
7
23
  const ID_IN_CARD = /^🗳 결정 요청 (D-\d{8}-\d+)(?: ·|\n)/;
8
24
  const ID_IN_REMINDER = /^⏰ 기한 2시간 전 — (D-\d{8}-\d+) /;
@@ -26,7 +42,7 @@ export function webPushDecisionTransport(
26
42
  const entry = ledger.show(id);
27
43
  if (entry.status !== 'open') return null;
28
44
  const recommendation = 'skipped' in entry.recommendation ? '추천안 없음' : `추천안: ${entry.recommendation.option.toUpperCase()}`;
29
- const body = `${recommendation}${entry.dueAt ? ` · 기한: ${new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }).format(new Date(entry.dueAt))}` : ''}`;
45
+ const body = `${recommendation}${entry.dueAt ? ` · 기한: ${Number.isFinite(Date.parse(entry.dueAt)) ? new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }).format(new Date(entry.dueAt)) : '읽을 수 없음'}` : ''}`;
30
46
  const result = await push({ title: title('대표 결정 · ', entry.title), body, url: url(id), tag: tag(id) });
31
47
  if (result.attempted) debug.log('decisions.webpush', 'card-sent', { id, delivered: result.delivered });
32
48
  return result.delivered ? { chat: 'webpush', message: id } : null;