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.
- package/CHANGELOG.md +49 -0
- package/README-CN.md +4 -2
- package/README.md +23 -4
- package/package.json +17 -2
- package/src/generator.js +19 -6
- package/src/index.js +531 -38
- package/src/prompts.js +4 -4
- package/src/ui/dist/assets/AgentsRoute-BGGs90wH.js +7 -0
- package/src/ui/dist/assets/Assistant-Bold-gm-uSS1B.woff2 +0 -0
- package/src/ui/dist/assets/Assistant-Medium-DrcxCXg3.woff2 +0 -0
- package/src/ui/dist/assets/Assistant-Regular-DVxZuzxb.woff2 +0 -0
- package/src/ui/dist/assets/Assistant-SemiBold-SCI4bEL9.woff2 +0 -0
- package/src/ui/dist/assets/Combination-DhBLEmof.js +42 -0
- package/src/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/src/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/src/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/src/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/src/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/src/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/src/ui/dist/assets/RolesRoute-DnodCSz0.js +2 -0
- package/src/ui/dist/assets/RuntimePicker-CucD8TGn.js +7 -0
- package/src/ui/dist/assets/SettingsRoute-DquMWjac.js +2 -0
- package/src/ui/dist/assets/TaskList-Bxc0Uktx.js +7 -0
- package/src/ui/dist/assets/TerminalDrawer-CDusYltc.js +36 -0
- package/src/ui/dist/assets/WorkflowRoute-BN8yHmUs.css +1 -0
- package/src/ui/dist/assets/WorkflowRoute-D-0wVDpY.js +334 -0
- package/src/ui/dist/assets/abnfDiagram-VRR7QNED-zkRKkaxO.js +2 -0
- package/src/ui/dist/assets/apl-B4CMkyY2.js +2 -0
- package/src/ui/dist/assets/ar-SA-G6X2FPQ2-BiHaArx5.js +11 -0
- package/src/ui/dist/assets/arc-CBnLtOFO.js +2 -0
- package/src/ui/dist/assets/architectureDiagram-ZJ3FMSHR-DWXRXsh1.js +37 -0
- package/src/ui/dist/assets/asciiarmor-Df11BRmG.js +2 -0
- package/src/ui/dist/assets/asn1-EdZsLKOL.js +2 -0
- package/src/ui/dist/assets/asterisk-B-8jnY81.js +2 -0
- package/src/ui/dist/assets/az-AZ-76LH7QW2-CiT05voO.js +2 -0
- package/src/ui/dist/assets/bg-BG-XCXSNQG7-L-UM9tNf.js +6 -0
- package/src/ui/dist/assets/blockDiagram-677ZJIJ3-BIyh3Bry.js +133 -0
- package/src/ui/dist/assets/bn-BD-2XOGV67Q-NdgbA0bC.js +6 -0
- package/src/ui/dist/assets/brainfuck-C4LP7Hcl.js +2 -0
- package/src/ui/dist/assets/c4Diagram-LMCZKHZV-CA54vWWM.js +11 -0
- package/src/ui/dist/assets/ca-ES-6MX7JW3Y-BKZZsQ5J.js +9 -0
- package/src/ui/dist/assets/channel-Da_-zcAu.js +2 -0
- package/src/ui/dist/assets/chunk-2Q5K7J3B-DE4cxr1v.js +2 -0
- package/src/ui/dist/assets/chunk-32BRIVSS-i7FwbEU9.js +2 -0
- package/src/ui/dist/assets/chunk-5VM5RSS4-BhIcOYSu.js +16 -0
- package/src/ui/dist/assets/chunk-EX3LRPZG-Ci9zZRIs.js +232 -0
- package/src/ui/dist/assets/chunk-JWPE2WC7-BFdkcz-G.js +2 -0
- package/src/ui/dist/assets/chunk-MOJQB5TN-Dzmapl_S.js +89 -0
- package/src/ui/dist/assets/chunk-RYQCIY6F-RTmp7FOy.js +2 -0
- package/src/ui/dist/assets/chunk-V7JOEXUC-DInU3v3D.js +207 -0
- package/src/ui/dist/assets/chunk-VR4S4FIN-BHoyGBQO.js +2 -0
- package/src/ui/dist/assets/chunk-XXDRQBXY-DfeLZNZx.js +2 -0
- package/src/ui/dist/assets/classDiagram-OUVF2IWQ-FKbUS0bu.js +2 -0
- package/src/ui/dist/assets/classDiagram-v2-EOCWNBFH-FKbUS0bu.js +2 -0
- package/src/ui/dist/assets/clike-B9uivgTg.js +2 -0
- package/src/ui/dist/assets/clojure-BMjYHr_A.js +2 -0
- package/src/ui/dist/assets/cmake-BQqOBYOt.js +2 -0
- package/src/ui/dist/assets/cobol-CWcv1MsR.js +2 -0
- package/src/ui/dist/assets/coffeescript-S37ZYGWr.js +2 -0
- package/src/ui/dist/assets/commonlisp-DBKNyK5s.js +2 -0
- package/src/ui/dist/assets/cose-bilkent-JH36ORCC-_5PUJ615.js +2 -0
- package/src/ui/dist/assets/crystal-SjHAIU92.js +2 -0
- package/src/ui/dist/assets/cs-CZ-2BRQDIVT-DnkfnhDU.js +12 -0
- package/src/ui/dist/assets/css-BnMrqG3P.js +2 -0
- package/src/ui/dist/assets/cynefin-VYW2F7L2-CmkcFv-b.js +179 -0
- package/src/ui/dist/assets/cynefinDiagram-TSTJHNR4-D72VZn8H.js +63 -0
- package/src/ui/dist/assets/cypher-C_CwsFkJ.js +2 -0
- package/src/ui/dist/assets/cytoscape.esm-DTSO7Bv0.js +332 -0
- package/src/ui/dist/assets/d-pRatUO7H.js +2 -0
- package/src/ui/dist/assets/da-DK-5WZEPLOC-C54tQUgd.js +6 -0
- package/src/ui/dist/assets/dagre-VKFMJZFB-0BsAkrmo.js +5 -0
- package/src/ui/dist/assets/de-DE-XR44H4JA-DGfZlR10.js +9 -0
- package/src/ui/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
- package/src/ui/dist/assets/diagram-FQU43EPY-C1ZJDOca.js +4 -0
- package/src/ui/dist/assets/diagram-G47NLZAW-D3pr3FSP.js +25 -0
- package/src/ui/dist/assets/diagram-NH7WQ7WH-Bwry0NV-.js +25 -0
- package/src/ui/dist/assets/diagram-OA4YK3LP-L6g09cmV.js +31 -0
- package/src/ui/dist/assets/diagram-WEI45ONY-Bh1puYVX.js +42 -0
- package/src/ui/dist/assets/diff-DbItnlRl.js +2 -0
- package/src/ui/dist/assets/directory-open-01563666-DWU9wJ6I.js +2 -0
- package/src/ui/dist/assets/directory-open-4ed118d0-CunoC1EB.js +2 -0
- package/src/ui/dist/assets/dockerfile-BKs6k2Af.js +2 -0
- package/src/ui/dist/assets/dtd-DF_7sFjM.js +2 -0
- package/src/ui/dist/assets/dylan-DwRh75JA.js +2 -0
- package/src/ui/dist/assets/ebnf-CDyGwa7X.js +2 -0
- package/src/ui/dist/assets/ebnfDiagram-CCIWWBDH-BC_mBRR5.js +2 -0
- package/src/ui/dist/assets/ecl-Cabwm37j.js +2 -0
- package/src/ui/dist/assets/eiffel-CnydiIhH.js +2 -0
- package/src/ui/dist/assets/el-GR-BZB4AONW-DsnwWweL.js +11 -0
- package/src/ui/dist/assets/elm-vLlmbW-K.js +2 -0
- package/src/ui/dist/assets/erDiagram-Q63AITRT-Bkxam36l.js +86 -0
- package/src/ui/dist/assets/erlang-BNw1qcRV.js +2 -0
- package/src/ui/dist/assets/es-ES-U4NZUMDT-CRxBcQgC.js +10 -0
- package/src/ui/dist/assets/eu-ES-A7QVB2H4-CTd_E7YR.js +12 -0
- package/src/ui/dist/assets/excalidraw-default-bMWIgNCy.svg +1 -0
- package/src/ui/dist/assets/fa-IR-HGAKTJCU-DO56k7eG.js +9 -0
- package/src/ui/dist/assets/factor-kuTfRLto.js +2 -0
- package/src/ui/dist/assets/fcl-Kvtd6kyn.js +2 -0
- package/src/ui/dist/assets/fi-FI-Z5N7JZ37-DEDCF9WB.js +7 -0
- package/src/ui/dist/assets/file-open-002ab408-DIuFHtCF.js +2 -0
- package/src/ui/dist/assets/file-open-7c801643-684qeFg4.js +2 -0
- package/src/ui/dist/assets/file-save-3189631c-C1wFhQhH.js +2 -0
- package/src/ui/dist/assets/file-save-745eba88-Bb9F9Kg7.js +2 -0
- package/src/ui/dist/assets/flowDiagram-23GEKE2U-C3SAEao7.js +157 -0
- package/src/ui/dist/assets/forth-Ffai-XNe.js +2 -0
- package/src/ui/dist/assets/fortran-DYz_wnZ1.js +2 -0
- package/src/ui/dist/assets/fr-FR-RHASNOE6-DE2nPyDt.js +10 -0
- package/src/ui/dist/assets/ganttDiagram-NO4QXBWP-U-J_Xi-_.js +293 -0
- package/src/ui/dist/assets/gas-Bneqetm1.js +2 -0
- package/src/ui/dist/assets/gherkin-heZmZLOM.js +2 -0
- package/src/ui/dist/assets/gitGraphDiagram-IHSO6WYX-BADVbD-a.js +107 -0
- package/src/ui/dist/assets/gl-ES-HMX3MZ6V-mCqVgQHC.js +11 -0
- package/src/ui/dist/assets/graph-C9eacEi8.js +2 -0
- package/src/ui/dist/assets/groovy-D9Dt4D0W.js +2 -0
- package/src/ui/dist/assets/haskell-Cw1EW3IL.js +2 -0
- package/src/ui/dist/assets/haxe-H-WmDvRZ.js +2 -0
- package/src/ui/dist/assets/he-IL-6SHJWFNN-KnaLrCzw.js +11 -0
- package/src/ui/dist/assets/hi-IN-IWLTKZ5I-wuqiaaWt.js +5 -0
- package/src/ui/dist/assets/http-DBlCnlav.js +2 -0
- package/src/ui/dist/assets/hu-HU-A5ZG7DT2-DLg_zm22.js +8 -0
- package/src/ui/dist/assets/id-ID-SAP4L64H-MB2mXqcR.js +11 -0
- package/src/ui/dist/assets/idl-BEugSyMb.js +2 -0
- package/src/ui/dist/assets/image-blob-reduce.esm-HwCm7IZ0.js +8 -0
- package/src/ui/dist/assets/index-39SJtrt0.js +2 -0
- package/src/ui/dist/assets/index-BQ0LIrW-.js +2 -0
- package/src/ui/dist/assets/index-BcAUh2Nm.css +1 -0
- package/src/ui/dist/assets/index-BcThOK-i.js +331 -0
- package/src/ui/dist/assets/index-BnxV3k_S.js +3 -0
- package/src/ui/dist/assets/index-C7MZBHbT.js +117 -0
- package/src/ui/dist/assets/index-CCvKI2rM.js +2 -0
- package/src/ui/dist/assets/index-CZvmcCab.js +8 -0
- package/src/ui/dist/assets/index-Cp3hLKNl.js +2 -0
- package/src/ui/dist/assets/index-D7ayFxcx.js +2 -0
- package/src/ui/dist/assets/index-DAYxSQGU.js +2 -0
- package/src/ui/dist/assets/index-DD-HeMV0.css +1 -0
- package/src/ui/dist/assets/index-DPMxd3Qn.js +2 -0
- package/src/ui/dist/assets/index-DSe2jx3k.js +4 -0
- package/src/ui/dist/assets/index-DUirCkgW.js +2 -0
- package/src/ui/dist/assets/index-DaKPQ2hN.js +159 -0
- package/src/ui/dist/assets/index-DzpuR0Jg.js +2 -0
- package/src/ui/dist/assets/index-POndwsCI.js +2 -0
- package/src/ui/dist/assets/index-R8NM9I_9.js +2 -0
- package/src/ui/dist/assets/index-TCDuDhBj.js +2 -0
- package/src/ui/dist/assets/index-TckzASdM.js +2 -0
- package/src/ui/dist/assets/index-Yi5ytFFr.js +2 -0
- package/src/ui/dist/assets/infoDiagram-FWYZ7A6U-CiGBlFqH.js +3 -0
- package/src/ui/dist/assets/init-Gi6I4Gst.js +2 -0
- package/src/ui/dist/assets/ishikawaDiagram-FXEZZL3T-B1aheRbz.js +71 -0
- package/src/ui/dist/assets/it-IT-JPQ66NNP-DT3HSU7X.js +12 -0
- package/src/ui/dist/assets/ja-JP-DBVTYXUO-CsfJjjWt.js +9 -0
- package/src/ui/dist/assets/javascript-iXu5QeM3.js +2 -0
- package/src/ui/dist/assets/journeyDiagram-5HDEW3XC-DtnJPxub.js +140 -0
- package/src/ui/dist/assets/julia-DuME0IfC.js +2 -0
- package/src/ui/dist/assets/kaa-6HZHGXH3-DQz-1-Gn.js +2 -0
- package/src/ui/dist/assets/kab-KAB-ZGHBKWFO-CaH-LSoK.js +9 -0
- package/src/ui/dist/assets/kanban-definition-HUTT4EX6-CZatSm3e.js +90 -0
- package/src/ui/dist/assets/katex-C5jXJg4s.js +258 -0
- package/src/ui/dist/assets/kk-KZ-P5N5QNE5-BMXmcm55.js +2 -0
- package/src/ui/dist/assets/km-KH-HSX4SM5Z-ZeoJNBpN.js +12 -0
- package/src/ui/dist/assets/ko-KR-MTYHY66A-BeaLRKph.js +10 -0
- package/src/ui/dist/assets/ku-TR-6OUDTVRD-B_28KrkR.js +10 -0
- package/src/ui/dist/assets/layout-DEXfKzaS.js +2 -0
- package/src/ui/dist/assets/linear-CpEDnQRC.js +2 -0
- package/src/ui/dist/assets/livescript-BwQOo05w.js +2 -0
- package/src/ui/dist/assets/lt-LT-XHIRWOB4-BxDcnUhp.js +4 -0
- package/src/ui/dist/assets/lua-VAEuO923.js +2 -0
- package/src/ui/dist/assets/lv-LV-5QDEKY6T-DpKDl1_y.js +8 -0
- package/src/ui/dist/assets/map-Czzmt4hB.js +2 -0
- package/src/ui/dist/assets/mathematica-DTrFuWx2.js +2 -0
- package/src/ui/dist/assets/mbox-CNhZ1qSd.js +2 -0
- package/src/ui/dist/assets/mermaidLoader-CBO31t0J.js +305 -0
- package/src/ui/dist/assets/mermaidLoader-CEK31ho9.css +1 -0
- package/src/ui/dist/assets/mindmap-definition-LN4V7U3C-CQ0TccEr.js +97 -0
- package/src/ui/dist/assets/mirc-CjQqDB4T.js +2 -0
- package/src/ui/dist/assets/mllike-CXdrOF99.js +2 -0
- package/src/ui/dist/assets/modelica-Dc1JOy9r.js +2 -0
- package/src/ui/dist/assets/mr-IN-CRQNXWMA-BKCZT58p.js +14 -0
- package/src/ui/dist/assets/mscgen-BA5vi2Kp.js +2 -0
- package/src/ui/dist/assets/mumps-BT43cFF4.js +2 -0
- package/src/ui/dist/assets/my-MM-5M5IBNSE-D34k0G9T.js +2 -0
- package/src/ui/dist/assets/nb-NO-T6EIAALU-DXr_KW8J.js +11 -0
- package/src/ui/dist/assets/nginx-DdIZxoE0.js +2 -0
- package/src/ui/dist/assets/nl-NL-IS3SIHDZ-C1L0aVDR.js +9 -0
- package/src/ui/dist/assets/nn-NO-6E72VCQL-CLWVSxbZ.js +9 -0
- package/src/ui/dist/assets/nsis-LdVXkNf5.js +2 -0
- package/src/ui/dist/assets/ntriples-BfvgReVJ.js +2 -0
- package/src/ui/dist/assets/oc-FR-POXYY2M6-nf8_J3eR.js +9 -0
- package/src/ui/dist/assets/octave-Ck1zUtKM.js +2 -0
- package/src/ui/dist/assets/ordinal-Cboi1Yqb.js +2 -0
- package/src/ui/dist/assets/oz-BzwKVEFT.js +2 -0
- package/src/ui/dist/assets/pa-IN-N4M65BXN-CAMJ-xd6.js +5 -0
- package/src/ui/dist/assets/pascal--L3eBynH.js +2 -0
- package/src/ui/dist/assets/pegDiagram-2B236MQR-Bj2RcmRd.js +2 -0
- package/src/ui/dist/assets/percentages-BXMCSKIN-s9yWFdr6.js +160 -0
- package/src/ui/dist/assets/perl-CdXCOZ3F.js +2 -0
- package/src/ui/dist/assets/pica-BGv_AhAB.js +8 -0
- package/src/ui/dist/assets/pieDiagram-ENE6RG2P-obpzz8dC.js +40 -0
- package/src/ui/dist/assets/pig-CevX1Tat.js +2 -0
- package/src/ui/dist/assets/pl-PL-T2D74RX3-DKJ5H85v.js +10 -0
- package/src/ui/dist/assets/powershell-CFHJl5sT.js +2 -0
- package/src/ui/dist/assets/properties-C78fOPTZ.js +2 -0
- package/src/ui/dist/assets/protobuf-ChK-085T.js +2 -0
- package/src/ui/dist/assets/{proxy-D0vUbds5.js → proxy-BSmwef4H.js} +2 -2
- package/src/ui/dist/assets/pt-BR-5N22H2LF-B5kow-kN.js +10 -0
- package/src/ui/dist/assets/pt-PT-UZXXM6DQ-B2G34fso.js +10 -0
- package/src/ui/dist/assets/pug-DeIclll2.js +2 -0
- package/src/ui/dist/assets/puppet-DMA9R1ak.js +2 -0
- package/src/ui/dist/assets/python-BuPzkPfP.js +2 -0
- package/src/ui/dist/assets/q-pXgVlZs6.js +2 -0
- package/src/ui/dist/assets/quadrantDiagram-ABIIQ3AL-Cl-T7NkJ.js +8 -0
- package/src/ui/dist/assets/r-B6wPVr8A.js +2 -0
- package/src/ui/dist/assets/railroadDiagram-RFXS5EU6-DMq82RHg.js +2 -0
- package/src/ui/dist/assets/{refresh-cw-JNmExijd.js → refresh-cw-CbFd7guV.js} +2 -2
- package/src/ui/dist/assets/requirementDiagram-TGXJPOKE-tGInMDgU.js +85 -0
- package/src/ui/dist/assets/ro-RO-JPDTUUEW-BwLdZW91.js +12 -0
- package/src/ui/dist/assets/roundRect-0PYZxl1G.js +2 -0
- package/src/ui/dist/assets/rpm-CTu-6PCP.js +2 -0
- package/src/ui/dist/assets/ru-RU-B4JR7IUQ-DpdAgIJc.js +10 -0
- package/src/ui/dist/assets/ruby-B2Rjki9n.js +2 -0
- package/src/ui/dist/assets/runtimeBrand-BoKPimsz.js +2 -0
- package/src/ui/dist/assets/sankeyDiagram-HTMAVEWB-C7X-ET4m.js +41 -0
- package/src/ui/dist/assets/sas-B4kiWyti.js +2 -0
- package/src/ui/dist/assets/save-D1CXHwBw.js +12 -0
- package/src/ui/dist/assets/scheme-C41bIUwD.js +2 -0
- package/src/ui/dist/assets/sequenceDiagram-DBY2YBRQ-Bn24i_nY.js +163 -0
- package/src/ui/dist/assets/settings-2-DtSNAAcU.js +22 -0
- package/src/ui/dist/assets/shell-CjFT_Tl9.js +2 -0
- package/src/ui/dist/assets/shield-check-BVbJ8T_N.js +7 -0
- package/src/ui/dist/assets/si-LK-N5RQ5JYF-naJaUy5u.js +2 -0
- package/src/ui/dist/assets/sieve-C3Gn_uJK.js +2 -0
- package/src/ui/dist/assets/simple-mode-GW_nhZxv.js +2 -0
- package/src/ui/dist/assets/sizeCapture-X5ZJPWSS-DAQHfm82.js +2 -0
- package/src/ui/dist/assets/sk-SK-C5VTKIMK-1NPz1J_d.js +7 -0
- package/src/ui/dist/assets/sl-SI-NN7IZMDC-D8RfmNQw.js +7 -0
- package/src/ui/dist/assets/smalltalk-CnHTOXQT.js +2 -0
- package/src/ui/dist/assets/solr-DehyRSwq.js +2 -0
- package/src/ui/dist/assets/sparql-DkYu6x3z.js +2 -0
- package/src/ui/dist/assets/spreadsheet-BCZA_wO0.js +2 -0
- package/src/ui/dist/assets/sql-D0XecflT.js +2 -0
- package/src/ui/dist/assets/stateDiagram-2N3HPSRC-Ck48D1ck.js +2 -0
- package/src/ui/dist/assets/stateDiagram-v2-6OUMAXLB-CdfRCJAJ.js +2 -0
- package/src/ui/dist/assets/stex-C3f8Ysf7.js +2 -0
- package/src/ui/dist/assets/style-C3QI7VPf.css +1 -0
- package/src/ui/dist/assets/stylus-B533Al4x.js +2 -0
- package/src/ui/dist/assets/subset-shared.chunk-eAtLHmbi.js +85 -0
- package/src/ui/dist/assets/subset-worker.chunk-DeHCTnTk.js +2 -0
- package/src/ui/dist/assets/sv-SE-XGPEYMSR-BeOYCU-8.js +11 -0
- package/src/ui/dist/assets/swift-BzpIVaGY.js +2 -0
- package/src/ui/dist/assets/swimlanes-5IMT3BWC-DOy22UjP.js +3 -0
- package/src/ui/dist/assets/swimlanesDiagram-G3AALYLV-sicPbVOg.js +9 -0
- package/src/ui/dist/assets/ta-IN-2NMHFXQM-CtS68WDd.js +10 -0
- package/src/ui/dist/assets/tcl-DVfN8rqt.js +2 -0
- package/src/ui/dist/assets/{terminal-BBQvnOAK.js → terminal-DEby5Y_P.js} +2 -2
- package/src/ui/dist/assets/terminalControl-BkFeDVXo.js +134 -0
- package/src/ui/dist/assets/textile-CnDTJFAw.js +2 -0
- package/src/ui/dist/assets/th-TH-HPSO5L25-DCHY9-Co.js +3 -0
- package/src/ui/dist/assets/tiddlywiki-DO-Gjzrf.js +2 -0
- package/src/ui/dist/assets/tiki-DGYXhP31.js +2 -0
- package/src/ui/dist/assets/timeline-definition-FHXFAJF6-DVkG72qO.js +121 -0
- package/src/ui/dist/assets/toml-Bm5Em-hy.js +2 -0
- package/src/ui/dist/assets/tr-TR-DEFEU3FU-y5-vjTv8.js +8 -0
- package/src/ui/dist/assets/troff-wAsdV37c.js +2 -0
- package/src/ui/dist/assets/ttcn-CfJYG6tj.js +2 -0
- package/src/ui/dist/assets/ttcn-cfg-B9xdYoR4.js +2 -0
- package/src/ui/dist/assets/turtle-B1tBg_DP.js +2 -0
- package/src/ui/dist/assets/uk-UA-QMV73CPH-BRbR5It6.js +7 -0
- package/src/ui/dist/assets/useReducedMotion-D07XP52Q.js +12 -0
- package/src/ui/dist/assets/vb-CmGdzxic.js +2 -0
- package/src/ui/dist/assets/vbscript-BuJXcnF6.js +2 -0
- package/src/ui/dist/assets/velocity-D8B20fx6.js +2 -0
- package/src/ui/dist/assets/vennDiagram-L72KCM5P-DwMwBlf-.js +35 -0
- package/src/ui/dist/assets/verilog-C6RDOZhf.js +2 -0
- package/src/ui/dist/assets/vhdl-lSbBsy5d.js +2 -0
- package/src/ui/dist/assets/vi-VN-M7AON7JQ-s6wSBv2s.js +6 -0
- package/src/ui/dist/assets/wardleyDiagram-EHGQE667-CNuuvzEg.js +79 -0
- package/src/ui/dist/assets/webidl-ZXfAyPTL.js +2 -0
- package/src/ui/dist/assets/{x-DoIOGAJz.js → x-B84wq78k.js} +2 -2
- package/src/ui/dist/assets/xquery-DzFWVndE.js +2 -0
- package/src/ui/dist/assets/xychartDiagram-FW5EYKEG-dUpZxmn6.js +8 -0
- package/src/ui/dist/assets/yacas-BJ4BC0dw.js +2 -0
- package/src/ui/dist/assets/z80-Hz9HOZM7.js +2 -0
- package/src/ui/dist/assets/zh-CN-LNUGB5OW-Cu_-POQN.js +11 -0
- package/src/ui/dist/assets/zh-HK-E62DVLB3-BCx4W4qZ.js +2 -0
- package/src/ui/dist/assets/zh-TW-RAJ6MFWO-02wx_Mrj.js +10 -0
- package/src/ui/dist/icons/excalidraw.svg +1 -0
- package/src/ui/dist/icons/markdown.svg +1 -0
- package/src/ui/dist/index.html +2 -2
- package/src/ui/package.json +10 -0
- package/src/ui/playwright.config.ts +36 -0
- package/src/ui/pnpm-workspace.yaml +2 -0
- package/src/ui/public/icons/excalidraw.svg +1 -0
- package/src/ui/public/icons/markdown.svg +1 -0
- package/src/ui/tsconfig.json +2 -1
- package/src/ui/vite.config.ts +1 -0
- package/src/wf-ui-server/__tests__/a2a-store.test.mjs +432 -15
- package/src/wf-ui-server/__tests__/action-registry-loader.test.mjs +156 -0
- package/src/wf-ui-server/__tests__/claude-stream-json.test.mjs +397 -0
- package/src/wf-ui-server/__tests__/codex-appserver.test.mjs +392 -0
- package/src/wf-ui-server/__tests__/component-node-api.test.mjs +881 -0
- package/src/wf-ui-server/__tests__/component-node-store.test.mjs +401 -0
- package/src/wf-ui-server/__tests__/control-plane-acceptance.test.mjs +2027 -0
- package/src/wf-ui-server/__tests__/control-plane-cli-smoke.test.mjs +1014 -0
- package/src/wf-ui-server/__tests__/dispatch-lifecycle.test.mjs +330 -0
- package/src/wf-ui-server/__tests__/effort-compatibility-red-092.test.mjs +151 -0
- package/src/wf-ui-server/__tests__/graph-layout-agent-tree.test.mjs +254 -0
- package/src/wf-ui-server/__tests__/graph-layout-tidy.test.mjs +260 -0
- package/src/wf-ui-server/__tests__/graph-layout.test.mjs +84 -0
- package/src/wf-ui-server/__tests__/node-config-api.test.mjs +384 -0
- package/src/wf-ui-server/__tests__/opencode-server.test.mjs +526 -0
- package/src/wf-ui-server/__tests__/peer-capsule.test.mjs +2 -2
- package/src/wf-ui-server/__tests__/pty-adapter.test.mjs +71 -1
- package/src/wf-ui-server/__tests__/runtime-config.test.mjs +3 -3
- package/src/wf-ui-server/__tests__/runtime-detector.test.mjs +21 -0
- package/src/wf-ui-server/__tests__/runtime-review.test.mjs +828 -0
- package/src/wf-ui-server/__tests__/server.integration.test.mjs +1463 -11
- package/src/wf-ui-server/__tests__/session-cleanup.test.mjs +159 -0
- package/src/wf-ui-server/__tests__/session-registry.test.mjs +52 -3
- package/src/wf-ui-server/__tests__/settings.test.mjs +12 -2
- package/src/wf-ui-server/__tests__/spawn-gate.test.mjs +78 -0
- package/src/wf-ui-server/__tests__/task-group-parser.test.mjs +120 -0
- package/src/wf-ui-server/__tests__/task-group-tag.test.mjs +264 -0
- package/src/wf-ui-server/__tests__/task-parser.test.mjs +49 -3
- package/src/wf-ui-server/__tests__/terminal-context-hardening.test.mjs +122 -0
- package/src/wf-ui-server/__tests__/terminal-context.test.mjs +164 -0
- package/src/wf-ui-server/__tests__/terminal-store.test.mjs +4 -4
- package/src/wf-ui-server/__tests__/wf-browser-api.test.mjs +599 -0
- package/src/wf-ui-server/__tests__/wf-browser-store.test.mjs +184 -0
- package/src/wf-ui-server/__tests__/workflow-action-registry.test.mjs +282 -0
- package/src/wf-ui-server/__tests__/workflow-agent-communication.test.mjs +411 -0
- package/src/wf-ui-server/__tests__/workflow-agent-context.test.mjs +323 -0
- package/src/wf-ui-server/__tests__/workflow-agent-cooperation-permissions.test.mjs +318 -0
- package/src/wf-ui-server/__tests__/workflow-agent-messages-structured.test.mjs +458 -0
- package/src/wf-ui-server/__tests__/workflow-agent-routing.test.mjs +434 -0
- package/src/wf-ui-server/__tests__/workflow-agent-runtime.test.mjs +324 -0
- package/src/wf-ui-server/__tests__/workflow-api-integration.test.mjs +263 -0
- package/src/wf-ui-server/__tests__/workflow-api-phase3.test.mjs +1213 -0
- package/src/wf-ui-server/__tests__/workflow-claude-materialize.test.mjs +209 -0
- package/src/wf-ui-server/__tests__/workflow-cli-registry-manuals.test.mjs +173 -0
- package/src/wf-ui-server/__tests__/workflow-cli-surface.test.mjs +176 -0
- package/src/wf-ui-server/__tests__/workflow-codex-resume-id.test.mjs +556 -0
- package/src/wf-ui-server/__tests__/workflow-cooperation-enforcement.test.mjs +553 -0
- package/src/wf-ui-server/__tests__/workflow-depth-resume-dock.test.mjs +846 -0
- package/src/wf-ui-server/__tests__/workflow-display-node.test.mjs +150 -0
- package/src/wf-ui-server/__tests__/workflow-edge-update.test.mjs +296 -0
- package/src/wf-ui-server/__tests__/workflow-file-cache-lock-watch.test.mjs +380 -0
- package/src/wf-ui-server/__tests__/workflow-file-formats.test.mjs +994 -0
- package/src/wf-ui-server/__tests__/workflow-file-node-actions.test.mjs +294 -0
- package/src/wf-ui-server/__tests__/workflow-goal-actions.test.mjs +357 -0
- package/src/wf-ui-server/__tests__/workflow-goal-task-autoclose.test.mjs +256 -0
- package/src/wf-ui-server/__tests__/workflow-graceful-stop.test.mjs +108 -0
- package/src/wf-ui-server/__tests__/workflow-graph-undo.test.mjs +524 -0
- package/src/wf-ui-server/__tests__/workflow-layout.test.mjs +732 -0
- package/src/wf-ui-server/__tests__/workflow-magnetic-topology.test.mjs +222 -0
- package/src/wf-ui-server/__tests__/workflow-markdown-lock.test.mjs +359 -0
- package/src/wf-ui-server/__tests__/workflow-mcp-hub.test.mjs +174 -0
- package/src/wf-ui-server/__tests__/workflow-node-manual-schema.test.mjs +241 -0
- package/src/wf-ui-server/__tests__/workflow-node-runtime.test.mjs +1991 -0
- package/src/wf-ui-server/__tests__/workflow-node-store-utils.test.mjs +125 -0
- package/src/wf-ui-server/__tests__/workflow-registry-drift.test.mjs +296 -0
- package/src/wf-ui-server/__tests__/workflow-resource-handle-four-side.test.mjs +217 -0
- package/src/wf-ui-server/__tests__/workflow-role-profile.test.mjs +234 -0
- package/src/wf-ui-server/__tests__/workflow-set-model.test.mjs +261 -0
- package/src/wf-ui-server/__tests__/workflow-skill-group-context-enabled.test.mjs +131 -0
- package/src/wf-ui-server/__tests__/workflow-skill-group-enable-disable.test.mjs +186 -0
- package/src/wf-ui-server/__tests__/workflow-skills-hub.test.mjs +125 -0
- package/src/wf-ui-server/__tests__/workflow-state-reconcile.test.mjs +139 -0
- package/src/wf-ui-server/__tests__/workflow-subagent-strategy-matrix.test.mjs +529 -0
- package/src/wf-ui-server/__tests__/workflow-team-flow.test.mjs +278 -0
- package/src/wf-ui-server/__tests__/workflow-terminal-control-live.test.mjs +294 -0
- package/src/wf-ui-server/__tests__/workflow-terminal-control.test.mjs +631 -0
- package/src/wf-ui-server/__tests__/workflow-timer-wakeup.test.mjs +318 -0
- package/src/wf-ui-server/__tests__/workflow-unified-resume.test.mjs +537 -0
- package/src/wf-ui-server/__tests__/workspace-api-hardening.test.mjs +187 -0
- package/src/wf-ui-server/__tests__/workspace-api.test.mjs +382 -0
- package/src/wf-ui-server/__tests__/workspace-reveal.test.mjs +138 -0
- package/src/wf-ui-server/__tests__/workspace-store-hardening.test.mjs +255 -0
- package/src/wf-ui-server/__tests__/workspace-store.test.mjs +208 -0
- package/src/wf-ui-server/__tests__/ws-events.integration.test.mjs +52 -25
- package/src/wf-ui-server/__tests__/ws-terminal.integration.test.mjs +12 -6
- package/src/wf-ui-server/__tests__/ws-wf-browser.integration.test.mjs +488 -0
- package/src/wf-ui-server/a2a-store.mjs +3007 -89
- package/src/wf-ui-server/action-registry.mjs +277 -0
- package/src/wf-ui-server/bridge-store.mjs +276 -0
- package/src/wf-ui-server/chat-driver.mjs +220 -0
- package/src/wf-ui-server/chat-store.mjs +109 -0
- package/src/wf-ui-server/claude-transcript-materializer.mjs +235 -0
- package/src/wf-ui-server/codex-update-prompt.mjs +53 -0
- package/src/wf-ui-server/component-node-store.mjs +689 -0
- package/src/wf-ui-server/composition-api.mjs +436 -0
- package/src/wf-ui-server/control-plane-token.mjs +17 -0
- package/src/wf-ui-server/dispatch-contract.mjs +150 -0
- package/src/wf-ui-server/drivers/claude-stream-json.mjs +371 -0
- package/src/wf-ui-server/drivers/codex-appserver.mjs +513 -0
- package/src/wf-ui-server/drivers/opencode-server.mjs +486 -0
- package/src/wf-ui-server/excalidraw-svg.mjs +141 -0
- package/src/wf-ui-server/file-format-adapters.mjs +511 -0
- package/src/wf-ui-server/file-watcher.mjs +215 -0
- package/src/wf-ui-server/graph-layout.mjs +778 -0
- package/src/wf-ui-server/harness-env.mjs +46 -0
- package/src/wf-ui-server/json-store-utils.mjs +48 -0
- package/src/wf-ui-server/model-capability.mjs +773 -0
- package/src/wf-ui-server/node-config-store.mjs +233 -0
- package/src/wf-ui-server/node-store-utils.mjs +88 -0
- package/src/wf-ui-server/peer-capsule.mjs +56 -1
- package/src/wf-ui-server/pty-adapter.mjs +513 -11
- package/src/wf-ui-server/reveal-foreground.mjs +69 -0
- package/src/wf-ui-server/runtime-detector.mjs +52 -6
- package/src/wf-ui-server/server.mjs +5613 -403
- package/src/wf-ui-server/session-cleanup.mjs +363 -0
- package/src/wf-ui-server/session-registry.mjs +179 -3
- package/src/wf-ui-server/settings.mjs +25 -0
- package/src/wf-ui-server/spawn-gate.mjs +46 -0
- package/src/wf-ui-server/task-parser.mjs +88 -3
- package/src/wf-ui-server/terminal-store.mjs +225 -11
- package/src/wf-ui-server/timer-wakeup-scheduler.mjs +226 -0
- package/src/wf-ui-server/wf-browser-store.mjs +733 -0
- package/src/wf-ui-server/workflow-agent-context.mjs +1731 -0
- package/src/wf-ui-server/workflow-capability-node-store.mjs +676 -0
- package/src/wf-ui-server/workflow-event-node-store.mjs +623 -0
- package/src/wf-ui-server/workflow-goal-node-store.mjs +328 -0
- package/src/wf-ui-server/workflow-graph-store.mjs +623 -0
- package/src/wf-ui-server/workflow-mcp-hub.mjs +286 -0
- package/src/wf-ui-server/workflow-node-runtime.mjs +1767 -0
- package/src/wf-ui-server/workflow-node-settings-store.mjs +339 -0
- package/src/wf-ui-server/workflow-node-types/agent-node.mjs +920 -0
- package/src/wf-ui-server/workflow-node-types/display-node.mjs +151 -0
- package/src/wf-ui-server/workflow-node-types/excalidraw-node.mjs +145 -0
- package/src/wf-ui-server/workflow-node-types/file-node.mjs +484 -0
- package/src/wf-ui-server/workflow-node-types/github-trigger-node.mjs +207 -0
- package/src/wf-ui-server/workflow-node-types/goal-node.mjs +491 -0
- package/src/wf-ui-server/workflow-node-types/markdown-node.mjs +225 -0
- package/src/wf-ui-server/workflow-node-types/mcp-connector-node.mjs +71 -0
- package/src/wf-ui-server/workflow-node-types/role-profile-store.mjs +191 -0
- package/src/wf-ui-server/workflow-node-types/skill-group-node.mjs +98 -0
- package/src/wf-ui-server/workflow-node-types/timer-node.mjs +607 -0
- package/src/wf-ui-server/workflow-ontology.mjs +681 -0
- package/src/wf-ui-server/workflow-operation-store.mjs +115 -0
- package/src/wf-ui-server/workflow-skills-hub.mjs +366 -0
- package/src/wf-ui-server/workflow-skills-market.mjs +723 -0
- package/src/wf-ui-server/workspace-store.mjs +951 -0
- package/src/wf-ui-server/ws-chat.mjs +299 -0
- package/src/wf-ui-server/ws-events.mjs +45 -20
- package/src/wf-ui-server/ws-terminal.mjs +165 -22
- package/src/wf-ui-server/ws-wf-browser.mjs +419 -0
- package/templates/common/.claude/agents/review-manager.md +33 -29
- package/templates/common/.claude/commands/wf-browser.md +1 -1
- package/templates/common/.claude/commands/wf-help.md +5 -3
- package/templates/common/.claude/commands/wf-init.md +44 -0
- package/templates/common/.claude/commands/wf-learn.md +34 -8
- package/templates/common/.claude/commands/wf-max.md +19 -9
- package/templates/common/.claude/commands/wf-review.md +3 -3
- package/templates/common/.claude/commands/wf-search.md +55 -0
- package/templates/common/.claude/commands/wf-task-archive.md +5 -4
- package/templates/common/.claude/commands/wf-task-list.md +6 -3
- package/templates/common/.claude/commands/wf-task-record.md +10 -2
- package/templates/common/.claude/commands/wf-ui.md +12 -5
- package/templates/common/.claude/commands/wf-update.md +4 -0
- package/templates/common/.claude/commands/wf.md +12 -1
- package/templates/common/.claude/rules/ecc/common.md +10 -1
- package/templates/common/.claude/skills/wf/SKILL.md +36 -0
- package/templates/common/.claude/skills/wf-browser/SKILL.md +427 -122
- package/templates/common/.claude/skills/wf-browser/references/BROWSER_CONTROL_PATTERNS.md +43 -0
- package/templates/common/.claude/skills/wf-init/SKILL.md +33 -0
- package/templates/common/.claude/skills/wf-learn/SKILL.md +106 -26
- package/templates/common/.claude/skills/wf-max/SKILL.md +45 -11
- package/templates/common/.claude/skills/wf-review/SKILL.md +26 -54
- package/templates/common/.claude/skills/wf-search/SKILL.md +122 -0
- package/templates/common/.claude/skills/wf-search/references/evidence-contract.md +77 -0
- package/templates/common/.claude/skills/wf-search/references/policies/compare.md +38 -0
- package/templates/common/.claude/skills/wf-search/references/policies/fact.md +39 -0
- package/templates/common/.claude/skills/wf-search/references/policies/troubleshoot.md +39 -0
- package/templates/common/.claude/skills/wf-search/references/policies/verify.md +44 -0
- package/templates/common/.claude/skills/wf-search/references/source-routing.md +40 -0
- package/templates/common/.claude/skills/wf-search/references/tool-adapters.md +38 -0
- package/templates/common/.claude/skills/wf-ui/SKILL.md +146 -12
- package/templates/common/.claude/skills/wf-update/SKILL.md +5 -1
- package/templates/common/.harness-version +188 -85
- package/templates/common/.opencode/agents/review-manager.md +31 -27
- package/templates/common/.opencode/commands/wf-browser.md +1 -1
- package/templates/common/.opencode/commands/wf-help.md +5 -3
- package/templates/common/.opencode/commands/wf-init.md +44 -0
- package/templates/common/.opencode/commands/wf-learn.md +34 -8
- package/templates/common/.opencode/commands/wf-max.md +19 -9
- package/templates/common/.opencode/commands/wf-review.md +3 -3
- package/templates/common/.opencode/commands/wf-search.md +55 -0
- package/templates/common/.opencode/commands/wf-task-archive.md +5 -7
- package/templates/common/.opencode/commands/wf-task-list.md +6 -6
- package/templates/common/.opencode/commands/wf-task-record.md +10 -5
- package/templates/common/.opencode/commands/wf-ui.md +12 -5
- package/templates/common/.opencode/commands/wf-update.md +4 -0
- package/templates/common/.opencode/commands/wf.md +12 -1
- package/templates/common/CLAUDE.md +61 -3
- package/templates/common/Harness/MEMORY.md +8 -5
- package/templates/common/Harness/README.md +14 -10
- package/templates/common/Harness/a2a/action-registry.json +4397 -0
- package/templates/common/Harness/a2a/role-graph.json +16 -3
- package/templates/common/Harness/a2a/skills/terminal-control.json +45 -1
- package/templates/common/Harness/a2a/skills/wf-ui-map.json +50 -0
- package/templates/common/Harness/a2a/skills/workflow-agent-node.json +143 -0
- package/templates/common/Harness/a2a/skills/workflow-context.json +95 -0
- package/templates/common/Harness/a2a/skills/workflow-diagram-node.json +60 -0
- package/templates/common/Harness/a2a/skills/workflow-display-node.json +69 -0
- package/templates/common/Harness/a2a/skills/workflow-file-node.json +92 -0
- package/templates/common/Harness/a2a/skills/workflow-goal-node.json +76 -0
- package/templates/common/Harness/a2a/skills/workflow-markdown-node.json +79 -0
- package/templates/common/Harness/a2a/skills/workflow-mcp-connector-node.json +59 -0
- package/templates/common/Harness/a2a/skills/workflow-node-actions.json +105 -0
- package/templates/common/Harness/a2a/skills/workflow-node-map.json +71 -0
- package/templates/common/Harness/a2a/skills/workflow-ontology.json +54 -0
- package/templates/common/Harness/a2a/skills/workflow-resource-node.json +68 -0
- package/templates/common/Harness/a2a/skills/workflow-skill-group-node.json +56 -0
- package/templates/common/Harness/a2a/skills/workflow-timer-node.json +81 -0
- package/templates/common/Harness/a2a/workflows.json +33 -0
- package/templates/common/Harness/ownership.manifest.json +263 -2
- package/templates/common/Harness/project/architecture.md +499 -0
- package/templates/common/Harness/research/README.md +20 -0
- package/templates/common/Harness/scripts/README.md +70 -6
- package/templates/common/Harness/scripts/a2a-terminal.mjs +12 -4
- package/templates/common/Harness/scripts/context-budget.mjs +7 -3
- package/templates/common/Harness/scripts/lib/memory-context.mjs +400 -0
- package/templates/common/Harness/scripts/lib/path-scope.mjs +77 -0
- package/templates/common/Harness/scripts/lib/research-policy.mjs +99 -0
- package/templates/common/Harness/scripts/lib/wf-search.mjs +189 -0
- package/templates/common/Harness/scripts/memory-context.mjs +63 -0
- package/templates/common/Harness/scripts/research-policy.mjs +27 -0
- package/templates/common/Harness/scripts/task-context.mjs +547 -0
- package/templates/common/Harness/scripts/task-group-index.mjs +242 -0
- package/templates/common/Harness/scripts/task-state.mjs +659 -95
- package/templates/common/Harness/scripts/validate-harness.mjs +70 -28
- package/templates/common/Harness/scripts/wf-auto-update-prompt.mjs +24 -0
- package/templates/common/Harness/scripts/wf-remove.mjs +10 -0
- package/templates/common/Harness/scripts/wf-search.mjs +10 -0
- package/templates/common/Harness/scripts/wf-ui-control.mjs +3144 -0
- package/templates/common/Harness/scripts/wf-update-check.mjs +274 -51
- package/templates/common/Harness/scripts/wf-update-runner.mjs +53 -16
- package/templates/common/Harness/settings.json +10 -0
- package/templates/common/Harness/specs/guides/SETUP.md +4 -3
- package/templates/common/Harness/specs/protocols/HARNESS_BRIDGE.md +429 -48
- package/templates/common/Harness/specs/protocols/MEMORY_PROTOCOL.md +24 -0
- package/templates/common/Harness/specs/protocols/TASK_ARCHIVE.md +14 -11
- package/templates/common/Harness/specs/runtime/command-surface.json +28 -0
- package/templates/common/Harness/specs/runtime/context-loading.md +6 -0
- package/templates/common/Harness/specs/runtime/dispatch.md +9 -1
- package/templates/common/Harness/specs/runtime/subagents.md +20 -5
- package/templates/common/Harness/specs/workflows/WF-AUTO-SPARK.md +19 -0
- package/templates/common/Harness/specs/workflows/WF-AUTO.md +21 -0
- package/templates/common/Harness/specs/workflows/WF-KERNEL.md +4 -2
- package/templates/common/Harness/specs/workflows/WF-MAX.md +39 -12
- package/templates/common/Harness/specs/workflows/WF-STATE.md +62 -14
- package/templates/common/Harness/specs/workflows/WF.md +32 -0
- package/templates/common/Harness/tasks/INDEX.json +7 -0
- package/templates/common/Harness/tasks/INDEX.md +12 -0
- package/templates/common/Harness/tasks/_template/PLAN.md +6 -0
- package/templates/common/Harness/tasks/_template/PROGRESS.md +5 -0
- package/templates/common/Harness/tasks/_template/STATE.json +22 -0
- package/templates/common/Harness/templates/TEST_PLAN.template.md +5 -4
- package/templates/common/Harness/templates/UI_CONTRACT.template.md +7 -5
- package/templates/common/Harness/wf-browser/README.md +69 -0
- package/templates/common/README.md +17 -0
- package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js +0 -17
- package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js.map +0 -1
- package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js +0 -7
- package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js.map +0 -1
- package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js +0 -12
- package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js.map +0 -1
- package/src/ui/dist/assets/TaskList-BN4r8s1i.js +0 -50
- package/src/ui/dist/assets/TaskList-BN4r8s1i.js.map +0 -1
- package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js +0 -74
- package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js.map +0 -1
- package/src/ui/dist/assets/WorkflowRoute-BnuhLJ6X.css +0 -1
- package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js +0 -39
- package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js.map +0 -1
- package/src/ui/dist/assets/index-BOVYWntB.js +0 -117
- package/src/ui/dist/assets/index-BOVYWntB.js.map +0 -1
- package/src/ui/dist/assets/index-DaUObq0H.css +0 -1
- package/src/ui/dist/assets/maximize-2-LNrr_rKr.js +0 -7
- package/src/ui/dist/assets/maximize-2-LNrr_rKr.js.map +0 -1
- package/src/ui/dist/assets/plus-QuTJyoT3.js +0 -7
- package/src/ui/dist/assets/plus-QuTJyoT3.js.map +0 -1
- package/src/ui/dist/assets/proxy-D0vUbds5.js.map +0 -1
- package/src/ui/dist/assets/refresh-cw-JNmExijd.js.map +0 -1
- package/src/ui/dist/assets/terminal-BBQvnOAK.js.map +0 -1
- package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js +0 -7
- package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js.map +0 -1
- package/src/ui/dist/assets/x-DoIOGAJz.js.map +0 -1
- package/src/ui/pnpm-lock.yaml +0 -1582
- package/src/ui/src/App.tsx +0 -86
- package/src/ui/src/api.ts +0 -93
- package/src/ui/src/components/AgentsRoute.tsx +0 -503
- package/src/ui/src/components/Footer.tsx +0 -69
- package/src/ui/src/components/Header.tsx +0 -175
- package/src/ui/src/components/LoadingView.tsx +0 -22
- package/src/ui/src/components/RolesRoute.tsx +0 -169
- package/src/ui/src/components/SettingsRoute.tsx +0 -166
- package/src/ui/src/components/TaskList.tsx +0 -388
- package/src/ui/src/components/TerminalDrawer.tsx +0 -611
- package/src/ui/src/components/WorkflowRoute.tsx +0 -670
- package/src/ui/src/hooks/useReducedMotion.ts +0 -17
- package/src/ui/src/hooks/useServerConnection.ts +0 -114
- package/src/ui/src/index.css +0 -281
- package/src/ui/src/main.tsx +0 -11
- package/src/ui/src/types.ts +0 -108
- /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 }
|