elanous 0.2.38 → 0.2.41

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 (712) hide show
  1. package/README.md +7 -7
  2. package/apps/pwa/out/404/index.html +1 -1
  3. package/apps/pwa/out/404.html +1 -1
  4. package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → GiOLWmt4MqDZePubBjA4Q}/_buildManifest.js +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +149 -0
  6. package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +36 -0
  7. package/apps/pwa/out/_next/static/chunks/1178.1aa9cad0e7695427.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{5203.51e5d8b5f1dcfe53.js → 1219.7e17964e0e7cd8e5.js} +3 -3
  10. package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +287 -0
  11. package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +90 -0
  16. package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{7573.2376e13c9c21f1f8.js → 1765.679b29625c8e88d4.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/{3528.e4b8ab70d339f965.js → 1800.f7ff51dc4978a958.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2073.689dcb2680113d76.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{8879.ac06755bcf3e44a1.js → 2263.e09b6edea33bad2d.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2743.5d3f76948be32b34.js +41 -0
  31. package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +32 -0
  32. package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{9fe1b809.738da85c8b17e3fb.js → 2fdf2931.b431eee4fb468bc3.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/{eaad0cba.771200940c529df7.js → 2fe2c302.41b517f88d6fe502.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +79 -0
  36. package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3230-49298c3b73ef2268.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +74 -0
  41. package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{b7478fef.5917716286213fcc.js → 385e4574.e9886ab32759eda3.js} +3 -3
  46. package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4133.2056bb4d78f621af.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +148 -0
  53. package/apps/pwa/out/_next/static/chunks/{8911.bf5e712acb25fb6c.js → 4527.a69f2894d1bc9f4a.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +226 -0
  55. package/apps/pwa/out/_next/static/chunks/{5307.d7328020227880c2.js → 4667.97e31aa38c95c475.js} +4 -4
  56. package/apps/pwa/out/_next/static/chunks/{6142.913b44e260a3f925.js → 4702.4a4adc1f16d7c93b.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +94 -0
  64. package/apps/pwa/out/_next/static/chunks/{8487.291666583bebe640.js → 5159.115f1c2ca471386c.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/530.d26346e18089640a.js +115 -0
  67. package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +8 -0
  68. package/apps/pwa/out/_next/static/chunks/{89d6c04f-6b8ab341748e468a.js → 53aeb4ee-51c92f8d683f5220.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/{3291.f6c1005387d514bd.js → 5471.1e611302ed3a7c53.js} +2 -2
  70. package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/{3086.fb14b60ce98b53d3.js → 5574.f35accf4f132b29d.js} +1 -1
  73. package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +24 -0
  74. package/apps/pwa/out/_next/static/chunks/{1632.7d87f998e714bede.js → 5744.b9415e18ad623100.js} +1 -1
  75. package/apps/pwa/out/_next/static/chunks/{5300.677c97e0393742e6.js → 5892.2526d962339662d8.js} +1 -1
  76. package/apps/pwa/out/_next/static/chunks/5937.c2df9e3447e1f667.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +286 -0
  78. package/apps/pwa/out/_next/static/chunks/{7161-8f22db3ec5ed005e.js → 5947-135e26537d80a6b9.js} +3 -3
  79. package/apps/pwa/out/_next/static/chunks/{3124-561f7f037943cde2.js → 5964-7e21164a8f2cf0ce.js} +1 -1
  80. package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +27 -0
  84. package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +62 -0
  86. package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +24 -0
  87. package/apps/pwa/out/_next/static/chunks/6874.d5cf7eb8edb2cabe.js +2 -0
  88. package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +122 -0
  90. package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{2415.738b777642a02233.js → 7191.fdc955f7d96064a4.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{1026-44010f405704050c.js → 8050-9b364bdef8f71927.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +104 -0
  103. package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{5638.107314dc479e2f37.js → 9048.212083de42d25be3.js} +2 -2
  110. package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{8019.21ca554a821dad01.js → 9507.7026657a2f47eb64.js} +16 -16
  117. package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +93 -0
  118. package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +34 -0
  123. package/apps/pwa/out/_next/static/chunks/{6493.27ad77de7aac7966.js → 9834.63ab2bbc3153172e.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/{3389.012c70767a872f9b.js → 9869.81a1e24ca682d5a0.js} +1 -1
  125. package/apps/pwa/out/_next/static/chunks/{8994d93e.33ba491f95345fc2.js → a0a01613.6d1cca322238d7fe.js} +1 -1
  126. package/apps/pwa/out/_next/static/chunks/{de8b930d.d94c0f42acf807fc.js → addc2b32.8c4ff8f0aefe987d.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-866aac5ff226a7f3.js → page-14949db884bfa672.js} +1 -1
  132. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-40f9e19149024298.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a142dfb0331a05f5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/b2271e54.c1de3347976e90b0.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/{b7459770.6539b11860eb8a9c.js → c0c1a699.0ba79f97005965d4.js} +7 -7
  180. package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +1 -0
  185. package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +1 -0
  186. package/apps/pwa/out/approvals/index.html +1 -1
  187. package/apps/pwa/out/approvals/index.txt +22 -22
  188. package/apps/pwa/out/autopilot/index.html +1 -1
  189. package/apps/pwa/out/autopilot/index.txt +22 -22
  190. package/apps/pwa/out/board/index.html +1 -1
  191. package/apps/pwa/out/board/index.txt +22 -22
  192. package/apps/pwa/out/botlab/index.html +1 -1
  193. package/apps/pwa/out/botlab/index.txt +21 -21
  194. package/apps/pwa/out/bots/index.html +1 -1
  195. package/apps/pwa/out/bots/index.txt +21 -21
  196. package/apps/pwa/out/ceo/index.html +1 -1
  197. package/apps/pwa/out/ceo/index.txt +22 -22
  198. package/apps/pwa/out/chat/index.html +1 -1
  199. package/apps/pwa/out/chat/index.txt +21 -21
  200. package/apps/pwa/out/consult/index.html +1 -1
  201. package/apps/pwa/out/consult/index.txt +22 -22
  202. package/apps/pwa/out/control/index.html +1 -1
  203. package/apps/pwa/out/control/index.txt +22 -22
  204. package/apps/pwa/out/decisions/index.html +1 -1
  205. package/apps/pwa/out/decisions/index.txt +21 -21
  206. package/apps/pwa/out/design-check/index.html +1 -1
  207. package/apps/pwa/out/design-check/index.txt +22 -22
  208. package/apps/pwa/out/editor/index.html +1 -1
  209. package/apps/pwa/out/editor/index.txt +22 -22
  210. package/apps/pwa/out/exec/index.html +1 -1
  211. package/apps/pwa/out/exec/index.txt +22 -22
  212. package/apps/pwa/out/field/index.html +1 -1
  213. package/apps/pwa/out/field/index.txt +22 -22
  214. package/apps/pwa/out/healthz +1 -1
  215. package/apps/pwa/out/index.html +1 -1
  216. package/apps/pwa/out/index.txt +21 -21
  217. package/apps/pwa/out/inside/index.html +1 -1
  218. package/apps/pwa/out/inside/index.txt +21 -21
  219. package/apps/pwa/out/intake/index.html +1 -1
  220. package/apps/pwa/out/intake/index.txt +22 -22
  221. package/apps/pwa/out/live/index.html +1 -1
  222. package/apps/pwa/out/live/index.txt +22 -22
  223. package/apps/pwa/out/live-run/index.html +1 -1
  224. package/apps/pwa/out/live-run/index.txt +22 -22
  225. package/apps/pwa/out/loops/index.html +1 -1
  226. package/apps/pwa/out/loops/index.txt +21 -21
  227. package/apps/pwa/out/market/index.html +1 -1
  228. package/apps/pwa/out/market/index.txt +21 -21
  229. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  230. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  231. package/apps/pwa/out/morning/index.html +1 -1
  232. package/apps/pwa/out/morning/index.txt +22 -22
  233. package/apps/pwa/out/observatory/index.html +1 -1
  234. package/apps/pwa/out/observatory/index.txt +22 -22
  235. package/apps/pwa/out/ops/checklist/index.html +1 -1
  236. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  237. package/apps/pwa/out/ops/release/index.html +1 -1
  238. package/apps/pwa/out/ops/release/index.txt +21 -21
  239. package/apps/pwa/out/ops/seats/index.html +1 -1
  240. package/apps/pwa/out/ops/seats/index.txt +21 -21
  241. package/apps/pwa/out/outputs/index.html +1 -1
  242. package/apps/pwa/out/outputs/index.txt +21 -21
  243. package/apps/pwa/out/reflection/index.html +1 -1
  244. package/apps/pwa/out/reflection/index.txt +22 -22
  245. package/apps/pwa/out/scheduler/index.html +1 -1
  246. package/apps/pwa/out/scheduler/index.txt +22 -22
  247. package/apps/pwa/out/sessions/index.html +1 -1
  248. package/apps/pwa/out/sessions/index.txt +21 -21
  249. package/apps/pwa/out/settings/devices/index.html +1 -1
  250. package/apps/pwa/out/settings/devices/index.txt +22 -22
  251. package/apps/pwa/out/settings/index.html +1 -1
  252. package/apps/pwa/out/settings/index.txt +22 -22
  253. package/apps/pwa/out/setup/done/index.html +1 -1
  254. package/apps/pwa/out/setup/done/index.txt +22 -22
  255. package/apps/pwa/out/setup/index.html +1 -1
  256. package/apps/pwa/out/setup/index.txt +22 -22
  257. package/apps/pwa/out/share/index.html +1 -1
  258. package/apps/pwa/out/share/index.txt +22 -22
  259. package/apps/pwa/out/showroom/index.html +1 -1
  260. package/apps/pwa/out/showroom/index.txt +21 -21
  261. package/apps/pwa/out/tasks/index.html +1 -1
  262. package/apps/pwa/out/tasks/index.txt +22 -22
  263. package/apps/pwa/out/term/index.html +1 -1
  264. package/apps/pwa/out/term/index.txt +22 -22
  265. package/apps/pwa/out/today/index.html +1 -1
  266. package/apps/pwa/out/today/index.txt +22 -22
  267. package/apps/pwa/out/trace/index.html +1 -1
  268. package/apps/pwa/out/trace/index.txt +22 -22
  269. package/apps/pwa/out/vault/index.html +1 -1
  270. package/apps/pwa/out/vault/index.txt +22 -22
  271. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  272. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  273. package/apps/pwa/out/workflows/index.html +1 -1
  274. package/apps/pwa/out/workflows/index.txt +22 -22
  275. package/apps/pwa/out/workspace/index.html +1 -1
  276. package/apps/pwa/out/workspace/index.txt +22 -22
  277. package/apps/pwa/out/worktrees/index.html +1 -1
  278. package/apps/pwa/out/worktrees/index.txt +22 -22
  279. package/bin/elanous.mjs +6 -1
  280. package/catalog/models/openai/gpt-6.1-sol.yaml +16 -0
  281. package/catalog/models/openai/gpt-6.1-terra.yaml +16 -0
  282. package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
  283. package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
  284. package/graphs/demo/persona-marketer/recipes.yaml +19 -0
  285. package/graphs/demo/persona-teacher/lesson-pack.yaml +16 -0
  286. package/graphs/demo/persona-teacher/recipes.yaml +17 -0
  287. package/graphs/demo/persona-teacher/weekly-lesson.yaml +36 -0
  288. package/graphs/overlays/stop-heal-ladder.yaml +23 -2
  289. package/graphs/release/release-loop.yaml +3 -1
  290. package/graphs/units/gate/gate.yaml +20 -0
  291. package/graphs/units/git/git.yaml +26 -0
  292. package/graphs/units/implement/implement.yaml +19 -0
  293. package/graphs/units/landing/landing.yaml +18 -0
  294. package/graphs/units/review/review.yaml +20 -0
  295. package/graphs/units/verbs/recipes.yaml +3 -0
  296. package/graphs/units/verbs/research.yaml +20 -0
  297. package/graphs/video/explainer-line.yaml +4 -1
  298. package/graphs/work/research-report.yaml +11 -1
  299. package/package.json +1 -1
  300. package/scripts/dead-code/report.ts +169 -0
  301. package/scripts/disk-steward.ts +46 -0
  302. package/scripts/fleet/node-setup.sh +50 -0
  303. package/scripts/graph-units/verbs/research.ts +55 -0
  304. package/scripts/lib/morning-report-options.ts +3 -4
  305. package/scripts/lib/tui-regress-evidence.ts +56 -0
  306. package/scripts/llm-cost-ledger.ts +179 -8
  307. package/scripts/measure-nl-routing-corpus.ts +10 -2
  308. package/scripts/morning-report.ts +5 -1
  309. package/scripts/persona-teacher/weekly-lesson-node.ts +172 -0
  310. package/scripts/public-copy-lint.ts +163 -19
  311. package/scripts/public-export.ts +15 -7
  312. package/scripts/ratchets/train-side-invariants.sh +0 -1
  313. package/scripts/release-loop/export-check-node.ts +21 -3
  314. package/scripts/release-loop/gate-autoheal.ts +117 -0
  315. package/scripts/release-loop/gate-baseline-receipt.ts +8 -1
  316. package/scripts/release-loop/gate-diff.ts +22 -3
  317. package/scripts/release-loop/gate-node.ts +583 -64
  318. package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
  319. package/scripts/release-loop/gate-shard-load-flaky.ts +256 -0
  320. package/scripts/release-loop/gate-shard-receipts.ts +89 -0
  321. package/scripts/release-loop/gate-triage-node.ts +70 -10
  322. package/scripts/release-loop/gate-wall.ts +5 -5
  323. package/scripts/release-loop/preflight.ts +6 -2
  324. package/scripts/release-loop/resume-release.ts +267 -20
  325. package/scripts/release-loop/resume.ts +48 -0
  326. package/scripts/release-loop/traffic-node.ts +6 -3
  327. package/scripts/release-loop/unattended-release.ts +4 -2
  328. package/scripts/release-loop/version-node.ts +7 -2
  329. package/scripts/release-story/draft.ts +1 -1
  330. package/scripts/research-bench/README.md +53 -0
  331. package/scripts/research-bench/questions.json +66 -0
  332. package/scripts/research-bench/rubric.md +33 -0
  333. package/scripts/research-bench/run.ts +523 -0
  334. package/scripts/shadow-authoring-probe.ts +20 -0
  335. package/scripts/tui-regress.ts +85 -10
  336. package/scripts/ux-sim.ts +19 -2
  337. package/src/acp/core-turn-bridge.ts +94 -4
  338. package/src/agent/autonomous-tools.ts +10 -3
  339. package/src/agent/monad-agent-turn.ts +4 -1
  340. package/src/agent/registry.ts +26 -2
  341. package/src/agent/shared-app-tools.ts +1 -1
  342. package/src/agent/surface-ux/build.ts +12 -3
  343. package/src/agent/surface-ux/types.ts +1 -1
  344. package/src/agent/task-notification.ts +75 -6
  345. package/src/agent/types.ts +3 -0
  346. package/src/agent-mission/driver.ts +29 -3
  347. package/src/agent-mission/mission-cli.ts +2 -1
  348. package/src/agent-substrate/review-context-pack.ts +365 -0
  349. package/src/agent-substrate/self-review-cli.ts +291 -20
  350. package/src/ask-user-question/index.ts +6 -0
  351. package/src/ask-user-question/inline-resolver.ts +49 -0
  352. package/src/auto-research/question-ladder-contract.ts +22 -3
  353. package/src/auto-research/research-turn.ts +359 -17
  354. package/src/autopilot/agent-loop.ts +1 -1
  355. package/src/autopilot/discovery/wiki-claim-proposer.ts +22 -1
  356. package/src/autopilot/pty-control-loop.ts +8 -1
  357. package/src/boot/daemon-tools/index.ts +4 -3
  358. package/src/boot/daemon-tools/self-implement.ts +312 -7
  359. package/src/boot/daemon-tools/types.ts +2 -0
  360. package/src/budget/llm-cost.ts +44 -5
  361. package/src/budget/shadow-arms.ts +52 -0
  362. package/src/budget/unified-usage.ts +17 -1
  363. package/src/capture/tui-self-report.ts +14 -0
  364. package/src/chat/index.ts +33 -7
  365. package/src/chat/pickers/state.ts +7 -1
  366. package/src/cli/agent-cli.ts +43 -8
  367. package/src/cli/intake-cli.ts +22 -1
  368. package/src/cli/lesson-cli.ts +19 -3
  369. package/src/cli/log-event-names.ts +6 -0
  370. package/src/cli/mcp-login.ts +8 -18
  371. package/src/cli/msg-cli.ts +57 -1
  372. package/src/cli/pod-cli.ts +17 -2
  373. package/src/cli/pr-land-heavy-remote.ts +15 -9
  374. package/src/cli/pty-takeover-cli.ts +67 -7
  375. package/src/cli/release-cli.ts +79 -7
  376. package/src/cli/repo-cli.ts +2 -1
  377. package/src/cli/sim-cli.ts +7 -1
  378. package/src/cli/tasks-cli.ts +41 -13
  379. package/src/codex/models.ts +30 -15
  380. package/src/control-plane/ledger.ts +21 -4
  381. package/src/core-turn/run-core-turn.ts +47 -3
  382. package/src/core-turn/run-goal-loop.ts +240 -10
  383. package/src/core-turn/types.ts +9 -0
  384. package/src/dashboard/acp-boot.ts +72 -3
  385. package/src/dashboard/chat/acp-chat.ts +2 -2
  386. package/src/dashboard/classic-sigquit.ts +16 -0
  387. package/src/dashboard/index.ts +327 -27
  388. package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
  389. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
  390. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  391. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  392. package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
  393. package/src/dashboard/input/external-input-host.ts +2 -0
  394. package/src/dashboard/sidetab-runtime.ts +228 -0
  395. package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
  396. package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -8
  397. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
  398. package/src/dashboard/term-slash-runtime.ts +16 -18
  399. package/src/dashboard/turn-preamble.ts +14 -1
  400. package/src/disk-steward/judge.ts +73 -0
  401. package/src/disk-steward/ledger.ts +122 -0
  402. package/src/disk-steward/steward.ts +373 -0
  403. package/src/domains/guardian-tick.ts +191 -2
  404. package/src/domains/knowledge.ts +1 -1
  405. package/src/esc-abort-gate.ts +33 -1
  406. package/src/execution-loop/launch-gate.ts +206 -1
  407. package/src/graph-runner/graph-cli.ts +27 -4
  408. package/src/graph-runner/in-process-registry.ts +37 -0
  409. package/src/graph-runner/runner.ts +63 -11
  410. package/src/graph-wizard/generate.ts +16 -7
  411. package/src/graph-wizard/mission-compose.ts +201 -0
  412. package/src/grok/agent-search.ts +8 -2
  413. package/src/grok/credential.ts +5 -0
  414. package/src/grounding/ref-index.ts +30 -0
  415. package/src/grounding/ref-vector.ts +61 -0
  416. package/src/grounding/sources-cli.ts +11 -3
  417. package/src/grounding/sources.ts +15 -1
  418. package/src/harness/harness-cli-command.ts +305 -23
  419. package/src/harness/harness-incidents.ts +312 -7
  420. package/src/harness/harness-pod-dispatch.ts +7 -1
  421. package/src/harness/harness-space.ts +15 -1
  422. package/src/harness/progress-worker-entry.ts +59 -0
  423. package/src/harness/progress-worker-runtime.ts +11 -0
  424. package/src/index.ts +35 -5
  425. package/src/input/external-input-queue.ts +10 -0
  426. package/src/instance/dev-project.ts +25 -0
  427. package/src/intake-plane/collect-telegram-saved.ts +36 -1
  428. package/src/intake-plane/intake-to-tasks.ts +246 -3
  429. package/src/intelligence-map/model-alias.ts +6 -5
  430. package/src/intelligence-map/model-catalog.ts +59 -2
  431. package/src/lessons/friction-ledger.ts +154 -0
  432. package/src/live-supply/collector.ts +149 -0
  433. package/src/live-supply/probes.ts +52 -0
  434. package/src/live-supply/snapshot.ts +40 -0
  435. package/src/llm/model-defaults.ts +4 -4
  436. package/src/llm.ts +473 -87
  437. package/src/loops/orchestrator/tick.ts +56 -0
  438. package/src/mcp/mcp-oauth.ts +3 -1
  439. package/src/model-tier/llm-tier-map.ts +9 -9
  440. package/src/model-tier/turn-tier.ts +1 -1
  441. package/src/msg/msg-mirror-github.ts +80 -0
  442. package/src/msg/msg-mirror-policy.ts +61 -0
  443. package/src/msg/msg-mirror-runner.ts +219 -0
  444. package/src/msg/msg-mirror-state.ts +33 -0
  445. package/src/msg/msg-store.ts +11 -0
  446. package/src/nexus/api/harness-api.ts +2 -1
  447. package/src/output-truncation.ts +41 -12
  448. package/src/project/project-store.ts +48 -1
  449. package/src/pty/snapshot.py +132 -0
  450. package/src/pty-shell/pty-control-ipc.ts +29 -2
  451. package/src/pty-shell/pty-manifest.ts +59 -3
  452. package/src/pty-shell/registry.ts +2 -0
  453. package/src/pty-shell/tui-run-state.ts +80 -3
  454. package/src/release-loop/gate-host-reservation.ts +157 -4
  455. package/src/release-loop/gate-shard-ledger.ts +68 -0
  456. package/src/release-loop/merged-pr-checklist.ts +25 -2
  457. package/src/release-loop/rehearsal-shard-plan.ts +6 -1
  458. package/src/release-loop/rehearsal.ts +27 -0
  459. package/src/release-loop/release-schedule.ts +90 -1
  460. package/src/research/bloom-exemplars.ts +135 -0
  461. package/src/research/edge-decision.ts +124 -15
  462. package/src/research/gap-followup.ts +249 -0
  463. package/src/research/lenses/counter-evidence.ts +100 -0
  464. package/src/research/lenses/working-backwards.ts +89 -0
  465. package/src/research/plugin-discovery.ts +242 -0
  466. package/src/research-bridge/invoke.ts +4 -2
  467. package/src/research-bridge/types.ts +2 -0
  468. package/src/self-dev/ask-launch-flow.ts +73 -131
  469. package/src/self-dev/dev-cli.ts +19 -17
  470. package/src/self-dev/dev-pipeline.ts +8 -4
  471. package/src/self-dev/graph-front-nodes.ts +23 -0
  472. package/src/self-dev/graph-journey-route.ts +10 -2
  473. package/src/self-dev/launch-preflight-text.ts +2 -2
  474. package/src/self-dev/launch-preflight.ts +47 -11
  475. package/src/self-dev/orchestrate-cli.ts +1 -0
  476. package/src/self-dev/orchestrate.ts +15 -0
  477. package/src/self-dev/run-supervisor.ts +204 -3
  478. package/src/self-dev/run-types.ts +3 -0
  479. package/src/self-implement/device-first.ts +8 -2
  480. package/src/self-implement/doctor-visit.ts +76 -58
  481. package/src/self-implement/gate-artifacts.ts +16 -0
  482. package/src/self-implement/gate-baseline.ts +75 -4
  483. package/src/self-implement/gate-cli.ts +368 -30
  484. package/src/self-implement/gate-receipt-registry.ts +180 -0
  485. package/src/self-implement/gate-remote.ts +165 -24
  486. package/src/self-implement/goal-author-clarification.ts +205 -32
  487. package/src/self-implement/goal-author-decompose.ts +24 -15
  488. package/src/self-implement/goal-author.ts +86 -10
  489. package/src/self-implement/graph-stage-units.ts +172 -0
  490. package/src/self-implement/graph-templates.ts +162 -1
  491. package/src/self-implement/graph-variant.ts +37 -4
  492. package/src/self-implement/host-regate.ts +124 -49
  493. package/src/self-implement/impl-findings-feedback.ts +188 -0
  494. package/src/self-implement/knowhow-pack.ts +227 -10
  495. package/src/self-implement/off-diff-evidence.ts +124 -0
  496. package/src/self-implement/orchestrator.ts +320 -28
  497. package/src/self-implement/run-ledger.ts +110 -14
  498. package/src/self-implement/run-stop.ts +33 -2
  499. package/src/self-implement/running-runs.ts +35 -12
  500. package/src/self-implement/seams.ts +6 -3
  501. package/src/self-implement/self-implement-cli.ts +40 -6
  502. package/src/self-implement/stop-autoheal-operational.ts +43 -0
  503. package/src/self-implement/stop-autoheal.ts +15 -6
  504. package/src/session/chat.ts +66 -15
  505. package/src/session/request-size-guard.ts +123 -0
  506. package/src/session-runtime/provider-circuit.ts +140 -0
  507. package/src/shell-runner/file-engine.ts +1 -0
  508. package/src/shell-runner/types.ts +4 -0
  509. package/src/sidetab-core/model.ts +312 -0
  510. package/src/skills/tools/schedule-wakeup.ts +23 -1
  511. package/src/skills/tools/shell.ts +51 -5
  512. package/src/steward/directive-audit.ts +354 -0
  513. package/src/surface/child-process.ts +31 -0
  514. package/src/surface/tui-stderr-owner.ts +48 -0
  515. package/src/task-agent/cover.ts +30 -12
  516. package/src/task-agent/judge.ts +56 -0
  517. package/src/task-agent/parent-host.ts +14 -1
  518. package/src/task-agent/postland-card.ts +35 -2
  519. package/src/task-agent/rejudge-on-head.ts +46 -2
  520. package/src/task-agent/repair-cycle.ts +1 -1
  521. package/src/task-agent/task-hand.ts +133 -25
  522. package/src/task-agent/tier-split.ts +105 -21
  523. package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
  524. package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
  525. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +70 -2
  526. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +29 -4
  527. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
  528. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
  529. package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
  530. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
  531. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
  532. package/src/task-orchestrator/surfaces/self-implement-pod.ts +298 -45
  533. package/src/task-orchestrator/surfaces/self-implement.ts +18 -0
  534. package/src/tool-runtime/skill-exec-runtime.ts +95 -5
  535. package/src/tui/entry.ts +25 -5
  536. package/src/tui/inline-choice.ts +188 -0
  537. package/src/tui/sidetab/list.ts +36 -165
  538. package/src/tui/sidetab/nl-tool.ts +2 -136
  539. package/src/tui/sidetab/peek.ts +52 -0
  540. package/src/tui/slash/term.ts +12 -1
  541. package/src/tui-client/dashboard-session.ts +10 -1
  542. package/src/user-config.ts +45 -9
  543. package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
  544. package/src/ux-sim/fake-land-queue.ts +88 -0
  545. package/src/ux-sim/fault-needs-human-reason-repair.ts +107 -0
  546. package/src/ux-sim/fault-pod-child-result.ts +42 -0
  547. package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
  548. package/src/ux-sim/goal-interim-trace.ts +24 -0
  549. package/src/ux-sim/next-tui-seat-scenarios.ts +8 -13
  550. package/src/ux-sim/release-sim-rig.ts +262 -0
  551. package/src/ux-sim/seminar-rehearsal.ts +109 -0
  552. package/src/ux-sim/subagent-tools-device.ts +2 -2
  553. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
  554. package/src/version/packed-revision.json +1 -1
  555. package/src/video-pipeline/recipes/explainer.ts +54 -2
  556. package/src/web-search/grok.ts +32 -6
  557. package/src/web-search/index.ts +8 -7
  558. package/src/workflow-runtime/node-catalog.ts +53 -4
  559. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +0 -27
  560. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +0 -148
  567. package/apps/pwa/out/_next/static/chunks/2104.70e086d5174a4736.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +0 -93
  571. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +0 -104
  572. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +0 -24
  581. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +0 -36
  583. package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +0 -287
  586. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +0 -94
  592. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4199-f7c6eb40cd0322f8.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +0 -32
  604. package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +0 -90
  605. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +0 -79
  607. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +0 -74
  610. package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +0 -286
  614. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +0 -8
  617. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +0 -62
  629. package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7488.966b116789f3d41a.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7524.ce973525d30b3d52.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/7628.6b16863ac3972333.js +0 -34
  636. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/7954.4f7a8832663ee979.js +0 -115
  639. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +0 -149
  647. package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +0 -41
  648. package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +0 -226
  649. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +0 -24
  650. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +0 -2
  654. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/bb6987f9.3647e1a23b0e3217.js +0 -122
  705. package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +0 -1
  711. package/scripts/ratchets/next-tui-entry-budget.ts +0 -124
  712. /package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → GiOLWmt4MqDZePubBjA4Q}/_ssgManifest.js +0 -0
@@ -0,0 +1,262 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import { getTestStateRoot } from '../nexus/paths.js';
5
+ import { listGraphRuns, runGraph, type GraphRunState } from '../graph-runner/runner.js';
6
+ import { resolveScenarioFilePath } from './scenario.js';
7
+
8
+ const REPOSITORY_ROOT = join(import.meta.dir, '../..');
9
+ const RELEASE_GRAPH = join(REPOSITORY_ROOT, 'graphs/release/release-loop.yaml');
10
+ const CUT_TIP = 'a'.repeat(40);
11
+
12
+ export interface ReleaseSimRigCase {
13
+ id: string;
14
+ mode?: 'baseline' | 'cut-tip-moved-after-resume';
15
+ fault?: { node: string; outcome: 'fail' | 'error' | 'timeout'; evidence?: Record<string, unknown> };
16
+ expect: { status: 'done' | 'failed' | 'resume-refused'; mustVisit: string[]; mustNotVisit: string[] };
17
+ }
18
+
19
+ export interface ReleaseSimRigScenario {
20
+ version: 1;
21
+ kind: 'release-graph';
22
+ id: string;
23
+ isolation: 'test';
24
+ input: { version: string; previousVersion: string };
25
+ cases: ReleaseSimRigCase[];
26
+ }
27
+
28
+ export interface ReleaseSimRigCaseResult {
29
+ id: string;
30
+ pass: boolean;
31
+ status: string;
32
+ path: string[];
33
+ dispatchedNodes: string[];
34
+ unexpectedEdges: Array<{ from: string; to: string; outcome: string; expectedTo?: string }>;
35
+ checks: { status: boolean; mustVisit: boolean; mustNotVisit: boolean; ledgerEvents: boolean };
36
+ injectedEvidence: Record<string, unknown>;
37
+ ledgerEvents: Array<Record<string, unknown>>;
38
+ statePath: string;
39
+ refusal?: string;
40
+ }
41
+
42
+ function unexpectedEdges(path: string[], state: GraphRunState, edges: Map<string, Record<string, unknown>>): ReleaseSimRigCaseResult['unexpectedEdges'] {
43
+ const nodes = new Map(state.nodes.map((node) => [node.nodeId, node]));
44
+ const issues: ReleaseSimRigCaseResult['unexpectedEdges'] = [];
45
+ for (let index = 0; index + 1 < path.length; index++) {
46
+ const from = path[index]!;
47
+ const to = path[index + 1]!;
48
+ const edge = edges.get(from);
49
+ const output = nodes.get(from)?.output;
50
+ let parsed: Record<string, unknown> = {};
51
+ if (typeof output === 'string') {
52
+ try { parsed = record(JSON.parse(output.trim().split('\n').at(-1) ?? ''), `${from} output`); } catch { /* use runner fallback below */ }
53
+ } else if (output && typeof output === 'object' && !Array.isArray(output)) parsed = output as Record<string, unknown>;
54
+ const named = typeof parsed.outcome === 'string' ? parsed.outcome : nodes.get(from)?.ok ? 'ok' : 'fail';
55
+ const map = edge?.map && typeof edge.map === 'object' ? edge.map as Record<string, unknown> : {};
56
+ const expectedTo = typeof map[named] === 'string' ? map[named] as string : typeof map[named === 'ok' ? 'ok' : 'fail'] === 'string'
57
+ ? map[named === 'ok' ? 'ok' : 'fail'] as string : undefined;
58
+ if (expectedTo !== to) issues.push({ from, to, outcome: named, ...(expectedTo ? { expectedTo } : {}) });
59
+ }
60
+ return issues;
61
+ }
62
+
63
+ function recordObservedEdges(path: string[], events: Array<Record<string, unknown>>): void {
64
+ for (let index = 0; index + 1 < path.length; index++) {
65
+ events.push({ event: 'edge-observed', from: path[index], to: path[index + 1], source: 'release-run-path' });
66
+ }
67
+ }
68
+
69
+ export interface ReleaseSimRigResult {
70
+ id: string;
71
+ pass: boolean;
72
+ universe: string;
73
+ cases: ReleaseSimRigCaseResult[];
74
+ table: Array<{ scenario: string; path: string; status: string; unexpectedEdges: string }>;
75
+ artifactPath: string;
76
+ }
77
+
78
+ function record(value: unknown, where: string): Record<string, unknown> {
79
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${where} must be an object`);
80
+ return value as Record<string, unknown>;
81
+ }
82
+
83
+ function exactKeys(value: Record<string, unknown>, allowed: readonly string[], where: string): void {
84
+ const extra = Object.keys(value).filter((key) => !allowed.includes(key));
85
+ if (extra.length) throw new Error(`${where} has unsupported key(s): ${extra.join(', ')}`);
86
+ }
87
+
88
+ function stringList(value: unknown, where: string): string[] {
89
+ if (!Array.isArray(value) || value.some((item) => typeof item !== 'string' || item.trim() === '')) {
90
+ throw new Error(`${where} must be an array of non-empty strings`);
91
+ }
92
+ return value as string[];
93
+ }
94
+
95
+ function releaseGraphShape(): { nodeIds: Set<string>; edges: Map<string, Record<string, unknown>> } {
96
+ const graph = record(parseYaml(readFileSync(RELEASE_GRAPH, 'utf8')), 'release graph');
97
+ if (!Array.isArray(graph.nodes) || !Array.isArray(graph.edges)) throw new Error('release graph nodes or edges missing');
98
+ const nodeIds = new Set(graph.nodes.map((value) => record(value, 'release graph node').node_id)
99
+ .filter((id): id is string => typeof id === 'string'));
100
+ const edges = new Map<string, Record<string, unknown>>();
101
+ for (const raw of graph.edges) {
102
+ const edge = record(raw, 'release edge');
103
+ if (typeof edge.from !== 'string' || edge.on !== 'outcome' || !edge.map || typeof edge.map !== 'object') {
104
+ throw new Error('release simulation requires outcome edges with explicit maps');
105
+ }
106
+ if (edges.has(edge.from)) throw new Error(`release graph has multiple outcome edges from ${edge.from}`);
107
+ edges.set(edge.from, edge);
108
+ }
109
+ return { nodeIds, edges };
110
+ }
111
+
112
+ export function parseReleaseSimRigScenario(source: string): ReleaseSimRigScenario {
113
+ const root = record(parseYaml(source), 'release simulation scenario');
114
+ exactKeys(root, ['version', 'kind', 'id', 'isolation', 'input', 'cases'], 'release simulation scenario');
115
+ if (root.version !== 1 || root.kind !== 'release-graph' || root.isolation !== 'test') {
116
+ throw new Error('release simulation scenario requires version: 1, kind: release-graph, isolation: test');
117
+ }
118
+ if (typeof root.id !== 'string' || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(root.id)) throw new Error('scenario.id must be lowercase letters, digits, and hyphens');
119
+ const input = record(root.input, 'scenario.input');
120
+ exactKeys(input, ['version', 'previousVersion'], 'scenario.input');
121
+ if (typeof input.version !== 'string' || !/^\d+\.\d+\.\d+$/.test(input.version)
122
+ || typeof input.previousVersion !== 'string' || !/^\d+\.\d+\.\d+$/.test(input.previousVersion)) {
123
+ throw new Error('scenario.input requires release version and previousVersion');
124
+ }
125
+ const rawCases = root.cases;
126
+ if (!Array.isArray(rawCases) || rawCases.length === 0 || rawCases.length > 32) throw new Error('scenario.cases must contain 1–32 cases');
127
+ const { nodeIds } = releaseGraphShape();
128
+ const ids = new Set<string>();
129
+ const cases = rawCases.map((raw, index): ReleaseSimRigCase => {
130
+ const row = record(raw, `scenario.cases[${index}]`);
131
+ exactKeys(row, ['id', 'mode', 'fault', 'expect'], `scenario.cases[${index}]`);
132
+ if (typeof row.id !== 'string' || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(row.id) || ids.has(row.id)) throw new Error(`scenario.cases[${index}].id must be unique lowercase text`);
133
+ ids.add(row.id);
134
+ let mode: ReleaseSimRigCase['mode'];
135
+ if (row.mode !== undefined) {
136
+ if (row.mode !== 'baseline' && row.mode !== 'cut-tip-moved-after-resume') throw new Error(`scenario.cases[${index}].mode is unregistered`);
137
+ mode = row.mode;
138
+ }
139
+ let fault: ReleaseSimRigCase['fault'];
140
+ if (row.fault !== undefined) {
141
+ const parsed = record(row.fault, `scenario.cases[${index}].fault`);
142
+ exactKeys(parsed, ['node', 'outcome', 'evidence'], `scenario.cases[${index}].fault`);
143
+ if (typeof parsed.node !== 'string' || !nodeIds.has(parsed.node)) throw new Error(`scenario.cases[${index}].fault.node is not in the release graph`);
144
+ if (parsed.outcome !== 'fail' && parsed.outcome !== 'error' && parsed.outcome !== 'timeout') throw new Error(`scenario.cases[${index}].fault.outcome is unregistered`);
145
+ fault = { node: parsed.node, outcome: parsed.outcome, ...(parsed.evidence === undefined ? {} : { evidence: record(parsed.evidence, `scenario.cases[${index}].fault.evidence`) }) };
146
+ }
147
+ if ((mode === undefined) === (fault === undefined)) throw new Error(`scenario.cases[${index}] requires exactly one of mode or fault`);
148
+ const expected = record(row.expect, `scenario.cases[${index}].expect`);
149
+ exactKeys(expected, ['status', 'mustVisit', 'mustNotVisit'], `scenario.cases[${index}].expect`);
150
+ if (expected.status !== 'done' && expected.status !== 'failed' && expected.status !== 'resume-refused') throw new Error(`scenario.cases[${index}].expect.status is invalid`);
151
+ const mustVisit = stringList(expected.mustVisit, `scenario.cases[${index}].expect.mustVisit`);
152
+ const mustNotVisit = stringList(expected.mustNotVisit, `scenario.cases[${index}].expect.mustNotVisit`);
153
+ for (const id of [...mustVisit, ...mustNotVisit]) if (!nodeIds.has(id)) throw new Error(`scenario.cases[${index}] names unknown release node ${id}`);
154
+ if (mustVisit.some((id) => mustNotVisit.includes(id))) throw new Error(`scenario.cases[${index}] visits and excludes the same node`);
155
+ return { id: row.id, ...(mode ? { mode } : {}), ...(fault ? { fault } : {}), expect: { status: expected.status, mustVisit, mustNotVisit } };
156
+ });
157
+ return { version: 1, kind: 'release-graph', id: root.id, isolation: 'test',
158
+ input: { version: input.version, previousVersion: input.previousVersion }, cases };
159
+ }
160
+
161
+ function parseContext(env: NodeJS.ProcessEnv): { nodeId: string } {
162
+ const location = env.ELANOUS_GRAPH_CONTEXT;
163
+ if (!location) throw new Error('ELANOUS_GRAPH_CONTEXT missing in release simulation');
164
+ const context = record(JSON.parse(readFileSync(location, 'utf8')), 'release graph context');
165
+ if (typeof context.nodeId !== 'string') throw new Error('release graph context nodeId missing');
166
+ return { nodeId: context.nodeId };
167
+ }
168
+
169
+ function resultForNode(nodeId: string, fault: ReleaseSimRigCase['fault'], version: string): { exitCode: number; stdout: string; stderr: string; evidence: Record<string, unknown> } {
170
+ const triggeredFault = fault?.node === nodeId ? fault : undefined;
171
+ const outcome = triggeredFault ? triggeredFault.outcome === 'timeout' ? 'error' : triggeredFault.outcome : 'ok';
172
+ const evidence = triggeredFault?.evidence ?? {};
173
+ const commit = nodeId === 'version-release' ? { commit: CUT_TIP, tag: `v${version}` } : {};
174
+ const payload = { outcome, verdict: outcome === 'ok' ? 'pass' : 'fail', summary: triggeredFault ? `simulated ${triggeredFault.outcome}` : `simulated ${nodeId} success`, ...commit,
175
+ simulation: { injected: triggeredFault !== undefined, node: nodeId, evidence } };
176
+ return { exitCode: !triggeredFault ? 0 : triggeredFault.outcome === 'fail' ? 1 : triggeredFault.outcome === 'timeout' ? 124 : 2,
177
+ stdout: `${JSON.stringify(payload)}\n`, stderr: triggeredFault ? `SIMULATED_${triggeredFault.outcome.toUpperCase()}` : '', evidence };
178
+ }
179
+
180
+ async function runCase(scenario: ReleaseSimRigScenario, item: ReleaseSimRigCase, root: string,
181
+ edges: Map<string, Record<string, unknown>>): Promise<ReleaseSimRigCaseResult> {
182
+ const runId = `release-sim-${scenario.id}-${item.id}`;
183
+ const ledgerEvents: Array<Record<string, unknown>> = [];
184
+ const dispatchedNodes: string[] = [];
185
+ const runBash = async (command: string, options: { env?: NodeJS.ProcessEnv }) => {
186
+ const { nodeId } = parseContext(options.env ?? {});
187
+ if (!command.trim()) throw new Error(`empty command at simulated node ${nodeId}`);
188
+ dispatchedNodes.push(nodeId);
189
+ const result = resultForNode(nodeId, item.fault, scenario.input.version);
190
+ return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
191
+ };
192
+ const capture = (event: string, data: Record<string, unknown>) => ledgerEvents.push({ event, ...data });
193
+
194
+ if (item.mode === 'cut-tip-moved-after-resume') {
195
+ let beforeNode = 0;
196
+ const simulatedStop = new Error('simulated runner stop after cut');
197
+ try {
198
+ await runGraph(RELEASE_GRAPH, { runId, input: scenario.input, pinChildUniverse: true, quiet: true,
199
+ deps: { root, runBash, log: capture, beforeNode: () => { if (++beforeNode === 2) throw simulatedStop; } } });
200
+ } catch (error) {
201
+ if (error !== simulatedStop) throw error;
202
+ }
203
+ let refusal = '';
204
+ try {
205
+ await runGraph(RELEASE_GRAPH, { resumeRunId: runId, pinChildUniverse: true, quiet: true,
206
+ releaseCommandSource: { root: REPOSITORY_ROOT, cutTip: 'b'.repeat(40), git: () => { throw new Error('git must not be consulted after the saved tip differs'); } },
207
+ deps: { root, runBash, log: capture } });
208
+ } catch (error) { refusal = error instanceof Error ? error.message : String(error); }
209
+ const interrupted = listGraphRuns(root).runs.find((run) => run.runId === runId);
210
+ const stateFile = interrupted?.statePath ?? '';
211
+ const path = interrupted?.path ?? [];
212
+ recordObservedEdges(path, ledgerEvents);
213
+ const edgeIssues = interrupted ? unexpectedEdges(path, interrupted, edges) : [];
214
+ const statusOk = item.expect.status === 'resume-refused' && refusal.includes('release command source differs from the saved cut tip');
215
+ const visitOk = item.expect.mustVisit.every((id) => path.includes(id));
216
+ const notVisitOk = item.expect.mustNotVisit.every((id) => !path.includes(id));
217
+ const ledgerOk = ledgerEvents.some((row) => row.event === 'node-end')
218
+ && ledgerEvents.filter((row) => row.event === 'edge-observed').length === Math.max(0, path.length - 1);
219
+ return { id: item.id, pass: statusOk && visitOk && notVisitOk && ledgerOk && edgeIssues.length === 0, status: statusOk ? 'resume-refused' : interrupted?.status ?? 'missing',
220
+ path, dispatchedNodes, unexpectedEdges: edgeIssues, checks: { status: statusOk, mustVisit: visitOk, mustNotVisit: notVisitOk, ledgerEvents: ledgerOk }, injectedEvidence: {}, ledgerEvents,
221
+ statePath: stateFile, ...(refusal ? { refusal } : {}) };
222
+ }
223
+
224
+ // Initial runs have no releaseCommandSource (the runner only accepts it on resume); all node shell work is intercepted here.
225
+ const state = await runGraph(RELEASE_GRAPH, { runId, input: scenario.input, pinChildUniverse: true, quiet: true,
226
+ deps: { root, runBash, log: capture } });
227
+ const path = state.path;
228
+ recordObservedEdges(path, ledgerEvents);
229
+ const edgeIssues = unexpectedEdges(path, state, edges);
230
+ const statusOk = state.status === item.expect.status;
231
+ const visitOk = item.expect.mustVisit.every((id) => path.includes(id));
232
+ const notVisitOk = item.expect.mustNotVisit.every((id) => !path.includes(id));
233
+ const ledgerOk = ledgerEvents.some((row) => row.event === 'node-start') && ledgerEvents.some((row) => row.event === 'node-end')
234
+ && ledgerEvents.filter((row) => row.event === 'edge-observed').length === Math.max(0, path.length - 1);
235
+ const injectedEvidence = item.fault ? item.fault.evidence ?? {} : {};
236
+ return { id: item.id, pass: statusOk && visitOk && notVisitOk && ledgerOk && edgeIssues.length === 0, status: state.status, path, dispatchedNodes, unexpectedEdges: edgeIssues,
237
+ checks: { status: statusOk, mustVisit: visitOk, mustNotVisit: notVisitOk, ledgerEvents: ledgerOk }, injectedEvidence,
238
+ ledgerEvents, statePath: state.statePath };
239
+ }
240
+
241
+ export async function runReleaseSimRigScenario(source: string): Promise<ReleaseSimRigResult> {
242
+ const scenario = parseReleaseSimRigScenario(source);
243
+ const root = getTestStateRoot();
244
+ if (!root) throw new Error('release simulation rig requires --test isolated mode');
245
+ const { edges } = releaseGraphShape();
246
+ const cases = [];
247
+ for (const item of scenario.cases) cases.push(await runCase(scenario, item, root, edges));
248
+ const result: ReleaseSimRigResult = { id: scenario.id, pass: cases.every((item) => item.pass), universe: root, cases,
249
+ table: cases.map((item) => ({ scenario: item.id, path: item.path.join(' → '), status: item.status,
250
+ unexpectedEdges: item.unexpectedEdges.length ? JSON.stringify(item.unexpectedEdges) : 'none' })),
251
+ artifactPath: join(root, 'ux-sim', 'evidence', `${scenario.id}.json`) };
252
+ mkdirSync(join(root, 'ux-sim', 'evidence'), { recursive: true });
253
+ writeFileSync(result.artifactPath, `${JSON.stringify(result, null, 2)}\n`, { mode: 0o600 });
254
+ return result;
255
+ }
256
+
257
+ export async function runReleaseSimRigIfFile(filePath: string): Promise<ReleaseSimRigResult | null> {
258
+ const source = readFileSync(resolveScenarioFilePath(filePath), 'utf8');
259
+ if (record(parseYaml(source), 'scenario').kind !== 'release-graph') return null;
260
+ if (!getTestStateRoot()) throw new Error('release simulation rig requires --test isolated mode');
261
+ return runReleaseSimRigScenario(source);
262
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Simulate the 40-minute, seven-scene seminar rehearsal protocol.
3
+ *
4
+ * This checks timing, evidence completeness, fallback, and disclosure guards
5
+ * with injected records. It never claims that a real rehearsal or device run
6
+ * took place.
7
+ */
8
+ // Targets mirror RUNBOOK-1027-seminar-smart-wizard-demo-2026-10-24.md; the test
9
+ // parses that table so edits to the runbook cannot silently drift from this rig.
10
+ export const SEMINAR_SCENES = [
11
+ { id: 1, name: 'hook', targetMinutes: 3 },
12
+ { id: 2, name: 'problem', targetMinutes: 5 },
13
+ { id: 3, name: 'AI executive', targetMinutes: 8 },
14
+ { id: 4, name: 'development demo', targetMinutes: 8 },
15
+ { id: 5, name: 'two phones', targetMinutes: 8 },
16
+ { id: 6, name: 'transit demo', targetMinutes: 4 },
17
+ { id: 7, name: 'close', targetMinutes: 4 },
18
+ ] as const;
19
+
20
+ export type SeminarSceneId = (typeof SEMINAR_SCENES)[number]['id'];
21
+ export type SeminarOutcome = 'pass' | 'fail' | 'unknown';
22
+
23
+ export interface SeminarSceneRecord {
24
+ readonly scene: SeminarSceneId;
25
+ readonly elapsedMinutes: number | null;
26
+ readonly medium: string | null;
27
+ readonly evidenceId: string | null;
28
+ readonly outcome: SeminarOutcome;
29
+ readonly publicSafe: boolean | null;
30
+ readonly fallbackUsed: boolean | null;
31
+ readonly offlineFallbackPlayed: boolean | null;
32
+ }
33
+
34
+ export interface SeminarRehearsalResult {
35
+ readonly simulated: true;
36
+ readonly totalTargetMinutes: number;
37
+ readonly scenes: ReadonlyArray<{
38
+ scene: SeminarSceneId;
39
+ name: string;
40
+ targetMinutes: number;
41
+ observedMinutes: number | null;
42
+ verdict: 'pass' | 'fail' | 'unknown';
43
+ reason: string;
44
+ }>;
45
+ readonly verdict: 'pass' | 'fail' | 'unknown';
46
+ }
47
+
48
+ export function simSeminarRehearsal(records: readonly SeminarSceneRecord[]): SeminarRehearsalResult {
49
+ const byScene = new Map<SeminarSceneId, SeminarSceneRecord>();
50
+ for (const record of records) {
51
+ if (!SEMINAR_SCENES.some((scene) => scene.id === record.scene)) throw new Error(`unknown scene record: ${String(record.scene)}`);
52
+ if (byScene.has(record.scene)) throw new Error(`duplicate scene record: ${record.scene}`);
53
+ byScene.set(record.scene, record);
54
+ }
55
+
56
+ const scenes = SEMINAR_SCENES.map((scene) => {
57
+ const record = byScene.get(scene.id);
58
+ if (!record || record.elapsedMinutes === null || !record.medium || !record.evidenceId || record.outcome === 'unknown' || record.publicSafe === null || record.fallbackUsed === null || (record.fallbackUsed && record.offlineFallbackPlayed === null)) {
59
+ return { scene: scene.id, name: scene.name, targetMinutes: scene.targetMinutes, observedMinutes: record?.elapsedMinutes ?? null, verdict: 'unknown' as const, reason: '실행 기록의 시간·매체·증거·결과·공개 안전 중 미확인 값이 있음' };
60
+ }
61
+ if (record.outcome === 'fail') {
62
+ return { scene: scene.id, name: scene.name, targetMinutes: scene.targetMinutes, observedMinutes: record.elapsedMinutes, verdict: 'fail' as const, reason: '주입된 장면 결과가 fail' };
63
+ }
64
+ if (Math.abs(record.elapsedMinutes - scene.targetMinutes) > 1) {
65
+ return { scene: scene.id, name: scene.name, targetMinutes: scene.targetMinutes, observedMinutes: record.elapsedMinutes, verdict: 'fail' as const, reason: `목표 ${scene.targetMinutes}분에서 ±1분 초과` };
66
+ }
67
+ if (!record.publicSafe) {
68
+ return { scene: scene.id, name: scene.name, targetMinutes: scene.targetMinutes, observedMinutes: record.elapsedMinutes, verdict: 'fail' as const, reason: '공개 안전 확인 실패' };
69
+ }
70
+ if (record.fallbackUsed && !record.offlineFallbackPlayed) {
71
+ return { scene: scene.id, name: scene.name, targetMinutes: scene.targetMinutes, observedMinutes: record.elapsedMinutes, verdict: 'fail' as const, reason: '대체 경로를 선택했으나 오프라인 매체 재생을 확인하지 못함' };
72
+ }
73
+ return { scene: scene.id, name: scene.name, targetMinutes: scene.targetMinutes, observedMinutes: record.elapsedMinutes, verdict: 'pass' as const, reason: record.fallbackUsed ? '오프라인 대체 매체 재생 확인' : '주입된 시나리오 통과' };
74
+ });
75
+
76
+ const verdict = scenes.some((scene) => scene.verdict === 'unknown')
77
+ ? 'unknown'
78
+ : scenes.some((scene) => scene.verdict === 'fail')
79
+ ? 'fail'
80
+ : 'pass';
81
+
82
+ return {
83
+ simulated: true,
84
+ totalTargetMinutes: SEMINAR_SCENES.reduce((sum, scene) => sum + scene.targetMinutes, 0),
85
+ scenes,
86
+ verdict,
87
+ };
88
+ }
89
+
90
+ export function seminarRehearsalSweep(): SeminarRehearsalResult {
91
+ const records: SeminarSceneRecord[] = SEMINAR_SCENES.map((scene) => ({
92
+ scene: scene.id,
93
+ elapsedMinutes: scene.targetMinutes,
94
+ medium: scene.id === 5 ? 'simulated iPhone + Fold8' : scene.id === 4 ? 'simulated offline video' : 'simulated stage screen',
95
+ evidenceId: `sim-scene-${scene.id}`,
96
+ outcome: 'pass',
97
+ publicSafe: true,
98
+ fallbackUsed: scene.id === 5,
99
+ offlineFallbackPlayed: scene.id === 5 ? true : null,
100
+ }));
101
+ return simSeminarRehearsal(records);
102
+ }
103
+
104
+ export function renderSeminarRehearsal(result: SeminarRehearsalResult): string[] {
105
+ return [
106
+ `세미나 리허설 · ${result.totalTargetMinutes}분 · ${result.verdict} · sim only (실제 행사 실행 증거 아님)`,
107
+ ...result.scenes.map((scene) => ` S${scene.scene} ${scene.name.padEnd(18)} ${scene.observedMinutes === null ? '미확인' : `${scene.observedMinutes}분`.padEnd(5)} / 목표 ${scene.targetMinutes}분 · ${scene.verdict} · ${scene.reason}`),
108
+ ];
109
+ }
@@ -1,5 +1,5 @@
1
1
  // N03 장치 — SUBAGENT-TOOLS-EMPTY (0.2.36 · 2026-10-22 · 대표 P0).
2
- // 진짜 classic TUI(bare `elanous`) ⊕ fake LLM 이 Agent 도구를 «틀린 이름» tool_filter 로 부른다
2
+ // 진짜 classic TUI(`--legacy`) ⊕ fake LLM 이 Agent 도구를 «틀린 이름» tool_filter 로 부른다
3
3
  // (10-22 운영 실물: allow 5~12개를 줘도 49→0 · «0 tools · Blocked»). 판정은 같은 바이너리의 `logs --json`:
4
4
  // mismatch — allow 가 모르는 이름뿐 → tool-filter allowIgnored ⊕ dispatch noTools=false(도구 상속)
5
5
  // deny-all — 모든 도구를 deny → no-tools-refused(발사 거부 · 빈손 실행 0)
@@ -33,7 +33,7 @@ export async function runSubagentToolsDevice(spec: SubagentToolsSpec): Promise<S
33
33
  : { allow: ['Read'], deny: ['Read'] };
34
34
  const run = await mockSeatPtySequence({
35
35
  executable: spec.executable,
36
- args: [spec.entry, '--config-dir', '{root}', '--test-state-dir', '{root}'],
36
+ args: [spec.entry, '--legacy', '--config-dir', '{root}', '--test-state-dir', '{root}'],
37
37
  root,
38
38
  rows: 30,
39
39
  cols: 100,
@@ -31,6 +31,8 @@ export interface PodDeviceEvent {
31
31
  jobConditionReason?: string;
32
32
  jobConditionMessage?: string;
33
33
  activeDeadlineSeconds?: number;
34
+ jobCreatedAt?: string;
35
+ jobCompletedAt?: string;
34
36
  podPhase?: string;
35
37
  podCreatedAt?: string;
36
38
  containerReason?: string | null;
@@ -86,6 +88,7 @@ export const POD_DEVICE_EVENTS: readonly PodDeviceEvent[] = [
86
88
  jobConditionReason: 'DeadlineExceeded',
87
89
  jobConditionMessage: 'Job was active longer than specified deadline',
88
90
  activeDeadlineSeconds: 3600,
91
+ jobCreatedAt: '2026-10-22T12:55:10Z',
89
92
  podPhase: 'Failed',
90
93
  containerReason: 'Error',
91
94
  containerExitCode: 143,
@@ -114,7 +117,7 @@ const ok = (stdout: string) => ({ status: 0, stdout, stderr: '' });
114
117
 
115
118
  function answerJob(event: PodDeviceEvent, jsonpath: string): { status: number; stdout: string; stderr: string } {
116
119
  if (jsonpath === POD_TERMINATION_JOB_JSONPATH) {
117
- return ok(`${event.jobConditionReason ?? ''}\t${event.activeDeadlineSeconds ?? ''}\t${event.jobUid ?? ''}`);
120
+ return ok(`${event.jobConditionReason ?? ''}\t${event.activeDeadlineSeconds ?? ''}\t${event.jobUid ?? ''}\t${event.jobCreatedAt ?? ''}\t${event.jobCompletedAt ?? ''}`);
118
121
  }
119
122
  if (jsonpath.includes('.spec.activeDeadlineSeconds')) return ok(event.activeDeadlineSeconds != null ? String(event.activeDeadlineSeconds) : '');
120
123
  if (jsonpath.includes('conditions[?(@.type=="Failed")].reason')) return ok(event.jobConditionReason ?? '');
@@ -1 +1 @@
1
- {"commit":"a78f3f66a3db5de0bce1342c99d3c4abc0a96f45"}
1
+ {"commit":"479072f6639b631e74d2a88a4e2f982193e00f89"}
@@ -1,13 +1,16 @@
1
1
  import { spawnSync } from 'node:child_process';
2
2
  import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync } from 'node:fs';
3
3
  import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
4
+ import { parse as parseYaml } from 'yaml';
4
5
  import type { RunResult } from './ffmpeg.js';
5
6
  import { UNOBSERVED, type Recipe, type RecipeCtx, type RecipeResult } from './types.js';
7
+ import { parseGraphTemplateYaml, type GraphParseIssue, type GraphTemplateSpec } from '../../self-implement/graph-yaml.js';
6
8
 
7
9
  type CommandRunner = (bin: string, args: readonly string[], timeoutMs: number, cwd?: string) => RunResult;
8
- interface ExplainerDeps { readonly run?: CommandRunner; readonly engineDir?: string }
10
+ interface ExplainerDeps { readonly run?: CommandRunner; readonly engineDir?: string; readonly declarationPath?: string }
9
11
 
10
12
  const ENGINE = resolve(import.meta.dir, '../../../skills/explainer-video/engine');
13
+ const LINE_DECLARATION = resolve(import.meta.dir, '../../../graphs/video/explainer-line.yaml');
11
14
  const ENGINE_MS = 600_000;
12
15
  const QC_MS = 180_000;
13
16
 
@@ -199,7 +202,19 @@ export function explainerQc(deps: ExplainerDeps = {}): Recipe {
199
202
  const peak = Number(j.input_tp);
200
203
  if (j.input_i == null || j.input_tp == null || !Number.isFinite(loudness) || !Number.isFinite(peak)) throw new Error('통합 음량/트루 피크가 비수다');
201
204
  const produced = { loudness_lufs: loudness, true_peak_db: peak };
202
- const outcome = loudness >= -16 && loudness <= -12 && peak <= -1 ? 'pass' : 'loudness';
205
+ let outcome = loudness >= -16 && loudness <= -12 && peak <= -1 ? 'pass' : 'loudness';
206
+ // ⭐ «3분 영상» — qc 생산 경로에서 loadExplainerLine 으로 선언의 target_seconds(180)를 소비한다.
207
+ // 내레이션이 목표 총 길이를 넘으면 too-long → build(재구성). narration_seconds 를 못 쟀으면 건너뛴다(기존 동작 보존).
208
+ const narrationSeconds = ctx.state.narration_seconds;
209
+ if (outcome === 'pass' && typeof narrationSeconds === 'number' && Number.isFinite(narrationSeconds)) {
210
+ const plan = loadExplainerLine(deps.declarationPath);
211
+ if (plan.targetSeconds !== null && narrationSeconds > plan.targetSeconds) {
212
+ return finish(ctx, 'qc', {
213
+ outcome: 'too-long', produced,
214
+ note: `${Math.round(narrationSeconds)}초 내레이션이 선언 목표 ${plan.targetSeconds}초를 넘는다 — build 로 재구성한다`,
215
+ });
216
+ }
217
+ }
203
218
  return finish(ctx, 'qc', { outcome, produced, note: `${loudness} LUFS · ${peak} dBTP` });
204
219
  } catch (e) { return finish(ctx, 'qc', { outcome: UNOBSERVED, note: `loudnorm 결과를 못 읽었다: ${String(e)}` }); }
205
220
  };
@@ -211,3 +226,40 @@ export const EXPLAINER: Readonly<Record<string, Recipe>> = {
211
226
  'explainer-build': explainerBuild(),
212
227
  'explainer-qc': explainerQc(),
213
228
  };
229
+
230
+ /** ⭐ «3분 영상» — explainer-line 선언이 이 라인의 영상 계획에 건 목표 총 길이(초). */
231
+ export interface ExplainerLinePlan {
232
+ /** 지속 필드 `target_seconds`(초). 선언에 없으면 이 라인은 목표 총 길이를 정하지 않았다(null). */
233
+ readonly targetSeconds: number | null;
234
+ /** 생산 컴파일러(parseGraphTemplateYaml)가 낸 정규형 — 나머지 선언(노드·계약·엣지)은 이것으로 관측한다. */
235
+ readonly template: GraphTemplateSpec | null;
236
+ readonly errors: readonly GraphParseIssue[];
237
+ }
238
+
239
+ /** ⭐ 생산 로드 — 라인 저작본(graphs/video/explainer-line.yaml)을 읽어 영상 계획을 낸다.
240
+ * 컴파일러는 top-level 계획 상수를 정규형에 싣지 않는다 — 지속 필드 `target_seconds` 는 로드에서 직접 읽는다.
241
+ * ⛔ 던지지 않는다(graph-yaml 계약) · 뿌리는 인자로 덮는다(ENGINE 과 같은 관습). */
242
+ export function loadExplainerLine(declarationPath = LINE_DECLARATION): ExplainerLinePlan {
243
+ let source: string;
244
+ try {
245
+ source = readFileSync(declarationPath, 'utf8');
246
+ } catch (error) {
247
+ return {
248
+ targetSeconds: null,
249
+ template: null,
250
+ errors: [{ path: declarationPath, message: `선언 읽기 실패: ${error instanceof Error ? error.message : String(error)}` }],
251
+ };
252
+ }
253
+ const compiled = parseGraphTemplateYaml(source, 'explainer-line.yaml');
254
+ let targetSeconds: number | null = null;
255
+ try {
256
+ const raw: unknown = parseYaml(source);
257
+ const declared = raw !== null && typeof raw === 'object' && !Array.isArray(raw)
258
+ ? (raw as Record<string, unknown>).target_seconds
259
+ : undefined;
260
+ if (typeof declared === 'number' && Number.isFinite(declared) && declared > 0) targetSeconds = declared;
261
+ } catch {
262
+ // YAML 파싱 실패는 컴파일 결과(errors)가 이미 싣는다 — 로드는 던지지 않는다.
263
+ }
264
+ return { targetSeconds, template: compiled.template ?? null, errors: compiled.errors };
265
+ }
@@ -18,18 +18,43 @@
18
18
  // custom MCP provider without touching skill bodies.
19
19
 
20
20
  import { getGrokApiKey } from '../config.js';
21
- import { grokAgentSearch, GROK_SEARCH_MODEL } from '../grok/agent-search.js';
21
+ import { grokAgentSearch, GROK_SEARCH_MODEL, type GrokAgentSearchOpts } from '../grok/agent-search.js';
22
+ import { peekGrokCredential, resolveFreshGrokCredential } from '../grok/credential.js';
22
23
  import { wantsXSearch } from './x-intent.js';
23
24
  import type { WebSearchHit, WebSearchProvider, WebSearchResult } from './provider.js';
24
25
 
25
26
  const DEFAULT_LIMIT = 5;
26
27
  const GROK_TIMEOUT_MS = 45_000;
28
+ // The subscription proxy's known working model differs from the metered API default.
29
+ const GROK_SUBSCRIPTION_SEARCH_MODEL = 'grok-4.6';
27
30
 
28
- export function buildGrokWebSearchProvider(): WebSearchProvider {
31
+ /** Explicitly metered API provider. The registry only adds it with webSearch.grokApi.enabled. */
32
+ export function buildGrokWebSearchProvider(opts: { id?: string } = {}): WebSearchProvider {
33
+ return makeGrokProvider(opts.id ?? 'grok', 'Grok (xAI agent-tools search)',
34
+ () => !!getGrokApiKey(), () => ({}));
35
+ }
36
+
37
+ /** Subscription search uses the proven cli-chat-proxy /responses route. No API-key fallback. */
38
+ export function buildGrokSubscriptionWebSearchProvider(): WebSearchProvider {
39
+ return makeGrokProvider('grok', 'Grok (subscription search)',
40
+ () => peekGrokCredential({ model: GROK_SUBSCRIPTION_SEARCH_MODEL })?.kind === 'subscription',
41
+ () => {
42
+ const credential = resolveFreshGrokCredential({ model: GROK_SUBSCRIPTION_SEARCH_MODEL });
43
+ if (credential?.kind !== 'subscription') throw new Error('Grok subscription search unavailable');
44
+ return { apiKey: credential.token, baseUrl: credential.baseUrl, headers: credential.headers, model: GROK_SUBSCRIPTION_SEARCH_MODEL };
45
+ });
46
+ }
47
+
48
+ function makeGrokProvider(
49
+ id: string,
50
+ displayName: string,
51
+ available: () => boolean,
52
+ searchOptions: () => GrokAgentSearchOpts,
53
+ ): WebSearchProvider {
29
54
  return {
30
- id: 'grok',
31
- displayName: 'Grok (xAI agent-tools search)',
32
- available: () => !!getGrokApiKey(),
55
+ id,
56
+ displayName,
57
+ available,
33
58
  search: async (q, signal) => {
34
59
  const startedAt = Date.now();
35
60
  const limit = Math.max(1, Math.min(20, q.limit ?? DEFAULT_LIMIT));
@@ -45,6 +70,7 @@ export function buildGrokWebSearchProvider(): WebSearchProvider {
45
70
 
46
71
  const r = await grokAgentSearch(query, {
47
72
  model: GROK_SEARCH_MODEL,
73
+ ...searchOptions(),
48
74
  tools: ['web_search', 'x_search'],
49
75
  systemPrompt: 'You are a concise web-search assistant. Answer in one or two sentences and let the cited sources carry the detail.',
50
76
  timeoutMs: GROK_TIMEOUT_MS,
@@ -67,7 +93,7 @@ export function buildGrokWebSearchProvider(): WebSearchProvider {
67
93
  const note = r.text.length > 0 ? r.text.slice(0, 1500) : undefined;
68
94
  return {
69
95
  hits,
70
- providerName: 'grok',
96
+ providerName: id,
71
97
  durationMs: Date.now() - startedAt,
72
98
  ...(note ? { note } : {}),
73
99
  } satisfies WebSearchResult;
@@ -5,11 +5,11 @@
5
5
  // order) and routes the query. Callers that want a specific
6
6
  // provider pass `providerId` to force the choice.
7
7
 
8
- import { buildGrokWebSearchProvider } from './grok.js';
8
+ import { buildGrokSubscriptionWebSearchProvider, buildGrokWebSearchProvider } from './grok.js';
9
9
  import { buildFirecrawlWebSearchProvider } from './firecrawl.js';
10
10
  import { buildTavilyWebSearchProvider } from './tavily.js';
11
11
  import { buildFreeWebSearchProvider } from './free.js';
12
- import { isTavilySearchEnabled } from '../user-config.js';
12
+ import { isPaidWebSearchEnabled, isTavilySearchEnabled } from '../user-config.js';
13
13
  import { debug } from '../debug/log.js';
14
14
  import { wantsXSearch } from './x-intent.js';
15
15
  import {
@@ -35,8 +35,9 @@ function registerBuiltins(): void {
35
35
  // ⇒ 켜면 종전과 «똑같이» 1순위로 복귀한다: `elanous config set webSearch.tavily.enabled true`.
36
36
  // ⚠️ 등록 시점이라 config 변경은 **다음 기동부터** 먹는다(이미 뜬 프로세스엔 안 먹는다).
37
37
  if (isTavilySearchEnabled()) providers.push(buildTavilyWebSearchProvider());
38
- providers.push(buildGrokWebSearchProvider());
39
- providers.push(buildFirecrawlWebSearchProvider());
38
+ providers.push(buildGrokSubscriptionWebSearchProvider());
39
+ if (isPaidWebSearchEnabled('grokApi')) providers.push(buildGrokWebSearchProvider({ id: 'grok-api' }));
40
+ if (isPaidWebSearchEnabled('firecrawl')) providers.push(buildFirecrawlWebSearchProvider());
40
41
  providers.push(buildFreeWebSearchProvider());
41
42
  }
42
43
  registerBuiltins();
@@ -70,10 +71,10 @@ export async function searchWeb(
70
71
  ): Promise<WebSearchResult> {
71
72
  const xIntent = !opts.providerId && wantsXSearch(q.query);
72
73
  const candidates = opts.providerId
73
- ? providers.filter(p => p.id === opts.providerId)
74
+ ? providers.filter(p => p.id === opts.providerId || (opts.providerId === 'grok' && p.id === 'grok-api'))
74
75
  : providers.filter(p => p.available());
75
76
  if (xIntent) {
76
- const grokIndex = candidates.findIndex(p => p.id === 'grok');
77
+ const grokIndex = candidates.findIndex(p => p.id === 'grok' || p.id === 'grok-api');
77
78
  if (grokIndex > 0) candidates.unshift(...candidates.splice(grokIndex, 1));
78
79
  }
79
80
  if (candidates.length === 0) {
@@ -91,7 +92,7 @@ export async function searchWeb(
91
92
  try {
92
93
  const result = await provider.search(q, opts.signal);
93
94
  if (!xIntent) return result;
94
- if (provider.id === 'grok') {
95
+ if (provider.id === 'grok' || provider.id === 'grok-api') {
95
96
  const isXUrl = (raw: string): boolean => {
96
97
  try {
97
98
  const url = new URL(raw);