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
@@ -1,5 +1,7 @@
1
- import { readFileSync } from 'node:fs';
2
- import { cpus, freemem, loadavg, totalmem } from 'node:os';
1
+ import { execFile } from 'node:child_process';
2
+ import { readFileSync, promises as fs } from 'node:fs';
3
+ import { promisify } from 'node:util';
4
+ import { cpus, freemem, loadavg, platform, totalmem } from 'node:os';
3
5
  import { join } from 'node:path';
4
6
  import { debug } from '../debug/log.js';
5
7
  import { effectiveInstanceRoot } from '../instance/resolve.js';
@@ -12,13 +14,173 @@ const MAX_RETRY_MS = 300_000;
12
14
  // Ordinary ticks start within the 10-minute TTL; first failure retries within 30 seconds.
13
15
  const MAX_INTERVAL_MS = MAX_RETRY_MS;
14
16
  const REQUEST_TIMEOUT_MS = 5_000;
17
+ const PROCESS_PROBE_TIMEOUT_MS = 2_000;
18
+ const execFileAsync = promisify(execFile);
15
19
 
16
- export function measureLoad(now: () => number = Date.now): {
20
+ type Measurement<T> = { value: T; source: string; observedAt: number; status: 'ok' }
21
+ | { value: null; source: string; observedAt: number; status: 'unmeasured'; reason: string };
22
+
23
+ function unmeasured<T>(source: string, observedAt: number, reason: string): Measurement<T> {
24
+ return { value: null, source, observedAt, status: 'unmeasured', reason };
25
+ }
26
+
27
+ export interface HarnessParentSummary {
28
+ count: Measurement<number>;
29
+ oldestAgeSeconds: Measurement<number>;
30
+ versionMismatchCount: Measurement<number>;
31
+ }
32
+
33
+ // Pod image commit is fixed at process startup; file paths and mutable package versions are not process identities.
34
+ const STARTUP_IMAGE_COMMIT = process.env.ELANOUS_IMAGE_COMMIT?.trim();
35
+ const HARNESS_PARENT_COMMAND = /^(?:(?:\S*\/)?(?:bun|node)\s+)?(?:\S*\/)?elanous\.mjs\s+harness\s+(?:say|ask)(?:\s|$)/;
36
+
37
+ export function parseHarnessParentPs(text: string): HarnessProcessList {
38
+ if (!text.trim()) return { status: 'incomplete', stage: 'ps-parse' };
39
+ const records: Array<{ pid: number; command: string; elapsedSeconds: number }> = [];
40
+ let incomplete = false;
41
+ for (const line of text.split('\n')) {
42
+ const candidate = line.trim().match(/^\d+\s+\S+\s+(.+)$/)?.[1];
43
+ if (!candidate || !HARNESS_PARENT_COMMAND.test(candidate)) continue;
44
+ const match = line.trim().match(/^(\d+)\s+(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)\s+(.+)$/);
45
+ if (!match) { incomplete = true; continue; }
46
+ const pid = Number(match[1]);
47
+ const days = Number(match[2] ?? 0);
48
+ const hours = Number(match[3] ?? 0);
49
+ const minutes = Number(match[4]);
50
+ const seconds = Number(match[5]);
51
+ if (!Number.isSafeInteger(pid) || pid <= 0 || minutes >= 60 || seconds >= 60 || (match[3] !== undefined && hours >= 24)) { incomplete = true; continue; }
52
+ records.push({ pid, elapsedSeconds: days * 86_400 + hours * 3_600 + minutes * 60 + seconds, command: match[6]! });
53
+ }
54
+ return incomplete ? { status: 'incomplete', stage: 'ps-parse' } : { status: 'ok', records };
55
+ }
56
+
57
+ interface HarnessProcessList {
58
+ status: 'ok' | 'incomplete' | 'failed';
59
+ stage?: string;
60
+ records?: readonly { pid: number; command: string; elapsedSeconds: number; version?: string }[];
61
+ }
62
+
63
+ async function readHarnessProcessVersion(pid: number): Promise<string | undefined> {
64
+ if (platform() !== 'linux') return undefined;
65
+ try {
66
+ const env = await fs.readFile(`/proc/${pid}/environ`, { encoding: 'utf8', signal: AbortSignal.timeout(PROCESS_PROBE_TIMEOUT_MS) });
67
+ const versions = env.split('\0').filter(entry => entry.startsWith('ELANOUS_IMAGE_COMMIT='))
68
+ .map(entry => entry.slice('ELANOUS_IMAGE_COMMIT='.length).trim());
69
+ return versions.length === 1 && versions[0] ? versions[0] : undefined;
70
+ } catch { return undefined; }
71
+ }
72
+
73
+ export async function listHarnessParents(
74
+ run: typeof execFileAsync = execFileAsync,
75
+ readVersion: (pid: number) => Promise<string | undefined> = readHarnessProcessVersion,
76
+ ): Promise<HarnessProcessList> {
77
+ try {
78
+ const { stdout } = await run('ps', ['-axo', 'pid=,etime=,command='], {
79
+ encoding: 'utf8', timeout: PROCESS_PROBE_TIMEOUT_MS, maxBuffer: 4 * 1024 * 1024,
80
+ });
81
+ const parsed = parseHarnessParentPs(stdout);
82
+ if (parsed.status !== 'ok' || !parsed.records) return parsed;
83
+ const records = await Promise.all(parsed.records.map(async record => {
84
+ const version = await readVersion(record.pid).catch(() => undefined);
85
+ return { ...record, ...(version ? { version } : {}) };
86
+ }));
87
+ return { status: 'ok', records };
88
+ } catch { return { status: 'failed', stage: 'ps-exec' }; }
89
+ }
90
+
91
+ /** A process command/path is not the version loaded into a running process. Only startup-stamped identities count. */
92
+ export function measureHarnessParents(
93
+ observedAt = Date.now(),
94
+ observation: HarnessProcessList = { status: 'failed', stage: 'ps-exec' },
95
+ currentVersion?: string,
96
+ ): HarnessParentSummary {
97
+ const source = 'ps:harness-processes';
98
+ if (observation.status !== 'ok' || !observation.records) {
99
+ const reason = observation.status === 'incomplete' ? 'ps-parse incomplete' : (observation.stage ?? 'ps-exec');
100
+ return { count: unmeasured(source, observedAt, reason), oldestAgeSeconds: unmeasured(source, observedAt, reason),
101
+ versionMismatchCount: unmeasured(source, observedAt, reason) };
102
+ }
103
+ const ok = (value: number): Measurement<number> => ({ value, source, observedAt, status: 'ok' });
104
+ const records = observation.records.filter(record => HARNESS_PARENT_COMMAND.test(record.command));
105
+ const count = ok(records.length);
106
+ const oldestAgeSeconds = records.length === 0
107
+ ? unmeasured<number>(source, observedAt, 'no-parents')
108
+ : records.every(record => Number.isFinite(record.elapsedSeconds) && record.elapsedSeconds >= 0)
109
+ ? ok(Math.max(...records.map(record => record.elapsedSeconds)))
110
+ : unmeasured<number>(source, observedAt, 'elapsed-unavailable');
111
+ const versionMismatchCount = records.length === 0 ? ok(0)
112
+ : currentVersion && records.every(record => typeof record.version === 'string' && record.version.length > 0)
113
+ ? ok(records.filter(record => record.version !== currentVersion).length)
114
+ : unmeasured<number>(source, observedAt, 'version-unavailable');
115
+ return { count, oldestAgeSeconds, versionMismatchCount };
116
+ }
117
+
118
+ export interface DiskIoPressure {
119
+ pageouts: Measurement<number>;
120
+ io: Measurement<{ someAvg10: number; fullAvg10: number }>;
121
+ }
122
+
123
+ export async function measureDiskIoPressure(
124
+ observedAt = Date.now(),
125
+ deps: { platform?: NodeJS.Platform; vmStat?: () => Promise<string> | string; readPressure?: () => Promise<string> | string } = {},
126
+ pageoutBaseline?: { value: number },
127
+ ): Promise<DiskIoPressure> {
128
+ const os = deps.platform ?? platform();
129
+ let pageouts: Measurement<number> = unmeasured('vm_stat:pageouts', observedAt, 'platform');
130
+ if (os === 'darwin') {
131
+ try {
132
+ const text = await (deps.vmStat ?? (async () => (await execFileAsync('vm_stat', [], {
133
+ encoding: 'utf8', timeout: PROCESS_PROBE_TIMEOUT_MS, maxBuffer: 1024 * 1024,
134
+ })).stdout))();
135
+ // Real macOS vm_stat prints `Pageouts:`; older/other formats print `Pages paged out:`.
136
+ const value = text.match(/^(?:Pageouts|Pages paged out):\s*([\d,]+)\s*\.?\s*$/m)?.[1];
137
+ if (value && Number.isSafeInteger(Number(value.replaceAll(',', '')))) {
138
+ const total = Number(value.replaceAll(',', ''));
139
+ pageouts = pageoutBaseline
140
+ ? Number.isFinite(pageoutBaseline.value) && total >= pageoutBaseline.value
141
+ ? { value: total - pageoutBaseline.value, source: 'vm_stat:pageouts', observedAt, status: 'ok' }
142
+ : unmeasured('vm_stat:pageouts', observedAt, 'baseline-unavailable')
143
+ : { value: total, source: 'vm_stat:pageouts', observedAt, status: 'ok' };
144
+ if (pageoutBaseline) pageoutBaseline.value = total;
145
+ }
146
+ else pageouts = unmeasured('vm_stat:pageouts', observedAt, 'invalid-output');
147
+ } catch { pageouts = unmeasured('vm_stat:pageouts', observedAt, 'vm_stat-failed'); }
148
+ }
149
+ let io: DiskIoPressure['io'] = unmeasured('/proc/pressure/io', observedAt, 'platform');
150
+ if (os === 'linux') {
151
+ try {
152
+ const text = await (deps.readPressure ?? (() => fs.readFile('/proc/pressure/io', {
153
+ encoding: 'utf8', signal: AbortSignal.timeout(PROCESS_PROBE_TIMEOUT_MS),
154
+ })))();
155
+ const some = text.match(/^some\s+avg10=(\d+(?:\.\d+)?)(?:\s|$)/m)?.[1];
156
+ const full = text.match(/^full\s+avg10=(\d+(?:\.\d+)?)(?:\s|$)/m)?.[1];
157
+ if (some !== undefined && full !== undefined && Number.isFinite(Number(some)) && Number.isFinite(Number(full)))
158
+ io = { value: { someAvg10: Number(some), fullAvg10: Number(full) }, source: '/proc/pressure/io', observedAt, status: 'ok' };
159
+ else io = unmeasured('/proc/pressure/io', observedAt, 'invalid-output');
160
+ } catch { io = unmeasured('/proc/pressure/io', observedAt, 'pressure-read-failed'); }
161
+ }
162
+ return { pageouts, io };
163
+ }
164
+
165
+ export async function measureLoad(
166
+ now: () => number = Date.now,
167
+ pageoutBaseline?: { value: number },
168
+ deps: { listParents?: () => Promise<HarnessProcessList>; diskIo?: (at: number, baseline?: { value: number }) => Promise<DiskIoPressure>; currentVersion?: string } = {},
169
+ ): Promise<{
17
170
  loadAvg: number[]; cpuCount: number; freeMem: number; totalMem: number; observedAt: number;
18
- } {
171
+ harnessParents: HarnessParentSummary; diskIo: DiskIoPressure;
172
+ }> {
173
+ const observedAt = now();
174
+ const [parents, diskIo] = await Promise.all([
175
+ (deps.listParents ?? listHarnessParents)().catch((): HarnessProcessList => ({ status: 'failed', stage: 'ps-exec' })),
176
+ (deps.diskIo ?? ((at, baseline) => measureDiskIoPressure(at, {}, baseline)))(observedAt, pageoutBaseline)
177
+ .catch((): DiskIoPressure => ({ pageouts: unmeasured<number>('vm_stat:pageouts', observedAt, 'probe-failed'),
178
+ io: unmeasured<{ someAvg10: number; fullAvg10: number }>('/proc/pressure/io', observedAt, 'probe-failed') })),
179
+ ]);
19
180
  return {
20
181
  loadAvg: loadavg(), cpuCount: cpus().length,
21
- freeMem: freemem(), totalMem: totalmem(), observedAt: now(),
182
+ freeMem: freemem(), totalMem: totalmem(), observedAt,
183
+ harnessParents: measureHarnessParents(observedAt, parents, deps.currentVersion ?? STARTUP_IMAGE_COMMIT), diskIo,
22
184
  };
23
185
  }
24
186
 
@@ -50,6 +212,7 @@ export interface MemberHeartbeatOptions {
50
212
  intervalMs?: number;
51
213
  fetch?: (input: URL | RequestInfo, init?: RequestInit) => Promise<Response>;
52
214
  now?: () => number;
215
+ measure?: (now: () => number, pageoutBaseline: { value: number }) => Promise<Awaited<ReturnType<typeof measureLoad>>>;
53
216
  }
54
217
 
55
218
  /** 넥서스 멤버의 기계 신원 — OS hostname 이 아니라 임대·관제가 쓰는 기계 식별자(`resolveMachineName`)를 쓴다.
@@ -81,6 +244,8 @@ export function startMemberHeartbeat(opts: MemberHeartbeatOptions): () => void {
81
244
  let failures = 0;
82
245
  let lastFailure: string | undefined;
83
246
  const machineId = opts.machine.id;
247
+ const pageoutBaseline: { value: number } = { value: Number.NaN };
248
+ const machineLoad = () => (opts.measure ?? measureLoad)(now, pageoutBaseline);
84
249
  // 자원의 `machine` 칸 = 기계 «이름»(가벼운 멤버·임대와 같은 값). 기계 범위 토큰은 이 칸을 토큰의 기계와 대조한다(server.ts requireMachine).
85
250
  const machineName = opts.machine.name;
86
251
 
@@ -106,7 +271,7 @@ export function startMemberHeartbeat(opts: MemberHeartbeatOptions): () => void {
106
271
  const register = async (): Promise<void> => {
107
272
  await post('/v1/resources/register', {
108
273
  ...opts.machine, kind: 'machine', machine: machineName, owner: '',
109
- attrs: { ...opts.machine.attrs, load: measureLoad(now) }, observedAt: now(), ttlMs: MAX_RETRY_MS * 2,
274
+ attrs: { ...opts.machine.attrs, load: await machineLoad() }, observedAt: now(), ttlMs: MAX_RETRY_MS * 2,
110
275
  });
111
276
  await post('/v1/resources/register', {
112
277
  ...opts.instance, kind: 'instance', machine: machineName, owner: '',
@@ -125,7 +290,7 @@ export function startMemberHeartbeat(opts: MemberHeartbeatOptions): () => void {
125
290
  try {
126
291
  if (!registered) await register();
127
292
  else {
128
- await post(`/v1/resources/${encodeURIComponent(machineId)}/heartbeat`, { attrs: { load: measureLoad(now) } });
293
+ await post(`/v1/resources/${encodeURIComponent(machineId)}/heartbeat`, { attrs: { load: await machineLoad() } });
129
294
  heartbeatsSinceInstanceRefresh++;
130
295
  if (heartbeatsSinceInstanceRefresh * interval >= MAX_RETRY_MS) {
131
296
  await post(`/v1/resources/${encodeURIComponent(opts.instance.id)}/heartbeat`, {});
@@ -33,7 +33,7 @@ import { debug } from '../debug/log.js';
33
33
  import { publishGoalLifecycle } from '../goals/loop.js';
34
34
  import { boundReadableText } from '../self-implement/orchestrator.js';
35
35
  import { changedFiles } from '../self-implement/seams.js';
36
- import { getHarnessRunId, getHarnessSpace } from '../harness/harness-space.js';
36
+ import { getHarnessRole, getHarnessRunId, getHarnessSpace } from '../harness/harness-space.js';
37
37
  import { CONTROL_INBOX_DIR_ENV, drainControlInbox, drainSoftStopControlInbox, enqueueControlMemo, type ControlInboxDrain, type ControlMemoPayload } from '../harness/control-inbox.js';
38
38
  import { enqueuePendingUserInput } from '../session/pending-input.js';
39
39
  import { getCurrentPtyId } from '../agent/pty-identity.js';
@@ -180,6 +180,7 @@ export const GOAL_CONTINUATION_PROMPT = [
180
180
  '[continue]',
181
181
  '아직 목표가 완료로 증명되지 않았다. 완료를 미리 선언하지 말고, 현재 상태 대비 실제로 검증하라:',
182
182
  '남은 요구사항을 식별하고, 다음 최고가치 스텝을 지금 도구로 실행하라.',
183
+ '이미 사용자에게 한 답을 다시 쓰지 마라 — 새 사실이 없으면 텍스트 없이 update_goal 만 호출하라.',
183
184
  // evidence-audit(ref codex ext/goal continuation.md:41,51) — 스푸핑·조기완료 차단.
184
185
  '완료 증거로 의도/부분진전/이전 작업 기억/그럴듯한 답을 쓰지 마라. 현재 상태(파일·명령출력·테스트결과·PR·런타임 동작)를 실제로 확인한 증거만 인정한다.',
185
186
  '예산이 곧 소진된다거나 그만두고 싶다는 이유로 완료를 선언하지 마라.',
@@ -196,8 +197,25 @@ export const GOAL_READBACK_PROMPT = [
196
197
  '[finalize]',
197
198
  `완료를 텍스트로만 말했다. 텍스트 문장은 완료 신호가 아니다 — 완료가 사실이면 ${UPDATE_GOAL_TOOL_NAME} 도구를 status="complete" 로 호출하고 evidence 에 현재 상태에서 실제로 확인한 증거(파일·명령출력·테스트·PR)를 적어라.`,
198
199
  '아직 미충족 항목이 있으면 완료를 주장하지 말고 다음 스텝을 지금 실행하라.',
200
+ '이미 사용자에게 한 답을 다시 쓰지 마라 — 새 사실이 없으면 텍스트 없이 update_goal 만 호출하라.',
199
201
  ].join('\n');
200
202
 
203
+ /** GOAL-LOOP-INTENT-STALL (0.2.24 · OP or-audit-1010) — 구현 자식이 «도구를 한 번도 안 부르고 말만 한 턴»에
204
+ * 넣는 재촉. hermes-agent stall guard(`agent/turn_final_response.py` 172-205)를 본떴다.
205
+ * ⛔ 기존 프롬프트 상수는 건드리지 않는다 — 재촉 문면은 이 상수 하나뿐이다. */
206
+ export const GOAL_INTENT_STALL_PROMPT = [
207
+ '[act now]',
208
+ '말로 계획만 적고 도구를 하나도 호출하지 않았다. 지금 바로 실제로 도구를 호출해 첫 스텝을 실행하라(예: 대상 파일 읽기).',
209
+ '설명 문장만으로 이 턴을 끝내지 마라.',
210
+ ].join('\n');
211
+
212
+ /** 재촉 상한 — 이 횟수를 쓰고도 텍스트만이면 종전 ④(텍스트 수용)로 그대로 떨어진다. */
213
+ export const GOAL_INTENT_STALL_MAX_REPROMPTS = 2;
214
+
215
+ /** 재촉 가드가 켜지는 provider — ⭐ 이번 조각은 OpenRouter(오픈웨이트 모델) 구현 자식 «한정»이다
216
+ * (OP 10-10 결정 · 실측 GLM Flash 첫 턴 40토큰 말만 하고 abandoned). 다른 provider 는 종전 그대로. */
217
+ export const GOAL_INTENT_STALL_PROVIDERS: ReadonlySet<string> = new Set(['openrouter']);
218
+
201
219
  /** evidence 누락 complete 재주입 — update_goal(complete) 를 호출했으나 evidence 가 비었을 때. */
202
220
  export const GOAL_EVIDENCE_REQUIRED_PROMPT = [
203
221
  '[evidence required]',
@@ -262,6 +280,10 @@ export interface GoalLoopOptions {
262
280
  controlSpaceId?: string | null;
263
281
  /** Test seam — file-backed child liveness heartbeat. Default starts the workspace-file writer. */
264
282
  startLivenessHeartbeat?: typeof startChildLivenessHeartbeat;
283
+ /** GOAL-LOOP-INTENT-STALL — 구현 자식의 LLM provider. `openrouter` 일 때만 «도구 0회·텍스트만» 턴을
284
+ * 최대 2번 재촉한다. 생략하면 harness role 이 executor 인 프로세스에서만 활성 provider 로 푼다.
285
+ * null = 가드 꺼짐. 시험은 이 인자를 명시해 env 에 기대지 않는다. */
286
+ intentStallProvider?: string | null;
265
287
  }
266
288
 
267
289
  export type GoalLoopStopReason =
@@ -447,10 +469,17 @@ export async function runGoalLoop(
447
469
  // ※ 객체 홀더: onToolResult 클로저에서 변이하므로 let narrowing 대신 property 타입으로 읽는다.
448
470
  const runTests: { last: { ok: boolean; fail: number; unmatchedFilters: string[]; pass: number } | null } = { last: null };
449
471
  let lastResult: CoreTurnResult = { stopReason: 'end_turn', finalText: '' };
472
+ // GOAL-LOOP-INTENT-STALL — provider 는 루프 진입 시 «한 번» 정한다. 런 전체 도구 활동은 누적한다.
473
+ const intentStallProvider = await resolveIntentStallProvider(opts.intentStallProvider);
474
+ const intentStallGuard = intentStallProvider !== null && GOAL_INTENT_STALL_PROVIDERS.has(intentStallProvider);
475
+ let anyToolActivity = false;
476
+ let intentStallReprompts = 0;
477
+ // GOAL-LOOP-MIDRUN-STALL — 도구를 쓴 «뒤»의 말뿐인 턴 재촉은 런당 1회뿐이다.
478
+ let intentStallMidrunUsed = false;
450
479
 
451
480
  debug.log('goal.loop', 'start', {
452
481
  sessionId: ctx.sessionId, ...runAttribution, objective, maxIterations, noProgressLimit,
453
- contextTokenLimit, contextPressureRatio,
482
+ contextTokenLimit, contextPressureRatio, intentStallGuard, intentStallProvider,
454
483
  }, { level: 'info' });
455
484
  const bus = getChannelBus();
456
485
  ensureProcessLifecycleBridge(bus, opts.attachLifecycleBridge ?? attachLifecycleBridge);
@@ -689,6 +718,7 @@ export async function runGoalLoop(
689
718
  },
690
719
  };
691
720
 
721
+ const previousFinalText = lastResult.finalText;
692
722
  try {
693
723
  lastResult = await runTurn(turnCtx);
694
724
  } finally {
@@ -699,6 +729,7 @@ export async function runGoalLoop(
699
729
  const goalUpdate = findGoalUpdate(turnNewMessages);
700
730
  const rejectedTools = findRejectedToolCalls(turnNewMessages);
701
731
  const toolActivity = hadToolActivity(turnNewMessages);
732
+ if (toolActivity) anyToolActivity = true;
702
733
  const markerComplete = hasCompletionMarker(lastResult.finalText);
703
734
  const markerBlocked = hasBlockedMarker(lastResult.finalText);
704
735
 
@@ -786,8 +817,26 @@ export async function runGoalLoop(
786
817
  debug.log('goal.loop', 'complete', {
787
818
  sessionId: ctx.sessionId, ...runAttribution, iterations, via: 'update_goal', evidenceCheck,
788
819
  }, { level: 'info' });
820
+ const normalizeAnswer = (text: string) => text.trim().replace(/\s+/g, ' ');
821
+ const previousAnswer = normalizeAnswer(previousFinalText);
822
+ const completionAnswer = normalizeAnswer(lastResult.finalText);
823
+ const previousAt = previousAnswer ? completionAnswer.indexOf(previousAnswer) : -1;
824
+ const prefix = previousAt >= 0 ? completionAnswer.slice(0, previousAt).trim() : '';
825
+ const suffix = previousAt >= 0 ? completionAnswer.slice(previousAt + previousAnswer.length).trim() : '';
826
+ // Only a readback preface is non-factual; a new sentence before the old answer
827
+ // (including one joined by a colon) must survive just like a new suffix.
828
+ const readbackPreface = /^(?:확인 결과|(?:방금\s+)?다시\s+확인(?:했습니다|했지만|해보니|해 보니|해봤지만|해 봤지만|했으나|했는데))[\s::,.!?。!?-]*$/u;
829
+ const hasNewFact = (prefix.length > 0 && !readbackPreface.test(prefix)) || /\p{L}|\p{N}/u.test(suffix);
830
+ const duplicateAnswer = previousAnswer.length > 0 && (
831
+ completionAnswer.length === 0 || (previousAt >= 0 && !hasNewFact)
832
+ );
833
+ if (duplicateAnswer) {
834
+ debug.log('goal.loop', 'complete-duplicate-answer-suppressed', {
835
+ sessionId: ctx.sessionId, ...runAttribution, iterations, chars: lastResult.finalText.length,
836
+ });
837
+ }
789
838
  return finish(
790
- { finalText: lastResult.finalText, iterations, stopReason: 'goal_complete', goalComplete: true },
839
+ { finalText: duplicateAnswer ? previousFinalText : lastResult.finalText, iterations, stopReason: 'goal_complete', goalComplete: true },
791
840
  { summary: completionSummary, changedFiles: completionChangedFiles },
792
841
  );
793
842
  }
@@ -847,6 +896,43 @@ export async function runGoalLoop(
847
896
  }
848
897
  readbackStreak = 0;
849
898
 
899
+ // ④-0 GOAL-LOOP-INTENT-STALL — OpenRouter 구현 자식이 런 내내 도구를 한 번도 안 부르고 말만 했다
900
+ // (예: 「먼저 파일을 읽겠습니다」 후 멈춤). 일상 답변으로 수락하기 전에 «실제로 도구를 호출하라»를
901
+ // 최대 GOAL_INTENT_STALL_MAX_REPROMPTS 번 넣는다. 재촉 턴도 maxIterations 에 센다(하드캡이 이긴다).
902
+ // 상한을 쓰고도 텍스트만이면 포기 이벤트만 남기고 아래 ④ 로 «그대로» 떨어진다(포기 경로 불변).
903
+ // ⛔ 가드가 꺼졌거나(다른 provider·비-executor) 한 번이라도 도구를 불렀으면 이 블록은 아무것도 안 한다.
904
+ // ⭐ 빈 답(finalChars 0)도 «도구 0회»면 같은 정체로 본다 — 빈 답도 종전엔 text-only-accept 로 abandoned 됐다.
905
+ if (!toolActivity && intentStallGuard && !anyToolActivity) {
906
+ if (intentStallReprompts < GOAL_INTENT_STALL_MAX_REPROMPTS) {
907
+ intentStallReprompts += 1;
908
+ debug.log('goal.loop', 'intent-stall-reprompt', {
909
+ sessionId: ctx.sessionId, ...runAttribution, iterations, attempt: intentStallReprompts,
910
+ finalChars: lastResult.finalText.length, provider: intentStallProvider,
911
+ }, { level: 'info' });
912
+ messages.push({ role: 'user', content: GOAL_INTENT_STALL_PROMPT });
913
+ continue;
914
+ }
915
+ debug.log('goal.loop', 'intent-stall-exhausted', {
916
+ sessionId: ctx.sessionId, ...runAttribution, iterations, attempts: intentStallReprompts,
917
+ provider: intentStallProvider,
918
+ }, { level: 'warn' });
919
+ }
920
+
921
+ // ④-0b GOAL-LOOP-MIDRUN-STALL — 앞서 도구를 썼는데 이번 턴은 도구 없이 말로 끝났다
922
+ // (예: 파일을 읽은 뒤 「이제 수정하겠습니다」 후 멈춤 → 변경 0 abort · 10-10). 같은 가드에서
923
+ // 같은 GOAL_INTENT_STALL_PROMPT 를 «런당 1회»만 넣는다. 재촉 턴도 maxIterations 에 센다.
924
+ // 두 번째 중간 정체는 아래 ④ 로 «그대로» 떨어진다(text-only-accept 불변).
925
+ // ⛔ 가드가 꺼졌으면(다른 provider·비-executor) 이 블록은 아무것도 안 한다 · ④-0 과는 anyToolActivity 로 배타.
926
+ if (!toolActivity && intentStallGuard && anyToolActivity && !intentStallMidrunUsed) {
927
+ intentStallMidrunUsed = true;
928
+ debug.log('goal.loop', 'intent-stall-midrun', {
929
+ sessionId: ctx.sessionId, ...runAttribution, iterations,
930
+ finalChars: lastResult.finalText.length, provider: intentStallProvider,
931
+ }, { level: 'info' });
932
+ messages.push({ role: 'user', content: GOAL_INTENT_STALL_PROMPT });
933
+ continue;
934
+ }
935
+
850
936
  // ④ 순수 텍스트(도구 없음)로 끝났고 종결 신호도 없음 = 일상 답변(목표성 작업 아님).
851
937
  // 재주입하지 않고 그대로 수용해 trivial chat 을 이중 루프하지 않는다.
852
938
  if (!toolActivity) {
@@ -887,3 +973,22 @@ export async function runGoalLoop(
887
973
  stopLivenessHeartbeat();
888
974
  }
889
975
  }
976
+
977
+ /** 가드 provider 를 정한다. 명시 인자가 이긴다(시험·호출부). 생략하면 «구현 자식»(harness role executor)
978
+ * 프로세스에서만 활성 provider(`resolveActiveProvider` — `ELANOUS_LLM_PROVIDER` 릴레이 포함)를 읽는다.
979
+ * ⛔ executor 가 아닌 프로세스(ACP 대시보드·`chat --goal-loop`)는 읽지도 않는다 ⇒ null = 가드 꺼짐.
980
+ * 읽기 실패도 null(fail-open = 종전 동작). */
981
+ async function resolveIntentStallProvider(explicit: string | null | undefined): Promise<string | null> {
982
+ if (explicit !== undefined) return explicit?.trim().toLowerCase() || null;
983
+ if (getHarnessRole() !== 'executor') return null;
984
+ try {
985
+ const { getUserConfig, resolveActiveProvider } = await import('../user-config.js');
986
+ return resolveActiveProvider(getUserConfig());
987
+ } catch (error) {
988
+ // fail-open(가드 꺼짐 = 종전 동작)이지만 «왜 꺼졌나»는 남긴다 — 조용한 꺼짐은 관측 안 한 것이다.
989
+ debug.log('goal.loop', 'intent-stall-provider-unresolved', {
990
+ error: error instanceof Error ? error.message : String(error),
991
+ }, { level: 'warn' });
992
+ return null;
993
+ }
994
+ }
@@ -0,0 +1,20 @@
1
+ import { format, getMessages } from '../expression/i18n/index.js';
2
+
3
+ type Locale = NonNullable<Parameters<typeof getMessages>[0]>;
4
+
5
+ export function splitNoSynthesisTail(text: string): { head: string; tail: string } | null {
6
+ const index = text.indexOf('[NO FINAL SYNTHESIS]');
7
+ if (index === -1) return null;
8
+ return {
9
+ head: text.slice(0, index).trimEnd(),
10
+ tail: text.slice(index),
11
+ };
12
+ }
13
+
14
+ /** English fallback for locale bundles that do not carry the optional key. */
15
+ const FOLDED_TAIL_FALLBACK = '● Internal notes folded · {n} lines · press f to expand';
16
+
17
+ export function buildFoldedTailLine(lineCount: number, locale?: Locale): string {
18
+ const template = getMessages(locale).chatFoldedInternalTail ?? FOLDED_TAIL_FALLBACK;
19
+ return format(template, { n: lineCount });
20
+ }
@@ -1,6 +1,111 @@
1
+ import { debug } from '../debug/log.js';
2
+ import { resolveCurrentInstance } from '../instance/current.js';
3
+ import { resolveDaemonEndpoint, type DaemonEndpoint } from '../nexus/daemon-endpoint.js';
4
+
5
+ export type TuiDaemonLink =
6
+ | { readonly status: 'checking' }
7
+ | { readonly status: 'connected'; readonly address: string }
8
+ | { readonly status: 'absent' | 'unhealthy'; readonly startCommand: string }
9
+ | { readonly status: 'error'; readonly stage: 'endpoint' | 'health' | 'identity' };
10
+
11
+ export interface TuiDaemonLinkDeps {
12
+ readonly endpoint?: () => Pick<DaemonEndpoint, 'baseUrl' | 'healthUrl' | 'source'> | null;
13
+ readonly probe?: (url: string, init: RequestInit) => Promise<Response>;
14
+ readonly universe?: () => 'test' | 'prod';
15
+ /** An explicitly chosen test root (`--test=<root>` / parent stamp); bare `--test` cannot name it. */
16
+ readonly testRoot?: () => string | undefined;
17
+ readonly observe?: (data: {
18
+ status: TuiDaemonLink['status'];
19
+ stage: 'endpoint' | 'health' | 'identity';
20
+ universe: 'test' | 'prod' | 'unknown';
21
+ source: 'registry' | 'lifecycle' | 'none';
22
+ }) => void;
23
+ }
24
+
25
+ // C0/C1 controls incl. ESC (ANSI sequences), newline and DEL.
26
+ const CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f]/;
27
+
28
+ function shellQuote(value: string): string {
29
+ return /^[A-Za-z0-9_./:=@%+-]+$/.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
30
+ }
31
+
32
+ /** Probe the write target in this universe only; never use a watch/production fallback. */
33
+ export async function resolveTuiDaemonLink(deps: TuiDaemonLinkDeps = {}): Promise<TuiDaemonLink> {
34
+ const universe = deps.universe ?? (() => resolveCurrentInstance().kind === 'test' ? 'test' : 'prod');
35
+ const observe = deps.observe ?? ((data) => debug.log('dashboard.tui-daemon-link', 'resolved', data));
36
+ let kind: 'test' | 'prod' | 'unknown' = 'unknown';
37
+ let source: 'registry' | 'lifecycle' | 'none' = 'none';
38
+ const finish = (result: TuiDaemonLink, stage: 'endpoint' | 'health' | 'identity'): TuiDaemonLink => {
39
+ try { observe({ status: result.status, stage, universe: kind, source }); } catch { /* observation is fail-soft */ }
40
+ return result;
41
+ };
42
+ try {
43
+ kind = universe();
44
+ } catch {
45
+ return finish({ status: 'error', stage: 'identity' }, 'identity');
46
+ }
47
+ let explicitRoot: string | undefined;
48
+ if (kind === 'test') {
49
+ try {
50
+ // An injected identity comes with its own root (or none); only the real identity reads the real root.
51
+ explicitRoot = (deps.testRoot ?? (deps.universe ? () => undefined : () => {
52
+ const resolution = resolveCurrentInstance();
53
+ return resolution.layer === 'explicit-flag' || resolution.layer === 'parent-stamp' ? resolution.root : undefined;
54
+ }))();
55
+ } catch {
56
+ return finish({ status: 'error', stage: 'identity' }, 'identity');
57
+ }
58
+ }
59
+ // The start command must name *this* universe: a custom test root is passed as one literal shell argument.
60
+ // A root with control characters cannot be shown safely (it would rewrite the screen): name no command at all.
61
+ const startCommand = kind === 'test'
62
+ ? explicitRoot ? (CONTROL_CHARS.test(explicitRoot) ? '' : `elanous --test=${shellQuote(explicitRoot)} nexus run --hmr`) : 'elanous --test nexus run --hmr'
63
+ : 'elanous nexus run --hmr';
64
+ let endpoint: ReturnType<NonNullable<TuiDaemonLinkDeps['endpoint']>>;
65
+ try {
66
+ endpoint = (deps.endpoint ?? (() => resolveDaemonEndpoint({ purpose: 'write' })))();
67
+ if (!endpoint) return finish({ status: 'absent', startCommand }, 'endpoint');
68
+ source = endpoint.source;
69
+ } catch {
70
+ return finish({ status: 'error', stage: 'endpoint' }, 'endpoint');
71
+ }
72
+ let address: string;
73
+ let healthAddress: string;
74
+ try {
75
+ const url = new URL(endpoint.baseUrl);
76
+ const healthUrl = new URL(endpoint.healthUrl);
77
+ if (!['http:', 'https:'].includes(url.protocol) || !url.hostname || url.username || url.password
78
+ || url.pathname !== '/' || url.search || url.hash || healthUrl.origin !== url.origin
79
+ || healthUrl.username || healthUrl.password || healthUrl.pathname !== '/v1/health'
80
+ || healthUrl.search || healthUrl.hash) {
81
+ return finish({ status: 'error', stage: 'endpoint' }, 'endpoint');
82
+ }
83
+ address = url.origin;
84
+ healthAddress = `${address}/v1/health`;
85
+ } catch {
86
+ return finish({ status: 'error', stage: 'endpoint' }, 'endpoint');
87
+ }
88
+ try {
89
+ const response = await (deps.probe ?? fetch)(healthAddress, { signal: AbortSignal.timeout(1500) });
90
+ if (!response.ok) return finish({ status: 'unhealthy', startCommand }, 'health');
91
+ const body: unknown = await response.json();
92
+ if (!body || typeof body !== 'object' || !('ok' in body) || body.ok !== true) {
93
+ return finish({ status: 'unhealthy', startCommand }, 'health');
94
+ }
95
+ // «Connected» is a claim about *this* universe: the daemon must state its universe and it must match.
96
+ if (!('testUniverse' in body) || typeof body.testUniverse !== 'boolean' || body.testUniverse !== (kind === 'test')) {
97
+ return finish({ status: 'error', stage: 'identity' }, 'identity');
98
+ }
99
+ return finish({ status: 'connected', address }, 'health');
100
+ } catch {
101
+ return finish({ status: 'error', stage: 'health' }, 'health');
102
+ }
103
+ }
104
+
1
105
  export interface FirstScreenBandInput {
2
106
  readonly width: number;
3
107
  readonly daemon: boolean;
108
+ readonly link?: TuiDaemonLink;
4
109
  readonly pwa?: {
5
110
  readonly tailnet?: string | null;
6
111
  readonly lan?: string | null;
@@ -8,6 +113,31 @@ export interface FirstScreenBandInput {
8
113
  };
9
114
  }
10
115
 
116
+ // The link row contains Hangul (two terminal cells per syllable); count display cells, not UTF-16 units.
117
+ function cellWidth(text: string): number {
118
+ let width = 0;
119
+ for (const char of text) {
120
+ const point = char.codePointAt(0)!;
121
+ if (point >= 0x1100 && (point <= 0x115f || point >= 0x2329 && point <= 0x232a
122
+ || point >= 0x2e80 && point <= 0xa4cf || point >= 0xac00 && point <= 0xd7a3
123
+ || point >= 0xf900 && point <= 0xfaff || point >= 0xfe10 && point <= 0xfe6f
124
+ || point >= 0xff01 && point <= 0xff60 || point >= 0xffe0 && point <= 0xffe6
125
+ || point >= 0x1f000 && point <= 0x1ffff)) width += 2;
126
+ else if (point >= 0x300 && point <= 0x36f || point >= 0xfe00 && point <= 0xfe0f) continue;
127
+ else width++;
128
+ }
129
+ return width;
130
+ }
131
+
132
+ function fitCells(text: string, limit: number): string {
133
+ let result = '';
134
+ for (const char of text) {
135
+ if (cellWidth(result + char) > limit) break;
136
+ result += char;
137
+ }
138
+ return result;
139
+ }
140
+
11
141
  /** A startup transcript band; never includes credentials or a partial address. */
12
142
  export function buildFirstScreenBand(input: FirstScreenBandInput): string[] {
13
143
  const width = Number.isFinite(input.width) ? Math.max(0, Math.floor(input.width)) : 0;
@@ -27,8 +157,28 @@ export function buildFirstScreenBand(input: FirstScreenBandInput): string[] {
27
157
  const fallback = input.pwa === undefined ? 'PWA: not checked' : 'PWA: unavailable';
28
158
  const addressLine = address ? `PWA: ${address}` : fallback;
29
159
 
160
+ const daemonLine = (() => {
161
+ const link = input.link;
162
+ if (!link) return `elanous | daemon: ${input.daemon ? 'online' : 'offline'}`;
163
+ if (link.status === 'checking') return 'elanous | 데몬: 확인 중';
164
+ if (link.status === 'connected') {
165
+ let address: string;
166
+ try {
167
+ const url = new URL(link.address);
168
+ address = ['http:', 'https:'].includes(url.protocol) && url.hostname ? url.origin : '';
169
+ } catch { address = ''; }
170
+ const line = `elanous | 데몬: 연결됨${address ? ` (${address})` : ''}`;
171
+ return cellWidth(line) <= width ? line : 'elanous | 데몬: 연결됨';
172
+ }
173
+ if (link.status === 'error') return `elanous | 데몬: ${link.stage} 조회 오류`;
174
+ const bare = `elanous | 데몬: ${link.status === 'absent' ? '없음' : '응답 없음'}`;
175
+ if (!link.startCommand || CONTROL_CHARS.test(link.startCommand)) return bare;
176
+ const line = `${bare} · 시작: ${link.startCommand}`;
177
+ return cellWidth(line) <= width ? line : bare;
178
+ })();
179
+
30
180
  return [
31
- fit(`elanous | daemon: ${input.daemon ? 'online' : 'offline'}`),
181
+ input.link ? fitCells(daemonLine, width) : fit(daemonLine),
32
182
  addressLine.length <= width ? addressLine : fit(address ? 'PWA: address available' : fallback),
33
183
  fit('Type a message to begin | /help for commands'),
34
184
  ];