gitifact 0.1.0 → 0.3.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/README.md +9 -6
- package/dist/THIRD_PARTY_NOTICES.txt +0 -198
- package/dist/browser/assets/{BottomSheet-DUajo7ZC.js → BottomSheet-DFEd7qcJ.js} +1 -1
- package/dist/browser/assets/{Icon-BL6mvojd.js → IconButton-DQKowV1I.js} +2 -2
- package/dist/browser/assets/{MenuBottomSheet-uD8HCpnn.js → MenuBottomSheet-BKiLm4Gk.js} +1 -1
- package/dist/browser/assets/{Section-CxDofIgF.js → Section-CXNZYeQ6.js} +1 -1
- package/dist/browser/assets/{Text-DRvg_LY8.js → Text-LX6541eF.js} +2 -2
- package/dist/browser/assets/TimestampHoverCard-CEVz4ZE2.js +1 -0
- package/dist/browser/assets/{Tooltip-CSXUs0wo.js → Tooltip-CH5OxdmX.js} +1 -1
- package/dist/browser/assets/about-Dbyd48t6.js +1 -0
- package/dist/browser/assets/contributors._email-BMqQlPdF.js +1 -0
- package/dist/browser/assets/{contributors-DG1A_fxV.js → contributors.index-Dk42HR-l.js} +1 -1
- package/dist/browser/assets/features._featureId-zHnvA0Go.js +1 -0
- package/dist/browser/assets/{requirements-CSGZCMPA.js → features.index-xgyvTm5d.js} +1 -1
- package/dist/browser/assets/git-D8SQ9LAI.js +1 -0
- package/dist/browser/assets/git-nj7fScNQ.css +1 -0
- package/dist/browser/assets/guides._documentId-jvtVZl4b.js +1 -0
- package/dist/browser/assets/guides.index-DKNn9kCJ.js +1 -0
- package/dist/browser/assets/{ime-DpJB0Xdq.js → ime-u5HljzMu.js} +1 -1
- package/dist/browser/assets/index-CiEgP5lo.css +1 -0
- package/dist/browser/assets/index-Cul6rpdA.js +56 -0
- package/dist/browser/assets/page-header-9-i3H9WR.css +1 -0
- package/dist/browser/assets/page-header-pnZFm0-7.js +56 -0
- package/dist/browser/assets/product-B_C25r7E.js +75 -0
- package/dist/browser/assets/product-DIl1IXZo.css +1 -0
- package/dist/browser/assets/product.index-IBLtgiMT.js +1 -0
- package/dist/browser/assets/request-state-q7VzEh1O.js +3 -0
- package/dist/browser/assets/requirements-BmW8BEdu.js +1 -0
- package/dist/browser/assets/{routes-E_7O-5Bj.js → routes-BDsb61_V.js} +1 -1
- package/dist/browser/assets/useClipboard-D2fN4Nhs.js +1 -0
- package/dist/browser/assets/{useIsomorphicLayoutEffect-C7U2IcbD.js → useIsomorphicLayoutEffect-DPqcigQ0.js} +1 -1
- package/dist/browser/favicon.png +0 -0
- package/dist/browser/favicon.svg +5 -0
- package/dist/browser/index.html +24 -15
- package/dist/docs/commit.md +36 -0
- package/dist/docs/design.md +42 -0
- package/dist/docs/product.md +21 -0
- package/dist/docs/spec.md +54 -0
- package/dist/docs/workflow.md +42 -0
- package/dist/main.js +902 -469
- package/package.json +1 -1
- package/dist/browser/assets/IconButton-lHbix98V.js +0 -1
- package/dist/browser/assets/Table-DeD03NuQ.js +0 -3
- package/dist/browser/assets/TimestampHoverCard-CdwdDY2W.js +0 -1
- package/dist/browser/assets/about-BDnPkVlL.js +0 -1
- package/dist/browser/assets/features-8KaaKFr1.js +0 -1
- package/dist/browser/assets/git-BLYFkHAP.js +0 -1
- package/dist/browser/assets/index-CFjKQp32.js +0 -56
- package/dist/browser/assets/index-DnHDaIjm.css +0 -1
- package/dist/browser/assets/noto-sans-kr-0-800-normal-Bw_wPEW6.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-0-800-normal-CU2ZAuxN.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-1-800-normal-Bv79PX5h.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-1-800-normal-J_tKEQwZ.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-10-800-normal-DE_9FlHK.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-10-800-normal-DRiks4sP.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-100-800-normal-BwmJ5UQj.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-100-800-normal-DmRRRn-a.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-101-800-normal-B-hehSjp.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-101-800-normal-YdhdcxJt.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-102-800-normal-C6kOYHZD.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-102-800-normal-C_hmEXnv.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-103-800-normal-CmDrDQ9V.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-103-800-normal-c5SsBHZM.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-104-800-normal-CHG9R-zy.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-104-800-normal-DMx294uT.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-105-800-normal-BmLq4tHL.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-105-800-normal-fEWHmGbY.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-106-800-normal-CjjLA4cZ.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-106-800-normal-Du7jON9q.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-107-800-normal-5ie2GORa.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-107-800-normal-B-vw3liL.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-108-800-normal-BR9Zw7IY.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-108-800-normal-VCcXKMkT.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-109-800-normal-C7tEA3KS.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-109-800-normal-IlLk0ufL.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-11-800-normal-BinZyvQR.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-11-800-normal-CL9Ahwpo.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-110-800-normal-DEZBQ-5W.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-110-800-normal-Do0gAnv1.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-111-800-normal-Cxb-EKnN.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-111-800-normal-D1o1iTAW.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-112-800-normal-DvsOBbyY.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-112-800-normal-HV4h3xxa.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-113-800-normal-DXGusidw.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-113-800-normal-tbylWl5F.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-114-800-normal-BICMpgoW.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-114-800-normal-DU1U5ue1.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-115-800-normal-C1oRdW1M.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-115-800-normal-CLr-Zxv_.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-116-800-normal-C9sKyFCZ.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-116-800-normal-CtM3GUM6.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-117-800-normal-3A2aP5IS.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-117-800-normal-DwrcPOym.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-118-800-normal-CsMV-v3_.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-118-800-normal-DV16Oj1F.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-119-800-normal-Bxd2OEQS.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-119-800-normal-C3JA3uCT.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-12-800-normal-BLqjm9D5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-12-800-normal-BdSxEe2g.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-13-800-normal-8rZnesK8.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-13-800-normal-BedB76c8.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-14-800-normal-BtiVONz_.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-14-800-normal-mA9SFjVh.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-15-800-normal-BYbeZAE2.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-15-800-normal-CXEvvUix.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-16-800-normal-B8OWqNF3.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-16-800-normal-CQuF5Ih3.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-17-800-normal-CTUGDjHX.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-17-800-normal-DNvAlAcZ.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-18-800-normal-Petpk6Wi.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-18-800-normal-ThFSRZa4.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-19-800-normal-BMyRF7fz.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-19-800-normal-BNNtnBhl.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-2-800-normal-CQ6iDWMP.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-2-800-normal-DrQB0PtS.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-20-800-normal-CuNmAe4n.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-20-800-normal-DdfIMDx9.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-21-800-normal-C08X3_0x.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-21-800-normal-Dn-tQ8Cr.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-22-800-normal-B6q-RFF5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-22-800-normal-DZF106py.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-23-800-normal-B0lHlsqh.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-23-800-normal-DRCDT0r0.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-24-800-normal-C1wKob6w.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-24-800-normal-DG0Bfaz1.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-25-800-normal-BuWQxFvN.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-25-800-normal-DlN6uf6B.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-26-800-normal-BQPGMN-7.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-26-800-normal-CYgTLzoi.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-27-800-normal-DsrJXERC.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-27-800-normal-eDTiDgrj.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-28-800-normal-CmRY-nZ4.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-28-800-normal-CpLjKGyi.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-29-800-normal-BFNDreIt.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-29-800-normal-CDzh3Sik.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-3-800-normal-CAuXj4Ks.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-3-800-normal-DkylunKW.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-30-800-normal-D4A2u9et.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-30-800-normal-t7TpxFL5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-31-800-normal-D1jtl7Q7.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-31-800-normal-DX9UFu0w.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-32-800-normal-B-9BPuXB.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-32-800-normal-Bm8HsYTW.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-33-800-normal-CBJnLOB4.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-33-800-normal-Lp3eLj8E.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-34-800-normal-BTn3_cSG.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-34-800-normal-C7F12ZiM.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-35-800-normal--n-itfth.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-35-800-normal-DMKFJwpr.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-36-800-normal-DP2FYFvb.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-36-800-normal-Udjkk8cw.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-37-800-normal-BJ3T0Ds4.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-37-800-normal-vbBvr6Mj.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-38-800-normal-DHyLtjF-.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-38-800-normal-DY5ycwVP.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-39-800-normal-BYRd7hnV.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-39-800-normal-BbTuYCr_.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-4-800-normal-DaMhz_mp.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-4-800-normal-DcaaVzHe.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-40-800-normal-kb_Elzoh.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-40-800-normal-pcG3sBn_.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-41-800-normal-B5pJMNX9.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-41-800-normal-Becq2RH9.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-42-800-normal-DFBF7PpF.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-42-800-normal-DkTTYUqF.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-43-800-normal-CijJp3m4.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-43-800-normal-DzNpr1oi.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-44-800-normal-8gcTNNZz.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-44-800-normal-DipWX1RS.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-45-800-normal-CNAISROp.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-45-800-normal-zw2L23b5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-46-800-normal-B5EFObh7.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-46-800-normal-Be8SS2VS.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-47-800-normal-CWuA3LZo.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-47-800-normal-KHZYT9s5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-48-800-normal-DOY1zu52.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-48-800-normal-X43Exj68.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-49-800-normal-BDUKdhR6.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-49-800-normal-CqO6w8TQ.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-5-800-normal-B6D-Yisg.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-5-800-normal-CYVng5-O.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-50-800-normal-278ctRQM.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-50-800-normal-D8iwvLic.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-51-800-normal-BaGYW3mn.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-51-800-normal-DVNzNOzs.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-52-800-normal-DFoNpPkV.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-52-800-normal-PYkRemOp.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-53-800-normal-Cal8VidM.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-53-800-normal-VTCBtYDl.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-54-800-normal-D87sXgkk.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-54-800-normal-IXtT1yi4.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-55-800-normal-BHlclLP6.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-55-800-normal-CDsENtgr.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-56-800-normal-BC24-4fs.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-56-800-normal-yP6meTAz.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-57-800-normal-DHZYjKKG.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-57-800-normal-Db3MU7be.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-58-800-normal-Bgj8xXYj.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-58-800-normal-DkonTaND.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-59-800-normal-CDotMClO.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-59-800-normal-F9A2zoTv.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-6-800-normal-0EETWYnS.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-6-800-normal-DvzBE-Ju.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-60-800-normal-CFYPd-h9.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-60-800-normal-CsKtzFP-.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-61-800-normal-CcpiOzGM.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-61-800-normal-Dr8kbSyF.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-62-800-normal-CUSp51L1.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-62-800-normal-juHSbMFI.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-63-800-normal-C-Jv8bed.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-63-800-normal-DyZHAD6M.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-64-800-normal-CcBn_W6-.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-64-800-normal-DZDmEpbV.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-65-800-normal-B6c9hlnM.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-65-800-normal-CUX4NhcL.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-66-800-normal-BicMJeOH.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-66-800-normal-C8Teepkx.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-67-800-normal-BDuNl8zH.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-67-800-normal-DV8QzaX3.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-68-800-normal-B-uLhfx0.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-68-800-normal-D5rgL5jh.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-69-800-normal-Cvs4DPNE.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-69-800-normal-DS_MTTAa.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-7-800-normal-BV0xbNLH.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-7-800-normal-DSoiWegj.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-70-800-normal-2_gMfyoa.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-70-800-normal-Ccivp_R5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-71-800-normal-BKDmUMNW.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-71-800-normal-BodPXKoj.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-72-800-normal-DWkAPAKb.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-72-800-normal-D_-QJd8k.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-73-800-normal-BWGKteHn.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-73-800-normal-CoWOTZbQ.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-74-800-normal-ClYMONqb.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-74-800-normal-DO42epRW.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-75-800-normal-DeRDdZX1.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-75-800-normal-GBSDTxzy.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-76-800-normal-De3chvya.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-76-800-normal-G-QSyD_x.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-77-800-normal-BqaEcnIO.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-77-800-normal-D_prdc66.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-78-800-normal-CBVRfgq1.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-78-800-normal-CNFTj3Q6.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-79-800-normal-CHvPT7M2.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-79-800-normal-l-9QHPwU.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-8-800-normal-BVnjuvZV.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-8-800-normal-CW9POvIA.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-80-800-normal-BmDyH9qV.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-80-800-normal-CcFmOj-_.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-81-800-normal-BebVz-4m.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-81-800-normal-Chq57HAf.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-82-800-normal-PBYyv2iB.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-82-800-normal-T-Uuq98C.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-83-800-normal-Ebp3T0Cc.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-83-800-normal-YBUm2gi-.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-84-800-normal-B5fzB2_B.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-84-800-normal-CjUaLFZH.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-85-800-normal-B3EF-yy4.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-85-800-normal-BNXCj4iI.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-86-800-normal-CJ-r59U1.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-86-800-normal-DsjCgbm5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-87-800-normal-BP7eds1i.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-87-800-normal-DLjlXPBa.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-88-800-normal-D3d48PyQ.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-88-800-normal-Yz-IPA9D.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-89-800-normal-C3brTUST.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-89-800-normal-DPV6dJIF.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-9-800-normal-BUEQgTu0.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-9-800-normal-DSOwaGDE.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-90-800-normal-BIRlwXwP.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-90-800-normal-Dynpszs5.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-91-800-normal-CXzl4gBc.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-91-800-normal-CgDxpVz2.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-92-800-normal-CBFbbVQL.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-92-800-normal-DlmY38cH.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-93-800-normal-D7ItOUjg.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-93-800-normal-D9xl1xM9.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-94-800-normal-B4_1-zLI.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-94-800-normal-D_inom35.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-95-800-normal-5wwFPIYQ.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-95-800-normal-LEtKc04Z.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-96-800-normal-BPumKL3d.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-96-800-normal-LcPZgb3x.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-97-800-normal-B6DuSXHl.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-97-800-normal-CM_R_M9F.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-98-800-normal-BIIfv0pl.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-98-800-normal-Db3f-61W.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-99-800-normal-Bw0sYswE.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-99-800-normal-iudhGOO-.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-cyrillic-800-normal-CfofMVm8.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-cyrillic-800-normal-DYNGV4gq.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-latin-800-normal-BYRGi1Y1.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-latin-800-normal-LOyLFpCE.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-latin-ext-800-normal-BLx4oR_u.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-latin-ext-800-normal-Ct5SpdHD.woff +0 -0
- package/dist/browser/assets/noto-sans-kr-vietnamese-800-normal-B93Gh2EH.woff2 +0 -0
- package/dist/browser/assets/noto-sans-kr-vietnamese-800-normal-DSdRDyh3.woff +0 -0
- package/dist/browser/assets/outfit-latin-800-normal-BRHLSPcU.woff +0 -0
- package/dist/browser/assets/page-header-BMoXdF8-.css +0 -1
- package/dist/browser/assets/page-header-_RNO4t-D.js +0 -56
- package/dist/browser/assets/product-C_SFSrKx.js +0 -75
- package/dist/browser/assets/product-f-WX-_YX.css +0 -1
- package/dist/skills/gitifact-workflow/SKILL.md +0 -157
- /package/dist/browser/{assets/outfit-latin-800-normal-CQna6-G7.woff2 → fonts/outfit-latin-800-normal.woff2} +0 -0
package/dist/main.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
-
var __export = (
|
|
3
|
+
var __export = (target, all) => {
|
|
4
4
|
for (var name in all)
|
|
5
|
-
__defProp(
|
|
5
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// scripts/node-require.mjs
|
|
@@ -1635,9 +1635,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1635
1635
|
* @param {string} invalidArgumentMessage
|
|
1636
1636
|
* @private
|
|
1637
1637
|
*/
|
|
1638
|
-
_callParseArg(
|
|
1638
|
+
_callParseArg(target, value, previous, invalidArgumentMessage) {
|
|
1639
1639
|
try {
|
|
1640
|
-
return
|
|
1640
|
+
return target.parseArg(value, previous);
|
|
1641
1641
|
} catch (err) {
|
|
1642
1642
|
if (err.code === "commander.invalidArgument") {
|
|
1643
1643
|
const message = `${invalidArgumentMessage} ${err.message}`;
|
|
@@ -1926,13 +1926,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1926
1926
|
* @param {string} source - expected values are default/config/env/cli/implied
|
|
1927
1927
|
* @return {Command} `this` command for chaining
|
|
1928
1928
|
*/
|
|
1929
|
-
setOptionValueWithSource(key, value,
|
|
1929
|
+
setOptionValueWithSource(key, value, source) {
|
|
1930
1930
|
if (this._storeOptionsAsProperties) {
|
|
1931
1931
|
this[key] = value;
|
|
1932
1932
|
} else {
|
|
1933
1933
|
this._optionValues[key] = value;
|
|
1934
1934
|
}
|
|
1935
|
-
this._optionValueSources[key] =
|
|
1935
|
+
this._optionValueSources[key] = source;
|
|
1936
1936
|
return this;
|
|
1937
1937
|
}
|
|
1938
1938
|
/**
|
|
@@ -1953,13 +1953,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1953
1953
|
* @return {string}
|
|
1954
1954
|
*/
|
|
1955
1955
|
getOptionValueSourceWithGlobals(key) {
|
|
1956
|
-
let
|
|
1956
|
+
let source;
|
|
1957
1957
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
1958
1958
|
if (cmd.getOptionValueSource(key) !== void 0) {
|
|
1959
|
-
|
|
1959
|
+
source = cmd.getOptionValueSource(key);
|
|
1960
1960
|
}
|
|
1961
1961
|
});
|
|
1962
|
-
return
|
|
1962
|
+
return source;
|
|
1963
1963
|
}
|
|
1964
1964
|
/**
|
|
1965
1965
|
* Get user arguments from implied or explicit arguments.
|
|
@@ -2826,10 +2826,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2826
2826
|
const optionKey = option2.attributeName();
|
|
2827
2827
|
const optionValue = this.getOptionValue(optionKey);
|
|
2828
2828
|
const negativeOption = this.options.find(
|
|
2829
|
-
(
|
|
2829
|
+
(target) => target.negate && optionKey === target.attributeName()
|
|
2830
2830
|
);
|
|
2831
2831
|
const positiveOption = this.options.find(
|
|
2832
|
-
(
|
|
2832
|
+
(target) => !target.negate && optionKey === target.attributeName()
|
|
2833
2833
|
);
|
|
2834
2834
|
if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
|
|
2835
2835
|
return negativeOption;
|
|
@@ -2839,8 +2839,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2839
2839
|
const getErrorMessage = (option2) => {
|
|
2840
2840
|
const bestOption = findBestOptionFromValue(option2);
|
|
2841
2841
|
const optionKey = bestOption.attributeName();
|
|
2842
|
-
const
|
|
2843
|
-
if (
|
|
2842
|
+
const source = this.getOptionValueSource(optionKey);
|
|
2843
|
+
if (source === "env") {
|
|
2844
2844
|
return `environment variable '${bestOption.envVar}'`;
|
|
2845
2845
|
}
|
|
2846
2846
|
return `option '${bestOption.flags}'`;
|
|
@@ -3492,12 +3492,36 @@ function parseManagedConfig(text2) {
|
|
|
3492
3492
|
var SpecPreviewError = class extends Error {
|
|
3493
3493
|
code = "INVALID_SPEC_PREVIEW";
|
|
3494
3494
|
};
|
|
3495
|
+
var DOCUMENT_KINDS = ["product", "guide"];
|
|
3496
|
+
var DOCUMENT_DIRS = { product: ".gitifact/product", guide: ".gitifact/guides" };
|
|
3497
|
+
var documentHistoryPath = (kind) => DOCUMENT_DIRS[kind] + "/history.jsonl";
|
|
3498
|
+
var PRODUCT_PATH = ".gitifact/product/PRODUCT.md";
|
|
3499
|
+
var PRODUCT_ASSET_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,120}\.(?:png|jpe?g|gif|svg|webp)$/i;
|
|
3500
|
+
function isProductAssetPath(path3) {
|
|
3501
|
+
const match = /^\.gitifact\/product\/([^/]+)$/.exec(path3);
|
|
3502
|
+
return !!match && PRODUCT_ASSET_NAME.test(match[1]);
|
|
3503
|
+
}
|
|
3495
3504
|
var token = "[a-z2-7]{10}";
|
|
3496
3505
|
var STORE_DIR = ".gitifact";
|
|
3497
3506
|
var LEGACY_STORE_DIR = ".tryce";
|
|
3498
3507
|
var STORE_DIRS = [STORE_DIR, LEGACY_STORE_DIR];
|
|
3499
3508
|
var marker = "(?:gitifact|tryce)";
|
|
3500
|
-
var recordPathPattern =
|
|
3509
|
+
var recordPathPattern = /^(?:\.(?:gitifact|tryce)\/spec\/[^/]+\/(?:requirements\.md|design\.md|history\.jsonl)|\.gitifact\/(?:product|guides)\/(?:(?:[^/]+\/)*[^/]+\.md|history\.jsonl))$/;
|
|
3510
|
+
var documentPathPattern = /^\.gitifact\/(product|guides)\/((?:[^/]+\/)*[^/]+\.md)$/;
|
|
3511
|
+
var documentHistoryPattern = /^\.gitifact\/(product|guides)\/history\.jsonl$/;
|
|
3512
|
+
var kindOfDir = (dir) => dir === "product" ? "product" : "guide";
|
|
3513
|
+
var nameToken = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
3514
|
+
function validateDocumentRelativePath(relative) {
|
|
3515
|
+
const parts = relative.split("/");
|
|
3516
|
+
if (relative.length > 200 || parts.length > 8)
|
|
3517
|
+
fail("\uBB38\uC11C \uACBD\uB85C \uAE4A\uC774 \uB610\uB294 \uAE38\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: " + relative);
|
|
3518
|
+
const file2 = parts.pop();
|
|
3519
|
+
if (!file2.endsWith(".md") || !nameToken.test(file2.slice(0, -3)))
|
|
3520
|
+
fail("\uBB38\uC11C \uD30C\uC77C \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uACFC .md\uC5EC\uC57C \uD569\uB2C8\uB2E4: " + relative);
|
|
3521
|
+
for (const part of parts)
|
|
3522
|
+
if (!nameToken.test(part) || part.length > 80)
|
|
3523
|
+
fail("\uBB38\uC11C \uD3F4\uB354 \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: " + relative);
|
|
3524
|
+
}
|
|
3501
3525
|
var storeRelative = (path3) => path3.replace(/^\.(?:gitifact|tryce)\//, "");
|
|
3502
3526
|
var reqId = new RegExp(`^R-${token}$`);
|
|
3503
3527
|
var fail = (message) => {
|
|
@@ -3512,10 +3536,10 @@ function renderDesignPreview(id, design) {
|
|
|
3512
3536
|
${design.body}
|
|
3513
3537
|
`;
|
|
3514
3538
|
}
|
|
3515
|
-
function parseDesignPreview(
|
|
3516
|
-
if (
|
|
3539
|
+
function parseDesignPreview(source, specId) {
|
|
3540
|
+
if (source.includes("\0") || /\r(?!\n)/.test(source))
|
|
3517
3541
|
fail("\uC798\uBABB\uB41C \uC124\uACC4 \uBB38\uC790\uC785\uB2C8\uB2E4.");
|
|
3518
|
-
const lines = normalized(
|
|
3542
|
+
const lines = normalized(source).split("\n");
|
|
3519
3543
|
if (!new RegExp(`^<!-- ${marker}-design: ${specId} -->$`).test(lines.shift() ?? ""))
|
|
3520
3544
|
fail("\uC124\uACC4\uC758 gitifact-design ID\uB294 \uAC19\uC740 \uAE30\uB2A5\uC758 S-ID\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
|
|
3521
3545
|
while (lines[0] === "")
|
|
@@ -3556,27 +3580,138 @@ function parseDesignPreview(source2, specId) {
|
|
|
3556
3580
|
fail("\uC124\uACC4 \uCF54\uB4DC \uBE14\uB85D\uC774 \uB2EB\uD788\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
3557
3581
|
return { title, body, requirements: [...references] };
|
|
3558
3582
|
}
|
|
3583
|
+
function renderDocument(doc) {
|
|
3584
|
+
return `<!-- gitifact-${doc.kind}: ${doc.id} -->
|
|
3585
|
+
|
|
3586
|
+
# ${doc.title}
|
|
3587
|
+
|
|
3588
|
+
${doc.body}
|
|
3589
|
+
`;
|
|
3590
|
+
}
|
|
3591
|
+
function parseDocument(path3, source) {
|
|
3592
|
+
const match = documentPathPattern.exec(path3);
|
|
3593
|
+
if (!match)
|
|
3594
|
+
fail("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBB38\uC11C \uACBD\uB85C: " + path3);
|
|
3595
|
+
const kind = kindOfDir(match[1]);
|
|
3596
|
+
if (kind === "product") {
|
|
3597
|
+
if (path3 !== PRODUCT_PATH)
|
|
3598
|
+
fail("\uC81C\uD488 \uD3F4\uB354\uC5D0\uB294 PRODUCT.md \uD558\uB098\uB9CC \uB461\uB2C8\uB2E4: " + path3);
|
|
3599
|
+
} else
|
|
3600
|
+
validateDocumentRelativePath(match[2]);
|
|
3601
|
+
if (source.includes("\0") || /\r(?!\n)/.test(source))
|
|
3602
|
+
fail("\uC798\uBABB\uB41C \uBB38\uC11C \uBB38\uC790: " + path3);
|
|
3603
|
+
const lines = normalized(source).split("\n");
|
|
3604
|
+
const id = new RegExp(`^<!-- gitifact-${kind}: ([PG]-${token}) -->$`).exec(lines.shift() ?? "")?.[1];
|
|
3605
|
+
if (!id || id[0] !== (kind === "product" ? "P" : "G"))
|
|
3606
|
+
return fail(`\uCCAB \uC904\uC5D0 \uC720\uD6A8\uD55C gitifact-${kind} \uC8FC\uC11D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: ` + path3);
|
|
3607
|
+
while (lines[0] === "")
|
|
3608
|
+
lines.shift();
|
|
3609
|
+
const heading = lines.shift();
|
|
3610
|
+
if (!heading?.startsWith("# ") || !heading.slice(2).trim())
|
|
3611
|
+
fail("\uBB38\uC11C \uC81C\uBAA9\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: " + path3);
|
|
3612
|
+
const title = heading.slice(2).trim();
|
|
3613
|
+
const body = normalized(lines.join("\n"));
|
|
3614
|
+
if (!body)
|
|
3615
|
+
fail("\uBB38\uC11C \uBCF8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: " + path3);
|
|
3616
|
+
let fence;
|
|
3617
|
+
for (const line of body.split("\n")) {
|
|
3618
|
+
if (fence) {
|
|
3619
|
+
if (new RegExp(`^ {0,3}${fence.char}{${fence.size},}\\s*$`).test(line))
|
|
3620
|
+
fence = void 0;
|
|
3621
|
+
continue;
|
|
3622
|
+
}
|
|
3623
|
+
const open6 = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
|
|
3624
|
+
if (open6) {
|
|
3625
|
+
fence = { char: open6[1][0], size: open6[1].length };
|
|
3626
|
+
continue;
|
|
3627
|
+
}
|
|
3628
|
+
if (/^#\s/.test(line))
|
|
3629
|
+
fail("\uBB38\uC11C \uCD5C\uC0C1\uC704 \uC81C\uBAA9\uC740 \uD558\uB098\uB9CC \uC501\uB2C8\uB2E4: " + path3);
|
|
3630
|
+
if (/<!-- (?:gitifact|tryce)-/.test(line))
|
|
3631
|
+
fail("\uBB38\uC11C \uBCF8\uBB38\uC5D0\uB294 gitifact \uC8FC\uC11D\uC744 \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + path3);
|
|
3632
|
+
}
|
|
3633
|
+
if (fence)
|
|
3634
|
+
fail("\uBB38\uC11C \uCF54\uB4DC \uBE14\uB85D\uC774 \uB2EB\uD788\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: " + path3);
|
|
3635
|
+
return { id, kind, path: path3, title, body };
|
|
3636
|
+
}
|
|
3637
|
+
function parseDocumentFiles(files) {
|
|
3638
|
+
const sets = DOCUMENT_KINDS.map((kind) => ({ kind, documents: [], history: parsePreviewHistory(files.get(documentHistoryPath(kind)) ?? "", "documents") }));
|
|
3639
|
+
for (const [path3, source] of files) {
|
|
3640
|
+
if (!documentPathPattern.test(path3))
|
|
3641
|
+
continue;
|
|
3642
|
+
const doc = parseDocument(path3, source);
|
|
3643
|
+
sets.find((s) => s.kind === doc.kind).documents.push(doc);
|
|
3644
|
+
}
|
|
3645
|
+
for (const set2 of sets)
|
|
3646
|
+
set2.documents.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
3647
|
+
validateDocumentSets(sets);
|
|
3648
|
+
return sets;
|
|
3649
|
+
}
|
|
3650
|
+
function validateDocumentSets(sets) {
|
|
3651
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3652
|
+
const paths2 = /* @__PURE__ */ new Set();
|
|
3653
|
+
const historyIds = /* @__PURE__ */ new Set();
|
|
3654
|
+
if (sets.map((s) => s.kind).sort().join(",") !== "guide,product")
|
|
3655
|
+
fail("\uBB38\uC11C \uC885\uB958 \uC9D1\uD569\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
|
|
3656
|
+
for (const set2 of sets) {
|
|
3657
|
+
for (const d of set2.documents) {
|
|
3658
|
+
if (d.kind !== set2.kind)
|
|
3659
|
+
fail("\uBB38\uC11C \uC885\uB958\uAC00 \uD3F4\uB354\uC640 \uB2E4\uB985\uB2C8\uB2E4: " + d.path);
|
|
3660
|
+
if (ids.has(d.id))
|
|
3661
|
+
fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBB38\uC11C ID: " + d.id);
|
|
3662
|
+
ids.add(d.id);
|
|
3663
|
+
const lower = d.path.toLowerCase();
|
|
3664
|
+
if (paths2.has(lower))
|
|
3665
|
+
fail("\uB300\uC18C\uBB38\uC790\uB9CC \uB2E4\uB978 \uBB38\uC11C \uACBD\uB85C: " + d.path);
|
|
3666
|
+
paths2.add(lower);
|
|
3667
|
+
}
|
|
3668
|
+
for (const h of set2.history) {
|
|
3669
|
+
if (historyIds.has(h.id))
|
|
3670
|
+
fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBCF4\uC870 \uAE30\uB85D ID: " + h.id);
|
|
3671
|
+
historyIds.add(h.id);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
var emptyDocumentSets = () => DOCUMENT_KINDS.map((kind) => ({ kind, documents: [], history: [] }));
|
|
3676
|
+
var asBundle = (value) => Array.isArray(value) ? { specs: value, documents: emptyDocumentSets() } : value;
|
|
3677
|
+
function parsePreviewBundle(files) {
|
|
3678
|
+
const bundle = { specs: parsePreviewFiles(files), documents: parseDocumentFiles(files) };
|
|
3679
|
+
validateBundle(bundle);
|
|
3680
|
+
return bundle;
|
|
3681
|
+
}
|
|
3682
|
+
function validateBundle(bundle) {
|
|
3683
|
+
validatePreviewSnapshot(bundle.specs);
|
|
3684
|
+
validateDocumentSets(bundle.documents);
|
|
3685
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3686
|
+
for (const h of [...bundle.specs.flatMap((s) => s.history), ...bundle.documents.flatMap((d) => d.history)]) {
|
|
3687
|
+
if (ids.has(h.id))
|
|
3688
|
+
fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBCF4\uC870 \uAE30\uB85D ID: " + h.id);
|
|
3689
|
+
ids.add(h.id);
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3559
3692
|
function designReferenceWarnings(specs) {
|
|
3560
3693
|
const known = new Set(specs.flatMap((s) => s.requirements.map((r) => r.id)));
|
|
3561
3694
|
return specs.flatMap((s) => (s.design?.requirements ?? []).filter((id) => !known.has(id)).map((id) => ({ specId: s.id, requirement: id, code: "MISSING_DESIGN_REFERENCE" })));
|
|
3562
3695
|
}
|
|
3563
3696
|
function parsePreviewFiles(files) {
|
|
3564
3697
|
const specs = [];
|
|
3565
|
-
for (const [path3,
|
|
3698
|
+
for (const [path3, source] of files) {
|
|
3699
|
+
if (documentPathPattern.test(path3) || documentHistoryPattern.test(path3))
|
|
3700
|
+
continue;
|
|
3566
3701
|
if (path3.endsWith("/requirements.md")) {
|
|
3567
|
-
specs.push(parseSpecPreview(path3,
|
|
3702
|
+
specs.push(parseSpecPreview(path3, source, files.get(path3.replace(/requirements\.md$/, "history.jsonl")) ?? "", files.get(path3.replace(/requirements\.md$/, "design.md"))));
|
|
3568
3703
|
} else if (!files.has(path3.replace(/(?:history\.jsonl|design\.md)$/, "requirements.md")))
|
|
3569
3704
|
fail("\uC694\uAD6C\uC0AC\uD56D \uBB38\uC11C \uC5C6\uB294 \uC124\uACC4 \uB610\uB294 \uC774\uC720 \uD30C\uC77C: " + path3);
|
|
3570
3705
|
}
|
|
3571
3706
|
validatePreviewSnapshot(specs);
|
|
3572
3707
|
return specs;
|
|
3573
3708
|
}
|
|
3574
|
-
function parseSpecPreview(path3,
|
|
3709
|
+
function parseSpecPreview(path3, source, history = "", designSource) {
|
|
3575
3710
|
if (!/^\.(?:gitifact|tryce)\/spec\/[^/]+\/requirements\.md$/.test(path3))
|
|
3576
3711
|
fail("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uACBD\uB85C: " + path3);
|
|
3577
|
-
if (
|
|
3712
|
+
if (source.includes("\0") || source.includes("\r") && /\r(?!\n)/.test(source))
|
|
3578
3713
|
fail("\uC798\uBABB\uB41C \uBA85\uC138 \uBB38\uC790: " + path3);
|
|
3579
|
-
const lines = normalized(
|
|
3714
|
+
const lines = normalized(source).split("\n");
|
|
3580
3715
|
const specMatch = new RegExp(`^<!-- ${marker}-spec: (S-${token}) -->$`).exec(lines[0] ?? "");
|
|
3581
3716
|
if (!specMatch)
|
|
3582
3717
|
fail("\uCCAB \uC904\uC5D0 \uC720\uD6A8\uD55C gitifact-spec \uC8FC\uC11D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: " + path3);
|
|
@@ -3651,10 +3786,11 @@ function parseSpecPreview(path3, source2, history = "", designSource) {
|
|
|
3651
3786
|
}
|
|
3652
3787
|
return { id: specMatch[1], path: path3, title, description: normalized(description), requirements, history: parsePreviewHistory(history), ...designSource === void 0 ? {} : { design: parseDesignPreview(designSource, specMatch[1]) } };
|
|
3653
3788
|
}
|
|
3654
|
-
function parsePreviewHistory(
|
|
3789
|
+
function parsePreviewHistory(source, scope = "spec") {
|
|
3655
3790
|
const records = [];
|
|
3656
3791
|
const ids = /* @__PURE__ */ new Set();
|
|
3657
|
-
|
|
3792
|
+
const shapes = scope === "spec" ? ["id,reason,requirements", "designs,id,reason,requirements"] : ["documents,id,reason,requirements"];
|
|
3793
|
+
for (const line of source.replace(/\r\n/g, "\n").split("\n")) {
|
|
3658
3794
|
if (!line.trim())
|
|
3659
3795
|
continue;
|
|
3660
3796
|
let value;
|
|
@@ -3666,10 +3802,10 @@ function parsePreviewHistory(source2) {
|
|
|
3666
3802
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
3667
3803
|
fail("\uC798\uBABB\uB41C \uBCF4\uC870 \uAE30\uB85D\uC785\uB2C8\uB2E4.");
|
|
3668
3804
|
const r = value;
|
|
3669
|
-
if (!
|
|
3805
|
+
if (!shapes.includes(Object.keys(r).sort().join(",")) || typeof r.id !== "string" || !new RegExp(`^H-${token}$`).test(r.id) || ids.has(r.id) || typeof r.reason !== "string" || !r.reason.trim() || !Array.isArray(r.requirements) || !r.requirements.length && !Array.isArray(r.designs) && !Array.isArray(r.documents) || r.documents !== void 0 && (r.requirements.length || !Array.isArray(r.documents) || !r.documents.length || r.documents.some((id) => typeof id !== "string" || !/^[PG]-[a-z2-7]{10}$/.test(id)) || new Set(r.documents).size !== r.documents.length) || r.designs !== void 0 && (!Array.isArray(r.designs) || !r.designs.length || r.designs.some((id) => typeof id !== "string" || !/^S-[a-z2-7]{10}$/.test(id)) || new Set(r.designs).size !== r.designs.length) || r.requirements.some((id) => typeof id !== "string" || !reqId.test(id)) || new Set(r.requirements).size !== r.requirements.length)
|
|
3670
3806
|
fail("\uBCF4\uC870 \uAE30\uB85D\uC758 \uD544\uB4DC\xB7ID\xB7\uB300\uC0C1\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
|
|
3671
3807
|
ids.add(r.id);
|
|
3672
|
-
records.push({ id: r.id, requirements: r.requirements, ...r.designs === void 0 ? {} : { designs: r.designs }, reason: r.reason });
|
|
3808
|
+
records.push({ id: r.id, requirements: r.requirements, ...r.designs === void 0 ? {} : { designs: r.designs }, ...r.documents === void 0 ? {} : { documents: r.documents }, reason: r.reason });
|
|
3673
3809
|
}
|
|
3674
3810
|
return records;
|
|
3675
3811
|
}
|
|
@@ -3743,6 +3879,50 @@ function compareSpecPreviews(before, after) {
|
|
|
3743
3879
|
});
|
|
3744
3880
|
return { specChanges, changes };
|
|
3745
3881
|
}
|
|
3882
|
+
function compareDocumentSets(before, after) {
|
|
3883
|
+
validateDocumentSets(before);
|
|
3884
|
+
validateDocumentSets(after);
|
|
3885
|
+
const index = (sets) => new Map(sets.flatMap((s) => s.documents.map((d) => [d.id, { id: d.id, title: d.title, body: d.body, specId: d.kind, path: d.path }])));
|
|
3886
|
+
const prev = index(before);
|
|
3887
|
+
const next = index(after);
|
|
3888
|
+
const previousHistory = new Map(before.flatMap((s) => s.history.map((h) => [h.id, h])));
|
|
3889
|
+
const reasons = after.flatMap((s) => s.history).filter((h) => {
|
|
3890
|
+
const old = previousHistory.get(h.id);
|
|
3891
|
+
if (old && JSON.stringify(old) !== JSON.stringify(h))
|
|
3892
|
+
fail("\uAE30\uC874 \uBCF4\uC870 \uAE30\uB85D\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + h.id);
|
|
3893
|
+
return !old;
|
|
3894
|
+
});
|
|
3895
|
+
const changes = [.../* @__PURE__ */ new Set([...prev.keys(), ...next.keys()])].sort().flatMap((id) => {
|
|
3896
|
+
const from = prev.get(id) ?? null;
|
|
3897
|
+
const to = next.get(id) ?? null;
|
|
3898
|
+
const types = [];
|
|
3899
|
+
if (!from)
|
|
3900
|
+
types.push("created");
|
|
3901
|
+
else if (!to)
|
|
3902
|
+
types.push("deleted");
|
|
3903
|
+
else {
|
|
3904
|
+
if (from.path !== to.path)
|
|
3905
|
+
types.push("moved");
|
|
3906
|
+
if (from.title !== to.title || from.body !== to.body)
|
|
3907
|
+
types.push("modified");
|
|
3908
|
+
}
|
|
3909
|
+
const kind = (to ?? from).specId;
|
|
3910
|
+
return types.length ? [{ id, types, before: from, after: to, kind, reasons: reasons.filter((h) => (h.documents ?? []).includes(id)) }] : [];
|
|
3911
|
+
});
|
|
3912
|
+
const changed = new Set(changes.map((c) => c.id));
|
|
3913
|
+
for (const h of reasons)
|
|
3914
|
+
if ((h.documents ?? []).some((id) => !changed.has(id)))
|
|
3915
|
+
fail("\uC0C8 \uBCF4\uC870 \uAE30\uB85D\uC774 \uC774\uBC88 \uBB38\uC11C \uBCC0\uACBD\uACFC \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + h.id);
|
|
3916
|
+
return changes;
|
|
3917
|
+
}
|
|
3918
|
+
function comparePreviewBundles(before, after) {
|
|
3919
|
+
const a = asBundle(before);
|
|
3920
|
+
const b = asBundle(after);
|
|
3921
|
+
validateBundle(a);
|
|
3922
|
+
validateBundle(b);
|
|
3923
|
+
const specs = compareSpecPreviews(a.specs, b.specs);
|
|
3924
|
+
return { specChanges: specs.specChanges, changes: [...specs.changes, ...compareDocumentSets(a.documents, b.documents)] };
|
|
3925
|
+
}
|
|
3746
3926
|
|
|
3747
3927
|
// ../../packages/core/dist/use-cases/edit-spec-preview.js
|
|
3748
3928
|
var fail2 = (message) => {
|
|
@@ -3769,9 +3949,11 @@ ${r.body}
|
|
|
3769
3949
|
function editSpecPreview(original, input2, generate) {
|
|
3770
3950
|
if (!Array.isArray(input2) || !input2.length || input2.length > 100)
|
|
3771
3951
|
fail2("operations\uB294 1~100\uAC1C\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
|
|
3772
|
-
const
|
|
3773
|
-
|
|
3774
|
-
const
|
|
3952
|
+
const source = asBundle(original);
|
|
3953
|
+
const specs = source.specs.map((s) => ({ ...s, requirements: s.requirements.map((r) => ({ ...r })), history: s.history.map((h) => ({ ...h, requirements: [...h.requirements] })) }));
|
|
3954
|
+
const documents = source.documents.map((set2) => ({ ...set2, documents: set2.documents.map((d) => ({ ...d })), history: set2.history.map((h) => ({ ...h })) }));
|
|
3955
|
+
validateBundle({ specs, documents });
|
|
3956
|
+
const used = /* @__PURE__ */ new Set([...specs.flatMap((s) => [s.id, ...s.requirements.map((r) => r.id)]), ...documents.flatMap((d) => d.documents.map((x) => x.id))]);
|
|
3775
3957
|
const allocate = (prefix) => {
|
|
3776
3958
|
for (let attempt = 0; attempt < 100; attempt++) {
|
|
3777
3959
|
const id = generate(prefix);
|
|
@@ -3796,7 +3978,13 @@ function editSpecPreview(original, input2, generate) {
|
|
|
3796
3978
|
move: ["type", "id", "feature"],
|
|
3797
3979
|
"rename-spec": ["type", "id", "title"],
|
|
3798
3980
|
"set-design": ["type", "feature", "title", "body"],
|
|
3799
|
-
"delete-design": ["type", "feature"]
|
|
3981
|
+
"delete-design": ["type", "feature"],
|
|
3982
|
+
"create-doc": ["type", "path", "title", "body"],
|
|
3983
|
+
"update-doc": ["type", "id", "title", "body"],
|
|
3984
|
+
"move-doc": ["type", "id", "path"],
|
|
3985
|
+
"delete-doc": ["type", "id"],
|
|
3986
|
+
"set-product": ["type", "title", "body"],
|
|
3987
|
+
"delete-product": ["type"]
|
|
3800
3988
|
};
|
|
3801
3989
|
const type = String(op.type);
|
|
3802
3990
|
const fields2 = schemas[type];
|
|
@@ -3812,10 +4000,63 @@ function editSpecPreview(original, input2, generate) {
|
|
|
3812
4000
|
fail2("\uC798\uBABB\uB41C \uD3B8\uC9D1 \uBB38\uC790: " + key);
|
|
3813
4001
|
return value;
|
|
3814
4002
|
};
|
|
3815
|
-
const
|
|
4003
|
+
const target = () => {
|
|
3816
4004
|
const path3 = previewPath(str("feature"));
|
|
3817
4005
|
return specs.find((s) => s.path === path3) ?? fail2("\uB300\uC0C1 \uBA85\uC138\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: " + path3);
|
|
3818
4006
|
};
|
|
4007
|
+
if (type === "set-product" || type === "delete-product") {
|
|
4008
|
+
const set2 = documents.find((s) => s.kind === "product");
|
|
4009
|
+
const existing = set2.documents[0];
|
|
4010
|
+
if (type === "delete-product") {
|
|
4011
|
+
if (!existing)
|
|
4012
|
+
fail2("\uC0AD\uC81C\uD560 \uC81C\uD488 \uBB38\uC11C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
4013
|
+
set2.documents = [];
|
|
4014
|
+
results.push({ type, id: existing.id });
|
|
4015
|
+
} else {
|
|
4016
|
+
const doc = { id: existing?.id ?? allocate("P"), kind: "product", path: PRODUCT_PATH, title: str("title"), body: str("body") };
|
|
4017
|
+
set2.documents = [doc];
|
|
4018
|
+
results.push({ type, id: doc.id });
|
|
4019
|
+
}
|
|
4020
|
+
continue;
|
|
4021
|
+
}
|
|
4022
|
+
if (type.endsWith("-doc")) {
|
|
4023
|
+
const all = () => documents.filter((set2) => set2.kind === "guide").flatMap((set2) => set2.documents);
|
|
4024
|
+
const documentPath = (kind, self) => {
|
|
4025
|
+
const relative = str("path");
|
|
4026
|
+
validateDocumentRelativePath(relative);
|
|
4027
|
+
const path3 = `${DOCUMENT_DIRS[kind]}/${relative}`;
|
|
4028
|
+
if (self && self.path === path3)
|
|
4029
|
+
fail2("\uC774\uBBF8 \uAC19\uC740 \uACBD\uB85C\uC785\uB2C8\uB2E4.");
|
|
4030
|
+
if (all().some((d) => d !== self && d.path.toLowerCase() === path3.toLowerCase()))
|
|
4031
|
+
fail2("\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uBB38\uC11C \uACBD\uB85C\uC785\uB2C8\uB2E4: " + path3);
|
|
4032
|
+
return path3;
|
|
4033
|
+
};
|
|
4034
|
+
const find = () => {
|
|
4035
|
+
const id = str("id");
|
|
4036
|
+
return all().find((d) => d.id === id) ?? fail2("\uC9C0\uCE68 \uBB38\uC11C ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: " + id);
|
|
4037
|
+
};
|
|
4038
|
+
if (type === "create-doc") {
|
|
4039
|
+
const kind = "guide";
|
|
4040
|
+
const doc = { id: allocate("G"), kind, path: documentPath(kind), title: str("title"), body: str("body") };
|
|
4041
|
+
documents.find((s) => s.kind === kind).documents.push(doc);
|
|
4042
|
+
results.push({ type, id: doc.id });
|
|
4043
|
+
} else if (type === "update-doc") {
|
|
4044
|
+
const doc = find();
|
|
4045
|
+
doc.title = str("title");
|
|
4046
|
+
doc.body = str("body");
|
|
4047
|
+
results.push({ type, id: doc.id });
|
|
4048
|
+
} else if (type === "move-doc") {
|
|
4049
|
+
const doc = find();
|
|
4050
|
+
doc.path = documentPath(doc.kind, doc);
|
|
4051
|
+
results.push({ type, id: doc.id });
|
|
4052
|
+
} else {
|
|
4053
|
+
const doc = find();
|
|
4054
|
+
const set2 = documents.find((s) => s.kind === doc.kind);
|
|
4055
|
+
set2.documents = set2.documents.filter((d) => d.id !== doc.id);
|
|
4056
|
+
results.push({ type, id: doc.id });
|
|
4057
|
+
}
|
|
4058
|
+
continue;
|
|
4059
|
+
}
|
|
3819
4060
|
if (type === "create") {
|
|
3820
4061
|
const path3 = previewPath(str("feature"));
|
|
3821
4062
|
if (specs.some((s) => s.path.toLowerCase() === path3.toLowerCase()))
|
|
@@ -3824,12 +4065,12 @@ function editSpecPreview(original, input2, generate) {
|
|
|
3824
4065
|
specs.push(spec2);
|
|
3825
4066
|
results.push({ type, id: spec2.id });
|
|
3826
4067
|
} else if (type === "add") {
|
|
3827
|
-
const spec2 =
|
|
4068
|
+
const spec2 = target();
|
|
3828
4069
|
const req = { id: allocate("R"), title: str("title"), body: str("body") };
|
|
3829
4070
|
spec2.requirements.push(req);
|
|
3830
4071
|
results.push({ type, id: req.id });
|
|
3831
4072
|
} else if (type === "set-design" || type === "delete-design") {
|
|
3832
|
-
const spec2 =
|
|
4073
|
+
const spec2 = target();
|
|
3833
4074
|
if (type === "delete-design") {
|
|
3834
4075
|
if (!spec2.design)
|
|
3835
4076
|
fail2("\uC0AD\uC81C\uD560 \uC124\uACC4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
@@ -3846,7 +4087,7 @@ function editSpecPreview(original, input2, generate) {
|
|
|
3846
4087
|
const source2 = specs.find((s) => s.requirements.some((r) => r.id === id)) ?? fail2("\uC694\uAD6C\uC0AC\uD56D ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
3847
4088
|
const req = source2.requirements.find((r) => r.id === id);
|
|
3848
4089
|
if (type === "move") {
|
|
3849
|
-
const destination =
|
|
4090
|
+
const destination = target();
|
|
3850
4091
|
if (source2 === destination)
|
|
3851
4092
|
fail2("\uC774\uBBF8 \uAC19\uC740 \uBA85\uC138\uC5D0 \uC18D\uD569\uB2C8\uB2E4.");
|
|
3852
4093
|
source2.requirements = source2.requirements.filter((r) => r.id !== id);
|
|
@@ -3863,8 +4104,14 @@ function editSpecPreview(original, input2, generate) {
|
|
|
3863
4104
|
if (JSON.stringify({ ...parsed, history: spec2.history }) !== JSON.stringify(spec2))
|
|
3864
4105
|
fail2("\uBCF8\uBB38\uC774 \uBA85\uC138 \uAD6C\uC870\uB97C \uBCC0\uACBD\uD569\uB2C8\uB2E4.");
|
|
3865
4106
|
}
|
|
3866
|
-
|
|
3867
|
-
|
|
4107
|
+
for (const set2 of documents) {
|
|
4108
|
+
set2.documents.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
4109
|
+
for (const doc of set2.documents)
|
|
4110
|
+
if (JSON.stringify(parseDocument(doc.path, renderDocument(doc))) !== JSON.stringify(doc))
|
|
4111
|
+
fail2("\uBCF8\uBB38\uC774 \uBB38\uC11C \uAD6C\uC870\uB97C \uBCC0\uACBD\uD569\uB2C8\uB2E4: " + doc.path);
|
|
4112
|
+
}
|
|
4113
|
+
validateBundle({ specs, documents });
|
|
4114
|
+
return { specs, documents, results };
|
|
3868
4115
|
}
|
|
3869
4116
|
|
|
3870
4117
|
// ../../packages/core/dist/use-cases/prepare-spec-preview.js
|
|
@@ -3873,27 +4120,50 @@ var fail3 = (message) => {
|
|
|
3873
4120
|
};
|
|
3874
4121
|
var equal = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
3875
4122
|
var historyPath = (s) => s.path.replace(/requirements\.md$/, "history.jsonl");
|
|
3876
|
-
function
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
4123
|
+
function pendingPreviewReasons(before, current) {
|
|
4124
|
+
const a = asBundle(before);
|
|
4125
|
+
const b = asBundle(current);
|
|
4126
|
+
return [
|
|
4127
|
+
...b.specs.flatMap((s) => s.history.slice(a.specs.find((p) => p.id === s.id)?.history.length ?? 0).map((h) => ({ specId: s.id, path: historyPath(s), ...h }))),
|
|
4128
|
+
...b.documents.flatMap((d) => d.history.slice(a.documents.find((p) => p.kind === d.kind)?.history.length ?? 0).map((h) => ({ kind: d.kind, path: documentHistoryPath(d.kind), ...h })))
|
|
4129
|
+
];
|
|
4130
|
+
}
|
|
4131
|
+
function finalSpecPreviewChanges(beforeValue, currentValue) {
|
|
4132
|
+
const before = asBundle(beforeValue);
|
|
4133
|
+
const current = asBundle(currentValue);
|
|
4134
|
+
validateBundle(before);
|
|
4135
|
+
validateBundle(current);
|
|
4136
|
+
for (const previous of before.specs) {
|
|
4137
|
+
const next = current.specs.find((s) => s.id === previous.id);
|
|
3881
4138
|
if (previous.history.length && !next)
|
|
3882
4139
|
fail3("\uAE30\uC874 \uC774\uC720\uB97C \uBCF4\uC874\uD560 \uBE48 \uBA85\uC138\uB97C \uB0A8\uACA8\uC8FC\uC138\uC694: " + previous.id);
|
|
3883
4140
|
if (next && !equal(next.history.slice(0, previous.history.length), previous.history))
|
|
3884
4141
|
fail3("\uCEE4\uBC0B\uB41C \uC774\uC720\uC758 \uC218\uC815\xB7\uC0AD\uC81C\xB7\uC7AC\uBC30\uCE58\uB294 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + previous.id);
|
|
3885
4142
|
}
|
|
3886
|
-
|
|
3887
|
-
|
|
4143
|
+
for (const previous of before.documents) {
|
|
4144
|
+
const next = current.documents.find((s) => s.kind === previous.kind);
|
|
4145
|
+
if (!equal(next.history.slice(0, previous.history.length), previous.history))
|
|
4146
|
+
fail3("\uCEE4\uBC0B\uB41C \uBB38\uC11C \uC774\uC720\uC758 \uC218\uC815\xB7\uC0AD\uC81C\xB7\uC7AC\uBC30\uCE58\uB294 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + previous.kind);
|
|
4147
|
+
}
|
|
4148
|
+
const clean = {
|
|
4149
|
+
specs: current.specs.map((s) => ({ ...s, history: before.specs.find((p) => p.id === s.id)?.history ?? [] })),
|
|
4150
|
+
documents: current.documents.map((d) => ({ ...d, history: before.documents.find((p) => p.kind === d.kind)?.history ?? [] }))
|
|
4151
|
+
};
|
|
4152
|
+
return comparePreviewBundles(before, clean);
|
|
3888
4153
|
}
|
|
3889
|
-
function prepareSpecPreview(
|
|
3890
|
-
const
|
|
4154
|
+
function prepareSpecPreview(beforeValue, currentValue, baseFiles, currentFiles, input2, generate) {
|
|
4155
|
+
const beforeBundle = asBundle(beforeValue);
|
|
4156
|
+
const currentBundle = asBundle(currentValue);
|
|
4157
|
+
const before = beforeBundle.specs;
|
|
4158
|
+
const current = currentBundle.specs;
|
|
4159
|
+
const delta = finalSpecPreviewChanges(beforeBundle, currentBundle);
|
|
3891
4160
|
if (!Array.isArray(input2) || input2.length > 100)
|
|
3892
4161
|
fail3("reasons\uB294 \uCD5C\uB300 100\uAC1C\uC758 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
|
|
3893
4162
|
const writes = /* @__PURE__ */ new Map();
|
|
3894
4163
|
const pending = /* @__PURE__ */ new Map();
|
|
3895
4164
|
const covered = /* @__PURE__ */ new Set();
|
|
3896
|
-
const used = new Set([...before, ...current
|
|
4165
|
+
const used = new Set([...before.flatMap((s) => s.history), ...current.flatMap((s) => s.history), ...beforeBundle.documents.flatMap((d) => d.history), ...currentBundle.documents.flatMap((d) => d.history)].map((h) => h.id));
|
|
4166
|
+
const documentPending = /* @__PURE__ */ new Map();
|
|
3897
4167
|
const allocate = () => {
|
|
3898
4168
|
for (let attempt = 0; attempt < 100; attempt++) {
|
|
3899
4169
|
const id = generate();
|
|
@@ -3910,10 +4180,32 @@ function prepareSpecPreview(before, current, baseFiles, currentFiles, input2, ge
|
|
|
3910
4180
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
3911
4181
|
fail3("\uC798\uBABB\uB41C \uC774\uC720 \uC785\uB825\uC785\uB2C8\uB2E4.");
|
|
3912
4182
|
const raw = value;
|
|
3913
|
-
|
|
4183
|
+
const shape = Object.keys(raw).sort().join(",");
|
|
4184
|
+
if (!["reason,requirements", "designs,reason,requirements", "documents,reason,requirements"].includes(shape) || typeof raw.reason !== "string" || !raw.reason.trim() || raw.reason.includes("\0") || raw.reason.length > 16e3 || !Array.isArray(raw.requirements) || raw.designs !== void 0 && !Array.isArray(raw.designs) || raw.documents !== void 0 && !Array.isArray(raw.documents) || !(raw.requirements.length || raw.designs?.length || raw.documents?.length))
|
|
3914
4185
|
fail3("\uC774\uC720\uC640 \uB300\uC0C1 \uC694\uAD6C\uC0AC\uD56D\uC744 \uD655\uC778\uD558\uC138\uC694.");
|
|
3915
4186
|
const reason = raw.reason.trim();
|
|
3916
4187
|
const groups = /* @__PURE__ */ new Map();
|
|
4188
|
+
if (raw.documents !== void 0) {
|
|
4189
|
+
if (raw.requirements.length)
|
|
4190
|
+
fail3("\uBB38\uC11C \uC774\uC720\uC5D0\uB294 \uC694\uAD6C\uC0AC\uD56D\uC744 \uD568\uAED8 \uC9C0\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
4191
|
+
const ids = raw.documents;
|
|
4192
|
+
let kind;
|
|
4193
|
+
for (const value2 of ids) {
|
|
4194
|
+
if (typeof value2 !== "string" || !/^[PG]-[a-z2-7]{10}$/.test(value2) || covered.has(value2))
|
|
4195
|
+
return fail3("\uBB38\uC11C \uC774\uC720 \uB300\uC0C1\uC774 \uC798\uBABB\uB410\uAC70\uB098 \uC911\uBCF5\uB429\uB2C8\uB2E4.");
|
|
4196
|
+
const change2 = delta.changes.find((c) => c.id === value2) ?? fail3("\uCD5C\uC885 \uBCC0\uACBD\uC774 \uC5C6\uB294 \uBB38\uC11C\uC5D0 \uC774\uC720\uB97C \uBD99\uC77C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: " + value2);
|
|
4197
|
+
if (kind && change2.kind !== kind)
|
|
4198
|
+
fail3("\uD55C \uC774\uC720\uB294 \uD55C \uC885\uB958\uC758 \uBB38\uC11C\uB9CC \uB300\uC0C1\uC73C\uB85C \uD569\uB2C8\uB2E4.");
|
|
4199
|
+
kind = change2.kind;
|
|
4200
|
+
covered.add(value2);
|
|
4201
|
+
}
|
|
4202
|
+
const documents = [...ids].sort();
|
|
4203
|
+
const set2 = currentBundle.documents.find((d) => d.kind === kind);
|
|
4204
|
+
const oldCount = beforeBundle.documents.find((d) => d.kind === kind)?.history.length ?? 0;
|
|
4205
|
+
const reusable = set2.history.slice(oldCount).find((h) => h.reason === reason && equal([...h.documents ?? []].sort(), documents));
|
|
4206
|
+
documentPending.set(kind, [...documentPending.get(kind) ?? [], { id: reusable?.id ?? allocate(), requirements: [], documents, reason }]);
|
|
4207
|
+
continue;
|
|
4208
|
+
}
|
|
3917
4209
|
for (const value2 of [...raw.requirements, ...raw.designs ?? []]) {
|
|
3918
4210
|
if (typeof value2 !== "string")
|
|
3919
4211
|
fail3("\uC798\uBABB\uB41C \uC774\uC720 \uB300\uC0C1\uC785\uB2C8\uB2E4.");
|
|
@@ -3951,11 +4243,22 @@ function prepareSpecPreview(before, current, baseFiles, currentFiles, input2, ge
|
|
|
3951
4243
|
if ((currentFiles.get(path3) ?? null) !== next)
|
|
3952
4244
|
writes.set(path3, next);
|
|
3953
4245
|
}
|
|
4246
|
+
for (const set2 of currentBundle.documents) {
|
|
4247
|
+
const path3 = documentHistoryPath(set2.kind);
|
|
4248
|
+
const base = baseFiles.get(path3);
|
|
4249
|
+
const records = (documentPending.get(set2.kind) ?? []).sort((a, b) => a.documents[0] < b.documents[0] ? -1 : 1);
|
|
4250
|
+
let text2 = base ?? "";
|
|
4251
|
+
if (records.length)
|
|
4252
|
+
text2 += (text2 && !text2.endsWith("\n") ? "\n" : "") + records.map((h) => JSON.stringify(h) + "\n").join("");
|
|
4253
|
+
const next = base !== void 0 || records.length ? text2 : null;
|
|
4254
|
+
if ((currentFiles.get(path3) ?? null) !== next)
|
|
4255
|
+
writes.set(path3, next);
|
|
4256
|
+
}
|
|
3954
4257
|
return {
|
|
3955
4258
|
writes,
|
|
3956
4259
|
changes: delta.changes,
|
|
3957
4260
|
specChanges: delta.specChanges,
|
|
3958
|
-
reasons: [...pending].flatMap(([specId, records]) => records.map((record3) => ({ specId, ...record3 }))),
|
|
4261
|
+
reasons: [...[...pending].flatMap(([specId, records]) => records.map((record3) => ({ specId, ...record3 }))), ...[...documentPending].flatMap(([kind, records]) => records.map((record3) => ({ kind, ...record3 })))],
|
|
3959
4262
|
withoutReason: delta.changes.filter((c) => !covered.has(c.id)).map((c) => c.id)
|
|
3960
4263
|
};
|
|
3961
4264
|
}
|
|
@@ -4908,10 +5211,10 @@ function cached(getter) {
|
|
|
4908
5211
|
function nullish(input2) {
|
|
4909
5212
|
return input2 === null || input2 === void 0;
|
|
4910
5213
|
}
|
|
4911
|
-
function cleanRegex(
|
|
4912
|
-
const start =
|
|
4913
|
-
const end =
|
|
4914
|
-
return
|
|
5214
|
+
function cleanRegex(source) {
|
|
5215
|
+
const start = source.startsWith("^") ? 1 : 0;
|
|
5216
|
+
const end = source.endsWith("$") ? source.length - 1 : source.length;
|
|
5217
|
+
return source.slice(start, end);
|
|
4915
5218
|
}
|
|
4916
5219
|
function floatSafeRemainder(val, step) {
|
|
4917
5220
|
const ratio = val / step;
|
|
@@ -4947,8 +5250,8 @@ function defineLazy(object4, key, getter) {
|
|
|
4947
5250
|
function objectClone(obj) {
|
|
4948
5251
|
return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
|
|
4949
5252
|
}
|
|
4950
|
-
function assignProp(
|
|
4951
|
-
Object.defineProperty(
|
|
5253
|
+
function assignProp(target, prop, value) {
|
|
5254
|
+
Object.defineProperty(target, prop, {
|
|
4952
5255
|
value,
|
|
4953
5256
|
writable: true,
|
|
4954
5257
|
enumerable: true,
|
|
@@ -4962,8 +5265,8 @@ function rawShape(def) {
|
|
|
4962
5265
|
function sourceShape(schema) {
|
|
4963
5266
|
return rawShape(schema._zod.def) ?? schema._zod.def.shape;
|
|
4964
5267
|
}
|
|
4965
|
-
function deferProp(
|
|
4966
|
-
Object.defineProperty(
|
|
5268
|
+
function deferProp(target, key, getter) {
|
|
5269
|
+
Object.defineProperty(target, key, {
|
|
4967
5270
|
get() {
|
|
4968
5271
|
const value = getter();
|
|
4969
5272
|
assignProp(this, key, value);
|
|
@@ -4973,36 +5276,36 @@ function deferProp(target2, key, getter) {
|
|
|
4973
5276
|
configurable: true
|
|
4974
5277
|
});
|
|
4975
5278
|
}
|
|
4976
|
-
function putProp(
|
|
4977
|
-
if (key in
|
|
4978
|
-
assignProp(
|
|
5279
|
+
function putProp(target, key, value) {
|
|
5280
|
+
if (key in target)
|
|
5281
|
+
assignProp(target, key, value);
|
|
4979
5282
|
else
|
|
4980
|
-
|
|
5283
|
+
target[key] = value;
|
|
4981
5284
|
}
|
|
4982
|
-
function mirrorShape(
|
|
4983
|
-
const raw = sourceShape(
|
|
5285
|
+
function mirrorShape(target, source, keys2, wrap) {
|
|
5286
|
+
const raw = sourceShape(source);
|
|
4984
5287
|
for (const key of keys2) {
|
|
4985
5288
|
const desc = Object.getOwnPropertyDescriptor(raw, key);
|
|
4986
5289
|
if (!desc.enumerable)
|
|
4987
5290
|
continue;
|
|
4988
5291
|
if (desc.get) {
|
|
4989
|
-
deferProp(
|
|
4990
|
-
const value =
|
|
5292
|
+
deferProp(target, key, () => {
|
|
5293
|
+
const value = source._zod.def.shape[key];
|
|
4991
5294
|
return wrap ? wrap(value, key) : value;
|
|
4992
5295
|
});
|
|
4993
5296
|
} else
|
|
4994
|
-
putProp(
|
|
5297
|
+
putProp(target, key, wrap ? wrap(desc.value, key) : desc.value);
|
|
4995
5298
|
}
|
|
4996
5299
|
}
|
|
4997
|
-
function mirrorProps(
|
|
4998
|
-
for (const key of Reflect.ownKeys(
|
|
4999
|
-
const desc = Object.getOwnPropertyDescriptor(
|
|
5300
|
+
function mirrorProps(target, source) {
|
|
5301
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
5302
|
+
const desc = Object.getOwnPropertyDescriptor(source, key);
|
|
5000
5303
|
if (!desc.enumerable)
|
|
5001
5304
|
continue;
|
|
5002
5305
|
if (desc.get)
|
|
5003
|
-
deferProp(
|
|
5306
|
+
deferProp(target, key, () => source[key]);
|
|
5004
5307
|
else
|
|
5005
|
-
putProp(
|
|
5308
|
+
putProp(target, key, desc.value);
|
|
5006
5309
|
}
|
|
5007
5310
|
}
|
|
5008
5311
|
function mergeDefs(...defs) {
|
|
@@ -5181,35 +5484,35 @@ function normalizeParams(_params) {
|
|
|
5181
5484
|
return params;
|
|
5182
5485
|
}
|
|
5183
5486
|
function createTransparentProxy(getter) {
|
|
5184
|
-
let
|
|
5487
|
+
let target;
|
|
5185
5488
|
return new Proxy({}, {
|
|
5186
5489
|
get(_, prop, receiver) {
|
|
5187
|
-
|
|
5188
|
-
return Reflect.get(
|
|
5490
|
+
target ?? (target = getter());
|
|
5491
|
+
return Reflect.get(target, prop, receiver);
|
|
5189
5492
|
},
|
|
5190
5493
|
set(_, prop, value, receiver) {
|
|
5191
|
-
|
|
5192
|
-
return Reflect.set(
|
|
5494
|
+
target ?? (target = getter());
|
|
5495
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5193
5496
|
},
|
|
5194
5497
|
has(_, prop) {
|
|
5195
|
-
|
|
5196
|
-
return Reflect.has(
|
|
5498
|
+
target ?? (target = getter());
|
|
5499
|
+
return Reflect.has(target, prop);
|
|
5197
5500
|
},
|
|
5198
5501
|
deleteProperty(_, prop) {
|
|
5199
|
-
|
|
5200
|
-
return Reflect.deleteProperty(
|
|
5502
|
+
target ?? (target = getter());
|
|
5503
|
+
return Reflect.deleteProperty(target, prop);
|
|
5201
5504
|
},
|
|
5202
5505
|
ownKeys(_) {
|
|
5203
|
-
|
|
5204
|
-
return Reflect.ownKeys(
|
|
5506
|
+
target ?? (target = getter());
|
|
5507
|
+
return Reflect.ownKeys(target);
|
|
5205
5508
|
},
|
|
5206
5509
|
getOwnPropertyDescriptor(_, prop) {
|
|
5207
|
-
|
|
5208
|
-
return Reflect.getOwnPropertyDescriptor(
|
|
5510
|
+
target ?? (target = getter());
|
|
5511
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
5209
5512
|
},
|
|
5210
5513
|
defineProperty(_, prop, descriptor) {
|
|
5211
|
-
|
|
5212
|
-
return Reflect.defineProperty(
|
|
5514
|
+
target ?? (target = getter());
|
|
5515
|
+
return Reflect.defineProperty(target, prop, descriptor);
|
|
5213
5516
|
}
|
|
5214
5517
|
});
|
|
5215
5518
|
}
|
|
@@ -5680,10 +5983,10 @@ function $constructor(name, initializer3, proto, params) {
|
|
|
5680
5983
|
let up = own2;
|
|
5681
5984
|
while (up && up !== ctorProto)
|
|
5682
5985
|
up = Object.getPrototypeOf(up);
|
|
5683
|
-
const
|
|
5684
|
-
if (!initialized.has(
|
|
5685
|
-
initialized.add(
|
|
5686
|
-
members(
|
|
5986
|
+
const target = up ?? own2;
|
|
5987
|
+
if (!initialized.has(target)) {
|
|
5988
|
+
initialized.add(target);
|
|
5989
|
+
members(target, protoMembers);
|
|
5687
5990
|
}
|
|
5688
5991
|
}
|
|
5689
5992
|
const proto2 = _.prototype;
|
|
@@ -6213,8 +6516,8 @@ var creditCard = /^\d(?:[ -]?\d){11,18}$/;
|
|
|
6213
6516
|
var currencyCode = /^(?:AED|AFN|ALL|AMD|AOA|ARS|AUD|AWG|AZN|BAM|BBD|BDT|BHD|BIF|BMD|BND|BOB|BOV|BRL|BSD|BTN|BWP|BYN|BZD|CAD|CDF|CHE|CHF|CHW|CLF|CLP|CNY|COP|COU|CRC|CUP|CVE|CZK|DJF|DKK|DOP|DZD|EGP|ERN|ETB|EUR|FJD|FKP|GBP|GEL|GHS|GIP|GMD|GNF|GTQ|GYD|HKD|HNL|HTG|HUF|IDR|ILS|INR|IQD|IRR|ISK|JMD|JOD|JPY|KES|KGS|KHR|KMF|KPW|KRW|KWD|KYD|KZT|LAK|LBP|LKR|LRD|LSL|LYD|MAD|MDL|MGA|MKD|MMK|MNT|MOP|MRU|MUR|MVR|MWK|MXN|MXV|MYR|MZN|NAD|NGN|NIO|NOK|NPR|NZD|OMR|PAB|PEN|PGK|PHP|PKR|PLN|PYG|QAR|RON|RSD|RUB|RWF|SAR|SBD|SCR|SDG|SEK|SGD|SHP|SLE|SOS|SRD|SSP|STN|SVC|SYP|SZL|THB|TJS|TMT|TND|TOP|TRY|TTD|TWD|TZS|UAH|UGX|USD|USN|UYI|UYU|UYW|UZS|VED|VES|VND|VUV|WST|XAD|XAF|XAG|XAU|XBA|XBB|XBC|XBD|XCD|XCG|XDR|XOF|XPD|XPF|XPT|XSU|XTS|XUA|XXX|YER|ZAR|ZMW|ZWG)$/;
|
|
6214
6517
|
var iban = /^[A-Z]{2}(?!00|01|99)\d{2}[A-Z0-9]{11,30}$/;
|
|
6215
6518
|
var dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
|
|
6216
|
-
function anchor(
|
|
6217
|
-
return new RegExp(`^${
|
|
6519
|
+
function anchor(source) {
|
|
6520
|
+
return new RegExp(`^${source}$`);
|
|
6218
6521
|
}
|
|
6219
6522
|
var date = /* @__PURE__ */ anchor(dateSource);
|
|
6220
6523
|
function timeSource(args) {
|
|
@@ -9037,11 +9340,11 @@ var $ZodTemplateLiteral = /* @__PURE__ */ $constructor("$ZodTemplateLiteral", (i
|
|
|
9037
9340
|
const regexParts = [];
|
|
9038
9341
|
for (const part of def.parts) {
|
|
9039
9342
|
if (typeof part === "object" && part !== null) {
|
|
9040
|
-
const
|
|
9041
|
-
if (!
|
|
9343
|
+
const source = partPattern(part);
|
|
9344
|
+
if (!source) {
|
|
9042
9345
|
throw new Error(`Invalid template literal part, no pattern found: ${[...part._zod.traits].shift()}`);
|
|
9043
9346
|
}
|
|
9044
|
-
regexParts.push(cleanRegex(
|
|
9347
|
+
regexParts.push(cleanRegex(source));
|
|
9045
9348
|
} else if (part === null || primitiveTypes.has(typeof part)) {
|
|
9046
9349
|
regexParts.push(escapeRegex(`${part}`));
|
|
9047
9350
|
} else {
|
|
@@ -17167,9 +17470,9 @@ function withParser(schema, parser) {
|
|
|
17167
17470
|
installCompiledUserMethods(clone2, schema, parser);
|
|
17168
17471
|
return clone2;
|
|
17169
17472
|
}
|
|
17170
|
-
function installCompiledUserMethods(
|
|
17171
|
-
const targetAny =
|
|
17172
|
-
const sourceAny =
|
|
17473
|
+
function installCompiledUserMethods(target, source, parser) {
|
|
17474
|
+
const targetAny = target;
|
|
17475
|
+
const sourceAny = source;
|
|
17173
17476
|
if (typeof sourceAny.safeParse === "function") {
|
|
17174
17477
|
const originalSafeParse = sourceAny.safeParse;
|
|
17175
17478
|
targetAny.safeParse = (data, params) => {
|
|
@@ -19763,26 +20066,26 @@ function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
|
|
|
19763
20066
|
}
|
|
19764
20067
|
|
|
19765
20068
|
// ../../node_modules/.pnpm/zod@4.6.4/node_modules/zod/v4/core/to-json-schema.js
|
|
19766
|
-
function assignProps(
|
|
19767
|
-
for (const
|
|
19768
|
-
for (const key of Reflect.ownKeys(
|
|
19769
|
-
if (Object.prototype.propertyIsEnumerable.call(
|
|
19770
|
-
assignProp(
|
|
20069
|
+
function assignProps(target, ...sources) {
|
|
20070
|
+
for (const source of sources) {
|
|
20071
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
20072
|
+
if (Object.prototype.propertyIsEnumerable.call(source, key)) {
|
|
20073
|
+
assignProp(target, key, source[key]);
|
|
19771
20074
|
}
|
|
19772
20075
|
}
|
|
19773
20076
|
}
|
|
19774
|
-
return
|
|
20077
|
+
return target;
|
|
19775
20078
|
}
|
|
19776
20079
|
function initializeContext(params) {
|
|
19777
|
-
let
|
|
19778
|
-
if (
|
|
19779
|
-
|
|
19780
|
-
if (
|
|
19781
|
-
|
|
20080
|
+
let target = params?.target ?? "draft-2020-12";
|
|
20081
|
+
if (target === "draft-4")
|
|
20082
|
+
target = "draft-04";
|
|
20083
|
+
if (target === "draft-7")
|
|
20084
|
+
target = "draft-07";
|
|
19782
20085
|
return {
|
|
19783
20086
|
processors: params.processors ?? {},
|
|
19784
20087
|
metadataRegistry: params?.metadata ?? globalRegistry,
|
|
19785
|
-
target
|
|
20088
|
+
target,
|
|
19786
20089
|
unrepresentable: params?.unrepresentable ?? "throw",
|
|
19787
20090
|
override: params?.override ?? (() => {
|
|
19788
20091
|
}),
|
|
@@ -20285,8 +20588,8 @@ var createToJSONSchemaMethod = (schema, processors = {}) => (params) => {
|
|
|
20285
20588
|
return finalize(ctx, schema);
|
|
20286
20589
|
};
|
|
20287
20590
|
var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => {
|
|
20288
|
-
const { libraryOptions, target
|
|
20289
|
-
const ctx = initializeContext({ ...libraryOptions ?? {}, target
|
|
20591
|
+
const { libraryOptions, target } = params ?? {};
|
|
20592
|
+
const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors });
|
|
20290
20593
|
processSchema(schema, ctx);
|
|
20291
20594
|
extractDefs(ctx, schema);
|
|
20292
20595
|
return finalize(ctx, schema);
|
|
@@ -21480,8 +21783,8 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
21480
21783
|
catch(params) {
|
|
21481
21784
|
return _catch2(this, params);
|
|
21482
21785
|
},
|
|
21483
|
-
pipe(
|
|
21484
|
-
return pipe(this,
|
|
21786
|
+
pipe(target) {
|
|
21787
|
+
return pipe(this, target);
|
|
21485
21788
|
},
|
|
21486
21789
|
readonly() {
|
|
21487
21790
|
return readonly(this);
|
|
@@ -23990,27 +24293,41 @@ var browserHttpErrorV1 = external_exports.strictObject({
|
|
|
23990
24293
|
})
|
|
23991
24294
|
});
|
|
23992
24295
|
|
|
23993
|
-
// ../../packages/contracts/dist/versions/
|
|
23994
|
-
var
|
|
24296
|
+
// ../../packages/contracts/dist/versions/project-init-v4.js
|
|
24297
|
+
var projectInitV4 = external_exports.discriminatedUnion("ok", [
|
|
23995
24298
|
external_exports.strictObject({
|
|
23996
|
-
contract: external_exports.literal("
|
|
23997
|
-
version: external_exports.literal(
|
|
24299
|
+
contract: external_exports.literal("project-init"),
|
|
24300
|
+
version: external_exports.literal(4),
|
|
23998
24301
|
ok: external_exports.literal(true),
|
|
23999
|
-
outcome: external_exports.enum(["planned", "
|
|
24302
|
+
outcome: external_exports.enum(["planned", "created", "already-initialized"]),
|
|
24000
24303
|
rootPath: external_exports.string(),
|
|
24001
|
-
|
|
24002
|
-
|
|
24003
|
-
|
|
24004
|
-
|
|
24005
|
-
|
|
24304
|
+
configPath: external_exports.literal(".gitifact/config.json"),
|
|
24305
|
+
schemaVersion: external_exports.literal(1),
|
|
24306
|
+
baseline: external_exports.discriminatedUnion("kind", [
|
|
24307
|
+
external_exports.strictObject({ kind: external_exports.literal("empty") }),
|
|
24308
|
+
external_exports.strictObject({ kind: external_exports.literal("commit"), objectFormat: external_exports.enum(["sha1", "sha256"]), commit: external_exports.string() })
|
|
24309
|
+
]),
|
|
24310
|
+
agentDocs: external_exports.strictObject({ mode: external_exports.enum(["install", "remove", "skip"]), paths: external_exports.array(external_exports.string()) })
|
|
24006
24311
|
}),
|
|
24007
|
-
external_exports.strictObject({ contract: external_exports.literal("
|
|
24312
|
+
external_exports.strictObject({ contract: external_exports.literal("project-init"), version: external_exports.literal(4), ok: external_exports.literal(false), error: external_exports.strictObject({ code: external_exports.string(), message: external_exports.string() }) })
|
|
24008
24313
|
]);
|
|
24009
24314
|
|
|
24010
24315
|
// ../../packages/contracts/dist/versions/browser-specs-v1.js
|
|
24011
24316
|
var requirement = external_exports.strictObject({ id: external_exports.string(), title: external_exports.string(), body: external_exports.string() });
|
|
24012
|
-
var
|
|
24317
|
+
var contributor = external_exports.strictObject({ email: external_exports.string(), name: external_exports.string(), commits: external_exports.number().int().nonnegative(), latest: external_exports.string() });
|
|
24318
|
+
var feature = external_exports.strictObject({
|
|
24319
|
+
id: external_exports.string(),
|
|
24320
|
+
path: external_exports.string(),
|
|
24321
|
+
title: external_exports.string(),
|
|
24322
|
+
description: external_exports.string(),
|
|
24323
|
+
requirements: external_exports.array(requirement),
|
|
24324
|
+
design: external_exports.strictObject({ title: external_exports.string(), body: external_exports.string(), requirements: external_exports.array(external_exports.string()) }).optional(),
|
|
24325
|
+
// Authors of commits touching the feature folder (current or legacy store) and the latest such commit; empty until first committed.
|
|
24326
|
+
contributors: external_exports.array(contributor),
|
|
24327
|
+
updatedAt: external_exports.string().nullable()
|
|
24328
|
+
});
|
|
24013
24329
|
var snapshot = requirement.extend({ specId: external_exports.string(), path: external_exports.string() }).nullable();
|
|
24330
|
+
var document = external_exports.strictObject({ id: external_exports.string(), kind: external_exports.enum(["product", "guide"]), path: external_exports.string(), title: external_exports.string(), body: external_exports.string(), updatedAt: external_exports.string().nullable() });
|
|
24014
24331
|
var browserSpecsV1 = external_exports.strictObject({
|
|
24015
24332
|
contract: external_exports.literal("browser-specs"),
|
|
24016
24333
|
version: external_exports.literal(1),
|
|
@@ -24019,6 +24336,7 @@ var browserSpecsV1 = external_exports.strictObject({
|
|
|
24019
24336
|
observedAt: external_exports.string(),
|
|
24020
24337
|
working: external_exports.boolean(),
|
|
24021
24338
|
features: external_exports.array(feature),
|
|
24339
|
+
documents: external_exports.array(document).default([]),
|
|
24022
24340
|
events: external_exports.array(external_exports.strictObject({
|
|
24023
24341
|
key: external_exports.string(),
|
|
24024
24342
|
commit: external_exports.string(),
|
|
@@ -24028,13 +24346,13 @@ var browserSpecsV1 = external_exports.strictObject({
|
|
|
24028
24346
|
committer: external_exports.string(),
|
|
24029
24347
|
message: external_exports.string(),
|
|
24030
24348
|
id: external_exports.string(),
|
|
24031
|
-
kind: external_exports.enum(["requirement", "design"]).optional(),
|
|
24349
|
+
kind: external_exports.enum(["requirement", "design", "product", "guide"]).optional(),
|
|
24032
24350
|
types: external_exports.array(external_exports.enum(["created", "modified", "moved", "deleted"])),
|
|
24033
24351
|
before: snapshot,
|
|
24034
24352
|
after: snapshot,
|
|
24035
24353
|
reasons: external_exports.array(external_exports.string())
|
|
24036
24354
|
})),
|
|
24037
|
-
contributors: external_exports.array(
|
|
24355
|
+
contributors: external_exports.array(contributor),
|
|
24038
24356
|
contributorsLimited: external_exports.boolean(),
|
|
24039
24357
|
nextCursor: external_exports.number().int().nonnegative().nullable(),
|
|
24040
24358
|
boundary: external_exports.boolean()
|
|
@@ -24106,6 +24424,8 @@ async function runStatus(format) {
|
|
|
24106
24424
|
import { createServer } from "node:http";
|
|
24107
24425
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
24108
24426
|
import { fileURLToPath } from "node:url";
|
|
24427
|
+
import { lstat as lstat3, readFile as readFile4 } from "node:fs/promises";
|
|
24428
|
+
import { join as join4 } from "node:path";
|
|
24109
24429
|
|
|
24110
24430
|
// src/server/assets.ts
|
|
24111
24431
|
import { readdir, readFile } from "node:fs/promises";
|
|
@@ -24135,6 +24455,9 @@ function contentType(path3) {
|
|
|
24135
24455
|
if (path3.endsWith(".svg")) return "image/svg+xml";
|
|
24136
24456
|
if (path3.endsWith(".woff2")) return "font/woff2";
|
|
24137
24457
|
if (path3.endsWith(".png")) return "image/png";
|
|
24458
|
+
if (/\.jpe?g$/.test(path3)) return "image/jpeg";
|
|
24459
|
+
if (path3.endsWith(".gif")) return "image/gif";
|
|
24460
|
+
if (path3.endsWith(".webp")) return "image/webp";
|
|
24138
24461
|
return "application/octet-stream";
|
|
24139
24462
|
}
|
|
24140
24463
|
|
|
@@ -24195,6 +24518,7 @@ function commandScoped(key, load) {
|
|
|
24195
24518
|
}
|
|
24196
24519
|
|
|
24197
24520
|
// src/adapters/git/spec-preview-reader.ts
|
|
24521
|
+
var RECORD_PATHSPECS = [...STORE_DIRS.map((d) => d + "/spec/"), ...Object.values(DOCUMENT_DIRS).map((d) => d + "/")];
|
|
24198
24522
|
function specPreviewReader(cwd) {
|
|
24199
24523
|
for (const key of Object.keys(process.env)) if (/^GIT_(DIR|WORK_TREE|COMMON_DIR|INDEX_FILE|OBJECT_DIRECTORY|ALTERNATE_OBJECT_DIRECTORIES|CONFIG_COUNT|CONFIG_PARAMETERS|CONFIG_KEY_\d+|CONFIG_VALUE_\d+)$/i.test(key)) {
|
|
24200
24524
|
throw new SpecPreviewError("Git \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uB36E\uC5B4\uC4F0\uB294 \uD658\uACBD\uC5D0\uC11C\uB294 \uC870\uD68C\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
@@ -24218,14 +24542,17 @@ function specPreviewReader(cwd) {
|
|
|
24218
24542
|
};
|
|
24219
24543
|
return {
|
|
24220
24544
|
async index() {
|
|
24221
|
-
const output2 = decode5(await git(["ls-files", "--stage", "-z", "--", ...
|
|
24545
|
+
const output2 = decode5(await git(["ls-files", "--stage", "-z", "--", ...RECORD_PATHSPECS]));
|
|
24222
24546
|
const files = /* @__PURE__ */ new Map();
|
|
24223
24547
|
for (const row of output2.split("\0").filter(Boolean)) {
|
|
24224
24548
|
const match = /^(\d+) ([a-f0-9]+) ([0-3])\t([\s\S]+)$/.exec(row);
|
|
24225
24549
|
if (!match) throw new SpecPreviewError("\uC798\uBABB\uB41C index \uD56D\uBAA9\uC785\uB2C8\uB2E4.");
|
|
24226
24550
|
const [, mode, oid2, stage, path3] = match;
|
|
24227
24551
|
if (!["100644", "100755"].includes(mode) || stage !== "0") throw new SpecPreviewError("\uBA85\uC138 staging\uC5D0 \uCDA9\uB3CC \uB610\uB294 \uB9C1\uD06C\uAC00 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
24228
|
-
if (!recordPathPattern.test(path3))
|
|
24552
|
+
if (!recordPathPattern.test(path3)) {
|
|
24553
|
+
if (/^\.gitifact\/(?:product|guides)\//.test(path3)) continue;
|
|
24554
|
+
throw new SpecPreviewError("\uBA85\uC138 staging\uC5D0 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
24555
|
+
}
|
|
24229
24556
|
files.set(path3, oid2);
|
|
24230
24557
|
}
|
|
24231
24558
|
return files;
|
|
@@ -24264,7 +24591,7 @@ function specPreviewReader(cwd) {
|
|
|
24264
24591
|
return oid2;
|
|
24265
24592
|
},
|
|
24266
24593
|
async files(oid2, allowLegacyBaseline = false) {
|
|
24267
|
-
const entries = decode5(await git(["ls-tree", "--full-tree", "-r", "-z", oid2, "--", ...
|
|
24594
|
+
const entries = decode5(await git(["ls-tree", "--full-tree", "-r", "-z", oid2, "--", ...RECORD_PATHSPECS]));
|
|
24268
24595
|
const files = /* @__PURE__ */ new Map();
|
|
24269
24596
|
let legacy;
|
|
24270
24597
|
for (const row of entries.split("\0").filter(Boolean)) {
|
|
@@ -24272,7 +24599,7 @@ function specPreviewReader(cwd) {
|
|
|
24272
24599
|
if (!match) throw new SpecPreviewError("\uC798\uBABB\uB41C Git tree\uC785\uB2C8\uB2E4.");
|
|
24273
24600
|
const [, mode, type, object4, path3] = match;
|
|
24274
24601
|
if (!["100644", "100755"].includes(mode) || type !== "blob") throw new SpecPreviewError("\uBA85\uC138 \uC601\uC5ED\uC5D0 \uB9C1\uD06C \uB610\uB294 \uC11C\uBE0C\uBAA8\uB4C8\uC774 \uC788\uC2B5\uB2C8\uB2E4: " + path3);
|
|
24275
|
-
if (
|
|
24602
|
+
if (!recordPathPattern.test(path3) && !path3.endsWith("/tryce.json")) continue;
|
|
24276
24603
|
if (path3.endsWith("/tryce.json")) {
|
|
24277
24604
|
if (!allowLegacyBaseline) throw new SpecPreviewError("\uAE30\uC874 JSON \uD615\uC2DD\uC740 req \uBA85\uB839\uC73C\uB85C \uC870\uD68C\uD558\uC138\uC694. \uC774 \uBA85\uB839\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
24278
24605
|
legacy = path3.split("/")[0];
|
|
@@ -24311,6 +24638,9 @@ function specPreviewReader(cwd) {
|
|
|
24311
24638
|
async read(oid2) {
|
|
24312
24639
|
const files = await this.files(oid2);
|
|
24313
24640
|
return parsePreviewFiles(files);
|
|
24641
|
+
},
|
|
24642
|
+
async readBundle(oid2) {
|
|
24643
|
+
return parsePreviewBundle(await this.files(oid2));
|
|
24314
24644
|
}
|
|
24315
24645
|
};
|
|
24316
24646
|
}
|
|
@@ -24421,18 +24751,18 @@ async function snapshot2(root) {
|
|
|
24421
24751
|
if (!parent && await info(join3(root, ".tryce"))) fail4(".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD55C \uB4A4 \uC0AC\uC6A9\uD558\uC138\uC694.");
|
|
24422
24752
|
const config2 = await readConfigFile(root);
|
|
24423
24753
|
if (config2 !== void 0 && !("schemaVersion" in parseManagedConfig(config2)) || await info(join3(root, "specs"))) fail4("\uAE30\uC874 \uD504\uB85C\uC81D\uD2B8 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
24424
|
-
async function visit2(path3, depth) {
|
|
24754
|
+
async function visit2(path3, depth, documents) {
|
|
24425
24755
|
const stat3 = await info(join3(root, path3));
|
|
24426
24756
|
if (!stat3) return;
|
|
24427
24757
|
if (stat3.isSymbolicLink() || !stat3.isDirectory() && !stat3.isFile()) fail4("\uB9C1\uD06C\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + path3);
|
|
24428
24758
|
if (++count > 4e3) fail4("\uBA85\uC138 \uD30C\uC77C \uC218 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
24429
24759
|
if (stat3.isDirectory()) {
|
|
24430
|
-
if (depth > 1) fail4("\uC911\uCCA9 \
|
|
24431
|
-
for (const name of (await readdir2(join3(root, path3))).sort()) await visit2(path3 + "/" + name, depth + 1);
|
|
24760
|
+
if (depth > (documents ? 8 : 1)) fail4("\uC911\uCCA9 \uD3F4\uB354 \uAE4A\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: " + path3);
|
|
24761
|
+
for (const name of (await readdir2(join3(root, path3))).sort()) await visit2(path3 + "/" + name, depth + 1, documents);
|
|
24432
24762
|
} else {
|
|
24433
24763
|
if (path3.endsWith("/tryce.json")) fail4("\uAE30\uC874 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
24434
|
-
if (!/\/(requirements\.md|design\.md|history\.jsonl)$/.test(path3)) return;
|
|
24435
|
-
if (
|
|
24764
|
+
if (documents ? !(path3.endsWith(".md") || depth === 1 && path3.endsWith("/history.jsonl")) : !/\/(requirements\.md|design\.md|history\.jsonl)$/.test(path3)) return;
|
|
24765
|
+
if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/")) fail4("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uACBD\uB85C\uC785\uB2C8\uB2E4: " + path3);
|
|
24436
24766
|
if (stat3.nlink !== 1 || stat3.size > 1024 * 1024) fail4("\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 1 MiB \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.");
|
|
24437
24767
|
const raw = await readFile3(join3(root, path3));
|
|
24438
24768
|
bytes += raw.length;
|
|
@@ -24440,9 +24770,10 @@ async function snapshot2(root) {
|
|
|
24440
24770
|
files.set(path3, decode3(raw));
|
|
24441
24771
|
}
|
|
24442
24772
|
}
|
|
24443
|
-
await visit2(".gitifact/spec", 0);
|
|
24444
|
-
const
|
|
24445
|
-
|
|
24773
|
+
await visit2(".gitifact/spec", 0, false);
|
|
24774
|
+
for (const dir of Object.values(DOCUMENT_DIRS)) await visit2(dir, 0, true);
|
|
24775
|
+
const bundle = parsePreviewBundle(files);
|
|
24776
|
+
return { files, specs: bundle.specs, documents: bundle.documents, bundle, config: config2, stamp: digest(JSON.stringify([...files].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) + (config2 ?? "")) };
|
|
24446
24777
|
}
|
|
24447
24778
|
async function readWorkingPreviewState(cwd) {
|
|
24448
24779
|
const { root, gitDir } = await specPreviewReader(cwd).location();
|
|
@@ -24455,21 +24786,29 @@ async function readWorkingPreviewState(cwd) {
|
|
|
24455
24786
|
return first;
|
|
24456
24787
|
}
|
|
24457
24788
|
async function readWorkingPreview(cwd) {
|
|
24458
|
-
const { stamp, specs } = await readWorkingPreviewState(cwd);
|
|
24459
|
-
return { stamp, specs, warnings: designReferenceWarnings(specs) };
|
|
24789
|
+
const { stamp, specs, documents } = await readWorkingPreviewState(cwd);
|
|
24790
|
+
return { stamp, specs, documents, warnings: designReferenceWarnings(specs) };
|
|
24460
24791
|
}
|
|
24461
24792
|
async function saveWorkingPreview(cwd, input2, publish = rename) {
|
|
24462
24793
|
if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail4("\uC800\uC7A5 \uC785\uB825\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
|
|
24463
24794
|
const request = input2;
|
|
24464
24795
|
if (Object.keys(request).sort().join(",") !== "expected,operations" || typeof request.expected !== "string") fail4("expected\uC640 operations\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
24465
24796
|
return previewTransaction(cwd, request.expected, async (before) => {
|
|
24466
|
-
const result = editSpecPreview(before.
|
|
24797
|
+
const result = editSpecPreview(before.bundle, request.operations, generatePreviewId);
|
|
24467
24798
|
const writes = /* @__PURE__ */ new Map();
|
|
24468
24799
|
for (const spec2 of result.specs) {
|
|
24469
24800
|
const old = before.specs.find((s) => s.id === spec2.id);
|
|
24470
24801
|
if (!old || renderSpecPreview(old) !== renderSpecPreview(spec2)) writes.set(spec2.path, renderSpecPreview(spec2));
|
|
24471
24802
|
if (JSON.stringify(old?.design) !== JSON.stringify(spec2.design)) writes.set(spec2.path.replace(/requirements\.md$/, "design.md"), spec2.design ? renderDesignPreview(spec2.id, spec2.design) : null);
|
|
24472
24803
|
}
|
|
24804
|
+
const previousDocs = before.documents.flatMap((s) => s.documents);
|
|
24805
|
+
const nextDocs = result.documents.flatMap((s) => s.documents);
|
|
24806
|
+
for (const doc of nextDocs) {
|
|
24807
|
+
const old = previousDocs.find((d) => d.id === doc.id);
|
|
24808
|
+
if (old && old.path !== doc.path) writes.set(old.path, null);
|
|
24809
|
+
if (!old || renderDocument(old) !== renderDocument(doc) || old.path !== doc.path) writes.set(doc.path, renderDocument(doc));
|
|
24810
|
+
}
|
|
24811
|
+
for (const old of previousDocs) if (!nextDocs.some((d) => d.id === old.id)) writes.set(old.path, null);
|
|
24473
24812
|
return { writes, data: { results: result.results } };
|
|
24474
24813
|
}, publish);
|
|
24475
24814
|
}
|
|
@@ -24477,9 +24816,9 @@ var readLockedPreviewState = (root) => snapshot2(root);
|
|
|
24477
24816
|
async function previewTransaction(cwd, expected2, build, publish = rename, afterPublish) {
|
|
24478
24817
|
const { root, gitDir } = await specPreviewReader(cwd).location();
|
|
24479
24818
|
await failOnLegacyLock(gitDir);
|
|
24480
|
-
const
|
|
24819
|
+
const lock = join3(gitDir, "gitifact-spec-preview.lock");
|
|
24481
24820
|
try {
|
|
24482
|
-
await mkdir2(
|
|
24821
|
+
await mkdir2(lock);
|
|
24483
24822
|
} catch (e) {
|
|
24484
24823
|
if (e.code === "EEXIST") fail4("\uBA85\uC138 \uC800\uC7A5 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
24485
24824
|
throw e;
|
|
@@ -24504,7 +24843,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
|
|
|
24504
24843
|
if (before.stamp !== expected2) fail4("\uC77D\uC740 \uB4A4 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. working\uC73C\uB85C \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.");
|
|
24505
24844
|
const result = await build(before);
|
|
24506
24845
|
for (const [path3, after2] of result.writes) {
|
|
24507
|
-
if (
|
|
24846
|
+
if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/") || path3.split("/").some((p) => p === ".." || p === "." || /[\\:\0]/.test(p))) fail4("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC800\uC7A5 \uACBD\uB85C\uC785\uB2C8\uB2E4.");
|
|
24508
24847
|
if (after2 !== null && Buffer.byteLength(after2) > 1024 * 1024) fail4("\uBA85\uC138 1 MiB \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
24509
24848
|
changed.push({ path: path3, before: before.files.get(path3) ?? null, after: after2 });
|
|
24510
24849
|
}
|
|
@@ -24514,7 +24853,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
|
|
|
24514
24853
|
else finalFiles.set(c.path, c.after);
|
|
24515
24854
|
}
|
|
24516
24855
|
if (finalFiles.size > 2e3 || [...finalFiles.values()].reduce((n, s) => n + Buffer.byteLength(s), 0) > 16 * 1024 * 1024) fail4("\uBA85\uC138 \uC804\uCCB4 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
24517
|
-
await writeFile(join3(
|
|
24856
|
+
await writeFile(join3(lock, "recovery.json"), JSON.stringify({ root, changed }), { flag: "wx" });
|
|
24518
24857
|
for (const c of changed) {
|
|
24519
24858
|
if (c.after === null) {
|
|
24520
24859
|
temporary.push("");
|
|
@@ -24540,7 +24879,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
|
|
|
24540
24879
|
if (after.stamp !== digest(JSON.stringify([...finalFiles].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) + (before.config ?? ""))) fail4("\uC800\uC7A5 \uC911 \uBA85\uC138 \uB610\uB294 \uC124\uC815\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
24541
24880
|
await result.recheck?.();
|
|
24542
24881
|
await afterPublish?.(after);
|
|
24543
|
-
return { ...result.data, stamp: after.stamp, paths: changed.map((c) => c.path), specs: after.specs, warnings: designReferenceWarnings(after.specs) };
|
|
24882
|
+
return { ...result.data, stamp: after.stamp, paths: changed.map((c) => c.path), specs: after.specs, documents: after.documents, warnings: designReferenceWarnings(after.specs) };
|
|
24544
24883
|
} catch (error62) {
|
|
24545
24884
|
if (error62 instanceof PreservedPreviewError) {
|
|
24546
24885
|
keepRecovery = true;
|
|
@@ -24565,7 +24904,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
|
|
|
24565
24904
|
keepRecovery = true;
|
|
24566
24905
|
}
|
|
24567
24906
|
}
|
|
24568
|
-
if (keepRecovery) fail4("\uC790\uB3D9 \uBCF5\uAD6C\uB97C \uC644\uB8CC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uB978 \uD3B8\uC9D1\uC744 \uBCF4\uC874\uD588\uC2B5\uB2C8\uB2E4. \uBCF5\uAD6C \uC790\uB8CC: " +
|
|
24907
|
+
if (keepRecovery) fail4("\uC790\uB3D9 \uBCF5\uAD6C\uB97C \uC644\uB8CC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uB978 \uD3B8\uC9D1\uC744 \uBCF4\uC874\uD588\uC2B5\uB2C8\uB2E4. \uBCF5\uAD6C \uC790\uB8CC: " + lock);
|
|
24569
24908
|
throw error62;
|
|
24570
24909
|
} finally {
|
|
24571
24910
|
for (const path3 of temporary.filter(Boolean)) await unlink2(path3).catch((e) => {
|
|
@@ -24574,10 +24913,10 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
|
|
|
24574
24913
|
for (const path3 of [...createdDirs].reverse()) await rmdir(path3).catch(() => {
|
|
24575
24914
|
});
|
|
24576
24915
|
if (!keepRecovery) {
|
|
24577
|
-
await unlink2(join3(
|
|
24916
|
+
await unlink2(join3(lock, "recovery.json")).catch((e) => {
|
|
24578
24917
|
if (e.code !== "ENOENT") throw e;
|
|
24579
24918
|
});
|
|
24580
|
-
await rmdir(
|
|
24919
|
+
await rmdir(lock);
|
|
24581
24920
|
}
|
|
24582
24921
|
}
|
|
24583
24922
|
}
|
|
@@ -24598,7 +24937,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
|
|
|
24598
24937
|
const snapshot3 = (oid2) => {
|
|
24599
24938
|
let value = snapshots.get(oid2);
|
|
24600
24939
|
if (!value) {
|
|
24601
|
-
value = reader.
|
|
24940
|
+
value = reader.readBundle(oid2).catch((e) => {
|
|
24602
24941
|
snapshots.delete(oid2);
|
|
24603
24942
|
throw e;
|
|
24604
24943
|
});
|
|
@@ -24615,12 +24954,39 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
|
|
|
24615
24954
|
const base = { head: await readHead() };
|
|
24616
24955
|
if (cursor > 0 && expectedHead !== base.head) throw new SpecPreviewError("\uC774\uB825\uC774 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.");
|
|
24617
24956
|
const current = await readWorkingPreviewState(root);
|
|
24618
|
-
const
|
|
24619
|
-
|
|
24957
|
+
const bare = current.specs.map(({ history: _history, ...s }) => ({ ...s, contributors: [], updatedAt: null }));
|
|
24958
|
+
const bareDocuments = current.documents.flatMap((set2) => set2.documents).map((d) => ({ ...d, updatedAt: null }));
|
|
24959
|
+
if (!base.head) return browserSpecsV1.parse({ contract: "browser-specs", version: 1, sessionId, head: null, observedAt: (/* @__PURE__ */ new Date()).toISOString(), working: bare.length > 0 || bareDocuments.length > 0, features: bare, documents: bareDocuments, events: [], contributors: [], contributorsLimited: false, nextCursor: null, boundary: false });
|
|
24620
24960
|
const head = base.head;
|
|
24961
|
+
const features = await Promise.all(bare.map(async (feature2) => {
|
|
24962
|
+
const folder = feature2.path.replace(/^\.(?:gitifact|tryce)\/(spec\/[^/]+)\/requirements\.md$/, "$1");
|
|
24963
|
+
const lines = (await git(["log", "--format=%aN%x00%aE%x00%aI", "--max-count=2000", head, "--", `.gitifact/${folder}`, `.tryce/${folder}`])).trim().split("\n").filter(Boolean);
|
|
24964
|
+
const people = /* @__PURE__ */ new Map();
|
|
24965
|
+
for (const line of lines) {
|
|
24966
|
+
const [name, email3, latest] = line.split("\0");
|
|
24967
|
+
if (!name || !email3 || !latest) throw new SpecPreviewError("Git \uC791\uC131\uC790\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
24968
|
+
const person = people.get(email3);
|
|
24969
|
+
if (person) person.commits++;
|
|
24970
|
+
else people.set(email3, { name, email: email3, latest, commits: 1 });
|
|
24971
|
+
}
|
|
24972
|
+
return { ...feature2, contributors: [...people.values()].sort((a, b) => b.commits - a.commits), updatedAt: lines[0]?.split("\0")[2] ?? null };
|
|
24973
|
+
}));
|
|
24974
|
+
const documents = await Promise.all(bareDocuments.map(async (doc) => ({ ...doc, updatedAt: (await git(["log", "--format=%aI", "--max-count=1", head, "--", doc.path])).trim() || null })));
|
|
24975
|
+
const documentDirs = Object.values(DOCUMENT_DIRS);
|
|
24621
24976
|
const [rows, dirty] = await Promise.all([
|
|
24622
|
-
git([
|
|
24623
|
-
|
|
24977
|
+
git([
|
|
24978
|
+
"log",
|
|
24979
|
+
"--first-parent",
|
|
24980
|
+
"--date-order",
|
|
24981
|
+
"--format=%H%x00%P%x00%aN%x00%aE%x00%aI%x00%cN%x00%s",
|
|
24982
|
+
"--max-count=11",
|
|
24983
|
+
"--skip=" + cursor,
|
|
24984
|
+
head,
|
|
24985
|
+
"--",
|
|
24986
|
+
...[".gitifact", ".tryce"].flatMap((d) => [`:(glob)${d}/spec/*/requirements.md`, `:(glob)${d}/spec/*/design.md`, `:(glob)${d}/spec/*/history.jsonl`]),
|
|
24987
|
+
...documentDirs.flatMap((d) => [`:(glob)${d}/**/*.md`, `:(glob)${d}/history.jsonl`])
|
|
24988
|
+
]),
|
|
24989
|
+
git(["status", "--porcelain=v1", "--", ".gitifact/spec", ...documentDirs])
|
|
24624
24990
|
]);
|
|
24625
24991
|
{
|
|
24626
24992
|
const people = /* @__PURE__ */ new Map();
|
|
@@ -24640,7 +25006,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
|
|
|
24640
25006
|
const [commit, parents, author, email3, date5, committer, message] = row.split("\0");
|
|
24641
25007
|
if (!commit || author === void 0 || email3 === void 0 || !date5 || committer === void 0 || message === void 0) throw new SpecPreviewError("Git \uC774\uB825 \uD615\uC2DD\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
24642
25008
|
const after = await snapshot3(commit);
|
|
24643
|
-
let before = [];
|
|
25009
|
+
let before = { specs: [], documents: [{ kind: "product", documents: [], history: [] }, { kind: "guide", documents: [], history: [] }] };
|
|
24644
25010
|
const parent = parents?.split(" ")[0];
|
|
24645
25011
|
if (parent) {
|
|
24646
25012
|
try {
|
|
@@ -24650,7 +25016,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
|
|
|
24650
25016
|
else throw error62;
|
|
24651
25017
|
}
|
|
24652
25018
|
}
|
|
24653
|
-
return
|
|
25019
|
+
return comparePreviewBundles(before, after).changes.map((c) => ({
|
|
24654
25020
|
key: commit + ":" + c.id,
|
|
24655
25021
|
commit,
|
|
24656
25022
|
author,
|
|
@@ -24675,6 +25041,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
|
|
|
24675
25041
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24676
25042
|
working: !!dirty.trim(),
|
|
24677
25043
|
features,
|
|
25044
|
+
documents,
|
|
24678
25045
|
events: groups.flat(),
|
|
24679
25046
|
contributors: peopleCache.data,
|
|
24680
25047
|
contributorsLimited: peopleCache.limited,
|
|
@@ -24756,6 +25123,21 @@ async function startBrowserServer(options) {
|
|
|
24756
25123
|
if (api) {
|
|
24757
25124
|
if (request.headers["sec-fetch-site"] === "cross-site" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", "\uC678\uBD80 \uD398\uC774\uC9C0\uC758 \uC694\uCCAD\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
24758
25125
|
if (url2.search && path3 !== "/api/v1/specs") return fail8(response, 400, "BAD_REQUEST", "\uC870\uD68C \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
25126
|
+
if (path3.startsWith("/api/v1/product/assets/")) {
|
|
25127
|
+
const name = path3.slice("/api/v1/product/assets/".length);
|
|
25128
|
+
if (request.method !== "GET") {
|
|
25129
|
+
response.setHeader("Allow", "GET");
|
|
25130
|
+
return fail8(response, 405, "METHOD_NOT_ALLOWED", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.");
|
|
25131
|
+
}
|
|
25132
|
+
if (!isProductAssetPath(".gitifact/product/" + name)) return fail8(response, 404, "NOT_FOUND", "\uC81C\uD488 \uC774\uBBF8\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
25133
|
+
const file2 = join4(initial.repository.rootPath, ".gitifact", "product", name);
|
|
25134
|
+
const stat3 = await lstat3(file2).catch(() => void 0);
|
|
25135
|
+
if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > 5 * 1024 * 1024) return fail8(response, 404, "NOT_FOUND", "\uC81C\uD488 \uC774\uBBF8\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
25136
|
+
const bytes = await readFile4(file2);
|
|
25137
|
+
response.writeHead(200, { "Content-Type": contentType(name.toLowerCase()), "Cache-Control": "no-cache", "Content-Length": bytes.length });
|
|
25138
|
+
response.end(bytes);
|
|
25139
|
+
return;
|
|
25140
|
+
}
|
|
24759
25141
|
const method = path3 === "/api/v1/status/refresh" ? "POST" : "GET";
|
|
24760
25142
|
if (!["/api/v1/session", "/api/v1/status", "/api/v1/status/refresh", "/api/v1/specs"].includes(path3)) return fail8(response, 404, "NOT_FOUND", "API\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
24761
25143
|
if (request.method !== method) {
|
|
@@ -24881,12 +25263,12 @@ async function runBrowser(options) {
|
|
|
24881
25263
|
|
|
24882
25264
|
// src/commands/spec-init.ts
|
|
24883
25265
|
import { readdir as readdir3 } from "node:fs/promises";
|
|
24884
|
-
import { join as
|
|
25266
|
+
import { join as join7 } from "node:path";
|
|
24885
25267
|
|
|
24886
25268
|
// src/adapters/git/init-repository.ts
|
|
24887
25269
|
import { createHash as createHash3 } from "node:crypto";
|
|
24888
|
-
import { readFile as
|
|
24889
|
-
import { join as
|
|
25270
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
25271
|
+
import { join as join5 } from "node:path";
|
|
24890
25272
|
function initRepository(cwd, inherited = process.env) {
|
|
24891
25273
|
const env = { ...inherited, GIT_OPTIONAL_LOCKS: "0", GIT_NO_LAZY_FETCH: "1", GIT_TERMINAL_PROMPT: "0", GIT_LITERAL_PATHSPECS: "1", LC_ALL: "C" };
|
|
24892
25274
|
const runner = createGitRunner();
|
|
@@ -24906,10 +25288,10 @@ function initRepository(cwd, inherited = process.env) {
|
|
|
24906
25288
|
const gitDir = locations.length === 2 ? locations[0] : decodeGitLine(await git(["rev-parse", "--absolute-git-dir"], root));
|
|
24907
25289
|
const indexPath = locations.length === 2 ? locations[1] : decodeGitLine(await git(["rev-parse", "--path-format=absolute", "--git-path", "index"], root));
|
|
24908
25290
|
for (const marker2 of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"]) {
|
|
24909
|
-
if (await fileInfo(
|
|
25291
|
+
if (await fileInfo(join5(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: " + marker2);
|
|
24910
25292
|
}
|
|
24911
25293
|
if (state.changes.some((change2) => change2.kind === "unmerged")) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.");
|
|
24912
|
-
const index = await
|
|
25294
|
+
const index = await readFile5(indexPath).catch((error62) => {
|
|
24913
25295
|
if (error62.code === "ENOENT") return Buffer.alloc(0);
|
|
24914
25296
|
throw error62;
|
|
24915
25297
|
});
|
|
@@ -24923,11 +25305,6 @@ function initRepository(cwd, inherited = process.env) {
|
|
|
24923
25305
|
stamp: JSON.stringify({ repository: state.repository, head: state.head, index: createHash3("sha256").update(index).digest("hex") })
|
|
24924
25306
|
};
|
|
24925
25307
|
},
|
|
24926
|
-
async trackedPaths(root, prefix, commit) {
|
|
24927
|
-
const indexed = await git(["ls-files", "-z", "--", prefix], root);
|
|
24928
|
-
const committed = commit ? await git(["ls-tree", "-r", "--name-only", "-z", commit, "--", prefix], root) : Buffer.alloc(0);
|
|
24929
|
-
return [...new Set(Buffer.concat([indexed, committed]).toString("utf8").split("\0").filter(Boolean))];
|
|
24930
|
-
},
|
|
24931
25308
|
async checkIgnore(root, path3 = ".gitifact/config.json") {
|
|
24932
25309
|
const output2 = (await git(["check-ignore", "--no-index", "-v", "-z", "--stdin"], root, [0, 1], Buffer.from(path3 + "\0"))).toString("utf8");
|
|
24933
25310
|
const fields2 = output2.split("\0");
|
|
@@ -24947,87 +25324,12 @@ function initRepository(cwd, inherited = process.env) {
|
|
|
24947
25324
|
};
|
|
24948
25325
|
}
|
|
24949
25326
|
|
|
24950
|
-
// src/
|
|
24951
|
-
|
|
24952
|
-
const repo = initRepository(cwd, env);
|
|
24953
|
-
const first = await repo.inspect();
|
|
24954
|
-
const root = first.state.repository.rootPath;
|
|
24955
|
-
const result = (config3, outcome) => ({
|
|
24956
|
-
contract: "project-init",
|
|
24957
|
-
version: 3,
|
|
24958
|
-
ok: true,
|
|
24959
|
-
outcome,
|
|
24960
|
-
rootPath: root,
|
|
24961
|
-
configPath: ".gitifact/config.json",
|
|
24962
|
-
schemaVersion: config3.schemaVersion,
|
|
24963
|
-
baseline: config3.baseline,
|
|
24964
|
-
integrations: { skills: "not-installed-by-init", hooks: "not-installed-by-init" }
|
|
24965
|
-
});
|
|
24966
|
-
const existing = async (text2) => {
|
|
24967
|
-
const config3 = parseManagedConfig(text2);
|
|
24968
|
-
if (!("schemaVersion" in config3)) throw new InitError("MIGRATION_REQUIRED", "\uAE30\uC874 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC124\uC815\uACFC \uAE30\uB85D\uC744 \uBCF4\uC874\uD558\uC138\uC694.");
|
|
24969
|
-
await repo.validateBaseline(config3, root, first.state.head.commit, first.state.repository.objectFormat);
|
|
24970
|
-
if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text2) throw new InitError("INPUT_CHANGED", "\uCD08\uAE30\uD654 \uC870\uD68C \uC911 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
24971
|
-
return result(config3, "already-initialized");
|
|
24972
|
-
};
|
|
24973
|
-
const old = await readConfigFile(root);
|
|
24974
|
-
if (old !== void 0) return existing(old);
|
|
24975
|
-
if (first.trackedConfig) throw new InitError("CONFIG_DELETED", "\uAE30\uC874 \uC124\uC815\uC758 \uC0AD\uC81C\uB97C \uC2E0\uADDC \uB3C4\uC785\uC73C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
24976
|
-
const checkRecords = async () => {
|
|
24977
|
-
if (await fileInfo(join5(root, "specs"))) throw new InitError("EXISTING_RECORDS", "\uAE30\uC874 specs \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.");
|
|
24978
|
-
const entries = await readdir3(join5(root, ".gitifact")).catch((e) => {
|
|
24979
|
-
if (e.code === "ENOENT") return [];
|
|
24980
|
-
throw e;
|
|
24981
|
-
});
|
|
24982
|
-
if (entries.some((name) => !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) throw new InitError("EXISTING_RECORDS", "\uC124\uC815 \uC5C6\uB294 .gitifact \uC790\uB8CC\uB97C \uC790\uB3D9 \uCC44\uD0DD\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
24983
|
-
};
|
|
24984
|
-
const config2 = { schemaVersion: 1, baseline: first.state.head.commit ? { kind: "commit", objectFormat: first.state.repository.objectFormat, commit: first.state.head.commit } : { kind: "empty" } };
|
|
24985
|
-
const recheck = async () => {
|
|
24986
|
-
await checkRecords();
|
|
24987
|
-
await repo.checkIgnore(root);
|
|
24988
|
-
if ((await repo.inspect()).stamp !== first.stamp) throw new InitError("INPUT_CHANGED", "HEAD \uB610\uB294 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
24989
|
-
if (await readConfigFile(root) !== void 0) throw new InitError("CONFIG_APPEARED", "\uB2E4\uB978 \uC2E4\uD589\uC774 \uC124\uC815\uC744 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
24990
|
-
};
|
|
24991
|
-
await recheck();
|
|
24992
|
-
if (dryRun) return result(config2, "planned");
|
|
24993
|
-
try {
|
|
24994
|
-
await publishConfig(root, JSON.stringify(config2, null, 2) + "\n", recheck, beforePublish);
|
|
24995
|
-
} catch (error62) {
|
|
24996
|
-
if (error62.code === "EEXIST" || error62 instanceof InitError && error62.code === "CONFIG_APPEARED") {
|
|
24997
|
-
const concurrent = await readConfigFile(root);
|
|
24998
|
-
if (concurrent !== void 0) return existing(concurrent);
|
|
24999
|
-
}
|
|
25000
|
-
throw error62;
|
|
25001
|
-
}
|
|
25002
|
-
if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== JSON.stringify(config2, null, 2) + "\n") throw new InitError("INPUT_CHANGED_AFTER_WRITE", "\uC124\uC815 \uC0DD\uC131 \uD6C4 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.");
|
|
25003
|
-
return result(config2, "created");
|
|
25004
|
-
}
|
|
25005
|
-
|
|
25006
|
-
// src/commands/init.ts
|
|
25007
|
-
async function runInit(options) {
|
|
25008
|
-
try {
|
|
25009
|
-
const dto = await initializeSpecProject(process.cwd(), options.dryRun);
|
|
25010
|
-
process.stdout.write(options.format === "text" ? `${dto.outcome}: ${dto.rootPath}/.gitifact/config.json
|
|
25011
|
-
\uC800\uC7A5 \uADDC\uC57D: schemaVersion 1
|
|
25012
|
-
\uC2A4\uD0AC\xB7\uD6C5\uC740 \uC124\uCE58\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
25013
|
-
` : JSON.stringify(dto) + "\n");
|
|
25014
|
-
} catch (error62) {
|
|
25015
|
-
const known = error62 instanceof InitError || error62 instanceof RepositoryReadError;
|
|
25016
|
-
const failure2 = { code: known ? error62.code : "INIT_FAILED", message: known ? error62.message : "\uCD08\uAE30\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uD30C\uC77C \uC811\uADFC \uAD8C\uD55C\uACFC \uC0DD\uC131\uB41C \uC124\uC815\xB7\uC784\uC2DC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694." };
|
|
25017
|
-
process.stderr.write(options.format === "text" ? failure2.code + ": " + failure2.message + "\n" : JSON.stringify({ contract: "project-init", version: 1, ok: false, error: failure2 }) + "\n");
|
|
25018
|
-
process.exitCode = 1;
|
|
25019
|
-
}
|
|
25020
|
-
}
|
|
25021
|
-
|
|
25022
|
-
// src/commands/skills.ts
|
|
25023
|
-
import { createHash as createHash4 } from "node:crypto";
|
|
25024
|
-
import { readFile as readFile6 } from "node:fs/promises";
|
|
25025
|
-
|
|
25026
|
-
// src/adapters/filesystem/skill-files.ts
|
|
25027
|
-
import { open as open3, readFile as readFile5, mkdir as mkdir3, realpath as realpath2, rename as rename2, link as link2, unlink as unlink3 } from "node:fs/promises";
|
|
25327
|
+
// src/adapters/filesystem/managed-file.ts
|
|
25328
|
+
import { open as open3, readFile as readFile6, mkdir as mkdir3, realpath as realpath2, rename as rename2, link as link2, unlink as unlink3 } from "node:fs/promises";
|
|
25028
25329
|
import { join as join6, dirname as dirname2 } from "node:path";
|
|
25029
25330
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
25030
|
-
|
|
25331
|
+
var DEFAULT_LIMIT = 1024 * 1024;
|
|
25332
|
+
async function managedPath(root, path3, create = false) {
|
|
25031
25333
|
let full = root;
|
|
25032
25334
|
const parts = path3.split("/");
|
|
25033
25335
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -25045,41 +25347,41 @@ async function skillPath(root, path3, create = false) {
|
|
|
25045
25347
|
}
|
|
25046
25348
|
return full;
|
|
25047
25349
|
}
|
|
25048
|
-
async function
|
|
25049
|
-
const full = await
|
|
25350
|
+
async function managedRead(root, path3, limit = DEFAULT_LIMIT) {
|
|
25351
|
+
const full = await managedPath(root, path3);
|
|
25050
25352
|
const before = await fileInfo(full);
|
|
25051
25353
|
if (!before) return null;
|
|
25052
|
-
if (before.size >
|
|
25053
|
-
const bytes = await
|
|
25054
|
-
await
|
|
25354
|
+
if (before.size > limit) throw new InitError("FILE_TOO_LARGE", limit / 1024 + " KiB\uB97C \uCD08\uACFC\uD569\uB2C8\uB2E4: " + path3);
|
|
25355
|
+
const bytes = await readFile6(full);
|
|
25356
|
+
await managedPath(root, path3);
|
|
25055
25357
|
const after = await fileInfo(full);
|
|
25056
|
-
if (!after || before.ino !== after.ino || before.dev !== after.dev || before.mtimeMs !== after.mtimeMs || bytes.length >
|
|
25358
|
+
if (!after || before.ino !== after.ino || before.dev !== after.dev || before.mtimeMs !== after.mtimeMs || bytes.length > limit) {
|
|
25057
25359
|
throw new InitError("INPUT_CHANGED", "\uC870\uD68C \uC911 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25058
25360
|
}
|
|
25059
25361
|
try {
|
|
25060
25362
|
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
25061
25363
|
} catch {
|
|
25062
|
-
throw new InitError("
|
|
25364
|
+
throw new InitError("INVALID_UTF8", "UTF-8 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: " + path3);
|
|
25063
25365
|
}
|
|
25064
25366
|
}
|
|
25065
|
-
async function
|
|
25066
|
-
const full = await
|
|
25367
|
+
async function managedWrite(root, path3, previous, next, recheck) {
|
|
25368
|
+
const full = await managedPath(root, path3, true);
|
|
25067
25369
|
const directory = dirname2(full);
|
|
25068
25370
|
const owner = await fileInfo(directory);
|
|
25069
25371
|
const canonical = await realpath2(directory);
|
|
25070
25372
|
const unchanged = async () => {
|
|
25071
|
-
await
|
|
25373
|
+
await managedPath(root, path3);
|
|
25072
25374
|
const now = await fileInfo(directory);
|
|
25073
|
-
if (now?.ino !== owner?.ino || now?.dev !== owner?.dev || await realpath2(directory) !== canonical) throw new InitError("INPUT_CHANGED", "\
|
|
25375
|
+
if (now?.ino !== owner?.ino || now?.dev !== owner?.dev || await realpath2(directory) !== canonical) throw new InitError("INPUT_CHANGED", "\uB300\uC0C1 \uACBD\uB85C\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25074
25376
|
};
|
|
25075
25377
|
if (next === null) {
|
|
25076
25378
|
await recheck();
|
|
25077
25379
|
await unchanged();
|
|
25078
|
-
if (await
|
|
25380
|
+
if (await managedRead(root, path3) !== previous) throw new InitError("INPUT_CHANGED", "\uC81C\uAC70 \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25079
25381
|
if (previous !== null) await unlink3(full);
|
|
25080
25382
|
return;
|
|
25081
25383
|
}
|
|
25082
|
-
const temp = join6(directory, ".gitifact-
|
|
25384
|
+
const temp = join6(directory, ".gitifact-managed-" + randomUUID5() + ".tmp");
|
|
25083
25385
|
const handle = await open3(temp, "wx", 384);
|
|
25084
25386
|
const tempOwner = await handle.stat();
|
|
25085
25387
|
try {
|
|
@@ -25091,7 +25393,7 @@ async function skillWrite(root, path3, previous, next, recheck) {
|
|
|
25091
25393
|
}
|
|
25092
25394
|
await recheck();
|
|
25093
25395
|
await unchanged();
|
|
25094
|
-
if (await
|
|
25396
|
+
if (await managedRead(root, path3) !== previous || await readFile6(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", "\uAC8C\uC2DC \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25095
25397
|
if (previous === null) await link2(temp, full);
|
|
25096
25398
|
else await rename2(temp, full);
|
|
25097
25399
|
} finally {
|
|
@@ -25100,163 +25402,292 @@ async function skillWrite(root, path3, previous, next, recheck) {
|
|
|
25100
25402
|
if (now?.ino === tempOwner.ino && now.dev === tempOwner.dev) await unlink3(temp);
|
|
25101
25403
|
}
|
|
25102
25404
|
}
|
|
25103
|
-
|
|
25104
|
-
|
|
25105
|
-
|
|
25106
|
-
|
|
25107
|
-
|
|
25108
|
-
|
|
25109
|
-
|
|
25110
|
-
|
|
25111
|
-
|
|
25112
|
-
|
|
25113
|
-
|
|
25114
|
-
|
|
25115
|
-
|
|
25116
|
-
|
|
25405
|
+
|
|
25406
|
+
// src/commands/docs.ts
|
|
25407
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
25408
|
+
var docTopics = ["workflow", "spec", "design", "product", "commit"];
|
|
25409
|
+
var summaries = {
|
|
25410
|
+
workflow: "\uC2DC\uC791 \uC2DC \uD655\uC778\uD560 \uAC83, \uC694\uAD6C\uC0AC\uD56D\uC73C\uB85C \uB0A8\uAE38 \uC694\uCCAD\uC758 \uAD6C\uBD84, \uB9C8\uBB34\uB9AC \uBCF4\uACE0",
|
|
25411
|
+
spec: "\uC0AC\uC6A9\uC790 \uC2A4\uD1A0\uB9AC\xB7\uC218\uC6A9 \uC870\uAC74 \uD615\uC2DD, ID \uADDC\uCE59, spec save \uC785\uB825",
|
|
25412
|
+
design: "design.md \uBAA9\uCC28, \uCC38\uC870 \uC8FC\uC11D, \uAC1C\uC815 \uBC29\uC2DD",
|
|
25413
|
+
product: "PRODUCT.md\uC640 guides \uBB38\uC11C\uC758 \uC5ED\uD560\uACFC \uC800\uC7A5 \uBA85\uB839",
|
|
25414
|
+
commit: "spec commit \uC785\uB825, \uC774\uC720 \uAE30\uB85D, \uC2E4\uD328 \uD6C4 \uBCF5\uAD6C"
|
|
25415
|
+
};
|
|
25416
|
+
var isDocTopic = (value) => docTopics.includes(value);
|
|
25417
|
+
var readBundled = (topic) => readFile7(new URL("./docs/" + topic + ".md", import.meta.url), "utf8");
|
|
25418
|
+
function listDocTopics() {
|
|
25419
|
+
const width = Math.max(...docTopics.map((topic) => topic.length));
|
|
25420
|
+
return docTopics.map((topic) => topic.padEnd(width) + " " + summaries[topic]).join("\n") + "\n";
|
|
25421
|
+
}
|
|
25422
|
+
async function runDocs(topic, controls = {}) {
|
|
25423
|
+
if (topic === void 0) {
|
|
25424
|
+
process.stdout.write(listDocTopics());
|
|
25425
|
+
return;
|
|
25117
25426
|
}
|
|
25427
|
+
if (!isDocTopic(topic)) {
|
|
25428
|
+
const failure2 = { contract: "docs", version: 1, ok: false, error: { code: "UNKNOWN_TOPIC", message: "\uC54C \uC218 \uC5C6\uB294 \uC8FC\uC81C\uC785\uB2C8\uB2E4: " + topic + ". \uC0AC\uC6A9 \uAC00\uB2A5: " + docTopics.join(", ") } };
|
|
25429
|
+
process.stderr.write(JSON.stringify(failure2) + "\n");
|
|
25430
|
+
process.exitCode = 1;
|
|
25431
|
+
return;
|
|
25432
|
+
}
|
|
25433
|
+
process.stdout.write(await (controls.readDoc ?? readBundled)(topic));
|
|
25118
25434
|
}
|
|
25119
25435
|
|
|
25120
|
-
// src/commands/
|
|
25121
|
-
var
|
|
25122
|
-
var
|
|
25123
|
-
var
|
|
25124
|
-
var
|
|
25125
|
-
var
|
|
25126
|
-
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
|
|
25130
|
-
|
|
25131
|
-
|
|
25132
|
-
|
|
25133
|
-
|
|
25134
|
-
|
|
25135
|
-
|
|
25136
|
-
|
|
25436
|
+
// src/commands/agent-block.ts
|
|
25437
|
+
var AGENT_START = "<!-- GITIFACT:START -->";
|
|
25438
|
+
var AGENT_END = "<!-- GITIFACT:END -->";
|
|
25439
|
+
var candidatePaths = ["AGENTS.md", "CLAUDE.md", ".claude/CLAUDE.md", ".cursorrules", ".hermes.md", "HERMES.md"];
|
|
25440
|
+
var agentPresetNames = ["claude", "cursor", "codex", "hermes", "all"];
|
|
25441
|
+
var agentPresets = {
|
|
25442
|
+
claude: ["CLAUDE.md", ".claude/CLAUDE.md"],
|
|
25443
|
+
cursor: [".cursorrules", "AGENTS.md"],
|
|
25444
|
+
codex: ["AGENTS.md"],
|
|
25445
|
+
hermes: [".hermes.md", "HERMES.md", "AGENTS.md"]
|
|
25446
|
+
};
|
|
25447
|
+
function boilerplateFor(path3) {
|
|
25448
|
+
const name = path3 === "AGENTS.md" ? path3 : path3.split("/").pop().replace(/^\./, "").replace(/\.md$/, "");
|
|
25449
|
+
return "# " + name + "\n\nProject-specific guidance for AI coding agents.\n";
|
|
25450
|
+
}
|
|
25451
|
+
function renderAgentBlock(version2) {
|
|
25452
|
+
const lines = [
|
|
25453
|
+
AGENT_START,
|
|
25454
|
+
"gitifact v" + version2 + " \xB7 \uC800\uC7A5 \uADDC\uC57D schemaVersion 1",
|
|
25455
|
+
"CLI: \uBAA8\uB4E0 \uBA85\uB839\uC740 `gitifact <cmd>`\uB85C \uC2E4\uD589\uD55C\uB2E4. \uD504\uB85C\uC81D\uD2B8 \uC9C0\uCE68\uC774 \uB2E4\uB978 \uC2E4\uD589 \uBC29\uBC95\uC744 \uC9C0\uC815\uD558\uBA74 \uADF8\uAC83\uC744 \uB530\uB978\uB2E4.",
|
|
25456
|
+
"",
|
|
25457
|
+
"\uC2DC\uC791\uD560 \uB54C:",
|
|
25458
|
+
"- `gitifact spec working`\uC73C\uB85C \uC81C\uD488 \uC124\uBA85\xB7\uC9C0\uCE68\xB7\uAE30\uB2A5 \uBA85\uC138\uB97C \uC77D\uACE0 git status\uC640 \uAE30\uC874 staging\uC744 \uD655\uC778\uD55C\uB2E4.",
|
|
25459
|
+
"- \uC774 \uBE14\uB85D\uC740 \uC694\uC57D\uC774\uB2E4. \uC0C1\uC138 \uD615\uC2DD\uC740 `gitifact docs <topic>`\uC73C\uB85C \uC77D\uACE0 \uAE30\uC5B5\uC73C\uB85C \uCC44\uC6B0\uC9C0 \uC54A\uB294\uB2E4.",
|
|
25460
|
+
"",
|
|
25461
|
+
"\uBB34\uC5C7\uC744 \uC694\uAD6C\uC0AC\uD56D\uC73C\uB85C \uB0A8\uAE30\uB294\uAC00 (\uC81C\uD488 \uB3D9\uC791\uACFC \uC720\uC9C0\uD560 \uC81C\uC57D\uB9CC):",
|
|
25462
|
+
"| \uC694\uCCAD | \uCC98\uB9AC |",
|
|
25463
|
+
"| --- | --- |",
|
|
25464
|
+
"| \uAC8C\uC2DC\uBB3C\uC744 \uC0AD\uC81C\uD560 \uC218 \uC788\uAC8C \uD574\uC8FC\uC138\uC694 | \uC694\uAD6C\uC0AC\uD56D\uC73C\uB85C \uC815\uB9AC\uD55C\uB2E4 |",
|
|
25465
|
+
"| \uC774 \uB0B4\uBD80 \uD568\uC218 \uC774\uB984\uC744 \uBC14\uAFD4\uC8FC\uC138\uC694 | \uC77C\uBC18 \uAD6C\uD604 \uBCC0\uACBD\uC774\uB2E4 |",
|
|
25466
|
+
"| \uC9C0\uAE08 \uD478\uC2DC\uD574\uC8FC\uC138\uC694 | \uC791\uC5C5 \uC9C0\uC2DC\uB2E4. \uB4F1\uB85D\uD558\uC9C0 \uC54A\uB294\uB2E4 |",
|
|
25467
|
+
"| \uC678\uBD80 \uC11C\uBE44\uC2A4 \uC5C6\uC774 \uB3D9\uC791\uD574\uC57C \uD569\uB2C8\uB2E4 | \uC81C\uD488 \uC81C\uC57D\uC73C\uB85C \uBA85\uC138\uC5D0 \uBC18\uC601\uD55C\uB2E4 |",
|
|
25468
|
+
"",
|
|
25469
|
+
"\uADDC\uCE59:",
|
|
25470
|
+
"- \uBA85\uC138\uB97C \uC800\uC7A5\uD558\uAE30 \uC804\uC5D0 `gitifact docs spec`\uC744 \uC77D\uB294\uB2E4. ID\uB294 CLI\uAC00 \uBC1C\uAE09\uD55C \uAC12\uB9CC \uC4F4\uB2E4.",
|
|
25471
|
+
"- \uC0C8 \uAE30\uB2A5\uC740 requirements.md\uC640 design.md\uB97C \uD568\uAED8 \uC815\uB9AC\uD55C\uB2E4(`gitifact docs design`). \uC694\uAD6C\uC0AC\uD56D\uB9CC \uC694\uCCAD\uBC1B\uC73C\uBA74 \uB530\uB978\uB2E4.",
|
|
25472
|
+
"- \uCEE4\uBC0B \uC694\uCCAD\uC744 \uBC1B\uC73C\uBA74 `gitifact docs commit`\uC744 \uC77D\uACE0 \uBA85\uC138\xB7\uC774\uC720\xB7\uCF54\uB4DC\xB7\uD14C\uC2A4\uD2B8\uB97C \uD568\uAED8 \uCEE4\uBC0B\uD55C\uB2E4.",
|
|
25473
|
+
"- \uC790\uB3D9 \uAE30\uB85D\uC740 \uCEE4\uBC0B \uAD8C\uD55C\uC774 \uC544\uB2C8\uB2E4. \uC0AC\uC6A9\uC790 \uC694\uCCAD\uC774\uB098 \uBA85\uC2DC\uC801 \uD504\uB85C\uC81D\uD2B8 \uC815\uCC45\uC774 \uC788\uC744 \uB54C\uB9CC \uCEE4\uBC0B\uD558\uACE0 \uD478\uC2DC\uB294 \uBCC4\uB3C4 \uC694\uCCAD\uC744 \uB530\uB978\uB2E4.",
|
|
25474
|
+
"- \uBD88\uBA85\uD655\uD55C \uC81C\uD488 \uB3D9\uC791\uB9CC \uC9C8\uBB38\uD558\uACE0 \uB3C5\uB9BD\uC801\uC778 \uC791\uC5C5\uC740 \uC9C4\uD589\uD55C\uB2E4. \uAE30\uC874 \uAE30\uB2A5 \uC804\uCCB4 \uB3C4\uCD9C\uC740 \uC694\uCCAD\uBC1B\uC558\uC744 \uB54C \uD55C\uB2E4.",
|
|
25475
|
+
"- SELF-CHECK: save\xB7commit \uC785\uB825\uC744 \uB9CC\uB4E4\uAE30 \uC804\uC5D0 \uD574\uB2F9 docs\uB97C \uB2E4\uC2DC \uC77D\uACE0 \uD615\uC2DD\uC744 \uB300\uC870\uD55C\uB2E4. \uD655\uC2E4\uD558\uC9C0 \uC54A\uC73C\uBA74 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 `gitifact docs <topic>`\uC744 \uC2E4\uD589\uD55C\uB2E4.",
|
|
25476
|
+
"",
|
|
25477
|
+
"MORE CLI:",
|
|
25478
|
+
" docs <topic> " + docTopics.join(", "),
|
|
25479
|
+
" spec working \uD604\uC7AC \uBA85\uC138\xB7\uC81C\uD488\xB7\uC9C0\uCE68 \uC804\uCCB4\uC640 stamp",
|
|
25480
|
+
" spec save --file <json>: \uC694\uAD6C\uC0AC\uD56D\xB7\uC124\uACC4\xB7\uBB38\uC11C \uC800\uC7A5",
|
|
25481
|
+
" spec commit --file <json>: \uBCC0\uACBD \uC774\uC720 \uAE30\uB85D\uACFC \uCEE4\uBC0B\uC744 \uD55C \uBC88\uC5D0",
|
|
25482
|
+
" browser \uC77D\uAE30 \uC804\uC6A9 \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30",
|
|
25483
|
+
" init \uB2E4\uC2DC \uC2E4\uD589\uD558\uBA74 \uC774 \uBE14\uB85D\uC744 \uAC31\uC2E0\uD55C\uB2E4",
|
|
25484
|
+
AGENT_END
|
|
25485
|
+
];
|
|
25486
|
+
return lines.join("\n");
|
|
25487
|
+
}
|
|
25488
|
+
function findBlock(text2) {
|
|
25489
|
+
const start = text2.indexOf(AGENT_START);
|
|
25490
|
+
if (start === -1) {
|
|
25491
|
+
if (text2.includes(AGENT_END)) throw new InitError("AGENT_DOCS_MALFORMED", "\uC2DC\uC791 \uB9C8\uCEE4 \uC5C6\uC774 \uC885\uB8CC \uB9C8\uCEE4\uB9CC \uC788\uC2B5\uB2C8\uB2E4. \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
|
|
25492
|
+
return null;
|
|
25137
25493
|
}
|
|
25138
|
-
|
|
25494
|
+
const end = text2.indexOf(AGENT_END, start + AGENT_START.length);
|
|
25495
|
+
if (end === -1) throw new InitError("AGENT_DOCS_MALFORMED", "\uC885\uB8CC \uB9C8\uCEE4\uAC00 \uC5C6\uB294 GITIFACT \uBE14\uB85D\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
|
|
25496
|
+
if (text2.indexOf(AGENT_START, start + AGENT_START.length) !== -1) throw new InitError("AGENT_DOCS_MALFORMED", "GITIFACT \uC2DC\uC791 \uB9C8\uCEE4\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4. \uC911\uBCF5 \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
|
|
25497
|
+
return { start, end: end + AGENT_END.length };
|
|
25498
|
+
}
|
|
25499
|
+
function isWrapperFile(text2) {
|
|
25500
|
+
const found = findBlock(text2);
|
|
25501
|
+
const own2 = found ? text2.slice(0, found.start) + text2.slice(found.end) : text2;
|
|
25502
|
+
const lines = own2.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
25503
|
+
return lines.length > 0 && lines.every((line) => /^@(?:\.\/)?[^\s]+$/.test(line) && candidatePaths.includes(line.replace(/^@(?:\.\/)?/, "")));
|
|
25504
|
+
}
|
|
25505
|
+
function resolveAgentPaths(preset, existing) {
|
|
25506
|
+
if (preset && preset !== "all") {
|
|
25507
|
+
const order = agentPresets[preset];
|
|
25508
|
+
const found = order.find((path3) => existing.has(path3));
|
|
25509
|
+
return found ? { inject: [found], create: null } : { inject: [], create: order[order.length - 1] };
|
|
25510
|
+
}
|
|
25511
|
+
const inject = candidatePaths.filter((path3) => existing.has(path3) && !isWrapperFile(existing.get(path3)));
|
|
25512
|
+
if (inject.length > 0) return { inject, create: null };
|
|
25513
|
+
return { inject: [], create: "AGENTS.md" };
|
|
25514
|
+
}
|
|
25515
|
+
var eolOf = (text2) => text2?.includes("\r\n") ? "\r\n" : "\n";
|
|
25516
|
+
function injectBlock(text2, block, boilerplate) {
|
|
25517
|
+
const eol = eolOf(text2);
|
|
25518
|
+
const body = block.split("\n").join(eol);
|
|
25519
|
+
if (text2 === null) return boilerplate.split("\n").join(eol) + eol + body + eol;
|
|
25520
|
+
const found = findBlock(text2);
|
|
25521
|
+
if (found) return text2.slice(0, found.start) + body + text2.slice(found.end);
|
|
25522
|
+
const head = text2.replace(/\s+$/, "");
|
|
25523
|
+
return (head ? head + eol + eol : "") + body + eol;
|
|
25524
|
+
}
|
|
25525
|
+
function removeBlock(text2, boilerplate) {
|
|
25526
|
+
const found = findBlock(text2);
|
|
25527
|
+
if (!found) return text2;
|
|
25528
|
+
const eol = eolOf(text2);
|
|
25529
|
+
const before = text2.slice(0, found.start).replace(/\s+$/, "");
|
|
25530
|
+
const after = text2.slice(found.end).replace(/^\s+/, "");
|
|
25531
|
+
const rest = before && after ? before + eol + eol + after : before ? before + eol : after;
|
|
25532
|
+
const normalize = (value) => value.replace(/\r\n/g, "\n").trim();
|
|
25533
|
+
if (!normalize(rest) || normalize(rest) === normalize(boilerplate)) return null;
|
|
25534
|
+
return rest;
|
|
25139
25535
|
}
|
|
25140
|
-
|
|
25536
|
+
|
|
25537
|
+
// src/commands/agent-docs.ts
|
|
25538
|
+
var skippedAgentDocs = { mode: "skip", paths: [], writes: [] };
|
|
25539
|
+
async function planAgentDocs(root, options) {
|
|
25540
|
+
if (options.skip) return skippedAgentDocs;
|
|
25541
|
+
const existing = /* @__PURE__ */ new Map();
|
|
25542
|
+
for (const path3 of candidatePaths) {
|
|
25543
|
+
const text2 = await managedRead(root, path3);
|
|
25544
|
+
if (text2 !== null) existing.set(path3, text2);
|
|
25545
|
+
}
|
|
25546
|
+
const writes = [];
|
|
25547
|
+
const paths2 = [];
|
|
25548
|
+
if (options.remove) {
|
|
25549
|
+
const scope = options.agent && options.agent !== "all" ? agentPresets[options.agent] : candidatePaths;
|
|
25550
|
+
for (const path3 of scope) {
|
|
25551
|
+
const text2 = existing.get(path3);
|
|
25552
|
+
if (text2 === void 0 || !findBlock(text2)) continue;
|
|
25553
|
+
paths2.push(path3);
|
|
25554
|
+
writes.push({ path: path3, previous: text2, next: removeBlock(text2, boilerplateFor(path3)) });
|
|
25555
|
+
}
|
|
25556
|
+
return { mode: "remove", paths: paths2, writes };
|
|
25557
|
+
}
|
|
25558
|
+
const block = renderAgentBlock(options.version);
|
|
25559
|
+
const { inject, create } = resolveAgentPaths(options.agent, existing);
|
|
25560
|
+
for (const path3 of inject) {
|
|
25561
|
+
const previous = existing.get(path3);
|
|
25562
|
+
const next = injectBlock(previous, block, boilerplateFor(path3));
|
|
25563
|
+
paths2.push(path3);
|
|
25564
|
+
if (next !== previous) writes.push({ path: path3, previous, next });
|
|
25565
|
+
}
|
|
25566
|
+
if (create) {
|
|
25567
|
+
paths2.push(create);
|
|
25568
|
+
writes.push({ path: create, previous: null, next: injectBlock(null, block, boilerplateFor(create)) });
|
|
25569
|
+
}
|
|
25570
|
+
for (const [path3, text2] of existing) {
|
|
25571
|
+
if (paths2.includes(path3) || !isWrapperFile(text2) || !findBlock(text2)) continue;
|
|
25572
|
+
writes.push({ path: path3, previous: text2, next: removeBlock(text2, boilerplateFor(path3)) });
|
|
25573
|
+
}
|
|
25574
|
+
return { mode: "install", paths: paths2, writes };
|
|
25575
|
+
}
|
|
25576
|
+
async function applyAgentDocs(root, plan, recheck) {
|
|
25577
|
+
for (const write of plan.writes) await managedWrite(root, write.path, write.previous, write.next, recheck);
|
|
25578
|
+
return plan.writes.map((write) => write.path);
|
|
25579
|
+
}
|
|
25580
|
+
|
|
25581
|
+
// src/commands/spec-init.ts
|
|
25582
|
+
async function initializeSpecProject(cwd, dryRun = false, env = process.env, beforePublish, agentDocs) {
|
|
25141
25583
|
const repo = initRepository(cwd, env);
|
|
25142
25584
|
const first = await repo.inspect();
|
|
25143
25585
|
const root = first.state.repository.rootPath;
|
|
25144
|
-
const
|
|
25145
|
-
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25149
|
-
|
|
25150
|
-
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
|
|
25154
|
-
|
|
25155
|
-
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
|
|
25162
|
-
|
|
25163
|
-
|
|
25164
|
-
if (
|
|
25165
|
-
|
|
25166
|
-
|
|
25167
|
-
|
|
25168
|
-
|
|
25169
|
-
|
|
25170
|
-
|
|
25171
|
-
|
|
25172
|
-
const
|
|
25173
|
-
|
|
25174
|
-
|
|
25175
|
-
version: 1,
|
|
25176
|
-
ok: true,
|
|
25177
|
-
outcome,
|
|
25178
|
-
rootPath: root,
|
|
25179
|
-
agent: agent ?? null,
|
|
25180
|
-
source,
|
|
25181
|
-
target: agent === "claude" ? target : null,
|
|
25182
|
-
sourcePreserved: original !== null,
|
|
25183
|
-
sessionState: "not-observed"
|
|
25586
|
+
const docsPlan = agentDocs ? await planAgentDocs(root, agentDocs) : skippedAgentDocs;
|
|
25587
|
+
const result = (config3, outcome) => projectInitV4.parse({
|
|
25588
|
+
contract: "project-init",
|
|
25589
|
+
version: 4,
|
|
25590
|
+
ok: true,
|
|
25591
|
+
outcome,
|
|
25592
|
+
rootPath: root,
|
|
25593
|
+
configPath: ".gitifact/config.json",
|
|
25594
|
+
schemaVersion: config3.schemaVersion,
|
|
25595
|
+
baseline: config3.baseline,
|
|
25596
|
+
agentDocs: { mode: docsPlan.mode, paths: docsPlan.paths }
|
|
25597
|
+
});
|
|
25598
|
+
const existing = async (text3) => {
|
|
25599
|
+
const config3 = parseManagedConfig(text3);
|
|
25600
|
+
if (!("schemaVersion" in config3)) throw new InitError("MIGRATION_REQUIRED", "\uAE30\uC874 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC124\uC815\uACFC \uAE30\uB85D\uC744 \uBCF4\uC874\uD558\uC138\uC694.");
|
|
25601
|
+
await repo.validateBaseline(config3, root, first.state.head.commit, first.state.repository.objectFormat);
|
|
25602
|
+
const unchanged = async () => {
|
|
25603
|
+
if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text3) throw new InitError("INPUT_CHANGED", "\uCD08\uAE30\uD654 \uC870\uD68C \uC911 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25604
|
+
};
|
|
25605
|
+
await unchanged();
|
|
25606
|
+
if (!dryRun) await applyAgentDocs(root, docsPlan, unchanged);
|
|
25607
|
+
return result(config3, "already-initialized");
|
|
25608
|
+
};
|
|
25609
|
+
const old = await readConfigFile(root);
|
|
25610
|
+
if (old !== void 0) return existing(old);
|
|
25611
|
+
if (first.trackedConfig) throw new InitError("CONFIG_DELETED", "\uAE30\uC874 \uC124\uC815\uC758 \uC0AD\uC81C\uB97C \uC2E0\uADDC \uB3C4\uC785\uC73C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
25612
|
+
const checkRecords = async () => {
|
|
25613
|
+
if (await fileInfo(join7(root, "specs"))) throw new InitError("EXISTING_RECORDS", "\uAE30\uC874 specs \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.");
|
|
25614
|
+
const entries = await readdir3(join7(root, ".gitifact")).catch((e) => {
|
|
25615
|
+
if (e.code === "ENOENT") return [];
|
|
25616
|
+
throw e;
|
|
25184
25617
|
});
|
|
25185
|
-
if (
|
|
25186
|
-
|
|
25187
|
-
|
|
25188
|
-
|
|
25189
|
-
|
|
25190
|
-
|
|
25191
|
-
|
|
25192
|
-
|
|
25193
|
-
|
|
25194
|
-
|
|
25195
|
-
|
|
25196
|
-
|
|
25197
|
-
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25202
|
-
|
|
25203
|
-
if (!ignored) throw new InitError("LOCAL_SKILL_NOT_IGNORED", "\uB85C\uCEEC \uACBD\uB85C\uAC00 ignore\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25618
|
+
if (entries.some((name) => !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) throw new InitError("EXISTING_RECORDS", "\uC124\uC815 \uC5C6\uB294 .gitifact \uC790\uB8CC\uB97C \uC790\uB3D9 \uCC44\uD0DD\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
25619
|
+
};
|
|
25620
|
+
const config2 = { schemaVersion: 1, baseline: first.state.head.commit ? { kind: "commit", objectFormat: first.state.repository.objectFormat, commit: first.state.head.commit } : { kind: "empty" } };
|
|
25621
|
+
const text2 = JSON.stringify(config2, null, 2) + "\n";
|
|
25622
|
+
const recheck = async () => {
|
|
25623
|
+
await checkRecords();
|
|
25624
|
+
await repo.checkIgnore(root);
|
|
25625
|
+
if ((await repo.inspect()).stamp !== first.stamp) throw new InitError("INPUT_CHANGED", "HEAD \uB610\uB294 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25626
|
+
if (await readConfigFile(root) !== void 0) throw new InitError("CONFIG_APPEARED", "\uB2E4\uB978 \uC2E4\uD589\uC774 \uC124\uC815\uC744 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
25627
|
+
};
|
|
25628
|
+
await recheck();
|
|
25629
|
+
if (dryRun) return result(config2, "planned");
|
|
25630
|
+
try {
|
|
25631
|
+
await publishConfig(root, text2, recheck, beforePublish);
|
|
25632
|
+
} catch (error62) {
|
|
25633
|
+
if (error62.code === "EEXIST" || error62 instanceof InitError && error62.code === "CONFIG_APPEARED") {
|
|
25634
|
+
const concurrent = await readConfigFile(root);
|
|
25635
|
+
if (concurrent !== void 0) return existing(concurrent);
|
|
25204
25636
|
}
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
|
|
25209
|
-
if (await skillRead(root, source) !== original || await skillRead(root, target) !== copy) throw new InitError("INPUT_CHANGED", "\uC2A4\uD0AC \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25210
|
-
};
|
|
25211
|
-
await skillWrite(root, manifest, saved, journal, inputs);
|
|
25212
|
-
await controls.afterJournal?.();
|
|
25213
|
-
if (original === null && wanted !== null) await skillWrite(root, source, null, wanted, recheck);
|
|
25214
|
-
if (copy !== nextCopy) await skillWrite(root, target, copy, nextCopy, recheck);
|
|
25215
|
-
await skillWrite(root, manifest, journal, stateText([digest2(nextCopy)]), recheck);
|
|
25216
|
-
await recheck();
|
|
25217
|
-
if (await skillRead(root, source) !== wanted || await skillRead(root, target) !== nextCopy) throw new InitError("INPUT_CHANGED", "\uAC8C\uC2DC \uD6C4 \uC2A4\uD0AC\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.");
|
|
25218
|
-
return result(action === "remove" ? "removed" : action === "install" ? "installed" : "synced");
|
|
25637
|
+
throw error62;
|
|
25638
|
+
}
|
|
25639
|
+
const published = async () => {
|
|
25640
|
+
if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text2) throw new InitError("INPUT_CHANGED_AFTER_WRITE", "\uC124\uC815 \uC0DD\uC131 \uD6C4 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.");
|
|
25219
25641
|
};
|
|
25220
|
-
|
|
25642
|
+
await published();
|
|
25643
|
+
await applyAgentDocs(root, docsPlan, published);
|
|
25644
|
+
return result(config2, "created");
|
|
25221
25645
|
}
|
|
25222
|
-
|
|
25646
|
+
|
|
25647
|
+
// src/commands/init.ts
|
|
25648
|
+
async function runInit(options, version2) {
|
|
25223
25649
|
try {
|
|
25224
|
-
const
|
|
25225
|
-
|
|
25226
|
-
|
|
25227
|
-
|
|
25228
|
-
|
|
25650
|
+
const dto = await initializeSpecProject(
|
|
25651
|
+
process.cwd(),
|
|
25652
|
+
options.dryRun,
|
|
25653
|
+
process.env,
|
|
25654
|
+
void 0,
|
|
25655
|
+
{ version: version2, agent: options.agent, remove: options.removeAgents, skip: options.skipAgents }
|
|
25656
|
+
);
|
|
25657
|
+
if (!dto.ok) throw new Error("unreachable");
|
|
25658
|
+
const docs = dto.agentDocs.mode === "skip" ? "\uAC74\uB108\uB700" : dto.agentDocs.paths.join(", ") + (dto.agentDocs.mode === "remove" ? " (\uBE14\uB85D \uC81C\uAC70)" : dto.outcome === "planned" ? " (\uBE14\uB85D \uC124\uCE58 \uC608\uC815)" : " (\uBE14\uB85D \uAC31\uC2E0)");
|
|
25659
|
+
process.stdout.write(options.format === "text" ? `${dto.outcome}: ${dto.rootPath}/.gitifact/config.json
|
|
25660
|
+
\uC800\uC7A5 \uADDC\uC57D: schemaVersion 1
|
|
25661
|
+
\uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68: ${docs}
|
|
25662
|
+
` : JSON.stringify(dto) + "\n");
|
|
25229
25663
|
} catch (error62) {
|
|
25230
|
-
const
|
|
25231
|
-
|
|
25232
|
-
|
|
25233
|
-
} });
|
|
25234
|
-
console.error(JSON.stringify(failure2));
|
|
25664
|
+
const known = error62 instanceof InitError || error62 instanceof RepositoryReadError;
|
|
25665
|
+
const failure2 = { code: known ? error62.code : "INIT_FAILED", message: known ? error62.message : "\uCD08\uAE30\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uD30C\uC77C \uC811\uADFC \uAD8C\uD55C\uACFC \uC0DD\uC131\uB41C \uC124\uC815\xB7\uC784\uC2DC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694." };
|
|
25666
|
+
process.stderr.write(options.format === "text" ? failure2.code + ": " + failure2.message + "\n" : JSON.stringify(projectInitV4.parse({ contract: "project-init", version: 4, ok: false, error: failure2 })) + "\n");
|
|
25235
25667
|
process.exitCode = 1;
|
|
25236
25668
|
}
|
|
25237
25669
|
}
|
|
25238
25670
|
|
|
25239
25671
|
// src/commands/spec-preview.ts
|
|
25240
|
-
import { join as
|
|
25241
|
-
import { readFile as
|
|
25672
|
+
import { join as join12 } from "node:path";
|
|
25673
|
+
import { readFile as readFile11, stat as stat2 } from "node:fs/promises";
|
|
25242
25674
|
|
|
25243
25675
|
// src/adapters/filesystem/spec-preview-prepare.ts
|
|
25244
|
-
import { lstat as
|
|
25245
|
-
import { join as
|
|
25246
|
-
import { createHash as
|
|
25676
|
+
import { lstat as lstat4 } from "node:fs/promises";
|
|
25677
|
+
import { join as join8 } from "node:path";
|
|
25678
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
25247
25679
|
var fail5 = (message) => {
|
|
25248
25680
|
throw new SpecPreviewError(message);
|
|
25249
25681
|
};
|
|
25250
25682
|
var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
25251
|
-
var expected = (base, stamp) =>
|
|
25683
|
+
var expected = (base, stamp) => createHash4("sha256").update(JSON.stringify({ base, stamp })).digest("hex");
|
|
25252
25684
|
var previewExpected = expected;
|
|
25253
|
-
var parseFiles = parsePreviewFiles;
|
|
25254
25685
|
async function readPreviewContext(cwd) {
|
|
25255
25686
|
const reader = specPreviewReader(cwd);
|
|
25256
25687
|
const { gitDir } = await reader.location();
|
|
25257
25688
|
const checkOperation = async () => {
|
|
25258
25689
|
for (const name of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"]) {
|
|
25259
|
-
const exists = await
|
|
25690
|
+
const exists = await lstat4(join8(gitDir, name)).catch((e) => {
|
|
25260
25691
|
if (e.code === "ENOENT") return void 0;
|
|
25261
25692
|
throw e;
|
|
25262
25693
|
});
|
|
@@ -25267,20 +25698,21 @@ async function readPreviewContext(cwd) {
|
|
|
25267
25698
|
const base = await reader.baseline();
|
|
25268
25699
|
const working = await readWorkingPreviewState(cwd);
|
|
25269
25700
|
const files = base.head ? await reader.files(base.head, working.config !== void 0) : /* @__PURE__ */ new Map();
|
|
25270
|
-
const
|
|
25701
|
+
const bundle = parsePreviewBundle(files);
|
|
25702
|
+
const specs = bundle.specs;
|
|
25271
25703
|
const recheck = async () => {
|
|
25272
25704
|
await checkOperation();
|
|
25273
25705
|
if (!same(base, await reader.baseline())) fail5("HEAD \uB610\uB294 \uBE0C\uB79C\uCE58\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.");
|
|
25274
25706
|
};
|
|
25275
|
-
return { reader, base, files, specs, recheck, working };
|
|
25707
|
+
return { reader, base, files, specs, bundle, recheck, working };
|
|
25276
25708
|
}
|
|
25277
25709
|
var context = readPreviewContext;
|
|
25278
25710
|
async function readFinalPreviewChanges(cwd) {
|
|
25279
25711
|
const c = await context(cwd);
|
|
25280
25712
|
const current = await readWorkingPreviewState(cwd);
|
|
25281
|
-
const delta = finalSpecPreviewChanges(c.
|
|
25713
|
+
const delta = finalSpecPreviewChanges(c.bundle, current.bundle);
|
|
25282
25714
|
await c.recheck();
|
|
25283
|
-
const pendingReasons =
|
|
25715
|
+
const pendingReasons = pendingPreviewReasons(c.bundle, current.bundle);
|
|
25284
25716
|
return { base: c.base, expected: expected(c.base, current.stamp), stamp: current.stamp, pendingReasons, ...delta };
|
|
25285
25717
|
}
|
|
25286
25718
|
async function prepareWorkingPreview(cwd, input2, publish) {
|
|
@@ -25292,7 +25724,7 @@ async function prepareWorkingPreview(cwd, input2, publish) {
|
|
|
25292
25724
|
if (request.expected !== expected(c.base, current.stamp)) fail5("\uC900\uBE44 \uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.");
|
|
25293
25725
|
const result = await previewTransaction(cwd, current.stamp, async (before) => {
|
|
25294
25726
|
await c.recheck();
|
|
25295
|
-
const prepared = prepareSpecPreview(c.
|
|
25727
|
+
const prepared = prepareSpecPreview(c.bundle, before.bundle, c.files, before.files, request.reasons, () => generatePreviewId("H"));
|
|
25296
25728
|
return { writes: prepared.writes, data: { changes: prepared.changes, specChanges: prepared.specChanges, reasons: prepared.reasons, withoutReason: prepared.withoutReason }, recheck: c.recheck };
|
|
25297
25729
|
}, publish);
|
|
25298
25730
|
return { ...result, base: c.base, expected: expected(c.base, result.stamp), verification: { base: c.base, stamp: result.stamp } };
|
|
@@ -25304,15 +25736,15 @@ async function verifyPreparedPreview(cwd, input2, staged) {
|
|
|
25304
25736
|
const c = await context(cwd);
|
|
25305
25737
|
const current = await readWorkingPreviewState(cwd);
|
|
25306
25738
|
if (!same(request.base, c.base) || request.stamp !== current.stamp) fail5("\uC900\uBE44 \uB4A4 HEAD \uB610\uB294 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC900\uBE44\uD558\uC138\uC694.");
|
|
25307
|
-
finalSpecPreviewChanges(c.
|
|
25308
|
-
|
|
25739
|
+
finalSpecPreviewChanges(c.bundle, current.bundle);
|
|
25740
|
+
comparePreviewBundles(c.bundle, current.bundle);
|
|
25309
25741
|
if (staged) {
|
|
25310
25742
|
const index = await c.reader.index();
|
|
25311
25743
|
if (index.size !== current.files.size) fail5("staging\uC758 \uBA85\uC138 \uBC94\uC704\uAC00 \uC900\uBE44\uD55C \uC6D0\uBB38\uACFC \uB2E4\uB985\uB2C8\uB2E4.");
|
|
25312
|
-
for (const [path3,
|
|
25744
|
+
for (const [path3, source] of current.files) {
|
|
25313
25745
|
const oid2 = index.get(path3);
|
|
25314
|
-
const bytes = Buffer.from(
|
|
25315
|
-
const hash3 =
|
|
25746
|
+
const bytes = Buffer.from(source);
|
|
25747
|
+
const hash3 = createHash4(oid2?.length === 64 ? "sha256" : "sha1").update(`blob ${bytes.length}\0`).update(bytes).digest("hex");
|
|
25316
25748
|
if (oid2 !== hash3) fail5("staging \uC6D0\uBB38\uC774 \uC900\uBE44\uD55C \uD30C\uC77C\uACFC \uB2E4\uB985\uB2C8\uB2E4: " + path3);
|
|
25317
25749
|
}
|
|
25318
25750
|
if (!same([...index], [...await c.reader.index()])) fail5("\uD655\uC778 \uC911 staging\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
@@ -25324,22 +25756,22 @@ async function verifyPreparedPreview(cwd, input2, staged) {
|
|
|
25324
25756
|
|
|
25325
25757
|
// src/commands/spec-preview-commit.ts
|
|
25326
25758
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
25327
|
-
import { readFile as
|
|
25328
|
-
import { join as
|
|
25759
|
+
import { readFile as readFile9, mkdir as mkdir4, open as open4, rename as rename3, unlink as unlink4, rmdir as rmdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
25760
|
+
import { join as join10 } from "node:path";
|
|
25329
25761
|
|
|
25330
25762
|
// src/commands/spec-commit-files.ts
|
|
25331
|
-
import { createHash as
|
|
25332
|
-
import { lstat as
|
|
25333
|
-
import { join as
|
|
25763
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
25764
|
+
import { lstat as lstat5, readFile as readFile8 } from "node:fs/promises";
|
|
25765
|
+
import { join as join9 } from "node:path";
|
|
25334
25766
|
var fail6 = (message) => {
|
|
25335
25767
|
throw new SpecPreviewError(message);
|
|
25336
25768
|
};
|
|
25337
|
-
var hash2 = (value) =>
|
|
25338
|
-
var optional2 = (path3) =>
|
|
25769
|
+
var hash2 = (value) => createHash5("sha256").update(value).digest("hex");
|
|
25770
|
+
var optional2 = (path3) => readFile8(path3).catch((e) => {
|
|
25339
25771
|
if (e.code === "ENOENT") return null;
|
|
25340
25772
|
throw e;
|
|
25341
25773
|
});
|
|
25342
|
-
var info2 = (path3) =>
|
|
25774
|
+
var info2 = (path3) => lstat5(path3).catch((e) => {
|
|
25343
25775
|
if (e.code === "ENOENT") return void 0;
|
|
25344
25776
|
throw e;
|
|
25345
25777
|
});
|
|
@@ -25351,14 +25783,14 @@ async function fingerprint(root, path3) {
|
|
|
25351
25783
|
validPath2(path3);
|
|
25352
25784
|
const parts = path3.split("/");
|
|
25353
25785
|
for (let i = 1; i <= parts.length; i++) {
|
|
25354
|
-
const
|
|
25355
|
-
const stat3 = await info2(
|
|
25786
|
+
const target = join9(root, ...parts.slice(0, i));
|
|
25787
|
+
const stat3 = await info2(target);
|
|
25356
25788
|
if (!stat3) return null;
|
|
25357
25789
|
if (stat3.isSymbolicLink() || (i < parts.length ? !stat3.isDirectory() : !stat3.isFile())) fail6("\uB9C1\uD06C\xB7\uB514\uB809\uD130\uB9AC\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
25358
|
-
if (i < parts.length && await info2(
|
|
25790
|
+
if (i < parts.length && await info2(join9(target, ".git"))) fail6("\uC911\uCCA9 \uC800\uC7A5\uC18C\uB294 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
25359
25791
|
if (i === parts.length) {
|
|
25360
25792
|
if (stat3.nlink !== 1 || stat3.size > 16 * 1024 * 1024) fail6("\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 \uD30C\uC77C \uD06C\uAE30 \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.");
|
|
25361
|
-
return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await
|
|
25793
|
+
return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await readFile8(target)]));
|
|
25362
25794
|
}
|
|
25363
25795
|
}
|
|
25364
25796
|
return null;
|
|
@@ -25378,7 +25810,7 @@ function paths(value, limit = 128) {
|
|
|
25378
25810
|
return list;
|
|
25379
25811
|
}
|
|
25380
25812
|
function policyPaths(files) {
|
|
25381
|
-
const all = /* @__PURE__ */ new Set(["AGENTS.md", "CLAUDE.md", ".
|
|
25813
|
+
const all = /* @__PURE__ */ new Set(["AGENTS.md", "CLAUDE.md", ".gitignore", ".gitattributes", ".gitifact/config.json", ".tryce/config.json"]);
|
|
25382
25814
|
for (const file2 of files) {
|
|
25383
25815
|
const parts = file2.split("/");
|
|
25384
25816
|
for (let i = 1; i < parts.length; i++) for (const name of ["AGENTS.md", "CLAUDE.md", ".gitignore", ".gitattributes"]) all.add(parts.slice(0, i).join("/") + "/" + name);
|
|
@@ -25388,6 +25820,7 @@ function policyPaths(files) {
|
|
|
25388
25820
|
async function checkLegacySelection(root, selected) {
|
|
25389
25821
|
const legacyJson = /^\.(?:gitifact|tryce)\/(?:spec\/[^/]+\/tryce\.json|notes\/N-[a-f0-9-]+\.json|mode-[a-f0-9-]+\.json|config\.(?:init-1|prototype-1)\.[a-f0-9]+\.json)$/;
|
|
25390
25822
|
for (const p of selected.filter((p2) => p2.startsWith(".gitifact/") && !record2(p2) && p2 !== ".gitifact/config.json")) {
|
|
25823
|
+
if (isProductAssetPath(p)) continue;
|
|
25391
25824
|
if (!legacyJson.test(p) || await fingerprint(root, p) !== null) fail6(".gitifact\uC758 \uAD6C\uD615 \uAE30\uB85D\uC740 \uC0AD\uC81C\uB9CC \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: " + p);
|
|
25392
25825
|
}
|
|
25393
25826
|
for (const p of selected.filter((p2) => p2.startsWith(".tryce/"))) {
|
|
@@ -25420,7 +25853,7 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25420
25853
|
});
|
|
25421
25854
|
const indexPath = (await git(["rev-parse", "--path-format=absolute", "--git-path", "index"])).toString("utf8").trim();
|
|
25422
25855
|
const staged = async (index) => (await git(["diff", "--cached", "--ita-visible-in-index", "--name-only", "--no-renames", "-z"], index)).toString("utf8").split("\0").filter(Boolean).sort();
|
|
25423
|
-
const busy =
|
|
25856
|
+
const busy = join10(gitDir, "gitifact-spec-commit.lock");
|
|
25424
25857
|
if (await info2(busy)) fail6("\uC774\uC804 \uCEE4\uBC0B \uC791\uC5C5 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + busy);
|
|
25425
25858
|
if ((await staged()).length) fail6("\uAE30\uC874 staging\uC744 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uC120\uD0DD \uBC94\uC704\uB97C \uC815\uB9AC\uD55C \uD6C4 \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.");
|
|
25426
25859
|
const request = object3(input2);
|
|
@@ -25462,8 +25895,8 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25462
25895
|
if (data2.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6("\uACC4\uD68D \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25463
25896
|
return { outcome: "planned", plan: { ...data2, digest: seal(data2) }, committed: false };
|
|
25464
25897
|
}
|
|
25465
|
-
const { digest:
|
|
25466
|
-
if (request.kind !== "spec-preview-commit" || typeof
|
|
25898
|
+
const { digest: digest2, ...data } = request;
|
|
25899
|
+
if (request.kind !== "spec-preview-commit" || typeof digest2 !== "string" || digest2 !== seal(data)) fail6("\uCEE4\uBC0B \uACC4\uD68D\uC774 \uC190\uC0C1\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.");
|
|
25467
25900
|
plan = request;
|
|
25468
25901
|
if (plan.root !== root || !Array.isArray(plan.files) || !Array.isArray(plan.context)) fail6("\uACC4\uD68D\uC758 \uC800\uC7A5\uC18C \uB610\uB294 \uD30C\uC77C \uBC94\uC704\uAC00 \uB2E4\uB985\uB2C8\uB2E4.");
|
|
25469
25902
|
const selected = paths(plan.files.map((f) => f.path));
|
|
@@ -25479,16 +25912,16 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25479
25912
|
const before = await reader.baseline();
|
|
25480
25913
|
const original = await optional2(indexPath);
|
|
25481
25914
|
await mkdir4(busy);
|
|
25482
|
-
const draftLock =
|
|
25915
|
+
const draftLock = join10(gitDir, "gitifact-spec-preview.lock");
|
|
25483
25916
|
let draftOwned = false;
|
|
25484
25917
|
let indexLock;
|
|
25485
25918
|
let uncertain = false;
|
|
25486
25919
|
let commitStarted = false;
|
|
25487
|
-
const temporary =
|
|
25920
|
+
const temporary = join10(gitDir, "gitifact-commit-index-" + randomUUID6());
|
|
25488
25921
|
const checkFiles = async () => {
|
|
25489
25922
|
for (const f of [...plan.files, ...plan.context]) if (f.hash !== await fingerprint(root, f.path)) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + f.path);
|
|
25490
25923
|
if ((await readLockedPreviewState(root)).stamp !== object3(plan.verification).stamp) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uBA85\uC138 \uC9D1\uD569\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25491
|
-
for (const name of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"]) if (await info2(
|
|
25924
|
+
for (const name of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"]) if (await info2(join10(gitDir, name))) fail6("Git \uD1B5\uD569 \uC791\uC5C5\uC774 \uC2DC\uC791\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25492
25925
|
};
|
|
25493
25926
|
try {
|
|
25494
25927
|
await verifyPreparedPreview(cwd, plan.verification, false);
|
|
@@ -25496,7 +25929,7 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25496
25929
|
draftOwned = true;
|
|
25497
25930
|
indexLock = await open4(indexPath + ".lock", "wx", 384);
|
|
25498
25931
|
if (plan.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6("\uC7A0\uAE08 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25499
|
-
await writeFile2(
|
|
25932
|
+
await writeFile2(join10(busy, "recovery.json"), JSON.stringify({ before, originalIndex: original?.toString("base64") ?? null, temporary, plan }));
|
|
25500
25933
|
if (original) await writeFile2(temporary, original, { flag: "wx" });
|
|
25501
25934
|
else await git(["read-tree", "--empty"], temporary);
|
|
25502
25935
|
await git(["add", "--", ...selected], temporary);
|
|
@@ -25504,7 +25937,7 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25504
25937
|
if (!actual.length || actual.some((p) => !selected.includes(p))) fail6("\uBE48 \uCEE4\uBC0B \uB610\uB294 \uC120\uD0DD \uBC16 \uD30C\uC77C\uC774 \uAC10\uC9C0\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25505
25938
|
for (const file2 of plan.files.filter((f) => record2(f.path) && f.hash !== null)) {
|
|
25506
25939
|
const stagedBytes = await git(["show", ":" + file2.path], temporary);
|
|
25507
|
-
if (!stagedBytes.equals(await
|
|
25940
|
+
if (!stagedBytes.equals(await readFile9(join10(root, file2.path)))) fail6("Git \uD544\uD130\uAC00 \uBA85\uC138\xB7\uC774\uC720 \uC6D0\uBB38\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25508
25941
|
}
|
|
25509
25942
|
await checkFiles();
|
|
25510
25943
|
if (JSON.stringify(before) !== JSON.stringify(await reader.baseline())) fail6("HEAD\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
@@ -25519,7 +25952,7 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25519
25952
|
if (actualTree !== tree || after.branch !== before.branch || JSON.stringify(parents) !== JSON.stringify(before.head ? [before.head] : []) || trailers.some((t) => !message.split(/\r?\n/).includes(t))) fail6("\uCEE4\uBC0B\uC740 \uC2E4\uD589\uB410\uC9C0\uB9CC \uD6C5\xB7\uB3D9\uC2DC \uC791\uC5C5\uC774 \uACB0\uACFC\uB97C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25520
25953
|
if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== plan.index) fail6("\uCEE4\uBC0B \uD6C4 \uC6D0\uB798 index \uBCC0\uACBD\uC744 \uAC10\uC9C0\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25521
25954
|
if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6("\uD6C5\uC774 \uCEE4\uBC0B \uD6C4 staging\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25522
|
-
await indexLock.writeFile(await
|
|
25955
|
+
await indexLock.writeFile(await readFile9(temporary));
|
|
25523
25956
|
await indexLock.sync();
|
|
25524
25957
|
await indexLock.close();
|
|
25525
25958
|
await rename3(indexPath + ".lock", indexPath);
|
|
@@ -25543,7 +25976,7 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25543
25976
|
});
|
|
25544
25977
|
await unlink4(temporary).catch(() => {
|
|
25545
25978
|
});
|
|
25546
|
-
await unlink4(
|
|
25979
|
+
await unlink4(join10(busy, "recovery.json")).catch(() => {
|
|
25547
25980
|
});
|
|
25548
25981
|
await rmdir2(busy);
|
|
25549
25982
|
if (draftOwned) await rmdir2(draftLock);
|
|
@@ -25552,9 +25985,9 @@ async function previewCommit(cwd, action, input2) {
|
|
|
25552
25985
|
}
|
|
25553
25986
|
|
|
25554
25987
|
// src/commands/spec-commit.ts
|
|
25555
|
-
import { createHash as
|
|
25556
|
-
import { mkdir as mkdir5, open as open5, readFile as
|
|
25557
|
-
import { join as
|
|
25988
|
+
import { createHash as createHash7, randomUUID as randomUUID7 } from "node:crypto";
|
|
25989
|
+
import { mkdir as mkdir5, open as open5, readFile as readFile10, rename as rename4, rmdir as rmdir3, unlink as unlink5, writeFile as writeFile3 } from "node:fs/promises";
|
|
25990
|
+
import { join as join11 } from "node:path";
|
|
25558
25991
|
var fields = ["reasons", "paths", "message", "authorization", "requirements", "policyFiles", "expected"];
|
|
25559
25992
|
var integration = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"];
|
|
25560
25993
|
var same2 = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
@@ -25593,18 +26026,18 @@ async function specCommit(cwd, input2, dryRun) {
|
|
|
25593
26026
|
...stdin ? { input: stdin } : {}
|
|
25594
26027
|
});
|
|
25595
26028
|
const staged = async (index) => (await git(["diff", "--cached", "--ita-visible-in-index", "--name-only", "--no-renames", "-z"], index)).toString("utf8").split("\0").filter(Boolean).sort();
|
|
25596
|
-
const busy =
|
|
26029
|
+
const busy = join11(gitDir, "gitifact-spec-commit.lock");
|
|
25597
26030
|
await failOnLegacyLock(gitDir);
|
|
25598
26031
|
if (await info2(busy)) fail6("\uC774\uC804 \uCEE4\uBC0B \uC791\uC5C5 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + busy);
|
|
25599
26032
|
if ((await staged()).length) fail6("\uAE30\uC874 staging\uC744 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uC120\uD0DD \uBC94\uC704\uB97C \uC815\uB9AC\uD55C \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
|
|
25600
26033
|
const indexHash = hash2(await optional2(indexPath) ?? Buffer.alloc(0));
|
|
25601
26034
|
const current = c.working;
|
|
25602
26035
|
if (request.expected !== void 0 && request.expected !== previewExpected(c.base, current.stamp)) fail6("\uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.");
|
|
25603
|
-
const reasons = request.reasons ??
|
|
25604
|
-
const prepared = prepareSpecPreview(c.
|
|
26036
|
+
const reasons = request.reasons ?? pendingPreviewReasons(c.bundle, current.bundle).map((h) => ({ requirements: h.requirements, ...h.designs ? { designs: h.designs } : {}, ...h.documents ? { documents: h.documents } : {}, reason: h.reason }));
|
|
26037
|
+
const prepared = prepareSpecPreview(c.bundle, current.bundle, c.files, current.files, reasons, () => generatePreviewId("H"));
|
|
25605
26038
|
const blobId = (text2) => {
|
|
25606
26039
|
const bytes = Buffer.from(text2);
|
|
25607
|
-
return
|
|
26040
|
+
return createHash7(objectFormat).update(`blob ${bytes.length}\0`).update(bytes).digest("hex");
|
|
25608
26041
|
};
|
|
25609
26042
|
const present = [...current.files.keys()];
|
|
25610
26043
|
if (present.some((p) => p.includes("\n"))) fail6("\uC904\uBC14\uAFC8\uC774 \uD3EC\uD568\uB41C \uBA85\uC138 \uACBD\uB85C\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
@@ -25642,8 +26075,12 @@ async function specCommit(cwd, input2, dryRun) {
|
|
|
25642
26075
|
await c.recheck();
|
|
25643
26076
|
return { outcome: "dry-run", committed: false, ...summary };
|
|
25644
26077
|
}
|
|
25645
|
-
const trailers = [
|
|
25646
|
-
|
|
26078
|
+
const trailers = [
|
|
26079
|
+
...requirements.map((id) => "Gitifact-Req: " + id),
|
|
26080
|
+
...prepared.changes.filter((c2) => c2.kind === "design").map((c2) => "Gitifact-Design: " + c2.id),
|
|
26081
|
+
...prepared.changes.filter((c2) => c2.kind === "product" || c2.kind === "guide").map((c2) => "Gitifact-Doc: " + c2.id)
|
|
26082
|
+
];
|
|
26083
|
+
const temporary = join11(gitDir, "gitifact-commit-index-" + randomUUID7());
|
|
25647
26084
|
let owned = false;
|
|
25648
26085
|
let uncertain = false;
|
|
25649
26086
|
let indexLock;
|
|
@@ -25659,12 +26096,12 @@ async function specCommit(cwd, input2, dryRun) {
|
|
|
25659
26096
|
await previewTransaction(cwd, current.stamp, async () => ({ writes, data: {}, recheck: c.recheck }), rename4, async (published) => {
|
|
25660
26097
|
let commitStarted = false;
|
|
25661
26098
|
try {
|
|
25662
|
-
const
|
|
26099
|
+
const lock = indexLock = await open5(indexPath + ".lock", "wx", 384);
|
|
25663
26100
|
const original = await optional2(indexPath);
|
|
25664
26101
|
if (hash2(original ?? Buffer.alloc(0)) !== indexHash || (await staged()).length) fail6("\uC2E4\uD589 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25665
26102
|
const locked = await hashes([.../* @__PURE__ */ new Set([...selected, ...contextPaths])]);
|
|
25666
26103
|
for (const [path3, value] of started) if (locked.get(path3) !== value) fail6("\uC2E4\uD589 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25667
|
-
await writeFile3(
|
|
26104
|
+
await writeFile3(join11(busy, "recovery.json"), JSON.stringify({ before: c.base, originalIndex: original?.toString("base64") ?? null, temporary, paths: selected, message, requirements }));
|
|
25668
26105
|
if (original) await writeFile3(temporary, original, { flag: "wx" });
|
|
25669
26106
|
else await git(["read-tree", "--empty"], temporary);
|
|
25670
26107
|
await git(["add", "--", ...stageable], temporary);
|
|
@@ -25680,7 +26117,7 @@ async function specCommit(cwd, input2, dryRun) {
|
|
|
25680
26117
|
const size = Number(header[2]);
|
|
25681
26118
|
if (end < 0 || header[1] !== "blob" || !Number.isSafeInteger(size) || output2[end + 1 + size] !== 10) fail6("staging\uB41C \uBA85\uC138\xB7\uC774\uC720\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25682
26119
|
const staged2 = output2.subarray(end + 1, end + 1 + size);
|
|
25683
|
-
const file2 = await
|
|
26120
|
+
const file2 = await readFile10(join11(root, path3));
|
|
25684
26121
|
if (!staged2.equals(file2) && !staged2.equals(Buffer.from(file2.toString("latin1").replace(/\r\n/g, "\n"), "latin1"))) fail6("Git \uD544\uD130\uAC00 \uBA85\uC138\xB7\uC774\uC720 \uC6D0\uBB38\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25685
26122
|
offset = end + size + 2;
|
|
25686
26123
|
}
|
|
@@ -25688,7 +26125,7 @@ async function specCommit(cwd, input2, dryRun) {
|
|
|
25688
26125
|
const again = await hashes([...locked.keys()]);
|
|
25689
26126
|
for (const [path3, value] of locked) if (again.get(path3) !== value) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
|
|
25690
26127
|
if ((await readLockedPreviewState(root)).stamp !== published.stamp) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uBA85\uC138 \uC9D1\uD569\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25691
|
-
for (const name of integration) if (await info2(
|
|
26128
|
+
for (const name of integration) if (await info2(join11(gitDir, name))) fail6("Git \uD1B5\uD569 \uC791\uC5C5\uC774 \uC2DC\uC791\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25692
26129
|
if (!same2(c.base, await c.reader.baseline())) fail6("HEAD\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
|
|
25693
26130
|
const tree = (await git(["write-tree"], temporary)).toString("utf8").trim();
|
|
25694
26131
|
commitStarted = true;
|
|
@@ -25703,9 +26140,9 @@ async function specCommit(cwd, input2, dryRun) {
|
|
|
25703
26140
|
if (headers[0] !== "tree " + tree || after.branch !== c.base.branch || !same2(parents, c.base.head ? [c.base.head] : []) || trailers.some((t) => !body.split(/\r?\n/).includes(t))) fail6("\uCEE4\uBC0B\uC740 \uC2E4\uD589\uB410\uC9C0\uB9CC \uD6C5\xB7\uB3D9\uC2DC \uC791\uC5C5\uC774 \uACB0\uACFC\uB97C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25704
26141
|
if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== indexHash) fail6("\uCEE4\uBC0B \uD6C4 \uC6D0\uB798 index \uBCC0\uACBD\uC744 \uAC10\uC9C0\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25705
26142
|
if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6("\uD6C5\uC774 \uCEE4\uBC0B \uD6C4 staging\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25706
|
-
await
|
|
25707
|
-
await
|
|
25708
|
-
await
|
|
26143
|
+
await lock.writeFile(await readFile10(temporary));
|
|
26144
|
+
await lock.sync();
|
|
26145
|
+
await lock.close();
|
|
25709
26146
|
await rename4(indexPath + ".lock", indexPath);
|
|
25710
26147
|
indexLock = void 0;
|
|
25711
26148
|
committed = { commit: after.head, paths: actual };
|
|
@@ -25730,7 +26167,7 @@ async function specCommit(cwd, input2, dryRun) {
|
|
|
25730
26167
|
await unlink5(temporary).catch(() => {
|
|
25731
26168
|
});
|
|
25732
26169
|
if (owned) {
|
|
25733
|
-
await unlink5(
|
|
26170
|
+
await unlink5(join11(busy, "recovery.json")).catch(() => {
|
|
25734
26171
|
});
|
|
25735
26172
|
await rmdir3(busy);
|
|
25736
26173
|
}
|
|
@@ -25747,7 +26184,7 @@ async function execute(action, options) {
|
|
|
25747
26184
|
try {
|
|
25748
26185
|
const guard = specPreviewReader(process.cwd());
|
|
25749
26186
|
const { root, gitDir, objectFormat } = await guard.location();
|
|
25750
|
-
for (const marker2 of operations) if (await fileInfo(
|
|
26187
|
+
for (const marker2 of operations) if (await fileInfo(join12(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: " + marker2);
|
|
25751
26188
|
if (await guard.hasUnmerged()) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.");
|
|
25752
26189
|
const raw = await readConfigFile(root);
|
|
25753
26190
|
if (raw === void 0) throw new SpecPreviewError("\uBA3C\uC800 gitifact init\uC73C\uB85C \uCD08\uAE30\uD654\uD558\uC138\uC694.");
|
|
@@ -25759,9 +26196,9 @@ async function execute(action, options) {
|
|
|
25759
26196
|
if (action === "working") result = await readWorkingPreview(process.cwd());
|
|
25760
26197
|
else if (action === "changes") result = await readFinalPreviewChanges(process.cwd());
|
|
25761
26198
|
else {
|
|
25762
|
-
const
|
|
25763
|
-
if (!
|
|
25764
|
-
const bytes = await
|
|
26199
|
+
const source = await stat2(options.file);
|
|
26200
|
+
if (!source.isFile() || source.size > 1024 * 1024) throw new SpecPreviewError("\uC785\uB825\uC740 1 MiB \uC774\uD558\uC758 JSON \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
|
|
26201
|
+
const bytes = await readFile11(options.file);
|
|
25765
26202
|
if (bytes.length > 1024 * 1024) throw new SpecPreviewError("\uC785\uB825 \uD06C\uAE30\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
|
|
25766
26203
|
let input2;
|
|
25767
26204
|
try {
|
|
@@ -25777,12 +26214,12 @@ async function execute(action, options) {
|
|
|
25777
26214
|
const reader = specPreviewReader(process.cwd());
|
|
25778
26215
|
if (action === "read") {
|
|
25779
26216
|
const commit = await reader.resolve(options.ref ?? "HEAD");
|
|
25780
|
-
const
|
|
25781
|
-
process.stdout.write(JSON.stringify({ ...envelope, ok: true, commit, specs }) + "\n");
|
|
26217
|
+
const bundle = await reader.readBundle(commit);
|
|
26218
|
+
process.stdout.write(JSON.stringify({ ...envelope, ok: true, commit, specs: bundle.specs, documents: bundle.documents }) + "\n");
|
|
25782
26219
|
} else {
|
|
25783
26220
|
const [from, to] = await Promise.all([reader.resolve(options.from), reader.resolve(options.to)]);
|
|
25784
|
-
const [before, after] = await Promise.all([reader.
|
|
25785
|
-
process.stdout.write(JSON.stringify({ ...envelope, ok: true, from, to, ...
|
|
26221
|
+
const [before, after] = await Promise.all([reader.readBundle(from), reader.readBundle(to)]);
|
|
26222
|
+
process.stdout.write(JSON.stringify({ ...envelope, ok: true, from, to, ...comparePreviewBundles(before, after) }) + "\n");
|
|
25786
26223
|
}
|
|
25787
26224
|
} catch (error62) {
|
|
25788
26225
|
const known = error62 instanceof SpecPreviewError || error62 instanceof RepositoryReadError || error62 instanceof InitError;
|
|
@@ -25792,11 +26229,11 @@ async function execute(action, options) {
|
|
|
25792
26229
|
}
|
|
25793
26230
|
|
|
25794
26231
|
// src/commands/migrate.ts
|
|
25795
|
-
import { lstat as
|
|
25796
|
-
import { join as
|
|
26232
|
+
import { lstat as lstat7, readdir as readdir4, readFile as readFile12, rename as rename5, writeFile as writeFile4, unlink as unlink6 } from "node:fs/promises";
|
|
26233
|
+
import { join as join13 } from "node:path";
|
|
25797
26234
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
25798
26235
|
var operations2 = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"];
|
|
25799
|
-
var info3 = (path3) =>
|
|
26236
|
+
var info3 = (path3) => lstat7(path3).catch((e) => {
|
|
25800
26237
|
if (e.code === "ENOENT") return void 0;
|
|
25801
26238
|
throw e;
|
|
25802
26239
|
});
|
|
@@ -25807,18 +26244,18 @@ var fail7 = (code, message) => {
|
|
|
25807
26244
|
async function migrateStore(cwd, dryRun = false) {
|
|
25808
26245
|
const reader = specPreviewReader(cwd);
|
|
25809
26246
|
const { root, gitDir } = await reader.location();
|
|
25810
|
-
for (const marker3 of operations2) if (await info3(
|
|
26247
|
+
for (const marker3 of operations2) if (await info3(join13(gitDir, marker3))) fail7("GIT_OPERATION_IN_PROGRESS", "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: " + marker3);
|
|
25811
26248
|
if (await reader.hasUnmerged()) fail7("GIT_OPERATION_IN_PROGRESS", "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.");
|
|
25812
|
-
for (const name of [...LEGACY_LOCKS, "gitifact-spec-preview.lock", "gitifact-spec-commit.lock"]) if (await info3(
|
|
25813
|
-
const from =
|
|
25814
|
-
const to =
|
|
26249
|
+
for (const name of [...LEGACY_LOCKS, "gitifact-spec-preview.lock", "gitifact-spec-commit.lock"]) if (await info3(join13(gitDir, name))) fail7("LOCKED", "\uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + join13(gitDir, name));
|
|
26250
|
+
const from = join13(root, ".tryce");
|
|
26251
|
+
const to = join13(root, ".gitifact");
|
|
25815
26252
|
const fromInfo = await info3(from);
|
|
25816
26253
|
if (await info3(to)) fail7("ALREADY_MIGRATED", ".gitifact\uAC00 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4. .tryce\uAC00 \uB0A8\uC544 \uC788\uC73C\uBA74 \uB0B4\uC6A9\uC744 \uBE44\uAD50\uD55C \uB4A4 \uC9C1\uC811 \uC815\uB9AC\uD558\uC138\uC694.");
|
|
25817
26254
|
if (!fromInfo) return fail7("NOTHING_TO_MIGRATE", ".tryce \uC800\uC7A5\uC18C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
25818
26255
|
if (!fromInfo.isDirectory() || fromInfo.isSymbolicLink()) fail7("PATH_CONFLICT", ".tryce\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
|
|
25819
|
-
const configInfo = await info3(
|
|
26256
|
+
const configInfo = await info3(join13(from, "config.json"));
|
|
25820
26257
|
if (!configInfo?.isFile() || configInfo.isSymbolicLink()) fail7("NOT_INITIALIZED", ".tryce/config.json\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
25821
|
-
const config2 = parseManagedConfig(decode4(await
|
|
26258
|
+
const config2 = parseManagedConfig(decode4(await readFile12(join13(from, "config.json"))));
|
|
25822
26259
|
if (!("schemaVersion" in config2)) fail7("UNSUPPORTED_FORMAT", "\uAD6C\uD615 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uAE30\uB85D\uC744 \uBCF4\uC874\uD558\uACE0 \uBCC4\uB3C4 \uC808\uCC28\uB97C \uD655\uC778\uD558\uC138\uC694.");
|
|
25823
26260
|
const top = (await readdir4(from)).sort();
|
|
25824
26261
|
if (top.some((name) => name !== "config.json" && name !== "spec")) fail7("UNSUPPORTED_FORMAT", ".tryce\uC5D0 config.json\xB7spec \uC678 \uD56D\uBAA9\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
|
|
@@ -25827,20 +26264,20 @@ async function migrateStore(cwd, dryRun = false) {
|
|
|
25827
26264
|
const legacyRecords = [];
|
|
25828
26265
|
const marker2 = /^<!-- tryce-(spec|req|design|ref): /;
|
|
25829
26266
|
if (top.includes("spec")) {
|
|
25830
|
-
for (const feature2 of (await readdir4(
|
|
25831
|
-
const dir =
|
|
26267
|
+
for (const feature2 of (await readdir4(join13(from, "spec"))).sort()) {
|
|
26268
|
+
const dir = join13(from, "spec", feature2);
|
|
25832
26269
|
const stat3 = await info3(dir);
|
|
25833
26270
|
if (!stat3?.isDirectory() || stat3.isSymbolicLink()) fail7("UNSUPPORTED_FORMAT", "\uBA85\uC138 \uD3F4\uB354\uAC00 \uC544\uB2D9\uB2C8\uB2E4: " + feature2);
|
|
25834
26271
|
for (const name of (await readdir4(dir)).sort()) {
|
|
25835
26272
|
if (!["requirements.md", "design.md", "history.jsonl", "tryce.json"].includes(name)) fail7("UNSUPPORTED_FORMAT", "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uD30C\uC77C\uC785\uB2C8\uB2E4: .tryce/spec/" + feature2 + "/" + name);
|
|
25836
|
-
const fileStat = await info3(
|
|
26273
|
+
const fileStat = await info3(join13(dir, name));
|
|
25837
26274
|
if (!fileStat?.isFile() || fileStat.isSymbolicLink() || fileStat.nlink !== 1 || fileStat.size > 1024 * 1024) fail7("UNSUPPORTED_FORMAT", "\uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uAC70\uB098 1 MiB\uB97C \uB118\uC2B5\uB2C8\uB2E4: " + name);
|
|
25838
26275
|
const newPath = `.gitifact/spec/${feature2}/${name}`;
|
|
25839
26276
|
if (name === "tryce.json") {
|
|
25840
26277
|
legacyRecords.push(newPath);
|
|
25841
26278
|
continue;
|
|
25842
26279
|
}
|
|
25843
|
-
const text2 = decode4(await
|
|
26280
|
+
const text2 = decode4(await readFile12(join13(dir, name)));
|
|
25844
26281
|
if (name === "history.jsonl") {
|
|
25845
26282
|
files.set(newPath, text2);
|
|
25846
26283
|
continue;
|
|
@@ -25878,15 +26315,15 @@ async function migrateStore(cwd, dryRun = false) {
|
|
|
25878
26315
|
next: [
|
|
25879
26316
|
"\uBCC0\uACBD\uC744 \uD655\uC778\uD55C \uB4A4 gitifact spec commit\uC73C\uB85C .tryce \uC0AD\uC81C\uC640 .gitifact \uCD94\uAC00\uB97C \uD568\uAED8 \uCEE4\uBC0B\uD558\uC138\uC694.",
|
|
25880
26317
|
...legacyRecords.length ? ["\uAD6C\uD615 JSON \uBA85\uC138(tryce.json)\uB294 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB0B4\uC6A9\uC744 Markdown \uBA85\uC138\uB85C \uC62E\uAE34 \uB4A4 \uC0AD\uC81C\uB97C spec commit\uC5D0 \uC120\uD0DD\uD558\uC138\uC694."] : [],
|
|
25881
|
-
".agents/skills/tryce-workflow\uC640 .claude \uBCF5\uC0AC\uBCF8\uC774 \uC788\uC73C\uBA74 \uC815\uB9AC\uD558\uACE0 gitifact
|
|
26318
|
+
".agents/skills/tryce-workflow\uC640 .claude \uBCF5\uC0AC\uBCF8\uC774 \uC788\uC73C\uBA74 \uC815\uB9AC\uD558\uACE0 gitifact init\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 AGENTS.md \uB4F1\uC758 GITIFACT \uBE14\uB85D\uC744 \uAC31\uC2E0\uD558\uC138\uC694.",
|
|
25882
26319
|
".gitignore\xB7AGENTS.md\xB7CLAUDE.md\uC758 .tryce\xB7tryce-workflow \uC5B8\uAE09\uC744 \uC0C8 \uC774\uB984\uC73C\uB85C \uB9DE\uCD94\uC138\uC694."
|
|
25883
26320
|
]
|
|
25884
26321
|
});
|
|
25885
26322
|
if (dryRun) return result("planned");
|
|
25886
26323
|
await rename5(from, to);
|
|
25887
26324
|
for (const r of rewrites) {
|
|
25888
|
-
const full =
|
|
25889
|
-
const temp =
|
|
26325
|
+
const full = join13(root, r.path);
|
|
26326
|
+
const temp = join13(root, ".gitifact", "spec", ".gitifact-migrate-" + randomBytes2(8).toString("hex"));
|
|
25890
26327
|
await writeFile4(temp, r.content, { flag: "wx" });
|
|
25891
26328
|
try {
|
|
25892
26329
|
await rename5(temp, full);
|
|
@@ -25909,20 +26346,16 @@ async function runMigrate(options) {
|
|
|
25909
26346
|
}
|
|
25910
26347
|
|
|
25911
26348
|
// src/main.ts
|
|
25912
|
-
var program2 = new Command().name("gitifact").description("\uD504\uB85C\uC81D\uD2B8\uC758 \uC694\uAD6C\uC0AC\uD56D\uACFC \uACB0\uC815 \uC774\uB825\uC744 Git\uC5D0 \uB0A8\uAE30\uB294 \uB3C4\uAD6C").version("0.
|
|
26349
|
+
var program2 = new Command().name("gitifact").description("\uD504\uB85C\uC81D\uD2B8\uC758 \uC694\uAD6C\uC0AC\uD56D\uACFC \uACB0\uC815 \uC774\uB825\uC744 Git\uC5D0 \uB0A8\uAE30\uB294 \uB3C4\uAD6C").version("0.3.0").allowExcessArguments(false).addHelpText("after", "\n\uC804\uCCB4 \uC774\uB825 \uAC80\uC0AC\uC640 GUI \uC694\uAD6C\uC0AC\uD56D \uD3B8\uC9D1\uC740 \uC544\uC9C1 \uC81C\uACF5\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.").action(() => program2.outputHelp());
|
|
25913
26350
|
program2.command("status").description("\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC \uC870\uD68C (gitifact \uAC80\uC0AC \uBBF8\uC2E4\uD589)").allowExcessArguments(false).addOption(new Option("--format <format>", "\uCD9C\uB825 \uD615\uC2DD").choices(["json", "text"]).default("json")).action(async (options) => {
|
|
25914
26351
|
await runStatus(options.format);
|
|
25915
26352
|
});
|
|
25916
26353
|
program2.command("browser").description("\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC\uB97C \uB85C\uCEEC \uBE0C\uB77C\uC6B0\uC800\uB85C \uC870\uD68C").allowExcessArguments(false).option("--port <port>", "\uC218\uC2E0 \uD3EC\uD2B8 (0\uC740 \uC790\uB3D9 \uC120\uD0DD)", parsePort, 0).option("--dev", "Vite \uAC1C\uBC1C \uC11C\uBC84 Origin \uD5C8\uC6A9").action(runBrowser);
|
|
25917
|
-
program2.command("init").description("\uD504\uB85C\uC81D\uD2B8 \uC124\uC815\
|
|
26354
|
+
program2.command("init").description("\uD504\uB85C\uC81D\uD2B8 \uC124\uC815\xB7\uAE30\uC900\uC120 \uC0DD\uC131\uACFC \uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68 \uD30C\uC77C\uC758 GITIFACT \uBE14\uB85D \uC124\uCE58 (\uC7AC\uC2E4\uD589 \uC2DC \uBE14\uB85D \uAC31\uC2E0)").allowExcessArguments(false).option("--dry-run", "\uD30C\uC77C\uC744 \uB9CC\uB4E4\uC9C0 \uC54A\uACE0 \uCD08\uAE30\uD654 \uACC4\uD68D \uD655\uC778").addOption(new Option("--agent <agent>", "\uC9C0\uCE68 \uD30C\uC77C \uB300\uC0C1 (\uAE30\uBCF8: \uAE30\uC874 \uD30C\uC77C \uC804\uBD80, \uC5C6\uC73C\uBA74 AGENTS.md)").choices([...agentPresetNames])).addOption(new Option("--remove-agents", "GITIFACT \uBE14\uB85D\uC744 \uC81C\uAC70").conflicts("skipAgents")).option("--skip-agents", "\uC9C0\uCE68 \uD30C\uC77C\uC744 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC74C").addOption(new Option("--format <format>", "\uCD9C\uB825 \uD615\uC2DD").choices(["json", "text"]).default("json")).action((options) => runInit(options, "0.3.0"));
|
|
26355
|
+
program2.command("docs").description("\uC5D0\uC774\uC804\uD2B8\uC6A9 \uC791\uC5C5 \uC9C0\uCE68 \uCD9C\uB825 (\uC8FC\uC81C \uC5C6\uC774 \uC2E4\uD589\uD558\uBA74 \uBAA9\uB85D)").argument("[topic]", "workflow, spec, design, product, commit \uC911 \uD558\uB098").allowExcessArguments(false).action(async (topic) => {
|
|
26356
|
+
await runDocs(topic);
|
|
26357
|
+
});
|
|
25918
26358
|
program2.command("migrate").description(".tryce \uC800\uC7A5\uC18C\uB97C .gitifact\uB85C \uC804\uD658 (\uACBD\uB85C\uC640 \uB9C8\uCEE4\uB9CC \uBC14\uAFB8\uACE0 ID\xB7\uC774\uC720\xB7\uC774\uB825\uC740 \uBCF4\uC874)").allowExcessArguments(false).option("--dry-run", "\uD30C\uC77C\uC744 \uBC14\uAFB8\uC9C0 \uC54A\uACE0 \uC804\uD658 \uACC4\uD68D \uD655\uC778").action(runMigrate);
|
|
25919
|
-
var outputOption = () => new Option("--format <format>", "\uCD9C\uB825 \uD615\uC2DD").choices(["json", "text"]).default("json");
|
|
25920
|
-
var skills = program2.command("skills").description("\uD504\uB85C\uC81D\uD2B8 \uC2A4\uD0AC \uC6D0\uBCF8 \uC124\uCE58\uC640 \uB85C\uCEEC \uBCF5\uC0AC\uBCF8 \uAD00\uB9AC");
|
|
25921
|
-
for (const action of ["install", "sync", "remove"]) {
|
|
25922
|
-
const command = skills.command(action).allowExcessArguments(false).option("--dry-run", "\uD30C\uC77C\uC744 \uC4F0\uC9C0 \uC54A\uACE0 \uACC4\uD68D \uD655\uC778").addOption(outputOption());
|
|
25923
|
-
if (action !== "remove") command.addOption(new Option("--agent <agent>", "\uC0AC\uC6A9\uD560 \uC5D0\uC774\uC804\uD2B8").choices(["codex", "claude"]));
|
|
25924
|
-
command.action((options) => runSkills(action, options));
|
|
25925
|
-
}
|
|
25926
26359
|
var spec = program2.command("spec").description("Markdown \uBA85\uC138 \uC791\uC131\xB7\uC870\uD68C\xB7Git \uAE30\uB85D");
|
|
25927
26360
|
var replaced = "Deprecated: 0.6.0\uC5D0\uC11C \uC81C\uAC70 \uC608\uC815. spec commit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.";
|
|
25928
26361
|
spec.command("commit").description("\uBCC0\uACBD \uC774\uC720 \uAE30\uB85D\uACFC \uAD00\uB828 \uD30C\uC77C \uCEE4\uBC0B\uC744 \uD55C \uBC88\uC5D0 \uC2E4\uD589").allowExcessArguments(false).requiredOption("--file <path>", "reasons\xB7paths\xB7message\xB7authorization\uC744 \uB2F4\uC740 JSON \uD30C\uC77C").option("--dry-run", "\uD30C\uC77C\uC744 \uC4F0\uAC70\uB098 \uCEE4\uBC0B\uD558\uC9C0 \uC54A\uACE0 \uACB0\uACFC\uB9CC \uD655\uC778").action((o) => runSpecPreview("commit", o));
|