@agent-profile/web 0.2.0 → 0.3.1
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/build/client/_app/immutable/assets/9.BDcQmxob.css +1 -0
- package/build/client/_app/immutable/assets/9.BDcQmxob.css.br +0 -0
- package/build/client/_app/immutable/assets/9.BDcQmxob.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BcMnim1Z.js +2 -0
- package/build/client/_app/immutable/chunks/BcMnim1Z.js.br +0 -0
- package/build/client/_app/immutable/chunks/BcMnim1Z.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D5fBh0I2.js +1 -0
- package/build/client/_app/immutable/chunks/D5fBh0I2.js.br +2 -0
- package/build/client/_app/immutable/chunks/D5fBh0I2.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DJ5W1vn7.js +3 -0
- package/build/client/_app/immutable/chunks/DJ5W1vn7.js.br +0 -0
- package/build/client/_app/immutable/chunks/DJ5W1vn7.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DTBN031P.js +1 -0
- package/build/client/_app/immutable/chunks/DTBN031P.js.br +2 -0
- package/build/client/_app/immutable/chunks/DTBN031P.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D_wMLkFK.js +1 -0
- package/build/client/_app/immutable/chunks/D_wMLkFK.js.br +2 -0
- package/build/client/_app/immutable/chunks/D_wMLkFK.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CRcOA4L4.js → m4VeB-e-.js} +2 -2
- package/build/client/_app/immutable/chunks/m4VeB-e-.js.br +0 -0
- package/build/client/_app/immutable/chunks/m4VeB-e-.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.DMWpO7sJ.js +2 -0
- package/build/client/_app/immutable/entry/app.DMWpO7sJ.js.br +0 -0
- package/build/client/_app/immutable/entry/app.DMWpO7sJ.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BBaMgJ1R.js +1 -0
- package/build/client/_app/immutable/entry/start.BBaMgJ1R.js.br +0 -0
- package/build/client/_app/immutable/entry/start.BBaMgJ1R.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.Dv0k2Jqi.js +1 -0
- package/build/client/_app/immutable/nodes/0.Dv0k2Jqi.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.Dv0k2Jqi.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.E6HqFVj7.js +1 -0
- package/build/client/_app/immutable/nodes/1.E6HqFVj7.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.E6HqFVj7.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.DorD5wKe.js +3 -0
- package/build/client/_app/immutable/nodes/10.DorD5wKe.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.DorD5wKe.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{10.IHQDAuDz.js → 11.3lkgWYOd.js} +2 -2
- package/build/client/_app/immutable/nodes/11.3lkgWYOd.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.3lkgWYOd.js.gz +0 -0
- package/build/client/_app/immutable/nodes/12.p6ol8gkx.js +1 -0
- package/build/client/_app/immutable/nodes/12.p6ol8gkx.js.br +0 -0
- package/build/client/_app/immutable/nodes/12.p6ol8gkx.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{2.BHUaWFMZ.js → 2.DMK5rlQk.js} +2 -2
- package/build/client/_app/immutable/nodes/2.DMK5rlQk.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.DMK5rlQk.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.BBvN4Erf.js +2 -0
- package/build/client/_app/immutable/nodes/3.BBvN4Erf.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.BBvN4Erf.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.3VL8fZOS.js +4 -0
- package/build/client/_app/immutable/nodes/4.3VL8fZOS.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.3VL8fZOS.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.CiNtblYV.js +2 -0
- package/build/client/_app/immutable/nodes/5.CiNtblYV.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.CiNtblYV.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.BRCCYakl.js +5 -0
- package/build/client/_app/immutable/nodes/6.BRCCYakl.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.BRCCYakl.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.Bn-YL1OM.js +4 -0
- package/build/client/_app/immutable/nodes/7.Bn-YL1OM.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.Bn-YL1OM.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.CkQQuOBs.js +1 -0
- package/build/client/_app/immutable/nodes/8.CkQQuOBs.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.CkQQuOBs.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.6KxRZbKJ.js +9 -0
- package/build/client/_app/immutable/nodes/9.6KxRZbKJ.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.6KxRZbKJ.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/{0-IAeZ4YD5.js → 0-D1xG012U.js} +8 -8
- package/build/server/chunks/{0-IAeZ4YD5.js.map → 0-D1xG012U.js.map} +1 -1
- package/build/server/chunks/1-B1kTzRNn.js +9 -0
- package/build/server/chunks/{1--R3gZqoU.js.map → 1-B1kTzRNn.js.map} +1 -1
- package/build/server/chunks/{9-kCTRECfO.js → 10-DahfOzGu.js} +7 -7
- package/build/server/chunks/10-DahfOzGu.js.map +1 -0
- package/build/server/chunks/11-mzYblRmm.js +9 -0
- package/build/server/chunks/11-mzYblRmm.js.map +1 -0
- package/build/server/chunks/{11-DbxvesJH.js → 12-Dw1Y6Xen.js} +4 -4
- package/build/server/chunks/{11-DbxvesJH.js.map → 12-Dw1Y6Xen.js.map} +1 -1
- package/build/server/chunks/{2-CHviyPyI.js → 2-Cbd6Pglj.js} +3 -3
- package/build/server/chunks/{2-CHviyPyI.js.map → 2-Cbd6Pglj.js.map} +1 -1
- package/build/server/chunks/{3-CdNRNP5d.js → 3-DjAsck26.js} +2 -2
- package/build/server/chunks/{3-CdNRNP5d.js.map → 3-DjAsck26.js.map} +1 -1
- package/build/server/chunks/{4-CCj_Mhpz.js → 4-CKQYCTZo.js} +4 -4
- package/build/server/chunks/{4-CCj_Mhpz.js.map → 4-CKQYCTZo.js.map} +1 -1
- package/build/server/chunks/5-BDp1sX0Q.js +9 -0
- package/build/server/chunks/{5-CqBVRlNU.js.map → 5-BDp1sX0Q.js.map} +1 -1
- package/build/server/chunks/{6-BHxeFzUE.js → 6-CUIuzy6O.js} +2 -2
- package/build/server/chunks/{6-BHxeFzUE.js.map → 6-CUIuzy6O.js.map} +1 -1
- package/build/server/chunks/{7-BUFOaHdC.js → 7-BDv5_nF1.js} +6 -6
- package/build/server/chunks/{7-BUFOaHdC.js.map → 7-BDv5_nF1.js.map} +1 -1
- package/build/server/chunks/8-CspJz0xl.js +9 -0
- package/build/server/chunks/{8-BbviFV5J.js.map → 8-CspJz0xl.js.map} +1 -1
- package/build/server/chunks/9-BpgaO-rd.js +33 -0
- package/build/server/chunks/9-BpgaO-rd.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-CQM4xaaq.js → _layout.svelte-6X0-Uv9x.js} +13 -3
- package/build/server/chunks/_layout.svelte-6X0-Uv9x.js.map +1 -0
- package/build/server/chunks/_page.svelte-BEU4JrAd.js +433 -0
- package/build/server/chunks/_page.svelte-BEU4JrAd.js.map +1 -0
- package/build/server/chunks/{_page.svelte-B6d3qwTm.js → _page.svelte-Bi4xsxv7.js} +3 -3
- package/build/server/chunks/{_page.svelte-B6d3qwTm.js.map → _page.svelte-Bi4xsxv7.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-2W3EhlSt.js → _page.svelte-Bx-fv-rO.js} +3 -3
- package/build/server/chunks/{_page.svelte-2W3EhlSt.js.map → _page.svelte-Bx-fv-rO.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-sygmDxbg.js → _page.svelte-CveCaqpY.js} +3 -3
- package/build/server/chunks/{_page.svelte-sygmDxbg.js.map → _page.svelte-CveCaqpY.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-DfUc4h7g.js → _page.svelte-DNmC-yjw.js} +2 -2
- package/build/server/chunks/{_page.svelte-DfUc4h7g.js.map → _page.svelte-DNmC-yjw.js.map} +1 -1
- package/build/server/chunks/_server.ts-BBDD0W6t.js +167 -0
- package/build/server/chunks/_server.ts-BBDD0W6t.js.map +1 -0
- package/build/server/chunks/_server.ts-BkOJmVFg.js +101 -0
- package/build/server/chunks/_server.ts-BkOJmVFg.js.map +1 -0
- package/build/server/chunks/{_server.ts-C8Fe0kql.js → _server.ts-BkcLO56D.js} +2 -2
- package/build/server/chunks/{_server.ts-C8Fe0kql.js.map → _server.ts-BkcLO56D.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DsbQ4b7x.js → _server.ts-C2WpZqPW.js} +4 -4
- package/build/server/chunks/{_server.ts-DsbQ4b7x.js.map → _server.ts-C2WpZqPW.js.map} +1 -1
- package/build/server/chunks/{_server.ts-D1Ja2hnG.js → _server.ts-CKn8ym8s.js} +2 -2
- package/build/server/chunks/{_server.ts-D1Ja2hnG.js.map → _server.ts-CKn8ym8s.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BjPyYUki.js → _server.ts-CaVH9FSD.js} +4 -4
- package/build/server/chunks/{_server.ts-BjPyYUki.js.map → _server.ts-CaVH9FSD.js.map} +1 -1
- package/build/server/chunks/_server.ts-D7iLlRbM.js +337 -0
- package/build/server/chunks/_server.ts-D7iLlRbM.js.map +1 -0
- package/build/server/chunks/_server.ts-DPqZOGG_.js +18 -0
- package/build/server/chunks/_server.ts-DPqZOGG_.js.map +1 -0
- package/build/server/chunks/{_server.ts-B7znNtap.js → _server.ts-Dz9oKgWc.js} +5 -5
- package/build/server/chunks/{_server.ts-B7znNtap.js.map → _server.ts-Dz9oKgWc.js.map} +1 -1
- package/build/server/chunks/{_server.ts-hEGlXjuB.js → _server.ts-fVP0SuTW.js} +2 -2
- package/build/server/chunks/{_server.ts-hEGlXjuB.js.map → _server.ts-fVP0SuTW.js.map} +1 -1
- package/build/server/chunks/{client-h6Frgnzt.js → client-CydontyB.js} +2 -2
- package/build/server/chunks/{client-h6Frgnzt.js.map → client-CydontyB.js.map} +1 -1
- package/build/server/chunks/{doctorSummary-FyoWuR3R.js → doctorSummary-BOtGdd9z.js} +3 -3
- package/build/server/chunks/{doctorSummary-FyoWuR3R.js.map → doctorSummary-BOtGdd9z.js.map} +1 -1
- package/build/server/chunks/{error.svelte-DYzh-S9t.js → error.svelte-_CDx8UPv.js} +3 -3
- package/build/server/chunks/{error.svelte-DYzh-S9t.js.map → error.svelte-_CDx8UPv.js.map} +1 -1
- package/build/server/chunks/{hooks.server-BKavEpqC.js → hooks.server-Dva4z7fv.js} +35 -1
- package/build/server/chunks/hooks.server-Dva4z7fv.js.map +1 -0
- package/build/server/chunks/{internal-Dz8-ksla.js → internal-DyPeC3rk.js} +3 -3
- package/build/server/chunks/{internal-Dz8-ksla.js.map → internal-DyPeC3rk.js.map} +1 -1
- package/build/server/chunks/{marketingSeo-6Ec8IVzY.js → marketingSeo-CugwK52J.js} +2 -2
- package/build/server/chunks/{marketingSeo-6Ec8IVzY.js.map → marketingSeo-CugwK52J.js.map} +1 -1
- package/build/server/chunks/migrationReport-f6NoxAVZ.js +40 -0
- package/build/server/chunks/migrationReport-f6NoxAVZ.js.map +1 -0
- package/build/server/chunks/{profileApiHelpers-CUuQdn1G.js → profileApiHelpers-DCoI7zMU.js} +3 -3
- package/build/server/chunks/{profileApiHelpers-CUuQdn1G.js.map → profileApiHelpers-DCoI7zMU.js.map} +1 -1
- package/build/server/chunks/{projectContext-fk5wtjwg.js → projectContext-B1D-bieW.js} +1370 -17
- package/build/server/chunks/projectContext-B1D-bieW.js.map +1 -0
- package/build/server/chunks/{src2-BFardyAd.js → src2-BtraGDB1.js} +2 -2
- package/build/server/chunks/src2-BtraGDB1.js.map +1 -0
- package/build/server/chunks/{src3-vKD2iyNK.js → src3-BXch_OaJ.js} +219 -14
- package/build/server/chunks/src3-BXch_OaJ.js.map +1 -0
- package/build/server/chunks/{tokenStore-DQfTa-N3.js → tokenStore-CTHhmHsk.js} +30 -2
- package/build/server/chunks/tokenStore-CTHhmHsk.js.map +1 -0
- package/build/server/index.js +1 -1
- package/build/server/manifest.js +58 -22
- package/build/server/manifest.js.map +1 -1
- package/package.json +3 -3
- package/build/client/_app/immutable/chunks/4FiW6_9u.js +0 -1
- package/build/client/_app/immutable/chunks/4FiW6_9u.js.br +0 -2
- package/build/client/_app/immutable/chunks/4FiW6_9u.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CF39CcoQ.js +0 -3
- package/build/client/_app/immutable/chunks/CF39CcoQ.js.br +0 -0
- package/build/client/_app/immutable/chunks/CF39CcoQ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CRcOA4L4.js.br +0 -0
- package/build/client/_app/immutable/chunks/CRcOA4L4.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cc9Av3g9.js +0 -2
- package/build/client/_app/immutable/chunks/Cc9Av3g9.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cc9Av3g9.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DUEBfJ-c.js +0 -1
- package/build/client/_app/immutable/chunks/DUEBfJ-c.js.br +0 -4
- package/build/client/_app/immutable/chunks/DUEBfJ-c.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DvNNrklS.js +0 -1
- package/build/client/_app/immutable/chunks/DvNNrklS.js.br +0 -2
- package/build/client/_app/immutable/chunks/DvNNrklS.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.ZULfIbKE.js +0 -2
- package/build/client/_app/immutable/entry/app.ZULfIbKE.js.br +0 -0
- package/build/client/_app/immutable/entry/app.ZULfIbKE.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.XwZvWTgq.js +0 -1
- package/build/client/_app/immutable/entry/start.XwZvWTgq.js.br +0 -0
- package/build/client/_app/immutable/entry/start.XwZvWTgq.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.BTaKrNnR.js +0 -1
- package/build/client/_app/immutable/nodes/0.BTaKrNnR.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.BTaKrNnR.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.B4GcuHvH.js +0 -1
- package/build/client/_app/immutable/nodes/1.B4GcuHvH.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.B4GcuHvH.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.IHQDAuDz.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.IHQDAuDz.js.gz +0 -0
- package/build/client/_app/immutable/nodes/11.B5APptAv.js +0 -1
- package/build/client/_app/immutable/nodes/11.B5APptAv.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.B5APptAv.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.BHUaWFMZ.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.BHUaWFMZ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.DIhh3cSh.js +0 -2
- package/build/client/_app/immutable/nodes/3.DIhh3cSh.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.DIhh3cSh.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.DjkBBmOF.js +0 -4
- package/build/client/_app/immutable/nodes/4.DjkBBmOF.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.DjkBBmOF.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.BPcSAYs6.js +0 -2
- package/build/client/_app/immutable/nodes/5.BPcSAYs6.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.BPcSAYs6.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.DZa-5yoH.js +0 -5
- package/build/client/_app/immutable/nodes/6.DZa-5yoH.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.DZa-5yoH.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.v6t5o5IK.js +0 -4
- package/build/client/_app/immutable/nodes/7.v6t5o5IK.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.v6t5o5IK.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.UWqOmBTc.js +0 -1
- package/build/client/_app/immutable/nodes/8.UWqOmBTc.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.UWqOmBTc.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.xVCOCMfn.js +0 -3
- package/build/client/_app/immutable/nodes/9.xVCOCMfn.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.xVCOCMfn.js.gz +0 -0
- package/build/server/chunks/1--R3gZqoU.js +0 -9
- package/build/server/chunks/10-B2v4GVik.js +0 -9
- package/build/server/chunks/10-B2v4GVik.js.map +0 -1
- package/build/server/chunks/5-CqBVRlNU.js +0 -9
- package/build/server/chunks/8-BbviFV5J.js +0 -9
- package/build/server/chunks/9-kCTRECfO.js.map +0 -1
- package/build/server/chunks/_layout.svelte-CQM4xaaq.js.map +0 -1
- package/build/server/chunks/hooks.server-BKavEpqC.js.map +0 -1
- package/build/server/chunks/projectContext-fk5wtjwg.js.map +0 -1
- package/build/server/chunks/src2-BFardyAd.js.map +0 -1
- package/build/server/chunks/src3-vKD2iyNK.js.map +0 -1
- package/build/server/chunks/tokenStore-DQfTa-N3.js.map +0 -1
- /package/build/client/_app/immutable/assets/{9.BsbC-D7w.css → 10.BsbC-D7w.css} +0 -0
- /package/build/client/_app/immutable/assets/{9.BsbC-D7w.css.br → 10.BsbC-D7w.css.br} +0 -0
- /package/build/client/_app/immutable/assets/{9.BsbC-D7w.css.gz → 10.BsbC-D7w.css.gz} +0 -0
- /package/build/client/_app/immutable/chunks/{I8rQr1kY.js → CP97kCR3.js} +0 -0
- /package/build/client/_app/immutable/chunks/{I8rQr1kY.js.br → CP97kCR3.js.br} +0 -0
- /package/build/client/_app/immutable/chunks/{I8rQr1kY.js.gz → CP97kCR3.js.gz} +0 -0
- /package/build/client/_app/immutable/chunks/{BFYQcBYR.js → O6-aNYLC.js} +0 -0
- /package/build/client/_app/immutable/chunks/{BFYQcBYR.js.br → O6-aNYLC.js.br} +0 -0
- /package/build/client/_app/immutable/chunks/{BFYQcBYR.js.gz → O6-aNYLC.js.gz} +0 -0
|
@@ -17091,17 +17091,20 @@ function compareText(left, right) {
|
|
|
17091
17091
|
}
|
|
17092
17092
|
//#endregion
|
|
17093
17093
|
//#region ../../packages/compiler/src/lockfile.ts
|
|
17094
|
+
var SUPPORTED_VERSIONS = new Set([1, 2]);
|
|
17094
17095
|
function buildLockfile(input) {
|
|
17096
|
+
const profilePath = safeOutputPath(input.profilePath ?? "ai-profile.yaml");
|
|
17097
|
+
const mixedByPath = new Map((input.mixedOutputs ?? []).map((entry) => [safeOutputPath(entry.path), entry]));
|
|
17095
17098
|
return {
|
|
17096
|
-
version:
|
|
17099
|
+
version: 2,
|
|
17097
17100
|
profile: {
|
|
17098
|
-
path:
|
|
17101
|
+
path: profilePath,
|
|
17099
17102
|
schemaVersion: 1,
|
|
17100
17103
|
sha256: sha256Hex(input.profileBytes)
|
|
17101
17104
|
},
|
|
17102
17105
|
compiler: input.compiler ?? AGENT_PROFILE_COMPILER,
|
|
17103
17106
|
templates: input.templates.map(toLockTemplate).sort(compareLockTemplates),
|
|
17104
|
-
outputs: input.files.map(
|
|
17107
|
+
outputs: input.files.map((file) => toLockOutputV2(file, mixedByPath)).sort(compareLockOutputsV2)
|
|
17105
17108
|
};
|
|
17106
17109
|
}
|
|
17107
17110
|
function serializeLockfile(lockfile) {
|
|
@@ -17110,6 +17113,28 @@ function serializeLockfile(lockfile) {
|
|
|
17110
17113
|
function createLockfileFile(input) {
|
|
17111
17114
|
return createGeneratedTextFile("ai-profile.lock", "lockfile", "targets/lockfile@1", serializeLockfile(buildLockfile(input)));
|
|
17112
17115
|
}
|
|
17116
|
+
/**
|
|
17117
|
+
* Migrate a parsed v1 lockfile to v2 by promoting every v1 output to
|
|
17118
|
+
* `generated-owned`. Order, hashes, target, and template ids are copied
|
|
17119
|
+
* unchanged. The migration is deterministic and idempotent: calling it on the
|
|
17120
|
+
* result of `buildLockfile(input)` for the same inputs produces byte-identical
|
|
17121
|
+
* v2 bytes.
|
|
17122
|
+
*/
|
|
17123
|
+
function migrateLockfileV1ToV2(lockfile) {
|
|
17124
|
+
return {
|
|
17125
|
+
version: 2,
|
|
17126
|
+
profile: lockfile.profile,
|
|
17127
|
+
compiler: lockfile.compiler,
|
|
17128
|
+
templates: [...lockfile.templates].sort(compareLockTemplates),
|
|
17129
|
+
outputs: lockfile.outputs.map((output) => ({
|
|
17130
|
+
path: output.path,
|
|
17131
|
+
target: output.target,
|
|
17132
|
+
templateId: output.templateId,
|
|
17133
|
+
ownership: "generated-owned",
|
|
17134
|
+
sha256: output.sha256
|
|
17135
|
+
})).sort(compareLockOutputsV2)
|
|
17136
|
+
};
|
|
17137
|
+
}
|
|
17113
17138
|
function validateLockfileText(source) {
|
|
17114
17139
|
try {
|
|
17115
17140
|
return validateLockfileValue(JSON.parse(source));
|
|
@@ -17128,14 +17153,48 @@ function validateLockfileText(source) {
|
|
|
17128
17153
|
}
|
|
17129
17154
|
function validateLockfileValue(value) {
|
|
17130
17155
|
const issues = [];
|
|
17131
|
-
|
|
17156
|
+
if (!isRecord(value)) {
|
|
17157
|
+
issues.push(schemaIssue("/", "object", describeValue(value)));
|
|
17158
|
+
return {
|
|
17159
|
+
ok: false,
|
|
17160
|
+
issues
|
|
17161
|
+
};
|
|
17162
|
+
}
|
|
17163
|
+
const version = value.version;
|
|
17164
|
+
if (typeof version !== "number" || !SUPPORTED_VERSIONS.has(version)) {
|
|
17165
|
+
issues.push({
|
|
17166
|
+
code: "lockfile_unsupported_version",
|
|
17167
|
+
path: "/version",
|
|
17168
|
+
expected: "supported lockfile version (1 or 2)",
|
|
17169
|
+
actual: describeValue(version),
|
|
17170
|
+
message: `/version is not a supported lockfile version.`
|
|
17171
|
+
});
|
|
17172
|
+
return {
|
|
17173
|
+
ok: false,
|
|
17174
|
+
issues
|
|
17175
|
+
};
|
|
17176
|
+
}
|
|
17177
|
+
if (version === 1) {
|
|
17178
|
+
validateLockfileV1Object(value, issues);
|
|
17179
|
+
if (issues.length > 0) return {
|
|
17180
|
+
ok: false,
|
|
17181
|
+
issues: issues.sort(compareLockfileIssues)
|
|
17182
|
+
};
|
|
17183
|
+
return {
|
|
17184
|
+
ok: true,
|
|
17185
|
+
lockfile: value,
|
|
17186
|
+
version: 1
|
|
17187
|
+
};
|
|
17188
|
+
}
|
|
17189
|
+
validateLockfileV2Object(value, issues);
|
|
17132
17190
|
if (issues.length > 0) return {
|
|
17133
17191
|
ok: false,
|
|
17134
17192
|
issues: issues.sort(compareLockfileIssues)
|
|
17135
17193
|
};
|
|
17136
17194
|
return {
|
|
17137
17195
|
ok: true,
|
|
17138
|
-
lockfile: value
|
|
17196
|
+
lockfile: value,
|
|
17197
|
+
version: 2
|
|
17139
17198
|
};
|
|
17140
17199
|
}
|
|
17141
17200
|
function toLockTemplate(template) {
|
|
@@ -17146,7 +17205,7 @@ function toLockTemplate(template) {
|
|
|
17146
17205
|
sha256: template.sha256
|
|
17147
17206
|
};
|
|
17148
17207
|
}
|
|
17149
|
-
function
|
|
17208
|
+
function validateLockfileV1Object(value, issues) {
|
|
17150
17209
|
if (!isRecord(value)) {
|
|
17151
17210
|
issues.push(schemaIssue("/", "object", describeValue(value)));
|
|
17152
17211
|
return;
|
|
@@ -17162,7 +17221,25 @@ function validateLockfileObject(value, issues) {
|
|
|
17162
17221
|
validateProfile(value.profile, issues);
|
|
17163
17222
|
validateCompiler(value.compiler, issues);
|
|
17164
17223
|
validateTemplates(value.templates, issues);
|
|
17165
|
-
|
|
17224
|
+
validateOutputsV1(value.outputs, issues);
|
|
17225
|
+
}
|
|
17226
|
+
function validateLockfileV2Object(value, issues) {
|
|
17227
|
+
if (!isRecord(value)) {
|
|
17228
|
+
issues.push(schemaIssue("/", "object", describeValue(value)));
|
|
17229
|
+
return;
|
|
17230
|
+
}
|
|
17231
|
+
requireExactKeys(value, "/", [
|
|
17232
|
+
"version",
|
|
17233
|
+
"profile",
|
|
17234
|
+
"compiler",
|
|
17235
|
+
"templates",
|
|
17236
|
+
"outputs"
|
|
17237
|
+
], issues);
|
|
17238
|
+
if (value.version !== 2) issues.push(schemaIssue("/version", "constant 2", describeValue(value.version)));
|
|
17239
|
+
validateProfile(value.profile, issues);
|
|
17240
|
+
validateCompiler(value.compiler, issues);
|
|
17241
|
+
validateTemplates(value.templates, issues);
|
|
17242
|
+
validateOutputsV2(value.outputs, issues);
|
|
17166
17243
|
}
|
|
17167
17244
|
function validateProfile(value, issues) {
|
|
17168
17245
|
if (!isRecord(value)) {
|
|
@@ -17220,7 +17297,7 @@ function validateTemplates(value, issues) {
|
|
|
17220
17297
|
previous = current;
|
|
17221
17298
|
});
|
|
17222
17299
|
}
|
|
17223
|
-
function
|
|
17300
|
+
function validateOutputsV1(value, issues) {
|
|
17224
17301
|
if (!Array.isArray(value)) {
|
|
17225
17302
|
issues.push(schemaIssue("/outputs", "array", describeValue(value)));
|
|
17226
17303
|
return;
|
|
@@ -17253,6 +17330,89 @@ function validateOutputs(value, issues) {
|
|
|
17253
17330
|
previous = current;
|
|
17254
17331
|
});
|
|
17255
17332
|
}
|
|
17333
|
+
function validateOutputsV2(value, issues) {
|
|
17334
|
+
if (!Array.isArray(value)) {
|
|
17335
|
+
issues.push(schemaIssue("/outputs", "array", describeValue(value)));
|
|
17336
|
+
return;
|
|
17337
|
+
}
|
|
17338
|
+
let previous;
|
|
17339
|
+
value.forEach((item, index) => {
|
|
17340
|
+
const path = `/outputs/${index}`;
|
|
17341
|
+
if (!isRecord(item)) {
|
|
17342
|
+
issues.push(schemaIssue(path, "object", describeValue(item)));
|
|
17343
|
+
return;
|
|
17344
|
+
}
|
|
17345
|
+
const ownership = item.ownership;
|
|
17346
|
+
if (ownership === "generated-owned") {
|
|
17347
|
+
requireExactKeys(item, path, [
|
|
17348
|
+
"path",
|
|
17349
|
+
"target",
|
|
17350
|
+
"templateId",
|
|
17351
|
+
"ownership",
|
|
17352
|
+
"sha256"
|
|
17353
|
+
], issues);
|
|
17354
|
+
validatePath(item.path, `${path}/path`, issues);
|
|
17355
|
+
validateString(item.target, `${path}/target`, issues);
|
|
17356
|
+
validateString(item.templateId, `${path}/templateId`, issues);
|
|
17357
|
+
validateHash(item.sha256, `${path}/sha256`, issues);
|
|
17358
|
+
} else if (ownership === "mixed") {
|
|
17359
|
+
requireExactKeys(item, path, [
|
|
17360
|
+
"path",
|
|
17361
|
+
"target",
|
|
17362
|
+
"templateId",
|
|
17363
|
+
"ownership",
|
|
17364
|
+
"regions"
|
|
17365
|
+
], issues);
|
|
17366
|
+
validatePath(item.path, `${path}/path`, issues);
|
|
17367
|
+
validateString(item.target, `${path}/target`, issues);
|
|
17368
|
+
validateString(item.templateId, `${path}/templateId`, issues);
|
|
17369
|
+
validateRegions(item.regions, `${path}/regions`, issues);
|
|
17370
|
+
} else if (ownership === "manual-owned") {
|
|
17371
|
+
requireExactKeys(item, path, [
|
|
17372
|
+
"path",
|
|
17373
|
+
"target",
|
|
17374
|
+
"templateId",
|
|
17375
|
+
"ownership"
|
|
17376
|
+
], issues);
|
|
17377
|
+
validatePath(item.path, `${path}/path`, issues);
|
|
17378
|
+
if (item.target !== "manual") issues.push(schemaIssue(`${path}/target`, "\"manual\"", describeValue(item.target)));
|
|
17379
|
+
if (item.templateId !== "manual") issues.push(schemaIssue(`${path}/templateId`, "\"manual\"", describeValue(item.templateId)));
|
|
17380
|
+
} else issues.push(schemaIssue(`${path}/ownership`, "\"generated-owned\" | \"mixed\" | \"manual-owned\"", describeValue(ownership)));
|
|
17381
|
+
const current = item;
|
|
17382
|
+
if (previous && compareLockOutputsV2(previous, current) > 0) issues.push({
|
|
17383
|
+
code: "lockfile_order_error",
|
|
17384
|
+
path,
|
|
17385
|
+
expected: "outputs sorted by path then target",
|
|
17386
|
+
actual: "out of order",
|
|
17387
|
+
message: `${path} is not in deterministic order.`
|
|
17388
|
+
});
|
|
17389
|
+
previous = current;
|
|
17390
|
+
});
|
|
17391
|
+
}
|
|
17392
|
+
function validateRegions(value, pathPrefix, issues) {
|
|
17393
|
+
if (!Array.isArray(value)) {
|
|
17394
|
+
issues.push(schemaIssue(pathPrefix, "array", describeValue(value)));
|
|
17395
|
+
return;
|
|
17396
|
+
}
|
|
17397
|
+
if (value.length !== 1) issues.push(schemaIssue(pathPrefix, "exactly one generated region", `${value.length} regions`));
|
|
17398
|
+
value.forEach((item, index) => {
|
|
17399
|
+
const path = `${pathPrefix}/${index}`;
|
|
17400
|
+
if (!isRecord(item)) {
|
|
17401
|
+
issues.push(schemaIssue(path, "object", describeValue(item)));
|
|
17402
|
+
return;
|
|
17403
|
+
}
|
|
17404
|
+
requireExactKeys(item, path, [
|
|
17405
|
+
"id",
|
|
17406
|
+
"target",
|
|
17407
|
+
"templateId",
|
|
17408
|
+
"sha256"
|
|
17409
|
+
], issues);
|
|
17410
|
+
if (item.id !== "agent-profile:generated") issues.push(schemaIssue(`${path}/id`, "\"agent-profile:generated\"", describeValue(item.id)));
|
|
17411
|
+
validateString(item.target, `${path}/target`, issues);
|
|
17412
|
+
validateString(item.templateId, `${path}/templateId`, issues);
|
|
17413
|
+
validateHash(item.sha256, `${path}/sha256`, issues);
|
|
17414
|
+
});
|
|
17415
|
+
}
|
|
17256
17416
|
function requireExactKeys(value, path, keys, issues) {
|
|
17257
17417
|
const allowed = new Set(keys);
|
|
17258
17418
|
for (const key of keys) if (!Object.prototype.hasOwnProperty.call(value, key)) issues.push(schemaIssue(`${path}/${escapeJsonPointerSegment(key)}`, "required property", "missing"));
|
|
@@ -17310,11 +17470,26 @@ function escapeJsonPointerSegment(segment) {
|
|
|
17310
17470
|
function isRecord(value) {
|
|
17311
17471
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17312
17472
|
}
|
|
17313
|
-
function
|
|
17473
|
+
function toLockOutputV2(file, mixedByPath) {
|
|
17474
|
+
const safePath = safeOutputPath(file.path);
|
|
17475
|
+
const mixed = mixedByPath.get(safePath);
|
|
17476
|
+
if (mixed) return {
|
|
17477
|
+
path: safePath,
|
|
17478
|
+
target: file.target,
|
|
17479
|
+
templateId: file.templateId,
|
|
17480
|
+
ownership: "mixed",
|
|
17481
|
+
regions: [{
|
|
17482
|
+
id: "agent-profile:generated",
|
|
17483
|
+
target: mixed.target,
|
|
17484
|
+
templateId: mixed.templateId,
|
|
17485
|
+
sha256: mixed.regionHash
|
|
17486
|
+
}]
|
|
17487
|
+
};
|
|
17314
17488
|
return {
|
|
17315
|
-
path:
|
|
17489
|
+
path: safePath,
|
|
17316
17490
|
target: file.target,
|
|
17317
17491
|
templateId: file.templateId,
|
|
17492
|
+
ownership: "generated-owned",
|
|
17318
17493
|
sha256: file.sha256
|
|
17319
17494
|
};
|
|
17320
17495
|
}
|
|
@@ -17324,6 +17499,274 @@ function compareLockTemplates(left, right) {
|
|
|
17324
17499
|
function compareLockOutputs(left, right) {
|
|
17325
17500
|
return compareText(left.path, right.path) || compareText(left.target, right.target);
|
|
17326
17501
|
}
|
|
17502
|
+
function compareLockOutputsV2(left, right) {
|
|
17503
|
+
return compareText(left.path, right.path) || compareText(left.target, right.target);
|
|
17504
|
+
}
|
|
17505
|
+
/**
|
|
17506
|
+
* Normalize a v1 or v2 lockfile to a uniform v2 view for consumers. v1
|
|
17507
|
+
* outputs are promoted to `generated-owned` outputs.
|
|
17508
|
+
*/
|
|
17509
|
+
function toLockfileV2View(lockfile) {
|
|
17510
|
+
if (lockfile.version === 2) return lockfile;
|
|
17511
|
+
return migrateLockfileV1ToV2(lockfile);
|
|
17512
|
+
}
|
|
17513
|
+
//#endregion
|
|
17514
|
+
//#region ../../packages/compiler/src/regions.ts
|
|
17515
|
+
var GENERATED_START_MARKER = "<!-- agent-profile:generated:start -->";
|
|
17516
|
+
var GENERATED_END_MARKER = "<!-- agent-profile:generated:end -->";
|
|
17517
|
+
var MANUAL_START_MARKER = "<!-- agent-profile:manual:start -->";
|
|
17518
|
+
var MANUAL_END_MARKER = "<!-- agent-profile:manual:end -->";
|
|
17519
|
+
var LEGACY_GENERATED_MARKER = "<!-- Generated by Agent Profile Compiler. Do not edit by hand. -->";
|
|
17520
|
+
var GENERATED_START_RE = /^<!-- agent-profile:generated:start -->$/u;
|
|
17521
|
+
var GENERATED_END_RE = /^<!-- agent-profile:generated:end -->$/u;
|
|
17522
|
+
var MANUAL_START_RE = /^<!-- agent-profile:manual:start -->$/u;
|
|
17523
|
+
var MANUAL_END_RE = /^<!-- agent-profile:manual:end -->$/u;
|
|
17524
|
+
/**
|
|
17525
|
+
* Parse a mixed-ownership instruction file (AGENTS.md or CLAUDE.md) into its
|
|
17526
|
+
* generated and manual regions. Raw bytes are preserved; no normalization is
|
|
17527
|
+
* applied so that hashes match the on-disk content exactly.
|
|
17528
|
+
*
|
|
17529
|
+
* The Phase 14 spec defines a strict file shape: the file begins with the
|
|
17530
|
+
* generated start marker, the two regions are separated by exactly one blank
|
|
17531
|
+
* line, and the file ends with the manual end marker plus a single trailing
|
|
17532
|
+
* newline. Markers that appear inside fenced code blocks (``` ... ```) are
|
|
17533
|
+
* not counted as region markers.
|
|
17534
|
+
*/
|
|
17535
|
+
function parseMixedFile(bytes) {
|
|
17536
|
+
const text = bytes.toString("utf8");
|
|
17537
|
+
const lineEndings = [];
|
|
17538
|
+
const lines = [];
|
|
17539
|
+
let position = 0;
|
|
17540
|
+
while (position < text.length) {
|
|
17541
|
+
const newlineIndex = text.indexOf("\n", position);
|
|
17542
|
+
if (newlineIndex === -1) {
|
|
17543
|
+
lines.push(text.slice(position));
|
|
17544
|
+
lineEndings.push("");
|
|
17545
|
+
break;
|
|
17546
|
+
}
|
|
17547
|
+
let lineEnd = newlineIndex;
|
|
17548
|
+
let ending = "\n";
|
|
17549
|
+
if (lineEnd > position && text[lineEnd - 1] === "\r") {
|
|
17550
|
+
lineEnd = newlineIndex - 1;
|
|
17551
|
+
ending = "\r\n";
|
|
17552
|
+
}
|
|
17553
|
+
lines.push(text.slice(position, lineEnd));
|
|
17554
|
+
lineEndings.push(ending);
|
|
17555
|
+
position = newlineIndex + 1;
|
|
17556
|
+
}
|
|
17557
|
+
const inFence = computeCodeFenceMask(lines);
|
|
17558
|
+
const matches = {
|
|
17559
|
+
generatedStart: [],
|
|
17560
|
+
generatedEnd: [],
|
|
17561
|
+
manualStart: [],
|
|
17562
|
+
manualEnd: []
|
|
17563
|
+
};
|
|
17564
|
+
lines.forEach((line, index) => {
|
|
17565
|
+
if (inFence[index]) return;
|
|
17566
|
+
if (GENERATED_START_RE.test(line)) matches.generatedStart.push(index);
|
|
17567
|
+
if (GENERATED_END_RE.test(line)) matches.generatedEnd.push(index);
|
|
17568
|
+
if (MANUAL_START_RE.test(line)) matches.manualStart.push(index);
|
|
17569
|
+
if (MANUAL_END_RE.test(line)) matches.manualEnd.push(index);
|
|
17570
|
+
});
|
|
17571
|
+
const issues = [];
|
|
17572
|
+
if (matches.generatedStart.length > 1 || matches.generatedEnd.length > 1 || matches.manualStart.length > 1 || matches.manualEnd.length > 1) {
|
|
17573
|
+
issues.push({
|
|
17574
|
+
code: "duplicate-markers",
|
|
17575
|
+
message: "Mixed instruction file contains duplicate generated/manual region markers."
|
|
17576
|
+
});
|
|
17577
|
+
return {
|
|
17578
|
+
ok: false,
|
|
17579
|
+
issues
|
|
17580
|
+
};
|
|
17581
|
+
}
|
|
17582
|
+
if (matches.generatedStart.length !== 1 || matches.generatedEnd.length !== 1 || matches.manualStart.length !== 1 || matches.manualEnd.length !== 1) {
|
|
17583
|
+
issues.push({
|
|
17584
|
+
code: "missing-markers",
|
|
17585
|
+
message: "Mixed instruction file is missing one or more required region markers."
|
|
17586
|
+
});
|
|
17587
|
+
return {
|
|
17588
|
+
ok: false,
|
|
17589
|
+
issues
|
|
17590
|
+
};
|
|
17591
|
+
}
|
|
17592
|
+
const gs = matches.generatedStart[0];
|
|
17593
|
+
const ge = matches.generatedEnd[0];
|
|
17594
|
+
const ms = matches.manualStart[0];
|
|
17595
|
+
const me = matches.manualEnd[0];
|
|
17596
|
+
if (!(gs < ge && ge < ms && ms < me)) {
|
|
17597
|
+
issues.push({
|
|
17598
|
+
code: "out-of-order",
|
|
17599
|
+
message: "Mixed instruction file region markers must appear in generated-start, generated-end, manual-start, manual-end order."
|
|
17600
|
+
});
|
|
17601
|
+
return {
|
|
17602
|
+
ok: false,
|
|
17603
|
+
issues
|
|
17604
|
+
};
|
|
17605
|
+
}
|
|
17606
|
+
if (gs !== 0) {
|
|
17607
|
+
issues.push({
|
|
17608
|
+
code: "preamble",
|
|
17609
|
+
message: "Mixed instruction file must begin with the generated start marker; no preamble bytes are allowed."
|
|
17610
|
+
});
|
|
17611
|
+
return {
|
|
17612
|
+
ok: false,
|
|
17613
|
+
issues
|
|
17614
|
+
};
|
|
17615
|
+
}
|
|
17616
|
+
if (ms !== ge + 2 || (lines[ge + 1] ?? "") !== "") {
|
|
17617
|
+
issues.push({
|
|
17618
|
+
code: "missing-blank-line",
|
|
17619
|
+
message: "Mixed instruction file must have exactly one blank line between the generated and manual regions."
|
|
17620
|
+
});
|
|
17621
|
+
return {
|
|
17622
|
+
ok: false,
|
|
17623
|
+
issues
|
|
17624
|
+
};
|
|
17625
|
+
}
|
|
17626
|
+
if (!(lines.length === me + 1 && (lineEndings[me] ?? "").length > 0)) {
|
|
17627
|
+
issues.push({
|
|
17628
|
+
code: "missing-trailing-newline",
|
|
17629
|
+
message: "Mixed instruction file must end with the manual end marker followed by exactly one trailing newline."
|
|
17630
|
+
});
|
|
17631
|
+
return {
|
|
17632
|
+
ok: false,
|
|
17633
|
+
issues
|
|
17634
|
+
};
|
|
17635
|
+
}
|
|
17636
|
+
const generatedInnerBytes = computeRangeBytes(bytes, lines, lineEndings, gs, ge);
|
|
17637
|
+
return {
|
|
17638
|
+
ok: true,
|
|
17639
|
+
generatedInner: generatedInnerBytes,
|
|
17640
|
+
manualInner: computeRangeBytes(bytes, lines, lineEndings, ms, me),
|
|
17641
|
+
generatedInnerHash: sha256Hex(generatedInnerBytes)
|
|
17642
|
+
};
|
|
17643
|
+
}
|
|
17644
|
+
function computeCodeFenceMask(lines) {
|
|
17645
|
+
const mask = new Array(lines.length).fill(false);
|
|
17646
|
+
let open = false;
|
|
17647
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
17648
|
+
const line = lines[index] ?? "";
|
|
17649
|
+
if (/^\s{0,3}(?:```|~~~)/u.test(line)) {
|
|
17650
|
+
mask[index] = open || true;
|
|
17651
|
+
open = !open;
|
|
17652
|
+
continue;
|
|
17653
|
+
}
|
|
17654
|
+
mask[index] = open;
|
|
17655
|
+
}
|
|
17656
|
+
return mask;
|
|
17657
|
+
}
|
|
17658
|
+
function computeRangeBytes(bytes, lines, lineEndings, startMarkerIndex, endMarkerIndex) {
|
|
17659
|
+
const startByte = computeByteOffsetAfterLine(lines, lineEndings, startMarkerIndex);
|
|
17660
|
+
const endByte = computeByteOffsetAtLineStart(lines, lineEndings, endMarkerIndex);
|
|
17661
|
+
return bytes.subarray(startByte, endByte);
|
|
17662
|
+
}
|
|
17663
|
+
function computeByteOffsetAfterLine(lines, lineEndings, lineIndex) {
|
|
17664
|
+
let offset = 0;
|
|
17665
|
+
for (let index = 0; index <= lineIndex; index += 1) {
|
|
17666
|
+
offset += Buffer.byteLength(lines[index] ?? "", "utf8");
|
|
17667
|
+
offset += Buffer.byteLength(lineEndings[index] ?? "", "utf8");
|
|
17668
|
+
}
|
|
17669
|
+
return offset;
|
|
17670
|
+
}
|
|
17671
|
+
function computeByteOffsetAtLineStart(lines, lineEndings, lineIndex) {
|
|
17672
|
+
let offset = 0;
|
|
17673
|
+
for (let index = 0; index < lineIndex; index += 1) {
|
|
17674
|
+
offset += Buffer.byteLength(lines[index] ?? "", "utf8");
|
|
17675
|
+
offset += Buffer.byteLength(lineEndings[index] ?? "", "utf8");
|
|
17676
|
+
}
|
|
17677
|
+
return offset;
|
|
17678
|
+
}
|
|
17679
|
+
/**
|
|
17680
|
+
* Quick predicate: do any of the four region markers appear in the file?
|
|
17681
|
+
* Used to detect partial markers and choose ownership. Marker lines inside
|
|
17682
|
+
* fenced code blocks (``` ... ``` / ~~~ ... ~~~) are not counted.
|
|
17683
|
+
*/
|
|
17684
|
+
function hasAnyRegionMarker(bytes) {
|
|
17685
|
+
const lines = bytes.toString("utf8").split(/\r?\n/u);
|
|
17686
|
+
const fence = computeCodeFenceMask(lines);
|
|
17687
|
+
return lines.some((line, index) => !fence[index] && (GENERATED_START_RE.test(line) || GENERATED_END_RE.test(line) || MANUAL_START_RE.test(line) || MANUAL_END_RE.test(line)));
|
|
17688
|
+
}
|
|
17689
|
+
function hasAllRegionMarkers(bytes) {
|
|
17690
|
+
const lines = bytes.toString("utf8").split(/\r?\n/u);
|
|
17691
|
+
const fence = computeCodeFenceMask(lines);
|
|
17692
|
+
const present = (re) => lines.some((line, index) => !fence[index] && re.test(line));
|
|
17693
|
+
return present(GENERATED_START_RE) && present(GENERATED_END_RE) && present(MANUAL_START_RE) && present(MANUAL_END_RE);
|
|
17694
|
+
}
|
|
17695
|
+
function hasLegacyGeneratedMarker(bytes) {
|
|
17696
|
+
return bytes.toString("utf8").split(/\r?\n/u).some((line) => line === LEGACY_GENERATED_MARKER);
|
|
17697
|
+
}
|
|
17698
|
+
/**
|
|
17699
|
+
* Build a mixed-ownership file from a generated inner body and a manual inner
|
|
17700
|
+
* body. The output uses LF line endings between markers and ends with a single
|
|
17701
|
+
* trailing newline.
|
|
17702
|
+
*
|
|
17703
|
+
* `generatedInner` is treated as the bytes strictly between the generated
|
|
17704
|
+
* markers (excluding marker lines). It is emitted verbatim; callers are
|
|
17705
|
+
* responsible for ensuring it is LF-normalized.
|
|
17706
|
+
*
|
|
17707
|
+
* `manualInner` is the bytes strictly between the manual markers and is
|
|
17708
|
+
* emitted verbatim with no normalization.
|
|
17709
|
+
*/
|
|
17710
|
+
function serializeMixedFile(input) {
|
|
17711
|
+
const manualInner = endsWithNewline(input.manualInner) ? input.manualInner : Buffer.concat([input.manualInner, Buffer.from("\n", "utf8")]);
|
|
17712
|
+
const parts = [
|
|
17713
|
+
Buffer.from(`${GENERATED_START_MARKER}\n`, "utf8"),
|
|
17714
|
+
input.generatedInner,
|
|
17715
|
+
Buffer.from(`${GENERATED_END_MARKER}\n`, "utf8"),
|
|
17716
|
+
Buffer.from("\n", "utf8"),
|
|
17717
|
+
Buffer.from(`${MANUAL_START_MARKER}\n`, "utf8"),
|
|
17718
|
+
manualInner,
|
|
17719
|
+
Buffer.from(`${MANUAL_END_MARKER}\n`, "utf8")
|
|
17720
|
+
];
|
|
17721
|
+
return Buffer.concat(parts);
|
|
17722
|
+
}
|
|
17723
|
+
function endsWithNewline(bytes) {
|
|
17724
|
+
if (bytes.length === 0) return false;
|
|
17725
|
+
return bytes[bytes.length - 1] === 10;
|
|
17726
|
+
}
|
|
17727
|
+
/**
|
|
17728
|
+
* Replace only the generated region of an existing mixed file with a new
|
|
17729
|
+
* generated inner body. The manual region bytes and surrounding shape are
|
|
17730
|
+
* preserved byte-for-byte.
|
|
17731
|
+
*
|
|
17732
|
+
* Returns `undefined` if the existing bytes are not a valid mixed file; the
|
|
17733
|
+
* caller must refuse to write in that case.
|
|
17734
|
+
*/
|
|
17735
|
+
function replaceGeneratedRegion(existing, newGeneratedInner) {
|
|
17736
|
+
if (!parseMixedFile(existing).ok) return void 0;
|
|
17737
|
+
const text = existing.toString("utf8");
|
|
17738
|
+
let cursor = 0;
|
|
17739
|
+
let position = 0;
|
|
17740
|
+
let generatedStartInnerByte = -1;
|
|
17741
|
+
let generatedEndLineStartByte = -1;
|
|
17742
|
+
while (position < text.length) {
|
|
17743
|
+
const newlineIndex = text.indexOf("\n", position);
|
|
17744
|
+
const hasNewline = newlineIndex !== -1;
|
|
17745
|
+
let lineEnd = hasNewline ? newlineIndex : text.length;
|
|
17746
|
+
let endingLength = 0;
|
|
17747
|
+
if (hasNewline) {
|
|
17748
|
+
endingLength = 1;
|
|
17749
|
+
if (lineEnd > position && text[lineEnd - 1] === "\r") {
|
|
17750
|
+
lineEnd -= 1;
|
|
17751
|
+
endingLength = 2;
|
|
17752
|
+
}
|
|
17753
|
+
}
|
|
17754
|
+
const line = text.slice(position, lineEnd);
|
|
17755
|
+
const lineBytes = Buffer.byteLength(line, "utf8");
|
|
17756
|
+
if (line === "<!-- agent-profile:generated:start -->" && generatedStartInnerByte === -1) generatedStartInnerByte = cursor + lineBytes + endingLength;
|
|
17757
|
+
if (line === "<!-- agent-profile:generated:end -->" && generatedEndLineStartByte === -1) generatedEndLineStartByte = cursor;
|
|
17758
|
+
cursor += lineBytes + endingLength;
|
|
17759
|
+
position = hasNewline ? newlineIndex + 1 : text.length;
|
|
17760
|
+
}
|
|
17761
|
+
if (generatedStartInnerByte === -1 || generatedEndLineStartByte === -1) return;
|
|
17762
|
+
const before = existing.subarray(0, generatedStartInnerByte);
|
|
17763
|
+
const after = existing.subarray(generatedEndLineStartByte);
|
|
17764
|
+
return Buffer.concat([
|
|
17765
|
+
before,
|
|
17766
|
+
newGeneratedInner,
|
|
17767
|
+
after
|
|
17768
|
+
]);
|
|
17769
|
+
}
|
|
17327
17770
|
//#endregion
|
|
17328
17771
|
//#region ../../packages/compiler/src/guidance-content.ts
|
|
17329
17772
|
var REACT_STACK_TOPIC = {
|
|
@@ -17542,6 +17985,14 @@ ${topic.agentsMdChecklistReference}
|
|
|
17542
17985
|
//#endregion
|
|
17543
17986
|
//#region ../../packages/compiler/src/compiler.ts
|
|
17544
17987
|
var WORKFLOW_SKILLS = [
|
|
17988
|
+
{
|
|
17989
|
+
id: "grill-change",
|
|
17990
|
+
workflowFlag: "sdd"
|
|
17991
|
+
},
|
|
17992
|
+
{
|
|
17993
|
+
id: "request-to-spec-issues",
|
|
17994
|
+
workflowFlag: "sdd"
|
|
17995
|
+
},
|
|
17545
17996
|
{
|
|
17546
17997
|
id: "sdd-change",
|
|
17547
17998
|
workflowFlag: "sdd"
|
|
@@ -17577,6 +18028,7 @@ var TEMPLATE_SOURCES = [
|
|
|
17577
18028
|
source: renderLockfileTemplateSource()
|
|
17578
18029
|
},
|
|
17579
18030
|
guidelineTemplateSource("targets/tabnine-guidelines/00-general-agent-behavior@1", renderGeneralAgentBehaviorTemplateSource),
|
|
18031
|
+
guidelineTemplateSource("targets/tabnine-guidelines/05-planning-workflow@1", renderPlanningWorkflowGuideline),
|
|
17580
18032
|
guidelineTemplateSource("targets/tabnine-guidelines/10-sdd-workflow@1", renderSddWorkflowGuideline),
|
|
17581
18033
|
guidelineTemplateSource("targets/tabnine-guidelines/20-tdd-workflow@1", renderTddWorkflowGuideline),
|
|
17582
18034
|
guidelineTemplateSource("targets/tabnine-guidelines/30-stack-typescript-svelte@1", renderTypeScriptSvelteGuideline),
|
|
@@ -17599,6 +18051,8 @@ var TEMPLATE_SOURCES = [
|
|
|
17599
18051
|
version: "1",
|
|
17600
18052
|
source: renderCodexConfigToml()
|
|
17601
18053
|
},
|
|
18054
|
+
workflowSkillTemplateSource("targets/codex-workflow-skills/grill-change@1", "codex-workflow-skills", "grill-change"),
|
|
18055
|
+
workflowSkillTemplateSource("targets/codex-workflow-skills/request-to-spec-issues@1", "codex-workflow-skills", "request-to-spec-issues"),
|
|
17602
18056
|
workflowSkillTemplateSource("targets/codex-workflow-skills/sdd-change@1", "codex-workflow-skills", "sdd-change"),
|
|
17603
18057
|
workflowSkillTemplateSource("targets/codex-workflow-skills/tdd-change@2", "codex-workflow-skills", "tdd-change"),
|
|
17604
18058
|
workflowSkillTemplateSource("targets/codex-workflow-skills/final-review@1", "codex-workflow-skills", "final-review"),
|
|
@@ -17621,6 +18075,8 @@ var TEMPLATE_SOURCES = [
|
|
|
17621
18075
|
version: "1",
|
|
17622
18076
|
source: renderClaudeMd()
|
|
17623
18077
|
},
|
|
18078
|
+
workflowSkillTemplateSource("targets/claude-workflow-skills/grill-change@1", "claude-workflow-skills", "grill-change"),
|
|
18079
|
+
workflowSkillTemplateSource("targets/claude-workflow-skills/request-to-spec-issues@1", "claude-workflow-skills", "request-to-spec-issues"),
|
|
17624
18080
|
workflowSkillTemplateSource("targets/claude-workflow-skills/sdd-change@1", "claude-workflow-skills", "sdd-change"),
|
|
17625
18081
|
workflowSkillTemplateSource("targets/claude-workflow-skills/tdd-change@2", "claude-workflow-skills", "tdd-change"),
|
|
17626
18082
|
workflowSkillTemplateSource("targets/claude-workflow-skills/final-review@1", "claude-workflow-skills", "final-review"),
|
|
@@ -17696,6 +18152,10 @@ function renderAgentsMd(profile) {
|
|
|
17696
18152
|
const documentationSection = profile.workflow.documentation === true ? `\n${renderTopicAsAgentsMdSection(DOCUMENTATION_TOPIC)}` : "";
|
|
17697
18153
|
return normalizeGeneratedText(`# AGENTS.md
|
|
17698
18154
|
|
|
18155
|
+
## Instruction Precedence
|
|
18156
|
+
|
|
18157
|
+
If generated and manual instructions conflict, follow the manual project instructions unless they would weaken safety, privacy, or permission limits. Safety, privacy, and explicit deny rules always win.
|
|
18158
|
+
|
|
17699
18159
|
## Project
|
|
17700
18160
|
|
|
17701
18161
|
Name: ${escapeMarkdownText(profile.profile.name)}
|
|
@@ -17755,6 +18215,10 @@ Cursor, Aider, Copilot, hosted gateways, enterprise RBAC, SIEM integrations, and
|
|
|
17755
18215
|
function renderClaudeMd() {
|
|
17756
18216
|
return `<!-- Generated by Agent Profile Compiler. Do not edit by hand. -->
|
|
17757
18217
|
|
|
18218
|
+
## Instruction Precedence
|
|
18219
|
+
|
|
18220
|
+
If generated and manual instructions conflict, follow the manual project instructions unless they would weaken safety, privacy, or permission limits. Safety, privacy, and explicit deny rules always win.
|
|
18221
|
+
|
|
17758
18222
|
@AGENTS.md
|
|
17759
18223
|
|
|
17760
18224
|
# Claude Code
|
|
@@ -17800,7 +18264,10 @@ function renderTarget(target, profile) {
|
|
|
17800
18264
|
function renderTabnineGuidelines(profile) {
|
|
17801
18265
|
const common = { target: "tabnine-guidelines" };
|
|
17802
18266
|
const files = [createGeneratedTextFile(".tabnine/guidelines/00-general-agent-behavior.md", common.target, "targets/tabnine-guidelines/00-general-agent-behavior@1", renderGeneralAgentBehaviorGuideline(profile))];
|
|
17803
|
-
if (profile.workflow.sdd)
|
|
18267
|
+
if (profile.workflow.sdd) {
|
|
18268
|
+
files.push(createGeneratedTextFile(".tabnine/guidelines/05-planning-workflow.md", common.target, "targets/tabnine-guidelines/05-planning-workflow@1", renderPlanningWorkflowGuideline()));
|
|
18269
|
+
files.push(createGeneratedTextFile(".tabnine/guidelines/10-sdd-workflow.md", common.target, "targets/tabnine-guidelines/10-sdd-workflow@1", renderSddWorkflowGuideline()));
|
|
18270
|
+
}
|
|
17804
18271
|
if (profile.workflow.tdd) files.push(createGeneratedTextFile(".tabnine/guidelines/20-tdd-workflow.md", common.target, "targets/tabnine-guidelines/20-tdd-workflow@1", renderTddWorkflowGuideline()));
|
|
17805
18272
|
if (hasStack(profile, "languages", "typescript") && hasStack(profile, "frameworks", "sveltekit")) files.push(createGeneratedTextFile(".tabnine/guidelines/30-stack-typescript-svelte.md", common.target, "targets/tabnine-guidelines/30-stack-typescript-svelte@1", renderTypeScriptSvelteGuideline()));
|
|
17806
18273
|
if (hasStack(profile, "frameworks", "react")) files.push(createGeneratedTextFile(".tabnine/guidelines/30-stack-typescript-react.md", common.target, "targets/tabnine-guidelines/30-stack-typescript-react@1", renderTypeScriptReactGuideline()));
|
|
@@ -17820,6 +18287,193 @@ function getWorkflowSkillTemplateId(target, skill) {
|
|
|
17820
18287
|
}
|
|
17821
18288
|
function renderWorkflowSkill(skill) {
|
|
17822
18289
|
switch (skill) {
|
|
18290
|
+
case "grill-change": return `---
|
|
18291
|
+
name: grill-change
|
|
18292
|
+
description: Use when a stakeholder request is rough, ambiguous, or underspecified and needs clarification before planning, writing a spec, or creating issues.
|
|
18293
|
+
---
|
|
18294
|
+
|
|
18295
|
+
<!-- Generated by Agent Profile Compiler. Do not edit by hand. -->
|
|
18296
|
+
|
|
18297
|
+
# Grill Change
|
|
18298
|
+
|
|
18299
|
+
## Purpose
|
|
18300
|
+
|
|
18301
|
+
Clarify a stakeholder request before any spec, issue plan, or implementation work starts. The output is an agreement record for a follow-up synthesis workflow; it is not an implementation plan.
|
|
18302
|
+
|
|
18303
|
+
## Operating Rules
|
|
18304
|
+
|
|
18305
|
+
1. Ask one focused question, then wait for the user's answer.
|
|
18306
|
+
2. Include a recommended answer with the question and explain why that answer is safest for the project.
|
|
18307
|
+
3. Inspect relevant local specs, ADRs, docs, fixtures, and code before asking questions that local context can answer.
|
|
18308
|
+
4. Challenge vague terms, overloaded words, and claims that conflict with repository evidence.
|
|
18309
|
+
5. Prefer concrete examples, edge cases, and tradeoff choices over broad brainstorming.
|
|
18310
|
+
6. Keep implementation details provisional until the product intent and non-goals are settled.
|
|
18311
|
+
7. Capture durable terms and hard-to-reverse decisions in the agreement record when they crystallize.
|
|
18312
|
+
8. Do not create issue lists, edit files, or start implementation during the grill.
|
|
18313
|
+
|
|
18314
|
+
## Question Format
|
|
18315
|
+
|
|
18316
|
+
Use this shape for each question:
|
|
18317
|
+
|
|
18318
|
+
Question: \`<one decision or missing fact>\`
|
|
18319
|
+
Recommended answer: \`<the default direction you would choose>\`
|
|
18320
|
+
Why: \`<short reason based on product intent, safety, contracts, or repo evidence>\`
|
|
18321
|
+
|
|
18322
|
+
## Decision Checks
|
|
18323
|
+
|
|
18324
|
+
Before ending the grill, confirm:
|
|
18325
|
+
|
|
18326
|
+
- the problem in the stakeholder's terms
|
|
18327
|
+
- the desired outcome
|
|
18328
|
+
- explicit non-goals
|
|
18329
|
+
- product intent and why the change matters
|
|
18330
|
+
- tradeoff direction for ambiguous implementation choices
|
|
18331
|
+
- user-visible behavior changes
|
|
18332
|
+
- compatibility and migration expectations
|
|
18333
|
+
- durable terminology and hard-to-reverse decisions
|
|
18334
|
+
- safety and privacy constraints
|
|
18335
|
+
- unresolved unknowns, if any
|
|
18336
|
+
|
|
18337
|
+
## Output
|
|
18338
|
+
|
|
18339
|
+
When the user agrees the grill is complete, return:
|
|
18340
|
+
|
|
18341
|
+
- Problem
|
|
18342
|
+
- Intent
|
|
18343
|
+
- Non-goals
|
|
18344
|
+
- Decisions made
|
|
18345
|
+
- Durable terms and hard-to-reverse decisions
|
|
18346
|
+
- Decision rules for implementation tradeoffs
|
|
18347
|
+
- Open questions or risks
|
|
18348
|
+
- Confirmation that post-grill synthesis can run next
|
|
18349
|
+
|
|
18350
|
+
## Safety
|
|
18351
|
+
|
|
18352
|
+
- Do not upload source code.
|
|
18353
|
+
- Do not read or print secrets.
|
|
18354
|
+
- Do not ask for credentials, environment values, production data, or private endpoints.
|
|
18355
|
+
- Do not propose \`bypassPermissions\`, tool pre-approval, dependency auto-installation, hosted execution, or remote MCP behavior.
|
|
18356
|
+
- Do not write files, create issues, commit changes, or run implementation commands during the grill.
|
|
18357
|
+
`;
|
|
18358
|
+
case "request-to-spec-issues": return `---
|
|
18359
|
+
name: request-to-spec-issues
|
|
18360
|
+
description: Use after a grill-change session is complete to turn the agreement record into an intent-first spec candidate and vertical TDD-ready issue briefs.
|
|
18361
|
+
---
|
|
18362
|
+
|
|
18363
|
+
<!-- Generated by Agent Profile Compiler. Do not edit by hand. -->
|
|
18364
|
+
|
|
18365
|
+
# Request To Spec Issues
|
|
18366
|
+
|
|
18367
|
+
## Purpose
|
|
18368
|
+
|
|
18369
|
+
Convert a completed \`grill-change\` agreement record into an intent-first spec candidate and vertical TDD-ready issue briefs. Preserve product intent and decision rules so implementation choices follow the agreed direction.
|
|
18370
|
+
|
|
18371
|
+
## Preconditions
|
|
18372
|
+
|
|
18373
|
+
- The grill is complete.
|
|
18374
|
+
- The user has confirmed the direction is ready for synthesis.
|
|
18375
|
+
- Relevant local specs, ADRs, docs, fixtures, and code context have been checked.
|
|
18376
|
+
- If there is no completed grill agreement, stop and run \`grill-change\` first.
|
|
18377
|
+
|
|
18378
|
+
## Synthesis Rules
|
|
18379
|
+
|
|
18380
|
+
1. Do not re-interview the user unless the grill record contains a contradiction or a genuinely missing decision.
|
|
18381
|
+
2. Keep product intent, non-goals, durable terms, and hard-to-reverse decisions above implementation mechanics.
|
|
18382
|
+
3. Preserve existing spec contracts and safety rules unless the user explicitly approved changing them.
|
|
18383
|
+
4. Split work into vertical behavior slices, not file layers.
|
|
18384
|
+
5. Make every issue small enough for a focused RED, GREEN, refactor loop.
|
|
18385
|
+
6. Mark dependencies and parallel-safe work explicitly.
|
|
18386
|
+
7. Propose architecture rescue candidates before feature slices when a change would deepen an already fragmented codebase.
|
|
18387
|
+
|
|
18388
|
+
## Architecture Rescue Candidates
|
|
18389
|
+
|
|
18390
|
+
When architecture rescue is needed, propose candidates before feature issues. Each candidate must include:
|
|
18391
|
+
|
|
18392
|
+
- Files or modules involved
|
|
18393
|
+
- Current friction
|
|
18394
|
+
- Proposed deeper module or clearer interface
|
|
18395
|
+
- Expected locality and leverage improvement
|
|
18396
|
+
- Expected test improvement
|
|
18397
|
+
- ADR or spec conflicts
|
|
18398
|
+
- Recommended dependency state: prerequisite, parallel, or later cleanup
|
|
18399
|
+
|
|
18400
|
+
## Spec Candidate
|
|
18401
|
+
|
|
18402
|
+
Include these sections:
|
|
18403
|
+
|
|
18404
|
+
- Status
|
|
18405
|
+
- Problem
|
|
18406
|
+
- Goal
|
|
18407
|
+
- Intent
|
|
18408
|
+
- Decision Rules
|
|
18409
|
+
- Non-Goals
|
|
18410
|
+
- User Flow
|
|
18411
|
+
- Inputs
|
|
18412
|
+
- Outputs
|
|
18413
|
+
- Contracts
|
|
18414
|
+
- Security Rules
|
|
18415
|
+
- Acceptance Criteria
|
|
18416
|
+
- Tests
|
|
18417
|
+
- TDD Strategy
|
|
18418
|
+
- Issue Plan
|
|
18419
|
+
- Documentation Updates
|
|
18420
|
+
- Final Review Checklist
|
|
18421
|
+
|
|
18422
|
+
\`TDD Strategy\` complements \`Tests\`; it must not replace the required \`Tests\`
|
|
18423
|
+
section from \`docs/specs/SPEC_TEMPLATE.md\`.
|
|
18424
|
+
|
|
18425
|
+
## Issue Brief Format
|
|
18426
|
+
|
|
18427
|
+
Each issue brief must include:
|
|
18428
|
+
|
|
18429
|
+
- Title
|
|
18430
|
+
- Parent spec or request
|
|
18431
|
+
- Intent summary
|
|
18432
|
+
- Behavior slice
|
|
18433
|
+
- Non-goals
|
|
18434
|
+
- Acceptance criteria
|
|
18435
|
+
- Expected RED proof
|
|
18436
|
+
- Expected GREEN proof
|
|
18437
|
+
- Test command guidance
|
|
18438
|
+
- Likely file ownership
|
|
18439
|
+
- Dependencies
|
|
18440
|
+
- Parallelism notes
|
|
18441
|
+
- Contract impact
|
|
18442
|
+
- Security impact
|
|
18443
|
+
- Documentation impact
|
|
18444
|
+
- Implementation context
|
|
18445
|
+
- Review expectations
|
|
18446
|
+
|
|
18447
|
+
## Dependency States
|
|
18448
|
+
|
|
18449
|
+
Use these states:
|
|
18450
|
+
|
|
18451
|
+
- \`ready\`
|
|
18452
|
+
- \`blocked\`
|
|
18453
|
+
- \`parallel-safe\`
|
|
18454
|
+
- \`sequenced\`
|
|
18455
|
+
- \`human-gate\`
|
|
18456
|
+
|
|
18457
|
+
## Output
|
|
18458
|
+
|
|
18459
|
+
Return:
|
|
18460
|
+
|
|
18461
|
+
- Spec candidate or spec patch
|
|
18462
|
+
- Vertical issue briefs
|
|
18463
|
+
- Dependency map
|
|
18464
|
+
- Parallelism map
|
|
18465
|
+
- Human gates
|
|
18466
|
+
- Recommended next step
|
|
18467
|
+
|
|
18468
|
+
## Safety
|
|
18469
|
+
|
|
18470
|
+
- Do not upload source code.
|
|
18471
|
+
- Do not read or print secrets.
|
|
18472
|
+
- Do not include credentials, environment values, production data, or private endpoints.
|
|
18473
|
+
- Do not create GitHub issues, labels, projects, or milestones.
|
|
18474
|
+
- Do not write files unless the user explicitly asks for local file writes after reviewing the synthesis.
|
|
18475
|
+
- Do not propose \`bypassPermissions\`, tool pre-approval, dependency auto-installation, hosted execution, or remote MCP behavior.
|
|
18476
|
+
`;
|
|
17823
18477
|
case "sdd-change": return `---
|
|
17824
18478
|
name: sdd-change
|
|
17825
18479
|
description: Use when implementing a meaningful repository change that requires an approved spec before code edits.
|
|
@@ -17989,6 +18643,23 @@ Use the repository-local profile as the source of truth for agent behavior.
|
|
|
17989
18643
|
- Ask before mutating files, running shell commands, installing dependencies, or using external network access.
|
|
17990
18644
|
`;
|
|
17991
18645
|
}
|
|
18646
|
+
function renderPlanningWorkflowGuideline() {
|
|
18647
|
+
return `<!-- Generated by Agent Profile Compiler. Do not edit by hand. -->
|
|
18648
|
+
|
|
18649
|
+
# Planning Workflow
|
|
18650
|
+
|
|
18651
|
+
Use this before implementation when a stakeholder request is rough, ambiguous, or not yet tied to an approved spec.
|
|
18652
|
+
|
|
18653
|
+
- Clarify the request one decision at a time before writing or changing specs.
|
|
18654
|
+
- Provide a recommended answer and short rationale for each open decision.
|
|
18655
|
+
- Check local specs, ADRs, docs, fixtures, and generated artifacts before asking questions.
|
|
18656
|
+
- Preserve product intent, non-goals, tradeoffs, durable terms, and hard-to-reverse decisions.
|
|
18657
|
+
- If no completed clarification exists, complete the grill-style clarification first.
|
|
18658
|
+
- After clarification, prepare an intent-first spec candidate and vertical TDD-ready issue briefs.
|
|
18659
|
+
- Include dependencies, expected RED proof, expected GREEN proof, file ownership, contract impact, security impact, and review expectations in each issue brief.
|
|
18660
|
+
- Do not create GitHub issues, write files, upload source, read secrets, install dependencies, or change runtime permissions unless explicitly requested and allowed.
|
|
18661
|
+
`;
|
|
18662
|
+
}
|
|
17992
18663
|
function renderSddWorkflowGuideline() {
|
|
17993
18664
|
return `<!-- Generated by Agent Profile Compiler. Do not edit by hand. -->
|
|
17994
18665
|
|
|
@@ -18129,9 +18800,9 @@ function renderClaudeSubagent(agent, effective) {
|
|
|
18129
18800
|
"Glob",
|
|
18130
18801
|
"Grep"
|
|
18131
18802
|
];
|
|
18132
|
-
if (effective.filesystem.write
|
|
18133
|
-
if (effective.shell.run
|
|
18134
|
-
if (effective.network.external
|
|
18803
|
+
if (effective.filesystem.write !== "deny") tools.push("Edit", "Write");
|
|
18804
|
+
if (effective.shell.run !== "deny") tools.push("Bash");
|
|
18805
|
+
if (effective.network.external !== "deny") tools.push("WebFetch");
|
|
18135
18806
|
lines.push(`tools: ${tools.join(", ")}`);
|
|
18136
18807
|
}
|
|
18137
18808
|
const model = agent.modelPreference ?? "inherit";
|
|
@@ -18406,7 +19077,10 @@ function getRequiredAgentsMdTopicTemplateIds(profile) {
|
|
|
18406
19077
|
}
|
|
18407
19078
|
function getRequiredTabnineGuidelineTemplateIds(profile) {
|
|
18408
19079
|
const ids = ["targets/tabnine-guidelines/00-general-agent-behavior@1"];
|
|
18409
|
-
if (profile.workflow.sdd)
|
|
19080
|
+
if (profile.workflow.sdd) {
|
|
19081
|
+
ids.push("targets/tabnine-guidelines/05-planning-workflow@1");
|
|
19082
|
+
ids.push("targets/tabnine-guidelines/10-sdd-workflow@1");
|
|
19083
|
+
}
|
|
18410
19084
|
if (profile.workflow.tdd) ids.push("targets/tabnine-guidelines/20-tdd-workflow@1");
|
|
18411
19085
|
if (hasStack(profile, "languages", "typescript") && hasStack(profile, "frameworks", "sveltekit")) ids.push("targets/tabnine-guidelines/30-stack-typescript-svelte@1");
|
|
18412
19086
|
if (hasStack(profile, "frameworks", "react")) ids.push("targets/tabnine-guidelines/30-stack-typescript-react@1");
|
|
@@ -18457,6 +19131,92 @@ function compareIssues(left, right) {
|
|
|
18457
19131
|
}
|
|
18458
19132
|
//#endregion
|
|
18459
19133
|
//#region ../../packages/compiler/src/write-plan.ts
|
|
19134
|
+
async function planWrites(request) {
|
|
19135
|
+
return planWritesWithResolvedRoot(await fsPromises.realpath(path.resolve(request.rootDir)), request.writes);
|
|
19136
|
+
}
|
|
19137
|
+
async function planWritesWithResolvedRoot(rootRealPath, plannedWrites) {
|
|
19138
|
+
const writes = normalizeWrites(plannedWrites);
|
|
19139
|
+
const actions = [];
|
|
19140
|
+
for (const write of writes) {
|
|
19141
|
+
const current = await readOptionalFile(await assertWritePathContained(rootRealPath, write.path));
|
|
19142
|
+
const action = current ? Buffer.from(current).equals(Buffer.from(write.bytes)) ? "unchanged" : "change" : "create";
|
|
19143
|
+
actions.push({
|
|
19144
|
+
path: write.path,
|
|
19145
|
+
action,
|
|
19146
|
+
plannedBytes: write.bytes.byteLength
|
|
19147
|
+
});
|
|
19148
|
+
}
|
|
19149
|
+
return {
|
|
19150
|
+
actions,
|
|
19151
|
+
counts: countActions(actions)
|
|
19152
|
+
};
|
|
19153
|
+
}
|
|
19154
|
+
async function applyWritePlan(request) {
|
|
19155
|
+
const rootRealPath = await fsPromises.realpath(path.resolve(request.rootDir));
|
|
19156
|
+
const writes = normalizeWrites(request.writes);
|
|
19157
|
+
const plan = await planWritesWithResolvedRoot(rootRealPath, writes);
|
|
19158
|
+
const writesByPath = new Map(writes.map((write) => [write.path, write]));
|
|
19159
|
+
for (const action of plan.actions) {
|
|
19160
|
+
if (action.action === "unchanged") continue;
|
|
19161
|
+
const write = writesByPath.get(action.path);
|
|
19162
|
+
if (!write) continue;
|
|
19163
|
+
const absolutePath = await assertWritePathContained(rootRealPath, write.path);
|
|
19164
|
+
await fsPromises.mkdir(path.dirname(absolutePath), { recursive: true });
|
|
19165
|
+
await fsPromises.writeFile(absolutePath, write.bytes);
|
|
19166
|
+
}
|
|
19167
|
+
return plan;
|
|
19168
|
+
}
|
|
19169
|
+
function normalizeWrites(writes) {
|
|
19170
|
+
return writes.map((write) => ({
|
|
19171
|
+
path: safeOutputPath(write.path),
|
|
19172
|
+
bytes: typeof write.bytes === "string" ? Buffer.from(write.bytes, "utf8") : write.bytes
|
|
19173
|
+
})).sort((left, right) => compareText(left.path, right.path));
|
|
19174
|
+
}
|
|
19175
|
+
function countActions(actions) {
|
|
19176
|
+
return {
|
|
19177
|
+
create: actions.filter((action) => action.action === "create").length,
|
|
19178
|
+
change: actions.filter((action) => action.action === "change").length,
|
|
19179
|
+
unchanged: actions.filter((action) => action.action === "unchanged").length
|
|
19180
|
+
};
|
|
19181
|
+
}
|
|
19182
|
+
async function assertWritePathContained(rootRealPath, relativePath) {
|
|
19183
|
+
const safePath = safeOutputPath(relativePath);
|
|
19184
|
+
const absolutePath = path.resolve(rootRealPath, ...safePath.split("/").filter(Boolean));
|
|
19185
|
+
if (!isContainedBy(rootRealPath, absolutePath)) throw new Error(`Planned write escapes root: ${safePath}`);
|
|
19186
|
+
const existingTarget = await lstatOptional$1(absolutePath);
|
|
19187
|
+
if (existingTarget) {
|
|
19188
|
+
if (existingTarget.isSymbolicLink()) throw new Error(`Planned write target is a symlink (refusing to follow): ${safePath}`);
|
|
19189
|
+
if (!isContainedBy(rootRealPath, await fsPromises.realpath(absolutePath))) throw new Error(`Planned write target escapes root: ${safePath}`);
|
|
19190
|
+
}
|
|
19191
|
+
const existingParent = await findExistingAncestor(path.dirname(absolutePath));
|
|
19192
|
+
if (!isContainedBy(rootRealPath, await fsPromises.realpath(existingParent))) throw new Error(`Planned write parent escapes root: ${safePath}`);
|
|
19193
|
+
return absolutePath;
|
|
19194
|
+
}
|
|
19195
|
+
async function findExistingAncestor(startPath) {
|
|
19196
|
+
let current = startPath;
|
|
19197
|
+
while (true) {
|
|
19198
|
+
if (await lstatOptional$1(current)) return current;
|
|
19199
|
+
const parent = path.dirname(current);
|
|
19200
|
+
if (parent === current) throw new Error(`No existing parent directory for ${startPath}`);
|
|
19201
|
+
current = parent;
|
|
19202
|
+
}
|
|
19203
|
+
}
|
|
19204
|
+
async function readOptionalFile(absolutePath) {
|
|
19205
|
+
try {
|
|
19206
|
+
return await fsPromises.readFile(absolutePath);
|
|
19207
|
+
} catch (error) {
|
|
19208
|
+
if (isNodeError(error) && error.code === "ENOENT") return;
|
|
19209
|
+
throw error;
|
|
19210
|
+
}
|
|
19211
|
+
}
|
|
19212
|
+
async function lstatOptional$1(absolutePath) {
|
|
19213
|
+
try {
|
|
19214
|
+
return await fsPromises.lstat(absolutePath);
|
|
19215
|
+
} catch (error) {
|
|
19216
|
+
if (isNodeError(error) && error.code === "ENOENT") return;
|
|
19217
|
+
throw error;
|
|
19218
|
+
}
|
|
19219
|
+
}
|
|
18460
19220
|
function isContainedBy(rootPath, candidatePath) {
|
|
18461
19221
|
const relative = path.relative(rootPath, candidatePath);
|
|
18462
19222
|
return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
@@ -18551,6 +19311,599 @@ function computeFileEtag(bytes) {
|
|
|
18551
19311
|
return "sha256:" + createHash("sha256").update(bytes).digest("hex");
|
|
18552
19312
|
}
|
|
18553
19313
|
//#endregion
|
|
19314
|
+
//#region ../../packages/compiler/src/import-report.ts
|
|
19315
|
+
var PHASE_14_SUPPORTED_PATHS = [
|
|
19316
|
+
{
|
|
19317
|
+
path: "AGENTS.md",
|
|
19318
|
+
kind: "root-instructions",
|
|
19319
|
+
isLocalRuntime: false
|
|
19320
|
+
},
|
|
19321
|
+
{
|
|
19322
|
+
path: "CLAUDE.md",
|
|
19323
|
+
kind: "root-instructions",
|
|
19324
|
+
isLocalRuntime: false
|
|
19325
|
+
},
|
|
19326
|
+
{
|
|
19327
|
+
path: ".claude/settings.json",
|
|
19328
|
+
kind: "client-config",
|
|
19329
|
+
isLocalRuntime: false
|
|
19330
|
+
},
|
|
19331
|
+
{
|
|
19332
|
+
path: ".claude/settings.local.json",
|
|
19333
|
+
kind: "client-config",
|
|
19334
|
+
isLocalRuntime: true
|
|
19335
|
+
},
|
|
19336
|
+
{
|
|
19337
|
+
path: ".codex/config.toml",
|
|
19338
|
+
kind: "client-config",
|
|
19339
|
+
isLocalRuntime: true
|
|
19340
|
+
},
|
|
19341
|
+
{
|
|
19342
|
+
path: ".codex/hooks.json",
|
|
19343
|
+
kind: "client-config",
|
|
19344
|
+
isLocalRuntime: true
|
|
19345
|
+
},
|
|
19346
|
+
{
|
|
19347
|
+
path: ".mcp.json",
|
|
19348
|
+
kind: "mcp-config",
|
|
19349
|
+
isLocalRuntime: true
|
|
19350
|
+
}
|
|
19351
|
+
];
|
|
19352
|
+
var PHASE_14_SCAN_DIRS = [
|
|
19353
|
+
{
|
|
19354
|
+
root: ".agents/skills",
|
|
19355
|
+
kind: "workflow-skill",
|
|
19356
|
+
fileFilter: (rel) => rel.endsWith("/SKILL.md"),
|
|
19357
|
+
recursive: true
|
|
19358
|
+
},
|
|
19359
|
+
{
|
|
19360
|
+
root: ".claude/skills",
|
|
19361
|
+
kind: "workflow-skill",
|
|
19362
|
+
fileFilter: (rel) => rel.endsWith("/SKILL.md"),
|
|
19363
|
+
recursive: true
|
|
19364
|
+
},
|
|
19365
|
+
{
|
|
19366
|
+
root: ".claude/agents",
|
|
19367
|
+
kind: "subagent",
|
|
19368
|
+
fileFilter: (rel) => rel.endsWith(".md"),
|
|
19369
|
+
recursive: false
|
|
19370
|
+
},
|
|
19371
|
+
{
|
|
19372
|
+
root: ".codex/agents",
|
|
19373
|
+
kind: "subagent",
|
|
19374
|
+
fileFilter: (rel) => rel.endsWith(".toml"),
|
|
19375
|
+
recursive: false
|
|
19376
|
+
},
|
|
19377
|
+
{
|
|
19378
|
+
root: ".tabnine/agent/agents",
|
|
19379
|
+
kind: "subagent",
|
|
19380
|
+
fileFilter: (rel) => rel.endsWith(".md"),
|
|
19381
|
+
recursive: false
|
|
19382
|
+
}
|
|
19383
|
+
];
|
|
19384
|
+
var RECOMMENDED_IGNORE_LINES = [
|
|
19385
|
+
".cce/",
|
|
19386
|
+
".mcp.json",
|
|
19387
|
+
".claude/settings.local.json",
|
|
19388
|
+
".claude/worktrees/",
|
|
19389
|
+
".codex/config.toml",
|
|
19390
|
+
".codex/hooks.json"
|
|
19391
|
+
];
|
|
19392
|
+
async function buildPhase14ImportReport(input) {
|
|
19393
|
+
const files = [];
|
|
19394
|
+
let wouldUpdateRegions = 0;
|
|
19395
|
+
let preservedManualFiles = 0;
|
|
19396
|
+
let conflicts = 0;
|
|
19397
|
+
const collisionsByKey = /* @__PURE__ */ new Map();
|
|
19398
|
+
const lockfile = await readLockfileForRegions(input.rootDir);
|
|
19399
|
+
const ownershipByPath = /* @__PURE__ */ new Map();
|
|
19400
|
+
if (lockfile) for (const output of lockfile.outputs) ownershipByPath.set(output.path, output.ownership);
|
|
19401
|
+
for (const entry of PHASE_14_SUPPORTED_PATHS) {
|
|
19402
|
+
const read = await readRegionAwareFile(input.rootDir, entry.path);
|
|
19403
|
+
if (read.refused) {
|
|
19404
|
+
files.push({
|
|
19405
|
+
path: entry.path,
|
|
19406
|
+
exists: true,
|
|
19407
|
+
kind: entry.kind,
|
|
19408
|
+
ownership: "unknown",
|
|
19409
|
+
tags: [],
|
|
19410
|
+
action: "refuse-conflict",
|
|
19411
|
+
notes: ["symlinked; Phase 14 refuses to follow file symlinks"]
|
|
19412
|
+
});
|
|
19413
|
+
conflicts += 1;
|
|
19414
|
+
continue;
|
|
19415
|
+
}
|
|
19416
|
+
const existing = read.bytes;
|
|
19417
|
+
if (!existing) {
|
|
19418
|
+
if (entry.kind === "root-instructions") files.push({
|
|
19419
|
+
path: entry.path,
|
|
19420
|
+
exists: false,
|
|
19421
|
+
kind: entry.kind,
|
|
19422
|
+
ownership: "unknown",
|
|
19423
|
+
tags: [],
|
|
19424
|
+
action: "create",
|
|
19425
|
+
notes: []
|
|
19426
|
+
});
|
|
19427
|
+
continue;
|
|
19428
|
+
}
|
|
19429
|
+
const bytes = Buffer.from(existing);
|
|
19430
|
+
const tags = [];
|
|
19431
|
+
if (entry.isLocalRuntime) tags.push("local-runtime");
|
|
19432
|
+
if (containsAbsolutePathLiteral(bytes)) tags.push("contains-absolute-path");
|
|
19433
|
+
if (entry.kind === "client-config" && !entry.isLocalRuntime) {
|
|
19434
|
+
const ownership = ownershipByPath.get(entry.path) ?? "generated-owned";
|
|
19435
|
+
files.push({
|
|
19436
|
+
path: entry.path,
|
|
19437
|
+
exists: true,
|
|
19438
|
+
kind: entry.kind,
|
|
19439
|
+
ownership,
|
|
19440
|
+
tags,
|
|
19441
|
+
action: "preserve",
|
|
19442
|
+
notes: ["generated client config; refresh via `agent-profile compile --write`"]
|
|
19443
|
+
});
|
|
19444
|
+
preservedManualFiles += 1;
|
|
19445
|
+
continue;
|
|
19446
|
+
}
|
|
19447
|
+
if (entry.kind !== "root-instructions") {
|
|
19448
|
+
files.push({
|
|
19449
|
+
path: entry.path,
|
|
19450
|
+
exists: true,
|
|
19451
|
+
kind: entry.kind,
|
|
19452
|
+
ownership: "manual-owned",
|
|
19453
|
+
tags,
|
|
19454
|
+
action: "ignore-local-runtime",
|
|
19455
|
+
notes: entry.kind === "mcp-config" ? ["contains MCP entries; not imported into ai-profile.yaml in Phase 14"] : ["local runtime config; not adopted by Phase 14"]
|
|
19456
|
+
});
|
|
19457
|
+
preservedManualFiles += 1;
|
|
19458
|
+
continue;
|
|
19459
|
+
}
|
|
19460
|
+
if (hasAllRegionMarkers(bytes)) {
|
|
19461
|
+
const parsed = parseMixedFile(bytes);
|
|
19462
|
+
if (!parsed.ok) {
|
|
19463
|
+
files.push({
|
|
19464
|
+
path: entry.path,
|
|
19465
|
+
exists: true,
|
|
19466
|
+
kind: entry.kind,
|
|
19467
|
+
ownership: "unknown",
|
|
19468
|
+
tags,
|
|
19469
|
+
action: "refuse-conflict",
|
|
19470
|
+
notes: parsed.issues.map((item) => item.message)
|
|
19471
|
+
});
|
|
19472
|
+
conflicts += 1;
|
|
19473
|
+
continue;
|
|
19474
|
+
}
|
|
19475
|
+
files.push({
|
|
19476
|
+
path: entry.path,
|
|
19477
|
+
exists: true,
|
|
19478
|
+
kind: entry.kind,
|
|
19479
|
+
ownership: "mixed",
|
|
19480
|
+
tags,
|
|
19481
|
+
action: "update-generated-region",
|
|
19482
|
+
notes: []
|
|
19483
|
+
});
|
|
19484
|
+
if (input.strategy === "regions") wouldUpdateRegions += 1;
|
|
19485
|
+
continue;
|
|
19486
|
+
}
|
|
19487
|
+
if (hasAnyRegionMarker(bytes)) {
|
|
19488
|
+
files.push({
|
|
19489
|
+
path: entry.path,
|
|
19490
|
+
exists: true,
|
|
19491
|
+
kind: entry.kind,
|
|
19492
|
+
ownership: "unknown",
|
|
19493
|
+
tags,
|
|
19494
|
+
action: "refuse-conflict",
|
|
19495
|
+
notes: ["partial region markers; manual repair required"]
|
|
19496
|
+
});
|
|
19497
|
+
conflicts += 1;
|
|
19498
|
+
continue;
|
|
19499
|
+
}
|
|
19500
|
+
if (hasLegacyGeneratedMarker(bytes)) tags.push("generated-looking");
|
|
19501
|
+
if (input.strategy === "regions") {
|
|
19502
|
+
files.push({
|
|
19503
|
+
path: entry.path,
|
|
19504
|
+
exists: true,
|
|
19505
|
+
kind: entry.kind,
|
|
19506
|
+
ownership: "unknown",
|
|
19507
|
+
tags,
|
|
19508
|
+
action: "insert-regions",
|
|
19509
|
+
notes: ["existing content will be preserved in manual region"]
|
|
19510
|
+
});
|
|
19511
|
+
wouldUpdateRegions += 1;
|
|
19512
|
+
} else {
|
|
19513
|
+
files.push({
|
|
19514
|
+
path: entry.path,
|
|
19515
|
+
exists: true,
|
|
19516
|
+
kind: entry.kind,
|
|
19517
|
+
ownership: "unknown",
|
|
19518
|
+
tags,
|
|
19519
|
+
action: "preserve",
|
|
19520
|
+
notes: ["Run init --import --strategy regions --write to adopt into mixed ownership"]
|
|
19521
|
+
});
|
|
19522
|
+
preservedManualFiles += 1;
|
|
19523
|
+
}
|
|
19524
|
+
}
|
|
19525
|
+
for (const scan of PHASE_14_SCAN_DIRS) {
|
|
19526
|
+
const { files: discovered, refusals: scanRefusals } = await listFilesUnder(input.rootDir, scan.root, scan.recursive);
|
|
19527
|
+
for (const refusedPath of scanRefusals) {
|
|
19528
|
+
files.push({
|
|
19529
|
+
path: refusedPath,
|
|
19530
|
+
exists: true,
|
|
19531
|
+
kind: scan.kind,
|
|
19532
|
+
ownership: "unknown",
|
|
19533
|
+
tags: [],
|
|
19534
|
+
action: "refuse-conflict",
|
|
19535
|
+
notes: ["symlinked; Phase 14 refuses to follow file symlinks"]
|
|
19536
|
+
});
|
|
19537
|
+
conflicts += 1;
|
|
19538
|
+
}
|
|
19539
|
+
for (const relativePath of discovered) {
|
|
19540
|
+
if (!scan.fileFilter(relativePath)) continue;
|
|
19541
|
+
const read = await readRegionAwareFile(input.rootDir, relativePath);
|
|
19542
|
+
const tags = [];
|
|
19543
|
+
if (read.bytes) {
|
|
19544
|
+
const name = extractDeclaredName(Buffer.from(read.bytes), relativePath);
|
|
19545
|
+
if (name) recordName(scan.kind === "workflow-skill" ? "workflow-skill" : "subagent", name, relativePath, collisionsByKey);
|
|
19546
|
+
}
|
|
19547
|
+
if (read.refused) {
|
|
19548
|
+
files.push({
|
|
19549
|
+
path: relativePath,
|
|
19550
|
+
exists: true,
|
|
19551
|
+
kind: scan.kind,
|
|
19552
|
+
ownership: "unknown",
|
|
19553
|
+
tags,
|
|
19554
|
+
action: "refuse-conflict",
|
|
19555
|
+
notes: ["symlinked; Phase 14 refuses to follow file symlinks"]
|
|
19556
|
+
});
|
|
19557
|
+
conflicts += 1;
|
|
19558
|
+
continue;
|
|
19559
|
+
}
|
|
19560
|
+
if (!read.bytes) continue;
|
|
19561
|
+
const lockOwnership = ownershipByPath.get(relativePath);
|
|
19562
|
+
if (lockOwnership === "generated-owned") {
|
|
19563
|
+
files.push({
|
|
19564
|
+
path: relativePath,
|
|
19565
|
+
exists: true,
|
|
19566
|
+
kind: scan.kind,
|
|
19567
|
+
ownership: "generated-owned",
|
|
19568
|
+
tags,
|
|
19569
|
+
action: "preserve",
|
|
19570
|
+
notes: ["lockfile-owned generated output; refresh via `agent-profile compile --write`"]
|
|
19571
|
+
});
|
|
19572
|
+
preservedManualFiles += 1;
|
|
19573
|
+
continue;
|
|
19574
|
+
}
|
|
19575
|
+
if (lockOwnership === "mixed") {
|
|
19576
|
+
files.push({
|
|
19577
|
+
path: relativePath,
|
|
19578
|
+
exists: true,
|
|
19579
|
+
kind: scan.kind,
|
|
19580
|
+
ownership: "mixed",
|
|
19581
|
+
tags,
|
|
19582
|
+
action: "update-generated-region",
|
|
19583
|
+
notes: ["lockfile-owned mixed file; generated region is updated on compile --write"]
|
|
19584
|
+
});
|
|
19585
|
+
if (input.strategy === "regions") wouldUpdateRegions += 1;
|
|
19586
|
+
continue;
|
|
19587
|
+
}
|
|
19588
|
+
files.push({
|
|
19589
|
+
path: relativePath,
|
|
19590
|
+
exists: true,
|
|
19591
|
+
kind: scan.kind,
|
|
19592
|
+
ownership: "manual-owned",
|
|
19593
|
+
tags,
|
|
19594
|
+
action: "preserve",
|
|
19595
|
+
notes: [scan.kind === "workflow-skill" ? "existing workflow skill; not adopted as generated output" : "existing subagent file; not adopted as generated output"]
|
|
19596
|
+
});
|
|
19597
|
+
preservedManualFiles += 1;
|
|
19598
|
+
}
|
|
19599
|
+
}
|
|
19600
|
+
const gitignore = (await getLocalRuntimeGitignoreFindings(input.rootDir)).map((finding) => ({
|
|
19601
|
+
path: ".gitignore",
|
|
19602
|
+
line: finding.line,
|
|
19603
|
+
action: finding.action === "already-present" ? "already-present" : input.mode === "write" ? "would-add" : "suggest-add",
|
|
19604
|
+
reason: finding.reason
|
|
19605
|
+
}));
|
|
19606
|
+
const collisions = [];
|
|
19607
|
+
for (const [key, paths] of collisionsByKey) {
|
|
19608
|
+
if (paths.length < 2) continue;
|
|
19609
|
+
const [kindPart, name] = key.split("\0");
|
|
19610
|
+
collisions.push({
|
|
19611
|
+
name,
|
|
19612
|
+
kind: kindPart === "workflow-skill" ? "workflow-skill" : "subagent",
|
|
19613
|
+
paths: [...paths].sort()
|
|
19614
|
+
});
|
|
19615
|
+
for (const collidingPath of paths) {
|
|
19616
|
+
const row = files.find((f) => f.path === collidingPath);
|
|
19617
|
+
if (row && !row.notes.some((n) => n.startsWith("name collision"))) {
|
|
19618
|
+
const others = paths.filter((p) => p !== collidingPath).sort();
|
|
19619
|
+
row.notes.push(`name collision: \"${name}\" also declared by ${others.join(", ")}`);
|
|
19620
|
+
}
|
|
19621
|
+
}
|
|
19622
|
+
}
|
|
19623
|
+
collisions.sort((left, right) => {
|
|
19624
|
+
if (left.kind !== right.kind) return left.kind === "workflow-skill" ? -1 : 1;
|
|
19625
|
+
return left.name < right.name ? -1 : left.name > right.name ? 1 : 0;
|
|
19626
|
+
});
|
|
19627
|
+
return {
|
|
19628
|
+
command: "init",
|
|
19629
|
+
mode: input.mode,
|
|
19630
|
+
strategy: input.strategy,
|
|
19631
|
+
root: ".",
|
|
19632
|
+
profilePath: input.profilePath,
|
|
19633
|
+
stack: {
|
|
19634
|
+
languages: [...input.stack.languages].sort(),
|
|
19635
|
+
frameworks: [...input.stack.frameworks].sort(),
|
|
19636
|
+
packageManagers: [...input.stack.packageManagers].sort(),
|
|
19637
|
+
testing: [...input.stack.testing].sort()
|
|
19638
|
+
},
|
|
19639
|
+
files: files.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0),
|
|
19640
|
+
gitignore,
|
|
19641
|
+
collisions,
|
|
19642
|
+
summary: {
|
|
19643
|
+
wouldCreateProfile: input.wouldCreateProfile,
|
|
19644
|
+
wouldUpdateRegions,
|
|
19645
|
+
preservedManualFiles,
|
|
19646
|
+
conflicts,
|
|
19647
|
+
nameCollisions: collisions.length
|
|
19648
|
+
}
|
|
19649
|
+
};
|
|
19650
|
+
}
|
|
19651
|
+
function recordName(kind, name, path, map) {
|
|
19652
|
+
const key = `${kind}\0${name}`;
|
|
19653
|
+
const existing = map.get(key);
|
|
19654
|
+
if (existing) existing.push(path);
|
|
19655
|
+
else map.set(key, [path]);
|
|
19656
|
+
}
|
|
19657
|
+
/**
|
|
19658
|
+
* Extract the declared `name:` value from a SKILL.md / claude-style
|
|
19659
|
+
* subagent (.md with YAML frontmatter) or codex-style subagent (.toml).
|
|
19660
|
+
*
|
|
19661
|
+
* This deliberately avoids pulling in a YAML or TOML parser — the
|
|
19662
|
+
* relevant section is small, the line shape is fixed, and we want the
|
|
19663
|
+
* shared report module to stay dependency-light. Returns undefined when
|
|
19664
|
+
* no name is found; callers treat that as "this file does not
|
|
19665
|
+
* participate in collision detection."
|
|
19666
|
+
*/
|
|
19667
|
+
function extractDeclaredName(bytes, relativePath) {
|
|
19668
|
+
const text = bytes.toString("utf8");
|
|
19669
|
+
if (relativePath.endsWith(".toml")) return findTomlTopLevelName(text);
|
|
19670
|
+
if (relativePath.endsWith(".md")) return findYamlFrontmatterName(text);
|
|
19671
|
+
}
|
|
19672
|
+
function findYamlFrontmatterName(text) {
|
|
19673
|
+
const lines = text.split(/\r?\n/u);
|
|
19674
|
+
if (lines.length === 0 || lines[0].trim() !== "---") return void 0;
|
|
19675
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
19676
|
+
const line = lines[index];
|
|
19677
|
+
if (line.trim() === "---") return void 0;
|
|
19678
|
+
if (!line.startsWith("name")) continue;
|
|
19679
|
+
const match = line.match(/^name\s*:\s*(.+?)\s*$/u);
|
|
19680
|
+
if (!match) continue;
|
|
19681
|
+
return stripYamlQuotes(match[1]);
|
|
19682
|
+
}
|
|
19683
|
+
}
|
|
19684
|
+
function findTomlTopLevelName(text) {
|
|
19685
|
+
const lines = text.split(/\r?\n/u);
|
|
19686
|
+
for (const line of lines) {
|
|
19687
|
+
const trimmed = line.trim();
|
|
19688
|
+
if (trimmed.startsWith("#") || trimmed === "") continue;
|
|
19689
|
+
if (trimmed.startsWith("[")) break;
|
|
19690
|
+
const match = trimmed.match(/^name\s*=\s*(.+?)\s*$/u);
|
|
19691
|
+
if (!match) continue;
|
|
19692
|
+
return stripTomlQuotes(stripInlineTomlComment(match[1]));
|
|
19693
|
+
}
|
|
19694
|
+
}
|
|
19695
|
+
function stripInlineTomlComment(value) {
|
|
19696
|
+
let inDoubleQuote = false;
|
|
19697
|
+
let inSingleQuote = false;
|
|
19698
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
19699
|
+
const char = value[index];
|
|
19700
|
+
if (char === "\"" && !inSingleQuote) {
|
|
19701
|
+
if (inDoubleQuote && value[index - 1] === "\\") continue;
|
|
19702
|
+
inDoubleQuote = !inDoubleQuote;
|
|
19703
|
+
continue;
|
|
19704
|
+
}
|
|
19705
|
+
if (char === "'" && !inDoubleQuote) {
|
|
19706
|
+
inSingleQuote = !inSingleQuote;
|
|
19707
|
+
continue;
|
|
19708
|
+
}
|
|
19709
|
+
if (char === "#" && !inDoubleQuote && !inSingleQuote) return value.slice(0, index).replace(/\s+$/u, "");
|
|
19710
|
+
}
|
|
19711
|
+
return value.replace(/\s+$/u, "");
|
|
19712
|
+
}
|
|
19713
|
+
function stripYamlQuotes(value) {
|
|
19714
|
+
if (value.length >= 2) {
|
|
19715
|
+
const first = value[0];
|
|
19716
|
+
const last = value[value.length - 1];
|
|
19717
|
+
if (first === "\"" && last === "\"" || first === "'" && last === "'") return value.slice(1, -1);
|
|
19718
|
+
}
|
|
19719
|
+
return value;
|
|
19720
|
+
}
|
|
19721
|
+
function stripTomlQuotes(value) {
|
|
19722
|
+
if (value.startsWith("\"") && value.endsWith("\"") && value.length >= 2) return value.slice(1, -1);
|
|
19723
|
+
if (value.startsWith("'") && value.endsWith("'") && value.length >= 2) return value.slice(1, -1);
|
|
19724
|
+
return value;
|
|
19725
|
+
}
|
|
19726
|
+
async function readRegionAwareFile(rootDir, relativePath) {
|
|
19727
|
+
const safePath = safeOutputPath(relativePath);
|
|
19728
|
+
const absolutePath = path.resolve(rootDir, ...safePath.split("/"));
|
|
19729
|
+
let stat;
|
|
19730
|
+
try {
|
|
19731
|
+
stat = await fsPromises.lstat(absolutePath);
|
|
19732
|
+
} catch (error) {
|
|
19733
|
+
if (isNodeNotFound(error)) return {
|
|
19734
|
+
refused: false,
|
|
19735
|
+
bytes: void 0
|
|
19736
|
+
};
|
|
19737
|
+
throw error;
|
|
19738
|
+
}
|
|
19739
|
+
if (stat.isSymbolicLink()) return { refused: true };
|
|
19740
|
+
if (!stat.isFile()) return {
|
|
19741
|
+
refused: false,
|
|
19742
|
+
bytes: void 0
|
|
19743
|
+
};
|
|
19744
|
+
return {
|
|
19745
|
+
refused: false,
|
|
19746
|
+
bytes: await fsPromises.readFile(absolutePath)
|
|
19747
|
+
};
|
|
19748
|
+
}
|
|
19749
|
+
async function listFilesUnder(rootDir, relativeRoot, recursive) {
|
|
19750
|
+
const files = [];
|
|
19751
|
+
const refusals = [];
|
|
19752
|
+
const rootStat = await lstatOptional(path.join(rootDir, relativeRoot));
|
|
19753
|
+
if (!rootStat) return {
|
|
19754
|
+
files: [],
|
|
19755
|
+
refusals: []
|
|
19756
|
+
};
|
|
19757
|
+
if (rootStat.isSymbolicLink()) return {
|
|
19758
|
+
files: [],
|
|
19759
|
+
refusals: [relativeRoot]
|
|
19760
|
+
};
|
|
19761
|
+
if (!rootStat.isDirectory()) return {
|
|
19762
|
+
files: [],
|
|
19763
|
+
refusals: []
|
|
19764
|
+
};
|
|
19765
|
+
await walk(rootDir, relativeRoot, recursive, files, refusals);
|
|
19766
|
+
return {
|
|
19767
|
+
files: files.sort(),
|
|
19768
|
+
refusals: refusals.sort()
|
|
19769
|
+
};
|
|
19770
|
+
}
|
|
19771
|
+
async function walk(rootDir, relativeRoot, recursive, out, refusals) {
|
|
19772
|
+
let entries;
|
|
19773
|
+
try {
|
|
19774
|
+
entries = await fsPromises.readdir(path.join(rootDir, relativeRoot), { withFileTypes: true });
|
|
19775
|
+
} catch (error) {
|
|
19776
|
+
if (isNodeNotFound(error)) return;
|
|
19777
|
+
throw error;
|
|
19778
|
+
}
|
|
19779
|
+
for (const entry of entries) {
|
|
19780
|
+
const child = `${relativeRoot}/${entry.name}`;
|
|
19781
|
+
if (entry.isSymbolicLink()) {
|
|
19782
|
+
refusals.push(child);
|
|
19783
|
+
continue;
|
|
19784
|
+
}
|
|
19785
|
+
if (entry.isDirectory() && recursive) {
|
|
19786
|
+
await walk(rootDir, child, recursive, out, refusals);
|
|
19787
|
+
continue;
|
|
19788
|
+
}
|
|
19789
|
+
if (entry.isFile()) out.push(child);
|
|
19790
|
+
}
|
|
19791
|
+
}
|
|
19792
|
+
async function lstatOptional(absolutePath) {
|
|
19793
|
+
try {
|
|
19794
|
+
return await fsPromises.lstat(absolutePath);
|
|
19795
|
+
} catch (error) {
|
|
19796
|
+
if (isNodeNotFound(error)) return void 0;
|
|
19797
|
+
throw error;
|
|
19798
|
+
}
|
|
19799
|
+
}
|
|
19800
|
+
async function readOptionalBytes(rootDir, relativePath) {
|
|
19801
|
+
const result = await readRegionAwareFile(rootDir, relativePath);
|
|
19802
|
+
if (result.refused) return void 0;
|
|
19803
|
+
return result.bytes;
|
|
19804
|
+
}
|
|
19805
|
+
async function readOptionalText(rootDir, relativePath) {
|
|
19806
|
+
const bytes = await readOptionalBytes(rootDir, relativePath);
|
|
19807
|
+
if (!bytes) return void 0;
|
|
19808
|
+
return Buffer.from(bytes).toString("utf8");
|
|
19809
|
+
}
|
|
19810
|
+
async function readLockfileForRegions(rootDir) {
|
|
19811
|
+
const bytes = await readOptionalBytes(rootDir, "ai-profile.lock");
|
|
19812
|
+
if (!bytes) return void 0;
|
|
19813
|
+
const result = validateLockfileText(Buffer.from(bytes).toString("utf8"));
|
|
19814
|
+
if (!result.ok) return void 0;
|
|
19815
|
+
return toLockfileV2View(result.lockfile);
|
|
19816
|
+
}
|
|
19817
|
+
async function getLocalRuntimeGitignoreFindings(rootDir) {
|
|
19818
|
+
const lines = (await readOptionalText(rootDir, ".gitignore").catch(() => void 0) ?? "").split(/\r?\n/u).map((line) => line.trim()).filter((line) => line !== "" && !line.startsWith("#"));
|
|
19819
|
+
const findings = [];
|
|
19820
|
+
for (const recommended of RECOMMENDED_IGNORE_LINES) {
|
|
19821
|
+
const present = lines.some((line) => {
|
|
19822
|
+
return line.replace(/^\//u, "").replace(/\/$/u, "") === recommended.replace(/\/$/u, "");
|
|
19823
|
+
});
|
|
19824
|
+
findings.push({
|
|
19825
|
+
line: recommended,
|
|
19826
|
+
action: present ? "already-present" : "would-add",
|
|
19827
|
+
reason: "local runtime or machine-specific path"
|
|
19828
|
+
});
|
|
19829
|
+
}
|
|
19830
|
+
return findings;
|
|
19831
|
+
}
|
|
19832
|
+
function containsAbsolutePathLiteral(bytes) {
|
|
19833
|
+
const text = bytes.toString("utf8");
|
|
19834
|
+
return /[A-Z]:\\\\|"\/[A-Za-z]/u.test(text);
|
|
19835
|
+
}
|
|
19836
|
+
function isNodeNotFound(error) {
|
|
19837
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
19838
|
+
}
|
|
19839
|
+
var REGION_AWARE_ROOT_PATHS = ["AGENTS.md", "CLAUDE.md"];
|
|
19840
|
+
async function planRootInstructionsAdoption(rootDir, generatedBytesByPath = /* @__PURE__ */ new Map()) {
|
|
19841
|
+
const results = [];
|
|
19842
|
+
for (const relativePath of REGION_AWARE_ROOT_PATHS) {
|
|
19843
|
+
const read = await readRegionAwareFile(rootDir, relativePath);
|
|
19844
|
+
if (read.refused) {
|
|
19845
|
+
results.push({
|
|
19846
|
+
ok: false,
|
|
19847
|
+
path: relativePath,
|
|
19848
|
+
reason: "symlink"
|
|
19849
|
+
});
|
|
19850
|
+
continue;
|
|
19851
|
+
}
|
|
19852
|
+
const existing = read.bytes;
|
|
19853
|
+
if (!existing) {
|
|
19854
|
+
results.push({
|
|
19855
|
+
ok: false,
|
|
19856
|
+
path: relativePath,
|
|
19857
|
+
reason: "missing-file"
|
|
19858
|
+
});
|
|
19859
|
+
continue;
|
|
19860
|
+
}
|
|
19861
|
+
const compiled = generatedBytesByPath.get(relativePath);
|
|
19862
|
+
if (!compiled) {
|
|
19863
|
+
results.push({
|
|
19864
|
+
ok: false,
|
|
19865
|
+
path: relativePath,
|
|
19866
|
+
reason: "missing-generated-bytes"
|
|
19867
|
+
});
|
|
19868
|
+
continue;
|
|
19869
|
+
}
|
|
19870
|
+
const generatedInner = Buffer.from(compiled);
|
|
19871
|
+
const existingBuffer = Buffer.from(existing);
|
|
19872
|
+
if (hasAllRegionMarkers(existingBuffer)) {
|
|
19873
|
+
const updated = replaceGeneratedRegion(existingBuffer, generatedInner);
|
|
19874
|
+
if (updated) results.push({
|
|
19875
|
+
ok: true,
|
|
19876
|
+
path: relativePath,
|
|
19877
|
+
bytes: updated
|
|
19878
|
+
});
|
|
19879
|
+
else results.push({
|
|
19880
|
+
ok: false,
|
|
19881
|
+
path: relativePath,
|
|
19882
|
+
reason: "duplicate-markers"
|
|
19883
|
+
});
|
|
19884
|
+
continue;
|
|
19885
|
+
}
|
|
19886
|
+
if (hasAnyRegionMarker(existingBuffer)) {
|
|
19887
|
+
results.push({
|
|
19888
|
+
ok: false,
|
|
19889
|
+
path: relativePath,
|
|
19890
|
+
reason: "partial-markers"
|
|
19891
|
+
});
|
|
19892
|
+
continue;
|
|
19893
|
+
}
|
|
19894
|
+
const mixed = serializeMixedFile({
|
|
19895
|
+
generatedInner,
|
|
19896
|
+
manualInner: existingBuffer
|
|
19897
|
+
});
|
|
19898
|
+
results.push({
|
|
19899
|
+
ok: true,
|
|
19900
|
+
path: relativePath,
|
|
19901
|
+
bytes: mixed
|
|
19902
|
+
});
|
|
19903
|
+
}
|
|
19904
|
+
return results;
|
|
19905
|
+
}
|
|
19906
|
+
//#endregion
|
|
18554
19907
|
//#region src/lib/server/projectContext.ts
|
|
18555
19908
|
var PROFILE_FILENAME = "ai-profile.yaml";
|
|
18556
19909
|
/**
|
|
@@ -18631,5 +19984,5 @@ function truncatePreview(text, capBytes = 256 * 1024) {
|
|
|
18631
19984
|
};
|
|
18632
19985
|
}
|
|
18633
19986
|
|
|
18634
|
-
export { ProfileWriteError as P,
|
|
18635
|
-
//# sourceMappingURL=projectContext-
|
|
19987
|
+
export { writeProfileAtomic as A, ProfileWriteError as B, computeFileEtag as C, validateProfileValue as D, renderProfileYaml as E, truncatePreview as F, PHASE_14_SUPPORTED_PATHS as P, REGION_AWARE_ROOT_PATHS as R, applyWritePlan as a, buildPhase14ImportReport as b, compileProfile as c, deriveEffectivePermissions as d, containsSecretLikeLiteral as e, hasAnyRegionMarker as f, parseMixedFile as g, hasAllRegionMarkers as h, hasLegacyGeneratedMarker as i, createLockfileFile as j, sha256Hex as k, getEnabledSubagents as l, isSubagentBuiltinNameCollision as m, normalizeSafety as n, readLockfileForRegions as o, parseProfileYaml as p, planRootInstructionsAdoption as q, resolveProjectRoot as r, safeOutputPath as s, toLockfileV2View as t, planWrites as u, validateLockfileText as v, readRegionAwareFile as w, redactIfSecretLike as x, PHASE_14_SCAN_DIRS as y, loadProjectContext as z };
|
|
19988
|
+
//# sourceMappingURL=projectContext-B1D-bieW.js.map
|