create-harness-vibe-coding 0.8.19 → 0.9.3

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 (656) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README-CN.md +4 -2
  3. package/README.md +23 -4
  4. package/package.json +17 -2
  5. package/src/generator.js +19 -6
  6. package/src/index.js +531 -38
  7. package/src/prompts.js +4 -4
  8. package/src/ui/dist/assets/AgentsRoute-BGGs90wH.js +7 -0
  9. package/src/ui/dist/assets/Assistant-Bold-gm-uSS1B.woff2 +0 -0
  10. package/src/ui/dist/assets/Assistant-Medium-DrcxCXg3.woff2 +0 -0
  11. package/src/ui/dist/assets/Assistant-Regular-DVxZuzxb.woff2 +0 -0
  12. package/src/ui/dist/assets/Assistant-SemiBold-SCI4bEL9.woff2 +0 -0
  13. package/src/ui/dist/assets/Combination-DhBLEmof.js +42 -0
  14. package/src/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  15. package/src/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  16. package/src/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  17. package/src/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  18. package/src/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  19. package/src/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  20. package/src/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  21. package/src/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  22. package/src/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  23. package/src/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  24. package/src/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  25. package/src/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  26. package/src/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  27. package/src/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  28. package/src/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  29. package/src/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  30. package/src/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  31. package/src/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  32. package/src/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  33. package/src/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  34. package/src/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  35. package/src/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  36. package/src/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  37. package/src/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  38. package/src/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  39. package/src/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  40. package/src/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  41. package/src/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  42. package/src/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  43. package/src/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  44. package/src/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  45. package/src/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  46. package/src/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  47. package/src/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  48. package/src/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  49. package/src/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  50. package/src/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  51. package/src/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  52. package/src/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  53. package/src/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  54. package/src/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  55. package/src/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  56. package/src/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  57. package/src/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  58. package/src/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  59. package/src/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  60. package/src/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  61. package/src/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  62. package/src/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  63. package/src/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  64. package/src/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  65. package/src/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  66. package/src/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  67. package/src/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  68. package/src/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  69. package/src/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  70. package/src/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  71. package/src/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  72. package/src/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  73. package/src/ui/dist/assets/RolesRoute-DnodCSz0.js +2 -0
  74. package/src/ui/dist/assets/RuntimePicker-CucD8TGn.js +7 -0
  75. package/src/ui/dist/assets/SettingsRoute-DquMWjac.js +2 -0
  76. package/src/ui/dist/assets/TaskList-Bxc0Uktx.js +7 -0
  77. package/src/ui/dist/assets/TerminalDrawer-CDusYltc.js +36 -0
  78. package/src/ui/dist/assets/WorkflowRoute-BN8yHmUs.css +1 -0
  79. package/src/ui/dist/assets/WorkflowRoute-D-0wVDpY.js +334 -0
  80. package/src/ui/dist/assets/abnfDiagram-VRR7QNED-zkRKkaxO.js +2 -0
  81. package/src/ui/dist/assets/apl-B4CMkyY2.js +2 -0
  82. package/src/ui/dist/assets/ar-SA-G6X2FPQ2-BiHaArx5.js +11 -0
  83. package/src/ui/dist/assets/arc-CBnLtOFO.js +2 -0
  84. package/src/ui/dist/assets/architectureDiagram-ZJ3FMSHR-DWXRXsh1.js +37 -0
  85. package/src/ui/dist/assets/asciiarmor-Df11BRmG.js +2 -0
  86. package/src/ui/dist/assets/asn1-EdZsLKOL.js +2 -0
  87. package/src/ui/dist/assets/asterisk-B-8jnY81.js +2 -0
  88. package/src/ui/dist/assets/az-AZ-76LH7QW2-CiT05voO.js +2 -0
  89. package/src/ui/dist/assets/bg-BG-XCXSNQG7-L-UM9tNf.js +6 -0
  90. package/src/ui/dist/assets/blockDiagram-677ZJIJ3-BIyh3Bry.js +133 -0
  91. package/src/ui/dist/assets/bn-BD-2XOGV67Q-NdgbA0bC.js +6 -0
  92. package/src/ui/dist/assets/brainfuck-C4LP7Hcl.js +2 -0
  93. package/src/ui/dist/assets/c4Diagram-LMCZKHZV-CA54vWWM.js +11 -0
  94. package/src/ui/dist/assets/ca-ES-6MX7JW3Y-BKZZsQ5J.js +9 -0
  95. package/src/ui/dist/assets/channel-Da_-zcAu.js +2 -0
  96. package/src/ui/dist/assets/chunk-2Q5K7J3B-DE4cxr1v.js +2 -0
  97. package/src/ui/dist/assets/chunk-32BRIVSS-i7FwbEU9.js +2 -0
  98. package/src/ui/dist/assets/chunk-5VM5RSS4-BhIcOYSu.js +16 -0
  99. package/src/ui/dist/assets/chunk-EX3LRPZG-Ci9zZRIs.js +232 -0
  100. package/src/ui/dist/assets/chunk-JWPE2WC7-BFdkcz-G.js +2 -0
  101. package/src/ui/dist/assets/chunk-MOJQB5TN-Dzmapl_S.js +89 -0
  102. package/src/ui/dist/assets/chunk-RYQCIY6F-RTmp7FOy.js +2 -0
  103. package/src/ui/dist/assets/chunk-V7JOEXUC-DInU3v3D.js +207 -0
  104. package/src/ui/dist/assets/chunk-VR4S4FIN-BHoyGBQO.js +2 -0
  105. package/src/ui/dist/assets/chunk-XXDRQBXY-DfeLZNZx.js +2 -0
  106. package/src/ui/dist/assets/classDiagram-OUVF2IWQ-FKbUS0bu.js +2 -0
  107. package/src/ui/dist/assets/classDiagram-v2-EOCWNBFH-FKbUS0bu.js +2 -0
  108. package/src/ui/dist/assets/clike-B9uivgTg.js +2 -0
  109. package/src/ui/dist/assets/clojure-BMjYHr_A.js +2 -0
  110. package/src/ui/dist/assets/cmake-BQqOBYOt.js +2 -0
  111. package/src/ui/dist/assets/cobol-CWcv1MsR.js +2 -0
  112. package/src/ui/dist/assets/coffeescript-S37ZYGWr.js +2 -0
  113. package/src/ui/dist/assets/commonlisp-DBKNyK5s.js +2 -0
  114. package/src/ui/dist/assets/cose-bilkent-JH36ORCC-_5PUJ615.js +2 -0
  115. package/src/ui/dist/assets/crystal-SjHAIU92.js +2 -0
  116. package/src/ui/dist/assets/cs-CZ-2BRQDIVT-DnkfnhDU.js +12 -0
  117. package/src/ui/dist/assets/css-BnMrqG3P.js +2 -0
  118. package/src/ui/dist/assets/cynefin-VYW2F7L2-CmkcFv-b.js +179 -0
  119. package/src/ui/dist/assets/cynefinDiagram-TSTJHNR4-D72VZn8H.js +63 -0
  120. package/src/ui/dist/assets/cypher-C_CwsFkJ.js +2 -0
  121. package/src/ui/dist/assets/cytoscape.esm-DTSO7Bv0.js +332 -0
  122. package/src/ui/dist/assets/d-pRatUO7H.js +2 -0
  123. package/src/ui/dist/assets/da-DK-5WZEPLOC-C54tQUgd.js +6 -0
  124. package/src/ui/dist/assets/dagre-VKFMJZFB-0BsAkrmo.js +5 -0
  125. package/src/ui/dist/assets/de-DE-XR44H4JA-DGfZlR10.js +9 -0
  126. package/src/ui/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
  127. package/src/ui/dist/assets/diagram-FQU43EPY-C1ZJDOca.js +4 -0
  128. package/src/ui/dist/assets/diagram-G47NLZAW-D3pr3FSP.js +25 -0
  129. package/src/ui/dist/assets/diagram-NH7WQ7WH-Bwry0NV-.js +25 -0
  130. package/src/ui/dist/assets/diagram-OA4YK3LP-L6g09cmV.js +31 -0
  131. package/src/ui/dist/assets/diagram-WEI45ONY-Bh1puYVX.js +42 -0
  132. package/src/ui/dist/assets/diff-DbItnlRl.js +2 -0
  133. package/src/ui/dist/assets/directory-open-01563666-DWU9wJ6I.js +2 -0
  134. package/src/ui/dist/assets/directory-open-4ed118d0-CunoC1EB.js +2 -0
  135. package/src/ui/dist/assets/dockerfile-BKs6k2Af.js +2 -0
  136. package/src/ui/dist/assets/dtd-DF_7sFjM.js +2 -0
  137. package/src/ui/dist/assets/dylan-DwRh75JA.js +2 -0
  138. package/src/ui/dist/assets/ebnf-CDyGwa7X.js +2 -0
  139. package/src/ui/dist/assets/ebnfDiagram-CCIWWBDH-BC_mBRR5.js +2 -0
  140. package/src/ui/dist/assets/ecl-Cabwm37j.js +2 -0
  141. package/src/ui/dist/assets/eiffel-CnydiIhH.js +2 -0
  142. package/src/ui/dist/assets/el-GR-BZB4AONW-DsnwWweL.js +11 -0
  143. package/src/ui/dist/assets/elm-vLlmbW-K.js +2 -0
  144. package/src/ui/dist/assets/erDiagram-Q63AITRT-Bkxam36l.js +86 -0
  145. package/src/ui/dist/assets/erlang-BNw1qcRV.js +2 -0
  146. package/src/ui/dist/assets/es-ES-U4NZUMDT-CRxBcQgC.js +10 -0
  147. package/src/ui/dist/assets/eu-ES-A7QVB2H4-CTd_E7YR.js +12 -0
  148. package/src/ui/dist/assets/excalidraw-default-bMWIgNCy.svg +1 -0
  149. package/src/ui/dist/assets/fa-IR-HGAKTJCU-DO56k7eG.js +9 -0
  150. package/src/ui/dist/assets/factor-kuTfRLto.js +2 -0
  151. package/src/ui/dist/assets/fcl-Kvtd6kyn.js +2 -0
  152. package/src/ui/dist/assets/fi-FI-Z5N7JZ37-DEDCF9WB.js +7 -0
  153. package/src/ui/dist/assets/file-open-002ab408-DIuFHtCF.js +2 -0
  154. package/src/ui/dist/assets/file-open-7c801643-684qeFg4.js +2 -0
  155. package/src/ui/dist/assets/file-save-3189631c-C1wFhQhH.js +2 -0
  156. package/src/ui/dist/assets/file-save-745eba88-Bb9F9Kg7.js +2 -0
  157. package/src/ui/dist/assets/flowDiagram-23GEKE2U-C3SAEao7.js +157 -0
  158. package/src/ui/dist/assets/forth-Ffai-XNe.js +2 -0
  159. package/src/ui/dist/assets/fortran-DYz_wnZ1.js +2 -0
  160. package/src/ui/dist/assets/fr-FR-RHASNOE6-DE2nPyDt.js +10 -0
  161. package/src/ui/dist/assets/ganttDiagram-NO4QXBWP-U-J_Xi-_.js +293 -0
  162. package/src/ui/dist/assets/gas-Bneqetm1.js +2 -0
  163. package/src/ui/dist/assets/gherkin-heZmZLOM.js +2 -0
  164. package/src/ui/dist/assets/gitGraphDiagram-IHSO6WYX-BADVbD-a.js +107 -0
  165. package/src/ui/dist/assets/gl-ES-HMX3MZ6V-mCqVgQHC.js +11 -0
  166. package/src/ui/dist/assets/graph-C9eacEi8.js +2 -0
  167. package/src/ui/dist/assets/groovy-D9Dt4D0W.js +2 -0
  168. package/src/ui/dist/assets/haskell-Cw1EW3IL.js +2 -0
  169. package/src/ui/dist/assets/haxe-H-WmDvRZ.js +2 -0
  170. package/src/ui/dist/assets/he-IL-6SHJWFNN-KnaLrCzw.js +11 -0
  171. package/src/ui/dist/assets/hi-IN-IWLTKZ5I-wuqiaaWt.js +5 -0
  172. package/src/ui/dist/assets/http-DBlCnlav.js +2 -0
  173. package/src/ui/dist/assets/hu-HU-A5ZG7DT2-DLg_zm22.js +8 -0
  174. package/src/ui/dist/assets/id-ID-SAP4L64H-MB2mXqcR.js +11 -0
  175. package/src/ui/dist/assets/idl-BEugSyMb.js +2 -0
  176. package/src/ui/dist/assets/image-blob-reduce.esm-HwCm7IZ0.js +8 -0
  177. package/src/ui/dist/assets/index-39SJtrt0.js +2 -0
  178. package/src/ui/dist/assets/index-BQ0LIrW-.js +2 -0
  179. package/src/ui/dist/assets/index-BcAUh2Nm.css +1 -0
  180. package/src/ui/dist/assets/index-BcThOK-i.js +331 -0
  181. package/src/ui/dist/assets/index-BnxV3k_S.js +3 -0
  182. package/src/ui/dist/assets/index-C7MZBHbT.js +117 -0
  183. package/src/ui/dist/assets/index-CCvKI2rM.js +2 -0
  184. package/src/ui/dist/assets/index-CZvmcCab.js +8 -0
  185. package/src/ui/dist/assets/index-Cp3hLKNl.js +2 -0
  186. package/src/ui/dist/assets/index-D7ayFxcx.js +2 -0
  187. package/src/ui/dist/assets/index-DAYxSQGU.js +2 -0
  188. package/src/ui/dist/assets/index-DD-HeMV0.css +1 -0
  189. package/src/ui/dist/assets/index-DPMxd3Qn.js +2 -0
  190. package/src/ui/dist/assets/index-DSe2jx3k.js +4 -0
  191. package/src/ui/dist/assets/index-DUirCkgW.js +2 -0
  192. package/src/ui/dist/assets/index-DaKPQ2hN.js +159 -0
  193. package/src/ui/dist/assets/index-DzpuR0Jg.js +2 -0
  194. package/src/ui/dist/assets/index-POndwsCI.js +2 -0
  195. package/src/ui/dist/assets/index-R8NM9I_9.js +2 -0
  196. package/src/ui/dist/assets/index-TCDuDhBj.js +2 -0
  197. package/src/ui/dist/assets/index-TckzASdM.js +2 -0
  198. package/src/ui/dist/assets/index-Yi5ytFFr.js +2 -0
  199. package/src/ui/dist/assets/infoDiagram-FWYZ7A6U-CiGBlFqH.js +3 -0
  200. package/src/ui/dist/assets/init-Gi6I4Gst.js +2 -0
  201. package/src/ui/dist/assets/ishikawaDiagram-FXEZZL3T-B1aheRbz.js +71 -0
  202. package/src/ui/dist/assets/it-IT-JPQ66NNP-DT3HSU7X.js +12 -0
  203. package/src/ui/dist/assets/ja-JP-DBVTYXUO-CsfJjjWt.js +9 -0
  204. package/src/ui/dist/assets/javascript-iXu5QeM3.js +2 -0
  205. package/src/ui/dist/assets/journeyDiagram-5HDEW3XC-DtnJPxub.js +140 -0
  206. package/src/ui/dist/assets/julia-DuME0IfC.js +2 -0
  207. package/src/ui/dist/assets/kaa-6HZHGXH3-DQz-1-Gn.js +2 -0
  208. package/src/ui/dist/assets/kab-KAB-ZGHBKWFO-CaH-LSoK.js +9 -0
  209. package/src/ui/dist/assets/kanban-definition-HUTT4EX6-CZatSm3e.js +90 -0
  210. package/src/ui/dist/assets/katex-C5jXJg4s.js +258 -0
  211. package/src/ui/dist/assets/kk-KZ-P5N5QNE5-BMXmcm55.js +2 -0
  212. package/src/ui/dist/assets/km-KH-HSX4SM5Z-ZeoJNBpN.js +12 -0
  213. package/src/ui/dist/assets/ko-KR-MTYHY66A-BeaLRKph.js +10 -0
  214. package/src/ui/dist/assets/ku-TR-6OUDTVRD-B_28KrkR.js +10 -0
  215. package/src/ui/dist/assets/layout-DEXfKzaS.js +2 -0
  216. package/src/ui/dist/assets/linear-CpEDnQRC.js +2 -0
  217. package/src/ui/dist/assets/livescript-BwQOo05w.js +2 -0
  218. package/src/ui/dist/assets/lt-LT-XHIRWOB4-BxDcnUhp.js +4 -0
  219. package/src/ui/dist/assets/lua-VAEuO923.js +2 -0
  220. package/src/ui/dist/assets/lv-LV-5QDEKY6T-DpKDl1_y.js +8 -0
  221. package/src/ui/dist/assets/map-Czzmt4hB.js +2 -0
  222. package/src/ui/dist/assets/mathematica-DTrFuWx2.js +2 -0
  223. package/src/ui/dist/assets/mbox-CNhZ1qSd.js +2 -0
  224. package/src/ui/dist/assets/mermaidLoader-CBO31t0J.js +305 -0
  225. package/src/ui/dist/assets/mermaidLoader-CEK31ho9.css +1 -0
  226. package/src/ui/dist/assets/mindmap-definition-LN4V7U3C-CQ0TccEr.js +97 -0
  227. package/src/ui/dist/assets/mirc-CjQqDB4T.js +2 -0
  228. package/src/ui/dist/assets/mllike-CXdrOF99.js +2 -0
  229. package/src/ui/dist/assets/modelica-Dc1JOy9r.js +2 -0
  230. package/src/ui/dist/assets/mr-IN-CRQNXWMA-BKCZT58p.js +14 -0
  231. package/src/ui/dist/assets/mscgen-BA5vi2Kp.js +2 -0
  232. package/src/ui/dist/assets/mumps-BT43cFF4.js +2 -0
  233. package/src/ui/dist/assets/my-MM-5M5IBNSE-D34k0G9T.js +2 -0
  234. package/src/ui/dist/assets/nb-NO-T6EIAALU-DXr_KW8J.js +11 -0
  235. package/src/ui/dist/assets/nginx-DdIZxoE0.js +2 -0
  236. package/src/ui/dist/assets/nl-NL-IS3SIHDZ-C1L0aVDR.js +9 -0
  237. package/src/ui/dist/assets/nn-NO-6E72VCQL-CLWVSxbZ.js +9 -0
  238. package/src/ui/dist/assets/nsis-LdVXkNf5.js +2 -0
  239. package/src/ui/dist/assets/ntriples-BfvgReVJ.js +2 -0
  240. package/src/ui/dist/assets/oc-FR-POXYY2M6-nf8_J3eR.js +9 -0
  241. package/src/ui/dist/assets/octave-Ck1zUtKM.js +2 -0
  242. package/src/ui/dist/assets/ordinal-Cboi1Yqb.js +2 -0
  243. package/src/ui/dist/assets/oz-BzwKVEFT.js +2 -0
  244. package/src/ui/dist/assets/pa-IN-N4M65BXN-CAMJ-xd6.js +5 -0
  245. package/src/ui/dist/assets/pascal--L3eBynH.js +2 -0
  246. package/src/ui/dist/assets/pegDiagram-2B236MQR-Bj2RcmRd.js +2 -0
  247. package/src/ui/dist/assets/percentages-BXMCSKIN-s9yWFdr6.js +160 -0
  248. package/src/ui/dist/assets/perl-CdXCOZ3F.js +2 -0
  249. package/src/ui/dist/assets/pica-BGv_AhAB.js +8 -0
  250. package/src/ui/dist/assets/pieDiagram-ENE6RG2P-obpzz8dC.js +40 -0
  251. package/src/ui/dist/assets/pig-CevX1Tat.js +2 -0
  252. package/src/ui/dist/assets/pl-PL-T2D74RX3-DKJ5H85v.js +10 -0
  253. package/src/ui/dist/assets/powershell-CFHJl5sT.js +2 -0
  254. package/src/ui/dist/assets/properties-C78fOPTZ.js +2 -0
  255. package/src/ui/dist/assets/protobuf-ChK-085T.js +2 -0
  256. package/src/ui/dist/assets/{proxy-D0vUbds5.js → proxy-BSmwef4H.js} +2 -2
  257. package/src/ui/dist/assets/pt-BR-5N22H2LF-B5kow-kN.js +10 -0
  258. package/src/ui/dist/assets/pt-PT-UZXXM6DQ-B2G34fso.js +10 -0
  259. package/src/ui/dist/assets/pug-DeIclll2.js +2 -0
  260. package/src/ui/dist/assets/puppet-DMA9R1ak.js +2 -0
  261. package/src/ui/dist/assets/python-BuPzkPfP.js +2 -0
  262. package/src/ui/dist/assets/q-pXgVlZs6.js +2 -0
  263. package/src/ui/dist/assets/quadrantDiagram-ABIIQ3AL-Cl-T7NkJ.js +8 -0
  264. package/src/ui/dist/assets/r-B6wPVr8A.js +2 -0
  265. package/src/ui/dist/assets/railroadDiagram-RFXS5EU6-DMq82RHg.js +2 -0
  266. package/src/ui/dist/assets/{refresh-cw-JNmExijd.js → refresh-cw-CbFd7guV.js} +2 -2
  267. package/src/ui/dist/assets/requirementDiagram-TGXJPOKE-tGInMDgU.js +85 -0
  268. package/src/ui/dist/assets/ro-RO-JPDTUUEW-BwLdZW91.js +12 -0
  269. package/src/ui/dist/assets/roundRect-0PYZxl1G.js +2 -0
  270. package/src/ui/dist/assets/rpm-CTu-6PCP.js +2 -0
  271. package/src/ui/dist/assets/ru-RU-B4JR7IUQ-DpdAgIJc.js +10 -0
  272. package/src/ui/dist/assets/ruby-B2Rjki9n.js +2 -0
  273. package/src/ui/dist/assets/runtimeBrand-BoKPimsz.js +2 -0
  274. package/src/ui/dist/assets/sankeyDiagram-HTMAVEWB-C7X-ET4m.js +41 -0
  275. package/src/ui/dist/assets/sas-B4kiWyti.js +2 -0
  276. package/src/ui/dist/assets/save-D1CXHwBw.js +12 -0
  277. package/src/ui/dist/assets/scheme-C41bIUwD.js +2 -0
  278. package/src/ui/dist/assets/sequenceDiagram-DBY2YBRQ-Bn24i_nY.js +163 -0
  279. package/src/ui/dist/assets/settings-2-DtSNAAcU.js +22 -0
  280. package/src/ui/dist/assets/shell-CjFT_Tl9.js +2 -0
  281. package/src/ui/dist/assets/shield-check-BVbJ8T_N.js +7 -0
  282. package/src/ui/dist/assets/si-LK-N5RQ5JYF-naJaUy5u.js +2 -0
  283. package/src/ui/dist/assets/sieve-C3Gn_uJK.js +2 -0
  284. package/src/ui/dist/assets/simple-mode-GW_nhZxv.js +2 -0
  285. package/src/ui/dist/assets/sizeCapture-X5ZJPWSS-DAQHfm82.js +2 -0
  286. package/src/ui/dist/assets/sk-SK-C5VTKIMK-1NPz1J_d.js +7 -0
  287. package/src/ui/dist/assets/sl-SI-NN7IZMDC-D8RfmNQw.js +7 -0
  288. package/src/ui/dist/assets/smalltalk-CnHTOXQT.js +2 -0
  289. package/src/ui/dist/assets/solr-DehyRSwq.js +2 -0
  290. package/src/ui/dist/assets/sparql-DkYu6x3z.js +2 -0
  291. package/src/ui/dist/assets/spreadsheet-BCZA_wO0.js +2 -0
  292. package/src/ui/dist/assets/sql-D0XecflT.js +2 -0
  293. package/src/ui/dist/assets/stateDiagram-2N3HPSRC-Ck48D1ck.js +2 -0
  294. package/src/ui/dist/assets/stateDiagram-v2-6OUMAXLB-CdfRCJAJ.js +2 -0
  295. package/src/ui/dist/assets/stex-C3f8Ysf7.js +2 -0
  296. package/src/ui/dist/assets/style-C3QI7VPf.css +1 -0
  297. package/src/ui/dist/assets/stylus-B533Al4x.js +2 -0
  298. package/src/ui/dist/assets/subset-shared.chunk-eAtLHmbi.js +85 -0
  299. package/src/ui/dist/assets/subset-worker.chunk-DeHCTnTk.js +2 -0
  300. package/src/ui/dist/assets/sv-SE-XGPEYMSR-BeOYCU-8.js +11 -0
  301. package/src/ui/dist/assets/swift-BzpIVaGY.js +2 -0
  302. package/src/ui/dist/assets/swimlanes-5IMT3BWC-DOy22UjP.js +3 -0
  303. package/src/ui/dist/assets/swimlanesDiagram-G3AALYLV-sicPbVOg.js +9 -0
  304. package/src/ui/dist/assets/ta-IN-2NMHFXQM-CtS68WDd.js +10 -0
  305. package/src/ui/dist/assets/tcl-DVfN8rqt.js +2 -0
  306. package/src/ui/dist/assets/{terminal-BBQvnOAK.js → terminal-DEby5Y_P.js} +2 -2
  307. package/src/ui/dist/assets/terminalControl-BkFeDVXo.js +134 -0
  308. package/src/ui/dist/assets/textile-CnDTJFAw.js +2 -0
  309. package/src/ui/dist/assets/th-TH-HPSO5L25-DCHY9-Co.js +3 -0
  310. package/src/ui/dist/assets/tiddlywiki-DO-Gjzrf.js +2 -0
  311. package/src/ui/dist/assets/tiki-DGYXhP31.js +2 -0
  312. package/src/ui/dist/assets/timeline-definition-FHXFAJF6-DVkG72qO.js +121 -0
  313. package/src/ui/dist/assets/toml-Bm5Em-hy.js +2 -0
  314. package/src/ui/dist/assets/tr-TR-DEFEU3FU-y5-vjTv8.js +8 -0
  315. package/src/ui/dist/assets/troff-wAsdV37c.js +2 -0
  316. package/src/ui/dist/assets/ttcn-CfJYG6tj.js +2 -0
  317. package/src/ui/dist/assets/ttcn-cfg-B9xdYoR4.js +2 -0
  318. package/src/ui/dist/assets/turtle-B1tBg_DP.js +2 -0
  319. package/src/ui/dist/assets/uk-UA-QMV73CPH-BRbR5It6.js +7 -0
  320. package/src/ui/dist/assets/useReducedMotion-D07XP52Q.js +12 -0
  321. package/src/ui/dist/assets/vb-CmGdzxic.js +2 -0
  322. package/src/ui/dist/assets/vbscript-BuJXcnF6.js +2 -0
  323. package/src/ui/dist/assets/velocity-D8B20fx6.js +2 -0
  324. package/src/ui/dist/assets/vennDiagram-L72KCM5P-DwMwBlf-.js +35 -0
  325. package/src/ui/dist/assets/verilog-C6RDOZhf.js +2 -0
  326. package/src/ui/dist/assets/vhdl-lSbBsy5d.js +2 -0
  327. package/src/ui/dist/assets/vi-VN-M7AON7JQ-s6wSBv2s.js +6 -0
  328. package/src/ui/dist/assets/wardleyDiagram-EHGQE667-CNuuvzEg.js +79 -0
  329. package/src/ui/dist/assets/webidl-ZXfAyPTL.js +2 -0
  330. package/src/ui/dist/assets/{x-DoIOGAJz.js → x-B84wq78k.js} +2 -2
  331. package/src/ui/dist/assets/xquery-DzFWVndE.js +2 -0
  332. package/src/ui/dist/assets/xychartDiagram-FW5EYKEG-dUpZxmn6.js +8 -0
  333. package/src/ui/dist/assets/yacas-BJ4BC0dw.js +2 -0
  334. package/src/ui/dist/assets/z80-Hz9HOZM7.js +2 -0
  335. package/src/ui/dist/assets/zh-CN-LNUGB5OW-Cu_-POQN.js +11 -0
  336. package/src/ui/dist/assets/zh-HK-E62DVLB3-BCx4W4qZ.js +2 -0
  337. package/src/ui/dist/assets/zh-TW-RAJ6MFWO-02wx_Mrj.js +10 -0
  338. package/src/ui/dist/icons/excalidraw.svg +1 -0
  339. package/src/ui/dist/icons/markdown.svg +1 -0
  340. package/src/ui/dist/index.html +2 -2
  341. package/src/ui/package.json +10 -0
  342. package/src/ui/playwright.config.ts +36 -0
  343. package/src/ui/pnpm-workspace.yaml +2 -0
  344. package/src/ui/public/icons/excalidraw.svg +1 -0
  345. package/src/ui/public/icons/markdown.svg +1 -0
  346. package/src/ui/tsconfig.json +2 -1
  347. package/src/ui/vite.config.ts +1 -0
  348. package/src/wf-ui-server/__tests__/a2a-store.test.mjs +432 -15
  349. package/src/wf-ui-server/__tests__/action-registry-loader.test.mjs +156 -0
  350. package/src/wf-ui-server/__tests__/claude-stream-json.test.mjs +397 -0
  351. package/src/wf-ui-server/__tests__/codex-appserver.test.mjs +392 -0
  352. package/src/wf-ui-server/__tests__/component-node-api.test.mjs +881 -0
  353. package/src/wf-ui-server/__tests__/component-node-store.test.mjs +401 -0
  354. package/src/wf-ui-server/__tests__/control-plane-acceptance.test.mjs +2027 -0
  355. package/src/wf-ui-server/__tests__/control-plane-cli-smoke.test.mjs +1014 -0
  356. package/src/wf-ui-server/__tests__/dispatch-lifecycle.test.mjs +330 -0
  357. package/src/wf-ui-server/__tests__/effort-compatibility-red-092.test.mjs +151 -0
  358. package/src/wf-ui-server/__tests__/graph-layout-agent-tree.test.mjs +254 -0
  359. package/src/wf-ui-server/__tests__/graph-layout-tidy.test.mjs +260 -0
  360. package/src/wf-ui-server/__tests__/graph-layout.test.mjs +84 -0
  361. package/src/wf-ui-server/__tests__/node-config-api.test.mjs +384 -0
  362. package/src/wf-ui-server/__tests__/opencode-server.test.mjs +526 -0
  363. package/src/wf-ui-server/__tests__/peer-capsule.test.mjs +2 -2
  364. package/src/wf-ui-server/__tests__/pty-adapter.test.mjs +71 -1
  365. package/src/wf-ui-server/__tests__/runtime-config.test.mjs +3 -3
  366. package/src/wf-ui-server/__tests__/runtime-detector.test.mjs +21 -0
  367. package/src/wf-ui-server/__tests__/runtime-review.test.mjs +828 -0
  368. package/src/wf-ui-server/__tests__/server.integration.test.mjs +1463 -11
  369. package/src/wf-ui-server/__tests__/session-cleanup.test.mjs +159 -0
  370. package/src/wf-ui-server/__tests__/session-registry.test.mjs +52 -3
  371. package/src/wf-ui-server/__tests__/settings.test.mjs +12 -2
  372. package/src/wf-ui-server/__tests__/spawn-gate.test.mjs +78 -0
  373. package/src/wf-ui-server/__tests__/task-group-parser.test.mjs +120 -0
  374. package/src/wf-ui-server/__tests__/task-group-tag.test.mjs +264 -0
  375. package/src/wf-ui-server/__tests__/task-parser.test.mjs +49 -3
  376. package/src/wf-ui-server/__tests__/terminal-context-hardening.test.mjs +122 -0
  377. package/src/wf-ui-server/__tests__/terminal-context.test.mjs +164 -0
  378. package/src/wf-ui-server/__tests__/terminal-store.test.mjs +4 -4
  379. package/src/wf-ui-server/__tests__/wf-browser-api.test.mjs +599 -0
  380. package/src/wf-ui-server/__tests__/wf-browser-store.test.mjs +184 -0
  381. package/src/wf-ui-server/__tests__/workflow-action-registry.test.mjs +282 -0
  382. package/src/wf-ui-server/__tests__/workflow-agent-communication.test.mjs +411 -0
  383. package/src/wf-ui-server/__tests__/workflow-agent-context.test.mjs +323 -0
  384. package/src/wf-ui-server/__tests__/workflow-agent-cooperation-permissions.test.mjs +318 -0
  385. package/src/wf-ui-server/__tests__/workflow-agent-messages-structured.test.mjs +458 -0
  386. package/src/wf-ui-server/__tests__/workflow-agent-routing.test.mjs +434 -0
  387. package/src/wf-ui-server/__tests__/workflow-agent-runtime.test.mjs +324 -0
  388. package/src/wf-ui-server/__tests__/workflow-api-integration.test.mjs +263 -0
  389. package/src/wf-ui-server/__tests__/workflow-api-phase3.test.mjs +1213 -0
  390. package/src/wf-ui-server/__tests__/workflow-claude-materialize.test.mjs +209 -0
  391. package/src/wf-ui-server/__tests__/workflow-cli-registry-manuals.test.mjs +173 -0
  392. package/src/wf-ui-server/__tests__/workflow-cli-surface.test.mjs +176 -0
  393. package/src/wf-ui-server/__tests__/workflow-codex-resume-id.test.mjs +556 -0
  394. package/src/wf-ui-server/__tests__/workflow-cooperation-enforcement.test.mjs +553 -0
  395. package/src/wf-ui-server/__tests__/workflow-depth-resume-dock.test.mjs +846 -0
  396. package/src/wf-ui-server/__tests__/workflow-display-node.test.mjs +150 -0
  397. package/src/wf-ui-server/__tests__/workflow-edge-update.test.mjs +296 -0
  398. package/src/wf-ui-server/__tests__/workflow-file-cache-lock-watch.test.mjs +380 -0
  399. package/src/wf-ui-server/__tests__/workflow-file-formats.test.mjs +994 -0
  400. package/src/wf-ui-server/__tests__/workflow-file-node-actions.test.mjs +294 -0
  401. package/src/wf-ui-server/__tests__/workflow-goal-actions.test.mjs +357 -0
  402. package/src/wf-ui-server/__tests__/workflow-goal-task-autoclose.test.mjs +256 -0
  403. package/src/wf-ui-server/__tests__/workflow-graceful-stop.test.mjs +108 -0
  404. package/src/wf-ui-server/__tests__/workflow-graph-undo.test.mjs +524 -0
  405. package/src/wf-ui-server/__tests__/workflow-layout.test.mjs +732 -0
  406. package/src/wf-ui-server/__tests__/workflow-magnetic-topology.test.mjs +222 -0
  407. package/src/wf-ui-server/__tests__/workflow-markdown-lock.test.mjs +359 -0
  408. package/src/wf-ui-server/__tests__/workflow-mcp-hub.test.mjs +174 -0
  409. package/src/wf-ui-server/__tests__/workflow-node-manual-schema.test.mjs +241 -0
  410. package/src/wf-ui-server/__tests__/workflow-node-runtime.test.mjs +1991 -0
  411. package/src/wf-ui-server/__tests__/workflow-node-store-utils.test.mjs +125 -0
  412. package/src/wf-ui-server/__tests__/workflow-registry-drift.test.mjs +296 -0
  413. package/src/wf-ui-server/__tests__/workflow-resource-handle-four-side.test.mjs +217 -0
  414. package/src/wf-ui-server/__tests__/workflow-role-profile.test.mjs +234 -0
  415. package/src/wf-ui-server/__tests__/workflow-set-model.test.mjs +261 -0
  416. package/src/wf-ui-server/__tests__/workflow-skill-group-context-enabled.test.mjs +131 -0
  417. package/src/wf-ui-server/__tests__/workflow-skill-group-enable-disable.test.mjs +186 -0
  418. package/src/wf-ui-server/__tests__/workflow-skills-hub.test.mjs +125 -0
  419. package/src/wf-ui-server/__tests__/workflow-state-reconcile.test.mjs +139 -0
  420. package/src/wf-ui-server/__tests__/workflow-subagent-strategy-matrix.test.mjs +529 -0
  421. package/src/wf-ui-server/__tests__/workflow-team-flow.test.mjs +278 -0
  422. package/src/wf-ui-server/__tests__/workflow-terminal-control-live.test.mjs +294 -0
  423. package/src/wf-ui-server/__tests__/workflow-terminal-control.test.mjs +631 -0
  424. package/src/wf-ui-server/__tests__/workflow-timer-wakeup.test.mjs +318 -0
  425. package/src/wf-ui-server/__tests__/workflow-unified-resume.test.mjs +537 -0
  426. package/src/wf-ui-server/__tests__/workspace-api-hardening.test.mjs +187 -0
  427. package/src/wf-ui-server/__tests__/workspace-api.test.mjs +382 -0
  428. package/src/wf-ui-server/__tests__/workspace-reveal.test.mjs +138 -0
  429. package/src/wf-ui-server/__tests__/workspace-store-hardening.test.mjs +255 -0
  430. package/src/wf-ui-server/__tests__/workspace-store.test.mjs +208 -0
  431. package/src/wf-ui-server/__tests__/ws-events.integration.test.mjs +52 -25
  432. package/src/wf-ui-server/__tests__/ws-terminal.integration.test.mjs +12 -6
  433. package/src/wf-ui-server/__tests__/ws-wf-browser.integration.test.mjs +488 -0
  434. package/src/wf-ui-server/a2a-store.mjs +3007 -89
  435. package/src/wf-ui-server/action-registry.mjs +277 -0
  436. package/src/wf-ui-server/bridge-store.mjs +276 -0
  437. package/src/wf-ui-server/chat-driver.mjs +220 -0
  438. package/src/wf-ui-server/chat-store.mjs +109 -0
  439. package/src/wf-ui-server/claude-transcript-materializer.mjs +235 -0
  440. package/src/wf-ui-server/codex-update-prompt.mjs +53 -0
  441. package/src/wf-ui-server/component-node-store.mjs +689 -0
  442. package/src/wf-ui-server/composition-api.mjs +436 -0
  443. package/src/wf-ui-server/control-plane-token.mjs +17 -0
  444. package/src/wf-ui-server/dispatch-contract.mjs +150 -0
  445. package/src/wf-ui-server/drivers/claude-stream-json.mjs +371 -0
  446. package/src/wf-ui-server/drivers/codex-appserver.mjs +513 -0
  447. package/src/wf-ui-server/drivers/opencode-server.mjs +486 -0
  448. package/src/wf-ui-server/excalidraw-svg.mjs +141 -0
  449. package/src/wf-ui-server/file-format-adapters.mjs +511 -0
  450. package/src/wf-ui-server/file-watcher.mjs +215 -0
  451. package/src/wf-ui-server/graph-layout.mjs +778 -0
  452. package/src/wf-ui-server/harness-env.mjs +46 -0
  453. package/src/wf-ui-server/json-store-utils.mjs +48 -0
  454. package/src/wf-ui-server/model-capability.mjs +773 -0
  455. package/src/wf-ui-server/node-config-store.mjs +233 -0
  456. package/src/wf-ui-server/node-store-utils.mjs +88 -0
  457. package/src/wf-ui-server/peer-capsule.mjs +56 -1
  458. package/src/wf-ui-server/pty-adapter.mjs +513 -11
  459. package/src/wf-ui-server/reveal-foreground.mjs +69 -0
  460. package/src/wf-ui-server/runtime-detector.mjs +52 -6
  461. package/src/wf-ui-server/server.mjs +5613 -403
  462. package/src/wf-ui-server/session-cleanup.mjs +363 -0
  463. package/src/wf-ui-server/session-registry.mjs +179 -3
  464. package/src/wf-ui-server/settings.mjs +25 -0
  465. package/src/wf-ui-server/spawn-gate.mjs +46 -0
  466. package/src/wf-ui-server/task-parser.mjs +88 -3
  467. package/src/wf-ui-server/terminal-store.mjs +225 -11
  468. package/src/wf-ui-server/timer-wakeup-scheduler.mjs +226 -0
  469. package/src/wf-ui-server/wf-browser-store.mjs +733 -0
  470. package/src/wf-ui-server/workflow-agent-context.mjs +1731 -0
  471. package/src/wf-ui-server/workflow-capability-node-store.mjs +676 -0
  472. package/src/wf-ui-server/workflow-event-node-store.mjs +623 -0
  473. package/src/wf-ui-server/workflow-goal-node-store.mjs +328 -0
  474. package/src/wf-ui-server/workflow-graph-store.mjs +623 -0
  475. package/src/wf-ui-server/workflow-mcp-hub.mjs +286 -0
  476. package/src/wf-ui-server/workflow-node-runtime.mjs +1767 -0
  477. package/src/wf-ui-server/workflow-node-settings-store.mjs +339 -0
  478. package/src/wf-ui-server/workflow-node-types/agent-node.mjs +920 -0
  479. package/src/wf-ui-server/workflow-node-types/display-node.mjs +151 -0
  480. package/src/wf-ui-server/workflow-node-types/excalidraw-node.mjs +145 -0
  481. package/src/wf-ui-server/workflow-node-types/file-node.mjs +484 -0
  482. package/src/wf-ui-server/workflow-node-types/github-trigger-node.mjs +207 -0
  483. package/src/wf-ui-server/workflow-node-types/goal-node.mjs +491 -0
  484. package/src/wf-ui-server/workflow-node-types/markdown-node.mjs +225 -0
  485. package/src/wf-ui-server/workflow-node-types/mcp-connector-node.mjs +71 -0
  486. package/src/wf-ui-server/workflow-node-types/role-profile-store.mjs +191 -0
  487. package/src/wf-ui-server/workflow-node-types/skill-group-node.mjs +98 -0
  488. package/src/wf-ui-server/workflow-node-types/timer-node.mjs +607 -0
  489. package/src/wf-ui-server/workflow-ontology.mjs +681 -0
  490. package/src/wf-ui-server/workflow-operation-store.mjs +115 -0
  491. package/src/wf-ui-server/workflow-skills-hub.mjs +366 -0
  492. package/src/wf-ui-server/workflow-skills-market.mjs +723 -0
  493. package/src/wf-ui-server/workspace-store.mjs +951 -0
  494. package/src/wf-ui-server/ws-chat.mjs +299 -0
  495. package/src/wf-ui-server/ws-events.mjs +45 -20
  496. package/src/wf-ui-server/ws-terminal.mjs +165 -22
  497. package/src/wf-ui-server/ws-wf-browser.mjs +419 -0
  498. package/templates/common/.claude/agents/review-manager.md +33 -29
  499. package/templates/common/.claude/commands/wf-browser.md +1 -1
  500. package/templates/common/.claude/commands/wf-help.md +5 -3
  501. package/templates/common/.claude/commands/wf-init.md +44 -0
  502. package/templates/common/.claude/commands/wf-learn.md +34 -8
  503. package/templates/common/.claude/commands/wf-max.md +19 -9
  504. package/templates/common/.claude/commands/wf-review.md +3 -3
  505. package/templates/common/.claude/commands/wf-search.md +55 -0
  506. package/templates/common/.claude/commands/wf-task-archive.md +5 -4
  507. package/templates/common/.claude/commands/wf-task-list.md +6 -3
  508. package/templates/common/.claude/commands/wf-task-record.md +10 -2
  509. package/templates/common/.claude/commands/wf-ui.md +12 -5
  510. package/templates/common/.claude/commands/wf-update.md +4 -0
  511. package/templates/common/.claude/commands/wf.md +12 -1
  512. package/templates/common/.claude/rules/ecc/common.md +10 -1
  513. package/templates/common/.claude/skills/wf/SKILL.md +36 -0
  514. package/templates/common/.claude/skills/wf-browser/SKILL.md +427 -122
  515. package/templates/common/.claude/skills/wf-browser/references/BROWSER_CONTROL_PATTERNS.md +43 -0
  516. package/templates/common/.claude/skills/wf-init/SKILL.md +33 -0
  517. package/templates/common/.claude/skills/wf-learn/SKILL.md +106 -26
  518. package/templates/common/.claude/skills/wf-max/SKILL.md +45 -11
  519. package/templates/common/.claude/skills/wf-review/SKILL.md +26 -54
  520. package/templates/common/.claude/skills/wf-search/SKILL.md +122 -0
  521. package/templates/common/.claude/skills/wf-search/references/evidence-contract.md +77 -0
  522. package/templates/common/.claude/skills/wf-search/references/policies/compare.md +38 -0
  523. package/templates/common/.claude/skills/wf-search/references/policies/fact.md +39 -0
  524. package/templates/common/.claude/skills/wf-search/references/policies/troubleshoot.md +39 -0
  525. package/templates/common/.claude/skills/wf-search/references/policies/verify.md +44 -0
  526. package/templates/common/.claude/skills/wf-search/references/source-routing.md +40 -0
  527. package/templates/common/.claude/skills/wf-search/references/tool-adapters.md +38 -0
  528. package/templates/common/.claude/skills/wf-ui/SKILL.md +146 -12
  529. package/templates/common/.claude/skills/wf-update/SKILL.md +5 -1
  530. package/templates/common/.harness-version +188 -85
  531. package/templates/common/.opencode/agents/review-manager.md +31 -27
  532. package/templates/common/.opencode/commands/wf-browser.md +1 -1
  533. package/templates/common/.opencode/commands/wf-help.md +5 -3
  534. package/templates/common/.opencode/commands/wf-init.md +44 -0
  535. package/templates/common/.opencode/commands/wf-learn.md +34 -8
  536. package/templates/common/.opencode/commands/wf-max.md +19 -9
  537. package/templates/common/.opencode/commands/wf-review.md +3 -3
  538. package/templates/common/.opencode/commands/wf-search.md +55 -0
  539. package/templates/common/.opencode/commands/wf-task-archive.md +5 -7
  540. package/templates/common/.opencode/commands/wf-task-list.md +6 -6
  541. package/templates/common/.opencode/commands/wf-task-record.md +10 -5
  542. package/templates/common/.opencode/commands/wf-ui.md +12 -5
  543. package/templates/common/.opencode/commands/wf-update.md +4 -0
  544. package/templates/common/.opencode/commands/wf.md +12 -1
  545. package/templates/common/CLAUDE.md +61 -3
  546. package/templates/common/Harness/MEMORY.md +8 -5
  547. package/templates/common/Harness/README.md +14 -10
  548. package/templates/common/Harness/a2a/action-registry.json +4397 -0
  549. package/templates/common/Harness/a2a/role-graph.json +16 -3
  550. package/templates/common/Harness/a2a/skills/terminal-control.json +45 -1
  551. package/templates/common/Harness/a2a/skills/wf-ui-map.json +50 -0
  552. package/templates/common/Harness/a2a/skills/workflow-agent-node.json +143 -0
  553. package/templates/common/Harness/a2a/skills/workflow-context.json +95 -0
  554. package/templates/common/Harness/a2a/skills/workflow-diagram-node.json +60 -0
  555. package/templates/common/Harness/a2a/skills/workflow-display-node.json +69 -0
  556. package/templates/common/Harness/a2a/skills/workflow-file-node.json +92 -0
  557. package/templates/common/Harness/a2a/skills/workflow-goal-node.json +76 -0
  558. package/templates/common/Harness/a2a/skills/workflow-markdown-node.json +79 -0
  559. package/templates/common/Harness/a2a/skills/workflow-mcp-connector-node.json +59 -0
  560. package/templates/common/Harness/a2a/skills/workflow-node-actions.json +105 -0
  561. package/templates/common/Harness/a2a/skills/workflow-node-map.json +71 -0
  562. package/templates/common/Harness/a2a/skills/workflow-ontology.json +54 -0
  563. package/templates/common/Harness/a2a/skills/workflow-resource-node.json +68 -0
  564. package/templates/common/Harness/a2a/skills/workflow-skill-group-node.json +56 -0
  565. package/templates/common/Harness/a2a/skills/workflow-timer-node.json +81 -0
  566. package/templates/common/Harness/a2a/workflows.json +33 -0
  567. package/templates/common/Harness/ownership.manifest.json +263 -2
  568. package/templates/common/Harness/project/architecture.md +499 -0
  569. package/templates/common/Harness/research/README.md +20 -0
  570. package/templates/common/Harness/scripts/README.md +70 -6
  571. package/templates/common/Harness/scripts/a2a-terminal.mjs +12 -4
  572. package/templates/common/Harness/scripts/context-budget.mjs +7 -3
  573. package/templates/common/Harness/scripts/lib/memory-context.mjs +400 -0
  574. package/templates/common/Harness/scripts/lib/path-scope.mjs +77 -0
  575. package/templates/common/Harness/scripts/lib/research-policy.mjs +99 -0
  576. package/templates/common/Harness/scripts/lib/wf-search.mjs +189 -0
  577. package/templates/common/Harness/scripts/memory-context.mjs +63 -0
  578. package/templates/common/Harness/scripts/research-policy.mjs +27 -0
  579. package/templates/common/Harness/scripts/task-context.mjs +547 -0
  580. package/templates/common/Harness/scripts/task-group-index.mjs +242 -0
  581. package/templates/common/Harness/scripts/task-state.mjs +659 -95
  582. package/templates/common/Harness/scripts/validate-harness.mjs +70 -28
  583. package/templates/common/Harness/scripts/wf-auto-update-prompt.mjs +24 -0
  584. package/templates/common/Harness/scripts/wf-remove.mjs +10 -0
  585. package/templates/common/Harness/scripts/wf-search.mjs +10 -0
  586. package/templates/common/Harness/scripts/wf-ui-control.mjs +3144 -0
  587. package/templates/common/Harness/scripts/wf-update-check.mjs +274 -51
  588. package/templates/common/Harness/scripts/wf-update-runner.mjs +53 -16
  589. package/templates/common/Harness/settings.json +10 -0
  590. package/templates/common/Harness/specs/guides/SETUP.md +4 -3
  591. package/templates/common/Harness/specs/protocols/HARNESS_BRIDGE.md +429 -48
  592. package/templates/common/Harness/specs/protocols/MEMORY_PROTOCOL.md +24 -0
  593. package/templates/common/Harness/specs/protocols/TASK_ARCHIVE.md +14 -11
  594. package/templates/common/Harness/specs/runtime/command-surface.json +28 -0
  595. package/templates/common/Harness/specs/runtime/context-loading.md +6 -0
  596. package/templates/common/Harness/specs/runtime/dispatch.md +9 -1
  597. package/templates/common/Harness/specs/runtime/subagents.md +20 -5
  598. package/templates/common/Harness/specs/workflows/WF-AUTO-SPARK.md +19 -0
  599. package/templates/common/Harness/specs/workflows/WF-AUTO.md +21 -0
  600. package/templates/common/Harness/specs/workflows/WF-KERNEL.md +4 -2
  601. package/templates/common/Harness/specs/workflows/WF-MAX.md +39 -12
  602. package/templates/common/Harness/specs/workflows/WF-STATE.md +62 -14
  603. package/templates/common/Harness/specs/workflows/WF.md +32 -0
  604. package/templates/common/Harness/tasks/INDEX.json +7 -0
  605. package/templates/common/Harness/tasks/INDEX.md +12 -0
  606. package/templates/common/Harness/tasks/_template/PLAN.md +6 -0
  607. package/templates/common/Harness/tasks/_template/PROGRESS.md +5 -0
  608. package/templates/common/Harness/tasks/_template/STATE.json +22 -0
  609. package/templates/common/Harness/templates/TEST_PLAN.template.md +5 -4
  610. package/templates/common/Harness/templates/UI_CONTRACT.template.md +7 -5
  611. package/templates/common/Harness/wf-browser/README.md +69 -0
  612. package/templates/common/README.md +17 -0
  613. package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js +0 -17
  614. package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js.map +0 -1
  615. package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js +0 -7
  616. package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js.map +0 -1
  617. package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js +0 -12
  618. package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js.map +0 -1
  619. package/src/ui/dist/assets/TaskList-BN4r8s1i.js +0 -50
  620. package/src/ui/dist/assets/TaskList-BN4r8s1i.js.map +0 -1
  621. package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js +0 -74
  622. package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js.map +0 -1
  623. package/src/ui/dist/assets/WorkflowRoute-BnuhLJ6X.css +0 -1
  624. package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js +0 -39
  625. package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js.map +0 -1
  626. package/src/ui/dist/assets/index-BOVYWntB.js +0 -117
  627. package/src/ui/dist/assets/index-BOVYWntB.js.map +0 -1
  628. package/src/ui/dist/assets/index-DaUObq0H.css +0 -1
  629. package/src/ui/dist/assets/maximize-2-LNrr_rKr.js +0 -7
  630. package/src/ui/dist/assets/maximize-2-LNrr_rKr.js.map +0 -1
  631. package/src/ui/dist/assets/plus-QuTJyoT3.js +0 -7
  632. package/src/ui/dist/assets/plus-QuTJyoT3.js.map +0 -1
  633. package/src/ui/dist/assets/proxy-D0vUbds5.js.map +0 -1
  634. package/src/ui/dist/assets/refresh-cw-JNmExijd.js.map +0 -1
  635. package/src/ui/dist/assets/terminal-BBQvnOAK.js.map +0 -1
  636. package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js +0 -7
  637. package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js.map +0 -1
  638. package/src/ui/dist/assets/x-DoIOGAJz.js.map +0 -1
  639. package/src/ui/pnpm-lock.yaml +0 -1582
  640. package/src/ui/src/App.tsx +0 -86
  641. package/src/ui/src/api.ts +0 -93
  642. package/src/ui/src/components/AgentsRoute.tsx +0 -503
  643. package/src/ui/src/components/Footer.tsx +0 -69
  644. package/src/ui/src/components/Header.tsx +0 -175
  645. package/src/ui/src/components/LoadingView.tsx +0 -22
  646. package/src/ui/src/components/RolesRoute.tsx +0 -169
  647. package/src/ui/src/components/SettingsRoute.tsx +0 -166
  648. package/src/ui/src/components/TaskList.tsx +0 -388
  649. package/src/ui/src/components/TerminalDrawer.tsx +0 -611
  650. package/src/ui/src/components/WorkflowRoute.tsx +0 -670
  651. package/src/ui/src/hooks/useReducedMotion.ts +0 -17
  652. package/src/ui/src/hooks/useServerConnection.ts +0 -114
  653. package/src/ui/src/index.css +0 -281
  654. package/src/ui/src/main.tsx +0 -11
  655. package/src/ui/src/types.ts +0 -108
  656. /package/src/ui/dist/assets/{TerminalDrawer-6GBZ9nXN.css → terminalControl-6GBZ9nXN.css} +0 -0
