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,631 @@
|
|
|
1
|
+
// workflow-terminal-control.test.mjs
|
|
2
|
+
//
|
|
3
|
+
// Agent terminal control surface (AC-CTRL-001/002/004).
|
|
4
|
+
//
|
|
5
|
+
// Group A (AC-CTRL-001): submit byte sequences — the body is typed
|
|
6
|
+
// CHAR-BY-CHAR (first char synchronously, the rest at 12ms gaps) followed
|
|
7
|
+
// by exactly ONE \r (0x0D), never \n; trailing CR/CRLF is stripped before
|
|
8
|
+
// typing; an empty body submits a single \r only.
|
|
9
|
+
// Group B (AC-CTRL-001): ready gating — sessions without a tracked terminal
|
|
10
|
+
// spawn submit immediately (preserving the 409 NO_PTY contract for dead
|
|
11
|
+
// sessions); sessions WITH a tracked spawn wait for the prompt marker
|
|
12
|
+
// (❯/›) before any write; never-ready terminals still submit after the
|
|
13
|
+
// wait window.
|
|
14
|
+
// Group C (AC-CTRL-001): retry + stale timers — a failed \r write is retried
|
|
15
|
+
// exactly once; a second submit cancels the first submit's pending
|
|
16
|
+
// poll/enter timers.
|
|
17
|
+
// Group D (AC-CTRL-002): initialPrompt chain (Enter-free trigger) —
|
|
18
|
+
// POST /api/sessions carries initialPrompt into spawnPty opts; the CLI
|
|
19
|
+
// create-agent --initial-prompt lands it in the POST body (real subprocess
|
|
20
|
+
// against a recording HTTP server).
|
|
21
|
+
// Group E (AC-CTRL-004): [harness-request] envelope delivery — exact prefix
|
|
22
|
+
// format preserved; envelope delivery ready-gated like prompt submits.
|
|
23
|
+
//
|
|
24
|
+
// Pattern: in-process node:test + HTTP server on port 0, temp roots, fake
|
|
25
|
+
// PTYs (mirrors control-plane-acceptance.test.mjs). The deterministic spawn
|
|
26
|
+
// path is provided by redirecting pty-adapter.mjs to an in-test fixture via
|
|
27
|
+
// module.registerHooks (node --test runs each file in its own process, so the
|
|
28
|
+
// redirect stays local). Runtime detection is satisfied by a stub `codex`
|
|
29
|
+
// executable prepended to PATH, so POST /api/sessions reaches the spawn branch
|
|
30
|
+
// without any real PTY backend.
|
|
31
|
+
//
|
|
32
|
+
// Envelope delivery (E1/E2) follows the same typed submit semantics: the
|
|
33
|
+
// [harness-request ...] prefix + text lands char-by-char and is ready-gated
|
|
34
|
+
// like prompt submits (E2).
|
|
35
|
+
//
|
|
36
|
+
// Run: node --test src/wf-ui-server/__tests__/workflow-terminal-control.test.mjs
|
|
37
|
+
import { describe, it, beforeEach, afterEach, before, after } from 'node:test';
|
|
38
|
+
import assert from 'node:assert/strict';
|
|
39
|
+
import fs from 'node:fs';
|
|
40
|
+
import path from 'node:path';
|
|
41
|
+
import http from 'node:http';
|
|
42
|
+
import { spawn } from 'node:child_process';
|
|
43
|
+
import { registerHooks } from 'node:module';
|
|
44
|
+
import { pathToFileURL } from 'node:url';
|
|
45
|
+
import { makeHarnessTempRoot } from '../../../tests/support/temp-root.js';
|
|
46
|
+
import { SessionRegistry } from '../session-registry.mjs';
|
|
47
|
+
import { registerPtyProcess, unregisterPtyProcess } from '../ws-terminal.mjs';
|
|
48
|
+
import { listBridgeMessages } from '../bridge-store.mjs';
|
|
49
|
+
|
|
50
|
+
// ── pty-adapter fixture (deterministic spawn path) ──────────────────────────
|
|
51
|
+
// Replaces pty-adapter.mjs for this process: spawnPty records the spawn opts
|
|
52
|
+
// (D1), returns an in-memory pty whose writes are captured (A/B/C/E), and
|
|
53
|
+
// exposes the onData/onExit hooks the server wires readiness through (B2/C2).
|
|
54
|
+
const FIXTURE_SOURCE = [
|
|
55
|
+
'// Test fixture replacing pty-adapter.mjs (see workflow-terminal-control.test.mjs).',
|
|
56
|
+
'const recorder = {',
|
|
57
|
+
' spawnOpts: [],',
|
|
58
|
+
' writesBySession: new Map(),',
|
|
59
|
+
' onDataBySession: new Map(),',
|
|
60
|
+
' onExitBySession: new Map(),',
|
|
61
|
+
' reset() {',
|
|
62
|
+
' this.spawnOpts.length = 0;',
|
|
63
|
+
' this.writesBySession.clear();',
|
|
64
|
+
' this.onDataBySession.clear();',
|
|
65
|
+
' this.onExitBySession.clear();',
|
|
66
|
+
' },',
|
|
67
|
+
'};',
|
|
68
|
+
'export async function spawnPty(opts) {',
|
|
69
|
+
' recorder.spawnOpts.push(opts);',
|
|
70
|
+
' const writes = [];',
|
|
71
|
+
' recorder.writesBySession.set(opts.sessionId, writes);',
|
|
72
|
+
' if (typeof opts.onData === "function") recorder.onDataBySession.set(opts.sessionId, opts.onData);',
|
|
73
|
+
' if (typeof opts.onExit === "function") recorder.onExitBySession.set(opts.sessionId, opts.onExit);',
|
|
74
|
+
' const ptyProcess = {',
|
|
75
|
+
' pid: 42000 + recorder.spawnOpts.length,',
|
|
76
|
+
' write(data) { writes.push(String(data)); },',
|
|
77
|
+
' kill() {},',
|
|
78
|
+
' onData() {},',
|
|
79
|
+
' onExit() {},',
|
|
80
|
+
' };',
|
|
81
|
+
' return { sessionId: opts.sessionId, pid: ptyProcess.pid, ptyProcess, ptyProvider: "test-fixture" };',
|
|
82
|
+
'}',
|
|
83
|
+
'export { recorder };',
|
|
84
|
+
].join('\n');
|
|
85
|
+
|
|
86
|
+
const fixtureDir = makeHarnessTempRoot('wf-ui-ctrl-fixture-');
|
|
87
|
+
const fixturePath = path.join(fixtureDir, 'pty-adapter.mjs');
|
|
88
|
+
fs.writeFileSync(fixturePath, FIXTURE_SOURCE, 'utf8');
|
|
89
|
+
const fixtureUrl = pathToFileURL(fixturePath).href;
|
|
90
|
+
|
|
91
|
+
registerHooks({
|
|
92
|
+
resolve(specifier, context, nextResolve) {
|
|
93
|
+
if (specifier === './pty-adapter.mjs' && String(context.parentURL || '').endsWith('/src/wf-ui-server/server.mjs')) {
|
|
94
|
+
return { url: fixtureUrl, shortCircuit: true };
|
|
95
|
+
}
|
|
96
|
+
return nextResolve(specifier, context);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const { startServer, stopServer, terminalReadyForInitialInput } = await import('../server.mjs');
|
|
101
|
+
const { recorder } = await import(fixtureUrl);
|
|
102
|
+
|
|
103
|
+
// ── runtime stub ────────────────────────────────────────────────────────────
|
|
104
|
+
// A stub `codex` on PATH makes createRuntimeSession take the spawn branch
|
|
105
|
+
// (runtimeInfo.path + launchable) so trackTerminalSpawn runs for real.
|
|
106
|
+
const ORIGINAL_PATH = process.env.PATH || '';
|
|
107
|
+
let runtimeStubDir = '';
|
|
108
|
+
|
|
109
|
+
before(() => {
|
|
110
|
+
runtimeStubDir = makeHarnessTempRoot('wf-ui-ctrl-runtime-');
|
|
111
|
+
if (process.platform === 'win32') {
|
|
112
|
+
fs.writeFileSync(path.join(runtimeStubDir, 'codex.cmd'), '@echo off\r\nrem wf-ui control test stub\r\n');
|
|
113
|
+
} else {
|
|
114
|
+
const stub = path.join(runtimeStubDir, 'codex');
|
|
115
|
+
fs.writeFileSync(stub, '#!/bin/sh\n');
|
|
116
|
+
fs.chmodSync(stub, 0o755);
|
|
117
|
+
}
|
|
118
|
+
process.env.PATH = `${runtimeStubDir}${path.delimiter}${ORIGINAL_PATH}`;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
after(() => {
|
|
122
|
+
process.env.PATH = ORIGINAL_PATH;
|
|
123
|
+
for (const dir of [runtimeStubDir, fixtureDir]) {
|
|
124
|
+
try { fs.rmSync(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }); } catch { /* best effort */ }
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// ── HTTP helper ──
|
|
129
|
+
function jsonRequest(baseUrl, route, { method = 'GET', body, token = '' } = {}) {
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
const url = new URL(route, baseUrl);
|
|
132
|
+
const payload = body ? JSON.stringify(body) : null;
|
|
133
|
+
const req = http.request({
|
|
134
|
+
hostname: url.hostname,
|
|
135
|
+
port: url.port,
|
|
136
|
+
path: `${url.pathname}${url.search}`,
|
|
137
|
+
method,
|
|
138
|
+
headers: {
|
|
139
|
+
...(payload ? { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } : {}),
|
|
140
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
141
|
+
},
|
|
142
|
+
}, (res) => {
|
|
143
|
+
let data = '';
|
|
144
|
+
res.on('data', chunk => { data += chunk; });
|
|
145
|
+
res.on('end', () => {
|
|
146
|
+
try { resolve({ status: res.statusCode, body: JSON.parse(data) }); }
|
|
147
|
+
catch { resolve({ status: res.statusCode, body: data }); }
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
req.on('error', reject);
|
|
151
|
+
if (payload) req.write(payload);
|
|
152
|
+
req.end();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Project seeding + suite helpers ──
|
|
157
|
+
function seedRoot(prefix) {
|
|
158
|
+
const root = makeHarnessTempRoot(prefix);
|
|
159
|
+
fs.mkdirSync(path.join(root, 'Harness', 'tasks'), { recursive: true });
|
|
160
|
+
fs.mkdirSync(path.join(root, 'Harness', 'a2a'), { recursive: true });
|
|
161
|
+
return root;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function waitFor(fn, { timeout = 5000, step = 25 } = {}) {
|
|
165
|
+
const deadline = Date.now() + timeout;
|
|
166
|
+
let last;
|
|
167
|
+
while (Date.now() < deadline) {
|
|
168
|
+
last = await fn();
|
|
169
|
+
if (last) return last;
|
|
170
|
+
await new Promise(resolve => setTimeout(resolve, step));
|
|
171
|
+
}
|
|
172
|
+
throw new Error(`waitFor timed out; last=${JSON.stringify(last)}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function sleep(ms) {
|
|
176
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// The one true submit sequence for typed delivery: the body lands CHAR-BY-CHAR
|
|
180
|
+
// (first char synchronously, the rest at PROMPT_TYPING_CHAR_DELAY_MS gaps),
|
|
181
|
+
// then exactly one \r (0x0D) as its own final write, and no \n anywhere in the
|
|
182
|
+
// injected bytes.
|
|
183
|
+
function assertTypedSubmitSequence(writes, body) {
|
|
184
|
+
const joined = writes.join('');
|
|
185
|
+
assert.equal(joined.includes('\n'), false, `no \\n may be injected: ${JSON.stringify(writes)}`);
|
|
186
|
+
assert.ok(joined.endsWith('\r'), `sequence must end with the single \\r: ${JSON.stringify(writes)}`);
|
|
187
|
+
assert.equal(writes[writes.length - 1], '\r', `the \\r must arrive as its own single-byte write: ${JSON.stringify(writes)}`);
|
|
188
|
+
assert.equal(joined.slice(0, -1), body, `the typed chars must join to the exact body: ${JSON.stringify(writes)}`);
|
|
189
|
+
if (body) {
|
|
190
|
+
assert.equal(writes[0], body[0], `the first char must be the first write (synchronous): ${JSON.stringify(writes)}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Spawn a real `node Harness/scripts/wf-ui-control.mjs <command>` subprocess
|
|
195
|
+
// (same runner as control-plane-cli-smoke.test.mjs).
|
|
196
|
+
function runWfUi(args, { cwd, env = {}, timeout = 15000 } = {}) {
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
const script = path.join(cwd, 'Harness', 'scripts', 'wf-ui-control.mjs');
|
|
199
|
+
const child = spawn(process.execPath, [script, ...args], {
|
|
200
|
+
cwd,
|
|
201
|
+
env: { ...process.env, ...env },
|
|
202
|
+
windowsHide: true,
|
|
203
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
204
|
+
});
|
|
205
|
+
let stdout = '';
|
|
206
|
+
let stderr = '';
|
|
207
|
+
const timer = setTimeout(() => {
|
|
208
|
+
child.kill();
|
|
209
|
+
reject(new Error(`wf-ui-control timeout: ${args.join(' ')}`));
|
|
210
|
+
}, timeout);
|
|
211
|
+
child.stdout.on('data', chunk => { stdout += chunk; });
|
|
212
|
+
child.stderr.on('data', chunk => { stderr += chunk; });
|
|
213
|
+
child.on('error', reject);
|
|
214
|
+
child.on('close', (status) => {
|
|
215
|
+
clearTimeout(timer);
|
|
216
|
+
let parsed = stdout.trim();
|
|
217
|
+
try { parsed = JSON.parse(parsed); } catch { /* raw text */ }
|
|
218
|
+
resolve({ status, stdout: parsed, stderr });
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ── Suite ──
|
|
224
|
+
describe('Agent Terminal Control Surface (AC-CTRL-001/002/004)', () => {
|
|
225
|
+
let root;
|
|
226
|
+
let registry;
|
|
227
|
+
let server;
|
|
228
|
+
let baseUrl;
|
|
229
|
+
const registeredPties = [];
|
|
230
|
+
|
|
231
|
+
beforeEach(async () => {
|
|
232
|
+
recorder.reset();
|
|
233
|
+
root = seedRoot('wf-ctrl-');
|
|
234
|
+
registry = new SessionRegistry();
|
|
235
|
+
const started = await startServer({
|
|
236
|
+
projectRoot: root,
|
|
237
|
+
host: '127.0.0.1',
|
|
238
|
+
port: 0,
|
|
239
|
+
sessionRegistry: registry,
|
|
240
|
+
eventsWs: false,
|
|
241
|
+
});
|
|
242
|
+
server = started.server;
|
|
243
|
+
baseUrl = `http://127.0.0.1:${started.port}`;
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
afterEach(async () => {
|
|
247
|
+
for (const sessionId of registeredPties.splice(0)) {
|
|
248
|
+
unregisterPtyProcess(sessionId);
|
|
249
|
+
}
|
|
250
|
+
if (server) {
|
|
251
|
+
await stopServer(server);
|
|
252
|
+
server = null;
|
|
253
|
+
}
|
|
254
|
+
if (root) {
|
|
255
|
+
fs.rmSync(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
256
|
+
root = null;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// ── Suite-local helpers ──
|
|
261
|
+
function registerPty(sessionId, writes) {
|
|
262
|
+
registerPtyProcess(sessionId, { write: data => writes.push(String(data)) });
|
|
263
|
+
registeredPties.push(sessionId);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Untracked session (deferPtySpawn): no tracked spawn, no readiness gating.
|
|
267
|
+
async function createAgentViaApi(overrides = {}) {
|
|
268
|
+
const res = await jsonRequest(baseUrl, '/api/sessions', {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
body: {
|
|
271
|
+
runtime: 'claude',
|
|
272
|
+
agentKind: 'subagent',
|
|
273
|
+
role: 'Subagent',
|
|
274
|
+
roleTitle: 'implementer',
|
|
275
|
+
displayName: 'implementer',
|
|
276
|
+
responsibility: 'terminal control test agent',
|
|
277
|
+
capabilities: ['terminal'],
|
|
278
|
+
objective: 'Terminal control acceptance agent',
|
|
279
|
+
attachGraphNode: true,
|
|
280
|
+
deferPtySpawn: true,
|
|
281
|
+
...overrides,
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
assert.equal(res.status, 201, JSON.stringify(res.body));
|
|
285
|
+
return { sessionId: res.body.sessionId, nodeId: `session-${res.body.sessionId}`, body: res.body };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Tracked session (real spawn branch through the pty-adapter fixture):
|
|
289
|
+
// trackTerminalSpawn records it and readiness is gated until the fixture's
|
|
290
|
+
// onData callback delivers a prompt marker.
|
|
291
|
+
async function createSpawnedAgent(overrides = {}) {
|
|
292
|
+
const agent = await createAgentViaApi({ runtime: 'codex', deferPtySpawn: false, ...overrides });
|
|
293
|
+
assert.equal(agent.body.status, 'running', JSON.stringify(agent.body));
|
|
294
|
+
registeredPties.push(agent.sessionId);
|
|
295
|
+
return agent;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async function connectDelegation(fromNodeId, toNodeId) {
|
|
299
|
+
const res = await jsonRequest(baseUrl, '/api/workflow/edges', {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
body: { from: fromNodeId, to: toNodeId, relation: 'delegation', direction: 'bidirectional' },
|
|
302
|
+
});
|
|
303
|
+
assert.equal(res.status, 201, JSON.stringify(res.body));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function submitInput(sessionId, data) {
|
|
307
|
+
return jsonRequest(baseUrl, `/api/sessions/${sessionId}/input`, {
|
|
308
|
+
method: 'POST',
|
|
309
|
+
body: { data, submit: true },
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ══════════════════════════════════════════════════════════════════
|
|
314
|
+
// Group A: submit byte sequences (AC-CTRL-001)
|
|
315
|
+
// ══════════════════════════════════════════════════════════════════
|
|
316
|
+
it('A1 - submit types the body char-by-char then exactly one \\r (0x0D), never \\n', async () => {
|
|
317
|
+
const agent = await createAgentViaApi();
|
|
318
|
+
const writes = [];
|
|
319
|
+
registerPty(agent.sessionId, writes);
|
|
320
|
+
|
|
321
|
+
const res = await submitInput(agent.sessionId, 'echo hello');
|
|
322
|
+
assert.equal(res.status, 200, JSON.stringify(res.body));
|
|
323
|
+
assert.equal(res.body.ok, true);
|
|
324
|
+
assert.equal(writes[0], 'e', 'the first char must be written synchronously on submit; the rest are typed');
|
|
325
|
+
|
|
326
|
+
// 10 chars: 9 × 12ms typing + 800ms before the enter lands.
|
|
327
|
+
await waitFor(() => (writes.join('') === 'echo hello\r' ? writes : null), { timeout: 5000 });
|
|
328
|
+
assertTypedSubmitSequence(writes, 'echo hello');
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('A2 - trailing CR/CRLF is stripped from the body before write', async () => {
|
|
332
|
+
const agent = await createAgentViaApi();
|
|
333
|
+
const writes = [];
|
|
334
|
+
registerPty(agent.sessionId, writes);
|
|
335
|
+
|
|
336
|
+
const res = await submitInput(agent.sessionId, 'echo hello\r\n');
|
|
337
|
+
assert.equal(res.status, 200, JSON.stringify(res.body));
|
|
338
|
+
assert.equal(writes[0], 'e', 'the stripped body must start typing synchronously');
|
|
339
|
+
await waitFor(() => (writes.join('') === 'echo hello\r' ? writes : null), { timeout: 5000 });
|
|
340
|
+
assertTypedSubmitSequence(writes, 'echo hello');
|
|
341
|
+
|
|
342
|
+
// CR-only trailing is stripped too.
|
|
343
|
+
const agent2 = await createAgentViaApi();
|
|
344
|
+
const writes2 = [];
|
|
345
|
+
registerPty(agent2.sessionId, writes2);
|
|
346
|
+
await submitInput(agent2.sessionId, 'list files\r');
|
|
347
|
+
assert.equal(writes2[0], 'l', 'the stripped CR-only body must start typing synchronously');
|
|
348
|
+
await waitFor(() => (writes2.join('') === 'list files\r' ? writes2 : null), { timeout: 5000 });
|
|
349
|
+
assertTypedSubmitSequence(writes2, 'list files');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('A3 - empty body + submit injects a single \\r only', async () => {
|
|
353
|
+
const agent = await createAgentViaApi();
|
|
354
|
+
const writes = [];
|
|
355
|
+
registerPty(agent.sessionId, writes);
|
|
356
|
+
|
|
357
|
+
const res = await submitInput(agent.sessionId, '');
|
|
358
|
+
assert.equal(res.status, 200, JSON.stringify(res.body));
|
|
359
|
+
await waitFor(() => (writes.length === 1 ? writes : null));
|
|
360
|
+
assert.equal(writes.length, 1, JSON.stringify(writes));
|
|
361
|
+
assert.equal(writes[0], '\r', 'an empty submit must inject exactly one \\r and no body');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// ══════════════════════════════════════════════════════════════════
|
|
365
|
+
// Group B: ready gating (AC-CTRL-001)
|
|
366
|
+
// ══════════════════════════════════════════════════════════════════
|
|
367
|
+
it('B0 - prompt-marker readiness detector contract (❯/›)', () => {
|
|
368
|
+
assert.equal(terminalReadyForInitialInput('Codex › ready', 'codex'), true);
|
|
369
|
+
assert.equal(terminalReadyForInitialInput('Codex ❯', 'codex'), true);
|
|
370
|
+
assert.equal(terminalReadyForInitialInput('Codex booting...', 'codex'), false);
|
|
371
|
+
assert.equal(terminalReadyForInitialInput('Claude Code 2.0.1 — ❯', 'claude'), true);
|
|
372
|
+
assert.equal(terminalReadyForInitialInput('Claude Code 2.0.1', 'claude'), false);
|
|
373
|
+
assert.equal(terminalReadyForInitialInput('❯', ''), true);
|
|
374
|
+
assert.equal(terminalReadyForInitialInput('', 'codex'), false);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('B1a - session WITHOUT tracked spawn keeps the 409 NO_PTY contract (no polling wait)', async () => {
|
|
378
|
+
const agent = await createAgentViaApi(); // blocked; no PTY registered
|
|
379
|
+
const res = await submitInput(agent.sessionId, 'dead session');
|
|
380
|
+
assert.equal(res.status, 409, JSON.stringify(res.body));
|
|
381
|
+
assert.equal(res.body.error.code, 'NO_PTY');
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('B1b - session WITHOUT tracked spawn submits immediately (no polling delay)', async () => {
|
|
385
|
+
const agent = await createAgentViaApi();
|
|
386
|
+
const writes = [];
|
|
387
|
+
registerPty(agent.sessionId, writes);
|
|
388
|
+
|
|
389
|
+
const res = await submitInput(agent.sessionId, 'B1b immediate');
|
|
390
|
+
assert.equal(res.status, 200, JSON.stringify(res.body));
|
|
391
|
+
assert.equal(writes[0], 'B', 'untracked sessions must type the first char synchronously — no gate');
|
|
392
|
+
await waitFor(() => (writes.join('') === 'B1b immediate\r' ? writes : null), { timeout: 5000 });
|
|
393
|
+
assertTypedSubmitSequence(writes, 'B1b immediate');
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('B2 - tracked spawn waits for the ready marker; nothing is written before it', async () => {
|
|
397
|
+
const agent = await createSpawnedAgent();
|
|
398
|
+
const writes = recorder.writesBySession.get(agent.sessionId);
|
|
399
|
+
assert.ok(writes, 'spawn fixture must register the session writes');
|
|
400
|
+
|
|
401
|
+
const res = await submitInput(agent.sessionId, 'B2 gated task');
|
|
402
|
+
assert.equal(res.status, 200, JSON.stringify(res.body));
|
|
403
|
+
assert.equal(res.body.ok, true);
|
|
404
|
+
assert.deepEqual(writes, [], 'ready-gated submit must not write before the marker is observed');
|
|
405
|
+
|
|
406
|
+
await sleep(700); // spans several 250ms poll cycles
|
|
407
|
+
assert.deepEqual(writes, [], 'poll must keep waiting while the prompt marker is missing');
|
|
408
|
+
|
|
409
|
+
const onData = recorder.onDataBySession.get(agent.sessionId);
|
|
410
|
+
assert.equal(typeof onData, 'function', 'spawn fixture must expose the onData hook');
|
|
411
|
+
onData('Codex › ready');
|
|
412
|
+
// 13 chars: 12 × 12ms typing + 800ms before the enter.
|
|
413
|
+
await waitFor(() => (writes.join('') === 'B2 gated task\r' ? writes : null), { timeout: 5000 });
|
|
414
|
+
assertTypedSubmitSequence(writes, 'B2 gated task');
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('B3 - never-ready tracked spawn still submits after the wait window', async () => {
|
|
418
|
+
const agent = await createSpawnedAgent();
|
|
419
|
+
const writes = recorder.writesBySession.get(agent.sessionId);
|
|
420
|
+
|
|
421
|
+
const res = await submitInput(agent.sessionId, 'B3 fallback task');
|
|
422
|
+
assert.equal(res.status, 200, JSON.stringify(res.body));
|
|
423
|
+
assert.deepEqual(writes, [], 'no write while not ready');
|
|
424
|
+
|
|
425
|
+
// The readiness wait window is 10s (poll 250ms), then the body is typed
|
|
426
|
+
// (15 × 12ms) and the enter fires 800ms after the last char. Never feed a
|
|
427
|
+
// ready marker: the fallback must still submit once the window elapses.
|
|
428
|
+
await waitFor(() => (writes.join('') === 'B3 fallback task\r' ? writes : null), { timeout: 16000 });
|
|
429
|
+
assertTypedSubmitSequence(writes, 'B3 fallback task');
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// ══════════════════════════════════════════════════════════════════
|
|
433
|
+
// Group C: retry + stale timers (AC-CTRL-001)
|
|
434
|
+
// ══════════════════════════════════════════════════════════════════
|
|
435
|
+
it('C1 - a failed \\r write is retried exactly once', async () => {
|
|
436
|
+
const agent = await createAgentViaApi();
|
|
437
|
+
const writes = [];
|
|
438
|
+
let accessCount = 0;
|
|
439
|
+
const realWrite = data => writes.push(String(data));
|
|
440
|
+
// writePtyInput checks `typeof pty.write === 'function'` before calling.
|
|
441
|
+
// Access map for the typed flow on 'C1 retry body' (14 chars):
|
|
442
|
+
// accesses 1-2: typeof+call for the synchronous first char,
|
|
443
|
+
// accesses 3-28: typeof+call for chars 2..14 (12ms gaps),
|
|
444
|
+
// access 29: typeof for the FIRST enter -> pretend the write channel is
|
|
445
|
+
// missing once, so writePtyInput returns false and the server retries
|
|
446
|
+
// the enter 800ms later (access 30: typeof, access 31: call -> \r).
|
|
447
|
+
const pty = {
|
|
448
|
+
pid: 4242,
|
|
449
|
+
kill() {},
|
|
450
|
+
onData() {},
|
|
451
|
+
onExit() {},
|
|
452
|
+
get write() {
|
|
453
|
+
accessCount += 1;
|
|
454
|
+
return accessCount === 2 * 'C1 retry body'.length + 1 ? undefined : realWrite;
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
registerPtyProcess(agent.sessionId, pty);
|
|
458
|
+
registeredPties.push(agent.sessionId);
|
|
459
|
+
|
|
460
|
+
const res = await submitInput(agent.sessionId, 'C1 retry body');
|
|
461
|
+
assert.equal(res.status, 200, JSON.stringify(res.body));
|
|
462
|
+
assert.equal(writes[0], 'C', 'the first char must be written synchronously');
|
|
463
|
+
|
|
464
|
+
// All 14 chars land by ~156ms; the first enter attempt fails at >=956ms;
|
|
465
|
+
// the retry cannot fire before >=1756ms. At 1200ms the write list must
|
|
466
|
+
// still hold only the typed body — this is what proves the retry path (a
|
|
467
|
+
// successful first enter would already have pushed the \r here).
|
|
468
|
+
await sleep(1200);
|
|
469
|
+
assert.equal(writes.join(''), 'C1 retry body', 'first enter must fail without writing, retry still pending');
|
|
470
|
+
assert.equal(writes.includes('\r'), false, 'no \\r may land before the retry fires');
|
|
471
|
+
|
|
472
|
+
await waitFor(() => (writes.join('') === 'C1 retry body\r' ? writes : null), { timeout: 5000 });
|
|
473
|
+
assertTypedSubmitSequence(writes, 'C1 retry body');
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('C2 - a second submit cancels the first submit pending timers', async () => {
|
|
477
|
+
const agent = await createSpawnedAgent();
|
|
478
|
+
const writes = recorder.writesBySession.get(agent.sessionId);
|
|
479
|
+
|
|
480
|
+
const first = await submitInput(agent.sessionId, 'first');
|
|
481
|
+
assert.equal(first.status, 200, JSON.stringify(first.body));
|
|
482
|
+
assert.deepEqual(writes, [], 'first submit is gated: nothing written yet');
|
|
483
|
+
|
|
484
|
+
const second = await submitInput(agent.sessionId, 'second');
|
|
485
|
+
assert.equal(second.status, 200, JSON.stringify(second.body));
|
|
486
|
+
|
|
487
|
+
const onData = recorder.onDataBySession.get(agent.sessionId);
|
|
488
|
+
onData('Codex › ready');
|
|
489
|
+
// 'second' = 6 chars: 5 × 12ms typing + 800ms before the enter.
|
|
490
|
+
await waitFor(() => (writes.join('') === 'second\r' ? writes : null), { timeout: 5000 });
|
|
491
|
+
await sleep(300); // let any stale first-submit char land, if cancellation failed
|
|
492
|
+
assert.equal(writes.join(''), 'second\r', 'only the second submit may land; the first must be cancelled');
|
|
493
|
+
assertTypedSubmitSequence(writes, 'second');
|
|
494
|
+
assert.ok(!writes.join('').includes('first'), `first submit body must never be written: ${JSON.stringify(writes)}`);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// ══════════════════════════════════════════════════════════════════
|
|
498
|
+
// Group D: initialPrompt chain (AC-CTRL-002, Enter-free trigger)
|
|
499
|
+
// ══════════════════════════════════════════════════════════════════
|
|
500
|
+
it('D1 - POST /api/sessions initialPrompt reaches spawnPty opts', async () => {
|
|
501
|
+
const created = await createSpawnedAgent({
|
|
502
|
+
agentKind: 'main',
|
|
503
|
+
role: 'Main Agent',
|
|
504
|
+
roleTitle: 'ceo',
|
|
505
|
+
initialPrompt: 'D1 initial task via API',
|
|
506
|
+
});
|
|
507
|
+
const opts = recorder.spawnOpts[recorder.spawnOpts.length - 1];
|
|
508
|
+
assert.ok(opts, 'spawn fixture must record the spawn');
|
|
509
|
+
assert.equal(opts.initialPrompt, 'D1 initial task via API', 'spawn must carry the initialPrompt argv');
|
|
510
|
+
assert.equal(opts.runtime, 'codex');
|
|
511
|
+
assert.equal(opts.sessionId, created.sessionId);
|
|
512
|
+
assert.ok(opts.launchPolicy, 'spawn must carry the launch policy');
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
it('D2 - CLI create-agent --initial-prompt lands initialPrompt in the POST body', async () => {
|
|
516
|
+
// Real subprocess against a recording HTTP server: the CLI posts to it,
|
|
517
|
+
// the server captures the request body and returns a fake session.
|
|
518
|
+
const captured = [];
|
|
519
|
+
const recording = http.createServer((req, res) => {
|
|
520
|
+
let body = '';
|
|
521
|
+
req.on('data', chunk => { body += chunk; });
|
|
522
|
+
req.on('end', () => {
|
|
523
|
+
captured.push({ method: req.method, url: req.url, body: body ? JSON.parse(body) : null });
|
|
524
|
+
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
525
|
+
res.end(JSON.stringify({ sessionId: 'd2-fake-session', status: 'running', ok: true }));
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
await new Promise(resolve => recording.listen(0, '127.0.0.1', resolve));
|
|
529
|
+
const port = recording.address().port;
|
|
530
|
+
try {
|
|
531
|
+
const cliRoot = seedRoot('wf-ctrl-cli-');
|
|
532
|
+
try {
|
|
533
|
+
const scriptDest = path.join(cliRoot, 'Harness', 'scripts', 'wf-ui-control.mjs');
|
|
534
|
+
fs.mkdirSync(path.dirname(scriptDest), { recursive: true });
|
|
535
|
+
fs.copyFileSync(path.join(process.cwd(), 'Harness', 'scripts', 'wf-ui-control.mjs'), scriptDest);
|
|
536
|
+
const run = await runWfUi([
|
|
537
|
+
'create-agent',
|
|
538
|
+
'--project', cliRoot,
|
|
539
|
+
'--url', `http://127.0.0.1:${port}`,
|
|
540
|
+
'--token', 'd2-token',
|
|
541
|
+
'--actor-kind', 'main',
|
|
542
|
+
'--initial-prompt', 'D2 initial task from CLI',
|
|
543
|
+
], { cwd: cliRoot });
|
|
544
|
+
assert.equal(run.status, 0, run.stderr);
|
|
545
|
+
assert.equal(run.stdout.sessionId, 'd2-fake-session', JSON.stringify(run.stdout));
|
|
546
|
+
assert.equal(captured.length, 1, JSON.stringify(captured));
|
|
547
|
+
assert.equal(captured[0].method, 'POST');
|
|
548
|
+
assert.ok(captured[0].url.startsWith('/api/sessions'), captured[0].url);
|
|
549
|
+
assert.equal(captured[0].body.initialPrompt, 'D2 initial task from CLI');
|
|
550
|
+
assert.equal(captured[0].body.runtime, 'claude', 'CLI defaults to the claude runtime');
|
|
551
|
+
assert.equal(captured[0].body.agentKind, 'subagent', 'CLI defaults to subagent kind');
|
|
552
|
+
} finally {
|
|
553
|
+
fs.rmSync(cliRoot, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
554
|
+
}
|
|
555
|
+
} finally {
|
|
556
|
+
recording.closeAllConnections?.();
|
|
557
|
+
await new Promise(resolve => recording.close(resolve));
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
// ══════════════════════════════════════════════════════════════════
|
|
562
|
+
// Group E: [harness-request] envelope delivery (AC-CTRL-004)
|
|
563
|
+
// ══════════════════════════════════════════════════════════════════
|
|
564
|
+
it('E1 - [harness-request] envelope keeps the exact format prefix', async () => {
|
|
565
|
+
const sender = await createAgentViaApi({ agentKind: 'main', role: 'Main Agent', roleTitle: 'ceo' });
|
|
566
|
+
const target = await createAgentViaApi();
|
|
567
|
+
const writes = [];
|
|
568
|
+
registerPty(target.sessionId, writes);
|
|
569
|
+
await connectDelegation(sender.nodeId, target.nodeId);
|
|
570
|
+
|
|
571
|
+
const sent = await jsonRequest(baseUrl, `/api/workflow/nodes/${sender.nodeId}/actions/agent.sendMessage`, {
|
|
572
|
+
method: 'POST',
|
|
573
|
+
body: { to: target.nodeId, text: 'STRUCTURED_E1', requestId: 'req-e1-1', toRole: 'implementer' },
|
|
574
|
+
});
|
|
575
|
+
assert.equal(sent.status, 200, JSON.stringify(sent.body));
|
|
576
|
+
assert.equal(sent.body.result.mode, 'direct');
|
|
577
|
+
assert.equal(sent.body.result.deliveries[0].ok, true);
|
|
578
|
+
|
|
579
|
+
// Envelope delivered like a prompt submit: prefix + body typed char-by-char
|
|
580
|
+
// (first char synchronously), then a single \r. The joined sequence must
|
|
581
|
+
// keep the exact prefix format.
|
|
582
|
+
const expectJoined1 = '[harness-request req-e1-1 to-role=implementer] STRUCTURED_E1\r';
|
|
583
|
+
assert.equal(writes[0], '[', 'envelope typing must start with the first prefix char synchronously');
|
|
584
|
+
await waitFor(() => (writes.join('') === expectJoined1 ? expectJoined1 : null), { timeout: 8000 });
|
|
585
|
+
assert.equal(writes.join(''), expectJoined1);
|
|
586
|
+
assert.equal(writes.join('').includes('\n'), false);
|
|
587
|
+
assert.equal(writes[writes.length - 1], '\r', 'the delivered sequence must end with the single \\r');
|
|
588
|
+
assert.equal(writes.filter(w => w === '\r').length, 1, 'exactly one \\r (0x0D) in the delivered sequence');
|
|
589
|
+
|
|
590
|
+
const bridge = listBridgeMessages(root, { fromSessionId: sender.sessionId, toSessionId: target.sessionId });
|
|
591
|
+
assert.equal(bridge.entries.length, 1);
|
|
592
|
+
assert.equal(bridge.entries[0].data.replace(/\r$/, ''), 'STRUCTURED_E1');
|
|
593
|
+
|
|
594
|
+
// Full envelope form with contextRefs.
|
|
595
|
+
const sent2 = await jsonRequest(baseUrl, `/api/workflow/nodes/${sender.nodeId}/actions/agent.sendMessage`, {
|
|
596
|
+
method: 'POST',
|
|
597
|
+
body: { to: target.nodeId, text: 'DO_E1_2', requestId: 'req-e1-2', toRole: 'reviewer', contextRefs: ['md-x1'] },
|
|
598
|
+
});
|
|
599
|
+
assert.equal(sent2.status, 200, JSON.stringify(sent2.body));
|
|
600
|
+
const expectJoined2 = expectJoined1 + '[harness-request req-e1-2 to-role=reviewer contextRefs=md-x1] DO_E1_2\r';
|
|
601
|
+
await waitFor(() => (writes.join('') === expectJoined2 ? expectJoined2 : null), { timeout: 8000 });
|
|
602
|
+
assert.equal(writes.join(''), expectJoined2);
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
it('E2 - envelope delivery is ready-gated like prompt submits (no write before ready)', async () => {
|
|
606
|
+
const sender = await createAgentViaApi({ agentKind: 'main', role: 'Main Agent', roleTitle: 'ceo' });
|
|
607
|
+
const target = await createSpawnedAgent();
|
|
608
|
+
const writes = recorder.writesBySession.get(target.sessionId);
|
|
609
|
+
await connectDelegation(sender.nodeId, target.nodeId);
|
|
610
|
+
|
|
611
|
+
const sent = await jsonRequest(baseUrl, `/api/workflow/nodes/${sender.nodeId}/actions/agent.sendMessage`, {
|
|
612
|
+
method: 'POST',
|
|
613
|
+
body: { to: target.nodeId, text: 'STRUCTURED_E2', requestId: 'req-e2-1', toRole: 'implementer' },
|
|
614
|
+
});
|
|
615
|
+
assert.equal(sent.status, 200, JSON.stringify(sent.body));
|
|
616
|
+
// EXPECTED RED until delivery is routed through the ready gate: the
|
|
617
|
+
// envelope must not reach the PTY before the prompt marker was observed.
|
|
618
|
+
assert.deepEqual(writes, [], 'no envelope write before the ready marker');
|
|
619
|
+
|
|
620
|
+
const onData = recorder.onDataBySession.get(target.sessionId);
|
|
621
|
+
onData('Codex › ready');
|
|
622
|
+
const expectJoined = '[harness-request req-e2-1 to-role=implementer] STRUCTURED_E2\r';
|
|
623
|
+
await waitFor(() => (writes.join('') === expectJoined ? expectJoined : null), { timeout: 5000 });
|
|
624
|
+
assert.equal(writes.join(''), expectJoined);
|
|
625
|
+
assert.equal((writes.join('').match(/\r/g) || []).length, 1, 'exactly one \\r in the delivered envelope');
|
|
626
|
+
|
|
627
|
+
const bridge = listBridgeMessages(root, { fromSessionId: sender.sessionId, toSessionId: target.sessionId });
|
|
628
|
+
assert.equal(bridge.entries.length, 1);
|
|
629
|
+
assert.equal(bridge.entries[0].data.replace(/\r$/, ''), 'STRUCTURED_E2', 'bridge data stays the plain text body');
|
|
630
|
+
});
|
|
631
|
+
});
|