elanous 0.2.42 → 0.2.44

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 (764) 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/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/08334415.f0e80896acbef722.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1032-78ba4f6391258cab.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1082-53f86a26e03d309d.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1109-7d0e264f6f2edbc7.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1124-7c26330402481143.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{2160.a097e7b138ae1c55.js → 118.2a89982fe4276880.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1244.6c435dbf1bf21d8a.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1252.9e665904d3aa3b1a.js +32 -0
  12. package/apps/pwa/out/_next/static/chunks/1266.a46cc33cb6a72d75.js +104 -0
  13. package/apps/pwa/out/_next/static/chunks/1306.967240ede9a0f757.js +24 -0
  14. package/apps/pwa/out/_next/static/chunks/1344.3b95f3bd1b77a3fe.js +94 -0
  15. package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 1401.22dfe92640a2b1ac.js} +4 -4
  16. package/apps/pwa/out/_next/static/chunks/1431-f7c78bd5be21e011.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1451-cdd35a8a0b31834b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 1694.18debfd77562e56d.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1708-f03d587b7a7545c8.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1775-fa7152bdeff6c95f.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/178-4da509cd7266672a.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1850-522de4ee34957210.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1876-c6f6e0ddcc76c6a1.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/1976.097066b072432242.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1978.eeb60a606dc5deac.js} +2 -2
  26. package/apps/pwa/out/_next/static/chunks/2043.e233e3b5a3e790f5.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2150.71b94e3348107c83.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2158.ebc6fc5a10280ab7.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2216.802962c04f40a26e.js +64 -0
  30. package/apps/pwa/out/_next/static/chunks/2294.7890edcfa046c97d.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/235.c89aaae4bcd6233a.js +74 -0
  32. package/apps/pwa/out/_next/static/chunks/{5885.0a3e52c8faccec98.js → 239.de075467b5523469.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/249.ba7051590d603c8f.js +226 -0
  34. package/apps/pwa/out/_next/static/chunks/2571.a6ac4e26c8618403.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/2610.e149cd564a08913e.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/2705.9816f3c244f8b85f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/2801.afeb8a4dae22f85f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/2954.bbefc95d6b20e0d8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/2e0f720a.a0697c08e3806a60.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3042.96ec235fe41c8d4e.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3097-8e358f158acef46b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3205-93b1abe28b4fb16a.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3273.b4434f0dcae7eb29.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3311.9cbc43ea0c90d60c.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 3349.b5f09ee474d9533e.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/3503.a47a9755fb4d97b0.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3506-5f429b3b7e1392b0.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/3843.bad404d008893291.js +77 -0
  49. package/apps/pwa/out/_next/static/chunks/3877-4b40e530b47e3bf9.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/435-ce2958253cf7de61.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4393.28fa5228d0eec217.js +149 -0
  52. package/apps/pwa/out/_next/static/chunks/4404.7281c847c6e10dfc.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 4415-b9d6a90960920a4a.js} +3 -3
  54. package/apps/pwa/out/_next/static/chunks/447-5b304de1fe098f43.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4484-8ebea83d431e6fae.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 4502.bdcc877abd437a05.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/4599-f95790fc5c65b8df.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 46.57c783fa4884714f.js} +2 -2
  59. package/apps/pwa/out/_next/static/chunks/463-b9114e411f33728e.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/4659.a57d1f0c5d754cd2.js +36 -0
  61. package/apps/pwa/out/_next/static/chunks/4722-a847e7a28115035f.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 4757.67c6d7473a038e78.js} +1 -1
  63. package/apps/pwa/out/_next/static/chunks/4874-c86f878ec4502ad3.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{6377.bc7df239edbff244.js → 4891.3f80ba517a3b2373.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/4998.810ca8833084caa9.js +62 -0
  66. package/apps/pwa/out/_next/static/chunks/4f98febc.ea5841d4d616bfb2.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5052.7dbb12a55d4f18f5.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/5166-ca73b3e361085a6d.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5180-039f4a18b07ad387.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/5232.5a2ce4daf7a9e11d.js +115 -0
  71. package/apps/pwa/out/_next/static/chunks/5439.3fec6dbce29ecb36.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5612-074d9a5e00dfac6a.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/5675-01989d524a84c505.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/5751.af641a1adf5ec697.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/5758-c6cb98714d18ab0c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/578eded8.b582637306e16964.js +122 -0
  77. package/apps/pwa/out/_next/static/chunks/5790.5eb06a653ebd8571.js +34 -0
  78. package/apps/pwa/out/_next/static/chunks/5853-4033e5bd5afbe06b.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/5904.97d70bb7f46b2db7.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 5989.7ecd362c5c44b747.js} +3 -3
  81. package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 5a34fb2f.52f1b4e1baebb48a.js} +3 -3
  82. package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 5a5078f8.2099200e5ea95e16.js} +1 -1
  83. package/apps/pwa/out/_next/static/chunks/6036-c302c34ff0b3d410.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/606.ef81c313381f4264.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/616.1af54a928b1ba704.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6201.bc936f71f613a8e9.js +41 -0
  87. package/apps/pwa/out/_next/static/chunks/6204-fdc86e0e64c4f92d.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 6245.1182e007e9d230d9.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 63699a35.17262e162bc514b2.js} +1 -1
  90. package/apps/pwa/out/_next/static/chunks/6420.494801a80030160c.js +27 -0
  91. package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → 6549dad0.2740b25e51bf8f05.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 6881.9e7955847640c7fe.js} +17 -17
  93. package/apps/pwa/out/_next/static/chunks/6931.fcdfb94141e67b3d.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/6991-8e081c6ce38c0ba1.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7010.1bbd17a7f2b3e376.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7029.d1466acf55fae2ed.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7152-a123aa8e129c131f.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7455.196168fffac3b9c4.js +24 -0
  99. package/apps/pwa/out/_next/static/chunks/7638.6ca4770dd1129138.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/7649-f37d76260e5e2a5a.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/7679.32c40cdd14f20b4a.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/7751.04bfbd16b4c6cd0a.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/7864.b1ff31d4030b8994.js +148 -0
  104. package/apps/pwa/out/_next/static/chunks/7869-c47bd2c075c1fefa.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 8442.2f09ca969d631615.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8445.2738dbd59a78c78c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8447.5510c439f9938c6d.js +286 -0
  108. package/apps/pwa/out/_next/static/chunks/{9415.69e4a21c60c7d2db.js → 8551.f762945c2cda2e95.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/8635-57a9d8d9db70f4f1.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/86961958-4b0689a5048f756b.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/8709.3c6019bb18f8554f.js +8 -0
  112. package/apps/pwa/out/_next/static/chunks/8759.c999528a0a907bf6.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9a852a62-6192a6ea9346ced3.js → 87f498e5-0881de09f2e44707.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/8843.c3197f904c952b81.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → 892fd990.456232f326cc39c2.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/8965-135a2c9eaa2464cb.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/8971-8d3b9c96f8a6c958.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9059.c8598d96f8e5e9cd.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9115.90447ae198b84eae.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9147.d9b0a02e0babc9b4.js +93 -0
  121. package/apps/pwa/out/_next/static/chunks/9204-83075f4b70c61cdc.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9244-c32ef14b5dc72bdf.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/930.2a9a30f964350c66.js +90 -0
  124. package/apps/pwa/out/_next/static/chunks/9398.1f56e3f17795f43f.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/9527.3e5ad31c891c5fcb.js +79 -0
  126. package/apps/pwa/out/_next/static/chunks/9571-4ac933e774d1225c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-9fc644de2d8edae3.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/approvals/page-0c9dace2db62bee8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f5e65c3dc9d89f2a.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/board/page-2a9c19b9a140b7b1.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/botlab/page-61533ad92141adfb.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/bots/page-112004ced6fd0329.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f733318c237a49d8.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/chat/page-51ea677d2d33bbc0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/consult/page-428b41f2f9566e3c.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/control/page-1b29396ea90a61e5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/decisions/page-cf83ec613ac904bf.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/design-check/page-3f4c0ecbc284bb5f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/editor/page-b63c322f54f70cc6.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/exec/page-fe328c4ee9aac6b4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/field/page-bfb855c584f0fb98.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/healthz/route-9fc644de2d8edae3.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/inside/page-47b1710c110eabd7.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/intake/page-42895214458bc6d2.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/layout-d03de0ebd8366e23.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/live/page-3ed6c47e4b1c61c2.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/live-run/page-ae653e9bf261c738.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/loops/page-23f3f0a0209c0ac4.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/market/page-88c691273aae66f9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e187ac52a95538b3.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/morning/page-6e45828daed1295e.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/not-found-edb5d7287bb46186.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/observatory/page-4a7eaacd93c3f6a5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ca073d43d74cc84.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1e9fee67b1199436.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-df1283ea963c6816.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/outputs/page-19fcf8d8301ccd18.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/page-5ab699e0303bbb40.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7cde0d29756984c5.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9d4c598e8ee22f7a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/sessions/page-cc1609a71f44ec62.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7659a9a1345bfaa9.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/settings/page-0afef60ecc0c4af5.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a3553949f8f34f5f.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/setup/layout-9fc644de2d8edae3.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/setup/page-057a69702f3c67c7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/share/page-c0f0e570f3f74c73.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/showroom/page-1825071ae34e3b89.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6244e3e135d8ccfc.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/term/page-da787e8a10b8a82e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/today/page-1316d32498e2be42.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/trace/page-4df94572e343de2e.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/vault/page-708969f7475e88c1.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c58add08c919a1dc.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a24847f45e5d5bf9.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/app/workspace/page-acfec65a3a60e22e.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-3dfc598e6fbde245.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-c658a626118411b7.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-4c73685fd891445b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-6310f7e5de7dd01d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-51c326bf48610be1.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-d0beadf754da59b0.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-acd243bfbf3f6732.js +1 -0
  184. package/apps/pwa/out/_next/static/css/d1f8bb401740a549.css +1 -0
  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/catalog/external-commands.yaml +5 -3
  279. package/catalog/meta/catalogVersion.yaml +2 -1
  280. package/catalog/signing/catalog-signing-public.pem +3 -0
  281. package/graphs/intake/intake-daily.yaml +16 -0
  282. package/graphs/intake/news-sources.yaml +1 -0
  283. package/graphs/intake/recipes.yaml +7 -0
  284. package/graphs/overlays/README.md +6 -0
  285. package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
  286. package/graphs/profiles/local.yaml +5 -0
  287. package/graphs/profiles/pod.yaml +4 -0
  288. package/graphs/release/release-loop.yaml +33 -17
  289. package/graphs/units/verbs/make-doc.yaml +1 -0
  290. package/package.json +6 -2
  291. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  292. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  293. package/plugins/demo-browser-hand/plugin.json +13 -0
  294. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  295. package/plugins/demo-linear-secretary/plugin.json +15 -0
  296. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  297. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  298. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  299. package/plugins/demo-research/plugin.json +16 -0
  300. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  301. package/plugins/demo-video-briefing/plugin.json +15 -0
  302. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  303. package/scripts/bench-metering-plan.ts +229 -0
  304. package/scripts/build-signed-catalog.ts +48 -0
  305. package/scripts/ci-typecheck-main-delta.sh +88 -0
  306. package/scripts/codex-fallback-live-probe.ts +1 -1
  307. package/scripts/demo/demo1104-parallel-host.ts +56 -0
  308. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  309. package/scripts/demo/demo1104-parallel.ts +72 -0
  310. package/scripts/demo/demo1104-stage.config.ts +21 -0
  311. package/scripts/demo/demo1104-stage.ts +316 -0
  312. package/scripts/goal-method-audit.ts +17 -1
  313. package/scripts/graph-units/land-enqueue.ts +90 -0
  314. package/scripts/hooks/codex-notify.sh +32 -0
  315. package/scripts/install.sh +10 -38
  316. package/scripts/landing-heal/land-plan.ts +57 -0
  317. package/scripts/public-leak-baseline.txt +0 -1
  318. package/scripts/release-loop/auto-approve-node.ts +1 -1
  319. package/scripts/release-loop/docs-node.ts +4 -2
  320. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  321. package/scripts/release-loop/gate-image-pin.ts +116 -2
  322. package/scripts/release-loop/gate-method.ts +139 -0
  323. package/scripts/release-loop/gate-node.ts +395 -43
  324. package/scripts/release-loop/gate-progress-sim.ts +73 -0
  325. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  326. package/scripts/release-loop/node-verdict.ts +38 -25
  327. package/scripts/release-loop/notes-repair.ts +18 -1
  328. package/scripts/release-loop/preflight.ts +544 -10
  329. package/scripts/release-loop/render-warm-control-manifest.ts +22 -0
  330. package/scripts/release-loop/resume-release.ts +9 -7
  331. package/scripts/release-loop/resume.ts +13 -4
  332. package/scripts/release-loop/unattended-release.ts +20 -9
  333. package/scripts/release-loop/warm-control-forward.ts +178 -0
  334. package/scripts/retro-cycle.ts +30 -8
  335. package/scripts/rhythm/daily.ts +39 -4
  336. package/scripts/rhythm/linear-progress-sync.ts +311 -0
  337. package/scripts/ux-sim.ts +7 -1
  338. package/scripts/video-pipeline.ts +9 -1
  339. package/scripts/warm-pool-provider-config.ts +35 -7
  340. package/src/acp/agent-manager.ts +1 -0
  341. package/src/acp/codex-app-server-agent.ts +33 -0
  342. package/src/acp/codex-app-server-client.ts +153 -16
  343. package/src/acp/core-turn-bridge.ts +17 -12
  344. package/src/acp/event-router.ts +20 -1
  345. package/src/acp/server.ts +6 -0
  346. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  347. package/src/agent-mission/claude-headless.ts +4 -1
  348. package/src/agent-mission/codex-exec.ts +105 -0
  349. package/src/agent-mission/driver.ts +192 -11
  350. package/src/agent-mission/grok-auth-status.ts +107 -0
  351. package/src/agent-mission/hand-hooks.ts +101 -0
  352. package/src/agent-mission/mission-cli.ts +56 -21
  353. package/src/agent-mission/mission-hand-reply.ts +118 -0
  354. package/src/agent-mission/mission-line.ts +180 -0
  355. package/src/agent-mission/mission-out.ts +256 -18
  356. package/src/agent-mission/tool-install.ts +122 -11
  357. package/src/agent-substrate/pr-reviewer.ts +147 -11
  358. package/src/agent-substrate/self-review-cli.ts +10 -2
  359. package/src/agents/general-purpose.md +1 -1
  360. package/src/auto-research/research-fanout.ts +221 -0
  361. package/src/auto-research/research-turn.ts +362 -31
  362. package/src/autopilot/mission-codebase-gate.ts +7 -3
  363. package/src/autopilot/pr-manager.ts +31 -3
  364. package/src/boot/daemon-tools/self-implement.ts +3 -1
  365. package/src/boot/daemon-tools/web-search.ts +1 -2
  366. package/src/briefing/brief-items.ts +55 -11
  367. package/src/cli/agent-cli.ts +2 -1
  368. package/src/cli/catalog-cli.ts +31 -0
  369. package/src/cli/connector-cli.ts +16 -0
  370. package/src/cli/control-cli.ts +15 -6
  371. package/src/cli/doctor-fix.ts +2 -2
  372. package/src/cli/intake-source-cli.ts +44 -8
  373. package/src/cli/log-event-names.ts +8 -0
  374. package/src/cli/msg-cli.ts +32 -3
  375. package/src/cli/pr-cli.ts +21 -1
  376. package/src/cli/pr-land-heavy-remote.ts +44 -6
  377. package/src/cli/pr-land-overlap-evidence.ts +13 -1
  378. package/src/cli/pr-land-pod-shadow-job.ts +143 -5
  379. package/src/cli/pr-land-pod-shadow.ts +9 -2
  380. package/src/cli/release-checklist-read-cli.ts +44 -16
  381. package/src/cli/release-cli.ts +23 -3
  382. package/src/cli/research-cli.ts +9 -0
  383. package/src/cli/setup-cli.ts +166 -6
  384. package/src/cli/setup-keys.ts +199 -0
  385. package/src/cli/task-plugin-wizard-host.ts +114 -0
  386. package/src/cli/tasks-cli.ts +54 -9
  387. package/src/cli/tui-test-cli.ts +190 -0
  388. package/src/config.ts +4 -2
  389. package/src/connectors/linear-daily-progress.ts +228 -0
  390. package/src/connectors/linear-projector.ts +34 -12
  391. package/src/connectors/linear.ts +151 -7
  392. package/src/control-plane/ledger.ts +42 -4
  393. package/src/control-plane/member-tokens.ts +25 -2
  394. package/src/control-plane/ports.ts +8 -3
  395. package/src/control-plane/server.ts +26 -5
  396. package/src/core-turn/deep-turn-bloom.ts +67 -0
  397. package/src/core-turn/research-policy.ts +43 -0
  398. package/src/core-turn/run-core-turn.ts +488 -51
  399. package/src/core-turn/types.ts +4 -0
  400. package/src/dashboard/chat/acp-chat.ts +10 -0
  401. package/src/dashboard/classic-sidetab-mission-job.ts +192 -0
  402. package/src/dashboard/classic-sidetab-mission-pair.ts +82 -0
  403. package/src/dashboard/classic-sidetab-mission-trio.ts +242 -0
  404. package/src/dashboard/classic-sidetab-mission.ts +169 -5
  405. package/src/dashboard/index.ts +387 -14
  406. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  407. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +8 -0
  408. package/src/dashboard/mission-cli-consumer.ts +20 -8
  409. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  410. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  411. package/src/dashboard/sidetab-runtime.ts +3 -1
  412. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  413. package/src/dashboard/visible-mission-diagnostics.ts +16 -0
  414. package/src/decisions/linear-progress-summary.ts +78 -0
  415. package/src/decisions/linear-progress-sync.ts +152 -0
  416. package/src/domains/outbound-alert.ts +49 -11
  417. package/src/domains/retro-cycle-observation.ts +43 -0
  418. package/src/domains/retro-cycle.ts +13 -2
  419. package/src/domains/retro-proposals.ts +92 -0
  420. package/src/domains/retro-report.ts +6 -1
  421. package/src/domains/telegram-kind-route.ts +16 -9
  422. package/src/graph-runner/arg-allowance.ts +13 -0
  423. package/src/graph-runner/graph-cli.ts +24 -1
  424. package/src/graph-runner/graph-grow-llm.ts +3 -1
  425. package/src/graph-runner/graph-run-api.ts +3 -1
  426. package/src/graph-runner/runner.ts +310 -46
  427. package/src/graph-wizard/mission-compose.ts +407 -12
  428. package/src/harness/dispatch-backpressure.ts +54 -1
  429. package/src/harness/dispatch-shadow-compare.ts +74 -0
  430. package/src/harness/harness-cli-command.ts +15 -3
  431. package/src/harness/harness-pod-dispatch.ts +3 -0
  432. package/src/harness/skill-exec.ts +21 -9
  433. package/src/harness/skill-select.ts +1 -1
  434. package/src/hooks/error-report-cloud.ts +101 -0
  435. package/src/hooks/receiver.ts +29 -2
  436. package/src/index.ts +129 -12
  437. package/src/intake-plane/actions.ts +354 -0
  438. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  439. package/src/intake-plane/intake-sources.ts +78 -8
  440. package/src/intake-plane/items.ts +14 -4
  441. package/src/intake-plane/linear-mission-sync.ts +80 -0
  442. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  443. package/src/intake-plane/linear-wish.ts +227 -1
  444. package/src/life/life-cli.ts +168 -0
  445. package/src/life/life-kinds.ts +160 -0
  446. package/src/live-supply/budget-consumer.ts +78 -0
  447. package/src/live-supply/read.ts +3 -0
  448. package/src/live-supply/snapshot.ts +45 -0
  449. package/src/llm/child-first-llm-observation.ts +112 -0
  450. package/src/llm/provider-credentials.ts +68 -6
  451. package/src/llm/provider-failure-evidence.ts +44 -0
  452. package/src/llm.ts +172 -12
  453. package/src/maturity/feature-maturity.ts +3 -3
  454. package/src/mcp/client.ts +7 -0
  455. package/src/mcp/proxy-runtime.ts +6 -1
  456. package/src/mcp/server.ts +54 -0
  457. package/src/msg/msg-sse-server.ts +3 -3
  458. package/src/msg/msg-store.ts +177 -19
  459. package/src/native-tool-catalog.ts +36 -2
  460. package/src/nexus/api/consult-requests.ts +18 -6
  461. package/src/nexus/api/discord-trigger-bot.ts +6 -6
  462. package/src/nexus/api/graphs-api.ts +4 -2
  463. package/src/nexus/api/grokbot-trigger-bot.ts +206 -0
  464. package/src/nexus/api/http-server.ts +37 -1
  465. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  466. package/src/nexus/api/telegram-trigger-bot.ts +6 -6
  467. package/src/nexus/boot/register-mcp-clients.ts +114 -8
  468. package/src/nexus/index.ts +22 -2
  469. package/src/nexus/outbound/format.ts +9 -0
  470. package/src/nexus/outbound/grokbot-adapter.ts +71 -0
  471. package/src/nexus/outbound/router.ts +121 -16
  472. package/src/nexus/setup-status.ts +9 -0
  473. package/src/nexus/state/state.ts +3 -0
  474. package/src/oauth/codex-account-store.ts +20 -7
  475. package/src/oauth/codex-owner-mirror.ts +81 -0
  476. package/src/oauth/codex.ts +17 -2
  477. package/src/oauth/fallback-chain.ts +47 -17
  478. package/src/onboarding/first-run-doctor.ts +8 -1
  479. package/src/onboarding/first-run.ts +126 -29
  480. package/src/onboarding/key-setup.ts +103 -0
  481. package/src/onboarding/menu-answer.ts +13 -0
  482. package/src/onboarding/secret-prompt.ts +37 -0
  483. package/src/plugins/install/plugin-install.ts +59 -0
  484. package/src/pr-tool/census.ts +130 -0
  485. package/src/preview/terminal.ts +22 -7
  486. package/src/prompt-enhance/enhance.ts +10 -0
  487. package/src/pty-shell/pty-control-ipc.ts +4 -1
  488. package/src/pty-shell/pty-write-provenance.ts +21 -3
  489. package/src/pty-shell/registry.ts +9 -2
  490. package/src/registry/catalog-server.ts +232 -0
  491. package/src/registry/loader.ts +45 -1
  492. package/src/registry/types.ts +1 -2
  493. package/src/release-loop/proposal-auto-place.ts +83 -0
  494. package/src/research/axis-fanout.ts +79 -29
  495. package/src/research/lenses/second-order.ts +312 -0
  496. package/src/self-dev/ask-launch-flow.ts +72 -1
  497. package/src/self-dev/dev-cli.ts +7 -2
  498. package/src/self-dev/dev-pipeline.ts +5 -0
  499. package/src/self-dev/draft-residue.ts +64 -5
  500. package/src/self-dev/draft-sweep.ts +31 -10
  501. package/src/self-dev/draft-triage-rules.ts +60 -3
  502. package/src/self-dev/graph-front-nodes.ts +2 -1
  503. package/src/self-dev/graph-journey-route.ts +76 -21
  504. package/src/self-dev/launch-preflight.ts +58 -0
  505. package/src/self-dev/orchestrate.ts +1 -1
  506. package/src/self-dev/run-supervisor.ts +152 -2
  507. package/src/self-dev/shard-aggregate.ts +4 -0
  508. package/src/self-dev/shard-run.ts +36 -15
  509. package/src/self-implement/abandoned-classification.ts +12 -3
  510. package/src/self-implement/budget-gate.ts +7 -0
  511. package/src/self-implement/child-llm-preference.ts +10 -1
  512. package/src/self-implement/doctor-visit.ts +30 -8
  513. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  514. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  515. package/src/self-implement/gate-artifacts.ts +2 -1
  516. package/src/self-implement/goal-author-cli.ts +4 -2
  517. package/src/self-implement/goal-author.ts +549 -10
  518. package/src/self-implement/graph-overlay-yaml.ts +181 -4
  519. package/src/self-implement/graph-overlay.ts +3 -1
  520. package/src/self-implement/graph-profile-yaml.ts +107 -0
  521. package/src/self-implement/graph-yaml.ts +94 -5
  522. package/src/self-implement/off-diff-evidence.ts +249 -5
  523. package/src/self-implement/orchestrator.ts +298 -26
  524. package/src/self-implement/run-chart.ts +6 -3
  525. package/src/self-implement/run-ledger.ts +51 -1
  526. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  527. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  528. package/src/self-implement/test-scenario-request.ts +37 -6
  529. package/src/self-implement/train-gate-receipt.ts +166 -0
  530. package/src/self-implement/train-gate-remote.ts +62 -18
  531. package/src/session/chat.ts +6 -4
  532. package/src/session/session-fanout.ts +2 -0
  533. package/src/session/streaming/acp-stream-sink.ts +2 -1
  534. package/src/session/streaming/chunk-producer.ts +6 -0
  535. package/src/session/streaming/stream-compositor.ts +3 -2
  536. package/src/session-runtime/index.ts +74 -6
  537. package/src/session-runtime/retry-policy.ts +1 -1
  538. package/src/setup/llm-env-detect.ts +3 -0
  539. package/src/setup/service-key-catalog.ts +46 -0
  540. package/src/setup/service-keys.ts +241 -0
  541. package/src/sidetab-core/model.ts +205 -10
  542. package/src/sidetab-core/visible-agent-mission-pair.ts +51 -0
  543. package/src/sidetab-core/visible-agent-mission.ts +182 -48
  544. package/src/skills/tools/agent.ts +23 -4
  545. package/src/skills/tools/omni-search.ts +127 -27
  546. package/src/task-agent/parent-host.ts +29 -1
  547. package/src/task-agent/recall-inject.ts +98 -0
  548. package/src/task-agent/repair-outcomes.ts +65 -0
  549. package/src/task-agent/task-hand.ts +46 -14
  550. package/src/task-orchestrator/dispatcher.ts +14 -1
  551. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  552. package/src/task-orchestrator/store.ts +16 -5
  553. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +23 -1
  554. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +107 -1
  555. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  556. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +21 -9
  557. package/src/task-orchestrator/surfaces/pod-source-receive.ts +23 -11
  558. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  559. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +1 -1
  560. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +467 -77
  561. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +45 -3
  562. package/src/task-orchestrator/surfaces/self-implement-pod.ts +210 -14
  563. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  564. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  565. package/src/task-orchestrator/types.ts +14 -0
  566. package/src/telegram.ts +14 -16
  567. package/src/terminal/coding-agent.ts +14 -5
  568. package/src/terminal/session-registry.ts +1 -1
  569. package/src/tool-hints/gate.ts +46 -14
  570. package/src/tool-hints/signals.ts +1 -1
  571. package/src/tool-hints/types.ts +2 -0
  572. package/src/tool-runtime/agent-runtime.ts +1 -0
  573. package/src/tool-runtime/browser-hand-runtime.ts +391 -0
  574. package/src/tool-runtime/browser-runtime.ts +33 -19
  575. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  576. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +173 -0
  577. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  578. package/src/tool-runtime/index.ts +6 -0
  579. package/src/tool-runtime/types.ts +5 -0
  580. package/src/tui/entry.ts +51 -8
  581. package/src/tui/sidetab/attach.ts +252 -11
  582. package/src/tui/sidetab/herdr-portal.ts +225 -0
  583. package/src/tui/sidetab/list.ts +3 -2
  584. package/src/tui-client/next-dashboard-runtime.ts +52 -0
  585. package/src/user-config.ts +34 -9
  586. package/src/user-intent/types.ts +4 -3
  587. package/src/ux-sim/browser-hand.ts +165 -0
  588. package/src/ux-sim/draft-inventory-builder.ts +199 -0
  589. package/src/ux-sim/fake-browser-page.ts +81 -0
  590. package/src/ux-sim/fake-linear-device.ts +31 -0
  591. package/src/ux-sim/graph-engine-sim.ts +47 -0
  592. package/src/ux-sim/linear-secretary.ts +208 -0
  593. package/src/ux-sim/mock-scenario-catalog.json +81 -26
  594. package/src/ux-sim/mock-scenario-catalog.ts +175 -5
  595. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  596. package/src/ux-sim/release-sim-rig.ts +62 -18
  597. package/src/ux-sim/scenario.ts +70 -26
  598. package/src/ux-sim/service-key-setup.ts +113 -0
  599. package/src/ux-sim/term-slash-device.ts +74 -0
  600. package/src/ux-sim/turn-throw-sim.ts +31 -0
  601. package/src/version/packed-revision.json +1 -1
  602. package/src/web-search/exa.ts +77 -0
  603. package/src/web-search/index.ts +30 -9
  604. package/src/web-search/provider.ts +4 -1
  605. package/src/web-search/x-intent.ts +5 -0
  606. package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +0 -36
  608. package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +0 -32
  614. package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +0 -286
  620. package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +0 -34
  623. package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/2690.0521c738b7749931.js +0 -115
  629. package/apps/pwa/out/_next/static/chunks/2974.595d1e29d040cb6a.js +0 -64
  630. package/apps/pwa/out/_next/static/chunks/3207.a756c95e9ec8c3c8.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/3285.89ee2f298682f5e5.js +0 -93
  632. package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +0 -41
  633. package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +0 -24
  635. package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/3837.a210d7d0db8d8abd.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +0 -77
  641. package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +0 -148
  647. package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
  648. package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +0 -122
  649. package/apps/pwa/out/_next/static/chunks/5112.4b9f300124fab7b3.js +0 -149
  650. package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +0 -27
  652. package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +0 -226
  664. package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +0 -90
  665. package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +0 -104
  671. package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +0 -94
  672. package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/7279-c199ea83f34338fa.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +0 -24
  679. package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +0 -8
  687. package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +0 -79
  689. package/apps/pwa/out/_next/static/chunks/8546-6f03f8ea34dd61d9.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/9249.976f1e69a9d80754.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/9353-12bfff0c130104cf.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/9656-374232558fd528d0.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/9832.f4a98c878ecf2c0a.js +0 -62
  705. package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +0 -1
  763. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  764. /package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_ssgManifest.js +0 -0
@@ -1,4 +1,5 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
3
  import { execFile, spawnSync } from 'node:child_process';
3
4
  import { existsSync, linkSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmdirSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
4
5
  import { dirname, join, resolve, sep } from 'node:path';
@@ -30,8 +31,18 @@ import { requireInProcessHandler, type InProcessHandlerRegistry } from './in-pro
30
31
  import { interpolate } from '../workflow-runtime/variables.js';
31
32
  import type { BashNode, ClassifyNode, NodeExecContext, NodeOutput, WorkflowDeps } from '../workflow-runtime/types.js';
32
33
  import { releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeGatePodPool, releaseResumeGateShardReroute, releaseResumeWaiver, type AcceptedRegression, type GateExecutorOverride, type GatePodPoolOverride, type GateShardRerouteOverride } from '../../scripts/release-loop/resume.js';
34
+ import { resolveChildAllowance } from './arg-allowance.js';
33
35
 
34
36
  type BashRun = WorkflowDeps['runBash'];
37
+
38
+ export type GraphGrowthScope = 'harness' | 'task-agent';
39
+ export const GRAPH_GROWTH_SCOPE_ENV = 'ELANOUS_GRAPH_GROWTH_SCOPE';
40
+ const graphGrowthScope = new AsyncLocalStorage<GraphGrowthScope>();
41
+
42
+ /** Scope implicit graph growth to an approved in-process harness dispatch. */
43
+ export function withGraphGrowthScope<T>(scope: GraphGrowthScope, work: () => T): T {
44
+ return graphGrowthScope.run(scope, work);
45
+ }
35
46
  const DEFAULT_BASH_TIMEOUT_MS = 5 * 60 * 1_000;
36
47
  // Independent of graph YAML and recipe snapshots: an already-wrong saved binding must fail closed.
37
48
  const RELEASE_NODE_COMMANDS: Readonly<Record<string, { recipe: string; command?: string }>> = {
@@ -40,12 +51,14 @@ const RELEASE_NODE_COMMANDS: Readonly<Record<string, { recipe: string; command?:
40
51
  cutoff: { recipe: 'cmd:cutoff', command: 'bun scripts/release-loop/node-verdict.ts cutoff' },
41
52
  'checklist-gate': { recipe: 'cmd:checklist-gate', command: 'bun scripts/release-loop/checklist-gate-node.ts' },
42
53
  prefetch: { recipe: 'cmd:docs', command: 'bun scripts/release-loop/docs-node.ts --json' },
54
+ 'pre-gate-join': { recipe: 'none' },
43
55
  gate: { recipe: 'cmd:gate', command: 'bun scripts/release-loop/gate-node.ts --json' },
44
56
  'traffic-gate-passed': { recipe: 'cmd:traffic-gate-passed', command: 'bun scripts/release-loop/traffic-node.ts traffic-gate-passed' },
45
57
  'gate-triage': { recipe: 'cmd:gate-triage', command: 'bun scripts/release-loop/gate-triage-node.ts' },
46
58
  'mac-smoke': { recipe: 'cmd:mac-smoke', command: 'bun scripts/release-loop/mac-smoke-node.ts' },
47
59
  'export-check': { recipe: 'cmd:export-check', command: 'bun scripts/release-loop/export-check-node.ts' },
48
60
  pwa: { recipe: 'cmd:pwa', command: 'bun scripts/release-loop/node-verdict.ts pwa' },
61
+ 'pre-prepare-join': { recipe: 'none' },
49
62
  prepare: { recipe: 'cmd:prepare', command: 'bun scripts/release-loop/prepare-node.ts' },
50
63
  upgrade: { recipe: 'cmd:upgrade', command: 'bun scripts/release-loop/upgrade-node.ts' },
51
64
  tui: { recipe: 'cmd:docs', command: 'bun scripts/release-loop/docs-node.ts --json' },
@@ -59,6 +72,7 @@ const RELEASE_NODE_COMMANDS: Readonly<Record<string, { recipe: string; command?:
59
72
  publish: { recipe: 'cmd:publish-command', command: 'bun scripts/release-loop/publish-node.ts' },
60
73
  'npm-publish': { recipe: 'cmd:npm-publish', command: 'bun scripts/release-loop/npm-publish-node.ts' },
61
74
  'traffic-npm-published': { recipe: 'cmd:traffic-npm-published', command: 'bun scripts/release-loop/traffic-node.ts traffic-npm-published' },
75
+ 'release-post-publish-join': { recipe: 'none' },
62
76
  'docs-land': { recipe: 'cmd:docs-land', command: 'bun scripts/release-loop/docs-land-node.ts' },
63
77
  verify: { recipe: 'cmd:verify', command: 'bun scripts/release-loop/verify-node.ts' },
64
78
  'traffic-verify-complete': { recipe: 'cmd:traffic-verify-complete', command: 'bun scripts/release-loop/traffic-node.ts traffic-verify-complete' },
@@ -67,7 +81,6 @@ const RELEASE_NODE_COMMANDS: Readonly<Record<string, { recipe: string; command?:
67
81
  'release-story': { recipe: 'cmd:release-story', command: 'bun scripts/release-story/draft.ts --graph' },
68
82
  'ops-upgrade': { recipe: 'cmd:ops-upgrade', command: 'bun scripts/release-loop/ops-upgrade-node.ts' },
69
83
  'version-dev-bump': { recipe: 'cmd:version-dev-bump', command: 'bun scripts/release-loop/version-node.ts dev-bump --json' },
70
- 'version-dev-bump-after-failure': { recipe: 'cmd:version-dev-bump', command: 'bun scripts/release-loop/version-node.ts dev-bump --json' },
71
84
  done: { recipe: 'none' },
72
85
  failed: { recipe: 'none' },
73
86
  };
@@ -91,6 +104,7 @@ const LOOP_TERMINAL_STATUS: Readonly<Record<string, Readonly<Record<string, 'don
91
104
  function topLevelTerminalStatus(graphId: string, terminal: string): 'done' | 'failed' | undefined {
92
105
  const aliases = Object.hasOwn(LOOP_TERMINAL_STATUS, graphId) ? LOOP_TERMINAL_STATUS[graphId] : undefined;
93
106
  if (aliases) return Object.hasOwn(aliases, terminal) ? aliases[terminal] : undefined;
107
+ if (terminal === 'needs-human' || terminal === 'rework') return 'failed';
94
108
  return terminal === 'done' || terminal === 'failed' ? terminal : undefined;
95
109
  }
96
110
 
@@ -148,6 +162,8 @@ export interface GraphRunState {
148
162
  /** Original named terminal when status is its canonical done/failed mapping. */
149
163
  reason?: string;
150
164
  path: string[];
165
+ /** Dry-run path with each fan-out branch's planned writes expanded before its join. */
166
+ plannedPath?: string[];
151
167
  /** startedAt/endedAt (ISO) and seconds are written when the node runs; ledgers before GRAPH-NODE-TIMES (0.2.19) have none. */
152
168
  nodes: Array<{ nodeId: string; ok: boolean; exit: number | null; executed: boolean; output?: unknown; error?: string; reason?: string;
153
169
  failure?: { errorCode: string; message: string; stage: string }; decidedBy?: string; decidedAt?: string;
@@ -166,9 +182,21 @@ export interface GraphRunState {
166
182
  parentRunId?: string;
167
183
  /** The entry chosen by a parent call; absent for existing single-entry runs. */
168
184
  entryNodeId?: string;
169
- unitCalls?: Array<{ node: string; unit: string; version: number; hash: string; childRunId: string; exit: string; steps: number; entry?: string }>;
185
+ unitCalls?: Array<{ node: string; unit: string; version: number; hash: string; childRunId: string; exit: string; steps: number; entry?: string; visit?: number; enteredAtMs?: number; exitedAtMs?: number; durationMs?: number }>;
186
+ /** Persisted fan-out child identities and terminal results; successful branches are immutable on resume. */
187
+ fanOuts?: Record<string, { from: string; join: string; branches: Record<string, {
188
+ runId: string; status: 'running' | 'done' | 'failed'; startedAt: string; endedAt?: string;
189
+ artifactSha256?: string; output?: unknown; error?: string; path?: string[];
190
+ }> }>;
191
+ /** Highest visit number handed to each unit in this run; not rewound by a restart, so
192
+ * a resumed run never reuses a (runId, unit, visit) span. */
193
+ unitVisitSeq?: Record<string, number>;
170
194
  growth?: GraphGrowth[];
171
195
  growthRejections?: Array<{ from: string; outcome: string; reason: string }>;
196
+ growthAttempts?: number;
197
+ /** `rejected` can represent a cap refusal before proposer invocation; `proposal` means the proposer was actually called.
198
+ * Legacy parked states without this field resume append-only, so their first recorded event may be applied/rejected. */
199
+ growthEvents?: Array<{ phase: 'proposal' | 'parked' | 'applied' | 'rejected' | 'undo-available'; from: string; outcome: string; at: string; nodeId?: string; kind?: string; reason?: string; undo?: GraphGrowth['undo'] }>;
172
200
  growthPark?: { from: string; outcome: string; reason: string; decisionId: string; decisionRef: string; growth: GraphGrowth; command?: GrowthCommand; approval?: string };
173
201
  resume?: { from: string; at: string; previousStatus: GraphRunState['status']; graph?: 'snapshot' | 'current' };
174
202
  /** GATE-HOST-EXECUTOR — every explicit input change a resume made (what was set and what it replaced), oldest first. */
@@ -225,6 +253,8 @@ export async function runGraphClassifyNode(node: ClassifyNode, ctx: NodeExecCont
225
253
 
226
254
  export interface GraphRunOptions {
227
255
  input?: unknown;
256
+ /** Abort an active graph command and stop before dispatching the next node. */
257
+ signal?: AbortSignal;
228
258
  /** Bytes already checked by the tick gate, used for a current-graph start or legacy resume. */
229
259
  graphSource?: string;
230
260
  dryRun?: boolean;
@@ -256,9 +286,15 @@ export interface GraphRunOptions {
256
286
  pinChildUniverse?: boolean;
257
287
  /** Release resume: command checkout and cut tip, checked before every Bash dispatch. */
258
288
  releaseCommandSource?: { root: string; cutTip: string; git?: (args: string[]) => string };
289
+ /** Internal fan-out child: the parent release ledger's verified cut tip. */
290
+ branchCutTip?: string;
291
+ /** Internal fan-out child: the original release graph snapshot (its entry-only graph is synthetic). */
292
+ branchGraphSnapshot?: { graphSha: string; recipesSha: string };
293
+ /** Parent outputs visible to a fan-out child, before its branch-local outputs. */
294
+ branchParentOutputs?: Readonly<Record<string, unknown>>;
259
295
  /** Optional per-run Bloom edge policy hook. */
260
296
  researchEdgeDecisionRegistry?: ResearchEdgeDecisionRegistry;
261
- deps?: { root?: string; runBash?: BashRun; callLLM?: (prompt: string) => Promise<string>; log?: (event: string, data: Record<string, unknown>) => void; beforeNode?: () => void; processStartMs?: (pid: number) => number | null; growthProposer?: GrowthProposer; growthLLM?: (prompt: string) => Promise<string>; classifyGrowthRecipe?: (node: GraphNodeSpec, resolved: { command?: string; approval?: string }) => GrowthRecipeEffect; growthDecision?: GrowthDecisionDeps & { list?: (filters: { status: 'all' }) => DecisionEntry[] }; inProcessHandlers?: InProcessHandlerRegistry };
297
+ deps?: { root?: string; runBash?: BashRun; callLLM?: (prompt: string) => Promise<string>; log?: (event: string, data: Record<string, unknown>) => void; beforeNode?: () => void; processStartMs?: (pid: number) => number | null; monotonicMs?: () => number; growthProposer?: GrowthProposer; growthLLM?: (prompt: string) => Promise<string>; growthScope?: GraphGrowthScope; classifyGrowthRecipe?: (node: GraphNodeSpec, resolved: { command?: string; approval?: string }) => GrowthRecipeEffect; growthDecision?: GrowthDecisionDeps & { list?: (filters: { status: 'all' }) => DecisionEntry[] }; inProcessHandlers?: InProcessHandlerRegistry };
262
298
  }
263
299
 
264
300
  /** The command directory must itself be the checkout at the cut tip. */
@@ -582,7 +618,8 @@ export function lastJsonObject(stdout: unknown): Record<string, unknown> | undef
582
618
  }
583
619
 
584
620
  /** Reconstruct the run-local edges from the ledger without rewriting the YAML snapshot. */
585
- function withGrowth(graph: GraphTemplateSpec, growth: readonly GraphGrowth[]): GraphTemplateSpec {
621
+ /** Apply validated, run-local edge growth to a graph snapshot. Exported for the graph simulator device. */
622
+ export function withGrowth(graph: GraphTemplateSpec, growth: readonly GraphGrowth[]): GraphTemplateSpec {
586
623
  return growth.reduce<GraphTemplateSpec>((current, item) => {
587
624
  const edge = current.edges.find((candidate) => candidate.from === item.undo.removeOutcome.from);
588
625
  if (!edge || !edge.map || !item.node || item.undo.removeNode !== item.node.nodeId ||
@@ -598,7 +635,8 @@ function withGrowth(graph: GraphTemplateSpec, growth: readonly GraphGrowth[]): G
598
635
  }
599
636
 
600
637
  /** 이름 붙은 결과: 산출의 `outcome` 이 그 간선 map 의 키면 그 목적지 — 아니면 종전 ok/fail(exit) → fallback. */
601
- function nextNode(edges: readonly GraphEdgeSpec[], nodeId: string, exitOutcome: 'ok' | 'fail', namedOutcome?: string): string | undefined {
638
+ /** Production edge selection shared by runGraph and the graph simulator device. */
639
+ export function nextNode(edges: readonly GraphEdgeSpec[], nodeId: string, exitOutcome: 'ok' | 'fail', namedOutcome?: string): string | undefined {
602
640
  const edge = edges.find((e) => e.from === nodeId);
603
641
  if (!edge) return undefined;
604
642
  if (edge.to !== undefined) return edge.to;
@@ -607,6 +645,38 @@ function nextNode(edges: readonly GraphEdgeSpec[], nodeId: string, exitOutcome:
607
645
  return edge.map?.[exitOutcome] ?? edge.fallback?.[0]?.node;
608
646
  }
609
647
 
648
+ function releaseRouteReachesKnownIssues(edges: readonly GraphEdgeSpec[], startAt: string): boolean {
649
+ const forbidden = new Set(['publish', 'approve-publish']);
650
+ const seen = new Set<string>();
651
+ let cursor: string | undefined = startAt;
652
+ while (cursor && cursor !== 'known-issues' && !seen.has(cursor)) {
653
+ if (forbidden.has(cursor)) return false;
654
+ seen.add(cursor);
655
+ const edge = edges.find((candidate) => candidate.from === cursor);
656
+ if (!edge) return false;
657
+ if (edge.branches) {
658
+ if (Object.values(edge.branches).flat().some((nodeId) => forbidden.has(nodeId))) return false;
659
+ cursor = edge.join;
660
+ } else {
661
+ cursor = nextNode(edges, cursor, 'ok', 'ok');
662
+ }
663
+ }
664
+ return cursor === 'known-issues' && ![...seen].some((nodeId) => forbidden.has(nodeId));
665
+ }
666
+
667
+ function fanOutGraphSource(source: string, graph: GraphTemplateSpec, branchNode: string): string {
668
+ const document = parseYaml(source) as Record<string, unknown>;
669
+ const terminals = graph.terminalNodes;
670
+ const done = graph.unit ? terminals.find((terminal) => terminal === 'done')
671
+ : terminals.find((terminal) => topLevelTerminalStatus(graph.graphId, terminal) === 'done');
672
+ const failed = graph.unit ? terminals.find((terminal) => terminal === 'failed')
673
+ : terminals.find((terminal) => topLevelTerminalStatus(graph.graphId, terminal) === 'failed');
674
+ if (!done || !failed) throw new Error(`fan-out requires declared success and failure terminals: ${graph.graphId}`);
675
+ document.entry_node = branchNode;
676
+ document.edges = [{ from: branchNode, on: 'outcome', map: { ok: done, fail: failed, error: failed } }];
677
+ return stringifyYaml(document);
678
+ }
679
+
610
680
  type ResolvedUnit = ResolvedGraphUnit;
611
681
  export const resolveUnit = resolveGraphUnit;
612
682
 
@@ -648,6 +718,12 @@ function validateUnitCallsWithResolver(graph: GraphTemplateSpec, path: string, a
648
718
  }
649
719
 
650
720
  export async function runGraph(path: string, options: GraphRunOptions = {}): Promise<GraphRunState> {
721
+ const scopedContext = options.deps?.growthScope ?? graphGrowthScope.getStore();
722
+ const envGrowthScope = process.env[GRAPH_GROWTH_SCOPE_ENV];
723
+ // A separate Pod process cannot inherit AsyncLocalStorage. Only the explicit
724
+ // harness handoff is trusted from env; task-agent remains an in-process scope.
725
+ const growthScope = scopedContext ?? (envGrowthScope === 'harness' ? 'harness' : undefined);
726
+ const rejectedGrowthScopeEnv = scopedContext === undefined && envGrowthScope !== undefined && envGrowthScope !== 'harness';
651
727
  if (options.resumeRunId && options.runId) throw new Error('runId and resumeRunId cannot be combined');
652
728
  if (options.fromNodeId && !options.resumeRunId) throw new Error('--from requires --resume');
653
729
  if (options.useCurrentGraph && !options.resumeRunId) throw new Error('--use-current-graph requires --resume');
@@ -711,7 +787,9 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
711
787
  })),
712
788
  edges: graph.edges.map((edge, index) => ({
713
789
  ...((document.edges as Record<string, unknown>[])[index] ?? {}), from: edge.from,
714
- ...(edge.to === undefined ? { on: edge.on, map: edge.map } : { to: edge.to }),
790
+ ...(edge.to === undefined ? { on: edge.on, ...(edge.map ? { map: edge.map } : {}),
791
+ ...(edge.branches ? { branches: edge.branches, join: edge.join,
792
+ ...(edge.warningBranches ? { warning_branches: edge.warningBranches } : {}) } : {}) } : { to: edge.to }),
715
793
  ...(edge.fallback ? { fallback: edge.fallback } : {}),
716
794
  })),
717
795
  }) : source;
@@ -810,17 +888,22 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
810
888
  ...(options.input === undefined ? {} : { input: options.input }),
811
889
  ...(options.unitContext?.entryNodeId === undefined ? {} : { entryNodeId: options.unitContext.entryNodeId }),
812
890
  executed: 0, dryRun: options.dryRun === true, statePath };
891
+ const branchResume = options.fromNodeId ? Object.values(state.fanOuts ?? {}).flatMap((fanout) =>
892
+ fanout.branches[options.fromNodeId!] !== undefined ? [{ fanout, branchId: options.fromNodeId! }] : [])[0] : undefined;
893
+ if (branchResume) {
894
+ throw new Error(`--from cannot resume fan-out branch '${branchResume.branchId}'; resume from fan-out source '${branchResume.fanout.from}' instead`);
895
+ }
813
896
  const verifyReleaseSource = (): string | undefined => {
814
897
  const source = options.releaseCommandSource;
815
898
  if (!source) return undefined;
816
- const savedCutTip = lastJsonObject(state.nodes.find((node) => node.nodeId === 'version-release')?.output)?.commit;
817
- if (graphId !== 'release-loop' || !options.resumeRunId || typeof savedCutTip !== 'string' || source.cutTip !== savedCutTip) {
899
+ const savedCutTip = lastJsonObject(state.nodes.find((node) => node.nodeId === 'version-release')?.output)?.commit ?? options.branchCutTip;
900
+ if (graphId !== 'release-loop' || (!options.resumeRunId && !options.branchCutTip) || typeof savedCutTip !== 'string' || source.cutTip !== savedCutTip) {
818
901
  throw new Error('release command source differs from the saved cut tip');
819
902
  }
820
903
  const commandRoot = verifyReleaseCommandRoot(source.root, savedCutTip, source.git);
821
904
  // The ledger snapshot must be the recipe that the cut checkout actually carries.
822
905
  // HEAD alone does not bind a saved graph to that checkout.
823
- verifyReleaseRecipeSnapshot(commandRoot, state.graphSnapshot);
906
+ verifyReleaseRecipeSnapshot(commandRoot, options.branchGraphSnapshot ?? state.graphSnapshot);
824
907
  return commandRoot;
825
908
  };
826
909
  verifyReleaseSource();
@@ -853,8 +936,16 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
853
936
  if (i > 0) {
854
937
  const prior = state.nodes[i - 1]!;
855
938
  const reported = lastJsonObject(prior.output)?.outcome;
856
- const next = nextNode(graph.edges, prior.nodeId, prior.ok ? 'ok' : 'fail', typeof reported === 'string' ? reported : undefined);
857
- if (next !== recorded.nodeId) throw new Error('saved run path does not follow graph edges');
939
+ const priorEdge = graph.edges.find((candidate) => candidate.from === prior.nodeId);
940
+ const exitOutcome = prior.ok ? 'ok' : 'fail';
941
+ const namedOutcome = typeof reported === 'string' ? reported : undefined;
942
+ const branchOutcome = priorEdge?.branches && namedOutcome && Object.hasOwn(priorEdge.branches, namedOutcome)
943
+ ? namedOutcome : priorEdge?.branches && Object.hasOwn(priorEdge.branches, exitOutcome) ? exitOutcome : undefined;
944
+ const next = branchOutcome !== undefined && priorEdge?.join
945
+ ? priorEdge.join : nextNode(graph.edges, prior.nodeId, exitOutcome, namedOutcome);
946
+ if (next !== recorded.nodeId) {
947
+ throw new Error(`saved run path does not follow graph edges: ${prior.nodeId} -> ${recorded.nodeId}, expected ${next ?? '<terminal>'}`);
948
+ }
858
949
  } else if (recorded.nodeId !== unitEntryNode) throw new Error('saved run path does not start at entry node');
859
950
  if (i < from && !recorded.ok) {
860
951
  // A warning-only node explicitly sends every outcome to the same next
@@ -887,23 +978,15 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
887
978
  const checked = releaseResumeWaiver(state, { from: options.fromNodeId, waive: options.releaseWaiver.nodeId, reason: options.releaseWaiver.reason, acceptedRegressions: options.releaseWaiver.requestedRegressions });
888
979
  if (!checked || JSON.stringify(checked.acceptedRegressions) !== JSON.stringify(options.releaseWaiver.acceptedRegressions) ||
889
980
  checked.unmeasured !== options.releaseWaiver.unmeasured) throw new Error('release waiver input changed before restart');
890
- const route = new Set<string>();
891
- let cursor: string | undefined = nextNode(graph.edges, options.fromNodeId, 'ok', 'ok');
892
- while (cursor && !route.has(cursor) && cursor !== 'known-issues') {
893
- route.add(cursor);
894
- cursor = nextNode(graph.edges, cursor, 'ok', 'ok');
981
+ if (!releaseRouteReachesKnownIssues(graph.edges, nextNode(graph.edges, options.fromNodeId, 'ok', 'ok') ?? '')) {
982
+ throw new Error('waived node must reach known-issues before publication');
895
983
  }
896
- if (cursor !== 'known-issues' || route.has('publish') || route.has('approve-publish')) throw new Error('waived node must reach known-issues before publication');
897
984
  }
898
985
  if (options.releaseAcceptedRegressions) {
899
986
  if (graphId !== 'release-loop') throw new Error('accepted regressions require the release-loop graph');
900
- const route = new Set<string>();
901
- let cursor: string | undefined = options.fromNodeId;
902
- while (cursor && !route.has(cursor) && cursor !== 'known-issues') {
903
- route.add(cursor);
904
- cursor = nextNode(graph.edges, cursor, 'ok', 'ok');
987
+ if (!releaseRouteReachesKnownIssues(graph.edges, options.fromNodeId)) {
988
+ throw new Error('accepted regressions must reach known-issues before publication');
905
989
  }
906
- if (cursor !== 'known-issues' || route.has('publish') || route.has('approve-publish')) throw new Error('accepted regressions must reach known-issues before publication');
907
990
  const checked = releaseResumeAcceptedRegressions(state, options.releaseAcceptedRegressions.requested, options.fromNodeId);
908
991
  if (JSON.stringify(checked) !== JSON.stringify(options.releaseAcceptedRegressions.acceptedRegressions)) throw new Error('accepted regressions changed before restart');
909
992
  state.input = { ...(state.input as Record<string, unknown>), acceptedRegressions: checked };
@@ -994,7 +1077,16 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
994
1077
  graph = withGrowth(graph, [parked.growth]);
995
1078
  state.growth ??= [];
996
1079
  state.growth.push(parked.growth);
1080
+ state.growthEvents ??= [];
1081
+ state.growthEvents.push({ phase: 'applied', from: parked.from, outcome: parked.outcome, at: new Date().toISOString(),
1082
+ nodeId: parked.growth.node.nodeId, kind: parked.growth.node.kind });
1083
+ state.growthEvents.push({ phase: 'undo-available', from: parked.from, outcome: parked.outcome, at: new Date().toISOString(),
1084
+ nodeId: parked.growth.node.nodeId, undo: parked.growth.undo });
997
1085
  state.growthRejections!.pop();
1086
+ } else {
1087
+ state.growthEvents ??= [];
1088
+ state.growthEvents.push({ phase: 'rejected', from: parked.from, outcome: parked.outcome, at: new Date().toISOString(),
1089
+ nodeId: parked.growth.node.nodeId, kind: parked.growth.node.kind, reason: 'human rejected growth proposal' });
998
1090
  }
999
1091
  resumedGrowth = true;
1000
1092
  delete state.pending;
@@ -1033,9 +1125,21 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1033
1125
  const log = options.unitContext
1034
1126
  ? (event: string, data: Record<string, unknown>) => baseLog(event, { ...data, parentRunId: options.unitContext!.parentRunId })
1035
1127
  : baseLog;
1128
+ if (rejectedGrowthScopeEnv && document.grow === 'on') {
1129
+ log('growth-scope-rejected', { graphId, runId, source: 'env', reason: 'not-allowlisted' });
1130
+ }
1036
1131
  const visits = new Map<string, number>();
1037
1132
  for (const nodeId of state.path) visits.set(nodeId, (visits.get(nodeId) ?? 0) + 1);
1133
+ // GRAPH-UNIT-SPAN-DURATION: visit index per unit within this run, so enter/exit of
1134
+ // the same (runId, unit, visit) can be paired. The clock source is monotonic and
1135
+ // injectable (fake clock in tests); it never goes backwards in production. The
1136
+ // sequence is carried on the run state so a restart continues it.
1137
+ const unitVisits = new Map<string, number>(Object.entries(state.unitVisitSeq ?? {}));
1138
+ const monotonicMs = options.deps?.monotonicMs ?? (() => performance.now());
1038
1139
  let current: string | undefined = options.fromNodeId ?? state.pending?.nodeId ?? state.path.at(-1) ?? unitEntryNode;
1140
+ let growthScopeSkipLogged = false;
1141
+ let growthCapReachedLogged = state.growthRejections?.some((item) =>
1142
+ item.reason === 'growth proposal limit 8 reached' || item.reason === 'growth limit 3 reached') ?? false;
1039
1143
  if (!options.resumeRunId) {
1040
1144
  mkdirSync(dirname(statePath), { recursive: true });
1041
1145
  if (readdirSync(dirname(statePath)).some((file) => file.startsWith(`${runId}.json.`) && file.endsWith('.decision.json'))) {
@@ -1051,6 +1155,12 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1051
1155
  writeFileSync(join(`${statePath}.graph`, 'recipes.yaml'), recipeSource, { flag: 'wx' });
1052
1156
  }
1053
1157
  while (current !== undefined) {
1158
+ if (options.signal?.aborted) {
1159
+ state.status = 'failed';
1160
+ state.reason = 'cancelled';
1161
+ persist();
1162
+ break;
1163
+ }
1054
1164
  options.deps?.beforeNode?.();
1055
1165
  const node = graph.nodes.find((n) => n.nodeId === current);
1056
1166
  if (!node) throw new Error(`undeclared node: ${current}`);
@@ -1059,8 +1169,12 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1059
1169
  const resumingCompleted = options.resumeRunId !== undefined && !options.fromNodeId && completed?.nodeId === current &&
1060
1170
  state.path.at(-1) === current && !resumingPending;
1061
1171
  const usedSteps = state.path.length + (state.unitCalls ?? []).reduce((sum, call) => sum + call.steps, 0);
1172
+ const effectiveRemaining = Math.min(
1173
+ graph.allowance ? graph.allowance.innerSteps - usedSteps : Infinity,
1174
+ options.unitContext ? options.unitContext.remainingSteps - usedSteps : Infinity,
1175
+ );
1062
1176
  if (!resumingPending && !resumingCompleted && ((visits.get(current) ?? 0) >= node.maxVisits ||
1063
- (options.unitContext && usedSteps >= options.unitContext.remainingSteps))) {
1177
+ (effectiveRemaining <= 0 && !graph.terminalNodes.includes(current)))) {
1064
1178
  state.status = 'budget-exceeded';
1065
1179
  log('budget-exceeded', { graphId, runId, nodeId: current });
1066
1180
  persist();
@@ -1106,17 +1220,25 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1106
1220
  publishInsideEvent({ kind: 'node', graphId, runId, nodeId: current, phase: 'start' });
1107
1221
  log('node-start', { graphId, runId, nodeId: current, visit: visits.get(current), dryRun: state.dryRun });
1108
1222
  persist();
1109
- let ok = approval && !state.dryRun ? state.pending?.decision === 'approved' : true;
1223
+ const joinedFanout = Object.values(state.fanOuts ?? {}).find((fanout) => fanout.join === current &&
1224
+ Object.values(fanout.branches).every((branch) => branch.status === 'done' || branch.status === 'failed'));
1225
+ const warningBranches = joinedFanout
1226
+ ? graph.edges.find((edge) => edge.from === joinedFanout.from)?.warningBranches ?? [] : [];
1227
+ let ok = approval && !state.dryRun ? state.pending?.decision === 'approved' : joinedFanout
1228
+ ? Object.entries(joinedFanout.branches).every(([branchId, branch]) => branch.status === 'done' || warningBranches.includes(branchId)) : true;
1110
1229
  let exit: number | null = null;
1111
1230
  let error: string | undefined;
1112
1231
  let commandFailureReason: string | undefined;
1113
1232
  let output: unknown;
1233
+ if (joinedFanout) output = JSON.stringify({ outcome: ok ? 'ok' : 'fail', branches: joinedFanout.branches });
1114
1234
  const waiving = options.releaseWaiver?.nodeId === current && waivedRecord !== undefined;
1115
1235
  const inProcessHandler = requireInProcessHandler(node.recipe, current, options.deps?.inProcessHandlers);
1116
1236
  let handlerExecuted = false;
1117
1237
  if (inProcessHandler && !waiving && !state.dryRun && !resumingCompleted) {
1118
- const outputs: Record<string, unknown> = Object.create(null);
1238
+ const outputs: Record<string, unknown> = Object.assign(Object.create(null), options.branchParentOutputs ?? {});
1119
1239
  for (const previous of state.nodes) outputs[previous.nodeId] = lastJsonObject(previous.output) ?? previous.output ?? null;
1240
+ for (const fanout of Object.values(state.fanOuts ?? {})) for (const [branchId, branch] of Object.entries(fanout.branches))
1241
+ if (branch.output !== undefined) outputs[branchId] = lastJsonObject(branch.output) ?? branch.output;
1120
1242
  handlerExecuted = true;
1121
1243
  debug.log('graph.run', 'handler-dispatch', { graphId, runId, nodeId: current, recipe: node.recipe });
1122
1244
  try {
@@ -1138,9 +1260,11 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1138
1260
  state.executed++;
1139
1261
  }
1140
1262
  if (command && !waiving && (!approval || state.dryRun || ok) && (!state.dryRun || command.dry_run_command) && !resumingCompleted) {
1141
- const outputs: Record<string, unknown> = Object.create(null);
1263
+ const outputs: Record<string, unknown> = Object.assign(Object.create(null), options.branchParentOutputs ?? {});
1142
1264
  // 구조 산출(마지막 JSON 줄)이 있으면 그것을, 없으면 원문을 준다 — 다음 노드가 판단을 «값»으로 받는다.
1143
1265
  for (const previous of state.nodes) outputs[previous.nodeId] = lastJsonObject(previous.output) ?? previous.output ?? null;
1266
+ for (const fanout of Object.values(state.fanOuts ?? {})) for (const [branchId, branch] of Object.entries(fanout.branches))
1267
+ if (branch.output !== undefined) outputs[branchId] = lastJsonObject(branch.output) ?? branch.output;
1144
1268
  const contextPath = join(`${statePath}.contexts`, `${state.path.length}.json`);
1145
1269
  mkdirSync(dirname(contextPath), { recursive: true });
1146
1270
  writeFileSync(contextPath, JSON.stringify({ graphId, runId, startedAt: state.startedAt, nodeId: current, input: state.input ?? null, outputs }, null, 2) + '\n');
@@ -1196,7 +1320,8 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1196
1320
  env.ELANOUS_GRAPH_CONTEXT = contextPath;
1197
1321
  env.ELANOUS_GRAPH_DRY_RUN = state.dryRun ? '1' : '0';
1198
1322
  env.ELANOUS_GRAPH_DIR = dirname(resolve(path));
1199
- const ctx = { arguments: '', artifactsDir: dirname(statePath), outputs: {}, resolvedProvider: undefined, resolvedModel: undefined, toolPolicy: {}, env } as NodeExecContext;
1323
+ const ctx = { arguments: '', artifactsDir: dirname(statePath), outputs: {}, resolvedProvider: undefined, resolvedModel: undefined, toolPolicy: {}, env,
1324
+ ...(options.signal ? { signal: options.signal } : {}) } as NodeExecContext;
1200
1325
  const result = await executeBashNode({ id: current, type: 'bash', bash: state.dryRun ? command.dry_run_command! : command.command,
1201
1326
  idle_timeout: command.timeout_ms ?? DEFAULT_BASH_TIMEOUT_MS } as BashNode, ctx, { runBash } as WorkflowDeps);
1202
1327
  output = result.output;
@@ -1231,25 +1356,53 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1231
1356
  if (value !== undefined) inputs[key] = value;
1232
1357
  }
1233
1358
  const alreadySpent = state.path.length + (state.unitCalls ?? []).reduce((sum, call) => sum + call.steps, 0);
1234
- const remaining = options.unitContext ? options.unitContext.remainingSteps - alreadySpent : Infinity;
1359
+ const remaining = Math.min(
1360
+ graph.allowance ? graph.allowance.innerSteps - alreadySpent : Infinity,
1361
+ options.unitContext ? options.unitContext.remainingSteps - alreadySpent : Infinity,
1362
+ );
1363
+ const requested = Math.min(node.budget!.innerSteps, node.allowance?.innerSteps ?? node.budget!.innerSteps);
1364
+ const allowance = resolveChildAllowance(requested, Math.max(0, remaining));
1235
1365
  const childRunId = randomUUID();
1236
1366
  const selectedEntry = node.callEntry ?? unit.template.entryNode;
1237
1367
  const recordEntry = node.callEntry !== undefined || unit.template.unit?.entries !== undefined;
1238
1368
  const info = { graphId, runId, nodeId: current, unit: unit.template.graphId, childRunId, parentRunId: runId,
1239
1369
  ...(recordEntry ? { entry: selectedEntry } : {}) };
1240
1370
  let entered = false;
1241
- try {
1371
+ let span: { visit: number; enteredAtMs: number } | undefined;
1372
+ if (allowance.kind === 'needs-human') {
1373
+ const exitName = unit.template.unit!.exits.includes('needs-human') ? 'needs-human'
1374
+ : unit.template.unit!.exits.includes('rework') ? 'rework' : undefined;
1375
+ if (!exitName) throw new Error(`unit has no needs-human or rework exit for zero allowance: ${current}`);
1376
+ output = JSON.stringify({ outcome: exitName });
1377
+ ok = false;
1378
+ error = `unit allowance exhausted before execution: ${current}`;
1379
+ debug.log('graph.unit', 'allowance-exhausted', { ...info, requested: allowance.requested, remaining: 0, exit: exitName });
1380
+ log('graph.unit', { ...info, phase: 'allowance-exhausted', requested: allowance.requested, remaining: 0, exit: exitName });
1381
+ } else try {
1242
1382
  for (const key of contract.inputs) if (!Object.hasOwn(inputs, key)) throw new Error(`unit input missing: ${current}.${key}`);
1243
1383
  if (createHash('sha256').update(readFileSync(unit.path, 'utf8')).digest('hex') !== unit.hash)
1244
1384
  throw new Error(`unit source changed before call: ${current}`);
1245
- debug.log('graph.unit', 'enter', info);
1246
- log('graph.unit', { ...info, phase: 'enter' });
1385
+ const visitIndex = (unitVisits.get(unit.template.graphId) ?? 0) + 1;
1386
+ unitVisits.set(unit.template.graphId, visitIndex);
1387
+ (state.unitVisitSeq ??= {})[unit.template.graphId] = visitIndex;
1388
+ const enteredAtMs = monotonicMs();
1389
+ span = { visit: visitIndex, enteredAtMs };
1390
+ debug.log('graph.unit', 'enter', { ...info, ...span });
1391
+ log('graph.unit', { ...info, phase: 'enter', ...span });
1392
+ if (allowance.clamped) {
1393
+ debug.log('graph.unit', 'allowance-clamped', { ...info, requested: allowance.requested, granted: allowance.granted, remaining });
1394
+ log('graph.unit', { ...info, phase: 'allowance-clamped', requested: allowance.requested, granted: allowance.granted, remaining });
1395
+ }
1247
1396
  entered = true;
1248
1397
  const child = await runGraph(unit.path, { runId: childRunId, input: inputs, dryRun: false,
1398
+ ...(options.signal ? { signal: options.signal } : {}),
1249
1399
  pinChildUniverse: options.pinChildUniverse,
1250
1400
  unitContext: { parentRunId: runId, ancestors: [...(options.unitContext?.ancestors ?? []), graphId],
1251
- remainingSteps: Math.min(node.budget!.innerSteps, remaining),
1401
+ remainingSteps: allowance.granted,
1252
1402
  ...(recordEntry ? { entryNodeId: selectedEntry } : {}) }, deps: options.deps });
1403
+ const exitedAtMs = monotonicMs();
1404
+ // Same (runId, unit, visit): never let a clock that went backwards emit a negative span.
1405
+ const durationMs = Math.max(0, exitedAtMs - enteredAtMs);
1253
1406
  const steps = child.path.length + (child.unitCalls ?? []).reduce((sum, call) => sum + call.steps, 0);
1254
1407
  const childExit = child.status === 'done' || child.status === 'failed' ? child.path.at(-1) : undefined;
1255
1408
  // The last successful record carrying every contracted output is the source;
@@ -1264,9 +1417,10 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1264
1417
  state.unitCalls ??= [];
1265
1418
  state.unitCalls.push({ node: current, unit: unit.template.graphId, version: unit.template.version,
1266
1419
  hash: unit.hash, childRunId, exit: childExit ?? child.status, steps,
1420
+ visit: visitIndex, enteredAtMs, exitedAtMs, durationMs,
1267
1421
  ...(recordEntry ? { entry: selectedEntry } : {}) });
1268
1422
  if (child.status === 'awaiting-approval') throw new Error(`unit cannot pause for approval: ${current}`);
1269
- if (child.status === 'budget-exceeded' || steps > node.budget!.innerSteps || steps > remaining) {
1423
+ if (child.status === 'budget-exceeded' || steps > allowance.granted || steps > remaining) {
1270
1424
  debug.log('graph.unit', 'budget-exhausted', { ...info, steps, innerSteps: node.budget!.innerSteps });
1271
1425
  log('graph.unit', { ...info, phase: 'budget-exhausted', steps });
1272
1426
  throw new Error(`unit inner_steps exceeded: ${current}`);
@@ -1280,14 +1434,21 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1280
1434
  }
1281
1435
  output = JSON.stringify(result);
1282
1436
  ok = child.status === 'done';
1283
- debug.log('graph.unit', 'exit', { ...info, exit: childExit, steps });
1284
- log('graph.unit', { ...info, phase: 'exit', exit: childExit, steps });
1437
+ debug.log('graph.unit', 'exit', { ...info, exit: childExit, steps, visit: visitIndex, enteredAtMs, exitedAtMs, durationMs });
1438
+ log('graph.unit', { ...info, phase: 'exit', exit: childExit, steps, visit: visitIndex, enteredAtMs, exitedAtMs, durationMs });
1285
1439
  } catch (cause) {
1286
1440
  ok = false;
1287
1441
  error = redactCredentials(cause instanceof Error ? cause.message : String(cause));
1288
- if (entered) {
1289
- debug.log('graph.unit', 'exit', { ...info, error });
1290
- log('graph.unit', { ...info, phase: 'exit', error });
1442
+ if (entered && span) {
1443
+ const exitedAtMs = monotonicMs();
1444
+ const durationMs = Math.max(0, exitedAtMs - span.enteredAtMs);
1445
+ const call = state.unitCalls?.at(-1);
1446
+ if (call && call.childRunId === childRunId) {
1447
+ call.exitedAtMs = exitedAtMs;
1448
+ call.durationMs = durationMs;
1449
+ }
1450
+ debug.log('graph.unit', 'exit', { ...info, error, ...span, exitedAtMs, durationMs });
1451
+ log('graph.unit', { ...info, phase: 'exit', error, ...span, exitedAtMs, durationMs });
1291
1452
  }
1292
1453
  }
1293
1454
  // A rejected invocation has no child ledger and did not execute a unit.
@@ -1389,7 +1550,7 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1389
1550
  delete state.pending;
1390
1551
  delete state.approvalSourceHash;
1391
1552
  }
1392
- const reported: unknown = waiving || harnessLoopRoute || units.has(current) || handlerExecuted || (resumingCompleted && inProcessHandler) || (prompt && !state.dryRun) || (command && (!state.dryRun || command.dry_run_command)) ? lastJsonObject(resumingCompleted ? completed?.output : output)?.outcome : undefined;
1553
+ const reported: unknown = joinedFanout || waiving || harnessLoopRoute || units.has(current) || handlerExecuted || (resumingCompleted && inProcessHandler) || (prompt && !state.dryRun) || (command && (!state.dryRun || command.dry_run_command)) ? lastJsonObject(resumingCompleted ? completed?.output : output)?.outcome : undefined;
1393
1554
  const namedOutcome: string | undefined = typeof reported === 'string' ? reported : undefined;
1394
1555
  if (!options.quiet) console.error(`[graph] ${current} ${ok ? 'ok' : 'fail'} (${seconds.toFixed(2)}s)`);
1395
1556
  const nodeFailure = state.nodes.at(-1)?.nodeId === current ? state.nodes.at(-1)?.failure : undefined;
@@ -1406,6 +1567,12 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1406
1567
  observeModelInputTokens({ scope: 'harness-node', nodeKind: node.kind, runId, nodeId: current });
1407
1568
  }
1408
1569
  persist();
1570
+ if (options.signal?.aborted) {
1571
+ state.status = 'failed';
1572
+ state.reason = 'cancelled';
1573
+ persist();
1574
+ break;
1575
+ }
1409
1576
  if (graph.terminalNodes.includes(current)) {
1410
1577
  state.status = !ok ? 'failed' : graph.unit ? (current === 'failed' ? 'failed' : 'done')
1411
1578
  : topLevelTerminalStatus(graph.graphId, current)!;
@@ -1419,30 +1586,62 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1419
1586
  }
1420
1587
  const fromNodeId = current;
1421
1588
  const edge = graph.edges.find((candidate) => candidate.from === current);
1422
- if (!resumedGrowth && document.grow === 'on' && !state.dryRun && namedOutcome !== undefined &&
1589
+ if (!growthScope && !growthScopeSkipLogged && !resumedGrowth && document.grow === 'on' && !state.dryRun && namedOutcome !== undefined &&
1590
+ (state.growthAttempts ?? 0) < 8 && (state.growth?.length ?? 0) < 3 &&
1423
1591
  edge?.on === 'outcome' && edge.map && !Object.hasOwn(edge.map, namedOutcome) &&
1424
1592
  !state.growth?.some((item) => item.undo.removeOutcome.from === current && item.undo.removeOutcome.outcome === namedOutcome) &&
1425
1593
  !state.growthRejections?.some((item) => item.from === current && item.outcome === namedOutcome)) {
1426
- const result = (state.growth?.length ?? 0) >= 3 ? { ok: false as const, reason: 'growth limit 3 reached' }
1427
- : await proposeGrowth({ graph, nodeId: current, outcome: namedOutcome, runId, output: state.nodes.at(-1)?.output },
1428
- options.deps?.growthProposer ?? createLLMGrowthProposer(options.deps?.growthLLM), (candidate) => {
1594
+ growthScopeSkipLogged = true;
1595
+ log('growth-skipped-no-scope', { graphId, runId, from: current, outcome: namedOutcome });
1596
+ }
1597
+ if (growthScope && !growthCapReachedLogged && !resumedGrowth && document.grow === 'on' && !state.dryRun && namedOutcome !== undefined &&
1598
+ edge?.on === 'outcome' && edge.map && !Object.hasOwn(edge.map, namedOutcome) &&
1599
+ !state.growth?.some((item) => item.undo.removeOutcome.from === current && item.undo.removeOutcome.outcome === namedOutcome) &&
1600
+ !state.growthRejections?.some((item) => item.from === current && item.outcome === namedOutcome)) {
1601
+ state.growthEvents ??= [];
1602
+ let result: Awaited<ReturnType<typeof proposeGrowth>>;
1603
+ if ((state.growthAttempts ?? 0) >= 8) result = { ok: false, reason: 'growth proposal limit 8 reached' };
1604
+ else if ((state.growth?.length ?? 0) >= 3) result = { ok: false, reason: 'growth limit 3 reached' };
1605
+ else {
1606
+ const at = new Date().toISOString();
1607
+ const input = { graph, nodeId: current, outcome: namedOutcome, runId, output: state.nodes.at(-1)?.output };
1608
+ state.growthEvents.push({ phase: 'proposal', from: current, outcome: namedOutcome, at });
1609
+ state.growthAttempts = (state.growthAttempts ?? 0) + 1;
1610
+ persist();
1611
+ const allowedKinds = new Set(['agent', 'observe', 'judge']);
1612
+ const proposer = options.deps?.growthProposer ?? createLLMGrowthProposer(options.deps?.growthLLM);
1613
+ // Enforce the vocabulary at the runner boundary even when a caller injects a non-LLM proposer.
1614
+ const constrainedProposer: GrowthProposer = async (proposalInput) => {
1615
+ const proposal = await proposer(proposalInput);
1616
+ return proposal && allowedKinds.has(proposal.node.kind) ? proposal : undefined;
1617
+ };
1618
+ result = await proposeGrowth(input, constrainedProposer, (candidate) => {
1429
1619
  const resolved = resolveNodeRecipe(candidate, recipes, catalogRoles);
1430
1620
  if (!resolved.command && !resolved.approval && candidate.recipe !== 'none') return 'unknown';
1431
1621
  return { effect: resolved.approval ? 'unknown' : options.deps?.classifyGrowthRecipe?.(candidate, { command: resolved.command?.command }) ?? 'unknown',
1432
1622
  command: resolved.command, approval: resolved.approval?.approval };
1433
1623
  }, { ...options.deps?.growthDecision, root }, options.researchEdgeDecisionRegistry);
1624
+ }
1434
1625
  if (result.ok) {
1435
1626
  graph = result.graph;
1436
1627
  state.growth ??= [];
1437
1628
  state.growth.push(result.growth);
1629
+ state.growthEvents.push({ phase: 'applied', from: current, outcome: namedOutcome, at: new Date().toISOString(),
1630
+ nodeId: result.growth.node.nodeId, kind: result.growth.node.kind });
1631
+ state.growthEvents.push({ phase: 'undo-available', from: current, outcome: namedOutcome, at: new Date().toISOString(),
1632
+ nodeId: result.growth.node.nodeId, undo: result.growth.undo });
1438
1633
  persist();
1439
1634
  log('edge-added', { graphId, runId, from: current, outcome: namedOutcome, to: result.growth.node.nodeId });
1440
1635
  debug.log('graph.run', 'edge-added', { graphId, runId, from: current, outcome: namedOutcome, to: result.growth.node.nodeId });
1441
1636
  publishInsideEvent({ kind: 'edge-added', graphId, runId, from: current, outcome: namedOutcome, to: result.growth.node.nodeId });
1442
1637
  } else {
1443
1638
  state.growthRejections ??= [];
1639
+ const capped = result.reason === 'growth proposal limit 8 reached' || result.reason === 'growth limit 3 reached';
1640
+ if (capped) growthCapReachedLogged = true;
1444
1641
  state.growthRejections.push({ from: current, outcome: namedOutcome, reason: result.reason });
1445
1642
  if (result.park && result.growth && result.decisionId && result.decisionRef) {
1643
+ state.growthEvents.push({ phase: 'parked', from: current, outcome: namedOutcome, at: new Date().toISOString(), reason: result.reason,
1644
+ nodeId: result.growth.node.nodeId, kind: result.growth.node.kind, undo: result.growth.undo });
1446
1645
  state.status = 'awaiting-approval';
1447
1646
  state.pending = { nodeId: current, message: result.reason, since: new Date().toISOString() };
1448
1647
  state.growthPark = { from: current, outcome: namedOutcome, reason: result.reason,
@@ -1451,12 +1650,66 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1451
1650
  persist();
1452
1651
  break;
1453
1652
  }
1653
+ state.growthEvents.push({ phase: 'rejected', from: current, outcome: namedOutcome, at: new Date().toISOString(), reason: result.reason,
1654
+ ...(result.growth ? { nodeId: result.growth.node.nodeId, kind: result.growth.node.kind, undo: result.growth.undo } : {}) });
1454
1655
  }
1455
1656
  persist();
1456
1657
  }
1457
1658
  // A planned harness loop follows its route directly: `changed-files` edges have no runner condition.
1458
- current = plannedStep ? plannedStep.to
1459
- : nextNode(graph.edges, current, state.dryRun && !command?.dry_run_command ? 'ok' : ok ? 'ok' : 'fail', namedOutcome);
1659
+ const edgeOutcome: 'ok' | 'fail' = state.dryRun && !command?.dry_run_command ? 'ok' : ok ? 'ok' : 'fail';
1660
+ const outgoing = graph.edges.find((candidate) => candidate.from === current);
1661
+ const branchOutcome: string | undefined = namedOutcome !== undefined && outgoing?.branches && Object.hasOwn(outgoing.branches, namedOutcome)
1662
+ ? namedOutcome : outgoing?.branches && Object.hasOwn(outgoing.branches, edgeOutcome) ? edgeOutcome : undefined;
1663
+ if (!plannedStep && outgoing?.branches && branchOutcome !== undefined && outgoing.join) {
1664
+ const destinations = outgoing.branches[branchOutcome]!;
1665
+ const fanOutKey: string = `${current}:${branchOutcome}`;
1666
+ const fanout: NonNullable<GraphRunState['fanOuts']>[string] = state.fanOuts?.[fanOutKey] ?? { from: current, join: outgoing.join, branches: {} };
1667
+ if (fanout.join !== outgoing.join) throw new Error(`fan-out state conflicts with graph: ${fanOutKey}`);
1668
+ const runningBranch = destinations.find((id) => fanout.branches[id]?.status === 'running');
1669
+ if (runningBranch) throw new Error(`fan-out branch ${runningBranch} is still marked running; crashed-child recovery is not supported`);
1670
+ state.fanOuts ??= {};
1671
+ state.fanOuts[fanOutKey] = fanout;
1672
+ const selected = destinations.filter((branchId) => fanout.branches[branchId]?.status !== 'done');
1673
+ const launches = selected.map((branchId) => {
1674
+ const runId = randomUUID();
1675
+ fanout.branches[branchId] = { runId, status: 'running', startedAt: new Date().toISOString() };
1676
+ return { branchId, runId };
1677
+ });
1678
+ persist();
1679
+ await Promise.all(launches.map(async ({ branchId, runId }) => {
1680
+ const branch = fanout.branches[branchId]!;
1681
+ try {
1682
+ const child = await runGraph(path, { runId, graphSource: fanOutGraphSource(variantSource, graph, branchId), input: state.input,
1683
+ dryRun: state.dryRun, quiet: true, signal: options.signal, pinChildUniverse: options.pinChildUniverse,
1684
+ releaseCommandSource: options.releaseCommandSource,
1685
+ branchCutTip: lastJsonObject(state.nodes.find((record) => record.nodeId === 'version-release')?.output)?.commit as string | undefined,
1686
+ branchGraphSnapshot: state.graphSnapshot,
1687
+ branchParentOutputs: Object.fromEntries(state.nodes.map((record) => [record.nodeId, lastJsonObject(record.output) ?? record.output ?? null])),
1688
+ researchEdgeDecisionRegistry: options.researchEdgeDecisionRegistry,
1689
+ deps: options.deps });
1690
+ const record = child.nodes.find((item) => item.nodeId === branchId);
1691
+ if (state.dryRun) branch.path = child.path;
1692
+ branch.status = child.status === 'done' && record?.ok ? 'done' : 'failed';
1693
+ if (record?.output !== undefined) {
1694
+ branch.output = record.output;
1695
+ branch.artifactSha256 = createHash('sha256').update(typeof record.output === 'string' ? record.output : JSON.stringify(record.output)).digest('hex');
1696
+ }
1697
+ if (record?.error) branch.error = record.error;
1698
+ else if (child.status !== 'done') branch.error = `branch child run ended ${child.status}`;
1699
+ } catch (cause) {
1700
+ branch.status = 'failed';
1701
+ branch.error = cause instanceof Error ? cause.message : String(cause);
1702
+ }
1703
+ branch.endedAt = new Date().toISOString();
1704
+ persist();
1705
+ return branchId;
1706
+ }));
1707
+ persist();
1708
+ current = outgoing.join;
1709
+ } else {
1710
+ current = plannedStep ? plannedStep.to
1711
+ : nextNode(graph.edges, current, edgeOutcome, namedOutcome);
1712
+ }
1460
1713
  resumedGrowth = false;
1461
1714
  if (current !== undefined) publishInsideEvent({ kind: 'edge', graphId, runId, from: fromNodeId, to: current });
1462
1715
  if (current === undefined) {
@@ -1467,6 +1720,17 @@ export async function runGraph(path: string, options: GraphRunOptions = {}): Pro
1467
1720
  }
1468
1721
  }
1469
1722
  }
1723
+ if (state.dryRun && Object.keys(state.fanOuts ?? {}).length > 0) {
1724
+ const fanoutsBySource = new Map<string, NonNullable<GraphRunState['fanOuts']>[string][]>();
1725
+ for (const fanout of Object.values(state.fanOuts!)) {
1726
+ const group = fanoutsBySource.get(fanout.from) ?? [];
1727
+ group.push(fanout);
1728
+ fanoutsBySource.set(fanout.from, group);
1729
+ }
1730
+ state.plannedPath = state.path.flatMap((nodeId) => [nodeId, ...(fanoutsBySource.get(nodeId) ?? []).flatMap((fanout) =>
1731
+ Object.values(fanout.branches).flatMap((branch) => (branch.path ?? []).filter((branchNode) => !graph.terminalNodes.includes(branchNode))))]);
1732
+ persist();
1733
+ }
1470
1734
  return state;
1471
1735
  } finally {
1472
1736
  if (options.resumeRunId && existsSync(resumeLock)) rmdirSync(resumeLock);