@@ -0,0 +1,920 @@
1
+ import crypto from 'node:crypto'
2
+ import { ComponentNodeError } from '../component-node-store.mjs'
3
+ import { loadWorkflowGraphMap, removeWorkflowGraphNode } from '../a2a-store.mjs'
4
+ import { acknowledgeBridgeMessages, listBridgeMessages, listBridgeMessagesForSession, recordBridgeMessage } from '../bridge-store.mjs'
5
+ import { compositionIdFor, listCompositionTransitions, recordCompositionTransition } from '../composition-api.mjs'
6
+ import { appendSessionEvent, appendTerminalData } from '../terminal-store.mjs'
7
+
8
+ async function getWsTerminal() {
9
+ return import('../ws-terminal.mjs')
10
+ }
11
+
12
+ async function getChatDriver() {
13
+ return import('../chat-driver.mjs')
14
+ }
15
+
16
+ const PROMPT_SUBMIT_ENTER_DELAY_MS = 800
17
+ // Per-character gap when typing a prompt submit into the TUI composer.
18
+ // Canonical definition: src/wf-ui-server/server.mjs PROMPT_TYPING_CHAR_DELAY_MS.
19
+ const PROMPT_TYPING_CHAR_DELAY_MS = 12
20
+ const PROMPT_SUBMIT_READY_WAIT_MS = 10000
21
+ const PROMPT_SUBMIT_READY_POLL_MS = 250
22
+
23
+ function rethrow(error) {
24
+ if (error instanceof ComponentNodeError) throw error
25
+ const wrapped = new ComponentNodeError(error.message, {
26
+ statusCode: error.statusCode,
27
+ code: error.code,
28
+ })
29
+ wrapped.cause = error
30
+ if (error?.stack) wrapped.stack = error.stack
31
+ throw wrapped
32
+ }
33
+
34
+ function isPlainObject(value) {
35
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
36
+ }
37
+
38
+ // Resolve a graph node by graph node id or session id
39
+ function findGraphNode(projectRoot, key) {
40
+ const graph = loadWorkflowGraphMap(projectRoot)
41
+ return (graph.nodes || []).find(node =>
42
+ (node.nodeId || node.id) === key || node.sessionId === key
43
+ ) || null
44
+ }
45
+
46
+ function graphNodeId(node) {
47
+ return node?.nodeId || node?.id || (node?.sessionId ? `session-${node.sessionId}` : '')
48
+ }
49
+
50
+ function assertAgentNode(projectRoot, key, label = 'Agent node') {
51
+ const node = findGraphNode(projectRoot, key)
52
+ if (!node?.sessionId) {
53
+ throw new ComponentNodeError(`${label} not found`, {
54
+ statusCode: 404,
55
+ code: 'AGENT_NOT_FOUND',
56
+ })
57
+ }
58
+ return node
59
+ }
60
+
61
+ function connectionEdges(graph = {}) {
62
+ const graphEdges = Array.isArray(graph.edges) ? graph.edges : []
63
+ const dockEdges = (Array.isArray(graph.capsuleDockLinks) ? graph.capsuleDockLinks : [])
64
+ .flatMap(link => (Array.isArray(link?.connections) ? link.connections : [])
65
+ .map(connection => ({
66
+ from: connection?.from || connection?.source,
67
+ to: connection?.to || connection?.target,
68
+ direction: connection?.direction || 'bidirectional',
69
+ relation: connection?.relation || 'wf-bridge',
70
+ })))
71
+ return [...graphEdges, ...dockEdges]
72
+ }
73
+
74
+ function isConnectedForMessage(graph, fromNodeId, toNodeId) {
75
+ return connectionEdges(graph).some((edge) => {
76
+ const from = String(edge?.from || edge?.source || '').trim()
77
+ const to = String(edge?.to || edge?.target || '').trim()
78
+ if (!from || !to) return false
79
+ if (String(edge?.direction || '') === 'source-to-target') {
80
+ return from === fromNodeId && to === toNodeId
81
+ }
82
+ return (from === fromNodeId && to === toNodeId) || (from === toNodeId && to === fromNodeId)
83
+ })
84
+ }
85
+
86
+ function connectedAgentNodeIds(graph, fromNodeId) {
87
+ const agentIds = new Set((Array.isArray(graph.nodes) ? graph.nodes : [])
88
+ .filter(node => node?.sessionId)
89
+ .map(graphNodeId)
90
+ .filter(Boolean))
91
+ const result = []
92
+ const seen = new Set()
93
+ for (const edge of connectionEdges(graph)) {
94
+ const from = String(edge?.from || edge?.source || '').trim()
95
+ const to = String(edge?.to || edge?.target || '').trim()
96
+ if (!from || !to) continue
97
+ let peer = ''
98
+ if (from === fromNodeId && agentIds.has(to)) peer = to
99
+ else if (to === fromNodeId && agentIds.has(from) && String(edge?.direction || '') !== 'source-to-target') peer = from
100
+ if (!peer || peer === fromNodeId || seen.has(peer)) continue
101
+ seen.add(peer)
102
+ result.push(peer)
103
+ }
104
+ return result
105
+ }
106
+
107
+ function recipientList(payload = {}) {
108
+ const raw = payload.to
109
+ ?? payload.targets
110
+ ?? payload.recipients
111
+ ?? payload.recipientNodeIds
112
+ ?? payload.targetNodeIds
113
+ ?? payload.nodeIds
114
+ ?? []
115
+ const values = Array.isArray(raw)
116
+ ? raw
117
+ : String(raw || '').split(/[,\n;]/)
118
+ return values.map(value => String(value || '').trim()).filter(Boolean)
119
+ }
120
+
121
+ function normalizeMessageData(payload = {}) {
122
+ const raw = payload.raw === true || payload.raw === 'true'
123
+ const text = String(payload.data ?? payload.input ?? payload.text ?? payload.message ?? '')
124
+ if (!text) {
125
+ throw new ComponentNodeError('Agent message requires text, message, input, or data', {
126
+ statusCode: 400,
127
+ code: 'MESSAGE_REQUIRED',
128
+ })
129
+ }
130
+ return raw || /[\r\n]$/.test(text) ? text : `${text}\r`
131
+ }
132
+
133
+ // F17/D14: a structured request reaches the target as a compact envelope
134
+ // prefix on the PTY input so the receiver can see the requestId (and echo it in
135
+ // replies) without parsing the bridge store. Composed only when structured
136
+ // fields are present; legacy text-only sends keep the exact previous input.
137
+ // The recorded bridge `data` stays the plain text body (spec §5).
138
+ function structuredEnvelopePrefix(envelope = {}) {
139
+ const fields = []
140
+ if (envelope.requestId) fields.push(envelope.requestId)
141
+ if (envelope.toRole) fields.push(`to-role=${envelope.toRole}`)
142
+ const contextRefs = (Array.isArray(envelope.contextRefs) ? envelope.contextRefs : [])
143
+ .map(ref => String(ref?.nodeId || '').trim())
144
+ .filter(Boolean)
145
+ if (contextRefs.length) fields.push(`contextRefs=${contextRefs.join(',')}`)
146
+ if (fields.length === 0) return ''
147
+ return `[harness-request ${fields.join(' ')}]`
148
+ }
149
+
150
+ function messageEnvelope(payload = {}, mode = 'direct') {
151
+ return {
152
+ messageId: String(payload.messageId || crypto.randomUUID()),
153
+ threadId: String(payload.threadId || payload.topic || ''),
154
+ topic: String(payload.topic || ''),
155
+ replyTo: String(payload.replyTo || payload.replyToMessageId || ''),
156
+ requestId: String(payload.requestId || ''),
157
+ toRole: String(payload.toRole || ''),
158
+ contextRefs: payload.contextRefs || [],
159
+ deliveryMode: String(payload.deliveryMode || mode),
160
+ source: String(payload.source || `agent.${mode}Message`),
161
+ }
162
+ }
163
+
164
+ // contextRefs entries are nodeId references only, never content (AC-019,
165
+ // spec 5). Accepts strings or {nodeId, relation} objects; rejects entries
166
+ // with no nodeId or with inlined markdown/body/content.
167
+ function normalizeContextRefs(payload = {}) {
168
+ const raw = payload.contextRefs
169
+ if (raw === undefined || raw === null) return []
170
+ if (!Array.isArray(raw)) {
171
+ throw new ComponentNodeError('agent message contextRefs must be an array', {
172
+ statusCode: 400,
173
+ code: 'INVALID_CONTEXT_REFS',
174
+ })
175
+ }
176
+ const refs = []
177
+ for (const entry of raw) {
178
+ let nodeId = ''
179
+ let relation = ''
180
+ if (typeof entry === 'string') {
181
+ nodeId = String(entry).trim()
182
+ } else if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
183
+ nodeId = String(entry.nodeId ?? entry.id ?? '').trim()
184
+ relation = String(entry.relation ?? '').trim()
185
+ if (entry.content != null || entry.body != null || entry.markdown != null) {
186
+ throw new ComponentNodeError(
187
+ 'contextRefs must reference nodes by nodeId only; never inline content',
188
+ { statusCode: 400, code: 'CONTEXT_REF_CONTENT_FORBIDDEN' }
189
+ )
190
+ }
191
+ }
192
+ if (!nodeId) {
193
+ throw new ComponentNodeError('each contextRefs entry must carry a nodeId', {
194
+ statusCode: 400,
195
+ code: 'INVALID_CONTEXT_REFS',
196
+ })
197
+ }
198
+ refs.push({ nodeId, relation })
199
+ }
200
+ return refs
201
+ }
202
+
203
+ function forceUnconnectedAllowed(sender, payload = {}) {
204
+ const force = payload.force === true || payload.force === 'true'
205
+ if (!force) return false
206
+ if (String(sender.agentKind || '').toLowerCase() === 'main') return true
207
+ throw new ComponentNodeError('Only Main Agent may force an unconnected Agent message', {
208
+ statusCode: 403,
209
+ code: 'MAIN_AGENT_FORCE_REQUIRED',
210
+ })
211
+ }
212
+
213
+ // A target is a chat target when it runs a live chat driver (this server
214
+ // lifetime) or its persisted STATE.json carries uiMode === 'chat'.
215
+ async function targetIsChatSession(projectRoot, sessionId) {
216
+ try {
217
+ const chatDriver = await getChatDriver()
218
+ if (chatDriver.hasLiveChatDriver(sessionId)) return true
219
+ } catch { /* chat-driver unavailable — fall through to the disk record */ }
220
+ try {
221
+ const { findTerminalSession } = await import('../terminal-store.mjs')
222
+ return findTerminalSession(projectRoot, sessionId)?.uiMode === 'chat'
223
+ } catch {
224
+ return false
225
+ }
226
+ }
227
+
228
+ async function deliverAgentMessage(projectRoot, {
229
+ graph,
230
+ sender,
231
+ targetKey,
232
+ data,
233
+ envelope,
234
+ recipientIndex,
235
+ recipientCount,
236
+ requireConnection = true,
237
+ ptyInput = null,
238
+ }) {
239
+ const senderNodeId = graphNodeId(sender)
240
+ const target = findGraphNode(projectRoot, targetKey)
241
+ const targetNodeId = graphNodeId(target)
242
+ if (!target?.sessionId || !targetNodeId) {
243
+ return {
244
+ ok: false,
245
+ code: 'AGENT_NOT_FOUND',
246
+ fromNodeId: senderNodeId,
247
+ toNodeId: String(targetKey || ''),
248
+ message: 'Target Agent node not found',
249
+ }
250
+ }
251
+ if (targetNodeId === senderNodeId || target.sessionId === sender.sessionId) {
252
+ return {
253
+ ok: false,
254
+ code: 'SELF_MESSAGE_SKIPPED',
255
+ fromNodeId: senderNodeId,
256
+ toNodeId: targetNodeId,
257
+ fromSessionId: sender.sessionId,
258
+ toSessionId: target.sessionId,
259
+ message: 'Skipping self message',
260
+ }
261
+ }
262
+ if (requireConnection && !isConnectedForMessage(graph, senderNodeId, targetNodeId)) {
263
+ return {
264
+ ok: false,
265
+ code: 'NOT_CONNECTED',
266
+ fromNodeId: senderNodeId,
267
+ toNodeId: targetNodeId,
268
+ fromSessionId: sender.sessionId,
269
+ toSessionId: target.sessionId,
270
+ message: 'Target Agent is not connected to sender',
271
+ }
272
+ }
273
+ const input = ptyInput || data
274
+ const targetSession = {
275
+ sessionId: target.sessionId,
276
+ taskId: target.taskId || null,
277
+ runtime: target.runtime || 'agent',
278
+ }
279
+ if (await targetIsChatSession(projectRoot, target.sessionId)) {
280
+ // Chat targets receive the message through their structured stdio driver
281
+ // (steer=true lets the driver pick its mid-turn steering channel, falling
282
+ // back to a plain send between turns); the TUI prompt-submit \r is
283
+ // stripped. No PTY is involved, so NO_PTY never applies to chat targets.
284
+ const { sendTo } = await getChatDriver()
285
+ const chatText = String(input).replace(/[\r\n]+$/g, '')
286
+ const sent = sendTo(target.sessionId, chatText, { steer: true })
287
+ if (!sent) {
288
+ return {
289
+ ok: false,
290
+ code: 'NO_CHAT_DRIVER',
291
+ fromNodeId: senderNodeId,
292
+ toNodeId: targetNodeId,
293
+ fromSessionId: sender.sessionId,
294
+ toSessionId: target.sessionId,
295
+ message: 'No live chat driver attached to target Agent',
296
+ }
297
+ }
298
+ } else {
299
+ const { writePtyInput } = await getWsTerminal()
300
+ // F17/D14: structured requests are delivered with the envelope prefix on
301
+ // the PTY input; the bridge record keeps the plain text `data` (spec §5).
302
+ // The input is submitted like a prompt submit (ready-gated, then a SINGLE
303
+ // \r after a delay; never \r\n) so the enter cannot be swallowed by a TUI
304
+ // startup flush.
305
+ const sent = writePromptSubmitInput(writePtyInput, target.sessionId, input)
306
+ if (!sent) {
307
+ return {
308
+ ok: false,
309
+ code: 'NO_PTY',
310
+ fromNodeId: senderNodeId,
311
+ toNodeId: targetNodeId,
312
+ fromSessionId: sender.sessionId,
313
+ toSessionId: target.sessionId,
314
+ message: 'No PTY process attached to target Agent',
315
+ }
316
+ }
317
+ appendTerminalData(projectRoot, targetSession, input, 'stdin')
318
+ }
319
+ const bridgeMessage = recordBridgeMessage(projectRoot, {
320
+ fromSessionId: sender.sessionId,
321
+ toSessionId: target.sessionId,
322
+ fromNodeId: senderNodeId,
323
+ toNodeId: targetNodeId,
324
+ data,
325
+ ...envelope,
326
+ recipientIndex,
327
+ recipientCount,
328
+ })
329
+ appendSessionEvent(projectRoot, targetSession, {
330
+ type: 'wf.bridge.message',
331
+ bridgeId: bridgeMessage?.bridgeId || null,
332
+ messageId: envelope.messageId,
333
+ fromSessionId: sender.sessionId,
334
+ toSessionId: target.sessionId,
335
+ fromNodeId: senderNodeId,
336
+ toNodeId: targetNodeId,
337
+ deliveryMode: envelope.deliveryMode,
338
+ topic: envelope.topic,
339
+ })
340
+ const deliveryKey = String(envelope.messageId || bridgeMessage?.bridgeId || '').trim()
341
+ const alreadyAudited = deliveryKey && listCompositionTransitions(projectRoot)
342
+ .some(item => item.cause === 'agent.delivery'
343
+ && item.messageId === deliveryKey
344
+ && item.targetNodeId === targetNodeId)
345
+ const transition = alreadyAudited
346
+ ? null
347
+ : recordCompositionTransition(projectRoot, {
348
+ compositionId: compositionIdFor(projectRoot),
349
+ from: 'queued',
350
+ to: 'delivered',
351
+ cause: 'agent.delivery',
352
+ messageId: deliveryKey || null,
353
+ eventId: envelope.eventId || null,
354
+ wakeupId: envelope.wakeupId || null,
355
+ timerNodeId: envelope.timerNodeId || null,
356
+ targetNodeId,
357
+ edgeId: envelope.edgeId || null,
358
+ graphVersion: Number(envelope.graphVersion || 1),
359
+ stateRevision: Number(envelope.stateRevision || 0),
360
+ deliveryMode: envelope.deliveryMode || 'direct',
361
+ contextRefs: [],
362
+ })
363
+ return {
364
+ ok: true,
365
+ code: 'DELIVERED',
366
+ messageId: envelope.messageId,
367
+ bridgeId: bridgeMessage?.bridgeId || null,
368
+ seq: bridgeMessage?.seq || null,
369
+ transition,
370
+ fromNodeId: senderNodeId,
371
+ toNodeId: targetNodeId,
372
+ fromSessionId: sender.sessionId,
373
+ toSessionId: target.sessionId,
374
+ topic: envelope.topic,
375
+ replyTo: envelope.replyTo,
376
+ }
377
+ }
378
+
379
+ function rangeOptions(payload = {}, defaultTail) {
380
+ const opts = isPlainObject(payload) ? payload : {}
381
+ const fromSeq = Number(opts.fromSeq)
382
+ const toSeq = Number(opts.toSeq)
383
+ const tail = Number(opts.tail)
384
+ return {
385
+ fromSeq: Number.isFinite(fromSeq) ? fromSeq : undefined,
386
+ toSeq: Number.isFinite(toSeq) ? toSeq : undefined,
387
+ tail: Number.isFinite(tail) && tail > 0 ? tail : defaultTail,
388
+ }
389
+ }
390
+
391
+ // ── Prompt-submit input (ready-gated, char-by-char typing, single \r) ──
392
+ // Mirror of the canonical server.mjs tracker + writePromptSubmitInput
393
+ // (server.mjs: terminalInputState/pendingSubmitTimers + writePromptSubmitInput):
394
+ // the body is typed char-by-char with PROMPT_TYPING_CHAR_DELAY_MS gaps (a
395
+ // bulk body write + \r leaves text unsubmitted in the codex composer, per-char
396
+ // typing submits), ready-gated (wait for the prompt marker, polling every
397
+ // PROMPT_SUBMIT_READY_POLL_MS up to PROMPT_SUBMIT_READY_WAIT_MS, then submit
398
+ // anyway), and the submit follows as a SINGLE \r (0x0D, never \r\n) after
399
+ // PROMPT_SUBMIT_ENTER_DELAY_MS, with one retry. A new submit for the same
400
+ // session cancels every pending poll/char/enter timer of the previous submit
401
+ // so a stale \r can never hit a re-registered PTY. Importing server.mjs here
402
+ // would create a cycle (server.mjs -> workflow-node-runtime.mjs ->
403
+ // agent-node.mjs), so the tracker is duplicated instead. server.mjs feeds this
404
+ // tracker through the exported trackTerminalSpawn/markTerminalReady/
405
+ // clearTerminalState at the same spawn/ready/exit/stop sites as its own
406
+ // tracker, so the two stay in lockstep; untracked sessions (direct
407
+ // registration, tests) are treated as ready (same default as the canonical).
408
+
409
+ /** sessionId -> { ready: boolean } — prompt-marker readiness for submit gating */
410
+ const terminalInputState = new Map()
411
+
412
+ /** sessionId -> pending submit timers (ready polls + enter), cancelled by the next submit */
413
+ const pendingSubmitTimers = new Map()
414
+
415
+ export function trackTerminalSpawn(sessionId) {
416
+ if (!sessionId) return
417
+ if (!terminalInputState.has(sessionId)) terminalInputState.set(sessionId, { ready: false })
418
+ }
419
+
420
+ export function markTerminalReady(sessionId) {
421
+ if (!sessionId) return
422
+ const entry = terminalInputState.get(sessionId) || { ready: false }
423
+ entry.ready = true
424
+ terminalInputState.set(sessionId, entry)
425
+ }
426
+
427
+ export function clearTerminalState(sessionId) {
428
+ if (!sessionId) return
429
+ terminalInputState.delete(sessionId)
430
+ }
431
+
432
+ function terminalSubmitReady(sessionId) {
433
+ const entry = terminalInputState.get(sessionId)
434
+ // Untracked sessions (direct registration, tests) are treated as ready:
435
+ // gating exists for server-spawned PTYs, which always record a spawn.
436
+ if (!entry) return true
437
+ return entry.ready === true
438
+ }
439
+
440
+ function cancelPendingSubmit(sessionId) {
441
+ const timers = pendingSubmitTimers.get(sessionId)
442
+ if (!timers) return
443
+ for (const timer of timers) clearTimeout(timer)
444
+ pendingSubmitTimers.delete(sessionId)
445
+ }
446
+
447
+ function scheduleSubmitTimer(sessionId, delayMs, fn) {
448
+ const timer = setTimeout(fn, delayMs)
449
+ const timers = pendingSubmitTimers.get(sessionId) || []
450
+ timers.push(timer)
451
+ pendingSubmitTimers.set(sessionId, timers)
452
+ return timer
453
+ }
454
+
455
+ function writePromptSubmitInput(writePtyInput, sessionId, data) {
456
+ const text = String(data || '')
457
+ const body = text.replace(/[\r\n]+$/g, '')
458
+ // A new submit supersedes any pending poll/char/enter of a previous submit.
459
+ cancelPendingSubmit(sessionId)
460
+
461
+ const scheduleEnter = () => {
462
+ scheduleSubmitTimer(sessionId, PROMPT_SUBMIT_ENTER_DELAY_MS, () => {
463
+ // Submit with a SINGLE \r (0x0D); never \r\n. Retry the enter once if
464
+ // the PTY disappeared between the last char and the enter.
465
+ if (!writePtyInput(sessionId, '\r')) {
466
+ scheduleSubmitTimer(sessionId, PROMPT_SUBMIT_ENTER_DELAY_MS, () => writePtyInput(sessionId, '\r'))
467
+ }
468
+ })
469
+ }
470
+
471
+ const submit = () => {
472
+ // Type the body char-by-char with PROMPT_TYPING_CHAR_DELAY_MS gaps, like
473
+ // the xterm.js frontend delivers keystrokes: a bulk write of the whole
474
+ // body + \r leaves the text unsubmitted in the codex composer, per-char
475
+ // typing submits reliably. The first char is written synchronously so a
476
+ // missing PTY still surfaces as NO_PTY (409) on the submit call; the
477
+ // remaining chars and the enter ride the pending-timer list and are
478
+ // cancelled by the next submit for the same session. An empty body skips
479
+ // the char loop and just schedules the enter.
480
+ const chars = Array.from(body)
481
+ if (chars.length > 0 && !writePtyInput(sessionId, chars[0])) return false
482
+ const typeNext = (index) => {
483
+ if (index >= chars.length) {
484
+ scheduleEnter()
485
+ return
486
+ }
487
+ // Every remaining char (and the enter) rides the pending-timer list, so
488
+ // a second submit for the same session aborts the whole sequence; stop
489
+ // typing early if the PTY disappeared mid-sequence.
490
+ scheduleSubmitTimer(sessionId, PROMPT_TYPING_CHAR_DELAY_MS, () => {
491
+ if (!writePtyInput(sessionId, chars[index])) return
492
+ typeNext(index + 1)
493
+ })
494
+ }
495
+ typeNext(1)
496
+ return true
497
+ }
498
+
499
+ if (terminalSubmitReady(sessionId)) return submit()
500
+
501
+ // PTY is not ready yet: poll for the prompt marker, then submit anyway.
502
+ const startedAt = Date.now()
503
+ const poll = () => {
504
+ if (terminalSubmitReady(sessionId) || Date.now() - startedAt >= PROMPT_SUBMIT_READY_WAIT_MS) {
505
+ submit()
506
+ return
507
+ }
508
+ scheduleSubmitTimer(sessionId, PROMPT_SUBMIT_READY_POLL_MS, poll)
509
+ }
510
+ poll()
511
+ return true
512
+ }
513
+
514
+ // Read latest terminal output for an agent node's session
515
+ export async function readOutput(nodeId, projectRoot, payload = {}) {
516
+ try {
517
+ const node = findGraphNode(projectRoot, nodeId)
518
+ const sessionId = node?.sessionId || nodeId
519
+ const { readTerminalRange } = await import('../terminal-store.mjs')
520
+ const result = readTerminalRange(projectRoot, {
521
+ sessionId,
522
+ ...rangeOptions(payload, 50),
523
+ })
524
+ return { sessionId, entries: result.entries || [], ...result }
525
+ } catch (error) {
526
+ rethrow(error)
527
+ }
528
+ }
529
+
530
+ // Send input to the agent's terminal
531
+ export async function sendInput(nodeId, projectRoot, payload = {}) {
532
+ try {
533
+ const node = findGraphNode(projectRoot, nodeId)
534
+ const sessionId = node?.sessionId || nodeId
535
+ const text = String(payload?.data ?? payload?.input ?? payload?.text ?? '')
536
+ const { writePtyInput } = await getWsTerminal()
537
+ const promptSubmit = payload?.submit === true || payload?.promptSubmit === true
538
+ const sent = promptSubmit
539
+ ? writePromptSubmitInput(writePtyInput, sessionId, text)
540
+ : writePtyInput(sessionId, text)
541
+ if (!sent) {
542
+ throw new ComponentNodeError('No PTY process attached to this session', {
543
+ statusCode: 409,
544
+ code: 'NO_PTY',
545
+ })
546
+ }
547
+ return { ok: true, sessionId, sent }
548
+ } catch (error) {
549
+ rethrow(error)
550
+ }
551
+ }
552
+
553
+ export async function sendMessage(nodeId, projectRoot, payload = {}) {
554
+ try {
555
+ const sender = assertAgentNode(projectRoot, nodeId, 'Sender Agent node')
556
+ const graph = loadWorkflowGraphMap(projectRoot)
557
+ const targets = recipientList(payload)
558
+ if (targets.length === 0) {
559
+ throw new ComponentNodeError('agent.sendMessage requires one recipient in to/target', {
560
+ statusCode: 400,
561
+ code: 'RECIPIENT_REQUIRED',
562
+ })
563
+ }
564
+ if (targets.length > 1) {
565
+ throw new ComponentNodeError('agent.sendMessage accepts exactly one recipient; use agent.broadcastMessage for multiple recipients', {
566
+ statusCode: 400,
567
+ code: 'TOO_MANY_RECIPIENTS',
568
+ })
569
+ }
570
+ const data = normalizeMessageData(payload)
571
+ const contextRefs = normalizeContextRefs(payload)
572
+ const envelope = { ...messageEnvelope(payload, 'direct'), contextRefs }
573
+ const force = forceUnconnectedAllowed(sender, payload)
574
+ const prefix = structuredEnvelopePrefix(envelope)
575
+ const delivery = await deliverAgentMessage(projectRoot, {
576
+ graph,
577
+ sender,
578
+ targetKey: targets[0],
579
+ data,
580
+ envelope,
581
+ recipientIndex: 1,
582
+ recipientCount: 1,
583
+ requireConnection: !force,
584
+ ptyInput: prefix ? `${prefix} ${data}` : data,
585
+ })
586
+ if (!delivery.ok) {
587
+ throw new ComponentNodeError(delivery.message || 'Agent message delivery failed', {
588
+ statusCode: delivery.code === 'NOT_CONNECTED' ? 403 : 409,
589
+ code: delivery.code || 'MESSAGE_DELIVERY_FAILED',
590
+ details: delivery,
591
+ })
592
+ }
593
+ return {
594
+ ok: true,
595
+ mode: 'direct',
596
+ messageId: envelope.messageId,
597
+ threadId: envelope.threadId,
598
+ requestId: envelope.requestId,
599
+ topic: envelope.topic,
600
+ deliveries: [delivery],
601
+ }
602
+ } catch (error) {
603
+ rethrow(error)
604
+ }
605
+ }
606
+
607
+ export async function broadcastMessage(nodeId, projectRoot, payload = {}) {
608
+ try {
609
+ const sender = assertAgentNode(projectRoot, nodeId, 'Sender Agent node')
610
+ const graph = loadWorkflowGraphMap(projectRoot)
611
+ const explicitTargets = recipientList(payload)
612
+ const targets = explicitTargets.length > 0
613
+ ? explicitTargets
614
+ : connectedAgentNodeIds(graph, graphNodeId(sender))
615
+ if (targets.length === 0) {
616
+ throw new ComponentNodeError('agent.broadcastMessage found no recipients', {
617
+ statusCode: 400,
618
+ code: 'RECIPIENT_REQUIRED',
619
+ })
620
+ }
621
+ const data = normalizeMessageData(payload)
622
+ const contextRefs = normalizeContextRefs(payload)
623
+ const envelope = { ...messageEnvelope(payload, 'broadcast'), contextRefs }
624
+ const force = forceUnconnectedAllowed(sender, payload)
625
+ const prefix = structuredEnvelopePrefix(envelope)
626
+ const uniqueTargets = [...new Set(targets)]
627
+ const deliveries = []
628
+ for (let index = 0; index < uniqueTargets.length; index += 1) {
629
+ deliveries.push(await deliverAgentMessage(projectRoot, {
630
+ graph,
631
+ sender,
632
+ targetKey: uniqueTargets[index],
633
+ data,
634
+ envelope,
635
+ recipientIndex: index + 1,
636
+ recipientCount: uniqueTargets.length,
637
+ requireConnection: !force,
638
+ ptyInput: prefix ? `${prefix} ${data}` : data,
639
+ }))
640
+ }
641
+ const deliveredCount = deliveries.filter(item => item.ok).length
642
+ return {
643
+ ok: deliveredCount === deliveries.length,
644
+ mode: 'broadcast',
645
+ messageId: envelope.messageId,
646
+ threadId: envelope.threadId,
647
+ requestId: envelope.requestId,
648
+ topic: envelope.topic,
649
+ deliveredCount,
650
+ failedCount: deliveries.length - deliveredCount,
651
+ deliveries,
652
+ }
653
+ } catch (error) {
654
+ rethrow(error)
655
+ }
656
+ }
657
+
658
+ export function readMessages(nodeId, projectRoot, payload = {}) {
659
+ try {
660
+ const sender = assertAgentNode(projectRoot, nodeId, 'Reader Agent node')
661
+ const opts = isPlainObject(payload) ? payload : {}
662
+ const requestId = String(opts.requestId || '').trim()
663
+ const threadId = String(opts.threadId || '').trim()
664
+ const wakeup = opts.wakeup === true || opts.wakeup === 'true'
665
+ const afterSeq = Number(opts.afterSeq)
666
+ const bridgeId = String(opts.bridgeId || '').trim()
667
+ const peerKey = String(opts.peer || opts.to || opts.from || opts.target || opts.node || '').trim()
668
+ const limit = Number(opts.limit || opts.tail || 200)
669
+ const senderNodeId = graphNodeId(sender)
670
+
671
+ // New filters (spec 5, 6.1): requestId aggregation and wakeup reads.
672
+ if (requestId || wakeup) {
673
+ if (wakeup) {
674
+ const ackRequested = opts.ack === true || opts.ack === 'true'
675
+ const consumedThroughSeq = Number(opts.consumedThroughSeq ?? opts.consumedSeq)
676
+ const consumedThroughByBridge = opts.consumedThroughByBridge
677
+ && typeof opts.consumedThroughByBridge === 'object'
678
+ && !Array.isArray(opts.consumedThroughByBridge)
679
+ ? opts.consumedThroughByBridge
680
+ : (bridgeId && Number.isFinite(consumedThroughSeq) ? { [bridgeId]: consumedThroughSeq } : null)
681
+ const pendingForAck = ackRequested && (Number.isFinite(consumedThroughSeq) || consumedThroughByBridge)
682
+ ? listBridgeMessagesForSession(projectRoot, sender.sessionId, {
683
+ deliveryMode: 'wakeup',
684
+ bridgeId,
685
+ limit: 1000,
686
+ includeConsumed: true,
687
+ }).entries.filter((entry) => {
688
+ const bridgeId = String(entry?.bridgeId || '').trim()
689
+ const bridgeSeq = consumedThroughByBridge?.[bridgeId]
690
+ const requested = bridgeSeq !== undefined ? Number(bridgeSeq) : consumedThroughSeq
691
+ return Number.isFinite(requested) && Number(entry?.seq || 0) <= requested
692
+ })
693
+ : []
694
+ const acknowledgement = ackRequested
695
+ ? acknowledgeBridgeMessages(projectRoot, sender.sessionId, consumedThroughSeq, consumedThroughByBridge)
696
+ : null
697
+ const result = listBridgeMessagesForSession(projectRoot, sender.sessionId, {
698
+ deliveryMode: 'wakeup',
699
+ bridgeId,
700
+ afterSeq: Number.isFinite(afterSeq) ? afterSeq : null,
701
+ afterSeqByBridge: opts.afterSeqByBridge,
702
+ limit,
703
+ })
704
+ let consumedTransition = null
705
+ if (acknowledgement?.consumedCount > 0) {
706
+ const entry = pendingForAck[0]
707
+ let envelope = {}
708
+ try { envelope = JSON.parse(String(entry?.data || '{}')) } catch { /* legacy bridge payload */ }
709
+ consumedTransition = recordCompositionTransition(projectRoot, {
710
+ compositionId: compositionIdFor(projectRoot),
711
+ from: 'delivered',
712
+ to: 'consumed',
713
+ cause: 'agent.readMessages.ack',
714
+ eventId: envelope.eventId || null,
715
+ wakeupId: envelope.wakeupId || envelope.messageId || entry?.messageId || null,
716
+ timerNodeId: envelope.timerNodeId || entry?.fromNodeId || null,
717
+ targetNodeId: senderNodeId,
718
+ edgeId: null,
719
+ graphVersion: Number(envelope.graphVersion || 1),
720
+ stateRevision: Number(envelope.stateRevision || 0),
721
+ consumedThroughSeq: acknowledgement.consumedThroughSeq,
722
+ contextRefs: [],
723
+ })
724
+ }
725
+ return {
726
+ ok: true,
727
+ mode: 'wakeup',
728
+ fromNodeId: senderNodeId,
729
+ fromSessionId: sender.sessionId,
730
+ entries: result.entries,
731
+ count: result.entries.length,
732
+ ...(acknowledgement ? acknowledgement : {}),
733
+ ...(consumedTransition ? { transition: consumedTransition } : {}),
734
+ }
735
+ }
736
+ // Aggregate all replies in one request thread across peers (AC-010).
737
+ const graph = loadWorkflowGraphMap(projectRoot)
738
+ const peerNodeIds = peerKey
739
+ ? [peerKey]
740
+ : (Array.isArray(graph.nodes) ? graph.nodes : [])
741
+ .filter(item => item?.sessionId)
742
+ .map(graphNodeId)
743
+ .filter(itemId => itemId && itemId !== senderNodeId)
744
+ const collected = []
745
+ for (const peerId of peerNodeIds) {
746
+ const peer = assertAgentNode(projectRoot, peerId, 'Peer Agent node')
747
+ const read = listBridgeMessages(projectRoot, {
748
+ fromSessionId: sender.sessionId,
749
+ toSessionId: peer.sessionId,
750
+ limit: Math.max(Number(limit) || 200, 1000),
751
+ })
752
+ for (const entry of read.entries) {
753
+ if (entry.requestId !== requestId) continue
754
+ if (threadId && entry.threadId !== threadId) continue
755
+ collected.push(entry)
756
+ }
757
+ }
758
+ collected.sort((a, b) => {
759
+ const tsA = String(a.ts || '')
760
+ const tsB = String(b.ts || '')
761
+ return tsA === tsB ? (Number(a.seq) || 0) - (Number(b.seq) || 0) : tsA.localeCompare(tsB)
762
+ })
763
+ return {
764
+ ok: true,
765
+ mode: 'request',
766
+ requestId,
767
+ threadId,
768
+ fromNodeId: senderNodeId,
769
+ fromSessionId: sender.sessionId,
770
+ toNodeId: peerKey || null,
771
+ entries: collected.slice(-(Number(limit) > 0 ? Number(limit) : collected.length)),
772
+ count: collected.length,
773
+ }
774
+ }
775
+
776
+ // Legacy behavior unchanged (AC-026/T14): peer-scoped read.
777
+ if (!peerKey) {
778
+ throw new ComponentNodeError('agent.readMessages requires peer/to/from target Agent node', {
779
+ statusCode: 400,
780
+ code: 'PEER_REQUIRED',
781
+ })
782
+ }
783
+ const peer = assertAgentNode(projectRoot, peerKey, 'Peer Agent node')
784
+ return {
785
+ ok: true,
786
+ ...listBridgeMessages(projectRoot, {
787
+ fromSessionId: sender.sessionId,
788
+ toSessionId: peer.sessionId,
789
+ limit,
790
+ }),
791
+ fromNodeId: senderNodeId,
792
+ toNodeId: graphNodeId(peer),
793
+ }
794
+ } catch (error) {
795
+ rethrow(error)
796
+ }
797
+ }
798
+
799
+ // Read the agent's transcript from disk
800
+ export async function readTranscript(nodeId, projectRoot, payload = {}) {
801
+ try {
802
+ const node = findGraphNode(projectRoot, nodeId)
803
+ const sessionId = node?.sessionId || nodeId
804
+ const { readTerminalRange } = await import('../terminal-store.mjs')
805
+ const result = readTerminalRange(projectRoot, {
806
+ sessionId,
807
+ ...rangeOptions(payload, 200),
808
+ })
809
+ return { sessionId, entries: result.entries || [], ...result }
810
+ } catch (error) {
811
+ rethrow(error)
812
+ }
813
+ }
814
+
815
+ // Start an agent node; the server control plane owns PTY spawning
816
+ export function start(nodeId, projectRoot, payload = {}) {
817
+ throw new ComponentNodeError(
818
+ 'agent.start is delegated to the server control plane. Use POST /api/a2a/nodes/:id/start',
819
+ { statusCode: 400, code: 'USE_A2A_START' }
820
+ )
821
+ }
822
+
823
+ // Stop an agent node's session and kill its PTY
824
+ export async function stop(nodeId, projectRoot, payload = {}) {
825
+ try {
826
+ const node = findGraphNode(projectRoot, nodeId)
827
+ const sessionId = node?.sessionId || nodeId
828
+ const { killPtyProcess } = await getWsTerminal()
829
+ killPtyProcess(sessionId)
830
+ return { ok: true, sessionId, stopped: true }
831
+ } catch (error) {
832
+ rethrow(error)
833
+ }
834
+ }
835
+
836
+ // Restart an agent node; the server control plane owns PTY respawning
837
+ export function restart(nodeId, projectRoot, payload = {}) {
838
+ throw new ComponentNodeError(
839
+ 'agent.restart is delegated to the server control plane. Use POST /api/a2a/nodes/:id/restart',
840
+ { statusCode: 400, code: 'USE_A2A_START' }
841
+ )
842
+ }
843
+
844
+ // Delete an agent node from the workflow graph (must be stopped first)
845
+ export function deleteAgentNode(nodeId, projectRoot, payload = {}) {
846
+ try {
847
+ const node = findGraphNode(projectRoot, nodeId)
848
+ if (!node) {
849
+ throw new ComponentNodeError('Agent node not found in graph', { statusCode: 404, code: 'NOT_FOUND' })
850
+ }
851
+ if (node.status === 'running' || node.status === 'starting') {
852
+ throw new ComponentNodeError('Stop the agent before deleting', { statusCode: 409, code: 'NODE_LIVE' })
853
+ }
854
+ const removed = removeWorkflowGraphNode(projectRoot, nodeId)
855
+ return { ok: true, removed: removed.removed }
856
+ } catch (error) {
857
+ rethrow(error)
858
+ }
859
+ }
860
+
861
+ // Build context for an agent node (connected peers, available actions)
862
+ export function readContext(nodeId, projectRoot, payload = {}) {
863
+ try {
864
+ const node = findGraphNode(projectRoot, nodeId)
865
+ if (!node) {
866
+ throw new ComponentNodeError('Agent node not found', { statusCode: 404, code: 'NOT_FOUND' })
867
+ }
868
+ const graph = loadWorkflowGraphMap(projectRoot)
869
+ const nodeKey = node.nodeId || node.id
870
+ const sessionKey = node.sessionId
871
+ const connections = (graph.edges || [])
872
+ .filter(edge =>
873
+ (edge.from === nodeKey || edge.to === nodeKey)
874
+ || (edge.source === nodeKey || edge.target === nodeKey)
875
+ || (sessionKey && (edge.fromSessionId === sessionKey || edge.toSessionId === sessionKey))
876
+ )
877
+ .map(edge => {
878
+ const isSource = edge.from === nodeKey || edge.source === nodeKey || edge.fromSessionId === sessionKey
879
+ return {
880
+ edgeId: edge.id || `${edge.from}->${edge.to}`,
881
+ peerNodeId: isSource ? (edge.to || edge.toSessionId) : (edge.from || edge.fromSessionId),
882
+ endpointRole: isSource ? 'source' : 'target',
883
+ localHandle: isSource ? edge.sourceHandle || null : edge.targetHandle || null,
884
+ peerHandle: isSource ? edge.targetHandle || null : edge.sourceHandle || null,
885
+ sourceHandle: edge.sourceHandle || null,
886
+ targetHandle: edge.targetHandle || null,
887
+ relation: edge.relation || 'wf-bridge',
888
+ direction: 'bidirectional',
889
+ }
890
+ })
891
+ const live = node.status === 'running' || node.status === 'starting'
892
+ return {
893
+ node,
894
+ connections,
895
+ availableActions: live
896
+ ? [
897
+ 'sendInput',
898
+ 'sendMessage',
899
+ 'broadcastMessage',
900
+ 'readMessages',
901
+ 'readOutput',
902
+ 'readTranscript',
903
+ 'stop',
904
+ 'agent.createNode',
905
+ 'agent.connectNodes',
906
+ 'agent.disconnectNodes',
907
+ 'agent.moveNode',
908
+ 'agent.deleteNode',
909
+ 'agent.deleteNodes',
910
+ 'agent.readGraph',
911
+ ]
912
+ : ['start', 'delete', 'agent.readGraph'],
913
+ }
914
+ } catch (error) {
915
+ rethrow(error)
916
+ }
917
+ }
918
+
919
+ // The workflow-node-runtime routes "agent.delete" to the "delete" adapter suffix
920
+ export { deleteAgentNode as delete }