elanous 0.2.36 → 0.2.38

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 (741) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → RrjXTwz-urRAbChP1bX02}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{9250-072df22eaadaa6b5.js → 1026-44010f405704050c.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +27 -0
  6. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{4304.e9b2512834a9e23e.js → 1632.7d87f998e714bede.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +148 -0
  14. package/apps/pwa/out/_next/static/chunks/{7784.1f0ac4a16d190cf4.js → 2104.70e086d5174a4736.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{6566.926a1d1b7c911442.js → 214.186a430da28338f1.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +93 -0
  18. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +104 -0
  19. package/apps/pwa/out/_next/static/chunks/{5711.957b095705c12560.js → 2415.738b777642a02233.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/{4286.b70c4520306817e8.js → 3086.fb14b60ce98b53d3.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/{3148-98efd4869d660a87.js → 3124-561f7f037943cde2.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +24 -0
  31. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{3727.7949ccaacaa71242.js → 3291.f6c1005387d514bd.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +36 -0
  34. package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +287 -0
  38. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/{8904.7d51af2dc033965c.js → 3528.e4b8ab70d339f965.js} +2 -2
  40. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +94 -0
  45. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{3031-85328a92fcce4da6.js → 4199-f7c6eb40cd0322f8.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +32 -0
  57. package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +90 -0
  58. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +79 -0
  60. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +74 -0
  63. package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{528.38ce20ef8aa251ff.js → 5203.51e5d8b5f1dcfe53.js} +16 -16
  65. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +286 -0
  68. package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{2683.c9773a0c589b031b.js → 5307.d7328020227880c2.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +8 -0
  73. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{552.b7d061ad91eeac51.js → 5638.107314dc479e2f37.js} +2 -2
  75. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6142.913b44e260a3f925.js +64 -0
  80. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/{6925.562d532110879886.js → 6493.27ad77de7aac7966.js} +1 -1
  84. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +62 -0
  88. package/apps/pwa/out/_next/static/chunks/{275-02ea4c2a33980422.js → 7161-8f22db3ec5ed005e.js} +3 -3
  89. package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{3136.30aaaa5fa03662a3.js → 7488.966b116789f3d41a.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/{4116.a84a92a2492c080e.js → 7524.ce973525d30b3d52.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +77 -0
  95. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{3324.a09703033abcbd2f.js → 7628.6b16863ac3972333.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{3410.7f9af5ab77cbe65f.js → 7954.4f7a8832663ee979.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{771.c3cdb6c1f7f47c02.js → 8019.21ca554a821dad01.js} +16 -16
  102. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{4615.8525eb0add35eba6.js → 8487.291666583bebe640.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{6943.c6b24124853a47b2.js → 8879.ac06755bcf3e44a1.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +149 -0
  111. package/apps/pwa/out/_next/static/chunks/{575.d929793a53f27c4b.js → 8911.bf5e712acb25fb6c.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/{9f31e478.fefcbcd3c388ebc5.js → 8994d93e.33ba491f95345fc2.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/{da5ecc5c-b005ad8cac737d57.js → 89d6c04f-6b8ab341748e468a.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{599.c39c571b6733f2a2.js → 9223.cbcc88e0e9950426.js} +2 -2
  115. package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +226 -0
  116. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +24 -0
  117. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{8037.e254fd797aa224d1.js → 9581.da63ddf41acfad46.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +2 -0
  121. package/apps/pwa/out/_next/static/chunks/{ceba0382.650712b56b85b582.js → 9fe1b809.738da85c8b17e3fb.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-866aac5ff226a7f3.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-e7abc34a48a6f71e.js → page-291ab19fe2acb173.js} +1 -1
  153. package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/{page-c15958835534404b.js → page-6b140f77593576eb.js} +1 -1
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{3a3d9966.cc4d4585a2708e7c.js → b7459770.6539b11860eb8a9c.js} +7 -7
  174. package/apps/pwa/out/_next/static/chunks/{053a429e.9a63436527cc751c.js → b7478fef.5917716286213fcc.js} +3 -3
  175. package/apps/pwa/out/_next/static/chunks/bb6987f9.3647e1a23b0e3217.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/{2812ca6a.3b9f4a7a08885744.js → de8b930d.d94c0f42acf807fc.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{873d6c12.09bd499f57171543.js → eaad0cba.771200940c529df7.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/graphs/drafts/recipes.yaml +27 -7
  279. package/graphs/release/recipes.yaml +9 -0
  280. package/graphs/release/release-loop.yaml +26 -18
  281. package/graphs/work/draft-close.yaml +54 -0
  282. package/graphs/work/green-close.yaml +37 -0
  283. package/graphs/work/recipes.yaml +46 -1
  284. package/graphs/work/run-research.yaml +35 -0
  285. package/package.json +1 -1
  286. package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
  287. package/scripts/ask-op-inbox-once.ts +17 -0
  288. package/scripts/boundary-proof-mapping-audit.ts +88 -0
  289. package/scripts/brand/check.ts +13 -4
  290. package/scripts/codex-fallback-live-probe.ts +17 -15
  291. package/scripts/fleet/node-setup.sh +32 -2
  292. package/scripts/fleet/run-light-worker.sh +9 -0
  293. package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
  294. package/scripts/gate-0226-failure-census.ts +546 -0
  295. package/scripts/goals/authoring-metrics.ts +258 -0
  296. package/scripts/graph-units/draft-close-node.ts +222 -0
  297. package/scripts/hook-order-sweep.ts +7 -4
  298. package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
  299. package/scripts/land-global-checks.ts +69 -1
  300. package/scripts/measure-nl-routing-corpus.ts +207 -2
  301. package/scripts/provision-export-redactions.ts +15 -0
  302. package/scripts/public-copy-lint.ts +122 -0
  303. package/scripts/public-export.ts +69 -2
  304. package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
  305. package/scripts/ratchets/train-side-invariants.sh +7 -1
  306. package/scripts/release-loop/cut-branch.ts +61 -12
  307. package/scripts/release-loop/docs-node.ts +140 -0
  308. package/scripts/release-loop/gate-closure.ts +48 -0
  309. package/scripts/release-loop/gate-diff.ts +2 -1
  310. package/scripts/release-loop/gate-node.ts +161 -25
  311. package/scripts/release-loop/gate-partial.ts +82 -3
  312. package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
  313. package/scripts/release-loop/gate-radius-live.ts +4 -2
  314. package/scripts/release-loop/known-issues-node.ts +6 -4
  315. package/scripts/release-loop/notes-repair.ts +216 -0
  316. package/scripts/release-loop/prepare-node.ts +61 -5
  317. package/scripts/release-loop/resume-cap.ts +2 -1
  318. package/scripts/release-loop/resume-release.ts +406 -7
  319. package/scripts/release-loop/resume-test-traffic.ts +10 -0
  320. package/scripts/release-loop/resume.ts +13 -5
  321. package/scripts/release-loop/traffic-node.ts +12 -4
  322. package/scripts/release-loop/traffic-transition.ts +53 -13
  323. package/scripts/release-loop/version-node.ts +109 -15
  324. package/scripts/train/green-leg.ts +176 -0
  325. package/scripts/tui-continue-real-evidence.ts +47 -0
  326. package/scripts/ux-sim.ts +1 -1
  327. package/scripts/video-pipeline.ts +2 -2
  328. package/src/acp/client.ts +31 -5
  329. package/src/acp/core-turn-bridge.ts +12 -1
  330. package/src/acp/stderr-summary.ts +49 -0
  331. package/src/agent/monad-agent-turn.ts +1 -0
  332. package/src/agent/run-context.ts +1 -1
  333. package/src/agent/task-notification.ts +3 -1
  334. package/src/agent/terminal-surface.ts +217 -0
  335. package/src/agent-substrate/pr-reviewer.ts +11 -3
  336. package/src/agent-substrate/review-observation.ts +10 -0
  337. package/src/agent-substrate/self-review-cli.ts +537 -57
  338. package/src/auto-research/question-ladder-contract.ts +137 -0
  339. package/src/auto-research/research-turn.ts +134 -0
  340. package/src/autopilot/discovery/doc-lint.ts +1 -1
  341. package/src/autopilot/lineage/sources.ts +1 -1
  342. package/src/autopilot/pr-manager.ts +64 -13
  343. package/src/boot/daemon-runtime.ts +35 -3
  344. package/src/boot/daemon-tools/pty-shell.ts +2 -1
  345. package/src/bots/screen-probe.ts +1 -1
  346. package/src/budget/run-usage-rollup.ts +12 -7
  347. package/src/budget/unified-usage.ts +20 -0
  348. package/src/capture/tui-self-report.ts +42 -5
  349. package/src/chat/index.ts +1 -0
  350. package/src/chat/tool-render/dispatch.ts +8 -1
  351. package/src/cli/autopilot-cli.ts +24 -9
  352. package/src/cli/decisions-cli.ts +7 -4
  353. package/src/cli/doctor-cli.ts +116 -7
  354. package/src/cli/guardian-cli.ts +3 -1
  355. package/src/cli/intake-cli.ts +48 -12
  356. package/src/cli/lesson-cli.ts +69 -9
  357. package/src/cli/logs-cli.ts +357 -2
  358. package/src/cli/memory-cli.ts +30 -1
  359. package/src/cli/msg-cli.ts +15 -11
  360. package/src/cli/pr-granularity.ts +5 -3
  361. package/src/cli/pr-land-overlap-evidence.ts +38 -5
  362. package/src/cli/pr-land-refusal.ts +1 -1
  363. package/src/cli/pty-takeover-cli.ts +58 -5
  364. package/src/cli/release-checklist-read-cli.ts +112 -4
  365. package/src/cli/release-cli.ts +89 -18
  366. package/src/cli/review-carry.ts +77 -0
  367. package/src/cli/self-update.ts +24 -6
  368. package/src/cli/self-utterances-cli.ts +13 -16
  369. package/src/cli/tasks-card-show.ts +31 -1
  370. package/src/cli/tasks-cli.ts +370 -33
  371. package/src/cli/tasks-read-cli.ts +13 -5
  372. package/src/cli/usage-cli.ts +12 -10
  373. package/src/context-bus/claude-memory-import.ts +99 -0
  374. package/src/context-bus/context-now.ts +86 -2
  375. package/src/context-bus/long-term-memory.ts +125 -0
  376. package/src/core-turn/run-core-turn.ts +9 -2
  377. package/src/core-turn/run-goal-loop.ts +5 -2
  378. package/src/core-turn/types.ts +5 -0
  379. package/src/dashboard/chat/acp-chat.ts +9 -0
  380. package/src/dashboard/index.ts +115 -30
  381. package/src/dashboard/input/agent-wake.ts +43 -0
  382. package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
  383. package/src/dashboard/input/terminal-modal-router.ts +8 -159
  384. package/src/dashboard/replay-preview.ts +25 -0
  385. package/src/dashboard/side-basic-runtime.ts +61 -0
  386. package/src/dashboard/slash-runtime/dashboard-handlers.ts +19 -8
  387. package/src/dashboard/synchronized-frame-output.ts +74 -0
  388. package/src/dashboard/term-slash-runtime.ts +2 -0
  389. package/src/dashboard/turn-preamble.ts +28 -4
  390. package/src/display/coordinator.ts +45 -12
  391. package/src/display/resize-listener.ts +41 -20
  392. package/src/display/synchronized-output-region.ts +60 -0
  393. package/src/domains/guardian-tick.ts +9 -0
  394. package/src/domains/surface-events.ts +80 -1
  395. package/src/exec-requests/planner.ts +37 -2
  396. package/src/execution-loop/launch-gate.ts +4 -3
  397. package/src/git-fs/cli-stderr.ts +45 -0
  398. package/src/git-fs/gh-cli.ts +6 -3
  399. package/src/git-fs/git-cli.ts +11 -5
  400. package/src/git-fs/watcher.ts +27 -22
  401. package/src/git-fs/worktree.ts +19 -3
  402. package/src/graph-runner/graph-cli.ts +26 -2
  403. package/src/graph-runner/graph-grow.ts +37 -9
  404. package/src/graph-runner/graph-run-api.ts +3 -2
  405. package/src/graph-runner/runner.ts +34 -7
  406. package/src/graph-wizard/generate.ts +29 -6
  407. package/src/grok/credential.ts +107 -36
  408. package/src/harness/harness-cli-command.ts +179 -33
  409. package/src/harness/review-adapter.ts +26 -6
  410. package/src/hq/fence-wrapper.ts +1 -1
  411. package/src/hq/transfer.ts +1 -1
  412. package/src/index.ts +151 -18
  413. package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
  414. package/src/intake-plane/collect-telegram-saved.ts +54 -5
  415. package/src/interactive-terminal-modal.ts +3 -0
  416. package/src/keybindings.ts +17 -22
  417. package/src/llm/provider-credentials.ts +1 -1
  418. package/src/llm/route-decision.ts +13 -0
  419. package/src/llm-tool-name.ts +37 -0
  420. package/src/llm-tool-schema.ts +55 -0
  421. package/src/llm.ts +203 -21
  422. package/src/loops/checker.ts +100 -0
  423. package/src/loops/consensus.ts +26 -2
  424. package/src/loops/loop-cli.ts +9 -4
  425. package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
  426. package/src/loops/orchestrator/inbox-once.ts +28 -0
  427. package/src/loops/orchestrator/inbox.ts +130 -1
  428. package/src/loops/orchestrator/tick.ts +55 -7
  429. package/src/maturity/feature-maturity.ts +1 -0
  430. package/src/model-tier/llm-tier-map.ts +12 -17
  431. package/src/msg/msg-store.ts +17 -0
  432. package/src/native-tool-catalog.ts +1 -1
  433. package/src/nexus/api/channel-ask-op.ts +96 -0
  434. package/src/nexus/api/discord-trigger-bot.ts +28 -1
  435. package/src/nexus/api/graph-wizard-api.ts +27 -2
  436. package/src/nexus/api/grid.ts +24 -4
  437. package/src/nexus/api/http-server.ts +1 -1
  438. package/src/nexus/api/ops-api.ts +14 -6
  439. package/src/nexus/api/telegram-trigger-bot.ts +24 -0
  440. package/src/nexus/api/terminals.ts +28 -6
  441. package/src/nexus/state/state.ts +7 -1
  442. package/src/oauth/codex-account-store.ts +34 -1
  443. package/src/ops/loops-map.ts +46 -0
  444. package/src/ops/overview-cache.ts +22 -4
  445. package/src/ops/overview.ts +41 -5
  446. package/src/patents/ledger.ts +18 -1
  447. package/src/policy/llm-policy.ts +3 -1
  448. package/src/preview/terminal.ts +4 -2
  449. package/src/prompt-cache/anthropic.ts +2 -0
  450. package/src/prompt-enhance/enhance.ts +9 -4
  451. package/src/pty-shell/availability.ts +7 -0
  452. package/src/pty-shell/herdr-agent-report.ts +40 -31
  453. package/src/pty-shell/herdr-prune-stale.ts +17 -0
  454. package/src/pty-shell/herdr-sequence-lease.ts +60 -0
  455. package/src/pty-shell/pty-control-ipc.ts +187 -18
  456. package/src/pty-shell/pty-manifest.ts +16 -2
  457. package/src/pty-shell/registry.ts +25 -15
  458. package/src/pty-shell/tui-run-state.ts +235 -1
  459. package/src/release-loop/checklist.ts +50 -5
  460. package/src/release-loop/feature-store.ts +9 -9
  461. package/src/release-loop/gate-shards.ts +61 -0
  462. package/src/release-loop/landed-but-yellow.ts +93 -12
  463. package/src/release-loop/light-rc.ts +7 -4
  464. package/src/release-loop/rehearsal.ts +1 -1
  465. package/src/repl/index.ts +18 -0
  466. package/src/research/axis-fanout.ts +133 -0
  467. package/src/research/edge-decision.ts +88 -0
  468. package/src/research/output-router.ts +127 -0
  469. package/src/research-bridge/format.ts +16 -1
  470. package/src/research-bridge/index.ts +1 -0
  471. package/src/research-bridge/invoke.ts +41 -5
  472. package/src/seat-loop/seat-report.ts +1 -0
  473. package/src/self-dev/ask-launch-flow.ts +86 -10
  474. package/src/self-dev/decompose-proposal.ts +29 -18
  475. package/src/self-dev/decompose.ts +45 -9
  476. package/src/self-dev/dev-pipeline.ts +29 -7
  477. package/src/self-dev/draft-residue.ts +221 -2
  478. package/src/self-dev/draft-sweep.ts +254 -16
  479. package/src/self-dev/draft-triage-rules.ts +19 -5
  480. package/src/self-dev/orchestrate.ts +1 -0
  481. package/src/self-dev/review-provider-fallback.ts +45 -7
  482. package/src/self-dev/run-supervisor.ts +22 -7
  483. package/src/self-dev/shard-plan.ts +48 -0
  484. package/src/self-dev/shard-run.ts +310 -6
  485. package/src/self-implement/comment-only-source.ts +54 -0
  486. package/src/self-implement/doctor-visit.ts +108 -0
  487. package/src/self-implement/gate-artifacts.ts +6 -2
  488. package/src/self-implement/gate-baseline.ts +99 -1
  489. package/src/self-implement/gate-cli.ts +231 -82
  490. package/src/self-implement/gate-failure-signature.ts +44 -0
  491. package/src/self-implement/gate-remote.ts +30 -4
  492. package/src/self-implement/gate-scope.ts +13 -1
  493. package/src/self-implement/goal-author.ts +407 -21
  494. package/src/self-implement/goal-doc/section.ts +22 -0
  495. package/src/self-implement/goal-supervisor-fill.ts +110 -27
  496. package/src/self-implement/importer-test-index.ts +215 -2
  497. package/src/self-implement/knowhow-pack.ts +125 -12
  498. package/src/self-implement/l8-merge-queue.ts +198 -32
  499. package/src/self-implement/off-diff-evidence.ts +23 -0
  500. package/src/self-implement/orchestrator.ts +369 -33
  501. package/src/self-implement/pod-inplace-worktree.ts +82 -0
  502. package/src/self-implement/pod-warm-pool-profile.ts +2 -2
  503. package/src/self-implement/premise-review.ts +7 -5
  504. package/src/self-implement/review-round-brief.ts +300 -0
  505. package/src/self-implement/rework-policy.ts +14 -0
  506. package/src/self-implement/run-ledger.ts +428 -6
  507. package/src/self-implement/run-stop.ts +1 -1
  508. package/src/self-implement/running-runs.ts +17 -3
  509. package/src/self-implement/seams.ts +45 -16
  510. package/src/self-implement/self-implement-cli.ts +26 -2
  511. package/src/self-implement/stop-autoheal.ts +1 -0
  512. package/src/self-implement/test-seams.ts +13 -1
  513. package/src/self-implement/train-reach-grouping.ts +8 -2
  514. package/src/session/channel-ask-op-envelope.ts +36 -0
  515. package/src/session/channel-op-reply-route.ts +200 -0
  516. package/src/session/chat.ts +10 -1
  517. package/src/session/id-prefix.ts +60 -0
  518. package/src/session/index.ts +6 -0
  519. package/src/session-runtime/index.ts +18 -23
  520. package/src/skills/runner.ts +7 -3
  521. package/src/skills/tools/dev-harness.ts +2 -2
  522. package/src/skills/tools/pty.ts +5 -0
  523. package/src/skills/tools/schedule-wakeup.ts +1 -6
  524. package/src/status/bar.ts +3 -3
  525. package/src/status/metrics.ts +12 -1
  526. package/src/steward/rejudge-tick.ts +12 -5
  527. package/src/steward/resync-tick.ts +31 -4
  528. package/src/storage/file-lock.ts +17 -4
  529. package/src/task-agent/actions.ts +199 -4
  530. package/src/task-agent/adopt-pr.ts +63 -2
  531. package/src/task-agent/boundary-proof-mapping.ts +12 -0
  532. package/src/task-agent/boundary-proof-producer.ts +147 -0
  533. package/src/task-agent/completion-evidence.ts +2 -1
  534. package/src/task-agent/evidence-command-normalize.ts +42 -0
  535. package/src/task-agent/export-redactions-provision.ts +43 -0
  536. package/src/task-agent/green-close-recipe.ts +239 -0
  537. package/src/task-agent/green-sweep.ts +64 -10
  538. package/src/task-agent/live-moves.ts +48 -3
  539. package/src/task-agent/map-host-adapter.ts +134 -0
  540. package/src/task-agent/map-reduce.ts +158 -0
  541. package/src/task-agent/map-run-ledger.ts +226 -0
  542. package/src/task-agent/parent-host.ts +74 -17
  543. package/src/task-agent/rejudge-on-head.ts +72 -5
  544. package/src/task-agent/repair-cycle.ts +108 -8
  545. package/src/task-agent/repair-next-move.ts +12 -2
  546. package/src/task-agent/repair-worker.ts +37 -1
  547. package/src/task-agent/review-prior-fix.ts +12 -2
  548. package/src/task-agent/shadow.ts +188 -5
  549. package/src/task-agent/task-hand.ts +253 -20
  550. package/src/task-agent/task-parent-role-llm.ts +9 -0
  551. package/src/task-agent/tier-split.ts +40 -5
  552. package/src/task-agent/work-order.ts +53 -2
  553. package/src/task-orchestrator/dispatcher.ts +46 -1
  554. package/src/task-orchestrator/generator-prompt.ts +6 -0
  555. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
  556. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +31 -4
  557. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
  558. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
  559. package/src/task-orchestrator/surfaces/pod-pool.ts +77 -8
  560. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +15 -9
  561. package/src/task-orchestrator/surfaces/self-implement-pod.ts +338 -79
  562. package/src/task-orchestrator/surfaces/self-implement.ts +37 -2
  563. package/src/terminal/session-registry.ts +1 -0
  564. package/src/terminal/terminal-modal-router.ts +156 -0
  565. package/src/testing/linux-env.ts +177 -0
  566. package/src/tool-hints/gate.ts +6 -4
  567. package/src/tool-hints/signals.ts +33 -1
  568. package/src/tui/chat/background-job-status.ts +8 -2
  569. package/src/tui/chat/goal-interim.ts +5 -1
  570. package/src/tui/entry.ts +722 -30
  571. package/src/tui/input/at-picker.ts +55 -0
  572. package/src/tui/sidetab/attach.ts +304 -0
  573. package/src/tui/sidetab/list.ts +176 -0
  574. package/src/tui/sidetab/nl-tool.ts +136 -0
  575. package/src/tui/slash/resume-command.ts +23 -0
  576. package/src/tui/slash/resume.ts +38 -35
  577. package/src/tui/slash/signals.ts +114 -0
  578. package/src/tui/slash/term-next.ts +72 -0
  579. package/src/tui-client/local-chat-turn.ts +31 -9
  580. package/src/user-config.ts +30 -3
  581. package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
  582. package/src/ux-sim/classic-tui-seat-scenarios.ts +158 -4
  583. package/src/ux-sim/fake-gh.ts +174 -0
  584. package/src/ux-sim/fake-kubectl.ts +142 -0
  585. package/src/ux-sim/fake-llm.ts +17 -6
  586. package/src/ux-sim/next-tui-seat-scenarios.ts +176 -6
  587. package/src/ux-sim/resume-picker-device.ts +173 -0
  588. package/src/ux-sim/session-id-seed.ts +60 -0
  589. package/src/ux-sim/skills-tools-shell-device.ts +156 -0
  590. package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
  591. package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
  592. package/src/version/packed-revision.json +1 -1
  593. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +0 -287
  594. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +0 -64
  600. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +0 -36
  601. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +0 -149
  604. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +0 -24
  609. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +0 -24
  612. package/apps/pwa/out/_next/static/chunks/2986.45d7652e4f13557e.js +0 -2
  613. package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +0 -226
  614. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +0 -8
  618. package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +0 -32
  619. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +0 -286
  621. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/3757-180308bc61021b05.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +0 -74
  625. package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +0 -104
  629. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +0 -148
  632. package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +0 -93
  634. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +0 -122
  636. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +0 -79
  641. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +0 -27
  653. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/7481.39f7a4654907bf6e.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/7891.03f910124a737985.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +0 -62
  664. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +0 -90
  666. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +0 -94
  667. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +0 -77
  672. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/9514.131c52cc75fe6439.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/ccae1c4b-0cf414f5eff1b10d.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +0 -1
  739. package/scripts/migrate-monad-to-elanous.ts +0 -195
  740. package/scripts/rebrand-elanous.ts +0 -242
  741. /package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → RrjXTwz-urRAbChP1bX02}/_ssgManifest.js +0 -0
@@ -1,4 +1,6 @@
1
1
  import { ownerMatches, type ChecklistItem } from './checklist.js';
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
3
+ import { dirname } from 'node:path';
2
4
 
3
5
  export interface MergedChecklistPr { number: number; title: string; body: string | null; mergedAt: string }
4
6
  type PrMatchBasis = 'cell-line' | 'title-strong' | 'mention';
@@ -113,35 +115,106 @@ export function landedButYellow(items: readonly ChecklistItem[], prs: readonly M
113
115
  return rows.sort((a, b) => Number(b.newer) - Number(a.newer));
114
116
  }
115
117
 
116
- export interface MergedPrRunResult { status: number | null; stdout: string; stderr: string }
118
+ export interface MergedPrRunResult { status: number | null; stdout: string; stderr: string; timedOut?: boolean }
117
119
  /** One `gh` invocation; resolves when the process exits. */
118
- export type MergedPrRunner = (command: string, args: readonly string[], cwd: string) => Promise<MergedPrRunResult>;
120
+ export type MergedPrRunner = (command: string, args: readonly string[], cwd: string, timeoutMs?: number) => Promise<MergedPrRunResult>;
119
121
 
120
122
  export const MERGED_PR_LIMIT = 400;
121
123
  /** Concurrent `gh pr list` calls once the first page is full (LANDED-YELLOW-FAST · 10-21 prod: 24 sequential calls ≈ 145s). */
122
124
  export const MERGED_PR_CONCURRENCY = 6;
123
125
  const DAY_MS = 86_400_000;
124
126
 
127
+ export interface MergedChecklistFetch {
128
+ prs: MergedChecklistPr[];
129
+ truncated: boolean;
130
+ calls: number;
131
+ /** Set when a time budget stopped the window walk before every window was fetched. */
132
+ stopReason: 'time-budget-exceeded' | undefined;
133
+ /** UTC windows not yet fetched when `stopReason` is set. */
134
+ remainingWindows: string[];
135
+ }
136
+
137
+ const FETCH_CACHE_TTL_MS = 10 * 60_000;
138
+ interface PersistedFetchCache { schema: 1; entries: Record<string, { savedAt: number; result: MergedChecklistFetch }> }
139
+
140
+ function cacheRead(path: string, key: string, nowMs: number): MergedChecklistFetch | undefined {
141
+ try {
142
+ if (!existsSync(path)) return undefined;
143
+ const cache = JSON.parse(readFileSync(path, 'utf8')) as PersistedFetchCache;
144
+ const entry = cache?.schema === 1 ? cache.entries?.[key] : undefined;
145
+ if (!entry || !Number.isFinite(entry.savedAt) || nowMs - entry.savedAt < 0 || nowMs - entry.savedAt >= FETCH_CACHE_TTL_MS) return undefined;
146
+ if (!Array.isArray(entry.result?.prs) || entry.result.stopReason !== undefined) return undefined;
147
+ return { ...entry.result, calls: 0 };
148
+ } catch { return undefined; }
149
+ }
150
+
151
+ function cacheWrite(path: string, key: string, result: MergedChecklistFetch, nowMs: number): void {
152
+ try {
153
+ mkdirSync(dirname(path), { recursive: true });
154
+ let entries: PersistedFetchCache['entries'] = {};
155
+ try {
156
+ const cache = JSON.parse(readFileSync(path, 'utf8')) as PersistedFetchCache;
157
+ if (cache?.schema === 1 && cache.entries && typeof cache.entries === 'object') entries = cache.entries;
158
+ } catch { /* replace an unreadable cache with a fresh one */ }
159
+ for (const [entryKey, entry] of Object.entries(entries)) if (!Number.isFinite(entry.savedAt) || nowMs - entry.savedAt >= FETCH_CACHE_TTL_MS) delete entries[entryKey];
160
+ entries[key] = { savedAt: nowMs, result };
161
+ const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
162
+ writeFileSync(temp, `${JSON.stringify({ schema: 1, entries } satisfies PersistedFetchCache)}\n`, { mode: 0o600 });
163
+ renameSync(temp, path);
164
+ } catch { /* cache is an optimization; a failed write must not fail the read-only command */ }
165
+ }
166
+
125
167
  /**
126
168
  * Merged PRs since `since` (UTC date). One call answers when it returns fewer than the cap. Otherwise the range
127
169
  * splits into UTC-day windows fetched with a concurrency cap; a full window is halved down to one second as before,
128
170
  * and a full one-second window probes one extra row to tell exactly 400 from truncation.
171
+ * With `timeBudgetMs`, each gh request is bounded by the remaining time; a slow initial request or window returns the
172
+ * partial result with `stopReason: 'time-budget-exceeded'` and UTC window starts in `remainingWindows`.
129
173
  * The returned set and the truncation flag match the former sequential bisection; only call shape and time differ.
174
+ * A completed result is cached across CLI processes for ten minutes; a partial (`stopReason`) result is never cached.
130
175
  */
131
176
  export async function fetchMergedChecklistPrs(since: string, now: Date, run: MergedPrRunner, cwd: string,
132
- { concurrency = MERGED_PR_CONCURRENCY }: { concurrency?: number } = {}): Promise<{ prs: MergedChecklistPr[]; truncated: boolean; calls: number }> {
177
+ { concurrency = MERGED_PR_CONCURRENCY, timeBudgetMs, cacheFile }: { concurrency?: number; timeBudgetMs?: number; cacheFile?: string } = {}): Promise<MergedChecklistFetch> {
178
+ const cacheKey = JSON.stringify([since, now.toISOString().slice(0, 10), cwd, concurrency,
179
+ process.env.GH_REPO ?? process.env.GITHUB_REPOSITORY ?? '']);
180
+ const cached = cacheFile ? cacheRead(cacheFile, cacheKey, Date.now()) : undefined;
181
+ if (cached) return cached;
182
+ const deadline = timeBudgetMs === undefined ? undefined : performance.now() + timeBudgetMs;
183
+ const over = (): boolean => deadline !== undefined && performance.now() >= deadline;
184
+ const cacheable = (result: MergedChecklistFetch): MergedChecklistFetch => {
185
+ if (result.stopReason !== undefined || !cacheFile) return result;
186
+ cacheWrite(cacheFile, cacheKey, result, Date.now());
187
+ return result;
188
+ };
133
189
  let calls = 0;
134
- const fetch = async (lower: string, upper?: string, limit = MERGED_PR_LIMIT): Promise<MergedChecklistPr[]> => {
190
+ const fetch = async (lower: string, upper?: string, limit = MERGED_PR_LIMIT): Promise<MergedChecklistPr[] | null> => {
135
191
  const search = `merged:>=${lower}${upper ? ` merged:<${upper}` : ''}`;
192
+ if (over()) return null;
136
193
  calls++;
137
- const r = await run('gh', ['pr', 'list', '--state', 'merged', '--search', search, '--limit', String(limit), '--json', 'number,title,body,mergedAt'], cwd);
194
+ const args = ['pr', 'list', '--state', 'merged', '--search', search, '--limit', String(limit), '--json', 'number,title,body,mergedAt'];
195
+ const remainingMs = deadline === undefined ? undefined : Math.max(1, Math.ceil(deadline - performance.now()));
196
+ let timer: ReturnType<typeof setTimeout> | undefined;
197
+ const request = run('gh', args, cwd, remainingMs);
198
+ let r: MergedPrRunResult | null;
199
+ try {
200
+ r = remainingMs === undefined ? await request : await Promise.race([
201
+ request,
202
+ new Promise<null>((resolve) => { timer = setTimeout(() => resolve(null), remainingMs); }),
203
+ ]);
204
+ } finally { if (timer !== undefined) clearTimeout(timer); }
205
+ if (r === null || r.timedOut) return null;
138
206
  if (r.status !== 0) throw new Error(`병합 PR 조회(gh) 실패 rc=${r.status}: ${(r.stderr || r.stdout).trim().slice(0, 400)}`);
139
207
  const page = JSON.parse(r.stdout.trim()) as MergedChecklistPr[];
140
208
  if (!Array.isArray(page)) throw new Error('병합 PR 조회(gh): 배열이 아니다');
141
209
  return page;
142
210
  };
211
+ const lower = Date.parse(`${since}T00:00:00Z`);
212
+ const upper = Math.max(lower + 1000, Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
213
+ const windows: Array<[number, number]> = [];
214
+ for (let start = lower; start < upper; start += DAY_MS) windows.push([start, Math.min(start + DAY_MS, upper)]);
143
215
  const first = await fetch(since);
144
- if (first.length < MERGED_PR_LIMIT) return { prs: first, truncated: false, calls };
216
+ if (first === null) return cacheable({ prs: [], truncated: false, calls, stopReason: 'time-budget-exceeded', remainingWindows: windows.map(([start]) => new Date(start).toISOString()) });
217
+ if (first.length < MERGED_PR_LIMIT) return cacheable({ prs: first, truncated: false, calls, stopReason: undefined, remainingWindows: [] });
145
218
  // Bounded pool: at most `concurrency` gh processes at once; a failure stops new calls and rejects.
146
219
  let active = 0;
147
220
  let failed: unknown;
@@ -155,14 +228,20 @@ export async function fetchMergedChecklistPrs(since: string, now: Date, run: Mer
155
228
  finally { active--; if (failed !== undefined) for (const wake of waiting.splice(0)) wake(); else waiting.shift()?.(); }
156
229
  };
157
230
  let truncated = false;
231
+ const remainingWindows: string[] = [];
158
232
  const visit = async (start: number, end: number): Promise<MergedChecklistPr[]> => {
159
233
  const from = new Date(start).toISOString();
160
234
  const to = new Date(end).toISOString();
161
- const page = await limited(() => fetch(from, to));
235
+ // The budget is checked when the window actually starts (inside the pool), not when `visit` is mapped —
236
+ // every window is mapped at once, so a check here would run before the first fetch resolves.
237
+ const page = await limited(async () => (over() ? null : fetch(from, to)));
238
+ if (page === null) { remainingWindows.push(from); return []; }
162
239
  if (page.length < MERGED_PR_LIMIT) return page;
163
240
  if (end - start <= 1000) {
164
241
  // The second-precision search cannot be subdivided; probe one extra row to distinguish exactly 400 from a real truncation.
242
+ if (over()) { remainingWindows.push(from); return page.slice(0, MERGED_PR_LIMIT); }
165
243
  const probe = await limited(() => fetch(from, to, MERGED_PR_LIMIT + 1));
244
+ if (probe === null) { remainingWindows.push(from); return page.slice(0, MERGED_PR_LIMIT); }
166
245
  if (probe.length > MERGED_PR_LIMIT) truncated = true;
167
246
  return probe.slice(0, MERGED_PR_LIMIT);
168
247
  }
@@ -170,15 +249,17 @@ export async function fetchMergedChecklistPrs(since: string, now: Date, run: Mer
170
249
  const [left, right] = await Promise.all([visit(start, middle), visit(middle, end)]);
171
250
  return [...left, ...right];
172
251
  };
173
- const lower = Date.parse(`${since}T00:00:00Z`);
174
- const upper = Math.max(lower + 1000, Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
175
- const windows: Array<[number, number]> = [];
176
- for (let start = lower; start < upper; start += DAY_MS) windows.push([start, Math.min(start + DAY_MS, upper)]);
177
252
  const settled = await Promise.allSettled(windows.map(([start, end]) => visit(start, end)));
178
253
  const rejected = settled.find((result): result is PromiseRejectedResult => result.status === 'rejected');
179
254
  if (rejected) throw failed ?? rejected.reason;
180
255
  // Chronological window order, first occurrence wins — the same de-duplication as before.
181
256
  const unique = new Map<number, MergedChecklistPr>();
182
257
  for (const result of settled) for (const pr of (result as PromiseFulfilledResult<MergedChecklistPr[]>).value) if (!unique.has(pr.number)) unique.set(pr.number, pr);
183
- return { prs: [...unique.values()], truncated, calls };
258
+ remainingWindows.sort();
259
+ if (remainingWindows.length) {
260
+ // The broad first page is usable partial evidence if the detailed window walk runs out of budget.
261
+ for (const pr of first) if (!unique.has(pr.number)) unique.set(pr.number, pr);
262
+ truncated = true;
263
+ }
264
+ return cacheable({ prs: [...unique.values()], truncated, calls, stopReason: remainingWindows.length ? 'time-budget-exceeded' : undefined, remainingWindows });
184
265
  }
@@ -7,7 +7,7 @@ import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
7
7
  import { tmpdir } from 'node:os';
8
8
  import { join } from 'node:path';
9
9
  import { debug } from '../debug/log.js';
10
- import { runSelfGateCli, type SelfGateCliOptions, type SelfGateCliResult } from '../self-implement/gate-cli.js';
10
+ import { runSelfGateCliAsync, type SelfGateCliOptions, type SelfGateCliResult } from '../self-implement/gate-cli.js';
11
11
  import { dispatchHeavyCheck, isValidGateHost, type DispatchDeps, type DispatchOptions } from '../self-implement/gate-remote.js';
12
12
  import { latestPublishedPreviousVersion } from '../../scripts/release-loop/unattended-release.js';
13
13
  import { baseVersion, isReleaseVersion } from '../../scripts/release-loop/release-version.js';
@@ -29,6 +29,8 @@ export interface LightRcOptions {
29
29
  /** Run on this machine (the remote child is re-invoked with it). */
30
30
  local?: boolean;
31
31
  shards?: number;
32
+ /** Maximum simultaneously active gate bundles, including per-file RSS samples (default three). */
33
+ shardConcurrency?: number;
32
34
  /** OP FU — pass `--fixed-shard-distribution` to self gate (sorted round-robin into `shards`, no RSS pre-measurement).
33
35
  * Opt-in; absent = the measured planner, unchanged. Also carried to the remote child. */
34
36
  fixedShardDistribution?: boolean;
@@ -71,7 +73,7 @@ export interface LightRcDeps {
71
73
  git?: (args: string[], cwd: string) => { rc: number | null; stdout: string };
72
74
  previousVersion?: (version: string, ledgerRoot?: string) => string;
73
75
  readFile?: (path: string) => string | undefined;
74
- runGate?: (cwd: string, options: SelfGateCliOptions) => SelfGateCliResult;
76
+ runGate?: (cwd: string, options: SelfGateCliOptions) => SelfGateCliResult | Promise<SelfGateCliResult>;
75
77
  dispatch?: (opts: DispatchOptions, deps?: DispatchDeps) => Promise<number>;
76
78
  /** Extra dispatch deps (runner · settings) — tests drive the real dispatch with a fake host. */
77
79
  dispatchDeps?: Omit<DispatchDeps, 'write'>;
@@ -175,6 +177,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
175
177
  if (!isReleaseVersion(version)) throw new Error(`release version must be x.y.z: ${version}`);
176
178
  const shards = opts.shards ?? LIGHT_RC_DEFAULT_SHARDS;
177
179
  if (!Number.isSafeInteger(shards) || shards < 1) throw new Error(`invalid --shards count: ${opts.shards}`);
180
+ if (opts.shardConcurrency !== undefined && (!Number.isSafeInteger(opts.shardConcurrency) || opts.shardConcurrency < 1 || opts.shardConcurrency > 4)) throw new Error(`invalid --shard-concurrency: ${opts.shardConcurrency}`);
178
181
  if (opts.remote !== undefined && !isValidGateHost(opts.remote)) throw new Error(`invalid --remote host: ${opts.remote}`);
179
182
  const log = opts.log ?? ((line: string) => process.stderr.write(`${line}\n`));
180
183
  const cwd = repoRoot(deps);
@@ -195,7 +198,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
195
198
  try {
196
199
  const dir = checkout?.dir ?? cwd;
197
200
  if (checkout) alwaysInclude = readList(dir);
198
- local = (deps.runGate ?? runSelfGateCli)(dir, { base, shards, ...(opts.fixedShardDistribution ? { fixedShardDistribution: true } : {}), alwaysInclude, includeImporterTests: true });
201
+ local = await (deps.runGate ?? runSelfGateCliAsync)(dir, { base, shards, ...(opts.shardConcurrency !== undefined ? { shardConcurrency: opts.shardConcurrency } : {}), ...(opts.fixedShardDistribution ? { fixedShardDistribution: true } : {}), alwaysInclude, includeImporterTests: true });
199
202
  if (opts.rehearsalTui) {
200
203
  const command = async (cmd: string, args: string[], tree: string, limitMs?: number) => {
201
204
  const run = spawnSync(cmd, args, { cwd: tree, encoding: 'utf8', timeout: limitMs });
@@ -212,7 +215,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
212
215
  // Keep the self-gate contract: an unavailable remote leaves this release check unmeasured; do not start a heavy gate locally.
213
216
  tool: 'self-gate', repo: cwd, installPwa: true, refs: [base], json: true, commit: measuredCommit,
214
217
  // The host re-runs this command with --local (and ELANOUS_GATE_REMOTE_CHILD=1), so it never recurses.
215
- remoteArgv: (sha) => ['bun', 'bin/elanous.mjs', 'release', 'light-rc', '--version', version, '--base', sha(base), '--head', measuredCommit, '--shards', String(shards), ...(opts.fixedShardDistribution ? ['--fixed-shard-distribution'] : []), '--local', '--json', ...(opts.rehearsalTui ? ['--rehearsal-tui'] : [])],
218
+ remoteArgv: (sha) => ['bun', 'bin/elanous.mjs', 'release', 'light-rc', '--version', version, '--base', sha(base), '--head', measuredCommit, '--shards', String(shards), ...(opts.shardConcurrency !== undefined ? ['--shard-concurrency', String(opts.shardConcurrency)] : []), ...(opts.fixedShardDistribution ? ['--fixed-shard-distribution'] : []), '--local', '--json', ...(opts.rehearsalTui ? ['--rehearsal-tui'] : [])],
216
219
  flags: { remote: opts.local ? undefined : opts.remote ?? true, local: !!opts.local },
217
220
  runLocal,
218
221
  }, {
@@ -495,7 +495,7 @@ export async function runRehearsalTick(opts: RehearsalOptions = {}, deps: Rehear
495
495
  const introducedCount: number | null = stamp.outcome === 'unmeasured' || stamp.outcome === 'error' ? null : hard.introduced.length;
496
496
  const preexistingCount: number | null = introducedCount === null ? null : hard.preexisting;
497
497
  const totalFailures: number | null = introducedCount === null || preexistingCount === null ? null : introducedCount + preexistingCount;
498
- stamp.summary = oneLine(`hard gate ${hard.outcome} · introduced ${introducedCount ?? 'UNKNOWN'} · preexisting ${preexistingCount ?? 'UNKNOWN'} · total failures ${totalFailures ?? 'UNKNOWN'} · node-b Pod · 12 shards · runId ${hardGateRunId} · evidence ${hardGateLog}${cause ? ` · ${cause}` : ''}`);
498
+ stamp.summary = oneLine(`hard gate ${hard.outcome} · introduced ${introducedCount ?? 'UNKNOWN'} · preexisting ${preexistingCount ?? 'UNKNOWN'} · total failures ${totalFailures ?? 'UNKNOWN'} · 원격 Pod · 12 shards · runId ${hardGateRunId} · evidence ${hardGateLog}${cause ? ` · ${cause}` : ''}`);
499
499
  } else {
500
500
  const shardPlan = opts.shards === undefined ? (deps.shardPlan ?? planRehearsalShards)(plan.version, root, checkout, { ...deps.shardPlanDeps, remoteGate: true }) : undefined;
501
501
  if (shardPlan) stamp.shardPlan = shardPlan;
package/src/repl/index.ts CHANGED
@@ -198,6 +198,7 @@ function buildReplTools(): {
198
198
  specs.push(wakeup.spec);
199
199
  dispatchByName.set(wakeup.spec.name, wakeup.dispatch);
200
200
  }
201
+ (require('../tui/sidetab/nl-tool.js') as typeof import('../tui/sidetab/nl-tool.js')).registerNextSidetabReplTool(specs, dispatchByName, process as unknown as import('../tui/sidetab/nl-tool.js').NextSidetabIpcProcess);
201
202
  const planner = sr.createSearchPlannerState({ maxAutoNarrowCandidates: 2 });
202
203
  const dispatch = async (name: string, args: Record<string, unknown>): Promise<unknown> => {
203
204
  try {
@@ -211,6 +212,14 @@ function buildReplTools(): {
211
212
  searchPlannerState: planner,
212
213
  turnIndex: undefined,
213
214
  ptyDashboardOn: false,
215
+ // Match the CLI agent path: native Agent fallback needs the parent's
216
+ // catalog and dispatcher so children can actually use inherited tools.
217
+ agentHostTools: specs,
218
+ agentDispatchTool: dispatch,
219
+ buildChildToolCatalog: (childCwd: string) => {
220
+ const cli = require('../cli/agent-cli.js') as typeof import('../cli/agent-cli.js');
221
+ return cli.buildCliAgentTools(undefined, undefined, childCwd);
222
+ },
214
223
  getToolRuntime: () => undefined,
215
224
  dispatchToolRuntime: async (n) => ({ error: `runtime unavailable in REPL: ${n}` }),
216
225
  dispatchPluginTool: async (n) => ({ ok: false as const, error: `plugin unavailable in REPL: ${n}` }),
@@ -334,6 +343,7 @@ async function runOneTurn(
334
343
  jsonOutput: boolean,
335
344
  nextTuiDelivery?: { pending: PendingTaskNotification[] },
336
345
  onJsonDelta?: (delta: string) => void,
346
+ onJsonStatus?: (line: string) => void,
337
347
  ): Promise<{ reply: string; provider: string; model: string | null; durationMs: number; logPath: string | null }> {
338
348
  const startedAt = Date.now();
339
349
  const replyChunks: string[] = [];
@@ -366,6 +376,10 @@ async function runOneTurn(
366
376
  userText,
367
377
  systemPrompt,
368
378
  userImages: userImages.length > 0 ? userImages : undefined,
379
+ ...(process.env.ELANOUS_TEST_FAKE_LLM === '1' && Number.isFinite(Number(process.env.ELANOUS_TEST_FAKE_LLM_IDLE_TIMEOUT_MS))
380
+ && Number(process.env.ELANOUS_TEST_FAKE_LLM_IDLE_TIMEOUT_MS) > 0
381
+ ? { llmOpts: { streamIdleTimeoutMs: Number(process.env.ELANOUS_TEST_FAKE_LLM_IDLE_TIMEOUT_MS) } }
382
+ : {}),
369
383
  onDelta: (d) => {
370
384
  if (jsonOutput) {
371
385
  replyChunks.push(d);
@@ -373,6 +387,7 @@ async function runOneTurn(
373
387
  }
374
388
  else process.stdout.write(d);
375
389
  },
390
+ onStatusLine: (line) => { onJsonStatus?.(line); },
376
391
  tools: replToolSpecs,
377
392
  dispatchTool: tools?.dispatch,
378
393
  onToolCall: (call) => {
@@ -777,6 +792,9 @@ export async function runRepl(opts: ReplOpts): Promise<number> {
777
792
  process.env.ELANOUS_NEXT_TUI_STREAM === '1' && typeof turn.id === 'string'
778
793
  ? (delta) => { process.stdout.write(`${JSON.stringify({ event: 'delta', turnId: turn.id, text: delta })}\n`); }
779
794
  : undefined,
795
+ process.env.ELANOUS_NEXT_TUI_STREAM === '1' && typeof turn.id === 'string'
796
+ ? (text) => { process.stdout.write(`${JSON.stringify({ event: 'status', turnId: turn.id, text })}\n`); }
797
+ : undefined,
780
798
  );
781
799
  } catch (error) {
782
800
  if (!backgroundBridge) throw error;
@@ -0,0 +1,133 @@
1
+ // Research-only native fanout. The caller supplies Bloom's question ladder;
2
+ // each axis gets its own direct tool call and evidence stays attributed to it.
3
+ import type { BloomResearchQuestion, ResearchEvidenceEnvelope } from '../auto-research/question-ladder-contract.js';
4
+ import type { WebSearchHit } from '../web-search/provider.js';
5
+
6
+ export interface AxisToolCallPlan {
7
+ questionId: string;
8
+ tool: 'OmniSearch';
9
+ query: string;
10
+ }
11
+
12
+ export interface AxisEvidenceGroup {
13
+ questionId: string;
14
+ evidence: ResearchEvidenceEnvelope[];
15
+ error?: string;
16
+ }
17
+
18
+ export interface AxisFanoutResult {
19
+ plan: AxisToolCallPlan[];
20
+ axes: AxisEvidenceGroup[];
21
+ }
22
+
23
+ export type AxisSearchHit = WebSearchHit & { engine?: string };
24
+ export interface AxisSearchResult {
25
+ hits: AxisSearchHit[];
26
+ errors: string[];
27
+ }
28
+ export type AxisSearch = (query: string) => Promise<AxisSearchHit[] | AxisSearchResult>;
29
+
30
+ export interface AxisFanoutDeps {
31
+ search?: AxisSearch;
32
+ }
33
+
34
+ /** Keep every query attached to the Bloom question that produced it. */
35
+ export function planAxisToolCalls(questions: readonly BloomResearchQuestion[]): AxisToolCallPlan[] {
36
+ return questions.flatMap(question => question.searchTerms
37
+ .map(query => query.trim())
38
+ .filter(Boolean)
39
+ .map(query => ({ questionId: question.id, tool: 'OmniSearch' as const, query })));
40
+ }
41
+
42
+ async function directOmniSearch(query: string): Promise<AxisSearchResult> {
43
+ const { dispatchOmniSearch } = await import('../skills/tools/omni-search.js');
44
+ const hits: AxisSearchHit[] = [];
45
+ const result = await dispatchOmniSearch({ query }, { onSource: hit => { hits.push(hit); } });
46
+ if (Object.keys(result.metadata.perEngine).length === 0) {
47
+ throw new Error('no available web-search providers');
48
+ }
49
+ const errors = Object.entries(result.metadata.perEngine)
50
+ .flatMap(([engine, info]) => info.error ? [`${engine}: ${info.error}`] : []);
51
+ return { hits, errors };
52
+ }
53
+
54
+ function evidenceFromHit(question: BloomResearchQuestion, hit: AxisSearchHit): ResearchEvidenceEnvelope {
55
+ const published = hit.publishedAt;
56
+ const date = published !== undefined && Number.isFinite(published) && published > 0
57
+ ? new Date(published) : undefined;
58
+ const observedAt = date && Number.isFinite(date.getTime()) ? date.toISOString() : undefined;
59
+ return {
60
+ questionId: question.id,
61
+ sourceKind: hit.engine ? `web-search:${hit.engine}` : 'web-search',
62
+ source: hit.url,
63
+ ...(question.requestedWindow ? { requestedWindow: question.requestedWindow } : {}),
64
+ ...(observedAt ? { observedAt } : {}),
65
+ content: [hit.title, hit.snippet].filter(Boolean).join(' — '),
66
+ outcome: hit.snippet ? 'complete' : 'partial',
67
+ truncated: true, // Search snippets are excerpts, not the complete source page.
68
+ };
69
+ }
70
+
71
+ function failedEvidence(question: BloomResearchQuestion, query: string, message: string): ResearchEvidenceEnvelope {
72
+ return {
73
+ questionId: question.id,
74
+ sourceKind: 'search-query',
75
+ source: query,
76
+ ...(question.requestedWindow ? { requestedWindow: question.requestedWindow } : {}),
77
+ content: message,
78
+ outcome: 'failed',
79
+ truncated: false,
80
+ };
81
+ }
82
+
83
+ /** Invoke all axis queries concurrently, preserving ladder order and partial failures. */
84
+ export async function fanOutAxisEvidence(
85
+ questions: readonly BloomResearchQuestion[],
86
+ deps: AxisFanoutDeps = {},
87
+ ): Promise<AxisFanoutResult> {
88
+ const plan = planAxisToolCalls(questions);
89
+ if (new Set(questions.map(question => question.id)).size !== questions.length) {
90
+ throw new Error('research axis question IDs must be unique');
91
+ }
92
+ const search = deps.search ?? directOmniSearch;
93
+ const settled = await Promise.allSettled(plan.map(call => search(call.query)));
94
+ const axes: AxisEvidenceGroup[] = questions.map(question => ({ questionId: question.id, evidence: [] }));
95
+ const groups = new Map(axes.map(axis => [axis.questionId, axis]));
96
+ const byQuestion = new Map(questions.map(question => [question.id, question]));
97
+ for (const question of questions) {
98
+ if (!plan.some(call => call.questionId === question.id)) {
99
+ const group = groups.get(question.id)!;
100
+ group.error = 'no search terms';
101
+ group.evidence.push(failedEvidence(question, question.prompt, group.error));
102
+ }
103
+ }
104
+ settled.forEach((outcome, index) => {
105
+ const call = plan[index]!;
106
+ const group = groups.get(call.questionId)!;
107
+ const question = byQuestion.get(call.questionId)!;
108
+ if (outcome.status === 'fulfilled') {
109
+ const response = Array.isArray(outcome.value) ? { hits: outcome.value, errors: [] } : outcome.value;
110
+ if (response.hits.length === 0 && response.errors.length === 0) {
111
+ group.evidence.push({ ...failedEvidence(question, call.query, 'no hits returned'), outcome: 'partial' });
112
+ }
113
+ for (const hit of response.hits) {
114
+ try {
115
+ group.evidence.push(evidenceFromHit(question, hit));
116
+ } catch (err) {
117
+ const message = err instanceof Error ? err.message : String(err);
118
+ group.error = group.error ? `${group.error}; ${message}` : message;
119
+ group.evidence.push(failedEvidence(question, call.query, message));
120
+ }
121
+ }
122
+ for (const message of response.errors) {
123
+ group.error = group.error ? `${group.error}; ${message}` : message;
124
+ group.evidence.push(failedEvidence(question, call.query, message));
125
+ }
126
+ } else {
127
+ const message = outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason);
128
+ group.error = group.error ? `${group.error}; ${message}` : message;
129
+ group.evidence.push(failedEvidence(question, call.query, message));
130
+ }
131
+ });
132
+ return { plan, axes };
133
+ }
@@ -0,0 +1,88 @@
1
+ import type { GraphNodeSpec } from '../self-implement/graph-yaml.js';
2
+
3
+ /** Opaque Bloom 4/5 output. The hook owns the decision boundary, not analysis policy. */
4
+ export interface BloomEdgeAssessment {
5
+ gaps: readonly unknown[];
6
+ contradictions: readonly unknown[];
7
+ verdicts: readonly unknown[];
8
+ }
9
+
10
+ export type ResearchEdgeAction = 'add' | 'prune' | 'deepen' | 'stop';
11
+
12
+ export interface ResearchEdgeProposal {
13
+ node: GraphNodeSpec;
14
+ returnTo?: string;
15
+ reason: string;
16
+ }
17
+
18
+ export interface ResearchEdgeDecision {
19
+ action: ResearchEdgeAction;
20
+ reason: string;
21
+ evidence: readonly string[];
22
+ proposal?: ResearchEdgeProposal;
23
+ }
24
+
25
+ export interface ResolvedResearchEdgeDecision extends ResearchEdgeDecision {
26
+ provider: string;
27
+ }
28
+
29
+ export type ResearchEdgeDecisionProvider = (
30
+ assessment: BloomEdgeAssessment,
31
+ ) => ResearchEdgeDecision | Promise<ResearchEdgeDecision>;
32
+
33
+ export interface ResearchEdgeDecisionRegistry {
34
+ register(provider: ResearchEdgeDecisionProvider, name?: string): () => void;
35
+ decide(assessment: BloomEdgeAssessment): Promise<ResolvedResearchEdgeDecision>;
36
+ }
37
+
38
+ const noOpDecision: ResearchEdgeDecision = {
39
+ action: 'stop',
40
+ reason: 'no edge decision provider registered',
41
+ evidence: [],
42
+ };
43
+
44
+ /** One registry belongs to one run. With no provider, the graph takes one round and stops. */
45
+ export function createResearchEdgeDecisionRegistry(): ResearchEdgeDecisionRegistry {
46
+ const providers = new Map<symbol, { name: string; decide: ResearchEdgeDecisionProvider }>();
47
+ return {
48
+ register(provider, name = 'registered') {
49
+ const key = Symbol('research-edge-decision-provider');
50
+ providers.set(key, { name, decide: provider });
51
+ return () => { providers.delete(key); };
52
+ },
53
+ async decide(assessment) {
54
+ const provider = [...providers.values()].at(-1);
55
+ if (!provider) return { ...noOpDecision, provider: 'default-noop' };
56
+ try {
57
+ const decision = await provider.decide(assessment);
58
+ if (!isResearchEdgeDecision(decision)) {
59
+ return { action: 'stop', reason: 'edge decision provider returned an invalid decision', evidence: [], provider: provider.name };
60
+ }
61
+ return { ...decision, evidence: [...decision.evidence], provider: provider.name };
62
+ } catch (error) {
63
+ return { action: 'stop', reason: `edge decision provider failed: ${String(error)}`, evidence: [], provider: provider.name };
64
+ }
65
+ },
66
+ };
67
+ }
68
+
69
+ function isResearchEdgeDecision(value: unknown): value is ResearchEdgeDecision {
70
+ if (!isRecord(value) || !['add', 'prune', 'deepen', 'stop'].includes(String(value.action))
71
+ || typeof value.reason !== 'string' || !value.reason.trim()
72
+ || !Array.isArray(value.evidence) || !value.evidence.every((item) => typeof item === 'string')) {
73
+ return false;
74
+ }
75
+ if (value.action === 'add') return isResearchEdgeProposal(value.proposal);
76
+ return value.proposal === undefined;
77
+ }
78
+
79
+ function isResearchEdgeProposal(value: unknown): value is ResearchEdgeProposal {
80
+ return isRecord(value) && isRecord(value.node) && typeof value.node.nodeId === 'string'
81
+ && typeof value.node.kind === 'string' && typeof value.node.recipe === 'string'
82
+ && typeof value.reason === 'string' && value.reason.trim().length > 0
83
+ && (value.returnTo === undefined || typeof value.returnTo === 'string');
84
+ }
85
+
86
+ function isRecord(value: unknown): value is Record<string, unknown> {
87
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
88
+ }
@@ -0,0 +1,127 @@
1
+ import type { SkillIndexEntry } from '../skills/index.js';
2
+ import { getSkillIndex } from '../skills/index.js';
3
+
4
+ export type ResearchQuestionWeight = 'light' | 'medium' | 'heavy';
5
+ export type ResearchOutputFormat = 'text' | 'table' | 'card' | 'web-article' | 'diagram';
6
+ export type ResearchOutputFallbackReason = 'no-matching-skill-in-registry';
7
+
8
+ export interface ResearchOutputRouteInput {
9
+ question: string;
10
+ synthesizedResult: string;
11
+ weight?: ResearchQuestionWeight;
12
+ axes?: readonly string[];
13
+ skills?: readonly SkillIndexEntry[];
14
+ }
15
+
16
+ export interface ResearchOutputRouteDecision {
17
+ weight: ResearchQuestionWeight;
18
+ weightSource: 'caller' | 'estimated';
19
+ format: ResearchOutputFormat;
20
+ skillCallPlan?: { skill: string; args: string };
21
+ fallbackReason?: ResearchOutputFallbackReason;
22
+ observation: {
23
+ resultChars: number;
24
+ axisCount: number;
25
+ estimatedWeight: ResearchQuestionWeight;
26
+ selectedSkill?: string;
27
+ fallback?: ResearchOutputFallbackReason;
28
+ };
29
+ }
30
+
31
+ const OUTPUT_FORMAT_SIGNALS: Record<Exclude<ResearchOutputFormat, 'text'>, readonly string[]> = {
32
+ table: ['comparison table', 'research table', 'data table', 'tabular report', '비교 표', '조사 표'],
33
+ card: ['knowledge card', 'research card', 'summary card', 'flashcard', '지식 카드', '요약 카드'],
34
+ 'web-article': ['web article', 'web publishing', 'html article', 'article publishing', '웹 아티클'],
35
+ diagram: ['diagram', '다이어그램', 'visualization', '시각화', 'chart'],
36
+ };
37
+
38
+ const normalizeMetadata = (value: string): string => value.toLowerCase().replace(/[_-]+/g, ' ').replace(/\s+/g, ' ').trim();
39
+
40
+ function countAxes(axes: readonly string[] | undefined): number {
41
+ return new Set((axes ?? []).map((axis) => normalizeMetadata(axis)).filter(Boolean)).size;
42
+ }
43
+
44
+ export function estimateResearchQuestionWeight(resultChars: number, axisCount: number): ResearchQuestionWeight {
45
+ if (resultChars >= 4_000 || axisCount >= 4) return 'heavy';
46
+ if (resultChars >= 1_200 || axisCount >= 2) return 'medium';
47
+ return 'light';
48
+ }
49
+
50
+ function chooseFormat(weight: ResearchQuestionWeight, axisCount: number): ResearchOutputFormat {
51
+ if (weight === 'light') return 'text';
52
+ if (weight === 'medium') return axisCount >= 2 ? 'table' : 'card';
53
+ return axisCount >= 4 ? 'diagram' : 'web-article';
54
+ }
55
+
56
+ function skillScore(format: Exclude<ResearchOutputFormat, 'text'>, skill: SkillIndexEntry): number {
57
+ const metadata = normalizeMetadata([
58
+ skill.name,
59
+ skill.category ?? '',
60
+ skill.description,
61
+ ...skill.triggers,
62
+ ...skill.extractedTriggers,
63
+ ].join(' '));
64
+ return OUTPUT_FORMAT_SIGNALS[format].reduce((score, signal) => {
65
+ const normalizedSignal = normalizeMetadata(signal);
66
+ return metadata.includes(normalizedSignal) ? score + normalizedSignal.length : score;
67
+ }, 0);
68
+ }
69
+
70
+ function findOutputSkill(
71
+ format: Exclude<ResearchOutputFormat, 'text'>,
72
+ skills: readonly SkillIndexEntry[],
73
+ ): SkillIndexEntry | undefined {
74
+ return skills
75
+ .map((skill) => ({ skill, score: skillScore(format, skill) }))
76
+ .filter((entry) => entry.score > 0)
77
+ .sort((a, b) => b.score - a.score || a.skill.name.localeCompare(b.skill.name))[0]?.skill;
78
+ }
79
+
80
+ function buildSkillArgs(question: string, synthesizedResult: string, format: ResearchOutputFormat): string {
81
+ return [
82
+ `Format the synthesized research output as ${format}.`,
83
+ `Question: ${escapeSkillArgument(question)}`,
84
+ 'Research synthesis:',
85
+ escapeSkillArgument(synthesizedResult),
86
+ ].join('\n\n');
87
+ }
88
+
89
+ /** Keep untrusted research text from closing the XML-like prefill argument block. */
90
+ function escapeSkillArgument(value: string): string {
91
+ return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
92
+ }
93
+
94
+ /** Deterministic output routing. Weight may be supplied by an upstream axis; otherwise it is inferred from synthesis size and distinct axes. */
95
+ export function routeResearchOutput(input: ResearchOutputRouteInput): ResearchOutputRouteDecision {
96
+ const resultChars = input.synthesizedResult.length;
97
+ const axisCount = countAxes(input.axes);
98
+ const estimatedWeight = estimateResearchQuestionWeight(resultChars, axisCount);
99
+ const weight = input.weight ?? estimatedWeight;
100
+ const desiredFormat = chooseFormat(weight, axisCount);
101
+ const observation = { resultChars, axisCount, estimatedWeight };
102
+
103
+ if (desiredFormat === 'text') {
104
+ return { weight, weightSource: input.weight ? 'caller' : 'estimated', format: 'text', observation };
105
+ }
106
+
107
+ const registry = input.skills ?? getSkillIndex();
108
+ const selected = findOutputSkill(desiredFormat, registry);
109
+ if (!selected) {
110
+ const fallbackReason: ResearchOutputFallbackReason = 'no-matching-skill-in-registry';
111
+ return {
112
+ weight,
113
+ weightSource: input.weight ? 'caller' : 'estimated',
114
+ format: 'text',
115
+ fallbackReason,
116
+ observation: { ...observation, fallback: fallbackReason },
117
+ };
118
+ }
119
+
120
+ return {
121
+ weight,
122
+ weightSource: input.weight ? 'caller' : 'estimated',
123
+ format: desiredFormat,
124
+ skillCallPlan: { skill: selected.name, args: buildSkillArgs(input.question, input.synthesizedResult, desiredFormat) },
125
+ observation: { ...observation, selectedSkill: selected.name },
126
+ };
127
+ }