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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
4
5
|
|
|
5
6
|
const root = process.cwd();
|
|
6
7
|
const harnessDir = path.join(root, 'Harness');
|
|
@@ -13,15 +14,15 @@ const command = args[0] && !args[0].startsWith('--') ? args[0] : 'help';
|
|
|
13
14
|
const OUTER_TASK_CAP = 5;
|
|
14
15
|
const RESERVED = new Set(['_template', '_archive', 'continuous']);
|
|
15
16
|
const TASK_ID_RE = /^task-[a-z]+(-[a-z0-9]+){1,4}$/;
|
|
17
|
+
const CANONICAL_STATUSES = new Set(['active', 'blocked', 'closed']);
|
|
16
18
|
const NEVER_ARCHIVE_STATUSES = new Set([
|
|
17
19
|
'active',
|
|
18
20
|
'blocked',
|
|
19
|
-
'in_progress',
|
|
20
|
-
'running',
|
|
21
|
-
'pending',
|
|
22
|
-
'needs-user-decision',
|
|
23
21
|
]);
|
|
24
22
|
const SAFE_ARCHIVE_STATUSES = new Set([
|
|
23
|
+
'closed',
|
|
24
|
+
// Legacy values are retained for archive compatibility. New writes use
|
|
25
|
+
// the canonical lifecycle statuses above.
|
|
25
26
|
'complete',
|
|
26
27
|
'verified',
|
|
27
28
|
'archived',
|
|
@@ -32,8 +33,13 @@ const SAFE_ARCHIVE_STATUSES = new Set([
|
|
|
32
33
|
'closeout',
|
|
33
34
|
]);
|
|
34
35
|
const VALID_STATUSES = new Set([
|
|
36
|
+
...CANONICAL_STATUSES,
|
|
35
37
|
...NEVER_ARCHIVE_STATUSES,
|
|
36
38
|
...SAFE_ARCHIVE_STATUSES,
|
|
39
|
+
'in_progress',
|
|
40
|
+
'running',
|
|
41
|
+
'pending',
|
|
42
|
+
'needs-user-decision',
|
|
37
43
|
'skipped',
|
|
38
44
|
'failed',
|
|
39
45
|
]);
|
|
@@ -64,15 +70,31 @@ const PHASE_ALIASES = new Map([
|
|
|
64
70
|
['closed', 'closeout'],
|
|
65
71
|
]);
|
|
66
72
|
const STATUS_ALIASES = new Map([
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
['
|
|
70
|
-
['
|
|
71
|
-
['
|
|
72
|
-
['
|
|
73
|
+
// Legacy values intentionally normalize to the smaller lifecycle. The raw
|
|
74
|
+
// value remains available to archive/history code when needed.
|
|
75
|
+
['in-progress', 'active'],
|
|
76
|
+
['inprogress', 'active'],
|
|
77
|
+
['in_progress', 'active'],
|
|
78
|
+
['running', 'active'],
|
|
79
|
+
['pending', 'active'],
|
|
80
|
+
['needs_user_decision', 'blocked'],
|
|
81
|
+
['needs-user-decision', 'blocked'],
|
|
82
|
+
['needs-user', 'blocked'],
|
|
83
|
+
['need-user-decision', 'blocked'],
|
|
84
|
+
['complete', 'closed'],
|
|
85
|
+
['completed', 'closed'],
|
|
86
|
+
['verified', 'closed'],
|
|
87
|
+
['archived', 'closed'],
|
|
88
|
+
['abandoned', 'closed'],
|
|
89
|
+
['obsolete', 'closed'],
|
|
90
|
+
['done', 'closed'],
|
|
91
|
+
['closeout', 'closed'],
|
|
92
|
+
['skipped', 'closed'],
|
|
93
|
+
['failed', 'blocked'],
|
|
94
|
+
['close-out', 'closed'],
|
|
73
95
|
]);
|
|
74
|
-
const OPEN_TASK_STATUSES = new Set(['active', 'blocked'
|
|
75
|
-
const VALUE_FLAGS = new Set(['--keep', '--mode', '--phase', '--status', '--task', '--text', '--title', '--note', '--context']);
|
|
96
|
+
const OPEN_TASK_STATUSES = new Set(['active', 'blocked']);
|
|
97
|
+
const VALUE_FLAGS = new Set(['--keep', '--mode', '--phase', '--status', '--task', '--text', '--title', '--note', '--context', '--group', '--project', '--tag', '--tags', '--keyword', '--since']);
|
|
76
98
|
|
|
77
99
|
function hasFlag(name) {
|
|
78
100
|
return args.includes(name);
|
|
@@ -111,10 +133,25 @@ function print(payload) {
|
|
|
111
133
|
if (payload.command === 'list') {
|
|
112
134
|
console.log(`Active Task: ${payload.activeTask || 'None'}`);
|
|
113
135
|
console.log(`Tasks: ${payload.taskCount}`);
|
|
114
|
-
|
|
136
|
+
const renderTask = (task) => {
|
|
115
137
|
const deps = task.dependsOn?.length ? ` dependsOn: [${task.dependsOn.join(', ')}]` : '';
|
|
116
138
|
const blocks = task.blocks?.length ? ` blocks: [${task.blocks.join(', ')}]` : '';
|
|
117
|
-
|
|
139
|
+
const project = task.project || task.group || 'default';
|
|
140
|
+
const tags = task.tags?.length ? ` tags=[${task.tags.join(', ')}]` : '';
|
|
141
|
+
const dates = task.createdAt || task.updatedAt
|
|
142
|
+
? ` created=${String(task.createdAt || '-').slice(0, 10)} updated=${String(task.updatedAt || '-').slice(0, 10)}`
|
|
143
|
+
: '';
|
|
144
|
+
console.log(`- ${task.id}: project=${project} status=${task.status || '-'} phase=${task.phase || '-'}${tags}${dates}${deps}${blocks}`);
|
|
145
|
+
};
|
|
146
|
+
if (payload.groups) {
|
|
147
|
+
console.log('');
|
|
148
|
+
console.log('=== Task Groups ===');
|
|
149
|
+
for (const group of payload.groups) {
|
|
150
|
+
console.log(`${group.group} (${group.tasks.length} task${group.tasks.length === 1 ? '' : 's'}):`);
|
|
151
|
+
for (const task of group.tasks) renderTask(task);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
for (const task of payload.tasks || []) renderTask(task);
|
|
118
155
|
}
|
|
119
156
|
|
|
120
157
|
// Render graph
|
|
@@ -154,11 +191,28 @@ function print(payload) {
|
|
|
154
191
|
for (const op of payload.operations) console.log(`- ${op.action}: ${op.taskId || op.path} (${op.reason})`);
|
|
155
192
|
} else if (payload.command === 'archive') {
|
|
156
193
|
if (payload.dryRun) console.log('[DRY RUN] No files moved. Use --apply to execute.');
|
|
194
|
+
if (payload.group) console.log(`Group: ${payload.group}`);
|
|
157
195
|
console.log(`Scanned: ${payload.scanned}, Archiveable: ${payload.archiveable}, To archive: ${payload.toArchive}, Kept: ${payload.kept}, Skipped: ${payload.skipped}`);
|
|
158
196
|
for (const r of payload.results) {
|
|
159
197
|
const suffix = r.path ? ` -> _archive/${r.path}` : '';
|
|
160
198
|
console.log(`- ${r.action}: ${r.dir} (${r.status})${suffix}`);
|
|
161
199
|
}
|
|
200
|
+
} else if (payload.command === 'open') {
|
|
201
|
+
console.log(`Open tasks: ${payload.taskCount}`);
|
|
202
|
+
for (const task of payload.tasks || []) {
|
|
203
|
+
const blocked = task.blockedByOpenDeps?.length ? ` blockedBy=[${task.blockedByOpenDeps.join(', ')}]` : '';
|
|
204
|
+
console.log(`- ${task.id}: project=${task.project || task.group || 'default'} status=${task.status || '-'} phase=${task.phase || '-'} updated=${String(task.updatedAt || '-').slice(0, 10)}${blocked}`);
|
|
205
|
+
}
|
|
206
|
+
} else if (payload.command === 'query') {
|
|
207
|
+
console.log(`Query: ${payload.keyword} (${payload.count} match${payload.count === 1 ? '' : 'es'})`);
|
|
208
|
+
for (const result of payload.results || []) {
|
|
209
|
+
console.log(`- ${result.id}: project=${result.project || result.group || 'default'} status=${result.status || '-'} path=${result.path}`);
|
|
210
|
+
for (const hit of result.hits || []) console.log(` ${hit.file}:${hit.line} ${hit.snippet}`);
|
|
211
|
+
}
|
|
212
|
+
} else if (payload.command === 'index') {
|
|
213
|
+
console.log(`Task index rebuilt: ${payload.taskCount} task(s) in ${payload.projectCount} project(s).`);
|
|
214
|
+
console.log(`- JSON: ${payload.path}`);
|
|
215
|
+
console.log(`- Markdown: ${payload.markdownPath}`);
|
|
162
216
|
} else {
|
|
163
217
|
console.log(payload.message || '');
|
|
164
218
|
}
|
|
@@ -179,23 +233,32 @@ function usage() {
|
|
|
179
233
|
message: `Usage: node Harness/scripts/task-state.mjs <command> [options]
|
|
180
234
|
|
|
181
235
|
Commands:
|
|
182
|
-
list [--json]
|
|
236
|
+
list [--json] [--group <project>] [--project <project>] [--status <s>] [--by-group]
|
|
237
|
+
List task state with dependency/resume info.
|
|
238
|
+
--group is a legacy alias for --project.
|
|
239
|
+
index [--json] Rebuild Harness/tasks/INDEX.json and INDEX.md.
|
|
240
|
+
query <keyword> [--project <project>] [--status <s>] [--json]
|
|
241
|
+
Search task metadata and capsule notes.
|
|
183
242
|
validate [--strict] [--json] Validate state consistency (includes link checks).
|
|
184
243
|
reconcile [--dry-run|--apply] [--json] Normalize STATE.json and root PROGRESS.md.
|
|
185
|
-
set-active <task-id> [--dry-run] Set the
|
|
244
|
+
set-active <task-id> [--dry-run] Set the focus/resume task (multiple open tasks are valid).
|
|
186
245
|
transition <task-id> --status <s> --phase <p> [--dry-run]
|
|
187
|
-
archive [--dry-run|--apply] [--keep n] [--task id] [--json]
|
|
246
|
+
archive [--dry-run|--apply] [--keep n] [--task id] [--group <tag>] [--json]
|
|
188
247
|
Archive eligible tasks to _archive/YYYY/MM/DD/.
|
|
189
|
-
Explicit --apply (no --task filter) archives ALL.
|
|
248
|
+
Explicit --apply (no --task/--group filter) archives ALL.
|
|
249
|
+
--group archives a whole tag (batch op, no confirmation;
|
|
250
|
+
it implies --apply unless --dry-run is given).
|
|
190
251
|
history list [--year YYYY] [--month MM] [--json]
|
|
191
252
|
List archived tasks, optional year/month filter.
|
|
192
253
|
history search <keyword> [--json] Full-text search archived PLAN/PROGRESS/PROBLEM/REFERENCES.
|
|
193
254
|
history load <task-id> [--json] Load one archived task's full record.
|
|
194
255
|
history delete <task-id> [--dry-run|--apply] [--json]
|
|
195
256
|
Delete an archived task (audit trail written).
|
|
196
|
-
record <task-id> [--create] [--text "description"] [--status <s>] [--mode <m>] [--dry-run|--apply] [--json]
|
|
257
|
+
record <task-id> [--create] [--text "description"] [--status <s>] [--phase <p>] [--mode <m>] [--group <project>] [--project <project>] [--tag <tag[,tag...]>] [--dry-run|--apply] [--json]
|
|
197
258
|
Create or update a task record.
|
|
198
|
-
|
|
259
|
+
--project is canonical; --group remains compatible.
|
|
260
|
+
open [--project <project>] [--status <s>] [--json]
|
|
261
|
+
List all active/blocked tasks; multiple open tasks are valid.
|
|
199
262
|
|
|
200
263
|
Archive defaults to dry-run and keeps ${OUTER_TASK_CAP} non-archived task capsules.`,
|
|
201
264
|
}, 0);
|
|
@@ -216,6 +279,33 @@ function writeJsonAtomic(file, value) {
|
|
|
216
279
|
writeTextAtomic(file, JSON.stringify(value, null, 2) + '\n');
|
|
217
280
|
}
|
|
218
281
|
|
|
282
|
+
// Small parameterized helpers for adjacent runtime consumers. The task-state
|
|
283
|
+
// CLI remains the canonical owner of task paths and atomic writes; these
|
|
284
|
+
// helpers deliberately do not normalize or maintain a second task store.
|
|
285
|
+
function taskPathsForProject(projectRoot) {
|
|
286
|
+
const project = path.resolve(String(projectRoot || ''));
|
|
287
|
+
const harness = path.join(project, 'Harness');
|
|
288
|
+
const tasks = path.join(harness, 'tasks');
|
|
289
|
+
return { project, harnessDir: harness, tasksDir: tasks };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function readTaskState(projectRoot, taskId) {
|
|
293
|
+
const { tasksDir: projectTasksDir } = taskPathsForProject(projectRoot);
|
|
294
|
+
const file = path.join(projectTasksDir, String(taskId));
|
|
295
|
+
const statePath = path.join(file, 'STATE.json');
|
|
296
|
+
if (!fs.existsSync(statePath)) return { state: null, error: null, path: statePath };
|
|
297
|
+
try {
|
|
298
|
+
return { state: JSON.parse(fs.readFileSync(statePath, 'utf8')), error: null, path: statePath };
|
|
299
|
+
} catch (err) {
|
|
300
|
+
return { state: null, error: `invalid STATE.json: ${err.message}`, path: statePath };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function writeTaskStateAtomic(projectRoot, taskId, state) {
|
|
305
|
+
const { tasksDir: projectTasksDir } = taskPathsForProject(projectRoot);
|
|
306
|
+
writeJsonAtomic(path.join(projectTasksDir, String(taskId), 'STATE.json'), state);
|
|
307
|
+
}
|
|
308
|
+
|
|
219
309
|
function normalizeCandidate(value, validSet, aliasMap) {
|
|
220
310
|
if (value === null || value === undefined) return '';
|
|
221
311
|
const raw = String(value).trim().toLowerCase();
|
|
@@ -272,12 +362,10 @@ function displayPhase(phase) {
|
|
|
272
362
|
|
|
273
363
|
function statusFromPhase(phase, isActive) {
|
|
274
364
|
const normalized = normalizePhase(phase);
|
|
275
|
-
if (
|
|
276
|
-
if (normalized === 'verified' || normalized === 'closeout') return 'verified';
|
|
277
|
-
if (normalized === 'archived') return 'archived';
|
|
365
|
+
if (normalized === 'verified' || normalized === 'closeout' || normalized === 'archived') return 'closed';
|
|
278
366
|
if (normalized === 'blocked') return 'blocked';
|
|
279
|
-
if (
|
|
280
|
-
return '
|
|
367
|
+
if (isActive) return 'active';
|
|
368
|
+
return 'active';
|
|
281
369
|
}
|
|
282
370
|
|
|
283
371
|
function defaultQueues() {
|
|
@@ -310,6 +398,10 @@ const VALID_MODES = new Set([
|
|
|
310
398
|
'wf-review',
|
|
311
399
|
'wf-browser',
|
|
312
400
|
]);
|
|
401
|
+
// Durable task lifecycle is opt-in only for the two task-owning WF modes.
|
|
402
|
+
// wf-auto/wf-auto-spark remain explicit workflow capabilities, but their
|
|
403
|
+
// continuous capsule is not a normal task lifecycle and must not adopt tasks.
|
|
404
|
+
const WF_MANAGED_MODES = new Set(['wf', 'wf-max']);
|
|
313
405
|
|
|
314
406
|
function normalizeMode(value) {
|
|
315
407
|
if (value === null || value === undefined) return '';
|
|
@@ -318,6 +410,21 @@ function normalizeMode(value) {
|
|
|
318
410
|
if (VALID_MODES.has(raw)) return raw;
|
|
319
411
|
return '';
|
|
320
412
|
}
|
|
413
|
+
|
|
414
|
+
function isWfManagedMode(value) {
|
|
415
|
+
return WF_MANAGED_MODES.has(normalizeMode(value));
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function lifecycleForState(state, fallbackStatus = 'active') {
|
|
419
|
+
const status = normalizeStatus(state?.status) || fallbackStatus;
|
|
420
|
+
const mode = normalizeMode(state?.mode) || 'direct';
|
|
421
|
+
const wfManaged = isWfManagedMode(mode);
|
|
422
|
+
return {
|
|
423
|
+
mode,
|
|
424
|
+
wfManaged,
|
|
425
|
+
resumeRequired: wfManaged && OPEN_TASK_STATUSES.has(status),
|
|
426
|
+
};
|
|
427
|
+
}
|
|
321
428
|
function normalizeQueues(state) {
|
|
322
429
|
const source = state && typeof state.queues === 'object' && state.queues ? state.queues : state || {};
|
|
323
430
|
return {
|
|
@@ -401,7 +508,9 @@ function collectTasks() {
|
|
|
401
508
|
const statePhase = normalizePhase(state?.phase);
|
|
402
509
|
const rootPhase = normalizePhase(rootRow?.phase);
|
|
403
510
|
const progressPhase = normalizePhase(progressPhaseRaw);
|
|
404
|
-
|
|
511
|
+
// STATE.json is authoritative once present; root/task progress remains a
|
|
512
|
+
// compatibility fallback for legacy capsules without normalized state.
|
|
513
|
+
const phase = statePhase || progressPhase || rootPhase;
|
|
405
514
|
const status = stateStatus || statusFromPhase(phase, id === rootProgress.activeTask);
|
|
406
515
|
const stat = fs.statSync(path.join(tasksDir, id));
|
|
407
516
|
return {
|
|
@@ -484,12 +593,8 @@ function validateState({ strict = false } = {}) {
|
|
|
484
593
|
if (task.state.phase && !normalizePhase(task.state.phase)) {
|
|
485
594
|
issue(`${task.id}: unknown phase "${task.state.phase}"`);
|
|
486
595
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
}
|
|
490
|
-
if (task.id === rootProgress.activeTask && normalizeStatus(task.state.status) && normalizeStatus(task.state.status) !== 'active') {
|
|
491
|
-
issue(`${task.id}: root Active Task points here but STATE.json status is "${normalizeStatus(task.state.status)}"`, true);
|
|
492
|
-
}
|
|
596
|
+
// Multiple tasks may be active. The root Active Task is retained as a
|
|
597
|
+
// focus/resume pointer for compatibility, not as a singleton invariant.
|
|
493
598
|
|
|
494
599
|
const links = task.state.links || {};
|
|
495
600
|
if (Array.isArray(links.dependsOn)) {
|
|
@@ -534,10 +639,18 @@ function validateState({ strict = false } = {}) {
|
|
|
534
639
|
}
|
|
535
640
|
}
|
|
536
641
|
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
642
|
+
const focusedTask = tasks.find(task => task.id === rootProgress.activeTask);
|
|
643
|
+
const openManagedTasks = tasks.filter(task => {
|
|
644
|
+
const status = normalizeStatus(task.state?.status) || task.status;
|
|
645
|
+
return isWfManagedMode(task.state?.mode) && OPEN_TASK_STATUSES.has(status);
|
|
646
|
+
});
|
|
647
|
+
if (focusedTask && openManagedTasks.length > 0) {
|
|
648
|
+
const focusedStatus = normalizeStatus(focusedTask.state?.status) || focusedTask.status;
|
|
649
|
+
if (!isWfManagedMode(focusedTask.state?.mode) && OPEN_TASK_STATUSES.has(focusedStatus)) {
|
|
650
|
+
issue(`Direct task "${focusedTask.id}" cannot be the active focus while an open WF-managed task exists`, true);
|
|
651
|
+
}
|
|
540
652
|
}
|
|
653
|
+
|
|
541
654
|
if (tasks.length > OUTER_TASK_CAP) {
|
|
542
655
|
issue(`Harness/tasks/ has ${tasks.length} outer task capsules (cap ${OUTER_TASK_CAP}); remind the user to run $wf-task-archive when they want to archive completed tasks`);
|
|
543
656
|
}
|
|
@@ -578,33 +691,41 @@ function safeTaskPath(...segments) {
|
|
|
578
691
|
}
|
|
579
692
|
|
|
580
693
|
function desiredPhaseForTask(task, activeTask) {
|
|
581
|
-
return task.
|
|
694
|
+
return task.statePhase || task.progressPhase || task.rootPhase || (task.id === activeTask ? 'implement' : 'intake');
|
|
582
695
|
}
|
|
583
696
|
|
|
584
697
|
function desiredStatusForTask(task, activeTask, desiredPhase) {
|
|
585
|
-
if (task.id === activeTask) return 'active';
|
|
586
698
|
const current = normalizeStatus(task.state?.status);
|
|
587
|
-
|
|
588
|
-
|
|
699
|
+
const phaseStatus = statusFromPhase(desiredPhase, false);
|
|
700
|
+
if (current === 'active' && phaseStatus === 'closed') return 'closed';
|
|
701
|
+
if (current) return current;
|
|
702
|
+
return statusFromPhase(desiredPhase, task.id === activeTask);
|
|
589
703
|
}
|
|
590
704
|
|
|
591
705
|
function defaultState(taskId, status, phase, now) {
|
|
592
706
|
const runtime = defaultTaskRuntime();
|
|
707
|
+
const lifecycleStatus = normalizeStatus(status) || 'active';
|
|
593
708
|
return {
|
|
594
709
|
schemaVersion: 1,
|
|
595
710
|
taskId,
|
|
596
|
-
status,
|
|
711
|
+
status: lifecycleStatus,
|
|
597
712
|
mode: 'direct',
|
|
598
713
|
defaultRuntime: runtime,
|
|
599
714
|
defaultAgentRuntime: runtime,
|
|
600
715
|
tier: 'none',
|
|
601
716
|
phase,
|
|
602
717
|
gate: null,
|
|
718
|
+
project: 'default',
|
|
719
|
+
tags: [],
|
|
720
|
+
createdAt: now,
|
|
721
|
+
startedAt: lifecycleStatus === 'active' ? now : null,
|
|
722
|
+
closedAt: lifecycleStatus === 'closed' ? now : null,
|
|
603
723
|
updatedAt: now,
|
|
604
724
|
activeQuestion: null,
|
|
605
725
|
nextAction: 'Review task state.',
|
|
606
726
|
acceptance: [],
|
|
607
727
|
queues: defaultQueues(),
|
|
728
|
+
workItems: [],
|
|
608
729
|
dispatchLedger: [],
|
|
609
730
|
decisions: [],
|
|
610
731
|
risks: [],
|
|
@@ -622,16 +743,30 @@ function normalizeState(task, activeTask, now) {
|
|
|
622
743
|
|
|
623
744
|
state.schemaVersion = 1;
|
|
624
745
|
state.taskId = task.id;
|
|
625
|
-
|
|
746
|
+
// Keep an archived marker intact when an old repository has an archived
|
|
747
|
+
// capsule in the live directory; archive migration can still move it.
|
|
748
|
+
const rawStatus = String(task.state?.status || '').trim().toLowerCase();
|
|
749
|
+
state.status = rawStatus === 'archived' ? 'archived' : status;
|
|
626
750
|
state.phase = phase;
|
|
627
751
|
if (!state.mode) state.mode = 'direct';
|
|
628
752
|
if (!state.defaultRuntime) state.defaultRuntime = defaultTaskRuntime();
|
|
629
753
|
if (!state.defaultAgentRuntime) state.defaultAgentRuntime = state.defaultRuntime;
|
|
630
754
|
if (!state.tier) state.tier = 'none';
|
|
631
755
|
if (!Object.prototype.hasOwnProperty.call(state, 'gate')) state.gate = null;
|
|
756
|
+
state.tags = normalizeTags(state.tags);
|
|
757
|
+
if (!state.createdAt) state.createdAt = now;
|
|
758
|
+
if (!Object.prototype.hasOwnProperty.call(state, 'startedAt')) state.startedAt = state.status === 'active' ? now : null;
|
|
759
|
+
if (!Object.prototype.hasOwnProperty.call(state, 'closedAt')) state.closedAt = state.status === 'closed' || state.status === 'archived' ? now : null;
|
|
760
|
+
if (state.status === 'active' && !state.startedAt) state.startedAt = now;
|
|
761
|
+
if (state.status === 'closed' || state.status === 'archived') {
|
|
762
|
+
if (!state.closedAt) state.closedAt = now;
|
|
763
|
+
} else if (state.closedAt) {
|
|
764
|
+
state.closedAt = null;
|
|
765
|
+
}
|
|
632
766
|
if (!Object.prototype.hasOwnProperty.call(state, 'activeQuestion')) state.activeQuestion = null;
|
|
633
767
|
if (!state.nextAction) state.nextAction = task.rootRow?.goal || 'Review task state.';
|
|
634
768
|
state.queues = normalizeQueues(state);
|
|
769
|
+
if (!Array.isArray(state.workItems)) state.workItems = [];
|
|
635
770
|
if (!Array.isArray(state.dispatchLedger)) state.dispatchLedger = [];
|
|
636
771
|
if (!Array.isArray(state.decisions)) state.decisions = [];
|
|
637
772
|
if (!Array.isArray(state.risks)) state.risks = [];
|
|
@@ -708,11 +843,14 @@ function buildRows(tasks, activeTask, excluded = new Set()) {
|
|
|
708
843
|
return ids.map(id => {
|
|
709
844
|
const task = byId.get(id);
|
|
710
845
|
const phase = normalizePhase(task.desiredState?.phase) || task.phase;
|
|
846
|
+
const desiredState = task.desiredState || task.state || {};
|
|
711
847
|
return {
|
|
712
848
|
id,
|
|
713
849
|
goal: task.rootRow?.goal || task.state?.goal || task.state?.nextAction || taskTitle(id),
|
|
714
850
|
phase: displayPhase(phase),
|
|
715
|
-
closed:
|
|
851
|
+
closed: desiredState.closedAt
|
|
852
|
+
? String(desiredState.closedAt).slice(0, 10)
|
|
853
|
+
: task.rootRow?.closed || '-',
|
|
716
854
|
};
|
|
717
855
|
});
|
|
718
856
|
}
|
|
@@ -740,6 +878,10 @@ function buildReconcilePlan({ activeOverride = undefined, transition = null } =
|
|
|
740
878
|
if (transition.status) {
|
|
741
879
|
const status = normalizeStatus(transition.status);
|
|
742
880
|
if (!status) errors.push(`${task.id}: unknown transition status "${transition.status}"`);
|
|
881
|
+
const currentStatus = normalizeStatus(task.state?.status) || task.status;
|
|
882
|
+
if (status && isWfManagedMode(task.state?.mode) && currentStatus === 'closed' && status !== 'closed') {
|
|
883
|
+
errors.push(`${task.id}: closed WF-managed task cannot be reopened; create a new task capsule`);
|
|
884
|
+
}
|
|
743
885
|
if (status === 'active') activeTask = task.id;
|
|
744
886
|
if (rootProgress.activeTask === task.id && SAFE_ARCHIVE_STATUSES.has(status)) activeTask = null;
|
|
745
887
|
}
|
|
@@ -749,6 +891,18 @@ function buildReconcilePlan({ activeOverride = undefined, transition = null } =
|
|
|
749
891
|
}
|
|
750
892
|
}
|
|
751
893
|
|
|
894
|
+
const focusedTask = tasks.find(task => task.id === activeTask);
|
|
895
|
+
const openManagedTasks = tasks.filter(task => {
|
|
896
|
+
const status = normalizeStatus(task.state?.status) || task.status;
|
|
897
|
+
return isWfManagedMode(task.state?.mode) && OPEN_TASK_STATUSES.has(status);
|
|
898
|
+
});
|
|
899
|
+
if (focusedTask && openManagedTasks.length > 0) {
|
|
900
|
+
const focusedStatus = normalizeStatus(focusedTask.state?.status) || focusedTask.status;
|
|
901
|
+
if (!isWfManagedMode(focusedTask.state?.mode) && OPEN_TASK_STATUSES.has(focusedStatus)) {
|
|
902
|
+
errors.push(`Direct task "${activeTask}" cannot replace an open WF-managed focus; close the WF task or focus another WF task.`);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
752
906
|
if (errors.length) {
|
|
753
907
|
return { ok: false, command: 'reconcile', dryRun: true, activeTask, errors, warnings: [], operations: [] };
|
|
754
908
|
}
|
|
@@ -761,6 +915,9 @@ function buildReconcilePlan({ activeOverride = undefined, transition = null } =
|
|
|
761
915
|
if (transition.status) nextState.status = normalizeStatus(transition.status);
|
|
762
916
|
if (transition.phase) nextState.phase = normalizePhase(transition.phase);
|
|
763
917
|
if (transition.nextAction) nextState.nextAction = transition.nextAction;
|
|
918
|
+
if (nextState.status === 'active' && !nextState.startedAt) nextState.startedAt = now;
|
|
919
|
+
if (nextState.status === 'closed' && !nextState.closedAt) nextState.closedAt = now;
|
|
920
|
+
if (nextState.status !== 'closed' && nextState.status !== 'archived') nextState.closedAt = null;
|
|
764
921
|
nextState.updatedAt = now;
|
|
765
922
|
normalized = {
|
|
766
923
|
state: nextState,
|
|
@@ -826,6 +983,31 @@ function applyOperations(operations) {
|
|
|
826
983
|
}
|
|
827
984
|
}
|
|
828
985
|
|
|
986
|
+
function syncTaskViewsForState(taskId, state) {
|
|
987
|
+
const { rootProgress, tasks } = collectTasks();
|
|
988
|
+
const task = tasks.find(item => item.id === taskId);
|
|
989
|
+
if (!task) return;
|
|
990
|
+
|
|
991
|
+
task.desiredState = state;
|
|
992
|
+
let activeTask = rootProgress.activeTask;
|
|
993
|
+
const status = normalizeStatus(state.status);
|
|
994
|
+
if (activeTask === taskId && (status === 'closed' || status === 'archived')) activeTask = null;
|
|
995
|
+
|
|
996
|
+
const progressFile = path.join(tasksDir, taskId, 'PROGRESS.md');
|
|
997
|
+
const existingProgress = readText(progressFile);
|
|
998
|
+
const desiredProgress = renderTaskProgress(existingProgress, taskId, state);
|
|
999
|
+
if (desiredProgress !== existingProgress.replace(/\r\n/g, '\n')) {
|
|
1000
|
+
writeTextAtomic(progressFile, desiredProgress);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const rows = buildRows(tasks, activeTask);
|
|
1004
|
+
const desiredRoot = renderRootProgress(rootProgress.text, activeTask, rows);
|
|
1005
|
+
if (desiredRoot !== rootProgress.text.replace(/\r\n/g, '\n')) {
|
|
1006
|
+
writeTextAtomic(progressPath, desiredRoot);
|
|
1007
|
+
}
|
|
1008
|
+
writeTaskIndex();
|
|
1009
|
+
}
|
|
1010
|
+
|
|
829
1011
|
function buildListGraph(expandedTasks) {
|
|
830
1012
|
const byId = new Map(expandedTasks.map(t => [t.id, t]));
|
|
831
1013
|
const graph = { roots: [], depEdges: [], blockEdges: [], orphanedDeps: [] };
|
|
@@ -858,19 +1040,151 @@ function buildListGraph(expandedTasks) {
|
|
|
858
1040
|
return graph;
|
|
859
1041
|
}
|
|
860
1042
|
|
|
1043
|
+
function taskGroupFor(state) {
|
|
1044
|
+
const project = String(state?.project || '').trim();
|
|
1045
|
+
const legacyGroup = String(state?.group || '').trim();
|
|
1046
|
+
// A migrated legacy capsule may have project="default" while its
|
|
1047
|
+
// meaningful grouping still lives in group. Preserve that grouping.
|
|
1048
|
+
return (project && project !== 'default') || !legacyGroup
|
|
1049
|
+
? (project || legacyGroup || 'default')
|
|
1050
|
+
: legacyGroup;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
function taskProjectFor(state) {
|
|
1054
|
+
return taskGroupFor(state);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function taskTagsFor(state) {
|
|
1058
|
+
return Array.isArray(state?.tags)
|
|
1059
|
+
? state.tags.map(tag => String(tag).trim()).filter(Boolean)
|
|
1060
|
+
: [];
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
function normalizeTags(value) {
|
|
1064
|
+
return String(value || '')
|
|
1065
|
+
.split(',')
|
|
1066
|
+
.map(tag => tag.trim())
|
|
1067
|
+
.filter(Boolean);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
function taskIndexEntry(task) {
|
|
1071
|
+
const state = task.state || {};
|
|
1072
|
+
const links = state.links || {};
|
|
1073
|
+
const status = normalizeStatus(state.status) || task.status || 'active';
|
|
1074
|
+
const lifecycle = lifecycleForState(state, status);
|
|
1075
|
+
return {
|
|
1076
|
+
id: task.id,
|
|
1077
|
+
project: taskProjectFor(state),
|
|
1078
|
+
group: taskProjectFor(state),
|
|
1079
|
+
title: task.rootRow?.goal || state.goal || state.nextAction || taskTitle(task.id),
|
|
1080
|
+
status,
|
|
1081
|
+
mode: lifecycle.mode,
|
|
1082
|
+
wfManaged: lifecycle.wfManaged,
|
|
1083
|
+
resumeRequired: lifecycle.resumeRequired,
|
|
1084
|
+
phase: normalizePhase(state.phase) || task.phase || 'intake',
|
|
1085
|
+
tags: taskTagsFor(state),
|
|
1086
|
+
createdAt: state.createdAt || null,
|
|
1087
|
+
startedAt: state.startedAt || null,
|
|
1088
|
+
updatedAt: state.updatedAt || null,
|
|
1089
|
+
closedAt: state.closedAt || null,
|
|
1090
|
+
dependsOn: Array.isArray(links.dependsOn) ? links.dependsOn : [],
|
|
1091
|
+
blocks: Array.isArray(links.blocks) ? links.blocks : [],
|
|
1092
|
+
path: `Harness/tasks/${task.id}`,
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function buildTaskIndexModel() {
|
|
1097
|
+
const { rootProgress, tasks } = collectTasks();
|
|
1098
|
+
const entries = tasks.map(taskIndexEntry).sort((a, b) => a.id.localeCompare(b.id));
|
|
1099
|
+
const projects = {};
|
|
1100
|
+
for (const task of entries) {
|
|
1101
|
+
if (!projects[task.project]) projects[task.project] = [];
|
|
1102
|
+
projects[task.project].push(task.id);
|
|
1103
|
+
}
|
|
1104
|
+
const activeEntry = entries.find(task => task.id === rootProgress.activeTask) || null;
|
|
1105
|
+
const resumeTask = activeEntry?.resumeRequired
|
|
1106
|
+
? {
|
|
1107
|
+
taskId: activeEntry.id,
|
|
1108
|
+
mode: activeEntry.mode,
|
|
1109
|
+
status: activeEntry.status,
|
|
1110
|
+
project: activeEntry.project,
|
|
1111
|
+
}
|
|
1112
|
+
: null;
|
|
1113
|
+
return {
|
|
1114
|
+
schemaVersion: 1,
|
|
1115
|
+
generatedAt: new Date().toISOString(),
|
|
1116
|
+
sourceOfTruth: 'Harness/tasks/*/STATE.json',
|
|
1117
|
+
activeTask: rootProgress.activeTask,
|
|
1118
|
+
resumeTask,
|
|
1119
|
+
resumeRequired: Boolean(resumeTask),
|
|
1120
|
+
projects,
|
|
1121
|
+
tasks: entries,
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
function renderTaskIndexMd(model) {
|
|
1126
|
+
const lines = [
|
|
1127
|
+
'# Task Index (generated)',
|
|
1128
|
+
'',
|
|
1129
|
+
`Generated: ${model.generatedAt}`,
|
|
1130
|
+
'',
|
|
1131
|
+
'This file is derived from task STATE.json files. Do not edit it directly.',
|
|
1132
|
+
'',
|
|
1133
|
+
'| Task | Project | Status | Mode | Phase | Created | Updated |',
|
|
1134
|
+
'|------|---------|--------|------|-------|---------|---------|',
|
|
1135
|
+
];
|
|
1136
|
+
for (const task of model.tasks) {
|
|
1137
|
+
lines.push(`| \`${task.id}\` | ${task.project} | ${task.status} | ${task.mode} | ${task.phase} | ${String(task.createdAt || '-').slice(0, 10)} | ${String(task.updatedAt || '-').slice(0, 10)} |`);
|
|
1138
|
+
}
|
|
1139
|
+
lines.push('', '## Projects', '');
|
|
1140
|
+
for (const [project, ids] of Object.entries(model.projects).sort(([a], [b]) => a.localeCompare(b))) {
|
|
1141
|
+
lines.push(`- **${project}**: ${ids.map(id => `\`${id}\``).join(', ')}`);
|
|
1142
|
+
}
|
|
1143
|
+
lines.push('');
|
|
1144
|
+
return lines.join('\n');
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
function writeTaskIndex() {
|
|
1148
|
+
const model = buildTaskIndexModel();
|
|
1149
|
+
writeJsonAtomic(path.join(tasksDir, 'INDEX.json'), model);
|
|
1150
|
+
writeTextAtomic(path.join(tasksDir, 'INDEX.md'), renderTaskIndexMd(model));
|
|
1151
|
+
return model;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
function taskSearchText(task) {
|
|
1155
|
+
const files = ['PLAN.md', 'PROGRESS.md', 'PROBLEM.md', 'REFERENCES.md'];
|
|
1156
|
+
const stateText = JSON.stringify(task.state || {});
|
|
1157
|
+
const fileText = files.map(file => readText(path.join(task.path, file))).join('\n');
|
|
1158
|
+
return `${task.id}\n${stateText}\n${fileText}`.toLowerCase();
|
|
1159
|
+
}
|
|
1160
|
+
|
|
861
1161
|
function runList() {
|
|
862
1162
|
const { rootProgress, tasks } = collectTasks();
|
|
1163
|
+
const groupFilter = flagValue('--group');
|
|
1164
|
+
const projectFilter = flagValue('--project') || groupFilter;
|
|
1165
|
+
const statusFilter = flagValue('--status');
|
|
863
1166
|
|
|
864
1167
|
const expandedTasks = tasks.map(task => {
|
|
865
1168
|
const state = task.state || {};
|
|
866
1169
|
const links = state.links || {};
|
|
867
1170
|
const status = normalizeStatus(state.status) || task.status;
|
|
1171
|
+
const lifecycle = lifecycleForState(state, status);
|
|
868
1172
|
return {
|
|
869
1173
|
id: task.id,
|
|
870
1174
|
status,
|
|
1175
|
+
mode: lifecycle.mode,
|
|
1176
|
+
wfManaged: lifecycle.wfManaged,
|
|
1177
|
+
resumeRequired: lifecycle.resumeRequired,
|
|
871
1178
|
phase: normalizePhase(state.phase) || task.phase,
|
|
872
1179
|
rootPhase: task.rootPhase,
|
|
873
1180
|
progressPhase: task.progressPhase,
|
|
1181
|
+
project: taskProjectFor(state),
|
|
1182
|
+
group: taskProjectFor(state),
|
|
1183
|
+
tags: taskTagsFor(state),
|
|
1184
|
+
createdAt: state.createdAt || null,
|
|
1185
|
+
startedAt: state.startedAt || null,
|
|
1186
|
+
updatedAt: state.updatedAt || null,
|
|
1187
|
+
closedAt: state.closedAt || null,
|
|
874
1188
|
dependsOn: Array.isArray(links.dependsOn) ? links.dependsOn : [],
|
|
875
1189
|
blocks: Array.isArray(links.blocks) ? links.blocks : [],
|
|
876
1190
|
statusDisplay: status || '-',
|
|
@@ -880,14 +1194,48 @@ function runList() {
|
|
|
880
1194
|
};
|
|
881
1195
|
});
|
|
882
1196
|
|
|
883
|
-
const
|
|
1197
|
+
const normalizedStatusFilter = statusFilter ? normalizeStatus(statusFilter) : null;
|
|
1198
|
+
if (statusFilter && !normalizedStatusFilter) {
|
|
1199
|
+
finish({
|
|
1200
|
+
ok: false,
|
|
1201
|
+
command: 'list',
|
|
1202
|
+
errors: [`Invalid status filter "${statusFilter}". Valid: active, blocked, closed (legacy aliases accepted)`],
|
|
1203
|
+
warnings: [],
|
|
1204
|
+
tasks: [],
|
|
1205
|
+
}, 1);
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
const selectedTasks = projectFilter
|
|
1209
|
+
? expandedTasks.filter(task => task.project === projectFilter)
|
|
1210
|
+
: expandedTasks;
|
|
1211
|
+
const statusTasks = normalizedStatusFilter
|
|
1212
|
+
? selectedTasks.filter(task => task.status === normalizedStatusFilter)
|
|
1213
|
+
: selectedTasks;
|
|
1214
|
+
|
|
1215
|
+
let groups = null;
|
|
1216
|
+
if (hasFlag('--by-group')) {
|
|
1217
|
+
const byName = new Map();
|
|
1218
|
+
for (const task of statusTasks) {
|
|
1219
|
+
if (!byName.has(task.group)) byName.set(task.group, []);
|
|
1220
|
+
byName.get(task.group).push(task);
|
|
1221
|
+
}
|
|
1222
|
+
groups = [...byName.entries()]
|
|
1223
|
+
.map(([group, groupTasks]) => ({ group, tasks: groupTasks }))
|
|
1224
|
+
.sort((a, b) => (a.group === 'default' ? 1 : 0) - (b.group === 'default' ? 1 : 0) || a.group.localeCompare(b.group));
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
const graph = buildListGraph(statusTasks);
|
|
884
1228
|
|
|
885
1229
|
const payload = {
|
|
886
1230
|
ok: true,
|
|
887
1231
|
command: 'list',
|
|
888
|
-
taskCount:
|
|
1232
|
+
taskCount: statusTasks.length,
|
|
889
1233
|
activeTask: rootProgress.activeTask,
|
|
890
|
-
|
|
1234
|
+
groupFilter: groupFilter || null,
|
|
1235
|
+
projectFilter: projectFilter || null,
|
|
1236
|
+
statusFilter: normalizedStatusFilter,
|
|
1237
|
+
tasks: statusTasks,
|
|
1238
|
+
groups,
|
|
891
1239
|
graph: {
|
|
892
1240
|
roots: graph.roots.map(t => t.id),
|
|
893
1241
|
depEdges: graph.depEdges,
|
|
@@ -900,6 +1248,77 @@ function runList() {
|
|
|
900
1248
|
finish(payload, 0);
|
|
901
1249
|
}
|
|
902
1250
|
|
|
1251
|
+
function runIndex() {
|
|
1252
|
+
const model = writeTaskIndex();
|
|
1253
|
+
finish({
|
|
1254
|
+
ok: true,
|
|
1255
|
+
command: 'index',
|
|
1256
|
+
path: 'Harness/tasks/INDEX.json',
|
|
1257
|
+
markdownPath: 'Harness/tasks/INDEX.md',
|
|
1258
|
+
generatedAt: model.generatedAt,
|
|
1259
|
+
projectCount: Object.keys(model.projects).length,
|
|
1260
|
+
taskCount: model.tasks.length,
|
|
1261
|
+
projects: model.projects,
|
|
1262
|
+
warnings: [],
|
|
1263
|
+
}, 0);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
function runQuery() {
|
|
1267
|
+
const keyword = flagValue('--keyword') || findTaskIdArg(1);
|
|
1268
|
+
const projectFilter = flagValue('--project') || flagValue('--group');
|
|
1269
|
+
const statusFilter = flagValue('--status');
|
|
1270
|
+
const normalizedStatusFilter = statusFilter ? normalizeStatus(statusFilter) : null;
|
|
1271
|
+
if (statusFilter && !normalizedStatusFilter) {
|
|
1272
|
+
finish({
|
|
1273
|
+
ok: false,
|
|
1274
|
+
command: 'query',
|
|
1275
|
+
errors: [`Invalid status filter "${statusFilter}". Valid: active, blocked, closed (legacy aliases accepted)`],
|
|
1276
|
+
warnings: [],
|
|
1277
|
+
results: [],
|
|
1278
|
+
}, 1);
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
if (!keyword) {
|
|
1282
|
+
finish({ ok: false, command: 'query', errors: ['query requires <keyword> or --keyword <text>'], warnings: [], results: [] }, 1);
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
const needle = String(keyword).trim().toLowerCase();
|
|
1287
|
+
const { tasks } = collectTasks();
|
|
1288
|
+
const results = tasks
|
|
1289
|
+
.filter(task => {
|
|
1290
|
+
const status = normalizeStatus(task.state?.status) || task.status;
|
|
1291
|
+
if (projectFilter && taskProjectFor(task.state) !== projectFilter) return false;
|
|
1292
|
+
if (normalizedStatusFilter && status !== normalizedStatusFilter) return false;
|
|
1293
|
+
return taskSearchText(task).includes(needle);
|
|
1294
|
+
})
|
|
1295
|
+
.map(task => {
|
|
1296
|
+
const entry = taskIndexEntry(task);
|
|
1297
|
+
const hits = [];
|
|
1298
|
+
for (const file of ['PLAN.md', 'PROGRESS.md', 'PROBLEM.md', 'REFERENCES.md', 'STATE.json']) {
|
|
1299
|
+
const content = readText(path.join(task.path, file));
|
|
1300
|
+
const lines = content.split('\n');
|
|
1301
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
1302
|
+
if (lines[index].toLowerCase().includes(needle)) {
|
|
1303
|
+
hits.push({ file, line: index + 1, snippet: lines[index].trim().slice(0, 160) });
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
return { ...entry, hits };
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1310
|
+
finish({
|
|
1311
|
+
ok: true,
|
|
1312
|
+
command: 'query',
|
|
1313
|
+
keyword,
|
|
1314
|
+
projectFilter: projectFilter || null,
|
|
1315
|
+
statusFilter: normalizedStatusFilter,
|
|
1316
|
+
count: results.length,
|
|
1317
|
+
results,
|
|
1318
|
+
warnings: [],
|
|
1319
|
+
}, 0);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
903
1322
|
function runValidate() {
|
|
904
1323
|
const payload = validateState({ strict: hasFlag('--strict') });
|
|
905
1324
|
finish(payload, payload.ok ? 0 : 1);
|
|
@@ -910,6 +1329,7 @@ function runReconcile(overrides = {}) {
|
|
|
910
1329
|
if (overrides.commandLabel) plan.command = overrides.commandLabel;
|
|
911
1330
|
if (plan.ok && hasFlag('--apply')) {
|
|
912
1331
|
applyOperations(plan.operations);
|
|
1332
|
+
writeTaskIndex();
|
|
913
1333
|
plan.dryRun = false;
|
|
914
1334
|
}
|
|
915
1335
|
finish(plan, plan.ok ? 0 : 1);
|
|
@@ -922,6 +1342,31 @@ function runSetActive() {
|
|
|
922
1342
|
} catch (err) {
|
|
923
1343
|
finish({ ok: false, command: 'set-active', errors: [err.message], warnings: [], operations: [] }, 1);
|
|
924
1344
|
}
|
|
1345
|
+
const { tasks } = collectTasks();
|
|
1346
|
+
const task = tasks.find(item => item.id === taskId);
|
|
1347
|
+
const status = normalizeStatus(task?.state?.status) || task?.status;
|
|
1348
|
+
if (status === 'closed' || status === 'archived') {
|
|
1349
|
+
finish({
|
|
1350
|
+
ok: false,
|
|
1351
|
+
command: 'set-active',
|
|
1352
|
+
errors: [`Cannot set closed task "${taskId}" as active focus.`],
|
|
1353
|
+
warnings: [],
|
|
1354
|
+
operations: [],
|
|
1355
|
+
}, 1);
|
|
1356
|
+
}
|
|
1357
|
+
const openManagedTasks = tasks.filter(item => {
|
|
1358
|
+
const itemStatus = normalizeStatus(item.state?.status) || item.status;
|
|
1359
|
+
return isWfManagedMode(item.state?.mode) && OPEN_TASK_STATUSES.has(itemStatus);
|
|
1360
|
+
});
|
|
1361
|
+
if (openManagedTasks.length > 0 && !isWfManagedMode(task?.state?.mode)) {
|
|
1362
|
+
finish({
|
|
1363
|
+
ok: false,
|
|
1364
|
+
command: 'set-active',
|
|
1365
|
+
errors: [`Direct task "${taskId}" cannot replace an open WF-managed focus; close the WF task or focus another WF task.`],
|
|
1366
|
+
warnings: [],
|
|
1367
|
+
operations: [],
|
|
1368
|
+
}, 1);
|
|
1369
|
+
}
|
|
925
1370
|
const previousApply = hasFlag('--apply');
|
|
926
1371
|
if (!previousApply && !hasFlag('--dry-run')) args.push('--apply');
|
|
927
1372
|
runReconcile({ activeOverride: taskId, commandLabel: 'set-active' });
|
|
@@ -959,11 +1404,23 @@ function buildArchivePlan() {
|
|
|
959
1404
|
}
|
|
960
1405
|
}
|
|
961
1406
|
|
|
1407
|
+
const groupFilter = flagValue('--group');
|
|
1408
|
+
if (taskFilter && groupFilter) {
|
|
1409
|
+
return { ok: false, command: 'archive', errors: ['archive accepts either --task <id> or --group <tag>, not both'], warnings: [], results: [] };
|
|
1410
|
+
}
|
|
1411
|
+
|
|
962
1412
|
const { rootProgress, tasks } = collectTasks();
|
|
963
|
-
const selectedTasks = taskFilter
|
|
1413
|
+
const selectedTasks = taskFilter
|
|
1414
|
+
? tasks.filter(task => task.id === taskFilter)
|
|
1415
|
+
: groupFilter
|
|
1416
|
+
? tasks.filter(task => taskGroupFor(task.state) === groupFilter)
|
|
1417
|
+
: tasks;
|
|
964
1418
|
if (taskFilter && selectedTasks.length === 0) {
|
|
965
1419
|
return { ok: false, command: 'archive', errors: [`Task "${taskFilter}" not found in Harness/tasks/`], warnings: [], results: [] };
|
|
966
1420
|
}
|
|
1421
|
+
if (groupFilter && selectedTasks.length === 0) {
|
|
1422
|
+
return { ok: false, command: 'archive', errors: [`Group "${groupFilter}" not found in Harness/tasks/`], warnings: [], results: [] };
|
|
1423
|
+
}
|
|
967
1424
|
|
|
968
1425
|
const archiveable = [];
|
|
969
1426
|
const skipped = [];
|
|
@@ -974,13 +1431,14 @@ function buildArchivePlan() {
|
|
|
974
1431
|
}
|
|
975
1432
|
|
|
976
1433
|
const dryRun = !hasFlag('--apply');
|
|
977
|
-
const explicitTrigger = dryRun === false && !taskFilter;
|
|
1434
|
+
const explicitTrigger = dryRun === false && !taskFilter && !groupFilter;
|
|
978
1435
|
archiveable.sort((a, b) => a.mtimeMs - b.mtimeMs || a.id.localeCompare(b.id));
|
|
979
1436
|
|
|
980
|
-
// Explicit user trigger (no --task filter, with --apply): archive ALL eligible tasks.
|
|
1437
|
+
// Explicit user trigger (no --task/--group filter, with --apply): archive ALL eligible tasks.
|
|
981
1438
|
// Explicit --task targets the selected eligible task in both dry-run and apply.
|
|
1439
|
+
// Explicit --group is a batch op that archives every eligible task in the tag (implies apply).
|
|
982
1440
|
// Auto/scheduled/dry-run: only archive tasks exceeding --keep cap.
|
|
983
|
-
const toArchiveCount = taskFilter
|
|
1441
|
+
const toArchiveCount = taskFilter || groupFilter
|
|
984
1442
|
? archiveable.length
|
|
985
1443
|
: explicitTrigger
|
|
986
1444
|
? archiveable.length
|
|
@@ -1019,8 +1477,8 @@ function buildArchivePlan() {
|
|
|
1019
1477
|
...dateParts(task.mtimeMs),
|
|
1020
1478
|
action: hasFlag('--apply') ? 'archived' : 'would-archive',
|
|
1021
1479
|
status: hasFlag('--apply')
|
|
1022
|
-
? (explicitTrigger ? 'explicit --apply: all eligible' : 'moved')
|
|
1023
|
-
: (taskFilter ? 'dry-run' : `dry-run (${toArchiveCount} of ${archiveable.length} eligible)`),
|
|
1480
|
+
? (groupFilter ? `group "${groupFilter}": batch archive` : explicitTrigger ? 'explicit --apply: all eligible' : 'moved')
|
|
1481
|
+
: (taskFilter ? 'dry-run' : groupFilter ? `dry-run (group "${groupFilter}")` : `dry-run (${toArchiveCount} of ${archiveable.length} eligible)`),
|
|
1024
1482
|
})),
|
|
1025
1483
|
...keptArchiveable.map(task => ({
|
|
1026
1484
|
dir: task.id,
|
|
@@ -1043,6 +1501,7 @@ function buildArchivePlan() {
|
|
|
1043
1501
|
ok: true,
|
|
1044
1502
|
command: 'archive',
|
|
1045
1503
|
dryRun: !hasFlag('--apply'),
|
|
1504
|
+
group: groupFilter || null,
|
|
1046
1505
|
keep: keepValue,
|
|
1047
1506
|
scanned: selectedTasks.length,
|
|
1048
1507
|
archiveable: archiveable.length,
|
|
@@ -1247,6 +1706,8 @@ function appendArchiveIndex(entries, graphContent) {
|
|
|
1247
1706
|
}
|
|
1248
1707
|
|
|
1249
1708
|
function runArchive() {
|
|
1709
|
+
// --group is a confirmation-less batch op: it implies --apply unless --dry-run is given.
|
|
1710
|
+
if (hasFlag('--group') && !hasFlag('--apply') && !hasFlag('--dry-run')) args.push('--apply');
|
|
1250
1711
|
const plan = buildArchivePlan();
|
|
1251
1712
|
if (!plan.ok) finish(plan, 1);
|
|
1252
1713
|
|
|
@@ -1279,6 +1740,7 @@ function runArchive() {
|
|
|
1279
1740
|
const rows = buildRows(plan.tasks, plan.rootProgress.activeTask, plan.toArchiveIds);
|
|
1280
1741
|
const desiredProgress = renderRootProgress(plan.rootProgress.text, plan.rootProgress.activeTask, rows);
|
|
1281
1742
|
writeTextAtomic(progressPath, desiredProgress);
|
|
1743
|
+
writeTaskIndex();
|
|
1282
1744
|
plan.dryRun = false;
|
|
1283
1745
|
}
|
|
1284
1746
|
|
|
@@ -1424,7 +1886,11 @@ function runRecord() {
|
|
|
1424
1886
|
|
|
1425
1887
|
const text = flagValue('--text');
|
|
1426
1888
|
const statusRaw = flagValue('--status');
|
|
1889
|
+
const phaseRaw = flagValue('--phase');
|
|
1427
1890
|
const modeRaw = flagValue('--mode');
|
|
1891
|
+
const groupRaw = flagValue('--group');
|
|
1892
|
+
const projectRaw = flagValue('--project');
|
|
1893
|
+
const tagsRaw = flagValue('--tag') || flagValue('--tags');
|
|
1428
1894
|
|
|
1429
1895
|
if (!existing.state && isCreate) {
|
|
1430
1896
|
const now = new Date().toISOString();
|
|
@@ -1435,20 +1901,31 @@ function runRecord() {
|
|
|
1435
1901
|
return;
|
|
1436
1902
|
}
|
|
1437
1903
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
const newState = defaultState(taskId, status, 'intake', now);
|
|
1441
|
-
newState.mode = mode;
|
|
1442
|
-
if (text) newState.nextAction = text;
|
|
1443
|
-
if (modeRaw) {
|
|
1444
|
-
const normalizedMode = normalizeMode(modeRaw);
|
|
1445
|
-
if (!normalizedMode) {
|
|
1446
|
-
finish({ ok: false, command: 'record', errors: [`Invalid mode "${modeRaw}". Valid: ${[...VALID_MODES].join(', ')}`], warnings: [] }, 1);
|
|
1904
|
+
if (phaseRaw && !normalizePhase(phaseRaw)) {
|
|
1905
|
+
finish({ ok: false, command: 'record', errors: [`Invalid phase "${phaseRaw}". Valid: ${[...VALID_PHASES].join(', ')}`], warnings: [] }, 1);
|
|
1447
1906
|
return;
|
|
1448
1907
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1908
|
+
const status = statusRaw ? normalizeStatus(statusRaw) : 'active';
|
|
1909
|
+
let mode = 'direct';
|
|
1910
|
+
if (modeRaw) {
|
|
1911
|
+
const normalizedMode = normalizeMode(modeRaw);
|
|
1912
|
+
if (!normalizedMode) {
|
|
1913
|
+
finish({ ok: false, command: 'record', errors: [`Invalid mode "${modeRaw}". Valid: ${[...VALID_MODES].join(', ')}`], warnings: [] }, 1);
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
mode = normalizedMode;
|
|
1917
|
+
}
|
|
1918
|
+
const phase = phaseRaw ? normalizePhase(phaseRaw) : 'intake';
|
|
1919
|
+
const newState = defaultState(taskId, status, phase, now);
|
|
1920
|
+
newState.mode = mode;
|
|
1921
|
+
const project = String(projectRaw || groupRaw || '').trim();
|
|
1922
|
+
if (project) {
|
|
1923
|
+
newState.project = project;
|
|
1924
|
+
// Keep the legacy key populated for older Harness readers.
|
|
1925
|
+
newState.group = project;
|
|
1926
|
+
}
|
|
1927
|
+
if (tagsRaw) newState.tags = normalizeTags(tagsRaw);
|
|
1928
|
+
if (text) newState.nextAction = text;
|
|
1452
1929
|
const templateState = readTemplateState();
|
|
1453
1930
|
if (templateState) {
|
|
1454
1931
|
if (Array.isArray(templateState.acceptance)) newState.acceptance = [...templateState.acceptance];
|
|
@@ -1480,8 +1957,12 @@ function runRecord() {
|
|
|
1480
1957
|
const newRow = { id: taskId, goal: text || taskTitle(taskId), phase: displayPhase('intake'), closed: '-' };
|
|
1481
1958
|
parsed.rows.push(newRow);
|
|
1482
1959
|
const rows = parsed.rows.map(r => ({ id: r.id, goal: r.goal, phase: r.phase, closed: r.closed }));
|
|
1483
|
-
const
|
|
1960
|
+
const newActiveTask = isWfManagedMode(newState.mode) && OPEN_TASK_STATUSES.has(newState.status)
|
|
1961
|
+
? taskId
|
|
1962
|
+
: parsed.activeTask;
|
|
1963
|
+
const newRoot = renderRootProgress(rootText, newActiveTask, rows);
|
|
1484
1964
|
writeTextAtomic(progressPath, newRoot);
|
|
1965
|
+
writeTaskIndex();
|
|
1485
1966
|
}
|
|
1486
1967
|
|
|
1487
1968
|
finish({
|
|
@@ -1499,9 +1980,36 @@ function runRecord() {
|
|
|
1499
1980
|
if (existing.state) {
|
|
1500
1981
|
const now = new Date().toISOString();
|
|
1501
1982
|
const updated = { ...existing.state };
|
|
1983
|
+
if (!updated.createdAt) updated.createdAt = updated.updatedAt || now;
|
|
1984
|
+
if (!Object.prototype.hasOwnProperty.call(updated, 'startedAt')) updated.startedAt = null;
|
|
1985
|
+
if (!Object.prototype.hasOwnProperty.call(updated, 'closedAt')) updated.closedAt = null;
|
|
1502
1986
|
updated.updatedAt = now;
|
|
1503
1987
|
if (!updated.defaultRuntime) updated.defaultRuntime = defaultTaskRuntime();
|
|
1504
1988
|
if (!updated.defaultAgentRuntime) updated.defaultAgentRuntime = updated.defaultRuntime;
|
|
1989
|
+
const currentMode = normalizeMode(updated.mode) || 'direct';
|
|
1990
|
+
const currentStatus = normalizeStatus(updated.status) || 'active';
|
|
1991
|
+
if (modeRaw) {
|
|
1992
|
+
const normalizedMode = normalizeMode(modeRaw);
|
|
1993
|
+
if (!normalizedMode) {
|
|
1994
|
+
finish({ ok: false, command: 'record', errors: [`Invalid mode "${modeRaw}". Valid: ${[...VALID_MODES].join(', ')}`], warnings: [] }, 1);
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
if (currentMode === 'direct' && isWfManagedMode(normalizedMode)) {
|
|
1998
|
+
finish({ ok: false, command: 'record', errors: [`Direct task "${taskId}" cannot be promoted into WF-managed lifecycle; create a new task with --mode ${normalizedMode}.`], warnings: [] }, 1);
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
if (isWfManagedMode(currentMode) && normalizedMode !== currentMode) {
|
|
2002
|
+
finish({ ok: false, command: 'record', errors: [`WF-managed task "${taskId}" cannot downgrade or exit WF lifecycle; close it and create a new task.`], warnings: [] }, 1);
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
if (isWfManagedMode(currentMode) && currentStatus === 'closed' && statusRaw) {
|
|
2007
|
+
const requestedStatus = normalizeStatus(statusRaw);
|
|
2008
|
+
if (requestedStatus && requestedStatus !== 'closed') {
|
|
2009
|
+
finish({ ok: false, command: 'record', errors: [`Closed WF-managed task "${taskId}" cannot be reopened; create a new task capsule.`], warnings: [] }, 1);
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
1505
2013
|
if (statusRaw) {
|
|
1506
2014
|
const ns = normalizeStatus(statusRaw);
|
|
1507
2015
|
if (!ns) {
|
|
@@ -1510,18 +2018,30 @@ function runRecord() {
|
|
|
1510
2018
|
}
|
|
1511
2019
|
updated.status = ns;
|
|
1512
2020
|
}
|
|
1513
|
-
if (
|
|
1514
|
-
const
|
|
1515
|
-
if (!
|
|
1516
|
-
finish({ ok: false, command: 'record', errors: [`Invalid
|
|
2021
|
+
if (phaseRaw) {
|
|
2022
|
+
const normalizedPhase = normalizePhase(phaseRaw);
|
|
2023
|
+
if (!normalizedPhase) {
|
|
2024
|
+
finish({ ok: false, command: 'record', errors: [`Invalid phase "${phaseRaw}". Valid: ${[...VALID_PHASES].join(', ')}`], warnings: [] }, 1);
|
|
1517
2025
|
return;
|
|
1518
2026
|
}
|
|
1519
|
-
updated.
|
|
2027
|
+
updated.phase = normalizedPhase;
|
|
2028
|
+
}
|
|
2029
|
+
if (modeRaw) updated.mode = normalizeMode(modeRaw);
|
|
2030
|
+
const project = String(projectRaw || groupRaw || '').trim();
|
|
2031
|
+
if (project) {
|
|
2032
|
+
updated.project = project;
|
|
2033
|
+
updated.group = project;
|
|
1520
2034
|
}
|
|
2035
|
+
if (tagsRaw) updated.tags = normalizeTags(tagsRaw);
|
|
1521
2036
|
if (text) updated.nextAction = text;
|
|
1522
2037
|
|
|
2038
|
+
if (updated.status === 'active' && !updated.startedAt) updated.startedAt = now;
|
|
2039
|
+
if (updated.status === 'closed' && !updated.closedAt) updated.closedAt = now;
|
|
2040
|
+
if (updated.status !== 'closed') updated.closedAt = null;
|
|
2041
|
+
|
|
1523
2042
|
if (actuallyApply) {
|
|
1524
2043
|
writeJsonAtomic(existing.path, updated);
|
|
2044
|
+
syncTaskViewsForState(taskId, updated);
|
|
1525
2045
|
}
|
|
1526
2046
|
|
|
1527
2047
|
finish({
|
|
@@ -1539,14 +2059,31 @@ function runRecord() {
|
|
|
1539
2059
|
|
|
1540
2060
|
function runOpen() {
|
|
1541
2061
|
const { rootProgress, tasks } = collectTasks();
|
|
2062
|
+
const projectFilter = flagValue('--project') || flagValue('--group');
|
|
2063
|
+
const statusFilter = flagValue('--status');
|
|
2064
|
+
const normalizedStatusFilter = statusFilter ? normalizeStatus(statusFilter) : null;
|
|
2065
|
+
if (statusFilter && !normalizedStatusFilter) {
|
|
2066
|
+
finish({
|
|
2067
|
+
ok: false,
|
|
2068
|
+
command: 'open',
|
|
2069
|
+
errors: [`Invalid status filter "${statusFilter}". Valid: active, blocked (legacy aliases accepted)`],
|
|
2070
|
+
warnings: [],
|
|
2071
|
+
tasks: [],
|
|
2072
|
+
}, 1);
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
1542
2075
|
|
|
1543
2076
|
const openTasks = tasks.filter(task => {
|
|
1544
2077
|
const status = normalizeStatus(task.state?.status) || task.status;
|
|
1545
|
-
|
|
2078
|
+
if (!OPEN_TASK_STATUSES.has(status)) return false;
|
|
2079
|
+
if (projectFilter && taskProjectFor(task.state) !== projectFilter) return false;
|
|
2080
|
+
if (normalizedStatusFilter && status !== normalizedStatusFilter) return false;
|
|
2081
|
+
return true;
|
|
1546
2082
|
}).map(task => {
|
|
1547
2083
|
const state = task.state || {};
|
|
1548
2084
|
const links = state.links || {};
|
|
1549
2085
|
const status = normalizeStatus(state.status) || task.status;
|
|
2086
|
+
const lifecycle = lifecycleForState(state, status);
|
|
1550
2087
|
const dependsOn = Array.isArray(links.dependsOn) ? links.dependsOn : [];
|
|
1551
2088
|
const openDepTasks = dependsOn.filter(depId => {
|
|
1552
2089
|
const depTask = tasks.find(t => t.id === depId);
|
|
@@ -1556,8 +2093,17 @@ function runOpen() {
|
|
|
1556
2093
|
});
|
|
1557
2094
|
return {
|
|
1558
2095
|
id: task.id,
|
|
2096
|
+
project: taskProjectFor(state),
|
|
2097
|
+
group: taskProjectFor(state),
|
|
1559
2098
|
status,
|
|
2099
|
+
mode: lifecycle.mode,
|
|
2100
|
+
wfManaged: lifecycle.wfManaged,
|
|
2101
|
+
resumeRequired: lifecycle.resumeRequired,
|
|
1560
2102
|
phase: normalizePhase(state.phase) || task.phase,
|
|
2103
|
+
createdAt: state.createdAt || null,
|
|
2104
|
+
startedAt: state.startedAt || null,
|
|
2105
|
+
updatedAt: state.updatedAt || null,
|
|
2106
|
+
closedAt: state.closedAt || null,
|
|
1561
2107
|
dependsOn,
|
|
1562
2108
|
blocks: Array.isArray(links.blocks) ? links.blocks : [],
|
|
1563
2109
|
blockedByOpenDeps: openDepTasks,
|
|
@@ -1570,6 +2116,8 @@ function runOpen() {
|
|
|
1570
2116
|
finish({
|
|
1571
2117
|
ok: true,
|
|
1572
2118
|
command: 'open',
|
|
2119
|
+
projectFilter: projectFilter || null,
|
|
2120
|
+
statusFilter: normalizedStatusFilter,
|
|
1573
2121
|
taskCount: openTasks.length,
|
|
1574
2122
|
tasks: openTasks,
|
|
1575
2123
|
errors: [],
|
|
@@ -1781,32 +2329,48 @@ function runHistoryDelete() {
|
|
|
1781
2329
|
}
|
|
1782
2330
|
}
|
|
1783
2331
|
|
|
2332
|
+
export {
|
|
2333
|
+
readTaskState,
|
|
2334
|
+
writeTaskStateAtomic,
|
|
2335
|
+
taskPathsForProject,
|
|
2336
|
+
writeTextAtomic,
|
|
2337
|
+
writeJsonAtomic,
|
|
2338
|
+
};
|
|
2339
|
+
|
|
1784
2340
|
// ---- dispatch ----
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
if (
|
|
1790
|
-
if (command === '
|
|
1791
|
-
if (command === '
|
|
1792
|
-
if (command === '
|
|
1793
|
-
if (command === '
|
|
1794
|
-
if (command === '
|
|
1795
|
-
|
|
1796
|
-
if (
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
2341
|
+
// Keep imports side-effect free so runtime workers can reuse the canonical
|
|
2342
|
+
// reader/writer without accidentally running the task-state CLI.
|
|
2343
|
+
const isMain = process.argv[1]
|
|
2344
|
+
&& path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
|
|
2345
|
+
if (isMain) {
|
|
2346
|
+
if (command === 'help' || hasFlag('--help') || hasFlag('-h')) usage();
|
|
2347
|
+
if (command === 'list') runList();
|
|
2348
|
+
if (command === 'index') runIndex();
|
|
2349
|
+
if (command === 'query') runQuery();
|
|
2350
|
+
if (command === 'validate') runValidate();
|
|
2351
|
+
if (command === 'reconcile') runReconcile();
|
|
2352
|
+
if (command === 'set-active') runSetActive();
|
|
2353
|
+
if (command === 'transition') runTransition();
|
|
2354
|
+
if (command === 'archive') runArchive();
|
|
2355
|
+
if (command === 'record') runRecord();
|
|
2356
|
+
if (command === 'open') runOpen();
|
|
2357
|
+
if (command === 'history') {
|
|
2358
|
+
const sub = args[1];
|
|
2359
|
+
if (sub === 'list') runHistoryList();
|
|
2360
|
+
else if (sub === 'search') runHistorySearch();
|
|
2361
|
+
else if (sub === 'load') runHistoryLoad();
|
|
2362
|
+
else if (sub === 'delete') runHistoryDelete();
|
|
2363
|
+
else finish({
|
|
2364
|
+
ok: false, command: 'history',
|
|
2365
|
+
errors: [`Unknown history subcommand "${sub}". Try: list, search <kw>, load <id>, delete <id>`],
|
|
2366
|
+
warnings: [],
|
|
2367
|
+
}, 1);
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
finish({
|
|
2371
|
+
ok: false,
|
|
2372
|
+
command,
|
|
2373
|
+
errors: [`Unknown command "${command}". Run node Harness/scripts/task-state.mjs --help.`],
|
|
1803
2374
|
warnings: [],
|
|
1804
2375
|
}, 1);
|
|
1805
2376
|
}
|
|
1806
|
-
|
|
1807
|
-
finish({
|
|
1808
|
-
ok: false,
|
|
1809
|
-
command,
|
|
1810
|
-
errors: [`Unknown command "${command}". Run node Harness/scripts/task-state.mjs --help.`],
|
|
1811
|
-
warnings: [],
|
|
1812
|
-
}, 1);
|