@openflowjs/cli 0.2.0
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/dist/bin/openflow.d.ts +2 -0
- package/dist/bin/openflow.js +8 -0
- package/dist/bin/openflow.js.map +1 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +38 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/flow.d.ts +1 -0
- package/dist/commands/flow.js +119 -0
- package/dist/commands/flow.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +1082 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/iteration.d.ts +1 -0
- package/dist/commands/iteration.js +131 -0
- package/dist/commands/iteration.js.map +1 -0
- package/dist/commands/mcp.d.ts +1 -0
- package/dist/commands/mcp.js +12 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/module.d.ts +1 -0
- package/dist/commands/module.js +137 -0
- package/dist/commands/module.js.map +1 -0
- package/dist/commands/plan.d.ts +1 -0
- package/dist/commands/plan.js +111 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/plugin.d.ts +1 -0
- package/dist/commands/plugin.js +246 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/preflight.d.ts +8 -0
- package/dist/commands/preflight.js +57 -0
- package/dist/commands/preflight.js.map +1 -0
- package/dist/commands/review.d.ts +1 -0
- package/dist/commands/review.js +145 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/state.d.ts +1 -0
- package/dist/commands/state.js +28 -0
- package/dist/commands/state.js.map +1 -0
- package/dist/commands/validate.d.ts +1 -0
- package/dist/commands/validate.js +310 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/core/artifacts.d.ts +140 -0
- package/dist/core/artifacts.js +809 -0
- package/dist/core/artifacts.js.map +1 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/index.js +27 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core-artifacts/marketplace.json +14 -0
- package/dist/core-artifacts/modules.json +20 -0
- package/dist/core-artifacts/openflow/.claude-plugin/plugin.json +8 -0
- package/dist/core-artifacts/openflow/.mcp.json +9 -0
- package/dist/core-artifacts/openflow/agents/openflow-artifact-reviewer.md +308 -0
- package/dist/core-artifacts/openflow/agents/openflow-code-reviewer.md +177 -0
- package/dist/core-artifacts/openflow/agents/openflow-executor-deep.md +119 -0
- package/dist/core-artifacts/openflow/agents/openflow-executor-general.md +104 -0
- package/dist/core-artifacts/openflow/agents/openflow-executor-quick.md +93 -0
- package/dist/core-artifacts/openflow/agents/openflow-explorer.md +69 -0
- package/dist/core-artifacts/openflow/agents/openflow-knowledge-curator.md +89 -0
- package/dist/core-artifacts/openflow/commands/knowledge.md +102 -0
- package/dist/core-artifacts/openflow/hooks/hooks.json +33 -0
- package/dist/core-artifacts/openflow/scripts/openflow-drift-guard.cjs +54 -0
- package/dist/core-artifacts/openflow/scripts/openflow-evidence-reminder.cjs +64 -0
- package/dist/core-artifacts/openflow/scripts/openflow-mcp-review.cjs +27 -0
- package/dist/core-artifacts/openflow/scripts/openflow-write-guard.cjs +27 -0
- package/dist/core-artifacts/openflow/scripts/session-start.cjs +12 -0
- package/dist/core-artifacts/openflow/skills/brainstorm/SKILL.md +131 -0
- package/dist/core-artifacts/openflow/skills/cli-reference/SKILL.md +196 -0
- package/dist/core-artifacts/openflow/skills/finalize/SKILL.md +109 -0
- package/dist/core-artifacts/openflow/skills/finalize/references/summary-template.md +39 -0
- package/dist/core-artifacts/openflow/skills/implement/SKILL.md +296 -0
- package/dist/core-artifacts/openflow/skills/implement/references/working-memory.md +49 -0
- package/dist/core-artifacts/openflow/skills/knowledge-retrieval/SKILL.md +78 -0
- package/dist/core-artifacts/openflow/skills/prd/SKILL.md +173 -0
- package/dist/core-artifacts/openflow/skills/prd/references/level-routing.md +94 -0
- package/dist/core-artifacts/openflow/skills/prd/references/prd-template.md +187 -0
- package/dist/core-artifacts/openflow/skills/prd/references/wireframe-template.html +122 -0
- package/dist/core-artifacts/openflow/skills/spec/SKILL.md +341 -0
- package/dist/core-artifacts/openflow/skills/spec/references/context-template.md +38 -0
- package/dist/core-artifacts/openflow/skills/spec/references/plan-template.md +61 -0
- package/dist/core-artifacts/openflow/skills/spec/references/spec-template.md +187 -0
- package/dist/core-artifacts/openflow/skills/spec/references/tasks-template.md +99 -0
- package/dist/core-artifacts/openflow/skills/workflow-governance/SKILL.md +384 -0
- package/dist/core-artifacts/openflow/skills/workflow-governance/references/knowledge-schema.md +241 -0
- package/dist/core-artifacts/openflow/skills/workflow-governance/references/state-files.md +148 -0
- package/dist/core-artifacts/openflow/skills/workflow-governance/references/workflow.md +119 -0
- package/dist/core-artifacts/templates/.gitkeep +0 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/review-mcp-server.d.ts +1 -0
- package/dist/mcp/review-mcp-server.js +191 -0
- package/dist/mcp/review-mcp-server.js.map +1 -0
- package/dist/mcp/review-server.d.ts +33 -0
- package/dist/mcp/review-server.js +340 -0
- package/dist/mcp/review-server.js.map +1 -0
- package/dist/mcp/review-ui/assets/arc-DH58vMfF.js +1 -0
- package/dist/mcp/review-ui/assets/architecture-YZFGNWBL-CW8o5JQi.js +1 -0
- package/dist/mcp/review-ui/assets/architectureDiagram-Q4EWVU46-CH35GquJ.js +36 -0
- package/dist/mcp/review-ui/assets/array-BCJ35G43.js +1 -0
- package/dist/mcp/review-ui/assets/blockDiagram-DXYQGD6D-B1JZnKG_.js +132 -0
- package/dist/mcp/review-ui/assets/c4Diagram-AHTNJAMY-DCAtnxWd.js +10 -0
- package/dist/mcp/review-ui/assets/channel-BgHR4NPf.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-2KRD3SAO-BkEfK915.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-4BX2VUAB-Dn9kswJO.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-4TB4RGXK-DbeI3ZO6.js +206 -0
- package/dist/mcp/review-ui/assets/chunk-55IACEB6-CLBoivXU.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-5FUZZQ4R-DU7La6QA.js +62 -0
- package/dist/mcp/review-ui/assets/chunk-5PVQY5BW-Dy3eUu9a.js +2 -0
- package/dist/mcp/review-ui/assets/chunk-67CJDMHE-BKQ4iYAM.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-7N4EOEYR-CUngSlME.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-AA7GKIK3-BClDbXxt.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-BSJP7CBP-BlpmbHL-.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-CIAEETIT-THpBXcoN.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-Dlc7tRH4.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-EDXVE4YY-DNUlHz7M.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-ENJZ2VHE-fwEKj0pQ.js +10 -0
- package/dist/mcp/review-ui/assets/chunk-FMBD7UC4-Cj8B2TLo.js +15 -0
- package/dist/mcp/review-ui/assets/chunk-FOC6F5B3-BtR_JW_A.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-ICPOFSXX-WTr3HDYE.js +122 -0
- package/dist/mcp/review-ui/assets/chunk-K5T4RW27-vtP3ehR7.js +94 -0
- package/dist/mcp/review-ui/assets/chunk-KGLVRYIC-Di2tkB7O.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-LIHQZDEY-DoHl9hYE.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-ORNJ4GCN-Bff-Vc2X.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-OYMX7WX6-Djey8TrX.js +231 -0
- package/dist/mcp/review-ui/assets/chunk-QZHKN3VN-C4w1Z4n9.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-U2HBQHQK-D8HUikvJ.js +70 -0
- package/dist/mcp/review-ui/assets/chunk-X2U36JSP-CuZ-SN2r.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-YZCP3GAM-D0-dHF3G.js +1 -0
- package/dist/mcp/review-ui/assets/chunk-ZZ45TVLE-C1aIZGDA.js +1 -0
- package/dist/mcp/review-ui/assets/classDiagram-6PBFFD2Q-DHrSK7zx.js +1 -0
- package/dist/mcp/review-ui/assets/classDiagram-v2-HSJHXN6E-ftN8ECVk.js +1 -0
- package/dist/mcp/review-ui/assets/clone-C3rjhi9V.js +1 -0
- package/dist/mcp/review-ui/assets/cose-bilkent-S5V4N54A-szpqu_3d.js +1 -0
- package/dist/mcp/review-ui/assets/cytoscape.esm-DZ22BVwz.js +321 -0
- package/dist/mcp/review-ui/assets/dagre-B4oIQbi5.js +1 -0
- package/dist/mcp/review-ui/assets/dagre-KV5264BT-zDsxU5-B.js +4 -0
- package/dist/mcp/review-ui/assets/defaultLocale-CIS5GEjP.js +1 -0
- package/dist/mcp/review-ui/assets/diagram-5BDNPKRD-UgfFjZ4o.js +10 -0
- package/dist/mcp/review-ui/assets/diagram-G4DWMVQ6-Wh9VCn50.js +24 -0
- package/dist/mcp/review-ui/assets/diagram-MMDJMWI5-xVD3G7_9.js +43 -0
- package/dist/mcp/review-ui/assets/diagram-TYMM5635-AUD291P2.js +24 -0
- package/dist/mcp/review-ui/assets/dist-B51l2n-9.js +1 -0
- package/dist/mcp/review-ui/assets/erDiagram-SMLLAGMA-B83D6NXm.js +85 -0
- package/dist/mcp/review-ui/assets/flatten-B80WBwOJ.js +1 -0
- package/dist/mcp/review-ui/assets/flowDiagram-DWJPFMVM-D3lXOeHD.js +162 -0
- package/dist/mcp/review-ui/assets/ganttDiagram-T4ZO3ILL-CFAN903o.js +292 -0
- package/dist/mcp/review-ui/assets/gitGraph-7Q5UKJZL-BfgkNWmC.js +1 -0
- package/dist/mcp/review-ui/assets/gitGraphDiagram-UUTBAWPF-DxqTOi4I.js +106 -0
- package/dist/mcp/review-ui/assets/graphlib-De-foo_H.js +1 -0
- package/dist/mcp/review-ui/assets/identity-CWMh0UL-.js +1 -0
- package/dist/mcp/review-ui/assets/index-Do0fBEfH.css +2 -0
- package/dist/mcp/review-ui/assets/index-uPMLqduV.js +123 -0
- package/dist/mcp/review-ui/assets/info-OMHHGYJF-DE18zZ5Z.js +1 -0
- package/dist/mcp/review-ui/assets/infoDiagram-42DDH7IO-Bnco1OGr.js +2 -0
- package/dist/mcp/review-ui/assets/init-BMBYmmUa.js +1 -0
- package/dist/mcp/review-ui/assets/ishikawaDiagram-UXIWVN3A-B89fugr9.js +70 -0
- package/dist/mcp/review-ui/assets/journeyDiagram-VCZTEJTY-CMx2w_is.js +139 -0
- package/dist/mcp/review-ui/assets/kanban-definition-6JOO6SKY-YvTOD1Vd.js +89 -0
- package/dist/mcp/review-ui/assets/katex-8mXVa4k3.js +257 -0
- package/dist/mcp/review-ui/assets/line-BCdBO-oK.js +1 -0
- package/dist/mcp/review-ui/assets/linear-d7UHSQqm.js +1 -0
- package/dist/mcp/review-ui/assets/mermaid-parser.core-DI1-3xL2.js +4 -0
- package/dist/mcp/review-ui/assets/mindmap-definition-QFDTVHPH-E_mV-_Fs.js +96 -0
- package/dist/mcp/review-ui/assets/ordinal-BDTCIhXR.js +1 -0
- package/dist/mcp/review-ui/assets/packet-4T2RLAQJ-BLPGKWDX.js +1 -0
- package/dist/mcp/review-ui/assets/path-CIRGLb_6.js +1 -0
- package/dist/mcp/review-ui/assets/pie-ZZUOXDRM-DVV6Yua9.js +1 -0
- package/dist/mcp/review-ui/assets/pieDiagram-DEJITSTG-Ct4JvywP.js +30 -0
- package/dist/mcp/review-ui/assets/quadrantDiagram-34T5L4WZ-BSFYvc1U.js +7 -0
- package/dist/mcp/review-ui/assets/radar-PYXPWWZC-BMkQDLKp.js +1 -0
- package/dist/mcp/review-ui/assets/reduce-C80XcylQ.js +1 -0
- package/dist/mcp/review-ui/assets/requirementDiagram-MS252O5E-Bp7uSYEK.js +84 -0
- package/dist/mcp/review-ui/assets/rough.esm-DtEqI08j.js +1 -0
- package/dist/mcp/review-ui/assets/sankeyDiagram-XADWPNL6-CV38ZpSv.js +10 -0
- package/dist/mcp/review-ui/assets/sequenceDiagram-FGHM5R23-BXN9jl1N.js +157 -0
- package/dist/mcp/review-ui/assets/src-Cxc1bu7b.js +1 -0
- package/dist/mcp/review-ui/assets/stateDiagram-FHFEXIEX-DZduDkIw.js +1 -0
- package/dist/mcp/review-ui/assets/stateDiagram-v2-QKLJ7IA2-xAWOcxSi.js +1 -0
- package/dist/mcp/review-ui/assets/timeline-definition-GMOUNBTQ-CLqXzNm8.js +120 -0
- package/dist/mcp/review-ui/assets/treeView-SZITEDCU-tPcANHUc.js +1 -0
- package/dist/mcp/review-ui/assets/treemap-W4RFUUIX-BGbXISSk.js +1 -0
- package/dist/mcp/review-ui/assets/vennDiagram-DHZGUBPP-gCnd0IYN.js +34 -0
- package/dist/mcp/review-ui/assets/wardley-RL74JXVD-CK3EfklM.js +1 -0
- package/dist/mcp/review-ui/assets/wardleyDiagram-NUSXRM2D-Dd7qMlPS.js +20 -0
- package/dist/mcp/review-ui/assets/xychartDiagram-5P7HB3ND-DXHXO8Zm.js +7 -0
- package/dist/mcp/review-ui/index.html +29 -0
- package/dist/mcp/studio/assets/arc-DH58vMfF.js +1 -0
- package/dist/mcp/studio/assets/architecture-YZFGNWBL-8xrwD39F.js +1 -0
- package/dist/mcp/studio/assets/architectureDiagram-Q4EWVU46-VmcLZTJf.js +36 -0
- package/dist/mcp/studio/assets/array-BCJ35G43.js +1 -0
- package/dist/mcp/studio/assets/blockDiagram-DXYQGD6D-D-1mlLYy.js +132 -0
- package/dist/mcp/studio/assets/c4Diagram-AHTNJAMY-DCAtnxWd.js +10 -0
- package/dist/mcp/studio/assets/channel-BgHR4NPf.js +1 -0
- package/dist/mcp/studio/assets/chunk-2KRD3SAO-CMDQx2WD.js +1 -0
- package/dist/mcp/studio/assets/chunk-4BX2VUAB-Dn9kswJO.js +1 -0
- package/dist/mcp/studio/assets/chunk-4TB4RGXK-aFEYGDkJ.js +206 -0
- package/dist/mcp/studio/assets/chunk-55IACEB6-CLBoivXU.js +1 -0
- package/dist/mcp/studio/assets/chunk-5FUZZQ4R-DU7La6QA.js +62 -0
- package/dist/mcp/studio/assets/chunk-5PVQY5BW-Dy3eUu9a.js +2 -0
- package/dist/mcp/studio/assets/chunk-67CJDMHE-DnkyJt7A.js +1 -0
- package/dist/mcp/studio/assets/chunk-7N4EOEYR-cnJ9dWSC.js +1 -0
- package/dist/mcp/studio/assets/chunk-AA7GKIK3-DjCZnyrT.js +1 -0
- package/dist/mcp/studio/assets/chunk-BSJP7CBP-BlpmbHL-.js +1 -0
- package/dist/mcp/studio/assets/chunk-CIAEETIT-CtvXSBsf.js +1 -0
- package/dist/mcp/studio/assets/chunk-Dlc7tRH4.js +1 -0
- package/dist/mcp/studio/assets/chunk-EDXVE4YY-DNUlHz7M.js +1 -0
- package/dist/mcp/studio/assets/chunk-ENJZ2VHE-fwEKj0pQ.js +10 -0
- package/dist/mcp/studio/assets/chunk-FMBD7UC4-Cj8B2TLo.js +15 -0
- package/dist/mcp/studio/assets/chunk-FOC6F5B3-Ca28VADd.js +1 -0
- package/dist/mcp/studio/assets/chunk-ICPOFSXX-WTr3HDYE.js +122 -0
- package/dist/mcp/studio/assets/chunk-K5T4RW27-pqiOLnBn.js +94 -0
- package/dist/mcp/studio/assets/chunk-KGLVRYIC-DZfGlR-G.js +1 -0
- package/dist/mcp/studio/assets/chunk-LIHQZDEY-6Ygb8Kwt.js +1 -0
- package/dist/mcp/studio/assets/chunk-ORNJ4GCN-DSlr7oSO.js +1 -0
- package/dist/mcp/studio/assets/chunk-OYMX7WX6-8z_2lCb3.js +231 -0
- package/dist/mcp/studio/assets/chunk-QZHKN3VN-C4w1Z4n9.js +1 -0
- package/dist/mcp/studio/assets/chunk-U2HBQHQK-D8HUikvJ.js +70 -0
- package/dist/mcp/studio/assets/chunk-X2U36JSP-CuZ-SN2r.js +1 -0
- package/dist/mcp/studio/assets/chunk-YZCP3GAM-D0-dHF3G.js +1 -0
- package/dist/mcp/studio/assets/chunk-ZZ45TVLE-C1aIZGDA.js +1 -0
- package/dist/mcp/studio/assets/classDiagram-6PBFFD2Q-IZXxqxqM.js +1 -0
- package/dist/mcp/studio/assets/classDiagram-v2-HSJHXN6E-BiJKwTXT.js +1 -0
- package/dist/mcp/studio/assets/clone-g4CuF1Hf.js +1 -0
- package/dist/mcp/studio/assets/cose-bilkent-S5V4N54A-szpqu_3d.js +1 -0
- package/dist/mcp/studio/assets/cytoscape.esm-DZ22BVwz.js +321 -0
- package/dist/mcp/studio/assets/dagre-Be9o0OzC.js +1 -0
- package/dist/mcp/studio/assets/dagre-KV5264BT-iB6PnHLr.js +4 -0
- package/dist/mcp/studio/assets/defaultLocale-CIS5GEjP.js +1 -0
- package/dist/mcp/studio/assets/diagram-5BDNPKRD-BLfWbiEB.js +10 -0
- package/dist/mcp/studio/assets/diagram-G4DWMVQ6-CgcnwgVO.js +24 -0
- package/dist/mcp/studio/assets/diagram-MMDJMWI5-CpkXvs2p.js +43 -0
- package/dist/mcp/studio/assets/diagram-TYMM5635-guxqmxjJ.js +24 -0
- package/dist/mcp/studio/assets/dist-B51l2n-9.js +1 -0
- package/dist/mcp/studio/assets/erDiagram-SMLLAGMA-Lwv-cC2Y.js +85 -0
- package/dist/mcp/studio/assets/flatten-Dv3Z_7XJ.js +1 -0
- package/dist/mcp/studio/assets/flowDiagram-DWJPFMVM-BKnaFfFR.js +162 -0
- package/dist/mcp/studio/assets/ganttDiagram-T4ZO3ILL-CFAN903o.js +292 -0
- package/dist/mcp/studio/assets/gitGraph-7Q5UKJZL-BSdEZNVc.js +1 -0
- package/dist/mcp/studio/assets/gitGraphDiagram-UUTBAWPF-D4z4QWni.js +106 -0
- package/dist/mcp/studio/assets/graphlib-C1IZi4Cg.js +1 -0
- package/dist/mcp/studio/assets/identity-CWMh0UL-.js +1 -0
- package/dist/mcp/studio/assets/index-CyBqHDpB.js +109 -0
- package/dist/mcp/studio/assets/index-Dn_Ujmba.css +2 -0
- package/dist/mcp/studio/assets/info-OMHHGYJF-CoTx64p3.js +1 -0
- package/dist/mcp/studio/assets/infoDiagram-42DDH7IO-QEji23sQ.js +2 -0
- package/dist/mcp/studio/assets/init-BMBYmmUa.js +1 -0
- package/dist/mcp/studio/assets/ishikawaDiagram-UXIWVN3A-lMurmqul.js +70 -0
- package/dist/mcp/studio/assets/journeyDiagram-VCZTEJTY-CMx2w_is.js +139 -0
- package/dist/mcp/studio/assets/kanban-definition-6JOO6SKY-DsOybLrS.js +89 -0
- package/dist/mcp/studio/assets/katex-8mXVa4k3.js +257 -0
- package/dist/mcp/studio/assets/line-BCdBO-oK.js +1 -0
- package/dist/mcp/studio/assets/linear-d7UHSQqm.js +1 -0
- package/dist/mcp/studio/assets/mermaid-parser.core-BZtTt4qJ.js +4 -0
- package/dist/mcp/studio/assets/mindmap-definition-QFDTVHPH-B2yfABR9.js +96 -0
- package/dist/mcp/studio/assets/ordinal-BDTCIhXR.js +1 -0
- package/dist/mcp/studio/assets/packet-4T2RLAQJ-Bi4IG7s8.js +1 -0
- package/dist/mcp/studio/assets/path-CIRGLb_6.js +1 -0
- package/dist/mcp/studio/assets/pie-ZZUOXDRM-DsJRjVcu.js +1 -0
- package/dist/mcp/studio/assets/pieDiagram-DEJITSTG-JeKGFs3r.js +30 -0
- package/dist/mcp/studio/assets/quadrantDiagram-34T5L4WZ-BSFYvc1U.js +7 -0
- package/dist/mcp/studio/assets/radar-PYXPWWZC-cUDYP2Ic.js +1 -0
- package/dist/mcp/studio/assets/reduce-x-wchVXY.js +1 -0
- package/dist/mcp/studio/assets/requirementDiagram-MS252O5E-CGeLKQyn.js +84 -0
- package/dist/mcp/studio/assets/rough.esm-DtEqI08j.js +1 -0
- package/dist/mcp/studio/assets/sankeyDiagram-XADWPNL6-CV38ZpSv.js +10 -0
- package/dist/mcp/studio/assets/sequenceDiagram-FGHM5R23-BbHPv3l1.js +157 -0
- package/dist/mcp/studio/assets/src-Cxc1bu7b.js +1 -0
- package/dist/mcp/studio/assets/stateDiagram-FHFEXIEX-BuBuguzn.js +1 -0
- package/dist/mcp/studio/assets/stateDiagram-v2-QKLJ7IA2-PQA-rl9o.js +1 -0
- package/dist/mcp/studio/assets/timeline-definition-GMOUNBTQ-D5xtyNE9.js +120 -0
- package/dist/mcp/studio/assets/treeView-SZITEDCU-DhRx0eaI.js +1 -0
- package/dist/mcp/studio/assets/treemap-W4RFUUIX-Btsj9DUH.js +1 -0
- package/dist/mcp/studio/assets/vennDiagram-DHZGUBPP-W4g15SMY.js +34 -0
- package/dist/mcp/studio/assets/wardley-RL74JXVD-BTpKsgl7.js +1 -0
- package/dist/mcp/studio/assets/wardleyDiagram-NUSXRM2D-f7wgXdwe.js +20 -0
- package/dist/mcp/studio/assets/xychartDiagram-5P7HB3ND-BWx9swPf.js +7 -0
- package/dist/mcp/studio/index.html +29 -0
- package/dist/review-mcp-server.d.ts +1 -0
- package/dist/review-mcp-server.js +178 -0
- package/dist/review-mcp-server.js.map +1 -0
- package/dist/review-server.d.ts +17 -0
- package/dist/review-server.js +223 -0
- package/dist/review-server.js.map +1 -0
- package/dist/review-ui/assets/arc-DH58vMfF.js +1 -0
- package/dist/review-ui/assets/architecture-YZFGNWBL-ChakYgFO.js +1 -0
- package/dist/review-ui/assets/architectureDiagram-Q4EWVU46-CcJOZCOb.js +36 -0
- package/dist/review-ui/assets/array-BCJ35G43.js +1 -0
- package/dist/review-ui/assets/blockDiagram-DXYQGD6D-H7mMv5Tv.js +132 -0
- package/dist/review-ui/assets/c4Diagram-AHTNJAMY-DCAtnxWd.js +10 -0
- package/dist/review-ui/assets/channel-BgHR4NPf.js +1 -0
- package/dist/review-ui/assets/chunk-2KRD3SAO-BfA3IkPQ.js +1 -0
- package/dist/review-ui/assets/chunk-4BX2VUAB-Dn9kswJO.js +1 -0
- package/dist/review-ui/assets/chunk-4TB4RGXK-CvTeZi33.js +206 -0
- package/dist/review-ui/assets/chunk-55IACEB6-CLBoivXU.js +1 -0
- package/dist/review-ui/assets/chunk-5FUZZQ4R-DU7La6QA.js +62 -0
- package/dist/review-ui/assets/chunk-5PVQY5BW-Dy3eUu9a.js +2 -0
- package/dist/review-ui/assets/chunk-67CJDMHE-BQ1xNHFx.js +1 -0
- package/dist/review-ui/assets/chunk-7N4EOEYR-B1ORNLQP.js +1 -0
- package/dist/review-ui/assets/chunk-AA7GKIK3-D3pS3mnx.js +1 -0
- package/dist/review-ui/assets/chunk-BSJP7CBP-BlpmbHL-.js +1 -0
- package/dist/review-ui/assets/chunk-CIAEETIT-BDZkAY47.js +1 -0
- package/dist/review-ui/assets/chunk-Dlc7tRH4.js +1 -0
- package/dist/review-ui/assets/chunk-EDXVE4YY-DNUlHz7M.js +1 -0
- package/dist/review-ui/assets/chunk-ENJZ2VHE-fwEKj0pQ.js +10 -0
- package/dist/review-ui/assets/chunk-FMBD7UC4-Cj8B2TLo.js +15 -0
- package/dist/review-ui/assets/chunk-FOC6F5B3-DGtCX5Ra.js +1 -0
- package/dist/review-ui/assets/chunk-ICPOFSXX-WTr3HDYE.js +122 -0
- package/dist/review-ui/assets/chunk-K5T4RW27-CWpdECLF.js +94 -0
- package/dist/review-ui/assets/chunk-KGLVRYIC-oI2XKaPz.js +1 -0
- package/dist/review-ui/assets/chunk-LIHQZDEY-Dzp3G35O.js +1 -0
- package/dist/review-ui/assets/chunk-ORNJ4GCN-DsHuVbPU.js +1 -0
- package/dist/review-ui/assets/chunk-OYMX7WX6-fgjoXAXJ.js +231 -0
- package/dist/review-ui/assets/chunk-QZHKN3VN-C4w1Z4n9.js +1 -0
- package/dist/review-ui/assets/chunk-U2HBQHQK-D8HUikvJ.js +70 -0
- package/dist/review-ui/assets/chunk-X2U36JSP-CuZ-SN2r.js +1 -0
- package/dist/review-ui/assets/chunk-YZCP3GAM-D0-dHF3G.js +1 -0
- package/dist/review-ui/assets/chunk-ZZ45TVLE-C1aIZGDA.js +1 -0
- package/dist/review-ui/assets/classDiagram-6PBFFD2Q-D_3LhkJc.js +1 -0
- package/dist/review-ui/assets/classDiagram-v2-HSJHXN6E-DQRUREh5.js +1 -0
- package/dist/review-ui/assets/clone-BZMtGzbS.js +1 -0
- package/dist/review-ui/assets/cose-bilkent-S5V4N54A-szpqu_3d.js +1 -0
- package/dist/review-ui/assets/cytoscape.esm-DZ22BVwz.js +321 -0
- package/dist/review-ui/assets/dagre-BfNtd34y.js +1 -0
- package/dist/review-ui/assets/dagre-KV5264BT-D6PbxORW.js +4 -0
- package/dist/review-ui/assets/defaultLocale-CIS5GEjP.js +1 -0
- package/dist/review-ui/assets/diagram-5BDNPKRD-BNAXBDig.js +10 -0
- package/dist/review-ui/assets/diagram-G4DWMVQ6-CIGS_5yQ.js +24 -0
- package/dist/review-ui/assets/diagram-MMDJMWI5-DJmcU2xZ.js +43 -0
- package/dist/review-ui/assets/diagram-TYMM5635-DW8XzrAz.js +24 -0
- package/dist/review-ui/assets/dist-B51l2n-9.js +1 -0
- package/dist/review-ui/assets/erDiagram-SMLLAGMA-BfUNH8zz.js +85 -0
- package/dist/review-ui/assets/flatten-BHh95bpO.js +1 -0
- package/dist/review-ui/assets/flowDiagram-DWJPFMVM-qgnlSvEC.js +162 -0
- package/dist/review-ui/assets/ganttDiagram-T4ZO3ILL-CFAN903o.js +292 -0
- package/dist/review-ui/assets/gitGraph-7Q5UKJZL-Dn47XunR.js +1 -0
- package/dist/review-ui/assets/gitGraphDiagram-UUTBAWPF-BcG6fDsE.js +106 -0
- package/dist/review-ui/assets/graphlib-Cie4kcbC.js +1 -0
- package/dist/review-ui/assets/identity-CWMh0UL-.js +1 -0
- package/dist/review-ui/assets/index-ByplNhhd.css +2 -0
- package/dist/review-ui/assets/index-S7nbpFp2.js +123 -0
- package/dist/review-ui/assets/info-OMHHGYJF-hAukP1xW.js +1 -0
- package/dist/review-ui/assets/infoDiagram-42DDH7IO-FblTAfC3.js +2 -0
- package/dist/review-ui/assets/init-BMBYmmUa.js +1 -0
- package/dist/review-ui/assets/ishikawaDiagram-UXIWVN3A-BA7dJd-J.js +70 -0
- package/dist/review-ui/assets/journeyDiagram-VCZTEJTY-CMx2w_is.js +139 -0
- package/dist/review-ui/assets/kanban-definition-6JOO6SKY-CFiOZCrT.js +89 -0
- package/dist/review-ui/assets/katex-8mXVa4k3.js +257 -0
- package/dist/review-ui/assets/line-BCdBO-oK.js +1 -0
- package/dist/review-ui/assets/linear-d7UHSQqm.js +1 -0
- package/dist/review-ui/assets/mermaid-parser.core-BHMXLuNx.js +4 -0
- package/dist/review-ui/assets/mindmap-definition-QFDTVHPH-CWO7vDqu.js +96 -0
- package/dist/review-ui/assets/ordinal-BDTCIhXR.js +1 -0
- package/dist/review-ui/assets/packet-4T2RLAQJ-Btz3ryW7.js +1 -0
- package/dist/review-ui/assets/path-CIRGLb_6.js +1 -0
- package/dist/review-ui/assets/pie-ZZUOXDRM-CreBtuDj.js +1 -0
- package/dist/review-ui/assets/pieDiagram-DEJITSTG-X2mFk5I3.js +30 -0
- package/dist/review-ui/assets/quadrantDiagram-34T5L4WZ-BSFYvc1U.js +7 -0
- package/dist/review-ui/assets/radar-PYXPWWZC-BcAPYMpV.js +1 -0
- package/dist/review-ui/assets/reduce-14YNCNxn.js +1 -0
- package/dist/review-ui/assets/requirementDiagram-MS252O5E-CDv1lxdq.js +84 -0
- package/dist/review-ui/assets/rough.esm-DtEqI08j.js +1 -0
- package/dist/review-ui/assets/sankeyDiagram-XADWPNL6-CV38ZpSv.js +10 -0
- package/dist/review-ui/assets/sequenceDiagram-FGHM5R23-DCuV_bhx.js +157 -0
- package/dist/review-ui/assets/src-Cxc1bu7b.js +1 -0
- package/dist/review-ui/assets/stateDiagram-FHFEXIEX-BfE_bGUQ.js +1 -0
- package/dist/review-ui/assets/stateDiagram-v2-QKLJ7IA2-u1yKXWoz.js +1 -0
- package/dist/review-ui/assets/timeline-definition-GMOUNBTQ-Ci0uFxaT.js +120 -0
- package/dist/review-ui/assets/treeView-SZITEDCU-BXg6-7zY.js +1 -0
- package/dist/review-ui/assets/treemap-W4RFUUIX-BToYbgol.js +1 -0
- package/dist/review-ui/assets/vennDiagram-DHZGUBPP-DvOuThac.js +34 -0
- package/dist/review-ui/assets/wardley-RL74JXVD-BAYzkcK-.js +1 -0
- package/dist/review-ui/assets/wardleyDiagram-NUSXRM2D-YxTu6WZw.js +20 -0
- package/dist/review-ui/assets/xychartDiagram-5P7HB3ND-V9j-Dl7t.js +7 -0
- package/dist/review-ui/index.html +29 -0
- package/dist/run-openflow-cli.d.ts +1 -0
- package/dist/run-openflow-cli.js +41 -0
- package/dist/run-openflow-cli.js.map +1 -0
- package/dist/shared/args.d.ts +3 -0
- package/dist/shared/args.js +27 -0
- package/dist/shared/args.js.map +1 -0
- package/dist/shared/browser.d.ts +4 -0
- package/dist/shared/browser.js +17 -0
- package/dist/shared/browser.js.map +1 -0
- package/dist/shared/fs.d.ts +15 -0
- package/dist/shared/fs.js +48 -0
- package/dist/shared/fs.js.map +1 -0
- package/dist/shared/i18n.d.ts +5 -0
- package/dist/shared/i18n.js +65 -0
- package/dist/shared/i18n.js.map +1 -0
- package/dist/shared/locales/en-US.json +88 -0
- package/dist/shared/locales/zh-CN.json +88 -0
- package/dist/shared/plugin-registry.d.ts +36 -0
- package/dist/shared/plugin-registry.js +51 -0
- package/dist/shared/plugin-registry.js.map +1 -0
- package/dist/shared/project-state.d.ts +17 -0
- package/dist/shared/project-state.js +75 -0
- package/dist/shared/project-state.js.map +1 -0
- package/dist/shared/terminal.d.ts +10 -0
- package/dist/shared/terminal.js +110 -0
- package/dist/shared/terminal.js.map +1 -0
- package/package.json +28 -0
- package/templates/archive/.gitkeep +1 -0
- package/templates/config.json +11 -0
- package/templates/current.json +3 -0
- package/templates/iterations/.gitkeep +1 -0
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
import { OPENFLOW_STAGES, OPENFLOW_LEVELS } from "./index.js";
|
|
2
|
+
export const REVIEW_STATUSES = ["approved", "changes_requested", "partial", "rejected"];
|
|
3
|
+
export const EXTENSION_STATUSES = ["passed", "failed", "skipped"];
|
|
4
|
+
export const FLOW_GATES = ["draft", "review_required", "changes_requested", "approved", "skipped", "blocked"];
|
|
5
|
+
export function validateOpenFlowConfig(value, path = "config.json") {
|
|
6
|
+
const issues = [];
|
|
7
|
+
if (!isRecord(value)) {
|
|
8
|
+
return withIssues([{ code: "config.type", message: "config.json must contain a JSON object.", path }]);
|
|
9
|
+
}
|
|
10
|
+
if (value.version !== 1) {
|
|
11
|
+
issues.push(error("config.version", "config.version must be 1.", `${path}.version`));
|
|
12
|
+
}
|
|
13
|
+
if (!isOpenFlowLevel(value.defaultLevel)) {
|
|
14
|
+
issues.push(error("config.defaultLevel", `config.defaultLevel must be one of: ${OPENFLOW_LEVELS.join(", ")}.`, `${path}.defaultLevel`));
|
|
15
|
+
}
|
|
16
|
+
if ("language" in value && !isLanguageTag(value.language)) {
|
|
17
|
+
issues.push(error("config.language", "config.language must be a non-empty language tag such as zh-CN or en-US.", `${path}.language`));
|
|
18
|
+
}
|
|
19
|
+
if ("review" in value) {
|
|
20
|
+
validateReviewConfig(value.review, `${path}.review`, issues);
|
|
21
|
+
}
|
|
22
|
+
if ("extensions" in value) {
|
|
23
|
+
validateExtensionConfigs(value.extensions, `${path}.extensions`, issues);
|
|
24
|
+
}
|
|
25
|
+
if ("modules" in value) {
|
|
26
|
+
if (!Array.isArray(value.modules)) {
|
|
27
|
+
issues.push(error("config.modules.type", "config.modules must be an array of strings.", `${path}.modules`));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
if (value.modules.length === 0) {
|
|
31
|
+
issues.push(error("config.modules.empty", "config.modules must contain at least one module.", `${path}.modules`));
|
|
32
|
+
}
|
|
33
|
+
for (const mod of value.modules) {
|
|
34
|
+
if (typeof mod !== "string") {
|
|
35
|
+
issues.push(error("config.modules.item", "Each config.modules item must be a string.", `${path}.modules`));
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (!value.modules.includes("core")) {
|
|
40
|
+
issues.push(error("config.modules.core", "config.modules must include 'core'.", `${path}.modules`));
|
|
41
|
+
}
|
|
42
|
+
const validModules = ["core", "brainstorm-prd"];
|
|
43
|
+
for (const mod of value.modules) {
|
|
44
|
+
if (typeof mod === "string" && !validModules.includes(mod)) {
|
|
45
|
+
issues.push(error("config.modules.invalid", `config.modules contains unknown module '${mod}'. Valid modules: ${validModules.join(", ")}.`, `${path}.modules`));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return fromIssues(issues);
|
|
51
|
+
}
|
|
52
|
+
export function validateFlowState(value, path = "flow.json") {
|
|
53
|
+
const issues = [];
|
|
54
|
+
if (!isRecord(value)) {
|
|
55
|
+
return withIssues([{ code: "flow.type", message: "flow.json must contain a JSON object.", path }]);
|
|
56
|
+
}
|
|
57
|
+
if (!nonEmptyString(value.id)) {
|
|
58
|
+
issues.push(error("flow.id", "flow.id must be a non-empty string.", `${path}.id`));
|
|
59
|
+
}
|
|
60
|
+
if (!nonEmptyString(value.title)) {
|
|
61
|
+
issues.push(error("flow.title", "flow.title must be a non-empty string.", `${path}.title`));
|
|
62
|
+
}
|
|
63
|
+
if (!isOpenFlowLevel(value.level)) {
|
|
64
|
+
issues.push(error("flow.level", `flow.level must be one of: ${OPENFLOW_LEVELS.join(", ")}.`, `${path}.level`));
|
|
65
|
+
}
|
|
66
|
+
if (!isOpenFlowStage(value.stage)) {
|
|
67
|
+
issues.push(error("flow.stage", `flow.stage must be one of: ${OPENFLOW_STAGES.join(", ")}.`, `${path}.stage`));
|
|
68
|
+
}
|
|
69
|
+
if (!Number.isInteger(value.revision) || value.revision < 1) {
|
|
70
|
+
issues.push(error("flow.revision", "flow.revision must be an integer greater than 0.", `${path}.revision`));
|
|
71
|
+
}
|
|
72
|
+
if (!isFlowGate(value.gate)) {
|
|
73
|
+
issues.push(error("flow.gate", `flow.gate must be one of: ${FLOW_GATES.join(", ")}.`, `${path}.gate`));
|
|
74
|
+
}
|
|
75
|
+
if (typeof value.createdAt !== "string" || !isIsoDate(value.createdAt)) {
|
|
76
|
+
issues.push(error("flow.createdAt", "flow.createdAt must be an ISO timestamp.", `${path}.createdAt`));
|
|
77
|
+
}
|
|
78
|
+
if (typeof value.updatedAt !== "string" || !isIsoDate(value.updatedAt)) {
|
|
79
|
+
issues.push(error("flow.updatedAt", "flow.updatedAt must be an ISO timestamp.", `${path}.updatedAt`));
|
|
80
|
+
}
|
|
81
|
+
if (value.activeTask !== null && typeof value.activeTask !== "string") {
|
|
82
|
+
issues.push(error("flow.activeTask", "flow.activeTask must be a string or null.", `${path}.activeTask`));
|
|
83
|
+
}
|
|
84
|
+
if ("knowledge_citations" in value) {
|
|
85
|
+
validateKnowledgeCitations(value.knowledge_citations, `${path}.knowledge_citations`, issues);
|
|
86
|
+
}
|
|
87
|
+
return fromIssues(issues);
|
|
88
|
+
}
|
|
89
|
+
export function validateReviewResult(value, path = "reviews/spec-review.json") {
|
|
90
|
+
const issues = [];
|
|
91
|
+
if (!isRecord(value)) {
|
|
92
|
+
return withIssues([{ code: "review.type", message: "review result must contain a JSON object.", path }]);
|
|
93
|
+
}
|
|
94
|
+
if (value.stage !== "spec" && value.stage !== "plan" && value.stage !== "prd" && value.stage !== "archive") {
|
|
95
|
+
issues.push(error("review.stage", "review.stage must be spec, plan, prd, or archive.", `${path}.stage`));
|
|
96
|
+
}
|
|
97
|
+
if (!Number.isInteger(value.revision) || value.revision < 1) {
|
|
98
|
+
issues.push(error("review.revision", "review.revision must be an integer greater than 0.", `${path}.revision`));
|
|
99
|
+
}
|
|
100
|
+
if (!isReviewStatus(value.status)) {
|
|
101
|
+
issues.push(error("review.status", `review.status must be one of: ${REVIEW_STATUSES.join(", ")}.`, `${path}.status`));
|
|
102
|
+
}
|
|
103
|
+
if (typeof value.reviewedAt !== "string") {
|
|
104
|
+
issues.push(error("review.reviewedAt", "review.reviewedAt must be a string.", `${path}.reviewedAt`));
|
|
105
|
+
}
|
|
106
|
+
else if (value.status === "approved" && !isIsoDate(value.reviewedAt)) {
|
|
107
|
+
issues.push(error("review.reviewedAt.iso", "approved reviews must include an ISO reviewedAt timestamp.", `${path}.reviewedAt`));
|
|
108
|
+
}
|
|
109
|
+
else if (value.reviewedAt !== "" && !isIsoDate(value.reviewedAt)) {
|
|
110
|
+
issues.push(warning("review.reviewedAt.iso", "review.reviewedAt should be an ISO timestamp when present.", `${path}.reviewedAt`));
|
|
111
|
+
}
|
|
112
|
+
validateStringArray(value.comments, `${path}.comments`, "review.comments", issues);
|
|
113
|
+
validateStringArray(value.requestedChanges, `${path}.requestedChanges`, "review.requestedChanges", issues);
|
|
114
|
+
if ("annotations" in value) {
|
|
115
|
+
validateReviewAnnotations(value.annotations, `${path}.annotations`, issues);
|
|
116
|
+
}
|
|
117
|
+
if ("approvedBy" in value && typeof value.approvedBy !== "string") {
|
|
118
|
+
issues.push(error("review.approvedBy", "review.approvedBy must be a string when present.", `${path}.approvedBy`));
|
|
119
|
+
}
|
|
120
|
+
return fromIssues(issues);
|
|
121
|
+
}
|
|
122
|
+
export function validateExtensionResult(value, path = "result.json") {
|
|
123
|
+
const issues = [];
|
|
124
|
+
if (!isRecord(value)) {
|
|
125
|
+
return withIssues([{ code: "extension.type", message: "extension result must contain a JSON object.", path }]);
|
|
126
|
+
}
|
|
127
|
+
if (!nonEmptyString(value.name)) {
|
|
128
|
+
issues.push(error("extension.name", "extension result name must be a non-empty string.", `${path}.name`));
|
|
129
|
+
}
|
|
130
|
+
if (!isExtensionStatus(value.status)) {
|
|
131
|
+
issues.push(error("extension.status", `extension status must be one of: ${EXTENSION_STATUSES.join(", ")}.`, `${path}.status`));
|
|
132
|
+
}
|
|
133
|
+
if (typeof value.required !== "boolean") {
|
|
134
|
+
issues.push(error("extension.required", "extension required must be a boolean.", `${path}.required`));
|
|
135
|
+
}
|
|
136
|
+
if (typeof value.summary !== "string") {
|
|
137
|
+
issues.push(error("extension.summary", "extension summary must be a string.", `${path}.summary`));
|
|
138
|
+
}
|
|
139
|
+
validateStringArray(value.artifacts, `${path}.artifacts`, "extension.artifacts", issues);
|
|
140
|
+
if (typeof value.createdAt !== "string" || !isIsoDate(value.createdAt)) {
|
|
141
|
+
issues.push(error("extension.createdAt", "extension createdAt must be an ISO timestamp.", `${path}.createdAt`));
|
|
142
|
+
}
|
|
143
|
+
return fromIssues(issues);
|
|
144
|
+
}
|
|
145
|
+
export function validatePrdMeta(value, path = "prd.json") {
|
|
146
|
+
const issues = [];
|
|
147
|
+
if (!isRecord(value)) {
|
|
148
|
+
return withIssues([{ code: "prd.type", message: "prd.json must contain a JSON object.", path }]);
|
|
149
|
+
}
|
|
150
|
+
if (!nonEmptyString(value.id)) {
|
|
151
|
+
issues.push(error("prd.id", "prd.id must be a non-empty string.", `${path}.id`));
|
|
152
|
+
}
|
|
153
|
+
else if (!/^\d{4}-\d{2}-\d{2}-/.test(value.id)) {
|
|
154
|
+
issues.push(error("prd.id.format", "prd.id must start with a YYYY-MM-DD- prefix.", `${path}.id`));
|
|
155
|
+
}
|
|
156
|
+
if (value.status !== "draft" && value.status !== "reviewing" && value.status !== "approved") {
|
|
157
|
+
issues.push(error("prd.status", "prd.status must be draft, reviewing, or approved.", `${path}.status`));
|
|
158
|
+
}
|
|
159
|
+
if (!Number.isInteger(value.revision) || value.revision < 0) {
|
|
160
|
+
issues.push(error("prd.revision", "prd.revision must be a non-negative integer.", `${path}.revision`));
|
|
161
|
+
}
|
|
162
|
+
if (value.linkedIteration !== null && typeof value.linkedIteration !== "string") {
|
|
163
|
+
issues.push(error("prd.linkedIteration", "prd.linkedIteration must be a string or null.", `${path}.linkedIteration`));
|
|
164
|
+
}
|
|
165
|
+
validateStringArray(value.assets, `${path}.assets`, "prd.assets", issues);
|
|
166
|
+
if (typeof value.createdAt !== "string" || !isIsoDate(value.createdAt)) {
|
|
167
|
+
issues.push(error("prd.createdAt", "prd.createdAt must be an ISO timestamp.", `${path}.createdAt`));
|
|
168
|
+
}
|
|
169
|
+
if (typeof value.updatedAt !== "string" || !isIsoDate(value.updatedAt)) {
|
|
170
|
+
issues.push(error("prd.updatedAt", "prd.updatedAt must be an ISO timestamp.", `${path}.updatedAt`));
|
|
171
|
+
}
|
|
172
|
+
return fromIssues(issues);
|
|
173
|
+
}
|
|
174
|
+
export function validateStateMarkdown(markdown, path = "STATE.md") {
|
|
175
|
+
const issues = [];
|
|
176
|
+
requireHeading(markdown, "# OpenFlow State", path, issues);
|
|
177
|
+
requireLinePrefix(markdown, "- Flow:", path, issues);
|
|
178
|
+
requireLinePrefix(markdown, "- Title:", path, issues);
|
|
179
|
+
requireLinePrefix(markdown, "- Stage:", path, issues);
|
|
180
|
+
requireLinePrefix(markdown, "- Level:", path, issues);
|
|
181
|
+
requireLinePrefix(markdown, "- Revision:", path, issues);
|
|
182
|
+
requireLinePrefix(markdown, "- Active task:", path, issues);
|
|
183
|
+
requireLinePrefix(markdown, "- Gate status:", path, issues);
|
|
184
|
+
const stage = readListValue(markdown, "Stage");
|
|
185
|
+
if (stage && !isOpenFlowStage(stage)) {
|
|
186
|
+
issues.push(error("state.stage", `STATE.md Stage must be one of: ${OPENFLOW_STAGES.join(", ")}.`, path));
|
|
187
|
+
}
|
|
188
|
+
const level = readListValue(markdown, "Level");
|
|
189
|
+
if (level && !isOpenFlowLevel(level)) {
|
|
190
|
+
issues.push(error("state.level", `STATE.md Level must be one of: ${OPENFLOW_LEVELS.join(", ")}.`, path));
|
|
191
|
+
}
|
|
192
|
+
return fromIssues(issues);
|
|
193
|
+
}
|
|
194
|
+
export function validateSpecMarkdown(markdown, path = "SPEC.md", level) {
|
|
195
|
+
const issues = [];
|
|
196
|
+
requireHeadingPattern(markdown, /^# Spec(?::\s+.+)?\s*$/m, "# Spec: <title>", path, issues);
|
|
197
|
+
for (const heading of [
|
|
198
|
+
"## One-Sentence Goal",
|
|
199
|
+
"## Scope",
|
|
200
|
+
"## Non-Goals",
|
|
201
|
+
"## Acceptance Criteria"
|
|
202
|
+
]) {
|
|
203
|
+
requireHeading(markdown, heading, path, issues);
|
|
204
|
+
}
|
|
205
|
+
if (level === undefined || level === "2" || level === "3") {
|
|
206
|
+
requireHeading(markdown, "## Risks", path, issues);
|
|
207
|
+
}
|
|
208
|
+
if (/^## Decisions Needed\s*$/m.test(markdown)) {
|
|
209
|
+
issues.push(warning("spec.deprecated.decisions", "SPEC.md should not include '## Decisions Needed'. Decisions belong in PLAN.md.", path));
|
|
210
|
+
}
|
|
211
|
+
if (/^## AI Execution Summary\s*$/m.test(markdown)) {
|
|
212
|
+
issues.push(warning("spec.deprecated.executionSummary", "SPEC.md should not include '## AI Execution Summary'. Execution details belong in PLAN.md and TASKS.md.", path));
|
|
213
|
+
}
|
|
214
|
+
return fromIssues(issues);
|
|
215
|
+
}
|
|
216
|
+
export function validateContextMarkdown(markdown, path = "CONTEXT.md") {
|
|
217
|
+
const issues = [];
|
|
218
|
+
requireHeading(markdown, "# Context", path, issues);
|
|
219
|
+
return fromIssues(issues);
|
|
220
|
+
}
|
|
221
|
+
export function validateTasksMarkdown(markdown, path = "TASKS.md") {
|
|
222
|
+
const issues = [];
|
|
223
|
+
requireHeading(markdown, "# Tasks", path, issues);
|
|
224
|
+
if (!/^-\s+\[[ xX]\]\s+T-\d{3}:/m.test(markdown)) {
|
|
225
|
+
issues.push(error("tasks.checkbox", "TASKS.md must include at least one checkbox task with a stable T-### id.", path));
|
|
226
|
+
}
|
|
227
|
+
for (const label of ["Action:", "Validation:", "Evidence:"]) {
|
|
228
|
+
if (!markdown.includes(label)) {
|
|
229
|
+
issues.push(error(`tasks.${label.toLowerCase().replace(":", "")}`, `TASKS.md must include ${label} for each task.`, path));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
for (const label of ["**Files:**", "**Read First:**", "**Acceptance Criteria:**"]) {
|
|
233
|
+
if (!markdown.includes(label)) {
|
|
234
|
+
issues.push(warning(`tasks.${label.toLowerCase().replace(/[^a-z]/g, "")}`, `TASKS.md should include ${label} for each task (Level 2+ recommended).`, path));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return fromIssues(issues);
|
|
238
|
+
}
|
|
239
|
+
export function validatePlanMarkdown(markdown, path = "PLAN.md", level) {
|
|
240
|
+
const issues = [];
|
|
241
|
+
requireHeadingPattern(markdown, /^# Plan(?::\s+.+)?\s*$/m, "# Plan: <title>", path, issues);
|
|
242
|
+
for (const heading of [
|
|
243
|
+
"## Context",
|
|
244
|
+
"## Decisions",
|
|
245
|
+
"## File Map",
|
|
246
|
+
"## Spec Coverage"
|
|
247
|
+
]) {
|
|
248
|
+
requireHeading(markdown, heading, path, issues);
|
|
249
|
+
}
|
|
250
|
+
if (level === "3") {
|
|
251
|
+
for (const heading of ["## Must Haves", "## Key Interfaces", "## Dependencies", "## Risks"]) {
|
|
252
|
+
requireHeading(markdown, heading, path, issues);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return fromIssues(issues);
|
|
256
|
+
}
|
|
257
|
+
export function validateSummaryMarkdown(markdown, path = "SUMMARY.md") {
|
|
258
|
+
const issues = [];
|
|
259
|
+
requireHeading(markdown, "# Summary", path, issues);
|
|
260
|
+
for (const heading of ["## Shipped Changes", "## Validation Evidence", "## Deferred Items", "## Durable Knowledge"]) {
|
|
261
|
+
requireHeading(markdown, heading, path, issues);
|
|
262
|
+
}
|
|
263
|
+
return fromIssues(issues);
|
|
264
|
+
}
|
|
265
|
+
export function validateKnowledgeCatalog(value, path = "knowledge/catalog.json") {
|
|
266
|
+
const issues = [];
|
|
267
|
+
if (!isRecord(value)) {
|
|
268
|
+
return withIssues([{ code: "knowledge.catalog.type", message: "catalog.json must contain a JSON object.", path }]);
|
|
269
|
+
}
|
|
270
|
+
if (typeof value.version !== "number" || !Number.isInteger(value.version)) {
|
|
271
|
+
issues.push(error("knowledge.catalog.version", "catalog.json version must be an integer.", `${path}.version`));
|
|
272
|
+
}
|
|
273
|
+
if (!Array.isArray(value.entries)) {
|
|
274
|
+
issues.push(error("knowledge.catalog.entries", "catalog.json entries must be an array.", `${path}.entries`));
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
validateCatalogEntries(value.entries, `${path}.entries`, issues);
|
|
278
|
+
}
|
|
279
|
+
return fromIssues(issues);
|
|
280
|
+
}
|
|
281
|
+
export function validateKnowledgeIndex(value, path = "knowledge/decisions/index.json") {
|
|
282
|
+
const issues = [];
|
|
283
|
+
if (!isRecord(value)) {
|
|
284
|
+
return withIssues([{ code: "knowledge.index.type", message: "index.json must contain a JSON object.", path }]);
|
|
285
|
+
}
|
|
286
|
+
if (typeof value.type !== "string" || value.type.trim().length === 0) {
|
|
287
|
+
issues.push(error("knowledge.index.type", "index.json type must be a non-empty string.", `${path}.type`));
|
|
288
|
+
}
|
|
289
|
+
if (!Array.isArray(value.entries)) {
|
|
290
|
+
issues.push(error("knowledge.index.entries", "index.json entries must be an array.", `${path}.entries`));
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
validateIndexEntries(value.entries, `${path}.entries`, issues);
|
|
294
|
+
}
|
|
295
|
+
return fromIssues(issues);
|
|
296
|
+
}
|
|
297
|
+
export function validateWorkingMemoryMarkdown(markdown, path = "WORKING_MEMORY.md") {
|
|
298
|
+
const issues = [];
|
|
299
|
+
for (const heading of [
|
|
300
|
+
"## Injected Knowledge",
|
|
301
|
+
"## Execution Observations",
|
|
302
|
+
"## Knowledge Candidates",
|
|
303
|
+
"## Blockers and Resolutions"
|
|
304
|
+
]) {
|
|
305
|
+
requireHeading(markdown, heading, path, issues);
|
|
306
|
+
}
|
|
307
|
+
return fromIssues(issues);
|
|
308
|
+
}
|
|
309
|
+
export function validateStageTransition(input) {
|
|
310
|
+
const issues = [];
|
|
311
|
+
if (input.targetStage === "implement" && requiresReviewBeforeExecute(input.level)) {
|
|
312
|
+
if (!input.review || input.review.stage !== "spec" || input.review.status !== "approved") {
|
|
313
|
+
issues.push(error("gate.specReview", `Level ${input.level} flows require an approved spec review before implement.`));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (input.targetStage === "archived" && requiresArchiveReview(input.level)) {
|
|
317
|
+
if (!input.review || input.review.stage !== "archive" || input.review.status !== "approved") {
|
|
318
|
+
issues.push(error("gate.archiveReview", `Level ${input.level} flows require an approved archive review before finalize.`));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (input.currentStage === "archived" && input.targetStage !== "archived") {
|
|
322
|
+
issues.push(error("gate.archived", "archived flows cannot transition back to an active stage."));
|
|
323
|
+
}
|
|
324
|
+
return fromIssues(issues);
|
|
325
|
+
}
|
|
326
|
+
export function validateOpenFlowArtifacts(artifacts) {
|
|
327
|
+
const issues = [];
|
|
328
|
+
if (artifacts.config !== undefined) {
|
|
329
|
+
issues.push(...validateOpenFlowConfig(artifacts.config).issues);
|
|
330
|
+
}
|
|
331
|
+
const resolvedFlowLevel = isFlowStateValue(artifacts.flow) ? artifacts.flow.level : undefined;
|
|
332
|
+
if (artifacts.flow !== undefined) {
|
|
333
|
+
issues.push(...validateFlowState(artifacts.flow).issues);
|
|
334
|
+
}
|
|
335
|
+
if (artifacts.specReview !== undefined) {
|
|
336
|
+
issues.push(...validateReviewResult(artifacts.specReview, "reviews/spec-review.json").issues);
|
|
337
|
+
}
|
|
338
|
+
if (artifacts.archiveReview !== undefined) {
|
|
339
|
+
issues.push(...validateReviewResult(artifacts.archiveReview, "reviews/archive-review.json").issues);
|
|
340
|
+
}
|
|
341
|
+
for (const result of artifacts.extensionResults ?? []) {
|
|
342
|
+
issues.push(...validateExtensionResult(result.value, result.path).issues);
|
|
343
|
+
}
|
|
344
|
+
if (artifacts.stateMarkdown !== undefined) {
|
|
345
|
+
issues.push(...validateStateMarkdown(artifacts.stateMarkdown).issues);
|
|
346
|
+
}
|
|
347
|
+
if (artifacts.specMarkdown !== undefined) {
|
|
348
|
+
issues.push(...validateSpecMarkdown(artifacts.specMarkdown, "SPEC.md", resolvedFlowLevel).issues);
|
|
349
|
+
}
|
|
350
|
+
if (artifacts.contextMarkdown !== undefined) {
|
|
351
|
+
issues.push(...validateContextMarkdown(artifacts.contextMarkdown).issues);
|
|
352
|
+
}
|
|
353
|
+
if (artifacts.tasksMarkdown !== undefined) {
|
|
354
|
+
issues.push(...validateTasksMarkdown(artifacts.tasksMarkdown).issues);
|
|
355
|
+
}
|
|
356
|
+
if (artifacts.planMarkdown !== undefined) {
|
|
357
|
+
issues.push(...validatePlanMarkdown(artifacts.planMarkdown, "PLAN.md", resolvedFlowLevel).issues);
|
|
358
|
+
}
|
|
359
|
+
if (artifacts.summaryMarkdown !== undefined) {
|
|
360
|
+
issues.push(...validateSummaryMarkdown(artifacts.summaryMarkdown).issues);
|
|
361
|
+
}
|
|
362
|
+
issues.push(...validateKnowledgeDirectories(artifacts));
|
|
363
|
+
issues.push(...validateKnowledgeCatalogAndIndices(artifacts));
|
|
364
|
+
issues.push(...validateWorkingMemory(artifacts));
|
|
365
|
+
issues.push(...validateSpecApprovalGate(artifacts));
|
|
366
|
+
issues.push(...validateExecutionEvidenceGate(artifacts));
|
|
367
|
+
issues.push(...validateArchiveGate(artifacts));
|
|
368
|
+
return fromIssues(issues);
|
|
369
|
+
}
|
|
370
|
+
export function requiresHumanReview(level) {
|
|
371
|
+
return level === "2" || level === "3";
|
|
372
|
+
}
|
|
373
|
+
export function requiresReviewBeforeExecute(level) {
|
|
374
|
+
return requiresHumanReview(level);
|
|
375
|
+
}
|
|
376
|
+
// No formal archive-review.json gate file exists in the workflow.
|
|
377
|
+
// Archive-stage quality checks (code-reviewer, artifact-reviewer) are
|
|
378
|
+
// performed by the AI agent during /openflow-finalize, not as a file-producing gate.
|
|
379
|
+
export function requiresArchiveReview(_level) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
function validateSpecApprovalGate(artifacts) {
|
|
383
|
+
if (!isFlowStateValue(artifacts.flow) || !requiresHumanReview(artifacts.flow.level) || artifacts.flow.gate !== "approved") {
|
|
384
|
+
return [];
|
|
385
|
+
}
|
|
386
|
+
if (!isReviewResultValue(artifacts.specReview)) {
|
|
387
|
+
return [error("gate.specReview", `approved Level ${artifacts.flow.level} flows require reviews/spec-review.json.`)];
|
|
388
|
+
}
|
|
389
|
+
if (artifacts.specReview.stage !== "spec" || artifacts.specReview.status !== "approved") {
|
|
390
|
+
return [error("gate.specReview.status", "reviews/spec-review.json must be an approved spec review.")];
|
|
391
|
+
}
|
|
392
|
+
if (artifacts.specReview.revision !== artifacts.flow.revision) {
|
|
393
|
+
return [error("gate.specReview.revision", "approved spec review revision must match flow.json revision.")];
|
|
394
|
+
}
|
|
395
|
+
return [];
|
|
396
|
+
}
|
|
397
|
+
function validateExecutionEvidenceGate(artifacts) {
|
|
398
|
+
if (artifacts.tasksMarkdown === undefined) {
|
|
399
|
+
return [];
|
|
400
|
+
}
|
|
401
|
+
const issues = [];
|
|
402
|
+
const tasks = parseTasks(artifacts.tasksMarkdown);
|
|
403
|
+
const flow = isFlowStateValue(artifacts.flow) ? artifacts.flow : undefined;
|
|
404
|
+
const closingFlow = flow?.stage === "finalize" || flow?.stage === "archived";
|
|
405
|
+
const flowLevel = flow?.level;
|
|
406
|
+
for (const task of tasks) {
|
|
407
|
+
if (task.checked) {
|
|
408
|
+
if (!isConcreteTaskEvidence(task.evidence)) {
|
|
409
|
+
issues.push(error("tasks.evidence.concrete", `${task.id} is checked but does not include concrete evidence. Record commands, results, screenshots, reviewer signal, or exact blocker text.`, "TASKS.md"));
|
|
410
|
+
}
|
|
411
|
+
if (!isConcreteTaskValidation(task.validation)) {
|
|
412
|
+
issues.push(error("tasks.validation.concrete", `${task.id} is checked but does not include a concrete validation signal.`, "TASKS.md"));
|
|
413
|
+
}
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (closingFlow && !isExplicitlyDeferred(task.evidence)) {
|
|
417
|
+
issues.push(error("tasks.incomplete.archive", `${task.id} is incomplete during archive. Complete it or record an explicit deferred/blocked/waived evidence note with rationale.`, "TASKS.md"));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return issues;
|
|
421
|
+
}
|
|
422
|
+
function validateArchiveGate(artifacts) {
|
|
423
|
+
if (!isFlowStateValue(artifacts.flow)) {
|
|
424
|
+
return [];
|
|
425
|
+
}
|
|
426
|
+
const issues = [];
|
|
427
|
+
const flow = artifacts.flow;
|
|
428
|
+
const finalArchive = flow.stage === "archived" || (flow.stage === "finalize" && flow.gate === "approved");
|
|
429
|
+
if (!finalArchive) {
|
|
430
|
+
return issues;
|
|
431
|
+
}
|
|
432
|
+
if (artifacts.summaryMarkdown === undefined) {
|
|
433
|
+
issues.push(error("gate.summary", "Final archive requires SUMMARY.md.", "SUMMARY.md"));
|
|
434
|
+
}
|
|
435
|
+
issues.push(...validateRequiredExtensionGate(artifacts));
|
|
436
|
+
return issues;
|
|
437
|
+
}
|
|
438
|
+
const REQUIRED_KNOWLEDGE_SUB_DIRS = ["guidelines", "processes", "archive"];
|
|
439
|
+
function validateKnowledgeDirectories(artifacts) {
|
|
440
|
+
if (artifacts.knowledgeSubDirs === undefined || artifacts.knowledgeSubDirs.length === 0) {
|
|
441
|
+
return [];
|
|
442
|
+
}
|
|
443
|
+
const issues = [];
|
|
444
|
+
for (const subDir of REQUIRED_KNOWLEDGE_SUB_DIRS) {
|
|
445
|
+
if (!artifacts.knowledgeSubDirs.includes(subDir)) {
|
|
446
|
+
issues.push(error("knowledge.directory.missing", `knowledge/ directory is missing required sub-directory: ${subDir}/.`, `knowledge/${subDir}/`));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return issues;
|
|
450
|
+
}
|
|
451
|
+
function validateKnowledgeCatalogAndIndices(artifacts) {
|
|
452
|
+
const issues = [];
|
|
453
|
+
if (artifacts.knowledgeCatalog !== undefined) {
|
|
454
|
+
issues.push(...validateKnowledgeCatalog(artifacts.knowledgeCatalog).issues);
|
|
455
|
+
}
|
|
456
|
+
for (const indexFile of artifacts.knowledgeIndexFiles ?? []) {
|
|
457
|
+
issues.push(...validateKnowledgeIndex(indexFile.value, indexFile.path).issues);
|
|
458
|
+
}
|
|
459
|
+
return issues;
|
|
460
|
+
}
|
|
461
|
+
function validateWorkingMemory(artifacts) {
|
|
462
|
+
if (artifacts.workingMemoryMarkdown === undefined) {
|
|
463
|
+
return [];
|
|
464
|
+
}
|
|
465
|
+
const issues = [];
|
|
466
|
+
issues.push(...validateWorkingMemoryMarkdown(artifacts.workingMemoryMarkdown).issues);
|
|
467
|
+
return issues;
|
|
468
|
+
}
|
|
469
|
+
function validateRequiredExtensionGate(artifacts) {
|
|
470
|
+
if (!isRecord(artifacts.config) || !isRecord(artifacts.config.extensions)) {
|
|
471
|
+
return [];
|
|
472
|
+
}
|
|
473
|
+
const issues = [];
|
|
474
|
+
const results = new Map();
|
|
475
|
+
for (const result of artifacts.extensionResults ?? []) {
|
|
476
|
+
if (isExtensionResultValue(result.value)) {
|
|
477
|
+
results.set(result.value.name, result.value);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
for (const [name, config] of Object.entries(artifacts.config.extensions)) {
|
|
481
|
+
if (!isRecord(config) || config.enabled !== true || config.required !== true) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
const result = results.get(name);
|
|
485
|
+
if (!result) {
|
|
486
|
+
issues.push(error("gate.extension.missing", `required extension "${name}" has no result.json.`, `extensions/${name}/result.json`));
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (result.status !== "passed" && !isAcceptedExtensionDeferral(result)) {
|
|
490
|
+
issues.push(error("gate.extension.status", `required extension "${name}" must pass or be skipped with an accepted deferral rationale.`, `extensions/${name}/result.json`));
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return issues;
|
|
494
|
+
}
|
|
495
|
+
function parseTasks(markdown) {
|
|
496
|
+
const matches = [...markdown.matchAll(/^-\s+\[([ xX])\]\s+(T-\d{3}):\s*(.+?)\s*$/gm)];
|
|
497
|
+
return matches.map((match, index) => {
|
|
498
|
+
const nextMatch = matches[index + 1];
|
|
499
|
+
const block = markdown.slice(match.index, nextMatch?.index ?? markdown.length);
|
|
500
|
+
return {
|
|
501
|
+
id: match[2],
|
|
502
|
+
checked: match[1].toLowerCase() === "x",
|
|
503
|
+
title: match[3].trim(),
|
|
504
|
+
block,
|
|
505
|
+
validation: readTaskField(block, "Validation"),
|
|
506
|
+
evidence: readTaskField(block, "Evidence"),
|
|
507
|
+
};
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
function readTaskField(block, field) {
|
|
511
|
+
const match = new RegExp(`^\\s*-\\s+\\*{0,2}${escapeRegExp(field)}:\\*{0,2}\\s*(.+?)\\s*$`, "m").exec(block);
|
|
512
|
+
return match?.[1]?.trim();
|
|
513
|
+
}
|
|
514
|
+
function isConcreteTaskValidation(value) {
|
|
515
|
+
return isConcreteText(value);
|
|
516
|
+
}
|
|
517
|
+
function isConcreteTaskEvidence(value) {
|
|
518
|
+
return isConcreteText(value);
|
|
519
|
+
}
|
|
520
|
+
function isConcreteText(value) {
|
|
521
|
+
if (!value) {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
const normalized = value.trim().toLowerCase();
|
|
525
|
+
if (normalized.length < 8) {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
return !["pending", "todo", "tbd", "none", "n/a", "na", "done", "complete", "completed", "yes"].includes(normalized);
|
|
529
|
+
}
|
|
530
|
+
function isExplicitlyDeferred(value) {
|
|
531
|
+
if (!isConcreteText(value)) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
return /\b(deferred|blocked|waived)\b/i.test(value ?? "");
|
|
535
|
+
}
|
|
536
|
+
function isAcceptedExtensionDeferral(result) {
|
|
537
|
+
return result.status === "skipped" && /\b(deferred|waived|accepted)\b/i.test(result.summary);
|
|
538
|
+
}
|
|
539
|
+
function validateReviewConfig(value, path, issues) {
|
|
540
|
+
if (!isRecord(value)) {
|
|
541
|
+
issues.push(error("config.review.type", "config.review must be an object.", path));
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
if (typeof value.required !== "boolean") {
|
|
545
|
+
issues.push(error("config.review.required", "config.review.required must be a boolean.", `${path}.required`));
|
|
546
|
+
}
|
|
547
|
+
if ("port" in value && (!Number.isInteger(value.port) || value.port < 1 || value.port > 65535)) {
|
|
548
|
+
issues.push(error("config.review.port", "config.review.port must be an integer from 1 to 65535.", `${path}.port`));
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function validateExtensionConfigs(value, path, issues) {
|
|
552
|
+
if (!isRecord(value)) {
|
|
553
|
+
issues.push(error("config.extensions.type", "config.extensions must be an object.", path));
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
for (const [name, extension] of Object.entries(value)) {
|
|
557
|
+
const extensionPath = `${path}.${name}`;
|
|
558
|
+
if (!isRecord(extension)) {
|
|
559
|
+
issues.push(error("config.extensions.item", "each extension config must be an object.", extensionPath));
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
if (typeof extension.enabled !== "boolean") {
|
|
563
|
+
issues.push(error("config.extensions.enabled", "extension enabled must be a boolean.", `${extensionPath}.enabled`));
|
|
564
|
+
}
|
|
565
|
+
if ("required" in extension && typeof extension.required !== "boolean") {
|
|
566
|
+
issues.push(error("config.extensions.required", "extension required must be a boolean.", `${extensionPath}.required`));
|
|
567
|
+
}
|
|
568
|
+
if ("hooks" in extension) {
|
|
569
|
+
validateStringArray(extension.hooks, `${extensionPath}.hooks`, "config.extensions.hooks", issues);
|
|
570
|
+
}
|
|
571
|
+
if ("command" in extension && typeof extension.command !== "string") {
|
|
572
|
+
issues.push(error("config.extensions.command", "extension command must be a string.", `${extensionPath}.command`));
|
|
573
|
+
}
|
|
574
|
+
if ("outputs" in extension) {
|
|
575
|
+
validateStringArray(extension.outputs, `${extensionPath}.outputs`, "config.extensions.outputs", issues);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
function validateStringArray(value, path, code, issues) {
|
|
580
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
581
|
+
issues.push(error(code, `${path} must be an array of strings.`, path));
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
function validateReviewAnnotations(value, path, issues) {
|
|
585
|
+
if (!Array.isArray(value)) {
|
|
586
|
+
issues.push(error("review.annotations", `${path} must be an array.`, path));
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
value.forEach((annotation, index) => {
|
|
590
|
+
const annotationPath = `${path}[${index}]`;
|
|
591
|
+
if (!isRecord(annotation)) {
|
|
592
|
+
issues.push(error("review.annotation.type", "review annotation must be an object.", annotationPath));
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (!nonEmptyString(annotation.id)) {
|
|
596
|
+
issues.push(error("review.annotation.id", "review annotation id must be a non-empty string.", `${annotationPath}.id`));
|
|
597
|
+
}
|
|
598
|
+
if (!isReviewAnnotationArtifact(annotation.artifact)) {
|
|
599
|
+
issues.push(error("review.annotation.artifact", "review annotation artifact must be one of: SPEC.md, TASKS.md, CONTEXT.md, PLAN.md, SUMMARY.md.", `${annotationPath}.artifact`));
|
|
600
|
+
}
|
|
601
|
+
if ("section" in annotation && typeof annotation.section !== "string") {
|
|
602
|
+
issues.push(error("review.annotation.section", "review annotation section must be a string when present.", `${annotationPath}.section`));
|
|
603
|
+
}
|
|
604
|
+
if ("lineStart" in annotation && (!Number.isInteger(annotation.lineStart) || annotation.lineStart < 1)) {
|
|
605
|
+
issues.push(error("review.annotation.lineStart", "review annotation lineStart must be an integer greater than 0.", `${annotationPath}.lineStart`));
|
|
606
|
+
}
|
|
607
|
+
if ("lineEnd" in annotation && (!Number.isInteger(annotation.lineEnd) || annotation.lineEnd < 1)) {
|
|
608
|
+
issues.push(error("review.annotation.lineEnd", "review annotation lineEnd must be an integer greater than 0.", `${annotationPath}.lineEnd`));
|
|
609
|
+
}
|
|
610
|
+
if (Number.isInteger(annotation.lineStart) &&
|
|
611
|
+
Number.isInteger(annotation.lineEnd) &&
|
|
612
|
+
annotation.lineEnd < annotation.lineStart) {
|
|
613
|
+
issues.push(error("review.annotation.lineRange", "review annotation lineEnd must be greater than or equal to lineStart.", annotationPath));
|
|
614
|
+
}
|
|
615
|
+
if (!isReviewAnnotationKind(annotation.kind)) {
|
|
616
|
+
issues.push(error("review.annotation.kind", "review annotation kind must be question, change, risk, or nit.", `${annotationPath}.kind`));
|
|
617
|
+
}
|
|
618
|
+
if (annotation.severity !== "blocking" && annotation.severity !== "non_blocking") {
|
|
619
|
+
issues.push(error("review.annotation.severity", "review annotation severity must be blocking or non_blocking.", `${annotationPath}.severity`));
|
|
620
|
+
}
|
|
621
|
+
if (!nonEmptyString(annotation.text)) {
|
|
622
|
+
issues.push(error("review.annotation.text", "review annotation text must be a non-empty string.", `${annotationPath}.text`));
|
|
623
|
+
}
|
|
624
|
+
if (annotation.status !== "open" && annotation.status !== "resolved") {
|
|
625
|
+
issues.push(error("review.annotation.status", "review annotation status must be open or resolved.", `${annotationPath}.status`));
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
function validateCatalogEntries(entries, path, issues) {
|
|
630
|
+
entries.forEach((entry, index) => {
|
|
631
|
+
const entryPath = `${path}[${index}]`;
|
|
632
|
+
if (!isRecord(entry)) {
|
|
633
|
+
issues.push(error("knowledge.catalog.entry.type", "Each catalog entry must be an object.", entryPath));
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
if (!nonEmptyString(entry.id)) {
|
|
637
|
+
issues.push(error("knowledge.catalog.entry.id", "Catalog entry id must be a non-empty string.", `${entryPath}.id`));
|
|
638
|
+
}
|
|
639
|
+
if (typeof entry.type !== "string" || entry.type.trim().length === 0) {
|
|
640
|
+
issues.push(error("knowledge.catalog.entry.type", "Catalog entry type must be a non-empty string.", `${entryPath}.type`));
|
|
641
|
+
}
|
|
642
|
+
if (!nonEmptyString(entry.title)) {
|
|
643
|
+
issues.push(error("knowledge.catalog.entry.title", "Catalog entry title must be a non-empty string.", `${entryPath}.title`));
|
|
644
|
+
}
|
|
645
|
+
if (!Array.isArray(entry.tags)) {
|
|
646
|
+
issues.push(error("knowledge.catalog.entry.tags", "Catalog entry tags must be an array.", `${entryPath}.tags`));
|
|
647
|
+
}
|
|
648
|
+
if (!Array.isArray(entry.scope)) {
|
|
649
|
+
issues.push(error("knowledge.catalog.entry.scope", "Catalog entry scope must be an array.", `${entryPath}.scope`));
|
|
650
|
+
}
|
|
651
|
+
if (typeof entry.summary !== "string") {
|
|
652
|
+
issues.push(error("knowledge.catalog.entry.summary", "Catalog entry summary must be a string.", `${entryPath}.summary`));
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
function validateIndexEntries(entries, path, issues) {
|
|
657
|
+
entries.forEach((entry, index) => {
|
|
658
|
+
const entryPath = `${path}[${index}]`;
|
|
659
|
+
if (!isRecord(entry)) {
|
|
660
|
+
issues.push(error("knowledge.index.entry.type", "Each index entry must be an object.", entryPath));
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
if (!nonEmptyString(entry.id)) {
|
|
664
|
+
issues.push(error("knowledge.index.entry.id", "Index entry id must be a non-empty string.", `${entryPath}.id`));
|
|
665
|
+
}
|
|
666
|
+
if (!nonEmptyString(entry.title)) {
|
|
667
|
+
issues.push(error("knowledge.index.entry.title", "Index entry title must be a non-empty string.", `${entryPath}.title`));
|
|
668
|
+
}
|
|
669
|
+
if (!Array.isArray(entry.tags)) {
|
|
670
|
+
issues.push(error("knowledge.index.entry.tags", "Index entry tags must be an array.", `${entryPath}.tags`));
|
|
671
|
+
}
|
|
672
|
+
if (!Array.isArray(entry.scope)) {
|
|
673
|
+
issues.push(error("knowledge.index.entry.scope", "Index entry scope must be an array.", `${entryPath}.scope`));
|
|
674
|
+
}
|
|
675
|
+
if (typeof entry.summary !== "string") {
|
|
676
|
+
issues.push(error("knowledge.index.entry.summary", "Index entry summary must be a string.", `${entryPath}.summary`));
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
function requireHeading(markdown, heading, path, issues) {
|
|
681
|
+
const escaped = escapeRegExp(heading);
|
|
682
|
+
if (!new RegExp(`^${escaped}\\s*$`, "m").test(markdown)) {
|
|
683
|
+
issues.push(error("markdown.heading", `${path} must include "${heading}".`, path));
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function requireHeadingPattern(markdown, pattern, label, path, issues) {
|
|
687
|
+
if (!pattern.test(markdown)) {
|
|
688
|
+
issues.push(error("markdown.heading", `${path} must include "${label}".`, path));
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
function requireLinePrefix(markdown, prefix, path, issues) {
|
|
692
|
+
const escaped = escapeRegExp(prefix);
|
|
693
|
+
if (!new RegExp(`^${escaped}`, "m").test(markdown)) {
|
|
694
|
+
issues.push(error("markdown.field", `${path} must include "${prefix}".`, path));
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
function readListValue(markdown, field) {
|
|
698
|
+
const match = new RegExp(`^-\\s+${escapeRegExp(field)}:\\s*(.+?)\\s*$`, "m").exec(markdown);
|
|
699
|
+
return match?.[1]?.trim();
|
|
700
|
+
}
|
|
701
|
+
function isOpenFlowStage(value) {
|
|
702
|
+
return typeof value === "string" && OPENFLOW_STAGES.includes(value);
|
|
703
|
+
}
|
|
704
|
+
function isOpenFlowLevel(value) {
|
|
705
|
+
return typeof value === "string" && OPENFLOW_LEVELS.includes(value);
|
|
706
|
+
}
|
|
707
|
+
function isFlowGate(value) {
|
|
708
|
+
return typeof value === "string" && FLOW_GATES.includes(value);
|
|
709
|
+
}
|
|
710
|
+
function isReviewStatus(value) {
|
|
711
|
+
return typeof value === "string" && REVIEW_STATUSES.includes(value);
|
|
712
|
+
}
|
|
713
|
+
function isReviewAnnotationArtifact(value) {
|
|
714
|
+
return value === "SPEC.md" || value === "TASKS.md" || value === "CONTEXT.md" || value === "PLAN.md" || value === "SUMMARY.md";
|
|
715
|
+
}
|
|
716
|
+
function isReviewAnnotationKind(value) {
|
|
717
|
+
return value === "question" || value === "change" || value === "risk" || value === "nit";
|
|
718
|
+
}
|
|
719
|
+
function isExtensionStatus(value) {
|
|
720
|
+
return typeof value === "string" && EXTENSION_STATUSES.includes(value);
|
|
721
|
+
}
|
|
722
|
+
function isIsoDate(value) {
|
|
723
|
+
if (!/^\d{4}-\d{2}-\d{2}T/.test(value)) {
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
const time = Date.parse(value);
|
|
727
|
+
return Number.isFinite(time);
|
|
728
|
+
}
|
|
729
|
+
function isFlowStateValue(value) {
|
|
730
|
+
return (isRecord(value) &&
|
|
731
|
+
typeof value.id === "string" &&
|
|
732
|
+
typeof value.title === "string" &&
|
|
733
|
+
isOpenFlowLevel(value.level) &&
|
|
734
|
+
isOpenFlowStage(value.stage) &&
|
|
735
|
+
Number.isInteger(value.revision) &&
|
|
736
|
+
isFlowGate(value.gate));
|
|
737
|
+
}
|
|
738
|
+
function isReviewResultValue(value) {
|
|
739
|
+
return (isRecord(value) &&
|
|
740
|
+
(value.stage === "spec" || value.stage === "plan" || value.stage === "prd" || value.stage === "archive") &&
|
|
741
|
+
Number.isInteger(value.revision) &&
|
|
742
|
+
isReviewStatus(value.status) &&
|
|
743
|
+
typeof value.reviewedAt === "string" &&
|
|
744
|
+
Array.isArray(value.comments) &&
|
|
745
|
+
Array.isArray(value.requestedChanges));
|
|
746
|
+
}
|
|
747
|
+
function isExtensionResultValue(value) {
|
|
748
|
+
return (isRecord(value) &&
|
|
749
|
+
typeof value.name === "string" &&
|
|
750
|
+
isExtensionStatus(value.status) &&
|
|
751
|
+
typeof value.required === "boolean" &&
|
|
752
|
+
typeof value.summary === "string" &&
|
|
753
|
+
Array.isArray(value.artifacts) &&
|
|
754
|
+
typeof value.createdAt === "string");
|
|
755
|
+
}
|
|
756
|
+
function validateKnowledgeCitations(value, path, issues) {
|
|
757
|
+
if (!Array.isArray(value)) {
|
|
758
|
+
issues.push(error("flow.knowledgeCitations.type", "flow.knowledge_citations must be an array.", path));
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
762
|
+
const item = value[index];
|
|
763
|
+
const itemPath = `${path}[${index}]`;
|
|
764
|
+
if (!isRecord(item)) {
|
|
765
|
+
issues.push(error("flow.knowledgeCitations.item", "Each knowledge_citations entry must be an object.", itemPath));
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
if (typeof item.id !== "string" || item.id.trim().length === 0) {
|
|
769
|
+
issues.push(error("flow.knowledgeCitations.id", "Each citation must have a non-empty id.", `${itemPath}.id`));
|
|
770
|
+
}
|
|
771
|
+
if (item.phase !== "spec" && item.phase !== "implement") {
|
|
772
|
+
issues.push(error("flow.knowledgeCitations.phase", "Citation phase must be spec or implement.", `${itemPath}.phase`));
|
|
773
|
+
}
|
|
774
|
+
if ("wave" in item && item.wave !== null && typeof item.wave !== "string") {
|
|
775
|
+
issues.push(error("flow.knowledgeCitations.wave", "Citation wave must be a string or null.", `${itemPath}.wave`));
|
|
776
|
+
}
|
|
777
|
+
if (typeof item.injected_at !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(item.injected_at)) {
|
|
778
|
+
issues.push(error("flow.knowledgeCitations.injectedAt", "Citation injected_at must be a YYYY-MM-DD date.", `${itemPath}.injected_at`));
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function isRecord(value) {
|
|
783
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
784
|
+
}
|
|
785
|
+
function isLanguageTag(value) {
|
|
786
|
+
return typeof value === "string" && /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(value.trim());
|
|
787
|
+
}
|
|
788
|
+
function nonEmptyString(value) {
|
|
789
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
790
|
+
}
|
|
791
|
+
function escapeRegExp(value) {
|
|
792
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
793
|
+
}
|
|
794
|
+
function error(code, message, path) {
|
|
795
|
+
return { code, message, path, severity: "error" };
|
|
796
|
+
}
|
|
797
|
+
function warning(code, message, path) {
|
|
798
|
+
return { code, message, path, severity: "warning" };
|
|
799
|
+
}
|
|
800
|
+
function withIssues(issues) {
|
|
801
|
+
return fromIssues(issues.map((issue) => ({ severity: "error", ...issue })));
|
|
802
|
+
}
|
|
803
|
+
function fromIssues(issues) {
|
|
804
|
+
return {
|
|
805
|
+
valid: issues.every((issue) => issue.severity !== "error"),
|
|
806
|
+
issues
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
//# sourceMappingURL=artifacts.js.map
|