CoolFace
Apppublic

admin08077/Githubgemini

sourceHugging Faceotherupdated 10mo agoView on Hugging Face
0likes
index-CX7Qxd1D.js.map1 linesDownload Raw Back to assets
1{"version":3,"mappings":"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;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,GAwGrB,YAAa;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA,iWAiEb,+BAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwDhC,iCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkNlC,mCAAoC;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyEpC,mCAAoC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgHpC,mCAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6EpC,gCAAiC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2GjC,+BAAgC;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,EAuGhC,6BAA8B;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkE9B,2BAA4B;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwB5B,8BAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuK/B,2BAA4B;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA+E5B,kCAAmC,GACnC,qCAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoItC,qCAAsC;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsCtC,iCAAkC;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BlC,gCAAiC;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA0FjC,+CAAgD;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4EhD,0CAA2C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqN3C,yCAA0C;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4G1C,4CAA6C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyE7C,0CAA2C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwM3C,4CAA6C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8H7C,2CAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4H5C,2CAA4C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgM5C,6CAA8C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyL9C,iDAAkD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuIlD,0CAA2C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2F3C,8CAA+C;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4G/C,2CAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8K5C,8CAA+C;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6H/C,sCAAuC;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA0GvC,wCAAyC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0EzC,6CAA8C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoF9C,gDAAiD;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2DjD,wCAAyC;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuGzC,wCAAyC;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6FzC,wCAAyC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoHzC,2CAA4C;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4D5C,gDAAiD;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuKjD,gDAAiD;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqBjD,sCAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmSvC,yCAA0C;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoF1C,wCAAyC;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwGzC,4CAA6C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2F7C,8CAA+C;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW/C,4CAA6C;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoI7C,qCAAsC;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwFtC,0CAA2C;AAAA;AAAA,yEAG3C,4CAA6C;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2E7C,8CAA+C;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4G/C,6CAA8C;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuE9C,8CAA+C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoJ/C,4CAA6C;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2G7C,2CAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuP5C,yCAA0C;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6F1C,wCAAyC;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4EzC,4CAA6C;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA0F7C,2CAA4C;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgH5C,8CAA+C;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoG/C,sCAAuC;AAAA;AAAA,uFAGvC,6CAA8C;AAAA;AAAA,8FAG9C,0CAA2C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4O3C,2CAA4C;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyF5C,yCAA0C;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6E1C,4CAA6C;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsF7C,uCAAwC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsGxC,2CAA4C;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiE5C,2CAA4C;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6G5C,yCAA0C;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoE1C,gDAAiD;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6FjD,0CAA2C;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiH3C,uCAAwC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6IxC,wCAAyC;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyHzC,wCAAyC;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkGzC,6CAA8C;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoE9C,wCAAyC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA0IzC,wCAAyC;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2EzC,wCAAyC;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyKzC,gDAAiD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuFjD,+CAAgD;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6HhD,gDAAiD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmSjD,wCAAyC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2FzC,+BAAgC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA,wEA2EhC,kCAAmC;AAAA;AAAA;AAAA,EAInC,0CAA2C,GAC3C,gDAAiD;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWjD,uCAAwC;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsCxC,uBAAwB;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8GxB,iCAAkC,GAClC,uCAAwC;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWxC,qCAAsC;AAAA;AAAA;AAAA;AAAA,EAKtC,8BAA+B;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsC/B,gCAAiC,GACjC,iDAAkD;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsFlD,wCAAyC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiEzC,qCAAsC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkFtC,gBAAiB;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,6DAiHjB,wBAAyB,GACzB,kCAAmC;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,qEAmKnC,mCAAoC;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsDpC,8BAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA+E/B,iCAAkC;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBlC,mBAAoB;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AA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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsqBzB,iCAAkC,GAClC,4CAA6C;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgC7C,0BAA2B;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6B3B,8BAA+B;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6C/B,4BAA6B;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,EA+F7B,wBAAyB;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAwGzB,wBAAyB;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwGzB,yBAA0B;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyC1B,4BAA6B,GAC7B,4BAA6B;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6Q7B,+BAAgC;AAAA;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAoDhC,gCAAiC;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAsGjC,oBAAqB;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iDAkBrB,gCAAiC,GACjC,yBAA0B;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,EAgD1B,iCAAkC;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6ElC,kCAAmC,GACnC,uCAAwC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoCxC,2CAA4C;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+D5C,iCAAkC,GAClC,6CAA8C;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,EA2D9C,6BAA8B;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAksB9B,8BAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6J/B,+BAAgC;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgFhC,2BAA4B;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,GAoF5B,wCAAyC;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAiIzC,+BAAgC;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,0KAyHhC,qBAAsB;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GA6CtB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GA2BjB,uBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcxB,WAAY;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["isTelemetryEnabled","sanitizePayload","payload","sanitized","key","value","logEvent","eventName","logError","error","context","measurePerformance","metricName","operation","start","result","duration","KEY_ALGORITHM","KEY_LENGTH","PBKDF2_ALGORITHM","PBKDF2_HASH","PBKDF2_ITERATIONS","SALT_LENGTH_BYTES","IV_LENGTH_BYTES","textEncoder","textDecoder","deriveKey","password","salt","masterKey","generateSalt","encrypt","plaintext","iv","encodedPlaintext","decrypt","ciphertext","decrypted","DB_NAME","DB_VERSION","FILES_STORE_NAME","VAULT_STORE_NAME","ENCRYPTED_TOKENS_STORE_NAME","dbPromise","openDB","db","oldVersion","saveFile","file","getAllFiles","clearAllFiles","saveVaultData","getVaultData","saveEncryptedToken","data","getEncryptedToken","id","sessionKey","isVaultInitialized","db.getVaultData","initializeVault","masterPassword","crypto.generateSalt","db.saveVaultData","crypto.deriveKey","isUnlocked","unlockVault","e","lockVault","saveCredential","crypto.encrypt","db.saveEncryptedToken","getDecryptedCredential","encryptedData","db.getEncryptedToken","crypto.decrypt","ai","isApiKeyConfigured","initializeAiClient","apiKey","GoogleGenAI","getAi","streamContent","prompt","systemInstruction","temperature","response","chunk","generateContent","generateJson","schema","generateRegExStream","description","generateCommitMessageStream","diff","generateUnitTestsStream","code","formatCodeStream","generateComponentFromImageStream","base64Image","transcribeAudioToCodeStream","base64Audio","mimeType","transferCodeStyleStream","args","generateCodingChallengeStream","_","reviewCodeStream","generateChangelogFromLogStream","log","enhanceSnippetStream","summarizeNotesStream","notes","migrateCodeStream","from","to","analyzeConcurrencyStream","debugErrorStream","convertJsonToXbrlStream","json","refactorForPerformance","refactorForReadability","convertToFunctionalComponent","classComponent","generateJsDoc","generateDockerfile","framework","generateBugReproductionTestStream","stackTrace","generateIamPolicyStream","platform","generatePipelineCode","flow","generateCiCdConfig","analyzePerformanceTrace","trace","suggestA11yFix","issue","generateMermaidJs","generateWeeklyDigest","commitLogs","telemetryData","generateTechnicalSpecFromDiff","summary","explainCodeStructured","Type","generateSemanticTheme","colorObjectSchema","accessibilityCheckSchema","generatePrSummaryStructured","generateFeature","styling","userPrompt","generateFullStackFeature","generateCronFromDescription","generateColorPalette","baseColor","analyzeCodeForVulnerabilities","detectCodeSmells","generateTagsForCode","generateTerraformConfig","cloud","getInferenceFunction","functionDeclarations","knowledgeBase","functionCalls","parts","part","generateImage","generateImageFromImageAndText","Modality","base64ImageBytes","IconWrapper","children","className","jsx","CpuChipIcon","DocumentIcon","FolderIcon","ClipboardDocumentIcon","ArrowDownTrayIcon","XMarkIcon","PlusIcon","TrashIcon","MagnifyingGlassIcon","ArrowUpOnSquareIcon","WindowIconWrapper","MinimizeIcon","FileCodeIcon","GitBranchIcon","SparklesIcon","EyeIcon","MapIcon","BeakerIcon","CommandLineIcon","LockClosedIcon","CodeBracketSquareIcon","PhotoIcon","ChartBarIcon","BugAntIcon","CloudIcon","PaperAirplaneIcon","ShieldCheckIcon","ArrowPathIcon","RectangleGroupIcon","DocumentTextIcon","MicrophoneIcon","MailIcon","CommandCenterIcon","jsxs","ProjectExplorerIcon","CodeExplainerIcon","FeatureBuilderIcon","CodeMigratorIcon","ThemeDesignerIcon","SnippetVaultIcon","DigitalWhiteboardIcon","UnitTestGeneratorIcon","CommitGeneratorIcon","GitLogAnalyzerIcon","ConcurrencyAnalyzerIcon","RegexSandboxIcon","PromptCraftPadIcon","CodeFormatterIcon","JsonTreeIcon","XbrlConverterIcon","CssGridEditorIcon","SchemaDesignerIcon","PwaManifestEditorIcon","MarkdownSlidesIcon","ScreenshotToComponentIcon","TypographyLabIcon","SvgPathEditorIcon","StyleTransferIcon","CodingChallengeIcon","CodeReviewBotIcon","AiPullRequestAssistantIcon","ChangelogGeneratorIcon","CronJobBuilderIcon","AsyncCallTreeIcon","AudioToCodeIcon","CodeDiffGhostIcon","CodeSpellCheckerIcon","ColorPaletteGeneratorIcon","LogicFlowBuilderIcon","MetaTagEditorIcon","NetworkVisualizerIcon","ResponsiveTesterIcon","SassCompilerIcon","ImageGeneratorIcon","GithubIcon","GcpIcon","LoadingSpinner","MarkdownRenderer","content","sanitizedHtml","setSanitizedHtml","useState","useEffect","html","marked","ErrorBoundary","React","props","stream","fullResponse","errorInfo","initialState","reducer","state","action","featureId","newHiddenFeatures","GlobalStateContext","createContext","LOCAL_STORAGE_KEY","CONSENT_KEY","GlobalStateProvider","canPersist","dispatch","useReducer","initial","storedStateJSON","storedState","hydratedState","handler","stateToSave","useGlobalState","useContext","RAW_FEATURES","ALL_FEATURE_IDS","f","lazyWithRetry","componentImport","exportName","lazy","i","module","resolve","componentMap","__vitePreload","n","ALL_FEATURES","feature","FEATURES_MAP","CommandPalette","isOpen","onClose","onSelect","searchTerm","setSearchTerm","selectedIndex","setSelectedIndex","commandOptions","useMemo","navigationCommands","featureCommands","handleKeyDown","prev","selected","item","index","NotificationContext","useNotification","NotificationProvider","notifications","setNotifications","addNotification","useCallback","message","type","typeStyles","notification","useLocalStorage","initialValue","storedValue","setStoredValue","valueToStore","defaultThemeState","applyColors","colors","root","rgb","x","useTheme","themeState","setThemeState","mode","VaultModalContext","useVaultModal","CreateMasterPasswordModal","onSuccess","onCancel","setPassword","confirmPassword","setConfirmPassword","setError","isLoading","setIsLoading","handleSubmit","vaultService.initializeVault","err","UnlockVaultModal","vaultService.unlockVault","VaultProvider","isCreateModalOpen","setCreateModalOpen","isUnlockModalOpen","setUnlockModalOpen","createPromise","setCreatePromise","unlockPromise","setUnlockPromise","requestCreation","requestUnlock","handleCreateSuccess","handleCreateCancel","handleUnlockSuccess","handleUnlockCancel","contextValue","GOOGLE_CLIENT_ID","SCOPES","tokenClient","onUserChangedCallback","getGoogleUserProfile","accessToken","initGoogleAuth","callback","tokenResponse","profile","appUser","signInWithGoogle","LoginView","FeatureButton","onOpen","FeatureDock","Window","isActive","onMinimize","onFocus","onUpdate","dragStartPos","useRef","initialPos","FeatureComponent","handleDragStart","handleDragMove","handleDragEnd","dx","dy","Suspense","LoadingIndicator","Taskbar","minimizedWindows","onRestore","sourceFiles","ActionManager","handleDownloadSource","zip","JSZip","filePath","generatedFiles","generatedFolder","zipBlob","link","Z_INDEX_BASE","DesktopView","openFeatureId","onNavigate","windows","setWindows","activeId","setActiveId","nextZIndex","setNextZIndex","openWindow","newZIndex","existingWindow","openWindowsCount","w","newWindow","closeWindow","newState","minimizeWindow","focusWindow","updateWindowState","updates","openWindows","featuresMap","win","ApiKeyPromptModal","setApiKey","initializeOctokit","token","Octokit","validateToken","tempOctokit","user","OctokitContext","useOctokit","OctokitProvider","octokit","setOctokit","vaultState","initialize","client","LocalStorageConsentModal","onAccept","onDecline","AppContent","activeView","isCommandPaletteOpen","setCommandPaletteOpen","handleViewChange","view","AppShell","consent","setConsent","isApiKeyMissing","consentStatus","handleUserChanged","initAuth","gsiScript","handleAcceptConsent","handleDeclineConsent","App","rootElement","ReactDOM"],"ignoreList":[],"sources":["../../services/telemetryService.ts","../../services/cryptoService.ts","../../services/dbService.ts","../../services/vaultService.ts","../../services/aiService.ts","../../components/icons.tsx","../../components/shared/index.tsx","../../components/ErrorBoundary.tsx","../../contexts/GlobalStateContext.tsx","../../constants.tsx","../../services/componentLoader.ts","../../components/features/index.ts","../../components/CommandPalette.tsx","../../contexts/NotificationContext.tsx","../../hooks/useLocalStorage.ts","../../hooks/useTheme.ts","../../contexts/VaultModalContext.tsx","../../components/shared/LoadingSpinner.tsx","../../components/vault/CreateMasterPasswordModal.tsx","../../components/vault/UnlockVaultModal.tsx","../../components/vault/VaultProvider.tsx","../../services/googleAuthService.ts","../../components/LoginView.tsx","../../components/desktop/FeatureDock.tsx","../../components/desktop/Window.tsx","../../components/desktop/Taskbar.tsx","../../services/sourceRegistry.ts","../../components/ActionManager.tsx","../../components/desktop/DesktopView.tsx","../../components/ApiKeyPromptModal.tsx","../../services/authService.ts","../../contexts/OctokitContext.tsx","../../App.tsx","../../index.tsx"],"sourcesContent":["\n\nconst isTelemetryEnabled = true; // Could be controlled by a setting\n\nconst sanitizePayload = (payload: Record<string, any>): Record<string, any> => {\n    const sanitized: Record<string, any> = {};\n    for (const key in payload) {\n        if (Object.prototype.hasOwnProperty.call(payload, key)) {\n            const value = payload[key];\n            // Truncate long strings to avoid polluting the console (e.g., base64 data)\n            if (typeof value === 'string' && value.length > 500) {\n                sanitized[key] = `${value.substring(0, 100)}... (truncated)`;\n            } else {\n                sanitized[key] = value;\n            }\n        }\n    }\n    return sanitized;\n};\n\n\nexport const logEvent = (eventName: string, payload: Record<string, any> = {}) => {\n  if (!isTelemetryEnabled) return;\n\n  console.log(\n    `%c[TELEMETRY EVENT]%c ${eventName}`,\n    'color: #84cc16; font-weight: bold;',\n    'color: inherit;',\n    sanitizePayload(payload)\n  );\n};\n\nexport const logError = (error: Error, context: Record<string, any> = {}) => {\n  if (!isTelemetryEnabled) return;\n\n  console.error(\n    `%c[TELEMETRY ERROR]%c ${error.message}`,\n    'color: #ef4444; font-weight: bold;',\n    'color: inherit;',\n    {\n      error,\n      context: sanitizePayload(context),\n      stack: error.stack,\n    }\n  );\n};\n\nexport const measurePerformance = async <T>(\n  metricName: string,\n  operation: () => Promise<T>\n): Promise<T> => {\n  const start = performance.now();\n  try {\n    const result = await operation();\n    const end = performance.now();\n    const duration = end - start;\n\n    if (isTelemetryEnabled) {\n      console.log(\n        `%c[TELEMETRY PERF]%c ${metricName}`,\n        'color: #3b82f6; font-weight: bold;',\n        'color: inherit;',\n        { duration: `${duration.toFixed(2)}ms` }\n      );\n    }\n    return result;\n  } catch (error) {\n    const end = performance.now();\n    const duration = end - start;\n     if (isTelemetryEnabled) {\n        console.warn(\n          `%c[TELEMETRY PERF FAILED]%c ${metricName}`,\n          'color: #f97316; font-weight: bold;',\n          'color: inherit;',\n          { duration: `${duration.toFixed(2)}ms`, error }\n        );\n      }\n    throw error;\n  }\n};","/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nconst KEY_ALGORITHM = 'AES-GCM';\nconst KEY_LENGTH = 256;\nconst PBKDF2_ALGORITHM = 'PBKDF2';\nconst PBKDF2_HASH = 'SHA-256';\nconst PBKDF2_ITERATIONS = 100000;\nconst SALT_LENGTH_BYTES = 16;\nconst IV_LENGTH_BYTES = 12;\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\n/**\n * Derives a cryptographic key from a master password and a salt using PBKDF2.\n * @param password The master password string.\n * @param salt The salt as an ArrayBuffer.\n * @returns A promise that resolves to a CryptoKey.\n */\nexport const deriveKey = async (password: string, salt: ArrayBuffer): Promise<CryptoKey> => {\n    const masterKey = await crypto.subtle.importKey(\n        'raw',\n        textEncoder.encode(password),\n        { name: PBKDF2_ALGORITHM },\n        false,\n        ['deriveKey']\n    );\n\n    return await crypto.subtle.deriveKey(\n        {\n            name: PBKDF2_ALGORITHM,\n            salt,\n            iterations: PBKDF2_ITERATIONS,\n            hash: PBKDF2_HASH,\n        },\n        masterKey,\n        { name: KEY_ALGORITHM, length: KEY_LENGTH },\n        true,\n        ['encrypt', 'decrypt']\n    );\n};\n\n/**\n * Generates a cryptographically secure random salt.\n * @returns A new salt as an ArrayBuffer.\n */\nexport const generateSalt = (): ArrayBuffer => {\n    return crypto.getRandomValues(new Uint8Array(SALT_LENGTH_BYTES)).buffer;\n};\n\n/**\n * Encrypts a plaintext string using a derived key.\n * @param plaintext The string to encrypt.\n * @param key The CryptoKey to use for encryption.\n * @returns A promise that resolves to an object containing the encrypted data (ciphertext), and the initialization vector (iv).\n */\nexport const encrypt = async (plaintext: string, key: CryptoKey): Promise<{ ciphertext: ArrayBuffer, iv: Uint8Array }> => {\n    const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH_BYTES));\n    const encodedPlaintext = textEncoder.encode(plaintext);\n\n    const ciphertext = await crypto.subtle.encrypt(\n        {\n            name: KEY_ALGORITHM,\n            iv,\n        },\n        key,\n        encodedPlaintext\n    );\n\n    return { ciphertext, iv };\n};\n\n/**\n * Decrypts a ciphertext ArrayBuffer using a derived key and IV.\n * @param ciphertext The ArrayBuffer of the encrypted data.\n * @param key The CryptoKey to use for decryption.\n * @param iv The initialization vector used during encryption.\n * @returns A promise that resolves to the decrypted plaintext string.\n */\nexport const decrypt = async (ciphertext: ArrayBuffer, key: CryptoKey, iv: Uint8Array): Promise<string> => {\n    const decrypted = await crypto.subtle.decrypt(\n        {\n            name: KEY_ALGORITHM,\n            iv,\n        },\n        key,\n        ciphertext\n    );\n\n    return textDecoder.decode(decrypted);\n};\n","import { openDB, DBSchema } from 'idb';\nimport type { GeneratedFile, EncryptedData } from '../types.ts';\n\nconst DB_NAME = 'devcore-db';\nconst DB_VERSION = 2;\nconst FILES_STORE_NAME = 'generated-files';\nconst VAULT_STORE_NAME = 'vault-data';\nconst ENCRYPTED_TOKENS_STORE_NAME = 'encrypted-tokens';\n\n\ninterface DevCoreDB extends DBSchema {\n  [FILES_STORE_NAME]: {\n    key: string;\n    value: GeneratedFile;\n    indexes: { 'by-filePath': string };\n  };\n  [VAULT_STORE_NAME]: {\n    key: string;\n    value: any;\n  };\n  [ENCRYPTED_TOKENS_STORE_NAME]: {\n    key: string;\n    value: EncryptedData;\n  };\n}\n\nconst dbPromise = openDB<DevCoreDB>(DB_NAME, DB_VERSION, {\n  upgrade(db, oldVersion) {\n    switch (oldVersion) {\n        case 0: {\n            const store = db.createObjectStore(FILES_STORE_NAME, {\n                keyPath: 'filePath',\n            });\n            store.createIndex('by-filePath', 'filePath');\n        }\n        // fall-through for new installations\n        case 1: {\n            if (!db.objectStoreNames.contains(VAULT_STORE_NAME)) {\n                db.createObjectStore(VAULT_STORE_NAME);\n            }\n            if (!db.objectStoreNames.contains(ENCRYPTED_TOKENS_STORE_NAME)) {\n                db.createObjectStore(ENCRYPTED_TOKENS_STORE_NAME, { keyPath: 'id' });\n            }\n        }\n    }\n  },\n});\n\n// --- Generated Files Store ---\nexport const saveFile = async (file: GeneratedFile): Promise<void> => {\n  const db = await dbPromise;\n  await db.put(FILES_STORE_NAME, file);\n};\n\nexport const getAllFiles = async (): Promise<GeneratedFile[]> => {\n  const db = await dbPromise;\n  return db.getAll(FILES_STORE_NAME);\n};\n\nexport const getFileByPath = async (filePath: string): Promise<GeneratedFile | undefined> => {\n  const db = await dbPromise;\n  return db.get(FILES_STORE_NAME, filePath);\n};\n\nexport const clearAllFiles = async (): Promise<void> => {\n  const db = await dbPromise;\n  await db.clear(FILES_STORE_NAME);\n};\n\n// --- Vault Store ---\nexport const saveVaultData = async (key: string, value: any): Promise<void> => {\n  const db = await dbPromise;\n  await db.put(VAULT_STORE_NAME, value, key);\n};\n\nexport const getVaultData = async (key: string): Promise<any | undefined> => {\n  const db = await dbPromise;\n  return db.get(VAULT_STORE_NAME, key);\n};\n\n// --- Encrypted Tokens Store ---\nexport const saveEncryptedToken = async (data: EncryptedData): Promise<void> => {\n  const db = await dbPromise;\n  await db.put(ENCRYPTED_TOKENS_STORE_NAME, data);\n};\n\nexport const getEncryptedToken = async (id: string): Promise<EncryptedData | undefined> => {\n  const db = await dbPromise;\n  return db.get(ENCRYPTED_TOKENS_STORE_NAME, id);\n};\n\nexport const getAllEncryptedTokenIds = async (): Promise<string[]> => {\n    const db = await dbPromise;\n    return db.getAllKeys(ENCRYPTED_TOKENS_STORE_NAME);\n};\n\n\n// --- Global Actions ---\nexport const clearAllData = async (): Promise<void> => {\n    const db = await dbPromise;\n    await db.clear(FILES_STORE_NAME);\n    await db.clear(VAULT_STORE_NAME);\n    await db.clear(ENCRYPTED_TOKENS_STORE_NAME);\n}","/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport * as crypto from './cryptoService.ts';\nimport * as db from './dbService.ts';\nimport type { EncryptedData } from '../types.ts';\n\nlet sessionKey: CryptoKey | null = null;\n\nexport const isVaultInitialized = async (): Promise<boolean> => {\n    const salt = await db.getVaultData('pbkdf2-salt');\n    return !!salt;\n};\n\nexport const initializeVault = async (masterPassword: string): Promise<void> => {\n    if (await isVaultInitialized()) {\n        throw new Error(\"Vault is already initialized.\");\n    }\n    const salt = crypto.generateSalt();\n    await db.saveVaultData('pbkdf2-salt', salt);\n    sessionKey = await crypto.deriveKey(masterPassword, salt);\n};\n\nexport const isUnlocked = (): boolean => {\n    return sessionKey !== null;\n};\n\nexport const unlockVault = async (masterPassword: string): Promise<void> => {\n    const salt = await db.getVaultData('pbkdf2-salt');\n    if (!salt) {\n        throw new Error(\"Vault not initialized.\");\n    }\n    try {\n        sessionKey = await crypto.deriveKey(masterPassword, salt);\n    } catch (e) {\n        console.error(\"Key derivation failed, likely incorrect password\", e);\n        throw new Error(\"Invalid Master Password.\");\n    }\n};\n\nexport const lockVault = (): void => {\n    sessionKey = null;\n};\n\nexport const saveCredential = async (id: string, plaintext: string): Promise<void> => {\n    if (!sessionKey) {\n        throw new Error(\"Vault is locked. Cannot save credential.\");\n    }\n    const { ciphertext, iv } = await crypto.encrypt(plaintext, sessionKey);\n    const encryptedData: EncryptedData = {\n        id,\n        ciphertext,\n        iv\n    };\n    await db.saveEncryptedToken(encryptedData);\n};\n\nexport const getDecryptedCredential = async (id: string): Promise<string | null> => {\n    if (!sessionKey) {\n        throw new Error(\"Vault is locked. Cannot retrieve credential.\");\n    }\n    const encryptedData = await db.getEncryptedToken(id);\n    if (!encryptedData) {\n        return null;\n    }\n    try {\n        return await crypto.decrypt(encryptedData.ciphertext, sessionKey, encryptedData.iv);\n    } catch (e) {\n        console.error(`Decryption failed for ${id}`, e);\n        lockVault(); // Relock the vault on decryption failure as a security measure\n        throw new Error(\"Decryption failed. The vault has been locked.\");\n    }\n};\n\nexport const listCredentials = async (): Promise<string[]> => {\n    return db.getAllEncryptedTokenIds();\n};\n\nexport const resetVault = async (): Promise<void> => {\n    await db.clearAllData();\n    lockVault();\n}","import { GoogleGenAI, Type, GenerateContentResponse, FunctionDeclaration, Modality } from \"@google/genai\";\nimport type { GeneratedFile, StructuredPrSummary, StructuredExplanation, ColorTheme, SemanticColorTheme, StructuredReview, SlideSummary, SecurityVulnerability, CodeSmell } from '../types.ts';\nimport { logError } from './telemetryService.ts';\nimport { getDecryptedCredential, isUnlocked, isVaultInitialized } from './vaultService.ts';\n\nlet ai: GoogleGenAI | null = null;\n\nexport async function isApiKeyConfigured(): Promise<boolean> {\n    const envKey = process.env.GEMINI_API_KEY;\n    if (envKey && envKey !== 'undefined' && envKey !== '') return true;\n    \n    // Only check vault if it's initialized and unlocked.\n    if (await isVaultInitialized() && isUnlocked()) {\n        try {\n            const vaultKey = await getDecryptedCredential('gemini_api_key');\n            return !!vaultKey;\n        } catch (e) {\n            console.error(\"Could not check for API key in vault:\", e);\n            return false;\n        }\n    }\n    return false;\n}\n\nexport async function initializeAiClient(): Promise<GoogleGenAI> {\n    if (ai) return ai;\n\n    let apiKey = process.env.GEMINI_API_KEY;\n    \n    if (!apiKey || apiKey === 'undefined' || apiKey === '') {\n        try {\n             apiKey = await getDecryptedCredential('gemini_api_key');\n        } catch(e) {\n             throw new Error(\"Vault is locked. Cannot retrieve API Key.\");\n        }\n    }\n    \n    if (!apiKey) {\n      throw new Error(\"Gemini API key not found. Please provide it when prompted.\");\n    }\n    \n    ai = new GoogleGenAI({ apiKey });\n    return ai;\n}\n\nconst getAi = async () => {\n    if (!ai) {\n        return await initializeAiClient();\n    }\n    return ai;\n}\n\n\nconst sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));\n\n// --- Unified AI Helpers ---\n\nexport async function* streamContent(prompt: string | { parts: any[] }, systemInstruction: string, temperature = 0.5) {\n    try {\n        const aiClient = await getAi();\n        const response = await aiClient.models.generateContentStream({\n            model: 'gemini-2.5-flash',\n            contents: prompt as any,\n            config: { systemInstruction, temperature }\n        });\n\n        for await (const chunk of response) {\n            yield chunk.text;\n        }\n    } catch (error) {\n        console.error(\"Error streaming from AI model:\", error);\n        logError(error as Error, { prompt, systemInstruction });\n        if (error instanceof Error) {\n            yield `An error occurred while communicating with the AI model: ${error.message}`;\n        } else {\n            yield \"An unknown error occurred while generating the response.\";\n        }\n    }\n}\n\nexport async function generateContent(prompt: string, systemInstruction: string, temperature = 0.5): Promise<string> {\n    try {\n        const aiClient = await getAi();\n        const response = await aiClient.models.generateContent({\n            model: 'gemini-2.5-flash',\n            contents: prompt,\n            config: { systemInstruction, temperature }\n        });\n        return response.text;\n    } catch (error) {\n         console.error(\"Error generating content from AI model:\", error);\n        logError(error as Error, { prompt, systemInstruction });\n        throw error;\n    }\n}\n\n\nexport async function generateJson<T>(prompt: any, systemInstruction: string, schema: any, temperature = 0.2): Promise<T> {\n    try {\n        const aiClient = await getAi();\n        const response = await aiClient.models.generateContent({\n            model: \"gemini-2.5-flash\",\n            contents: prompt,\n            config: {\n                systemInstruction,\n                responseMimeType: \"application/json\",\n                responseSchema: schema,\n                temperature,\n            }\n        });\n        return JSON.parse(response.text.trim());\n    } catch (error) {\n        console.error(\"Error generating JSON from AI model:\", error);\n        logError(error as Error, { prompt, systemInstruction });\n        throw error;\n    }\n}\n\n\n// --- Unified Feature Functions (Streaming) ---\n\nexport const explainCodeStream = (code: string) => streamContent(\n    `Please explain the following code snippet:\\n\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are an expert software engineer providing a clear, concise explanation of code.\"\n);\n\nexport const generateRegExStream = (description: string) => streamContent(\n    `Generate a single valid JavaScript regex literal (e.g., /abc/gi) for the following description. Respond with ONLY the regex literal and nothing else: \"${description}\"`,\n    \"You are an expert in regular expressions. You only output valid JavaScript regex literals.\",\n    0.7\n);\n\nexport const generateCommitMessageStream = (diff: string) => streamContent(\n    `Generate a conventional commit message for the following context of new files being added:\\n\\n${diff}`,\n    \"You are an expert programmer who writes excellent, conventional commit messages. The response should be only the commit message text.\",\n    0.8\n);\n\nexport const generateUnitTestsStream = (code: string) => streamContent(\n    `Generate Vitest unit tests for this React component code:\\n\\n\\`\\`\\`tsx\\n${code}\\n\\`\\`\\``,\n    \"You are a software quality engineer specializing in writing comprehensive and clear unit tests using Vitest and React Testing Library.\",\n    0.6\n);\n\nexport const formatCodeStream = (code: string) => streamContent(\n    `Format this code:\\n\\n\\`\\`\\`javascript\\n${code}\\n\\`\\`\\``,\n    \"You are a code formatter. Your only purpose is to format code. Respond with only the formatted code, enclosed in a single markdown block.\",\n    0.2\n);\n\nexport const generateComponentFromImageStream = (base64Image: string) => streamContent(\n    {\n        parts: [\n            { text: \"Generate a single-file React component using Tailwind CSS that looks like this image. Respond with only the code in a markdown block.\" },\n            { inlineData: { mimeType: 'image/png', data: base64Image } }\n        ]\n    },\n    \"You are an expert frontend developer specializing in React and Tailwind CSS. You create clean, functional components from screenshots.\"\n);\n\nexport const transcribeAudioToCodeStream = (base64Audio: string, mimeType: string) => streamContent(\n    {\n        parts: [\n            { text: \"Transcribe my speech into a code snippet. If I describe a function or component, write it out.\" },\n            { inlineData: { mimeType, data: base64Audio } }\n        ]\n    },\n    \"You are an expert programmer. You listen to a user's voice and transcribe their ideas into code.\"\n);\n\nexport const transferCodeStyleStream = (args: { code: string, styleGuide: string }) => streamContent(\n    `Rewrite the following code to match the provided style guide.\\n\\nStyle Guide:\\n${args.styleGuide}\\n\\nCode to rewrite:\\n\\`\\`\\`\\n${args.code}\\n\\`\\`\\``,\n    \"You are an AI assistant that rewrites code to match a specific style guide. Respond with only the rewritten code in a markdown block.\",\n    0.3\n);\n\nexport const generateCodingChallengeStream = (_: any) => streamContent(\n    `Generate a new, interesting coding challenge suitable for an intermediate developer. Include a clear problem description, one or two examples, and any constraints. Format it in markdown.`,\n    \"You are an AI that creates unique and interesting coding challenges for software developers.\",\n    0.9\n);\n\nexport const reviewCodeStream = (code: string, systemInstruction?: string) => streamContent(\n    `Please perform a detailed code review on the following code snippet. Identify potential bugs, suggest improvements for readability and performance, and point out any anti-patterns. Structure your feedback with clear headings.\\n\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    systemInstruction || \"You are a senior software engineer performing a code review. You are meticulous, helpful, and provide constructive feedback.\",\n    0.6\n);\n\nexport const generateChangelogFromLogStream = (log: string) => streamContent(\n    `Analyze this git log and create a changelog:\\n\\n\\`\\`\\`\\n${log}\\n\\`\\`\\``,\n    \"You are a git expert and project manager. Analyze the provided git log and generate a clean, categorized changelog in Markdown format. Group changes under 'Features' and 'Fixes'.\",\n    0.6\n);\n\nexport const enhanceSnippetStream = (code: string) => streamContent(\n    `Enhance this code snippet. Add comments, improve variable names, and refactor for clarity or performance if possible.\\n\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are a senior software engineer who excels at improving code. Respond with only the enhanced code in a markdown block.\",\n    0.5\n);\n\nexport const summarizeNotesStream = (notes: string) => streamContent(\n    `Summarize these developer notes into a bulleted list of key points and action items:\\n\\n${notes}`,\n    \"You are a productivity assistant who is an expert at summarizing technical notes.\",\n    0.7\n);\n\nexport const migrateCodeStream = (code: string, from: string, to: string) => streamContent(\n    `Translate this ${from} code to ${to}. Respond with only the translated code in a markdown block.\\n\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    `You are an expert polyglot programmer who specializes in migrating code between languages and frameworks.`,\n    0.4\n);\n\nexport const analyzeConcurrencyStream = (code: string) => streamContent(\n    `Analyze this JavaScript code for potential concurrency issues, especially related to Web Workers. Identify race conditions, deadlocks, or inefficient data passing.\\n\\n\\`\\`\\`javascript\\n${code}\\n\\`\\`\\``,\n    \"You are an expert in JavaScript concurrency, web workers, and multi-threaded programming concepts.\",\n    0.6\n);\n\nexport const debugErrorStream = (error: Error) => streamContent(\n    `I encountered an error in my React application. Here are the details:\\n    \\n    Message: ${error.message}\\n    \\n    Stack Trace:\\n    ${error.stack}\\n    \\n    Please analyze this error. Provide a brief explanation of the likely cause, followed by a bulleted list of potential solutions or debugging steps. Structure your response in clear, concise markdown.`,\n    \"You are an expert software engineer specializing in debugging React applications. You provide clear, actionable advice to help developers solve errors.\"\n);\n\nexport const convertJsonToXbrlStream = (json: string) => streamContent(\n    `Convert the following JSON to a simplified, XBRL-like XML format. Use meaningful tags based on the JSON keys. The root element should be <xbrl>. Do not include XML declarations or namespaces.\\n\\nJSON:\\n${json}`,\n    \"You are an expert in data formats who converts JSON to clean, XBRL-like XML.\"\n);\n\n// --- New Streaming Functions ---\n\nexport const refactorForPerformance = (code: string) => streamContent(\n    `Refactor the following code for maximum performance. Focus on algorithmic efficiency, efficient data structures, and avoiding unnecessary computations. Respond with only the refactored code in a markdown block.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are an expert software engineer specializing in code performance optimization.\"\n);\n\nexport const refactorForReadability = (code: string) => streamContent(\n    `Refactor the following code for maximum readability. Focus on clear variable names, breaking down complex functions, and adding helpful comments. Respond with only the refactored code in a markdown block.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are an expert software engineer who writes exceptionally clean and readable code.\"\n);\n\nexport const convertToFunctionalComponent = (classComponent: string) => streamContent(\n    `Convert the following React class component to a functional component using hooks (useState, useEffect, etc.). Ensure all lifecycle methods are correctly mapped. Respond with only the refactored code in a markdown block.\\n\\nCode:\\n\\`\\`\\`\\n${classComponent}\\n\\`\\`\\``,\n    \"You are a React expert specializing in modernizing codebases by converting class components to functional components with hooks.\"\n);\n\nexport const generateJsDoc = (code: string) => streamContent(\n    `Generate a complete JSDoc block for the following function or component. Include descriptions for the function, its parameters, and what it returns. Respond with only the JSDoc block and the original function.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are an AI assistant that writes comprehensive and accurate JSDoc documentation.\"\n);\n\nexport const translateComments = (code: string, targetLanguage: string) => streamContent(\n    `Translate only the code comments in the following snippet to ${targetLanguage}. Do not alter the code itself. Respond with the full code snippet including the translated comments.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are an AI assistant that translates code comments into different languages without changing any of the code.\"\n);\n\nexport const generateDockerfile = (framework: string) => streamContent(\n    `Generate a basic, multi-stage Dockerfile for a ${framework} project. The Dockerfile should be production-ready, including build and serve stages. Respond with only the Dockerfile content in a markdown block.`,\n    \"You are a DevOps expert specializing in containerization with Docker.\"\n);\n\nexport const convertCssToTailwind = (css: string) => streamContent(\n    `Convert the following CSS code to Tailwind CSS utility classes. Provide the equivalent HTML structure with the Tailwind classes. Respond with only the HTML in a markdown block.\\n\\nCSS:\\n\\`\\`\\`css\\n${css}\\n\\`\\`\\``,\n    \"You are an expert in Tailwind CSS and modern CSS practices.\"\n);\n\nexport const applySpecificRefactor = (code: string, instruction: string) => streamContent(\n    `Apply this specific refactoring instruction to the code: \"${instruction}\". Respond with only the complete, refactored code in a markdown block.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are an AI assistant that precisely applies refactoring instructions to code.\"\n);\n\nexport const generateBugReproductionTestStream = (stackTrace: string, context?: string) => streamContent(\n    `Generate a minimal, runnable unit test (using Vitest) that reproduces the bug described by the following stack trace. Respond with only the code in a markdown block.\\n\\nStack Trace:\\n${stackTrace}\\n\\n${context ? `Additional Context:\\n${context}` : ''}`,\n    \"You are a senior software engineer specializing in debugging and automated testing. You create concise, effective unit tests to reproduce bugs.\"\n);\n\nexport const generateIamPolicyStream = (description: string, platform: 'aws' | 'gcp') => streamContent(\n    `Generate a valid ${platform.toUpperCase()} IAM policy in JSON format based on this description: \"${description}\". Respond with only the JSON policy in a markdown block.`,\n    \"You are a cloud security expert specializing in IAM policies for AWS and GCP.\"\n);\n\n\n// --- Simple Generate Content ---\nexport const generatePipelineCode = (flow: string): Promise<string> => generateContent(`Based on the following described workflow, generate a single asynchronous JavaScript function that orchestrates the steps. Use placeholder functions for the actual tool logic. The workflow is: ${flow}`, \"You are an expert software architect who writes clean, asynchronous JavaScript code to orchestrate complex workflows based on a description.\", 0.5);\n\nexport const generateCiCdConfig = (platform: string, description: string): Promise<string> => generateContent(\n    `Generate a CI/CD configuration file for ${platform} based on this description: \"${description}\". Respond with only the YAML/config file content inside a markdown block.`,\n    \"You are a DevOps expert specializing in CI/CD pipelines.\"\n);\n\nexport const analyzePerformanceTrace = (trace: object): Promise<string> => generateContent(\n    `Analyze the following performance trace data and provide optimization suggestions in markdown format. Data: ${JSON.stringify(trace, null, 2)}`,\n    \"You are an expert performance engineer.\"\n);\n\nexport const suggestA11yFix = (issue: object): Promise<string> => generateContent(\n    `Explain this accessibility issue and suggest a code fix in markdown. Issue: ${JSON.stringify(issue, null, 2)}`,\n    \"You are an expert in web accessibility (a11y).\"\n);\n\nexport const createApiDocumentation = (apiCode: string): Promise<string> => generateContent(\n    `Generate Markdown documentation for the following API endpoint code. Include the endpoint, HTTP method, parameters, and example request/response.\\n\\nCode:\\n\\`\\`\\`\\n${apiCode}\\n\\`\\`\\``,\n    \"You are a technical writer who creates clear and concise API documentation.\"\n);\n\nexport const jsonToTypescriptInterface = (json: string): Promise<string> => generateContent(\n    `Generate a TypeScript interface from this JSON object. Respond with only the TypeScript code in a markdown block.\\n\\nJSON:\\n${json}`,\n    \"You are an expert in TypeScript and data modeling.\"\n);\n\nexport const suggestAlternativeLibraries = (code: string): Promise<string> => generateContent(\n    `Analyze the following code, particularly its import statements and common patterns (like date manipulation). Suggest modern, more efficient library alternatives where applicable (e.g., suggest 'date-fns' or 'dayjs' over 'moment.js'). Explain why.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are a senior software engineer with deep knowledge of the JavaScript ecosystem.\"\n);\n\nexport const explainRegex = (regex: string): Promise<string> => generateContent(\n    `Provide a step-by-step explanation of what each part of this regular expression does: \\`${regex}\\``,\n    \"You are an expert in regular expressions who can explain complex patterns simply.\"\n);\n\nexport const generateMermaidJs = (code: string): Promise<string> => generateContent(\n    `Generate a Mermaid.js flowchart string that represents the logic of the following code. Respond with only the Mermaid.js code in a markdown block (e.g., \\`\\`\\`mermaid\\n...\\n\\`\\`\\`).\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``,\n    \"You are an expert in code analysis and can visualize logic flows using Mermaid.js.\"\n);\n\nexport const generateWeeklyDigest = (commitLogs: string, telemetryData: object): Promise<string> => generateContent(\n    `Generate a concise, professional weekly summary email in HTML format based on the following data.\n    \n    Commit Logs:\n    \\`\\`\\`\n    ${commitLogs}\n    \\`\\`\\`\n    \n    Performance Telemetry:\n    \\`\\`\\`json\n    ${JSON.stringify(telemetryData, null, 2)}\n    \\`\\`\\`\n    \n    The email should have sections for \"New Features\", \"Bug Fixes\", and \"Performance Notes\". It should be visually clean and easy to read.`,\n    \"You are an AI assistant that generates weekly engineering progress reports in HTML format.\"\n);\n\nexport const generateTechnicalSpecFromDiff = (diff: string, summary: StructuredPrSummary): Promise<string> => generateContent(\n    `Generate a comprehensive technical specification document in Markdown format based on the following pull request information.\n\nThe spec should include the following sections:\n- **Problem:** A brief description of the issue being addressed.\n- **Solution:** A detailed explanation of the changes made.\n- **Technical Details:** An overview of the implementation, including any new functions, components, or patterns.\n- **Impact:** How this change affects other parts of the application.\n\n**PR Title:** ${summary.title}\n**PR Summary:** ${summary.summary}\n\n**Code Diff:**\n\\`\\`\\`diff\n${diff}\n\\`\\`\\`\n`,\n    \"You are an expert programmer who writes excellent, clear, and comprehensive technical specification documents from pull request data.\"\n);\n\n// --- STRUCTURED JSON ---\n\nexport const explainCodeStructured = async (code: string): Promise<StructuredExplanation> => {\n    const systemInstruction = \"You are an expert software engineer providing a structured analysis of a code snippet. In the summary, identify any imported dependencies and explain their purpose within the code.\";\n    const prompt = `Analyze this code: \\n\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``;\n    const schema = { type: Type.OBJECT, properties: { summary: { type: Type.STRING }, lineByLine: { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { lines: { type: Type.STRING }, explanation: { type: Type.STRING } }, required: [\"lines\", \"explanation\"] } }, complexity: { type: Type.OBJECT, properties: { time: { type: Type.STRING }, space: { type: Type.STRING } }, required: [\"time\", \"space\"] }, suggestions: { type: Type.ARRAY, items: { type: Type.STRING } } }, required: [\"summary\", \"lineByLine\", \"complexity\", \"suggestions\"] };\n    return generateJson(prompt, systemInstruction, schema);\n}\n\nexport const generateThemeFromDescription = async (description: string): Promise<ColorTheme> => {\n    const systemInstruction = \"You are a UI/UX design expert specializing in color theory. Generate a color theme based on the user's description. Provide hex codes for each color.\";\n    const prompt = `Generate a color theme for: \"${description}\"`;\n    const schema = { type: Type.OBJECT, properties: { primary: { type: Type.STRING }, background: { type: Type.STRING }, surface: { type: Type.STRING }, textPrimary: { type: Type.STRING }, textSecondary: { type: Type.STRING }, textOnPrimary: { type: Type.STRING }, border: { type: Type.STRING } }, required: [\"primary\", \"background\", \"surface\", \"textPrimary\", \"textSecondary\", \"textOnPrimary\", \"border\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateSemanticTheme = (prompt: { parts: any[] }): Promise<SemanticColorTheme> => {\n    const systemInstruction = `You are a world-class UI/UX designer with an expert understanding of color theory, accessibility, and branding.\n    Your task is to generate a comprehensive, semantically named color theme from a user's prompt (which could be text or an image).\n    - Determine if the theme should be 'light' or 'dark' mode.\n    - Palette colors should be harmonious and versatile.\n    - Theme colors must be derived from the palette and assigned to specific UI roles (background, text, border, etc.).\n    - 'textOnPrimary' MUST have a high contrast ratio against 'primary'.\n    - You MUST calculate the WCAG 2.1 contrast ratio for key text/background pairs and provide a score (AAA, AA, or Fail).\n    - Provide creative, evocative names for each color (e.g., \"Midnight Blue\", \"Dune Sand\").`;\n\n    const colorObjectSchema = {\n        type: Type.OBJECT,\n        properties: {\n            value: { type: Type.STRING, description: \"The hex code of the color, e.g., #RRGGBB\" },\n            name: { type: Type.STRING, description: \"A creative, evocative name for the color.\" }\n        },\n        required: [\"value\", \"name\"]\n    };\n\n    const accessibilityCheckSchema = {\n        type: Type.OBJECT,\n        properties: {\n            ratio: { type: Type.NUMBER, description: \"The calculated contrast ratio.\" },\n            score: { type: Type.STRING, enum: [\"AAA\", \"AA\", \"Fail\"], description: \"The WCAG 2.1 accessibility score.\" }\n        },\n        required: [\"ratio\", \"score\"]\n    };\n\n    const schema = {\n        type: Type.OBJECT,\n        properties: {\n            mode: {\n                type: Type.STRING, enum: [\"light\", \"dark\"],\n                description: \"The recommended UI mode for this theme, 'light' or 'dark'.\"\n            },\n            palette: {\n                type: Type.OBJECT,\n                description: \"A harmonious 4-color palette extracted from the prompt.\",\n                properties: {\n                    primary: colorObjectSchema,\n                    secondary: colorObjectSchema,\n                    accent: colorObjectSchema,\n                    neutral: colorObjectSchema,\n                },\n                required: [\"primary\", \"secondary\", \"accent\", \"neutral\"]\n            },\n            theme: {\n                type: Type.OBJECT,\n                description: \"Specific color assignments for UI elements, derived from the palette.\",\n                properties: {\n                    background: colorObjectSchema,\n                    surface: colorObjectSchema,\n                    textPrimary: colorObjectSchema,\n                    textSecondary: colorObjectSchema,\n                    textOnPrimary: colorObjectSchema,\n                    border: colorObjectSchema,\n                },\n                required: [\"background\", \"surface\", \"textPrimary\", \"textSecondary\", \"textOnPrimary\", \"border\"]\n            },\n            accessibility: {\n                type: Type.OBJECT,\n                description: \"WCAG 2.1 contrast ratio checks for common text/background pairings.\",\n                properties: {\n                    primaryOnSurface: accessibilityCheckSchema,\n                    textPrimaryOnSurface: accessibilityCheckSchema,\n                    textSecondaryOnSurface: accessibilityCheckSchema,\n                    textOnPrimaryOnPrimary: accessibilityCheckSchema,\n                },\n                required: [\"primaryOnSurface\", \"textPrimaryOnSurface\", \"textSecondaryOnSurface\", \"textOnPrimaryOnPrimary\"]\n            }\n        },\n        required: [\"mode\", \"palette\", \"theme\", \"accessibility\"]\n    };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\n\nexport const generatePrSummaryStructured = (diff: string): Promise<StructuredPrSummary> => {\n    const systemInstruction = \"You are an expert programmer who writes excellent PR summaries.\";\n    const prompt = `Generate a PR summary for the following diff:\\n\\n\\`\\`\\`diff\\n${diff}\\n\\`\\`\\``;\n    const schema = { type: Type.OBJECT, properties: { title: { type: Type.STRING }, summary: { type: Type.STRING }, changes: { type: Type.ARRAY, items: { type: Type.STRING } } }, required: [\"title\", \"summary\", \"changes\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateFeature = (prompt: string, framework: string, styling: string): Promise<GeneratedFile[]> => {\n    const systemInstruction = `You are an AI that generates complete, production-ready components. Create all necessary files for the requested framework and styling option.\n    IMPORTANT: When the user's prompt is about maps, location, addresses, or stores, you MUST use the Google Maps JavaScript API. Generate a component that accepts an 'apiKey' prop and uses it to load the Maps script.`;\n    const userPrompt = `Generate the files for a ${framework} component using ${styling} for the following feature request: \"${prompt}\". Make sure to include a .tsx component file.`;\n    const schema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(userPrompt, systemInstruction, schema);\n};\n\nexport const generateFullStackFeature = (prompt: string, framework: string, styling: string): Promise<GeneratedFile[]> => {\n    const systemInstruction = `You are an AI that generates complete, production-ready full-stack features.\n    You must generate three files:\n    1. A frontend ${framework} component using ${styling}. File path should be 'Component.tsx'.\n    2. A backend Google Cloud Function in Node.js. File path should be a simple HTTP-triggered function.\n    3. Firestore Security Rules that allow public reads but only authenticated writes. File path should be 'firestore.rules'.\n    Ensure the frontend component knows how to call the cloud function.\n    IMPORTANT: When the user's prompt is about maps, location, addresses, or stores, you MUST prioritize using the Google Maps JavaScript API in the frontend component. Generate a component that accepts an 'apiKey' prop and uses it to load the Maps script.`;\n    const userPrompt = `Generate a full-stack feature for: \"${prompt}\"`;\n    const schema = {\n        type: Type.ARRAY,\n        items: {\n            type: Type.OBJECT,\n            properties: {\n                filePath: { type: Type.STRING, enum: ['Component.tsx', 'functions/index.js', 'firestore.rules'] },\n                content: { type: Type.STRING },\n                description: { type: Type.STRING }\n            },\n            required: [\"filePath\", \"content\", \"description\"]\n        }\n    };\n    return generateJson(userPrompt, systemInstruction, schema);\n};\n\nexport interface CronParts { minute: string; hour: string; dayOfMonth: string; month: string; dayOfWeek: string; }\nexport const generateCronFromDescription = (description: string): Promise<CronParts> => {\n    const systemInstruction = \"You are an expert in cron expressions. Convert the user's description into a valid cron expression parts.\";\n    const prompt = `Convert this schedule to a cron expression: \"${description}\"`;\n    const schema = { type: Type.OBJECT, properties: { minute: { type: Type.STRING }, hour: { type: Type.STRING }, dayOfMonth: { type: Type.STRING }, month: { type: Type.STRING }, dayOfWeek: { type: Type.STRING } }, required: [\"minute\", \"hour\", \"dayOfMonth\", \"month\", \"dayOfWeek\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateColorPalette = (baseColor: string): Promise<{ colors: string[] }> => {\n    const systemInstruction = \"You are a color theory expert. Generate a 6-color palette based on the given base color.\";\n    const prompt = `Generate a harmonious 6-color palette based on the color ${baseColor}.`;\n    const schema = { type: Type.OBJECT, properties: { colors: { type: Type.ARRAY, items: { type: Type.STRING } } }, required: [\"colors\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateMockData = (description: string, count: number): Promise<object[]> => {\n    const systemInstruction = \"You are an expert data scientist who creates realistic mock data based on a schema description. You must respond with only a valid JSON array of objects.\";\n    const prompt = `Generate an array of ${count} mock data objects based on the following schema description. Respond with only the JSON array.\\n\\nSchema: \"${description}\"`;\n    const schema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: {} }}; // Freeform objects\n    return generateJson(prompt, systemInstruction, schema, 0.8);\n};\n\nexport const analyzeCodeForVulnerabilities = (code: string): Promise<SecurityVulnerability[]> => {\n    const systemInstruction = \"You are an expert security engineer. Analyze the code for vulnerabilities. For each vulnerability, provide a structured response including a potential cURL command or code snippet to demonstrate the exploit.\";\n    const prompt = `Analyze this code for security issues like XSS, injection, hardcoded secrets, etc. Provide detailed explanations, mitigation advice, and an exploit suggestion.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``;\n    const schema = {\n        type: Type.ARRAY,\n        items: {\n            type: Type.OBJECT,\n            properties: {\n                vulnerability: { type: Type.STRING },\n                severity: { type: Type.STRING, enum: ['Critical', 'High', 'Medium', 'Low', 'Informational'] },\n                description: { type: Type.STRING },\n                mitigation: { type: Type.STRING },\n                exploitSuggestion: { type: Type.STRING, description: \"A cURL command, code snippet, or description of how to exploit the vulnerability.\" }\n            },\n            required: ['vulnerability', 'severity', 'description', 'mitigation', 'exploitSuggestion']\n        }\n    };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const sqlToApiEndpoints = (schema: string, framework: 'express' | 'fastify'): Promise<GeneratedFile[]> => {\n    const systemInstruction = \"You are an expert backend developer who generates boilerplate CRUD API endpoints from a SQL schema.\";\n    const prompt = `Generate boilerplate CRUD API endpoint files for a ${framework} server based on the following SQL table schema. Create separate files for routes, controllers, and models.\\n\\nSQL:\\n\\`\\`\\`sql\\n${schema}\\n\\`\\`\\``;\n    const filesSchema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(prompt, systemInstruction, filesSchema);\n};\n\nexport const detectCodeSmells = (code: string): Promise<CodeSmell[]> => {\n    const systemInstruction = \"You are an expert software engineer who identifies code smells like long methods, large classes, feature envy, etc.\";\n    const prompt = `Analyze the following code for code smells and provide explanations.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``;\n    const schema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { smell: { type: Type.STRING }, line: { type: Type.INTEGER }, explanation: { type: Type.STRING } }, required: [\"smell\", \"line\", \"explanation\"] } };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateTagsForCode = (code: string): Promise<string[]> => {\n    const systemInstruction = \"You are an AI assistant that analyzes code and suggests relevant tags.\";\n    const prompt = `Generate 3-5 relevant, single-word, lowercase tags for this code snippet to help categorize it. Respond with only a JSON array of strings.\\n\\nCode:\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``;\n    const schema = { type: Type.ARRAY, items: { type: Type.STRING } };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const reviewCodeStructured = (code: string): Promise<StructuredReview> => {\n    const systemInstruction = \"You are a senior software engineer performing a meticulous code review. Provide a summary and a list of specific, actionable suggestions for improvement.\";\n    const prompt = `Review this code and provide structured feedback:\\n\\n\\`\\`\\`\\n${code}\\n\\`\\`\\``;\n    const schema = {\n        type: Type.OBJECT,\n        properties: {\n            summary: { type: Type.STRING, description: \"A high-level summary of the code quality, identifying the main issues.\" },\n            suggestions: {\n                type: Type.ARRAY,\n                items: {\n                    type: Type.OBJECT,\n                    properties: {\n                        suggestion: { type: Type.STRING, description: \"A concise description of the suggested change.\" },\n                        codeBlock: { type: Type.STRING, description: \"The exact block of code that should be replaced.\" },\n                        explanation: { type: Type.STRING, description: \"Why the change is recommended (e.g., performance, readability).\" }\n                    },\n                    required: [\"suggestion\", \"codeBlock\", \"explanation\"]\n                }\n            }\n        },\n        required: [\"summary\", \"suggestions\"]\n    };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateClientFromApiSchema = (schema: string, framework: string): Promise<GeneratedFile[]> => {\n    const systemInstruction = \"You are an expert full-stack developer. Generate client-side code from an API schema.\";\n    const prompt = `Generate all necessary files for a ${framework} client based on the following OpenAPI/GraphQL schema. This should include data-fetching hooks, type definitions, and basic display components.\\n\\nSchema:\\n\\`\\`\\`\\n${schema}\\n\\`\\`\\``;\n    const filesSchema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(prompt, systemInstruction, filesSchema);\n};\n\nexport const generateTerraformConfig = (cloud: 'aws' | 'gcp', description: string, context?: string): Promise<string> => {\n    const systemInstruction = `You are a DevOps expert specializing in Terraform. Generate a complete .tf file based on the user's description.`;\n    const prompt = `Generate a Terraform configuration for ${cloud}.\n    Description: \"${description}\"\n    ${context ? `\\n\\nCloud Context (e.g., existing resources):\\n${context}` : ''}\n    Respond with only the HCL code in a markdown block.`;\n    return generateContent(prompt, systemInstruction);\n};\n\n\n// --- FUNCTION CALLING ---\nexport interface CommandResponse { text: string; functionCalls?: { name: string; args: any; }[]; }\nexport const getInferenceFunction = async (prompt: string, functionDeclarations: FunctionDeclaration[], knowledgeBase: string): Promise<CommandResponse> => {\n    try {\n        const aiClient = await getAi();\n        const response: GenerateContentResponse = await aiClient.models.generateContent({ model: \"gemini-2.5-flash\", contents: prompt, config: { systemInstruction: `You are a helpful assistant for a developer tool. You must decide which function to call to satisfy the user's request, based on your knowledge base. If no specific tool seems appropriate, respond with text.\\n\\nKnowledge Base:\\n${knowledgeBase}`, tools: [{ functionDeclarations }] } });\n        const functionCalls: { name: string, args: any }[] = [];\n        const parts = response.candidates?.[0]?.content?.parts ?? [];\n        for (const part of parts) { if (part.functionCall) { functionCalls.push({ name: part.functionCall.name, args: part.functionCall.args }); } }\n        return { text: response.text, functionCalls: functionCalls.length > 0 ? functionCalls : undefined };\n    } catch (error) {\n        logError(error as Error, { prompt });\n        throw error;\n    }\n};\n\n\n// --- IMAGE & VIDEO GENERATION ---\nexport const generateImage = async (prompt: string): Promise<string> => {\n    const aiClient = await getAi();\n    const response = await aiClient.models.generateImages({\n        model: 'imagen-4.0-generate-001',\n        prompt: prompt,\n        config: { numberOfImages: 1, outputMimeType: 'image/png' },\n    });\n    const base64ImageBytes: string = response.generatedImages[0].image.imageBytes;\n    return `data:image/png;base64,${base64ImageBytes}`;\n};\n\nexport const generateImageFromImageAndText = async (prompt: string, base64Image: string, mimeType: string): Promise<string> => {\n    const aiClient = await getAi();\n    const response = await aiClient.models.generateContent({\n        model: 'gemini-2.5-flash-image-preview',\n        contents: {\n            parts: [\n                { inlineData: { data: base64Image, mimeType: mimeType } },\n                { text: prompt },\n            ],\n        },\n        config: {\n            responseModalities: [Modality.IMAGE, Modality.TEXT],\n        },\n    });\n\n    for (const part of response.candidates[0].content.parts) {\n        if (part.inlineData) {\n            const base64ImageBytes: string = part.inlineData.data;\n            return `data:${part.inlineData.mimeType};base64,${base64ImageBytes}`;\n        }\n    }\n\n    throw new Error(\"AI did not return an image. It may have refused the request.\");\n};\n\n\nexport const generateMultiComponentFlowFromVideo = async (videoBase64: string, mimeType: string, onUpdate: (message: string) => void): Promise<GeneratedFile[]> => {\n    const aiClient = await getAi();\n    const systemInstruction = \"You are an expert frontend developer. Analyze the user flow in this screen recording and generate all the necessary React components and routing logic to replicate it. Create separate files for each component.\";\n    \n    onUpdate(\"Starting video analysis...\");\n    let operation = await aiClient.models.generateVideos({\n      model: 'veo-2.0-generate-001',\n      prompt: \"A short, silent video showing a user interacting with a web UI. Transcribe the actions and UI elements into a step-by-step description of the user flow.\",\n      config: { numberOfVideos: 1 }\n    });\n\n    onUpdate(\"Video processing initiated. This may take several minutes...\");\n    while (!operation.done) {\n      await sleep(10000);\n      onUpdate(\"Checking video status...\");\n      operation = await aiClient.operations.getVideosOperation({operation: operation});\n    }\n\n    onUpdate(\"Video processing complete. Generating code from flow...\");\n    // This is a conceptual placeholder. A real implementation would require a multimodal model that can output structured data from video.\n    const flowDescription = operation.response?.generatedVideos?.[0]?.video?.uri || \"A user clicks a list item, sees a detail page, and clicks a button.\";\n    \n    const filesSchema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(flowDescription, systemInstruction, filesSchema);\n};","\n\nimport React from 'react';\n\nconst IconWrapper: React.FC<{children: React.ReactNode; className?: string}> = ({ children, className }) => (\n    <div className={className ?? 'w-6 h-6'}>{children}</div>\n);\n\n// --- From InterfaceIcons.tsx ---\nexport const CpuChipIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 3v1.5M4.5 8.25H3m18 0h-1.5M8.25 21v-1.5M4.5 15.75H3m18 0h-1.5M21 8.25v7.5A2.25 2.25 0 0 1 18.75 18H5.25A2.25 2.25 0 0 1 3 15.75v-7.5A2.25 2.25 0 0 1 5.25 6h13.5A2.25 2.25 0 0 1 21 8.25ZM12 18V6\" /></svg></IconWrapper>;\nexport const DocumentIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\" /></svg></IconWrapper>;\nexport const FolderIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z\" /></svg></IconWrapper>;\nexport const LinkIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244\" /></svg></IconWrapper>;\nexport const ArchiveBoxIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m20.25 7.5-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z\" /></svg></IconWrapper>;\nexport const ClipboardDocumentIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876C9.083 2.25 6.105 5.106 6.105 9.125v3.375c0 .621.504 1.125 1.125 1.125h9.75Z\" /></svg></IconWrapper>;\nexport const ArrowDownTrayIcon: React.FC<{className?: string}> = ({className}) => <IconWrapper className={className}><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3\" /></svg></IconWrapper>;\nexport const XMarkIcon: React.FC<{className?: string}> = ({className}) => <IconWrapper className={className}><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" /></svg></IconWrapper>;\nexport const PlusIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\" /></svg></IconWrapper>;\nexport const TrashIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.134-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.067-2.09 1.02-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0\" /></svg></IconWrapper>;\nexport const PencilIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125\" /></svg></IconWrapper>;\nexport const MagnifyingGlassIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z\" /></svg></IconWrapper>;\nexport const Cog6ToothIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.594 3.94c.09-.542.56-1.008 1.11-1.212l2.39-1.062a1.25 1.25 0 0 1 1.415.602l.62 1.24a1.25 1.25 0 0 0 1.282.693l2.394-.852a1.25 1.25 0 0 1 1.415 1.415l-.852 2.394a1.25 1.25 0 0 0 .693 1.282l1.24.62a1.25 1.25 0 0 1 .602 1.415l-1.062 2.39a1.25 1.25 0 0 0-1.212 1.11l-.22 1.319a1.25 1.25 0 0 1-1.393 1.053l-2.32-.82a1.25 1.25 0 0 0-1.353 0l-2.32.82a1.25 1.25 0 0 1-1.393-1.053l-.22-1.319a1.25 1.25 0 0 0-1.212-1.11l-1.062-2.39a1.25 1.25 0 0 1 .602-1.415l1.24-.62a1.25 1.25 0 0 0 .693-1.282l-.852-2.394a1.25 1.25 0 0 1 1.415-1.415l2.394.852a1.25 1.25 0 0 0 1.282-.693l.62-1.24a1.25 1.25 0 0 1 1.415-.602l-2.39 1.062a1.25 1.25 0 0 0-1.11 1.212Z\" /><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z\" /></svg></IconWrapper>;\nexport const HomeIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h7.5\" /></svg></IconWrapper>;\nexport const ChevronDownIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m19.5 8.25-7.5 7.5-7.5-7.5\" /></svg></IconWrapper>;\nexport const SunIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z\" /></svg></IconWrapper>;\nexport const MoonIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z\" /></svg></IconWrapper>;\nexport const ArrowLeftOnRectangleIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m-3 0-3-3m0 0 3-3m-3 3H5\" /></svg></IconWrapper>;\nexport const ArrowUpOnSquareIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 8.25H7.5a2.25 2.25 0 0 0-2.25 2.25v9a2.25 2.25 0 0 0 2.25 2.25h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25H15m0-3-3-3m0 0-3 3m3-3v12\" /></svg></IconWrapper>;\nconst WindowIconWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (<div className=\"w-4 h-4\">{children}</div>);\nexport const MinimizeIcon: React.FC = () => <WindowIconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={3} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 12h14\" /></svg></WindowIconWrapper>;\nexport const MaximizeIcon: React.FC = () => <WindowIconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={3} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 4.5h15v15h-15z\" /></svg></WindowIconWrapper>;\nexport const RestoreIcon: React.FC = () => <WindowIconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={3} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.5 8.5h11v11h-11z M4.5 4.5h11v11h-11z\" /></svg></WindowIconWrapper>;\n\n// --- From FeatureIcons.tsx ---\nexport const FileCodeIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\" /></svg></IconWrapper>;\nexport const GitBranchIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 3v4a3 3 0 0 0 3 3h4a3 3 0 0 0 3-3V3M6 21v-4a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3v4M12 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4z\" /></svg></IconWrapper>;\nexport const SparklesIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456Z\" /></svg></IconWrapper>;\nexport const EyeIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.036 12.322a1.012 1.012 0 0 1 0-.639l4.368-7.28A1.012 1.012 0 0 1 7.105 4.5h9.79a1.012 1.012 0 0 1 .701.293l4.368 7.28c.15.25.228.538.228.828s-.078.578-.228.828l-4.368 7.28a1.012 1.012 0 0 1-.701.293h-9.79a1.012 1.012 0 0 1-.701-.293l-4.368-7.28Z\" /><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z\" /></svg></IconWrapper>;\nexport const MapIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 6.75V15m6-6v8.25m.5-10.5h-7a.5.5 0 0 0-.5.5v13.5a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 .5-.5V4.25a.5.5 0 0 0-.5-.5Z\" /></svg></IconWrapper>;\nexport const BeakerIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c.139-.02.28-.032.427-.032.147 0 .288.012.427.032M5 14.5h14M14.25 3.104v5.714c0 .822-.394 1.573-.986 2.05l-2.014.915a2.25 2.25 0 0 0-.659 1.591v5.714m-3.468-18.222.01.001\" /></svg></IconWrapper>;\nexport const CommandLineIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6.75 7.5 3 11.25l3.75 3.75M17.25 7.5 21 11.25l-3.75 3.75\" /></svg></IconWrapper>;\nexport const LockClosedIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.5 10.5V6.75a4.5 4.5 0 0 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z\" /></svg></IconWrapper>;\nexport const CodeBracketSquareIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.25 9.75 16.5 12l-2.25 2.25m-4.5 0L7.5 12l2.25-2.25M6 20.25h12A2.25 2.25 0 0 0 20.25 18V6A2.25 2.25 0 0 0 18 3.75H6A2.25 2.25 0 0 0 3.75 6v12A2.25 2.25 0 0 0 6 20.25Z\" /></svg></IconWrapper>;\nexport const PhotoIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z\" /></svg></IconWrapper>;\nexport const BellIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0\" /></svg></IconWrapper>;\nexport const ChartBarIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625Zm6.75-5.25c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V3.375Z\" /></svg></IconWrapper>;\nexport const BugAntIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m15.182 16.318A4.5 4.5 0 0 0 18 12a4.5 4.5 0 0 0-3.818-4.318m-3.564 4.318a4.5 4.5 0 0 1 3.564 0M6 12a4.5 4.5 0 0 1 3.818-4.318M12 12a4.5 4.5 0 0 1-3.818-4.318m0 8.636a4.5 4.5 0 0 1 3.818 0M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm0 0a8.949 8.949 0 0 0 5.482-1.611m-10.964 0A8.949 8.949 0 0 1 12 21Zm0 0a8.949 8.949 0 0 0-5.482-1.611m10.964 0A8.949 8.949 0 0 0 12 21Zm-5.482 1.61a8.973 8.973 0 0 1-2.18-1.001m10.342 0a8.973 8.973 0 0 0-2.18-1.001m-6-1.611a8.973 8.973 0 0 1-2.18-1.001M18 12a8.973 8.973 0 0 0-2.18-1.001m-6 0a8.973 8.973 0 0 1-2.18-1.001M6 12a8.973 8.973 0 0 0-2.18-1.001m10.342 0a8.973 8.973 0 0 0-2.18-1.001M12 3a8.973 8.973 0 0 1 2.18 1.001m-4.36 0A8.973 8.973 0 0 1 12 3m0 18a8.973 8.973 0 0 0 2.18-1.001m-4.36 0A8.973 8.973 0 0 0 12 21Zm0-18a8.973 8.973 0 0 0-2.18-1.001m4.36 0A8.973 8.973 0 0 0 12 3Z\" /></svg></IconWrapper>;\nexport const TerminalIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6.75 7.5l3.75 3.75L6.75 15m6-7.5h4.5\" /></svg></IconWrapper>;\nexport const ServerStackIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 20.25h12m-7.5-3.75v3.75m3.75-3.75v3.75M12 3c-5.12 0-9.25 4.13-9.25 9.25s4.13 9.25 9.25 9.25 9.25-4.13 9.25-9.25S17.12 3 12 3Z\" /></svg></IconWrapper>;\nexport const CloudIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 15a4.5 4.5 0 0 0 4.5 4.5H18a3.75 3.75 0 0 0 1.332-7.257 3 3 0 0 0-5.056-2.287 4.5 4.5 0 0 0-8.25-2.287 4.5 4.5 0 0 0-1.25 8.25Z\" /></svg></IconWrapper>;\nexport const PaperAirplaneIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5\" /></svg></IconWrapper>;\nexport const ShieldCheckIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.286Z\" /></svg></IconWrapper>;\nexport const ArrowPathIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 11.667 0l3.181-3.183m-4.991-2.691V5.25a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75\" /></svg></IconWrapper>;\nexport const RectangleGroupIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 7.125A2.25 2.25 0 0 1 4.5 4.875h15A2.25 2.25 0 0 1 21.75 7.125v10.5A2.25 2.25 0 0 1 19.5 19.875h-15A2.25 2.25 0 0 1 2.25 17.625v-10.5ZM11.25 4.875v10.5a2.25 2.25 0 0 1-2.25 2.25h-1.5a2.25 2.25 0 0 1-2.25-2.25v-10.5a2.25 2.25 0 0 1 2.25-2.25h1.5a2.25 2.25 0 0 1 2.25 2.25Z\" /></svg></IconWrapper>;\nexport const MusicalNoteIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 9V4.5M9 9c0 .54.06.913.175 1.313M9 9H4.5M9.175 10.313C9.06 10.087 9 9.85 9 9.6V4.5a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 .75.75v5.1a.75.75 0 0 1-.75.75h-.625a.75.75 0 0 1-.75-.75V9.75\" /></svg></IconWrapper>;\nexport const VideoCameraIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9A2.25 2.25 0 0 0 13.5 5.25h-9A2.25 2.25 0 0 0 2.25 7.5v9A2.25 2.25 0 0 0 4.5 18.75Z\" /></svg></IconWrapper>;\nexport const DocumentTextIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\" /></svg></IconWrapper>;\nexport const PaintBrushIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\" /></svg></IconWrapper>;\nexport const PuzzlePieceIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.25 6.087c0-1.036-.84-1.875-1.875-1.875s-1.875.84-1.875 1.875v.563c-1.036 0-1.875.84-1.875 1.875v1.5c0 1.036.84 1.875 1.875 1.875h1.5c1.036 0 1.875-.84 1.875-1.875v-1.5c0-1.036-.84-1.875-1.875-1.875v-.563Zm-4.5 0v.563c-1.036 0-1.875.84-1.875 1.875v1.5c0 1.036.84 1.875 1.875 1.875h1.5c1.036 0 1.875-.84 1.875-1.875v-1.5c0-1.036-.84-1.875-1.875-1.875v-.563a1.875 1.875 0 0 0-3.75 0Z\" /></svg></IconWrapper>;\nexport const MicrophoneIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 18.75a6 6 0 0 0 6-6v-1.5m-6 7.5a6 6 0 0 1-6-6v-1.5m12 4.5v-1.5a6 6 0 0 0-12 0v1.5m12 0v-1.5a6 6 0 0 0-12 0v1.5m6 3.75a3 3 0 0 1-3-3V6.75a3 3 0 0 1 6 0v6a3 3 0 0 1-3 3Z\" /></svg></IconWrapper>;\nexport const MailIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75\" /></svg></IconWrapper>;\n\n\n// --- From CustomFeatureIcons.tsx ---\nexport const CommandCenterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 9V5l-7 7 7 7v-4.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/><path d=\"M14 14.5V19l7-7-7-7v4.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/><circle cx=\"12\" cy=\"12\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/></svg></IconWrapper>;\nexport const ProjectExplorerIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 9.75h16.5m-16.5 4.5h16.5m-16.5 4.5h16.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z\" /></svg></IconWrapper>;\nexport const ConnectionsIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244\" /></svg></IconWrapper>;\nexport const CodeExplainerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"/><path d=\"M14 2v6h6\"/><circle cx=\"12\" cy=\"15\" r=\"3\"/><path d=\"M12 18v2\"/></svg></IconWrapper>;\nexport const FeatureBuilderIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5\"/><path d=\"M2 12l10 5 10-5\"/><path d=\"M17 8.5l-5 2.5-5-2.5\"/><path d=\"M12 17.5V14\"/></svg></IconWrapper>;\nexport const CodeMigratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 22H5a2 2 0 01-2-2V4a2 2 0 012-2h5\"/><path d=\"M14 2h5a2 2 0 012 2v16a2 2 0 01-2 2h-5\"/><path d=\"M7 8h2m-2 4h4m-4 4h2\"/></svg></IconWrapper>;\nexport const ThemeDesignerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 2a10 10 0 000 20z\"/><path d=\"M22 12c-5.523 0-10-4.477-10-10\"/></svg></IconWrapper>;\nexport const SnippetVaultIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\" ry=\"2\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M8 12h8m-4-4v8\"/></svg></IconWrapper>;\nexport const DigitalWhiteboardIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" /><path d=\"M7 8h4m-4 4h8m-8 4h6\" /></svg></IconWrapper>;\nexport const UnitTestGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M4.5 12.5l3-3 3 3 6-6\"/><path d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"/></svg></IconWrapper>;\nexport const CommitGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2\"/><rect x=\"8\" y=\"2\" width=\"8\" height=\"4\" rx=\"1\" ry=\"1\"/></svg></IconWrapper>;\nexport const GitLogAnalyzerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M6 3v18\"/><path d=\"M18 3v18\"/><path d=\"M12 3v18\"/><circle cx=\"6\" cy=\"6\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/><circle cx=\"12\" cy=\"12\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/><circle cx=\"18\" cy=\"18\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/></svg></IconWrapper>;\nexport const ConcurrencyAnalyzerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M18 6l-6 6-6-6\"/><path d=\"M18 18l-6-6-6 6\"/></svg></IconWrapper>;\nexport const RegexSandboxIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M15 4l-8 16\"/><path d=\"M22 12H2\"/><path d=\"M10 3L6 21\"/></svg></IconWrapper>;\nexport const PromptCraftPadIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\"/></svg></IconWrapper>;\nexport const CodeFormatterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M3 6h3m-3 6h3m-3 6h3M9 6h12M9 12h12M9 18h12\"/></svg></IconWrapper>;\nexport const JsonTreeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 21v-4a2 2 0 012-2h8\"/><path d=\"M10 17H5a2 2 0 01-2-2V5a2 2 0 012-2h8a2 2 0 012 2v2\"/><rect x=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"2\" ry=\"2\" opacity=\"0.2\"/></svg></IconWrapper>;\nexport const XbrlConverterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M8 8l-4 4 4 4m8-8l4 4-4-4\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/><path d=\"M14.5 5.5l-5 13\" strokeLinecap=\"round\"/></svg></IconWrapper>;\nexport const CssGridEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"/></svg></IconWrapper>;\nexport const SchemaDesignerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M4 7V4h16v3\"/><path d=\"M4 12h16\"/><path d=\"M4 17h16\"/><rect x=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"2\" ry=\"2\" opacity=\"0.2\"/></svg></IconWrapper>;\nexport const PwaManifestEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 22a10 10 0 100-20 10 10 0 000 20z\"/><path d=\"M12 12l4-4m-4 8l-4-4\"/></svg></IconWrapper>;\nexport const MarkdownSlidesIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M20 3H4a2 2 0 00-2 2v14a2 2 0 002 2h16a2 2 0 002-2V5a2 2 0 00-2-2z\"/><path d=\"M9 16V8h6\"/></svg></IconWrapper>;\nexport const ScreenshotToComponentIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\"/><path d=\"M7 10l5-5 5 5m-5 8v-13\"/></svg></IconWrapper>;\nexport const TypographyLabIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M4 7V4h16v3\"/><path d=\"M4 17h16\"/><rect x=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"2\" ry=\"2\" opacity=\"0.2\"/></svg></IconWrapper>;\nexport const SvgPathEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 20.9l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 20.9z\"/></svg></IconWrapper>;\nexport const StyleTransferIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 2.69l.94-2.69.94 2.69L16.5 3l-2.69.94L13 6.58 12 4l-1 2.58L8.31 4 5.62 3l2.69.94.94 2.69.94-2.69z\"/><path d=\"M12 2.69l.94-2.69.94 2.69L16.5 3l-2.69.94L13 6.58 12 4l-1 2.58L8.31 4 5.62 3l2.69.94.94 2.69.94-2.69zM12 2.69l.94-2.69.94 2.69L16.5 3l-2.69.94L13 6.58 12 4l-1 2.58L8.31 4 5.62 3l2.69.94.94 2.69.94-2.69zM3.5 13.5c0-4.694 3.806-8.5 8.5-8.5s8.5 3.806 8.5 8.5-3.806 8.5-8.5 8.5-8.5-3.806-8.5-8.5z\"/></svg></IconWrapper>;\nexport const CodingChallengeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 8V6m0 12v-2m-4-6H6m12 0h-2m-2-4l-1.5-1.5M18 18l-1.5-1.5M6 18l1.5-1.5M6 6l1.5 1.5\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg></IconWrapper>;\nexport const CodeReviewBotIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 20V10m0 0V4m0 6h8m-8 0H4\"/><path d=\"M12 20a8 8 0 100-16 8 8 0 000 16z\"/></svg></IconWrapper>;\nexport const AiPullRequestAssistantIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M13 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V9z\"/><path d=\"M13 2v7h7\"/><path d=\"M17.5 2.5l-2-2m2 2l2-2m-2 2v4\"/></svg></IconWrapper>;\nexport const ChangelogGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"/><path d=\"M14 2v6h6\"/><path d=\"M16 13H8m8 4H8m-1-8l-2-2-2 2\"/></svg></IconWrapper>;\nexport const CronJobBuilderIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"/></svg></IconWrapper>;\nexport const AsyncCallTreeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M3 6h18M3 12h18M3 18h18\"/><path d=\"M6 3v18m12-18v18\"/></svg></IconWrapper>;\nexport const AudioToCodeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z\"/><path d=\"M19 10v2a7 7 0 01-14 0v-2\"/><path d=\"M12 19v4\"/></svg></IconWrapper>;\nexport const CodeDiffGhostIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M16 16l-4-4 4-4m-8 8l4-4-4-4\"/></svg></IconWrapper>;\nexport const CodeSpellCheckerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.72\"/><path d=\"M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.72-1.72\"/></svg></IconWrapper>;\nexport const ColorPaletteGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\"/></svg></IconWrapper>;\nexport const LogicFlowBuilderIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M3 6h18m-9 6H3m9 6H3\"/><path d=\"M8 3v18m8-18v18\"/></svg></IconWrapper>;\nexport const MetaTagEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z\"/><path d=\"M7 7h.01\"/></svg></IconWrapper>;\nexport const NetworkVisualizerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M18 10h4V6h-4V2l-4 4 4 4zM6 14H2v4h4v4l4-4-4-4z\"/><path d=\"M10 14v-4h4v4\"/></svg></IconWrapper>;\nexport const ResponsiveTesterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"/><path d=\"M21 12a9 9 0 00-9-9m9 9a9 9 0 01-9 9\"/></svg></IconWrapper>;\nexport const SassCompilerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21.168 18.168A10 10 0 118.832 2.832m12.336 15.336L8.832 2.832\"/></svg></IconWrapper>;\nexport const ImageGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><path d=\"M21 15l-5-5L5 21\"/></svg></IconWrapper>;\nexport const GithubIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path fillRule=\"evenodd\" d=\"M12 2C6.477 2 2 6.477 2 12c0 4.418 2.865 8.168 6.839 9.492.5.092.682-.217.682-.482 0-.237-.009-.868-.014-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.031-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.03 1.595 1.03 2.688 0 3.848-2.338 4.695-4.566 4.942.359.308.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.001 10.001 0 0022 12c0-5.523-4.477-10-10-10z\" clipRule=\"evenodd\" /></svg></IconWrapper>;\nexport const HuggingFaceIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20.25,4.01A2.25,2.25,0,0,0,18,1.76H6A2.25,2.25,0,0,0,3.75,4.01V15.5A2.25,2.25,0,0,0,6,17.75H8.6l3.4,3.4,3.4-3.4H18a2.25,2.25,0,0,0,2.25-2.25V4.01ZM8.5,12.06a1,1,0,0,1,1,1,1,1,0,0,1-2,0,1,1,0,0,1,1-1Zm4.9,0a1,1,0,0,1,1,1,1,1,0,0,1-2,0,1,1,0,0,1,1-1Zm2.6,3.44a3.25,3.25,0,0,1-6,0,.75.75,0,0,1,1.5,0,1.75,1.75,0,0,0,3,0,.75.75,0,0,1,1.5,0Z\"/></svg></IconWrapper>;\nexport const GcpIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 2L2 7l10 5 10-5-10-5z\" fill=\"#4285F4\" stroke=\"none\"/><path d=\"M2 12l10 5 10-5-10-5-10 5z\" fill=\"#34A853\" stroke=\"none\" opacity=\"0.7\"/><path d=\"M12 22L2 17l10-5 10 5-10 5z\" fill=\"#FBBC05\" stroke=\"none\" opacity=\"0.7\"/></svg></IconWrapper>;\n","import React, { useState, useEffect } from 'react';\nimport { marked } from 'marked';\n\nexport const LoadingSpinner: React.FC = () => (\n    <div className=\"flex items-center justify-center space-x-1\" aria-label=\"Loading\">\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n    </div>\n);\n\ninterface MarkdownRendererProps {\n    content: string;\n}\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content }) => {\n    const [sanitizedHtml, setSanitizedHtml] = useState<string | TrustedHTML>('');\n\n    useEffect(() => {\n        const parse = async () => {\n            if (content) {\n                const html = await marked.parse(content);\n                setSanitizedHtml(html);\n            } else {\n                setSanitizedHtml('');\n            }\n        };\n        parse();\n    }, [content]);\n\n    return (\n        <div\n            className=\"prose prose-sm max-w-none prose-headings:text-text-primary prose-p:text-text-primary prose-strong:text-text-primary prose-code:text-primary prose-code:before:content-none prose-code:after:content-none prose-pre:bg-gray-50 prose-pre:border prose-pre:border-border prose-pre:p-4 prose-pre:m-0\"\n            dangerouslySetInnerHTML={{ __html: sanitizedHtml }}\n        />\n    );\n};\n","import React from 'react';\nimport { logError } from '../services/telemetryService.ts';\nimport { debugErrorStream } from '../services/aiService.ts';\nimport { SparklesIcon } from './icons.tsx';\nimport { MarkdownRenderer, LoadingSpinner } from './shared/index.tsx';\n\ninterface Props {\n  children: React.ReactNode;\n}\n\ninterface State {\n  hasError: boolean;\n  error: Error | null;\n  aiHelp: string;\n  isAiLoading: boolean;\n}\n\nexport class ErrorBoundary extends React.Component<Props, State> {\n  constructor(props: Props) {\n    super(props);\n    this.state = { hasError: false, error: null, aiHelp: '', isAiLoading: false };\n  }\n\n  static getDerivedStateFromError(error: Error): Partial<State> {\n    return { hasError: true, error };\n  }\n\n  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n    logError(error, { componentStack: errorInfo.componentStack });\n  }\n  \n  handleRevert = () => {\n    window.location.reload();\n  };\n\n  handleAskAi = async () => {\n    if (!this.state.error) return;\n\n    this.setState({ isAiLoading: true, aiHelp: '' });\n    try {\n        const stream = debugErrorStream(this.state.error);\n        let fullResponse = '';\n        for await (const chunk of stream) {\n            fullResponse += chunk;\n            this.setState({ aiHelp: fullResponse });\n        }\n    } catch (e) {\n        this.setState({ aiHelp: 'Sorry, the AI assistant could not be reached.' });\n        logError(e as Error, { context: 'AI Error Debugging' });\n    } finally {\n        this.setState({ isAiLoading: false });\n    }\n};\n\n  render() {\n    if (this.state.hasError) {\n      return (\n        <div className=\"w-full h-full flex flex-col items-center justify-center p-4 sm:p-6 lg:p-8 bg-background text-text-primary\">\n            <div className=\"w-full max-w-4xl bg-surface border border-border rounded-lg p-6 shadow-2xl grid grid-cols-1 md:grid-cols-2 gap-6\">\n                <div className=\"flex flex-col\">\n                    <h1 className=\"text-2xl font-bold text-red-600 mb-2\">An Unexpected Error Occurred</h1>\n                    <p className=\"text-text-secondary mb-4\">A component has crashed. You can try reloading or ask the AI for debugging help.</p>\n                    \n                    <details className=\"text-left bg-gray-50 dark:bg-slate-900 p-2 rounded-md max-w-xl text-xs font-mono mb-4 flex-grow overflow-auto border border-border\">\n                        <summary className=\"cursor-pointer\">Error Details</summary>\n                        <pre className=\"mt-2 whitespace-pre-wrap\">{this.state.error?.stack}</pre>\n                    </details>\n                    \n                    <div className=\"flex gap-4 mt-auto\">\n                        <button\n                            onClick={this.handleRevert}\n                            className=\"flex-1 px-4 py-2 bg-yellow-400 text-yellow-900 font-bold rounded-md hover:bg-yellow-300 transition-colors\"\n                        >\n                            Reload Application\n                        </button>\n                         <button\n                            onClick={this.handleAskAi}\n                            disabled={this.state.isAiLoading}\n                            className=\"btn-primary flex-1 px-4 py-2 flex items-center justify-center gap-2\"\n                        >\n                            <SparklesIcon />\n                            {this.state.isAiLoading ? 'Analyzing...' : 'Ask AI for Help'}\n                        </button>\n                    </div>\n                </div>\n\n                <div className=\"flex flex-col bg-gray-50 dark:bg-slate-900 rounded-lg p-4 border border-border\">\n                    <h2 className=\"text-lg font-bold text-text-primary mb-2\">AI Assistant</h2>\n                    <div className=\"flex-grow overflow-y-auto\">\n                        {this.state.isAiLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div>}\n                        {this.state.aiHelp && <MarkdownRenderer content={this.state.aiHelp} />}\n                        {!this.state.isAiLoading && !this.state.aiHelp && <p className=\"text-text-secondary text-center pt-10\">Click \"Ask AI\" to get debugging suggestions.</p>}\n                    </div>\n                </div>\n            </div>\n        </div>\n      );\n    }\n\n    return this.props.children;\n  }\n}\n","import React, { createContext, useReducer, useContext, useEffect } from 'react';\nimport type { ViewType, AppUser, GitHubUser, FileNode } from '../types.ts';\n\n// State shape\ninterface GlobalState {\n  activeView: ViewType;\n  viewProps: any;\n  hiddenFeatures: string[];\n  user: AppUser | null;\n  githubUser: GitHubUser | null;\n  projectFiles: FileNode | null;\n  // Fix: Expand selectedRepo to include full_name and name for consistent usage across components\n  selectedRepo: { owner: string; repo: string; full_name: string; name: string; } | null;\n  vaultState: {\n    isInitialized: boolean;\n    isUnlocked: boolean;\n  };\n  isApiKeyMissing: boolean;\n}\n\n// Action types\ntype Action =\n  | { type: 'SET_VIEW'; payload: { view: ViewType, props?: any } }\n  | { type: 'TOGGLE_FEATURE_VISIBILITY'; payload: { featureId: string } }\n  | { type: 'SET_APP_USER', payload: AppUser | null }\n  | { type: 'SET_GITHUB_USER', payload: GitHubUser | null }\n  | { type: 'LOAD_PROJECT_FILES'; payload: FileNode | null }\n  // Fix: Expand selectedRepo payload to include full_name and name\n  | { type: 'SET_SELECTED_REPO'; payload: { owner: string; repo: string; full_name: string; name: string; } | null }\n  | { type: 'SET_VAULT_STATE'; payload: Partial<{ isInitialized: boolean, isUnlocked: boolean }> }\n  | { type: 'SET_API_KEY_MISSING', payload: boolean };\n\n\nconst initialState: GlobalState = {\n  activeView: 'project-explorer',\n  viewProps: {},\n  hiddenFeatures: [],\n  user: null,\n  githubUser: null,\n  projectFiles: null,\n  selectedRepo: null,\n  vaultState: {\n    isInitialized: false,\n    isUnlocked: false,\n  },\n  isApiKeyMissing: false,\n};\n\nconst reducer = (state: GlobalState, action: Action): GlobalState => {\n  switch (action.type) {\n    case 'SET_VIEW':\n      return { ...state, activeView: action.payload.view, viewProps: action.payload.props || {} };\n    case 'TOGGLE_FEATURE_VISIBILITY': {\n        const { featureId } = action.payload;\n        const isHidden = state.hiddenFeatures.includes(featureId);\n        const newHiddenFeatures = isHidden\n            ? state.hiddenFeatures.filter(id => id !== featureId)\n            : [...state.hiddenFeatures, featureId];\n        return { ...state, hiddenFeatures: newHiddenFeatures };\n    }\n    case 'SET_APP_USER':\n        if (action.payload === null) { // User logged out\n            return {\n                ...initialState, // Reset to initial state on logout\n                user: null,\n            }\n        }\n        return { ...state, user: action.payload };\n    case 'SET_GITHUB_USER':\n        return {\n            ...state,\n            githubUser: action.payload,\n             // Reset repo-specific data if disconnected\n            selectedRepo: action.payload ? state.selectedRepo : null,\n            projectFiles: action.payload ? state.projectFiles : null,\n        }\n    case 'LOAD_PROJECT_FILES':\n      return { ...state, projectFiles: action.payload };\n    case 'SET_SELECTED_REPO':\n      return { ...state, selectedRepo: action.payload, projectFiles: null }; // Reset files on repo change\n    case 'SET_VAULT_STATE':\n        return {\n            ...state,\n            vaultState: { ...state.vaultState, ...action.payload },\n        };\n    case 'SET_API_KEY_MISSING':\n        return { ...state, isApiKeyMissing: action.payload };\n    default:\n      return state;\n  }\n};\n\nconst GlobalStateContext = createContext<{\n  state: GlobalState;\n  dispatch: React.Dispatch<Action>;\n}>({\n  state: initialState,\n  dispatch: () => null,\n});\n\nconst LOCAL_STORAGE_KEY = 'devcore_snapshot';\nconst CONSENT_KEY = 'devcore_ls_consent';\n\nexport const GlobalStateProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n    const canPersist = (() => {\n        try {\n            return localStorage.getItem(CONSENT_KEY) === 'granted';\n        } catch (e) {\n            return false;\n        }\n    })();\n\n    const [state, dispatch] = useReducer(reducer, initialState, (initial) => {\n        if (!canPersist) return initial;\n        \n        try {\n            const storedStateJSON = localStorage.getItem(LOCAL_STORAGE_KEY);\n            if (!storedStateJSON) return initial;\n            \n            const storedState = JSON.parse(storedStateJSON);\n            const hydratedState = { ...initial };\n\n            // Hydrate state from local storage\n            if (storedState.selectedRepo) hydratedState.selectedRepo = storedState.selectedRepo;\n            if (storedState.activeView) hydratedState.activeView = storedState.activeView;\n            if (storedState.viewProps) hydratedState.viewProps = storedState.viewProps;\n            if (storedState.hiddenFeatures) hydratedState.hiddenFeatures = storedState.hiddenFeatures;\n            \n            return hydratedState;\n        } catch (error) {\n            console.error(\"Failed to parse state from localStorage\", error);\n            return initial;\n        }\n    });\n\n    useEffect(() => {\n        if (!canPersist) return;\n\n        const handler = setTimeout(() => {\n            try {\n                const stateToSave = { \n                    selectedRepo: state.selectedRepo,\n                    activeView: state.activeView,\n                    viewProps: state.viewProps,\n                    hiddenFeatures: state.hiddenFeatures, \n                };\n                localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(stateToSave));\n            } catch (error) {\n                console.error(\"Failed to save state to localStorage\", error);\n            }\n        }, 500);\n\n        return () => clearTimeout(handler);\n    }, [state, canPersist]);\n\n    return (\n        <GlobalStateContext.Provider value={{ state, dispatch }}>\n            {children}\n        </GlobalStateContext.Provider>\n    );\n};\n\nexport const useGlobalState = () => useContext(GlobalStateContext);","\n\nimport React from 'react';\nimport {\n    CommandCenterIcon, CodeExplainerIcon, FeatureBuilderIcon, CodeMigratorIcon, ThemeDesignerIcon, SnippetVaultIcon,\n    UnitTestGeneratorIcon, CommitGeneratorIcon, GitLogAnalyzerIcon, ConcurrencyAnalyzerIcon, RegexSandboxIcon,\n    PromptCraftPadIcon, CodeFormatterIcon, JsonTreeIcon, CssGridEditorIcon, SchemaDesignerIcon, PwaManifestEditorIcon,\n    MarkdownSlidesIcon, ScreenshotToComponentIcon, SvgPathEditorIcon, StyleTransferIcon, CodingChallengeIcon,\n    CodeReviewBotIcon, ChangelogGeneratorIcon, CronJobBuilderIcon,\n    AsyncCallTreeIcon, AudioToCodeIcon, CodeDiffGhostIcon, CodeSpellCheckerIcon, ColorPaletteGeneratorIcon, LogicFlowBuilderIcon,\n    MetaTagEditorIcon, NetworkVisualizerIcon, ResponsiveTesterIcon, SassCompilerIcon, ImageGeneratorIcon, XbrlConverterIcon,\n    DigitalWhiteboardIcon, TypographyLabIcon, AiPullRequestAssistantIcon, ProjectExplorerIcon,\n    ServerStackIcon, DocumentTextIcon, ChartBarIcon, EyeIcon, PaperAirplaneIcon, CloudIcon, ShieldCheckIcon, CpuChipIcon, SparklesIcon,\n    MailIcon, BugAntIcon, MagnifyingGlassIcon, RectangleGroupIcon, GcpIcon, HomeIcon, PhotoIcon\n} from './components/icons.tsx';\n\nexport const CHROME_VIEW_IDS = ['features-list'] as const;\n\nexport const FEATURE_CATEGORIES = ['Core', 'AI Tools', 'Frontend', 'Testing', 'Database', 'Data', 'Productivity', 'Git', 'Local Dev', 'Performance & Auditing', 'Deployment & CI/CD', 'Security', 'Workflow', 'Cloud'] as const;\nexport type FeatureCategory = typeof FEATURE_CATEGORIES[number];\n\nexport type SlotCategory = FeatureCategory;\nexport const SLOTS: SlotCategory[] = ['Core', 'AI Tools', 'Frontend', 'Testing', 'Git', 'Productivity'];\n\ninterface RawFeature {\n    id: string;\n    name: string;\n    description: string;\n    icon: React.ReactNode;\n    category: FeatureCategory;\n}\n\nexport const RAW_FEATURES: RawFeature[] = [\n    // --- Domain 1: Local Development & Testing Parity ---\n    { id: \"env-manager\", name: \".env Manager\", description: \"A graphical interface for creating and managing .env files.\", icon: <DocumentTextIcon />, category: \"Local Dev\" },\n\n    // --- Domain 2: Performance & Optimization Intelligence ---\n    { id: \"performance-profiler\", name: \"AI Performance Profiler\", description: \"Analyze runtime traces and bundle stats with AI-powered advice.\", icon: <ChartBarIcon />, category: \"Performance & Auditing\" },\n    { id: \"a11y-auditor\", name: \"Accessibility Auditor\", description: \"Audit a live URL for accessibility issues and get AI-powered fixes.\", icon: <EyeIcon />, category: \"Performance & Auditing\" },\n    { id: \"tech-debt-sonar\", name: \"Tech Debt Sonar\", description: \"Scan code to find code smells and areas with high complexity.\", icon: <MagnifyingGlassIcon />, category: \"Performance & Auditing\" },\n\n    // --- Domain 3: Deployment & CI/CD Automation ---\n    { id: \"ci-cd-generator\", name: \"AI CI/CD Architect\", description: \"Generate CI/CD config files from a natural language description.\", icon: <PaperAirplaneIcon />, category: \"Deployment & CI/CD\" },\n    { id: \"deployment-preview\", name: \"Static Deployment Preview\", description: \"See a live preview of files generated by the AI Feature Builder.\", icon: <CloudIcon />, category: \"Deployment & CI/CD\" },\n    { id: \"terraform-generator\", name: \"AI Terraform Generator\", description: \"Generate Terraform config from a description and cloud context.\", icon: <CpuChipIcon />, category: \"Deployment & CI/CD\" },\n\n    // --- Domain 4: Security & Vulnerability Scanning ---\n    { id: \"security-scanner\", name: \"AI Security Scanner\", description: \"Find common vulnerabilities in code with static analysis and AI.\", icon: <ShieldCheckIcon />, category: \"Security\" },\n    { id: \"iam-policy-generator\", name: \"IAM Policy Generator\", description: \"Generate AWS or GCP IAM policies from a natural language description.\", icon: <ShieldCheckIcon />, category: \"Security\" },\n    { id: \"iam-policy-visualizer\", name: \"GCP IAM Policy Visualizer\", description: \"Visually test and audit GCP IAM permissions in real-time across your resources.\", icon: <GcpIcon />, category: \"Cloud\" },\n\n    // --- Existing Features (Re-categorized and Ordered) ---\n    { id: \"ai-command-center\", name: \"AI Command Center\", description: \"Use natural language to navigate and control the toolkit.\", icon: <CommandCenterIcon />, category: \"Core\" },\n    { id: \"project-explorer\", name: \"Project Explorer\", description: \"Manage and edit files from your connected repositories.\", icon: <ProjectExplorerIcon />, category: \"Core\" },\n    { id: \"workspace-connector-hub\", name: \"Workspace Connector Hub\", description: \"Connect to services like Jira, Slack & GitHub to orchestrate actions with AI.\", icon: <RectangleGroupIcon />, category: \"Workflow\" },\n    { id: \"linter-formatter\", name: \"AI Code Formatter\", description: \"AI-powered, real-time code formatting.\", icon: <CodeFormatterIcon />, category: \"Core\" },\n    { id: \"json-tree-navigator\", name: \"JSON Tree Navigator\", description: \"Navigate large JSON objects as a collapsible tree.\", icon: <JsonTreeIcon />, category: \"Core\" },\n    \n    { id: \"ai-image-generator\", name: \"AI Image Generator\", description: \"Generate high-quality images from a text prompt.\", icon: <ImageGeneratorIcon />, category: \"AI Tools\" },\n    { id: \"ai-code-explainer\", name: \"AI Code Explainer\", description: \"Get a structured analysis of code, including complexity.\", icon: <CodeExplainerIcon />, category: \"AI Tools\" },\n    { id: \"ai-feature-builder\", name: \"AI Feature Builder\", description: \"Generate code, tests, and commit messages from a prompt or API schema.\", icon: <FeatureBuilderIcon />, category: \"AI Tools\" },\n    { id: \"ai-personality-forge\", name: \"AI Personality Forge\", description: \"Architect, test, and save complex system prompts to create different 'AI personalities'.\", icon: <SparklesIcon />, category: \"AI Tools\" },\n    { id: \"ai-code-migrator\", name: \"AI Code Migrator\", description: \"Translate code between languages & frameworks.\", icon: <CodeMigratorIcon />, category: \"AI Tools\" },\n    { id: \"theme-designer\", name: \"AI Theme Designer\", description: \"Generate, fine-tune, and export UI color themes from a text description or image.\", icon: <ThemeDesignerIcon />, category: \"AI Tools\" },\n    { id: \"one-click-refactor\", name: \"One-Click Refactor\", description: \"Apply common refactoring patterns to your code with a single click.\", icon: <SparklesIcon />, category: \"AI Tools\" },\n    { id: \"ai-commit-generator\", name: \"AI Commit Message Generator\", description: \"Smart, conventional commits via AI.\", icon: <CommitGeneratorIcon />, category: \"AI Tools\" },\n    { id: \"prompt-craft-pad\", name: \"Prompt Craft Pad\", description: \"Save, edit, and manage your custom AI prompts with variable testing.\", icon: <PromptCraftPadIcon />, category: \"AI Tools\" },\n    { id: \"screenshot-to-component\", name: \"Screenshot to Component\", description: \"Turn UI screenshots into functional component code.\", icon: <ScreenshotToComponentIcon />, category: \"AI Tools\" },\n    { id: \"ai-style-transfer\", name: \"AI Code Style Transfer\", description: \"Rewrite code to match a specific style guide.\", icon: <StyleTransferIcon />, category: \"AI Tools\" },\n    { id: \"ai-coding-challenge\", name: \"AI Coding Challenge Generator\", description: \"Generate unique coding exercises.\", icon: <CodingChallengeIcon />, category: \"AI Tools\" },\n    { id: \"code-review-bot\", name: \"AI Code Review Bot\", description: \"Get an automated code review with one-click refactoring.\", icon: <CodeReviewBotIcon />, category: \"AI Tools\" },\n    { id: \"ai-pull-request-assistant\", name: \"AI Pull Request Assistant\", description: \"Generate a structured PR summary from code diffs and populate a full template.\", icon: <AiPullRequestAssistantIcon />, category: \"AI Tools\" },\n    { id: \"pr-summary-generator\", name: \"PR Summary Generator\", description: \"Generate a structured PR summary from code diffs.\", icon: <AiPullRequestAssistantIcon />, category: \"AI Tools\" },\n    { id: \"audio-to-code\", name: \"AI Audio-to-Code\", description: \"Speak your programming ideas and watch them turn into code.\", icon: <AudioToCodeIcon />, category: \"AI Tools\" },\n    \n    { id: \"css-grid-editor\", name: \"CSS Grid Visual Editor\", description: \"Drag-based layout builder for CSS Grid.\", icon: <CssGridEditorIcon />, category: \"Frontend\" },\n    { id: \"pwa-manifest-editor\", name: \"PWA Manifest Editor\", description: \"Configure and preview Progressive Web App manifests with a home screen simulator.\", icon: <PwaManifestEditorIcon />, category: \"Frontend\" },\n    { id: \"typography-lab\", name: \"Typography Lab\", description: \"Preview font pairings and get CSS import rules.\", icon: <TypographyLabIcon />, category: \"Frontend\" },\n    { id: \"font-preview-picker\", name: \"Font Preview Picker\", description: \"Preview custom text with different fonts.\", icon: <TypographyLabIcon />, category: \"Frontend\" },\n    { id: \"font-pairing-tool\", name: \"Font Pairing Tool\", description: \"Experiment with different font pairings for headings and body text.\", icon: <TypographyLabIcon />, category: \"Frontend\" },\n    { id: \"svg-path-editor\", name: \"SVG Path Editor\", description: \"Visually create and manipulate SVG path data with an interactive canvas.\", icon: <SvgPathEditorIcon />, category: \"Frontend\" },\n    { id: \"color-palette-generator\", name: \"AI Color Palette Generator\", description: \"Pick a base color and let Gemini design a beautiful palette.\", icon: <ColorPaletteGeneratorIcon />, category: \"Frontend\" },\n    { id: \"meta-tag-editor\", name: \"Meta Tag Editor\", description: \"Generate SEO/social media meta tags with a live social card preview.\", icon: <MetaTagEditorIcon />, category: \"Frontend\" },\n    { id: \"responsive-tester\", name: \"Responsive Tester\", description: \"Preview your web pages at different screen sizes and custom resolutions.\", icon: <ResponsiveTesterIcon />, category: \"Frontend\" },\n    { id: \"sass-scss-compiler\", name: \"SASS/SCSS Compiler\", description: \"A real-time SASS/SCSS to CSS compiler.\", icon: <SassCompilerIcon />, category: \"Frontend\" },\n    \n    { id: \"ai-unit-test-generator\", name: \"AI Unit Test Generator\", description: \"Generate unit tests from source code.\", icon: <UnitTestGeneratorIcon />, category: \"Testing\" },\n    { id: \"bug-reproducer\", name: \"Bug Reproducer\", description: \"Paste a stack trace to automatically generate a failing unit test.\", icon: <BugAntIcon />, category: \"Testing\" },\n    { id: \"worker-thread-debugger\", name: \"AI Concurrency Analyzer\", description: \"Analyze JS for Web Worker issues like race conditions.\", icon: <ConcurrencyAnalyzerIcon />, category: \"Testing\" },\n    { id: \"regex-sandbox\", name: \"RegEx Sandbox\", description: \"Visually test regular expressions, generate them with AI, and inspect match groups.\", icon: <RegexSandboxIcon />, category: \"Testing\" },\n    { id: \"async-call-tree-viewer\", name: \"Async Call Tree Viewer\", description: \"Visualize a tree of asynchronous function calls from JSON data.\", icon: <AsyncCallTreeIcon />, category: \"Testing\" },\n    { id: \"code-spell-checker\", name: \"Code Spell Checker\", description: \"A spell checker that finds common typos in code.\", icon: <CodeSpellCheckerIcon />, category: \"Testing\" },\n    { id: \"network-visualizer\", name: \"Network Visualizer\", description: \"Inspect network resources with a summary and visual waterfall chart.\", icon: <NetworkVisualizerIcon />, category: \"Testing\" },\n    \n    { id: \"visual-git-tree\", name: \"Visual Git Tree\", description: \"Visually trace your git commit history with an interactive graph and an AI-powered summary.\", icon: <GitLogAnalyzerIcon />, category: \"Git\" },\n    { id: \"changelog-generator\", name: \"AI Changelog Generator\", description: \"Auto-build changelogs from raw git logs.\", icon: <ChangelogGeneratorIcon />, category: \"Git\" },\n    { id: \"code-diff-ghost\", name: \"Code Diff Ghost\", description: \"Visualize code changes with a 'ghost typing' effect.\", icon: <CodeDiffGhostIcon />, category: \"Git\" },\n    \n    { id: \"cron-job-builder\", name: \"AI Cron Job Builder\", description: \"Visually tool to configure cron jobs, with AI.\", icon: <CronJobBuilderIcon />, category: \"Deployment & CI/CD\" },\n    \n    { id: \"portable-snippet-vault\", name: \"Snippet Vault\", description: \"Store, search, tag, and enhance reusable code snippets with AI.\", icon: <SnippetVaultIcon />, category: \"Productivity\" },\n    { id: \"digital-whiteboard\", name: \"Digital Whiteboard\", description: \"Organize ideas with interactive sticky notes and get AI-powered summaries.\", icon: <DigitalWhiteboardIcon />, category: \"Productivity\" },\n    { id: \"project-moodboard\", name: \"Project Moodboard\", description: \"A visual space to gather ideas, images, and notes.\", icon: <PhotoIcon />, category: \"Productivity\" },\n    { id: \"markdown-slides-generator\", name: \"Markdown Slides\", description: \"Turn markdown into a fullscreen presentation with an interactive overlay.\", icon: <MarkdownSlidesIcon />, category: \"Productivity\" },\n    { id: \"weekly-digest-generator\", name: \"Weekly Digest Generator\", description: \"Generate and send a weekly project summary email via Gmail.\", icon: <MailIcon />, category: \"Productivity\" },\n    { id: \"gmail-addon-simulator\", name: \"Gmail Add-on Simulator\", description: \"A simulation of how contextual add-on scopes would work inside Gmail.\", icon: <MailIcon />, category: \"Productivity\" },\n    \n    { id: \"schema-designer\", name: \"Schema Designer\", description: \"Visually design a database schema with a drag-and-drop interface and SQL export.\", icon: <SchemaDesignerIcon />, category: \"Database\" },\n    { id: \"xbrl-converter\", name: \"XBRL Converter\", description: \"Convert JSON data to a simplified XBRL-like XML format using AI.\", icon: <XbrlConverterIcon />, category: \"Data\" },\n    { id: \"logic-flow-builder\", name: \"Logic Flow Builder\", description: \"A visual tool for building application logic flows.\", icon: <LogicFlowBuilderIcon />, category: \"Workflow\" },\n];\n\nexport const ALL_FEATURE_IDS = RAW_FEATURES.map(f => f.id);","import React, { lazy } from 'react';\n\n/**\n * A wrapper around React.lazy to retry loading a component if it fails.\n * This is useful for handling \"chunk load failed\" errors that can occur\n * when a user has an old version of the site and a new version is deployed.\n *\n * @param componentImport A function that returns a dynamic import, e.g., () => import('./MyComponent')\n * @param exportName The named export of the component to be loaded.\n * @returns A lazy-loaded React component.\n */\nexport const lazyWithRetry = <T extends React.ComponentType<any>>(\n    componentImport: () => Promise<{ [key: string]: T }>,\n    exportName: string\n) => {\n    return lazy(async () => {\n        const MAX_RETRIES = 3;\n        const RETRY_DELAY_MS = 1000;\n\n        for (let i = 0; i < MAX_RETRIES; i++) {\n            try {\n                const module = await componentImport();\n                if (module[exportName]) {\n                    return { default: module[exportName] };\n                }\n                // This would be a developer error (wrong export name), not a chunk load error.\n                throw new Error(`Named export '${exportName}' not found in module.`);\n            } catch (error) {\n                console.error(error); // Log error for debugging\n                if (i < MAX_RETRIES - 1) {\n                    await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));\n                } else {\n                    // After all retries, force a page reload.\n                    // This is the most effective way to solve stale chunk issues after a new deployment.\n                    console.error(\"Failed to load component after multiple retries. Reloading page.\");\n                    window.location.reload();\n                    // Throw to allow an ErrorBoundary to catch this, although reload will likely intervene.\n                    throw error;\n                }\n            }\n        }\n        // This part of the code should not be reachable\n        throw new Error('Component failed to load and retries were exhausted.');\n    });\n};","import React from 'react';\nimport type { Feature } from '../../types.ts';\nimport { RAW_FEATURES } from '../../constants.tsx';\nimport { lazyWithRetry } from '../../services/componentLoader.ts';\n\nconst componentMap: Record<string, React.FC<any>> = {\n    'ai-command-center': lazyWithRetry(() => import('./AiCommandCenter.tsx'), 'AiCommandCenter'),\n    'project-explorer': lazyWithRetry(() => import('./ProjectExplorer.tsx'), 'ProjectExplorer'),\n    'workspace-connector-hub': lazyWithRetry(() => import('./WorkspaceConnectorHub.tsx'), 'WorkspaceConnectorHub'),\n    'ai-code-explainer': lazyWithRetry(() => import('./AiCodeExplainer.tsx'), 'AiCodeExplainer'),\n    'ai-feature-builder': lazyWithRetry(() => import('./AiFeatureBuilder.tsx'), 'AiFeatureBuilder'),\n    'regex-sandbox': lazyWithRetry(() => import('./RegexSandbox.tsx'), 'RegexSandbox'),\n    'portable-snippet-vault': lazyWithRetry(() => import('./SnippetVault.tsx'), 'SnippetVault'),\n    'css-grid-editor': lazyWithRetry(() => import('./CssGridEditor.tsx'), 'CssGridEditor'),\n    'ai-commit-generator': lazyWithRetry(() => import('./AiCommitGenerator.tsx'), 'AiCommitGenerator'),\n    'json-tree-navigator': lazyWithRetry(() => import('./JsonTreeNavigator.tsx'), 'JsonTreeNavigator'),\n    'xbrl-converter': lazyWithRetry(() => import('./XbrlConverter.tsx'), 'XbrlConverter'),\n    'ai-unit-test-generator': lazyWithRetry(() => import('./AiUnitTestGenerator.tsx'), 'AiUnitTestGenerator'),\n    'prompt-craft-pad': lazyWithRetry(() => import('./PromptCraftPad.tsx'), 'PromptCraftPad'),\n    'linter-formatter': lazyWithRetry(() => import('./CodeFormatter.tsx'), 'CodeFormatter'),\n    'schema-designer': lazyWithRetry(() => import('./SchemaDesigner.tsx'), 'SchemaDesigner'),\n    'pwa-manifest-editor': lazyWithRetry(() => import('./PwaManifestEditor.tsx'), 'PwaManifestEditor'),\n    'markdown-slides-generator': lazyWithRetry(() => import('./MarkdownSlides.tsx'), 'MarkdownSlides'),\n    'screenshot-to-component': lazyWithRetry(() => import('./ScreenshotToComponent.tsx'), 'ScreenshotToComponent'),\n    'digital-whiteboard': lazyWithRetry(() => import('./DigitalWhiteboard.tsx'), 'DigitalWhiteboard'),\n    'theme-designer': lazyWithRetry(() => import('./ThemeDesigner.tsx'), 'ThemeDesigner'),\n    'svg-path-editor': lazyWithRetry(() => import('./SvgPathEditor.tsx'), 'SvgPathEditor'),\n    'ai-style-transfer': lazyWithRetry(() => import('./AiStyleTransfer.tsx'), 'AiStyleTransfer'),\n    'ai-coding-challenge': lazyWithRetry(() => import('./AiCodingChallenge.tsx'), 'AiCodingChallenge'),\n    'typography-lab': lazyWithRetry(() => import('./TypographyLab.tsx'), 'TypographyLab'),\n    'code-review-bot': lazyWithRetry(() => import('./CodeReviewBot.tsx'), 'CodeReviewBot'),\n    'ai-pull-request-assistant': lazyWithRetry(() => import('./AiPullRequestAssistant.tsx'), 'AiPullRequestAssistant'),\n    'changelog-generator': lazyWithRetry(() => import('./ChangelogGenerator.tsx'), 'ChangelogGenerator'),\n    'cron-job-builder': lazyWithRetry(() => import('./CronJobBuilder.tsx'), 'CronJobBuilder'),\n    'ai-code-migrator': lazyWithRetry(() => import('./AiCodeMigrator.tsx'), 'AiCodeMigrator'),\n    'visual-git-tree': lazyWithRetry(() => import('./VisualGitTree.tsx'), 'VisualGitTree'),\n    'worker-thread-debugger': lazyWithRetry(() => import('./WorkerThreadDebugger.tsx'), 'WorkerThreadDebugger'),\n    'ai-image-generator': lazyWithRetry(() => import('./AiImageGenerator.tsx'), 'AiImageGenerator'),\n    'async-call-tree-viewer': lazyWithRetry(() => import('./AsyncCallTreeViewer.tsx'), 'AsyncCallTreeViewer'),\n    'audio-to-code': lazyWithRetry(() => import('./AudioToCode.tsx'), 'AudioToCode'),\n    'code-diff-ghost': lazyWithRetry(() => import('./CodeDiffGhost.tsx'), 'CodeDiffGhost'),\n    'code-spell-checker': lazyWithRetry(() => import('./CodeSpellChecker.tsx'), 'CodeSpellChecker'),\n    'color-palette-generator': lazyWithRetry(() => import('./ColorPaletteGenerator.tsx'), 'ColorPaletteGenerator'),\n    'logic-flow-builder': lazyWithRetry(() => import('./LogicFlowBuilder.tsx'), 'LogicFlowBuilder'),\n    'meta-tag-editor': lazyWithRetry(() => import('./MetaTagEditor.tsx'), 'MetaTagEditor'),\n    'network-visualizer': lazyWithRetry(() => import('./NetworkVisualizer.tsx'), 'NetworkVisualizer'),\n    'responsive-tester': lazyWithRetry(() => import('./ResponsiveTester.tsx'), 'ResponsiveTester'),\n    'sass-scss-compiler': lazyWithRetry(() => import('./SassScssCompiler.tsx'), 'SassScssCompiler'),\n    'env-manager': lazyWithRetry(() => import('./EnvManager.tsx'), 'EnvManager'),\n    'performance-profiler': lazyWithRetry(() => import('./PerformanceProfiler.tsx'), 'PerformanceProfiler'),\n    'a11y-auditor': lazyWithRetry(() => import('./AccessibilityAuditor.tsx'), 'AccessibilityAuditor'),\n    'ci-cd-generator': lazyWithRetry(() => import('./CiCdPipelineGenerator.tsx'), 'CiCdPipelineGenerator'),\n    'deployment-preview': lazyWithRetry(() => import('./DeploymentPreview.tsx'), 'DeploymentPreview'),\n    'security-scanner': lazyWithRetry(() => import('./SecurityScanner.tsx'), 'SecurityScanner'),\n    'terraform-generator': lazyWithRetry(() => import('./TerraformGenerator.tsx'), 'TerraformGenerator'),\n    'ai-personality-forge': lazyWithRetry(() => import('./AiPersonalityForge.tsx'), 'AiPersonalityForge'),\n    'weekly-digest-generator': lazyWithRetry(() => import('./WeeklyDigestGenerator.tsx'), 'WeeklyDigestGenerator'),\n    'one-click-refactor': lazyWithRetry(() => import('./OneClickRefactor.tsx'), 'OneClickRefactor'),\n    'bug-reproducer': lazyWithRetry(() => import('./BugReproducer.tsx'), 'BugReproducer'),\n    'tech-debt-sonar': lazyWithRetry(() => import('./TechDebtSonar.tsx'), 'TechDebtSonar'),\n    'iam-policy-generator': lazyWithRetry(() => import('./IamPolicyGenerator.tsx'), 'IamPolicyGenerator'),\n    'iam-policy-visualizer': lazyWithRetry(() => import('./IamPolicyVisualizer.tsx'), 'IamPolicyVisualizer'),\n    'gmail-addon-simulator': lazyWithRetry(() => import('./GmailAddonSimulator.tsx'), 'GmailAddonSimulator'),\n    'pr-summary-generator': lazyWithRetry(() => import('./PrSummaryGenerator.tsx'), 'PrSummaryGenerator'),\n    'project-moodboard': lazyWithRetry(() => import('./ProjectMoodboard.tsx'), 'ProjectMoodboard'),\n    'font-preview-picker': lazyWithRetry(() => import('./FontPreviewPicker.tsx'), 'FontPreviewPicker'),\n    'font-pairing-tool': lazyWithRetry(() => import('./FontPairingTool.tsx'), 'FontPairingTool'),\n};\n\nexport const ALL_FEATURES: Feature[] = RAW_FEATURES.map(feature => ({\n    ...feature,\n    component: componentMap[feature.id],\n}));\n\nexport const FEATURES_MAP = new Map(ALL_FEATURES.map(f => [f.id, f]));","\nimport React, { useState, useEffect, useMemo } from 'react';\nimport { ALL_FEATURES } from './features/index.ts';\nimport type { ViewType } from '../types.ts';\n\ninterface CommandPaletteProps {\n  isOpen: boolean;\n  onClose: () => void;\n  onSelect: (view: ViewType) => void;\n}\n\nexport const CommandPalette: React.FC<CommandPaletteProps> = ({ isOpen, onClose, onSelect }) => {\n  const [searchTerm, setSearchTerm] = useState('');\n  const [selectedIndex, setSelectedIndex] = useState(0);\n\n  useEffect(() => {\n    if (!isOpen) {\n      setSearchTerm('');\n      setSelectedIndex(0);\n    }\n  }, [isOpen]);\n  \n  const commandOptions = useMemo(() => {\n    const navigationCommands = [\n      { id: 'ai-feature-builder', name: 'Go to AI Builder', category: 'Navigation', icon: <span />, description: ''},\n    ];\n    \n    const featureCommands = ALL_FEATURES.map(f => ({...f, name: `Open: ${f.name}`}));\n\n     return [\n      ...navigationCommands,\n      ...featureCommands,\n     ].filter(\n        (feature) =>\n          feature.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n          feature.category.toLowerCase().includes(searchTerm.toLowerCase())\n      );\n  }, [searchTerm]);\n\n  useEffect(() => {\n    setSelectedIndex(0);\n  }, [commandOptions.length]);\n\n  useEffect(() => {\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (!isOpen) return;\n      if (e.key === 'ArrowDown') {\n        e.preventDefault();\n        setSelectedIndex((prev) => (prev + 1) % commandOptions.length);\n      } else if (e.key === 'ArrowUp') {\n        e.preventDefault();\n        setSelectedIndex((prev) => (prev - 1 + commandOptions.length) % commandOptions.length);\n      } else if (e.key === 'Enter') {\n        e.preventDefault();\n        const selected = commandOptions[selectedIndex];\n        if (selected) {\n          onSelect(selected.id as ViewType);\n        }\n      }\n    };\n    window.addEventListener('keydown', handleKeyDown);\n    return () => window.removeEventListener('keydown', handleKeyDown);\n  }, [isOpen, commandOptions, selectedIndex, onSelect]);\n\n  if (!isOpen) return null;\n\n  return (\n    <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-start justify-center pt-20\" onClick={onClose}>\n      <div\n        className=\"w-full max-w-xl bg-surface border border-border rounded-lg shadow-2xl overflow-hidden\"\n        onClick={(e) => e.stopPropagation()}\n      >\n        <input\n          type=\"text\"\n          placeholder=\"Type a command or search...\"\n          value={searchTerm}\n          onChange={(e) => setSearchTerm(e.target.value)}\n          autoFocus\n          className=\"w-full p-4 bg-surface text-text-primary text-lg focus:outline-none border-b border-border\"\n        />\n        <ul className=\"max-h-96 overflow-y-auto p-2\">\n          {commandOptions.length > 0 ? (\n            commandOptions.map((item, index) => (\n              <li\n                key={item.id + index}\n                onMouseDown={() => {\n                   onSelect(item.id as ViewType);\n                }}\n                className={`flex items-center justify-between p-3 rounded-md cursor-pointer ${\n                  selectedIndex === index ? 'bg-primary/10 text-primary' : 'hover:bg-gray-100'\n                }`}\n              >\n                <div className=\"flex items-center space-x-3\">\n                    <div className=\"text-text-secondary\">{item.icon}</div>\n                    <span className=\"text-text-primary\">{item.name}</span>\n                </div>\n                <span className=\"text-xs text-text-secondary bg-gray-100 px-2 py-1 rounded\">{item.category}</span>\n              </li>\n            ))\n          ) : (\n            <li className=\"p-4 text-center text-text-secondary\">No results found.</li>\n          )}\n        </ul>\n      </div>\n    </div>\n  );\n};","import React, { createContext, useContext, useState, useCallback } from 'react';\n\ntype NotificationType = 'success' | 'error' | 'info';\n\ninterface Notification {\n  id: number;\n  message: string;\n  type: NotificationType;\n}\n\ninterface NotificationContextType {\n  addNotification: (message: string, type?: NotificationType) => void;\n}\n\nconst NotificationContext = createContext<NotificationContextType | undefined>(undefined);\n\nexport const useNotification = () => {\n  const context = useContext(NotificationContext);\n  if (!context) {\n    throw new Error('useNotification must be used within a NotificationProvider');\n  }\n  return context;\n};\n\nexport const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n  const [notifications, setNotifications] = useState<Notification[]>([]);\n\n  const addNotification = useCallback((message: string, type: NotificationType = 'info') => {\n    const id = Date.now();\n    setNotifications(prev => [...prev, { id, message, type }]);\n    setTimeout(() => {\n      setNotifications(prev => prev.filter(n => n.id !== id));\n    }, 4000);\n  }, []);\n  \n  const typeStyles = {\n    success: 'bg-emerald-500 border-emerald-600',\n    error: 'bg-red-500 border-red-600',\n    info: 'bg-sky-500 border-sky-600'\n  };\n\n  return (\n    <NotificationContext.Provider value={{ addNotification }}>\n      {children}\n      <div className=\"fixed bottom-4 right-4 z-[100] space-y-2 w-full max-w-sm\">\n        {notifications.map(notification => (\n           <div key={notification.id} role=\"alert\" className={`relative animate-pop-in shadow-lg rounded-lg text-white font-medium p-4 border-b-4 ${typeStyles[notification.type]}`}>\n               {notification.message}\n           </div>\n        ))}\n      </div>\n    </NotificationContext.Provider>\n  );\n};","import { useState } from 'react';\n\nexport const useLocalStorage = <T,>(key: string, initialValue: T) => {\n    const [storedValue, setStoredValue] = useState<T>(() => {\n        try {\n            const consent = window.localStorage.getItem('devcore_ls_consent');\n            if (consent !== 'granted') return initialValue;\n\n            const item = window.localStorage.getItem(key);\n            return item ? JSON.parse(item) : initialValue;\n        } catch (error) {\n            console.error(`Error reading localStorage key “${key}”:`, error);\n            return initialValue;\n        }\n    });\n\n    const setValue = (value: T | ((val: T) => T)) => {\n        try {\n            const consent = window.localStorage.getItem('devcore_ls_consent');\n            if (consent !== 'granted') {\n                // If consent is not granted, only update the in-memory state\n                const valueToStore = value instanceof Function ? value(storedValue) : value;\n                setStoredValue(valueToStore);\n                return;\n            };\n\n            const valueToStore = value instanceof Function ? value(storedValue) : value;\n            setStoredValue(valueToStore);\n            window.localStorage.setItem(key, JSON.stringify(valueToStore));\n        } catch (error) {\n            console.error(`Error setting localStorage key “${key}”:`, error);\n        }\n    };\n\n    return [storedValue, setValue] as const;\n};","import { useEffect } from 'react';\nimport { useLocalStorage } from './useLocalStorage.ts';\nimport type { ThemeState, ColorTheme, Theme } from '../types.ts';\n\nconst defaultThemeState: ThemeState = {\n    mode: 'light',\n    customColors: null,\n};\n\nconst applyColors = (colors: ColorTheme | null) => {\n    const root = window.document.documentElement;\n    if (colors) {\n        root.style.setProperty('--color-primary', colors.primary);\n        root.style.setProperty('--color-background', colors.background);\n        root.style.setProperty('--color-surface', colors.surface);\n        root.style.setProperty('--color-text-primary', colors.textPrimary);\n        root.style.setProperty('--color-text-secondary', colors.textSecondary);\n        root.style.setProperty('--color-text-on-primary', colors.textOnPrimary);\n        root.style.setProperty('--color-border', colors.border);\n        const rgb = colors.primary.match(/\\w\\w/g)?.map(x => parseInt(x, 16));\n        if (rgb) {\n             root.style.setProperty('--color-primary-rgb', rgb.join(', '));\n        }\n    } else {\n        // Clear inline styles to revert to CSS-defined variables\n        root.style.removeProperty('--color-primary');\n        root.style.removeProperty('--color-background');\n        root.style.removeProperty('--color-surface');\n        root.style.removeProperty('--color-text-primary');\n        root.style.removeProperty('--color-text-secondary');\n        root.style.removeProperty('--color-text-on-primary');\n        root.style.removeProperty('--color-border');\n        root.style.removeProperty('--color-primary-rgb');\n    }\n}\n\nexport const useTheme = (): [ThemeState, () => void, (colors: ColorTheme, mode: Theme) => void, () => void] => {\n    const [themeState, setThemeState] = useLocalStorage<ThemeState>('devcore_theme_state', defaultThemeState);\n\n    useEffect(() => {\n        const root = window.document.documentElement;\n        root.classList.remove('light', 'dark');\n        root.classList.add(themeState.mode);\n        applyColors(themeState.customColors);\n    }, [themeState]);\n\n    const toggleTheme = () => {\n        setThemeState(prev => ({\n            ...prev,\n            mode: prev.mode === 'light' ? 'dark' : 'light'\n        }));\n    };\n    \n    const applyCustomTheme = (colors: ColorTheme, mode: Theme) => {\n        setThemeState({ mode, customColors: colors });\n    };\n\n    const clearCustomTheme = () => {\n        // We keep the mode, but clear custom colors\n        setThemeState(prev => ({ ...prev, customColors: null }));\n    };\n\n    return [themeState, toggleTheme, applyCustomTheme, clearCustomTheme];\n};\n","/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { createContext, useContext } from 'react';\n\ninterface VaultModalContextType {\n    requestUnlock: () => Promise<boolean>;\n    requestCreation: () => Promise<boolean>;\n}\n\nexport const VaultModalContext = createContext<VaultModalContextType | undefined>(undefined);\n\nexport const useVaultModal = (): VaultModalContextType => {\n    const context = useContext(VaultModalContext);\n    if (!context) {\n        throw new Error('useVaultModal must be used within a VaultProvider');\n    }\n    return context;\n};\n","\nimport React from 'react';\n\nexport const LoadingSpinner: React.FC = () => (\n    <div className=\"flex items-center justify-center space-x-1\" aria-label=\"Loading\">\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n    </div>\n);\n","/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { useState } from 'react';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { LoadingSpinner } from '../shared/LoadingSpinner.tsx';\n\ninterface Props {\n    onSuccess: () => void;\n    onCancel: () => void;\n}\n\nexport const CreateMasterPasswordModal: React.FC<Props> = ({ onSuccess, onCancel }) => {\n    const [password, setPassword] = useState('');\n    const [confirmPassword, setConfirmPassword] = useState('');\n    const [error, setError] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n\n    const handleSubmit = async (e: React.FormEvent) => {\n        e.preventDefault();\n        setError('');\n\n        if (password.length < 8) {\n            setError('Password must be at least 8 characters long.');\n            return;\n        }\n        if (password !== confirmPassword) {\n            setError('Passwords do not match.');\n            return;\n        }\n\n        setIsLoading(true);\n        try {\n            await vaultService.initializeVault(password);\n            onSuccess();\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unexpected error occurred.');\n            setIsLoading(false);\n        }\n    };\n\n    return (\n        <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n            <div className=\"bg-surface border border-border rounded-lg shadow-2xl w-full max-w-md m-4 p-6 animate-pop-in\">\n                <h2 className=\"text-xl font-bold mb-2\">Create Master Password</h2>\n                <p className=\"text-sm text-text-secondary mb-4\">\n                    This password encrypts your API keys locally on your device. It is never stored or sent anywhere.\n                    <strong> If you forget it, your data will be unrecoverable.</strong>\n                </p>\n                <form onSubmit={handleSubmit} className=\"space-y-4\">\n                    <div>\n                        <label className=\"block text-sm font-medium\">New Master Password</label>\n                        <input\n                            type=\"password\"\n                            value={password}\n                            onChange={(e) => setPassword(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                            autoFocus\n                        />\n                    </div>\n                    <div>\n                        <label className=\"block text-sm font-medium\">Confirm Password</label>\n                        <input\n                            type=\"password\"\n                            value={confirmPassword}\n                            onChange={(e) => setConfirmPassword(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                        />\n                    </div>\n                    {error && <p className=\"text-red-500 text-sm\">{error}</p>}\n                    <div className=\"flex justify-end gap-2 pt-2\">\n                        <button type=\"button\" onClick={onCancel} className=\"px-4 py-2 bg-gray-100 rounded-md\">Cancel</button>\n                        <button type=\"submit\" disabled={isLoading} className=\"btn-primary px-4 py-2 min-w-[120px] flex justify-center\">\n                            {isLoading ? <LoadingSpinner /> : 'Create Vault'}\n                        </button>\n                    </div>\n                </form>\n            </div>\n        </div>\n    );\n};\n","/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { useState } from 'react';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { LoadingSpinner } from '../shared/LoadingSpinner.tsx';\n\ninterface Props {\n    onSuccess: () => void;\n    onCancel: () => void;\n}\n\nexport const UnlockVaultModal: React.FC<Props> = ({ onSuccess, onCancel }) => {\n    const [password, setPassword] = useState('');\n    const [error, setError] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n\n    const handleSubmit = async (e: React.FormEvent) => {\n        e.preventDefault();\n        setError('');\n        setIsLoading(true);\n\n        try {\n            await vaultService.unlockVault(password);\n            onSuccess();\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unexpected error occurred.');\n            setIsLoading(false);\n        }\n    };\n\n    return (\n        <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n            <div className=\"bg-surface border border-border rounded-lg shadow-2xl w-full max-w-sm m-4 p-6 animate-pop-in\">\n                <h2 className=\"text-xl font-bold mb-2\">Unlock Vault</h2>\n                <p className=\"text-sm text-text-secondary mb-4\">\n                    Enter your Master Password to access your encrypted API keys for this session.\n                </p>\n                <form onSubmit={handleSubmit} className=\"space-y-4\">\n                    <div>\n                        <label className=\"block text-sm font-medium\">Master Password</label>\n                        <input\n                            type=\"password\"\n                            value={password}\n                            onChange={(e) => setPassword(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                            autoFocus\n                        />\n                    </div>\n                    {error && <p className=\"text-red-500 text-sm\">{error}</p>}\n                    <div className=\"flex justify-end gap-2 pt-2\">\n                        <button type=\"button\" onClick={onCancel} className=\"px-4 py-2 bg-gray-100 rounded-md\">Cancel</button>\n                        <button type=\"submit\" disabled={isLoading} className=\"btn-primary px-4 py-2 min-w-[100px] flex justify-center\">\n                            {isLoading ? <LoadingSpinner /> : 'Unlock'}\n                        </button>\n                    </div>\n                </form>\n            </div>\n        </div>\n    );\n};\n","/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { useState, useCallback, useMemo } from 'react';\nimport { VaultModalContext } from '../../contexts/VaultModalContext.tsx';\nimport { CreateMasterPasswordModal } from './CreateMasterPasswordModal.tsx';\nimport { UnlockVaultModal } from './UnlockVaultModal.tsx';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\n\ntype PromiseResolver = (value: boolean) => void;\n\nexport const VaultProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n    const { dispatch } = useGlobalState();\n    const [isCreateModalOpen, setCreateModalOpen] = useState(false);\n    const [isUnlockModalOpen, setUnlockModalOpen] = useState(false);\n    const [createPromise, setCreatePromise] = useState<{ resolve: PromiseResolver } | null>(null);\n    const [unlockPromise, setUnlockPromise] = useState<{ resolve: PromiseResolver } | null>(null);\n\n    const requestCreation = useCallback(() => {\n        return new Promise<boolean>((resolve) => {\n            setCreatePromise({ resolve });\n            setCreateModalOpen(true);\n        });\n    }, []);\n\n    const requestUnlock = useCallback(() => {\n        return new Promise<boolean>((resolve) => {\n            setUnlockPromise({ resolve });\n            setUnlockModalOpen(true);\n        });\n    }, []);\n\n    const handleCreateSuccess = () => {\n        dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: true, isUnlocked: true } });\n        createPromise?.resolve(true);\n        setCreateModalOpen(false);\n        setCreatePromise(null);\n    };\n\n    const handleCreateCancel = () => {\n        createPromise?.resolve(false);\n        setCreateModalOpen(false);\n        setCreatePromise(null);\n    };\n\n    const handleUnlockSuccess = () => {\n        dispatch({ type: 'SET_VAULT_STATE', payload: { isUnlocked: true } });\n        unlockPromise?.resolve(true);\n        setUnlockModalOpen(false);\n        setUnlockPromise(null);\n    };\n\n    const handleUnlockCancel = () => {\n        unlockPromise?.resolve(false);\n        setUnlockModalOpen(false);\n        setUnlockPromise(null);\n    };\n\n    const contextValue = useMemo(() => ({ requestUnlock, requestCreation }), [requestUnlock, requestCreation]);\n\n    return (\n        <VaultModalContext.Provider value={contextValue}>\n            {children}\n            {isCreateModalOpen && (\n                <CreateMasterPasswordModal\n                    onSuccess={handleCreateSuccess}\n                    onCancel={handleCreateCancel}\n                />\n            )}\n            {isUnlockModalOpen && (\n                <UnlockVaultModal\n                    onSuccess={handleUnlockSuccess}\n                    onCancel={handleUnlockCancel}\n                />\n            )}\n        </VaultModalContext.Provider>\n    );\n};\n","import type { AppUser } from '../types.ts';\nimport { logError } from './telemetryService.ts';\n\ndeclare global {\n  const google: any;\n}\n\nconst GOOGLE_CLIENT_ID = \"555179712981-36hlicm802genhfo9iq1ufnp1n8cikt9.apps.googleusercontent.com\";\n\nconst SCOPES = [\n    'openid',\n    'https://www.googleapis.com/auth/userinfo.profile',\n    'https://www.googleapis.com/auth/userinfo.email',\n    'https://www.googleapis.com/auth/drive.appdata',\n    'https://www.googleapis.com/auth/drive.install',\n    'https://www.googleapis.com/auth/drive.file',\n    'https://www.googleapis.com/auth/iam.test',\n    'https://www.googleapis.com/auth/gmail.addons.current.action.compose',\n    'https://www.googleapis.com/auth/gmail.addons.current.message.action'\n].join(' ');\n\nlet tokenClient: any;\nlet onUserChangedCallback: (user: AppUser | null) => void = () => {};\n\nconst getGoogleUserProfile = async (accessToken: string) => {\n    const response = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {\n        headers: { Authorization: `Bearer ${accessToken}` },\n    });\n    if (!response.ok) {\n        throw new Error('Failed to fetch user profile');\n    }\n    return response.json();\n};\n\nexport function initGoogleAuth(callback: (user: AppUser | null) => void) {\n  if (!GOOGLE_CLIENT_ID) {\n    console.error('Google Client ID not configured.');\n    return;\n  }\n  onUserChangedCallback = callback;\n  \n  tokenClient = google.accounts.oauth2.initTokenClient({\n    client_id: GOOGLE_CLIENT_ID,\n    scope: SCOPES,\n    callback: async (tokenResponse: any) => {\n      if (tokenResponse && tokenResponse.access_token) {\n        sessionStorage.setItem('google_access_token', tokenResponse.access_token);\n        try {\n            const profile = await getGoogleUserProfile(tokenResponse.access_token);\n            const appUser: AppUser = {\n                uid: profile.sub, // 'sub' is the standard OIDC field for user ID\n                displayName: profile.name,\n                email: profile.email,\n                photoURL: profile.picture,\n                tier: 'free',\n            };\n            onUserChangedCallback(appUser);\n        } catch (error) {\n            logError(error as Error, { context: 'googleAuthInitCallback' });\n            onUserChangedCallback(null);\n        }\n      } else {\n        logError(new Error('Google sign-in failed: No access token received.'), { tokenResponse });\n        onUserChangedCallback(null);\n      }\n    },\n  });\n}\n\nexport function signInWithGoogle() {\n  if (tokenClient) {\n    tokenClient.requestAccessToken({ prompt: 'consent' });\n  } else {\n    logError(new Error(\"Google Token Client not initialized.\"));\n  }\n}\n\nexport function signOutUser() {\n  const token = sessionStorage.getItem('google_access_token');\n  // Always remove the token from session storage to ensure local logout\n  sessionStorage.removeItem('google_access_token');\n  \n  // Attempt to revoke the token with Google as a best-effort\n  if (token && window.google?.accounts?.oauth2?.revoke) {\n    try {\n      google.accounts.oauth2.revoke(token, (response: any) => {\n        if (response && response.error) {\n          console.warn('Google token revocation failed:', response.error);\n          logError(new Error('Google token revocation failed'), { error: response.error });\n        } else {\n          console.log('Google token revoked successfully.');\n        }\n      });\n    } catch (error) {\n        console.error(\"Error calling google.accounts.oauth2.revoke:\", error);\n        logError(error as Error, { context: 'signOutUser' });\n    }\n  }\n  \n  // Always update the application's state to reflect logout\n  onUserChangedCallback(null);\n}","import React from 'react';\nimport { signInWithGoogle } from '../services/googleAuthService.ts';\n\nexport const LoginView: React.FC = () => {\n    return (\n        <div className=\"h-full w-full flex items-center justify-center bg-background\">\n            <div className=\"text-center bg-surface p-8 rounded-lg border border-border max-w-md shadow-lg animate-pop-in\">\n                <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"text-primary mx-auto mb-4\">\n                    <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n                </svg>\n                <h1 className=\"text-2xl font-bold text-text-primary\">Welcome to DevCore AI</h1>\n                <p className=\"text-text-secondary my-4\">\n                    Please sign in with your Google account to securely access your workspace tools and manage API connections.\n                </p>\n                <button \n                    onClick={signInWithGoogle} \n                    className=\"btn-primary w-full px-6 py-3 flex items-center justify-center gap-2 mx-auto\"\n                >\n                    Sign in with Google\n                </button>\n            </div>\n        </div>\n    );\n};","import React from 'react';\nimport { ALL_FEATURES } from '../features/index.ts';\nimport type { Feature } from '../../types.ts';\n\ninterface FeatureButtonProps {\n    feature: Feature;\n    onOpen: (id: string) => void;\n}\n\nconst FeatureButton: React.FC<FeatureButtonProps> = ({ feature, onOpen }) => {\n    return (\n        <button\n            onClick={() => onOpen(feature.id)}\n            className=\"w-24 h-24 flex flex-col items-center justify-center p-2 rounded-lg bg-slate-800/50 hover:bg-slate-700/80 transition-colors group\"\n            title={feature.name}\n        >\n            <div className=\"text-cyan-400 group-hover:scale-110 transition-transform\">{feature.icon}</div>\n            <span className=\"text-xs text-slate-300 mt-2 text-center w-full break-words\">{feature.name}</span>\n        </button>\n    );\n};\n\ninterface FeatureDockProps {\n    onOpen: (id: string) => void;\n}\n\nexport const FeatureDock: React.FC<FeatureDockProps> = ({ onOpen }) => {\n    return (\n        <div className=\"h-96 flex-shrink-0 bg-slate-900/50 backdrop-blur-sm border-b border-slate-800 p-3 overflow-y-auto\">\n            <div className=\"flex flex-wrap gap-3 justify-center\">\n                {ALL_FEATURES.map(feature => (\n                    <FeatureButton key={feature.id} feature={feature} onOpen={onOpen} />\n                ))}\n            </div>\n        </div>\n    );\n};\n","import React, { Suspense, useRef, useState } from 'react';\nimport type { Feature } from '../../types.ts';\nimport { FEATURES_MAP } from '../features/index.ts';\nimport { LoadingIndicator } from '../../App.tsx';\nimport { MinimizeIcon, XMarkIcon } from '../icons.tsx';\n\ninterface WindowState {\n  id: string;\n  position: { x: number; y: number };\n  size: { width: number; height: number };\n  zIndex: number;\n  isMinimized: boolean;\n}\n\ninterface WindowProps {\n  feature: Feature;\n  state: WindowState;\n  isActive: boolean;\n  onClose: (id: string) => void;\n  onMinimize: (id: string) => void;\n  onFocus: (id: string) => void;\n  onUpdate: (id: string, updates: Partial<WindowState>) => void;\n}\n\nexport const Window: React.FC<WindowProps> = ({ feature, state, isActive, onClose, onMinimize, onFocus, onUpdate }) => {\n  const dragStartPos = useRef<{ x: number; y: number } | null>(null);\n  const initialPos = useRef<{ x: number; y: number } | null>(null);\n  \n  const FeatureComponent = FEATURES_MAP.get(feature.id)?.component;\n\n  const handleDragStart = (e: React.MouseEvent<HTMLDivElement>) => {\n    e.preventDefault();\n    onFocus(feature.id);\n    dragStartPos.current = { x: e.clientX, y: e.clientY };\n    initialPos.current = { x: state.position.x, y: state.position.y };\n    window.addEventListener('mousemove', handleDragMove);\n    window.addEventListener('mouseup', handleDragEnd);\n  };\n\n  const handleDragMove = (e: MouseEvent) => {\n    if (!dragStartPos.current || !initialPos.current) return;\n    const dx = e.clientX - dragStartPos.current.x;\n    const dy = e.clientY - dragStartPos.current.y;\n    onUpdate(feature.id, { position: { x: initialPos.current.x + dx, y: initialPos.current.y + dy }});\n  };\n\n  const handleDragEnd = () => {\n    dragStartPos.current = null;\n    initialPos.current = null;\n    window.removeEventListener('mousemove', handleDragMove);\n    window.removeEventListener('mouseup', handleDragEnd);\n  };\n  \n  return (\n    <div\n      className={`absolute bg-slate-800/70 backdrop-blur-md border rounded-lg shadow-2xl shadow-black/50 flex flex-col transition-all duration-100 ${isActive ? 'border-cyan-500/50' : 'border-slate-700/50'}`}\n      style={{\n        left: state.position.x,\n        top: state.position.y,\n        width: state.size.width,\n        height: state.size.height,\n        zIndex: state.zIndex\n      }}\n      onMouseDown={() => onFocus(feature.id)}\n    >\n      <header\n        className={`flex items-center justify-between h-8 px-2 border-b ${isActive ? 'bg-slate-700/50 border-slate-600' : 'bg-slate-800/50 border-slate-700'} rounded-t-lg cursor-move`}\n        onMouseDown={handleDragStart}\n      >\n        <div className=\"flex items-center gap-2 text-xs\">\n           <div className=\"w-4 h-4\">{feature.icon}</div>\n           <span>{feature.name}</span>\n        </div>\n        <div className=\"flex items-center gap-1\">\n          <button onClick={() => onMinimize(feature.id)} className=\"p-1 rounded hover:bg-slate-600\"><MinimizeIcon /></button>\n          <button onClick={() => onClose(feature.id)} className=\"p-1 rounded hover:bg-red-500/50\"><XMarkIcon className=\"w-4 h-4\"/></button>\n        </div>\n      </header>\n      <main className=\"flex-1 overflow-auto bg-slate-800/50 rounded-b-lg\">\n        {FeatureComponent ? (\n          <Suspense fallback={<LoadingIndicator/>}>\n            <FeatureComponent />\n          </Suspense>\n        ) : (\n            <div className=\"p-4 text-red-400\">Error: Component not found for {feature.name}</div>\n        )}\n      </main>\n    </div>\n  );\n};","import React from 'react';\nimport type { Feature } from '../../types.ts';\n\ninterface TaskbarProps {\n  minimizedWindows: Feature[];\n  onRestore: (id: string) => void;\n}\n\nexport const Taskbar: React.FC<TaskbarProps> = ({ minimizedWindows, onRestore }) => {\n  if (minimizedWindows.length === 0) {\n    return null;\n  }\n\n  return (\n    <div className=\"absolute bottom-0 left-20 right-0 h-10 bg-slate-900/80 backdrop-blur-sm border-t border-slate-700 flex items-center px-2 gap-2 z-[999]\">\n      {minimizedWindows.map(feature => (\n        <button\n          key={feature.id}\n          onClick={() => onRestore(feature.id)}\n          className=\"h-8 px-3 flex items-center gap-2 rounded-md bg-slate-700 hover:bg-slate-600 text-slate-200 text-sm\"\n          title={`Restore ${feature.name}`}\n        >\n          <div className=\"w-4 h-4\">{feature.icon}</div>\n          <span>{feature.name}</span>\n        </button>\n      ))}\n    </div>\n  );\n};\n","// This file is a registry of all source code files in the application.\n// It's used by the ActionManager to create a downloadable zip of the entire app source.\n// THIS FILE IS AUTO-GENERATED. DO NOT EDIT BY HAND.\n\nexport const sourceFiles: Record<string, string> = {\n  'App.tsx': `import React, { Suspense, useCallback, useState, useEffect } from 'react';\nimport { ErrorBoundary } from './components/ErrorBoundary.tsx';\nimport { useGlobalState } from './contexts/GlobalStateContext.tsx';\nimport { logEvent } from './services/telemetryService.ts';\nimport type { ViewType, AppUser } from './types.ts';\nimport { CommandPalette } from './components/CommandPalette.tsx';\nimport { NotificationProvider } from './contexts/NotificationContext.tsx';\nimport { useTheme } from './hooks/useTheme.ts';\nimport { VaultProvider } from './components/vault/VaultProvider.tsx';\nimport { initGoogleAuth } from './services/googleAuthService.ts';\nimport { LoginView } from './components/LoginView.tsx';\nimport { DesktopView } from './components/desktop/DesktopView.tsx';\nimport { isApiKeyConfigured, initializeAiClient } from './services/aiService.ts';\nimport { ApiKeyPromptModal } from './components/ApiKeyPromptModal.tsx';\nimport { OctokitProvider } from './contexts/OctokitContext.tsx';\nimport { useVaultModal } from './contexts/VaultModalContext.tsx';\nimport { isVaultInitialized } from './services/vaultService.ts';\n\n\nexport const LoadingIndicator: React.FC = () => (\n    <div className=\"w-full h-full flex items-center justify-center bg-surface\">\n        <div className=\"flex items-center justify-center space-x-2\">\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0s' }}></div>\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n            <span className=\"text-text-secondary ml-2\">Loading...</span>\n        </div>\n    </div>\n);\n\ninterface LocalStorageConsentModalProps {\n  onAccept: () => void;\n  onDecline: () => void;\n}\n\nconst LocalStorageConsentModal: React.FC<LocalStorageConsentModalProps> = ({ onAccept, onDecline }) => {\n  return (\n    <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n      <div \n        className=\"bg-surface border border-border rounded-2xl shadow-2xl shadow-black/50 w-full max-w-md m-4 p-8 text-center animate-pop-in\"\n      >\n        <h2 className=\"text-2xl mb-4\">Store Data Locally?</h2>\n        <p className=\"text-text-secondary mb-6\">\n          This application uses your browser's local storage to save your settings and remember your progress between sessions. This data stays on your computer and is not shared.\n        </p>\n        <div className=\"flex justify-center gap-4\">\n          <button\n            onClick={onDecline}\n            className=\"px-6 py-2 bg-surface border border-border text-text-primary font-bold rounded-md hover:bg-gray-100 dark:hover:bg-slate-700 transition-colors\"\n          >\n            Decline\n          </button>\n          <button\n            onClick={onAccept}\n            className=\"btn-primary px-6 py-2\"\n          >\n            Accept\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nconst AppContent: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const { activeView } = state;\n    const [isCommandPaletteOpen, setCommandPaletteOpen] = useState(false);\n  \n    useEffect(() => {\n      const handleKeyDown = (e: KeyboardEvent) => {\n          if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n              e.preventDefault();\n              setCommandPaletteOpen(isOpen => !isOpen);\n          }\n      };\n      window.addEventListener('keydown', handleKeyDown);\n      return () => window.removeEventListener('keydown', handleKeyDown);\n    }, []);\n  \n    const handleViewChange = useCallback((view: ViewType, props: any = {}) => {\n      logEvent('view_changed', { view });\n      dispatch({ type: 'SET_VIEW', payload: { view, props } });\n      setCommandPaletteOpen(false);\n    }, [dispatch]);\n  \n    return (\n        <OctokitProvider>\n            <div className=\"relative flex h-full w-full bg-slate-800\" style={{\n                backgroundImage: 'radial-gradient(circle at top left, var(--color-primary), transparent 60%), radial-gradient(circle at bottom right, #38bdf8, transparent 50%)',\n                backgroundBlendMode: 'multiply',\n            }}>\n                <ErrorBoundary>\n                    <Suspense fallback={<LoadingIndicator />}>\n                        <DesktopView openFeatureId={activeView} onNavigate={handleViewChange} />\n                    </Suspense>\n                </ErrorBoundary>\n                <CommandPalette isOpen={isCommandPaletteOpen} onClose={() => setCommandPaletteOpen(false)} onSelect={handleViewChange} />\n            </div>\n        </OctokitProvider>\n    )\n}\n\nconst AppShell: React.FC = () => {\n    const [consent, setConsent] = useState<'pending' | 'granted' | 'denied'>();\n    const { state, dispatch } = useGlobalState();\n    const { user, vaultState, isApiKeyMissing } = state;\n    const { requestCreation } = useVaultModal();\n    useTheme();\n\n    useEffect(() => {\n      try {\n          const consentStatus = localStorage.getItem('devcore_ls_consent');\n          if (!consentStatus) {\n              setConsent('pending');\n          } else {\n              setConsent(consentStatus as 'granted' | 'denied');\n          }\n      } catch (e) {\n          console.warn(\"Could not access localStorage.\", e);\n          setConsent('denied');\n      }\n    }, []);\n    \n    // Onboarding flow effect\n    useEffect(() => {\n        const runOnboardingChecks = async () => {\n            if (consent !== 'granted' || !user) return;\n            \n            // Check if vault needs to be created\n            const vaultExists = await isVaultInitialized();\n            if (!vaultExists) {\n                dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: false, isUnlocked: false } });\n                const created = await requestCreation();\n                if (created) {\n                     dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: true, isUnlocked: true } });\n                } else {\n                    return; // Stop flow if vault creation is cancelled\n                }\n            } else {\n                 dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: true } });\n            }\n\n            // After vault is confirmed to exist/be created, check for API key\n            const keyConfigured = await isApiKeyConfigured();\n            if (!keyConfigured) {\n                dispatch({ type: 'SET_API_KEY_MISSING', payload: true });\n            } else {\n                dispatch({ type: 'SET_API_KEY_MISSING', payload: false });\n                initializeAiClient(); // Attempt initialization\n            }\n        };\n        runOnboardingChecks();\n\n    }, [consent, user, requestCreation, dispatch]);\n\n\n    useEffect(() => {\n        const handleUserChanged = (appUser: AppUser | null) => {\n            dispatch({ type: 'SET_APP_USER', payload: appUser });\n        };\n\n        const initAuth = () => {\n            if (window.google) {\n                initGoogleAuth(handleUserChanged);\n            }\n        };\n\n        const gsiScript = document.getElementById('gsi-client');\n        if (window.google) {\n            initAuth();\n        } else if (gsiScript) {\n            gsiScript.addEventListener('load', initAuth);\n            return () => gsiScript.removeEventListener('load', initAuth);\n        }\n    }, [dispatch]);\n  \n    const handleAcceptConsent = () => {\n      try {\n          localStorage.setItem('devcore_ls_consent', 'granted');\n          window.location.reload(); // Reload to re-evaluate storage access\n      } catch (e) {\n          console.error(\"Could not write to localStorage.\", e);\n          setConsent('denied');\n      }\n    };\n  \n    const handleDeclineConsent = () => {\n      try {\n          localStorage.setItem('devcore_ls_consent', 'denied');\n      } catch (e) {\n          console.error(\"Could not write to localStorage.\", e);\n      }\n      setConsent('denied');\n    };\n    \n    const renderContent = () => {\n        if (consent === 'pending') {\n            return <LocalStorageConsentModal onAccept={handleAcceptConsent} onDecline={handleDeclineConsent} />;\n        }\n        if (consent === 'denied') {\n            return <div className=\"w-full h-full flex items-center justify-center p-8 text-center\">Local storage access is required for this application to function. Please reload and accept the prompt.</div>\n        }\n        if (!user) {\n            return <LoginView />;\n        }\n        if (!vaultState.isInitialized || !vaultState.isUnlocked) {\n             // The VaultProvider modals will handle prompting for creation/unlock\n             return <LoadingIndicator />;\n        }\n        if (isApiKeyMissing) {\n            return <ApiKeyPromptModal />;\n        }\n         // Only show main app if user is logged in, vault is handled, and key is present.\n        if (user && vaultState.isUnlocked && !isApiKeyMissing) {\n            return <AppContent />;\n        }\n        // Default to a loading state while checks are running\n        return <LoadingIndicator />;\n    };\n\n    return renderContent();\n};\n\n\nconst App: React.FC = () => {\n    return (\n        <div className=\"h-screen w-screen font-sans overflow-hidden bg-background\">\n            <NotificationProvider>\n                <VaultProvider>\n                    <AppShell />\n                </VaultProvider>\n            </NotificationProvider>\n        </div>\n    );\n};\n\nexport default App;`,\n  'ErrorBoundary.tsx': `import React from 'react';\r\nimport { logError } from '../services/index.ts';\r\nimport { debugErrorStream } from '../services/index.ts';\r\nimport { SparklesIcon } from './icons.tsx';\r\nimport { MarkdownRenderer, LoadingSpinner } from './shared/index.tsx';\r\n\r\ninterface Props {\r\n  children: React.ReactNode;\r\n}\r\n\r\ninterface State {\r\n  hasError: boolean;\r\n  error: Error | null;\r\n  aiHelp: string;\r\n  isAiLoading: boolean;\r\n}\r\n\r\nexport class ErrorBoundary extends React.Component<Props, State> {\r\n  constructor(props: Props) {\r\n    super(props);\r\n    this.state = { hasError: false, error: null, aiHelp: '', isAiLoading: false };\r\n  }\r\n\r\n  static getDerivedStateFromError(error: Error): Partial<State> {\r\n    return { hasError: true, error };\r\n  }\r\n\r\n  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\r\n    logError(error, { componentStack: errorInfo.componentStack });\r\n  }\r\n  \r\n  handleRevert = () => {\r\n    window.location.reload();\r\n  };\r\n\r\n  handleAskAi = async () => {\r\n    if (!this.state.error) return;\r\n\r\n    this.setState({ isAiLoading: true, aiHelp: '' });\r\n    try {\r\n        const stream = debugErrorStream(this.state.error);\r\n        let fullResponse = '';\r\n        for await (const chunk of stream) {\r\n            fullResponse += chunk;\r\n            this.setState({ aiHelp: fullResponse });\r\n        }\r\n    } catch (e) {\r\n        this.setState({ aiHelp: 'Sorry, the AI assistant could not be reached.' });\r\n        logError(e as Error, { context: 'AI Error Debugging' });\r\n    } finally {\r\n        this.setState({ isAiLoading: false });\r\n    }\r\n};\r\n\r\n  render() {\r\n    if (this.state.hasError) {\r\n      return (\r\n        <div className=\"w-full h-full flex flex-col items-center justify-center p-4 sm:p-6 lg:p-8 bg-background text-text-primary\">\r\n            <div className=\"w-full max-w-4xl bg-surface border border-border rounded-lg p-6 shadow-2xl grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n                {/* Left Column: Error Details & Actions */}\r\n                <div className=\"flex flex-col\">\r\n                    <h1 className=\"text-2xl font-bold text-red-600 mb-2\">An Unexpected Error Occurred</h1>\r\n                    <p className=\"text-text-secondary mb-4\">A component has crashed. You can try reloading or ask the AI for debugging help.</p>\r\n                    \r\n                    <details className=\"text-left bg-gray-50 p-2 rounded-md max-w-xl text-xs font-mono mb-4 flex-grow overflow-auto border border-border\">\r\n                        <summary className=\"cursor-pointer\">Error Details</summary>\r\n                        <pre className=\"mt-2 whitespace-pre-wrap\">{this.state.error?.stack}</pre>\r\n                    </details>\r\n                    \r\n                    <div className=\"flex gap-4 mt-auto\">\r\n                        <button\r\n                            onClick={this.handleRevert}\r\n                            className=\"flex-1 px-4 py-2 bg-yellow-400 text-yellow-900 font-bold rounded-md hover:bg-yellow-300 transition-colors\"\r\n                        >\r\n                            Reload Application\r\n                        </button>\r\n                         <button\r\n                            onClick={this.handleAskAi}\r\n                            disabled={this.state.isAiLoading}\r\n                            className=\"btn-primary flex-1 px-4 py-2 flex items-center justify-center gap-2\"\r\n                        >\r\n                            <SparklesIcon />\r\n                            {this.state.isAiLoading ? 'Analyzing...' : 'Ask AI for Help'}\r\n                        </button>\r\n                    </div>\r\n                </div>\r\n\r\n                {/* Right Column: AI Help */}\r\n                <div className=\"flex flex-col bg-gray-50 rounded-lg p-4 border border-border\">\r\n                    <h2 className=\"text-lg font-bold text-text-primary mb-2\">AI Assistant</h2>\r\n                    <div className=\"flex-grow overflow-y-auto\">\r\n                        {this.state.isAiLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div>}\r\n                        {this.state.aiHelp && <MarkdownRenderer content={this.state.aiHelp} />}\r\n                        {!this.state.isAiLoading && !this.state.aiHelp && <p className=\"text-text-secondary text-center pt-10\">Click \"Ask AI\" to get debugging suggestions.</p>}\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </div>\r\n      );\r\n    }\r\n\r\n    return this.props.children;\r\n  }\r\n}`,\n  'README.md': `# DevCore AI Toolkit\n\n> A supercharged, secure, client-side toolkit for modern developers, powered by Gemini. It runs entirely in your browser, keeping your code, data, and API keys private and secure on your local machine.\n\nDevCore is a serverless web application designed to be a powerful assistant in your development workflow. It combines a suite of intelligent tools with a unique, AI-driven command center that can orchestrate actions across your favorite services like Jira, Slack, and GitHub.\n\n---\n\n## ✨ Key Features\n\n-   **AI Command Center:** The heart of the toolkit. Use natural language (\\`Ctrl+K\\`) to navigate, run features, and execute complex, multi-service workflows.\n-   **Workspace Connector Hub:** Connect to Jira, Slack, GitHub, and more. Let the AI execute commands like \"create a high-priority Jira ticket and post a summary to the #dev channel in Slack.\"\n-   **AI Feature Builder:** Generate multi-file components, unit tests, and conventional commit messages from a single, high-level prompt.\n-   **Intelligent Code Tools:** Explain complex code, migrate between languages, review for bugs and security vulnerabilities, and refactor with one click.\n-   **Performance & Auditing:** Profile runtime performance, analyze bundle stats, and audit live websites for accessibility issues with AI-powered advice.\n-   **Visual Editors & Sandboxes:** A suite of focused tools, from a CSS Grid editor and a RegEx sandbox to a PWA Manifest generator, designed to streamline frontend development.\n\n---\n\n## 🏛️ Architecture: Secure & Client-Side\n\nDevCore is built on a serverless, client-side architecture. This design choice offers several key advantages:\n\n-   **Privacy First:** Your code, prompts, and sensitive data never leave your browser. All processing happens locally.\n-   **Ultimate Security:** API keys and credentials for services like GitHub, Gemini, or Jira are encrypted with AES-GCM using the Web Crypto API. They are stored securely in your browser's IndexedDB and can only be decrypted with your master password.\n-   **Runs Anywhere:** As a static application, you can deploy it on any CDN (like GitHub Pages or Netlify) or simply run it from your local filesystem. No backend, no databases, no complex setup.\n\n---\n\n## 🚀 Getting Started\n\n1.  **Open the App:** Just open \\`index.html\\` in your browser.\n2.  **Onboarding:** On first use, you'll be guided through a one-time setup:\n    -   **Consent:** Grant permission for the app to use local storage.\n    -   **Sign-In:** Sign in with your Google Account.\n    -   **Create Vault:** Create a master password. This password encrypts and decrypts your credentials locally and is **never** stored.\n    -   **Provide API Key:** If an API key was not provided during the build process, you will be prompted to enter your own Gemini API key, which will be stored securely in your new vault.\n3.  **Connect Your Services:** Navigate to the **Workspace Connector Hub** to securely add your API keys for services like GitHub, Jira, and Slack.\n4.  **Use the AI Command Center:** Press \\`Ctrl+K\\` (or \\`Cmd+K\\`) anywhere to open the command palette and start giving instructions to the AI.\n\n---\n\n## 🔌 The Workspace Connector Hub\n\nThis is the core of DevCore's workflow automation. Instead of just being a collection of tools, the Hub turns the app into a true command center.\n\n-   **Connect Once, Use Everywhere:** Securely store your API tokens for essential developer services in the encrypted vault.\n-   **AI-Powered Orchestration:** The AI Command Center can use these connections to perform multi-step actions across different platforms.\n-   **Example Command:** _\"A new critical bug was reported. Create a high-priority ticket in Jira, post a summary to the #engineering channel in Slack, and create a new git branch called \\`hotfix/payment-bug\\`.\"_\n\n---\n\n## 🔐 Security & Your Data\n\nYour privacy is paramount. Here's how your data is handled:\n\n-   **No Server-Side Storage:** All files, settings, and credentials reside exclusively in your browser's IndexedDB.\n-   **End-to-End Encryption (Locally):** Credentials entered into the Vault are encrypted using the Web Crypto API before being stored. The encryption key is derived from your master password and is only held in memory during your session.\n-   **Direct API Calls:** When you use an integrated service, the app makes direct, client-to-service API calls. Your data is not proxied through any intermediary server.\n\n---\n\n## 🛠️ Scope & Limitations\n\nAs a client-side application, DevCore has a focused scope. It is designed to be a powerful **assistant** for your development workflow, not a replacement for your primary IDE, backend services, or CI/CD platform. It excels at code generation, analysis, and API-based automation but does not run backend servers, train models, or manage infrastructure.`,\n  'components/ActionManager.tsx': `import React, { useState } from 'react';\nimport JSZip from 'jszip';\nimport { getAllFiles } from '../services/dbService.ts';\nimport { ArrowDownTrayIcon } from './icons.tsx';\nimport { LoadingSpinner } from './shared/index.tsx';\nimport { sourceFiles } from '../services/sourceRegistry.ts';\n\nexport const ActionManager: React.FC = () => {\n    const [isLoading, setIsLoading] = useState<string | null>(null);\n\n    const handleDownloadSource = async () => {\n        setIsLoading('zip');\n        try {\n            const zip = new JSZip();\n\n            for (const [filePath, content] of Object.entries(sourceFiles)) {\n                zip.file(filePath, content);\n            }\n\n            const generatedFiles = await getAllFiles();\n            if (generatedFiles.length > 0) {\n                const generatedFolder = zip.folder('generated');\n                generatedFiles.forEach(file => {\n                    generatedFolder?.file(file.filePath, file.content);\n                });\n            }\n            \n            const zipBlob = await zip.generateAsync({ type: 'blob' });\n            const link = document.createElement('a');\n            link.href = URL.createObjectURL(zipBlob);\n            link.download = 'devcore-ai-toolkit-source.zip';\n            document.body.appendChild(link);\n            link.click();\n            document.body.removeChild(link);\n        } catch (error) {\n            console.error(\"Failed to create ZIP file\", error);\n            alert(\\`Error creating ZIP: \\${error instanceof Error ? error.message : 'Unknown error'}\\`);\n        } finally {\n            setIsLoading(null);\n        }\n    };\n\n    return (\n        <div className=\"absolute top-6 right-6 z-10\">\n            <button\n                onClick={handleDownloadSource}\n                disabled={!!isLoading}\n                className=\"w-14 h-14 bg-primary text-text-on-primary rounded-full flex items-center justify-center shadow-lg hover:opacity-90 transition-colors disabled:bg-slate-600\"\n                aria-label=\"Download App Source Code & Generated Files\"\n                title=\"Download App Source Code & Generated Files\"\n            >\n                {isLoading === 'zip' ? <LoadingSpinner /> : <ArrowDownTrayIcon />}\n            </button>\n        </div>\n    );\n};`,\n  'components/AiCodeExplainer.tsx': `import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react';\nimport mermaid from 'mermaid';\nimport { explainCodeStructured, generateMermaidJs } from '../services/index.ts';\nimport type { StructuredExplanation } from '../types.ts';\nimport { CpuChipIcon } from './icons.tsx';\nimport { MarkdownRenderer, LoadingSpinner } from './shared/index.tsx';\n\nconst exampleCode = \\`const bubbleSort = (arr) => {\n  for (let i = 0; i < arr.length; i++) {\n    for (let j = 0; j < arr.length - i - 1; j++) {\n      if (arr[j] > arr[j + 1]) {\n        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];\n      }\n    }\n  }\n  return arr;\n};\\`;\n\ntype ExplanationTab = 'summary' | 'lineByLine' | 'complexity' | 'suggestions' | 'flowchart';\n\nconst simpleSyntaxHighlight = (code: string) => {\n    const escapedCode = code\n        .replace(/&/g, '&amp;')\n        .replace(/</g, '&lt;')\n        .replace(/>/g, '&gt;');\n\n    return escapedCode\n        .replace(/\\\\b(const|let|var|function|return|if|for|=>|import|from|export|default)\\\\b/g, '<span class=\"text-indigo-400 font-semibold\">\\$1</span>')\n        .replace(/(\\\\\\`|'|\")(.*?)(\\\\\\`|'|\")/g, '<span class=\"text-emerald-400\">\\$1\\$2\\$3</span>')\n        .replace(/(\\\\/\\\\/.*)/g, '<span class=\"text-gray-400 italic\">\\$1</span>')\n        .replace(/(\\\\{|\\\\}|\\\\(|\\\\)|\\\\[|\\\\])/g, '<span class=\"text-gray-400\">\\$1</span>');\n};\n\nmermaid.initialize({ startOnLoad: false, theme: 'neutral', securityLevel: 'loose' });\n\nexport const AiCodeExplainer: React.FC<{ initialCode?: string }> = ({ initialCode }) => {\n    const [code, setCode] = useState<string>(initialCode || exampleCode);\n    const [explanation, setExplanation] = useState<StructuredExplanation | null>(null);\n    const [mermaidCode, setMermaidCode] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    const [activeTab, setActiveTab] = useState<ExplanationTab>('summary');\n    const textareaRef = useRef<HTMLTextAreaElement>(null);\n    const preRef = useRef<HTMLPreElement>(null);\n    const mermaidContainerRef = useRef<HTMLDivElement>(null);\n\n    const handleExplain = useCallback(async (codeToExplain: string) => {\n        if (!codeToExplain.trim()) {\n            setError('Please enter some code to explain.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setExplanation(null);\n        setMermaidCode('');\n        setActiveTab('summary');\n        try {\n            const [explanationResult, mermaidResult] = await Promise.all([\n                explainCodeStructured(codeToExplain),\n                generateMermaidJs(codeToExplain)\n            ]);\n            setExplanation(explanationResult);\n            setMermaidCode(mermaidResult.replace(/\\`\\`\\`mermaid\\\\n|\\`\\`\\`/g, ''));\n\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to get explanation: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n    \n    useEffect(() => {\n        if (initialCode) {\n            setCode(initialCode);\n            handleExplain(initialCode);\n        }\n    }, [initialCode, handleExplain]);\n\n    useEffect(() => {\n        const renderMermaid = async () => {\n             if (activeTab === 'flowchart' && mermaidCode && mermaidContainerRef.current) {\n                try {\n                    mermaidContainerRef.current.innerHTML = ''; // Clear previous\n                    const { svg } = await mermaid.render(\\`mermaid-graph-\\${Date.now()}\\`, mermaidCode);\n                    mermaidContainerRef.current.innerHTML = svg;\n                } catch (e) {\n                    console.error(\"Mermaid rendering error:\", e);\n                    mermaidContainerRef.current.innerHTML = \\`<p class=\"text-red-500\">Error rendering flowchart.</p>\\`;\n                }\n            }\n        }\n        renderMermaid();\n    }, [activeTab, mermaidCode]);\n\n\n    const handleScroll = () => {\n        if (preRef.current && textareaRef.current) {\n            preRef.current.scrollTop = textareaRef.current.scrollTop;\n            preRef.current.scrollLeft = textareaRef.current.scrollLeft;\n        }\n    };\n\n    const highlightedCode = useMemo(() => simpleSyntaxHighlight(code), [code]);\n\n    const renderTabContent = () => {\n        if (!explanation) return null;\n        switch(activeTab) {\n            case 'summary':\n                return <MarkdownRenderer content={explanation.summary} />;\n            case 'lineByLine':\n                return (\n                    <div className=\"space-y-3\">\n                        {explanation.lineByLine.map((item, index) => (\n                            <div key={index} className=\"p-3 bg-background rounded-md border border-border\">\n                                <p className=\"font-mono text-xs text-primary mb-1\">Lines: {item.lines}</p>\n                                <p className=\"text-sm\">{item.explanation}</p>\n                            </div>\n                        ))}\n                    </div>\n                );\n            case 'complexity':\n                return (\n                    <div>\n                        <p><strong>Time Complexity:</strong> <span className=\"font-mono text-amber-600\">{explanation.complexity.time}</span></p>\n                        <p><strong>Space Complexity:</strong> <span className=\"font-mono text-amber-600\">{explanation.complexity.space}</span></p>\n                    </div>\n                );\n            case 'suggestions':\n                return (\n                     <ul className=\"list-disc list-inside space-y-2\">\n                        {explanation.suggestions.map((item, index) => <li key={index}>{item}</li>)}\n                    </ul>\n                );\n            case 'flowchart':\n                return (\n                    <div ref={mermaidContainerRef} className=\"w-full h-full flex items-center justify-center\">\n                        <LoadingSpinner />\n                    </div>\n                );\n        }\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex-shrink-0\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <CpuChipIcon />\n                    <span className=\"ml-3\">AI Code Explainer</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Get a detailed, structured analysis of any code snippet.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 md:grid-cols-2 gap-6 min-h-0\">\n                \n                {/* Left Column: Code Input */}\n                <div className=\"flex flex-col min-h-0 md:col-span-1\">\n                    <label htmlFor=\"code-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Your Code</label>\n                    <div className=\"relative flex-grow bg-surface border border-border rounded-md focus-within:ring-2 focus-within:ring-primary overflow-hidden\">\n                        <textarea\n                            ref={textareaRef}\n                            id=\"code-input\"\n                            value={code}\n                            onChange={(e) => setCode(e.target.value)}\n                            onScroll={handleScroll}\n                            placeholder=\"Paste your code here...\"\n                            spellCheck=\"false\"\n                            className=\"absolute inset-0 w-full h-full p-4 bg-transparent resize-none font-mono text-sm text-transparent caret-primary outline-none z-10\"\n                        />\n                        <pre \n                            ref={preRef}\n                            aria-hidden=\"true\"\n                            className=\"absolute inset-0 w-full h-full p-4 font-mono text-sm text-text-primary pointer-events-none z-0 whitespace-pre-wrap overflow-auto no-scrollbar\"\n                            dangerouslySetInnerHTML={{ __html: highlightedCode + '\\\\n' }}\n                        />\n                    </div>\n                    <div className=\"mt-4 flex-shrink-0\">\n                        <button\n                            onClick={() => handleExplain(code)}\n                            disabled={isLoading}\n                            className=\"btn-primary w-full flex items-center justify-center px-6 py-3\"\n                        >\n                            {isLoading ? <LoadingSpinner/> : 'Analyze Code'}\n                        </button>\n                    </div>\n                </div>\n\n                {/* Right Column: AI Analysis */}\n                <div className=\"flex flex-col min-h-0 md:col-span-1\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">AI Analysis</label>\n                    <div className=\"relative flex-grow flex flex-col bg-surface border border-border rounded-md overflow-hidden\">\n                        <div className=\"flex-shrink-0 flex border-b border-border\">\n                           {(['summary', 'lineByLine', 'complexity', 'suggestions', 'flowchart'] as ExplanationTab[]).map(tab => (\n                               <button key={tab} onClick={() => setActiveTab(tab)} disabled={!explanation}\n                                className={\\`px-4 py-2 text-sm font-medium capitalize transition-colors \\${activeTab === tab ? 'bg-background text-primary font-semibold' : 'text-text-secondary hover:bg-gray-100 dark:hover:bg-slate-700 disabled:text-gray-400 dark:disabled:text-slate-500'}\\`}>\n                                   {tab.replace(/([A-Z])/g, ' \\$1')}\n                               </button>\n                           ))}\n                        </div>\n                        <div className=\"p-4 flex-grow overflow-y-auto\">\n                            {isLoading && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                            {error && <p className=\"text-red-500\">{error}</p>}\n                            {explanation && !isLoading && renderTabContent()}\n                            {!isLoading && !explanation && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">The analysis will appear here.</div>}\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/AiCodingChallenge.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { generateCodingChallengeStream } from '../services/index.ts';\nimport { BeakerIcon } from './icons.tsx';\nimport { LoadingSpinner } from './shared/index.tsx';\nimport { MarkdownRenderer } from './shared/index.tsx';\n\nexport const AiCodingChallenge: React.FC = () => {\n    const [challenge, setChallenge] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleGenerate = useCallback(async () => {\n        setIsLoading(true);\n        setError('');\n        setChallenge('');\n        try {\n            const stream = generateCodingChallengeStream(null);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setChallenge(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate challenge: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        // Generate a challenge on initial load for a better user experience\n        handleGenerate();\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, []);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex justify-between items-center\">\n                <div>\n                    <h1 className=\"text-3xl font-bold flex items-center\">\n                        <BeakerIcon />\n                        <span className=\"ml-3\">AI Coding Challenge Generator</span>\n                    </h1>\n                    <p className=\"text-text-secondary mt-1\">Generate a unique coding problem to test your skills.</p>\n                </div>\n                <button\n                    onClick={handleGenerate}\n                    disabled={isLoading}\n                    className=\"btn-primary flex items-center justify-center px-6 py-3\"\n                >\n                    {isLoading ? <LoadingSpinner /> : 'Generate New Challenge'}\n                </button>\n            </header>\n            <div className=\"flex-grow p-4 bg-surface border border-border rounded-md overflow-y-auto\">\n                {isLoading && (\n                     <div className=\"flex items-center justify-center h-full\">\n                        <LoadingSpinner />\n                     </div>\n                )}\n                {error && <p className=\"text-red-500\">{error}</p>}\n                {challenge && !isLoading && (\n                    <MarkdownRenderer content={challenge} />\n                )}\n                 {!isLoading && !challenge && !error && (\n                    <div className=\"text-text-secondary h-full flex items-center justify-center\">\n                        Click \"Generate New Challenge\" to start.\n                    </div>\n                )}\n            </div>\n        </div>\n    );\n};`,\n  'components/AiCommitGenerator.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { generateCommitMessageStream } from '../services/index.ts';\nimport { GitBranchIcon } from './icons.tsx';\nimport { LoadingSpinner } from './shared/index.tsx';\n\nconst exampleDiff = \\`diff --git a/src/components/Button.tsx b/src/components/Button.tsx\nindex 1b2c3d4..5e6f7g8 100644\n--- a/src/components/Button.tsx\n+++ b/src/components/Button.tsx\n@@ -1,7 +1,7 @@\n import React from 'react';\n\n interface ButtonProps {\n-  text: string;\n+  label: string;\n   onClick: () => void;\n }\n\\`;\n\nexport const AiCommitGenerator: React.FC<{ diff?: string }> = ({ diff: initialDiff }) => {\n    const [diff, setDiff] = useState<string>(initialDiff || exampleDiff);\n    const [message, setMessage] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleGenerate = useCallback(async (diffToAnalyze: string) => {\n        if (!diffToAnalyze.trim()) {\n            setError('Please paste a diff to generate a message.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setMessage('');\n        try {\n            const stream = generateCommitMessageStream(diffToAnalyze);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setMessage(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate message: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        if (initialDiff) {\n            setDiff(initialDiff);\n            handleGenerate(initialDiff);\n        }\n    }, [initialDiff, handleGenerate]);\n    \n    const handleCopy = () => {\n        navigator.clipboard.writeText(message);\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl flex items-center\">\n                    <GitBranchIcon />\n                    <span className=\"ml-3\">AI Commit Message Generator</span>\n                </h1>\n                <p className=\"text-slate-400 mt-1\">Paste your diff and let Gemini craft the perfect commit message.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 h-full overflow-hidden\">\n                <div className=\"flex flex-col h-full\">\n                    <label htmlFor=\"diff-input\" className=\"text-sm font-medium text-slate-400 mb-2\">Git Diff</label>\n                    <textarea\n                        id=\"diff-input\"\n                        value={diff}\n                        onChange={(e) => setDiff(e.target.value)}\n                        placeholder=\"Paste your git diff here...\"\n                        className=\"flex-grow p-4 bg-slate-900 border border-slate-700 rounded-md resize-none font-mono text-sm text-slate-300 focus:ring-2 focus:ring-cyan-500 focus:outline-none\"\n                    />\n                     <button\n                        onClick={() => handleGenerate(diff)}\n                        disabled={isLoading}\n                        className=\"btn-primary mt-4 w-full flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Generate Commit Message'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col h-full\">\n                    <label className=\"text-sm font-medium text-slate-400 mb-2\">Generated Message</label>\n                    <div className=\"relative flex-grow p-4 bg-slate-800/50 border border-slate-700/50 rounded-md overflow-y-auto\">\n                        {isLoading && (\n                             <div className=\"flex items-center justify-center h-full\">\n                                <LoadingSpinner />\n                             </div>\n                        )}\n                        {error && <p className=\"text-red-400\">{error}</p>}\n                        {message && !isLoading && (\n                            <>\n                               <button onClick={handleCopy} className=\"absolute top-2 right-2 px-2 py-1 bg-slate-700 hover:bg-slate-600 rounded-md text-xs\">Copy</button>\n                               <pre className=\"whitespace-pre-wrap font-sans text-slate-200\">{message}</pre>\n                            </>\n                        )}\n                         {!isLoading && !message && !error && (\n                            <div className=\"text-slate-500 h-full flex items-center justify-center\">\n                                The commit message will appear here.\n                            </div>\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/ApiKeyPromptModal.tsx': `import React, { useState } from 'react';\nimport { useGlobalState } from '../contexts/GlobalStateContext.tsx';\nimport { useVaultModal } from '../contexts/VaultModalContext.tsx';\nimport { saveCredential } from '../services/vaultService.ts';\nimport { initializeAiClient } from '../services/aiService.ts';\nimport { LoadingSpinner } from './shared/LoadingSpinner.tsx';\nimport { useNotification } from '../contexts/NotificationContext.tsx';\n\nexport const ApiKeyPromptModal: React.FC = () => {\n    const { dispatch } = useGlobalState();\n    const { requestUnlock } = useVaultModal();\n    const { addNotification } = useNotification();\n    const [apiKey, setApiKey] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n\n    const handleSubmit = async (e: React.FormEvent) => {\n        e.preventDefault();\n        if (!apiKey.trim()) {\n            addNotification('Please enter an API key.', 'error');\n            return;\n        }\n\n        setIsLoading(true);\n\n        try {\n            // Ensure the vault is unlocked before saving\n            const unlocked = await requestUnlock();\n            if (!unlocked) {\n                addNotification('Vault must be unlocked to save the API key.', 'error');\n                setIsLoading(false);\n                return;\n            }\n\n            // Save the key and re-initialize the AI client\n            await saveCredential('gemini_api_key', apiKey);\n            await initializeAiClient();\n\n            addNotification('API Key saved successfully!', 'success');\n            dispatch({ type: 'SET_API_KEY_MISSING', payload: false });\n\n        } catch (error) {\n            addNotification(error instanceof Error ? error.message : 'An unknown error occurred.', 'error');\n        } finally {\n            setIsLoading(false);\n        }\n    };\n\n    return (\n        <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n            <div className=\"bg-surface border border-border rounded-lg shadow-2xl w-full max-w-md m-4 p-6 animate-pop-in\">\n                <h2 className=\"text-xl font-bold mb-2\">Enter Gemini API Key</h2>\n                <p className=\"text-sm text-text-secondary mb-4\">\n                    Your Gemini API key is required to power the AI features. It will be stored securely and encrypted in your browser's local storage.\n                </p>\n                <form onSubmit={handleSubmit} className=\"space-y-4\">\n                    <div>\n                        <label htmlFor=\"api-key-input\" className=\"block text-sm font-medium\">API Key</label>\n                        <input\n                            id=\"api-key-input\"\n                            type=\"password\"\n                            value={apiKey}\n                            onChange={(e) => setApiKey(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                            autoFocus\n                        />\n                    </div>\n                    <div className=\"flex justify-end gap-2 pt-2\">\n                        <button type=\"submit\" disabled={isLoading} className=\"btn-primary px-4 py-2 min-w-[100px] flex justify-center\">\n                            {isLoading ? <LoadingSpinner /> : 'Save & Continue'}\n                        </button>\n                    </div>\n                </form>\n            </div>\n        </div>\n    );\n};`,\n  'components/CommandPalette.tsx': `\nimport React, { useState, useEffect, useMemo } from 'react';\nimport { ALL_FEATURES } from './features/index.ts';\nimport type { ViewType } from '../types.ts';\n\ninterface CommandPaletteProps {\n  isOpen: boolean;\n  onClose: () => void;\n  onSelect: (view: ViewType) => void;\n}\n\nexport const CommandPalette: React.FC<CommandPaletteProps> = ({ isOpen, onClose, onSelect }) => {\n  const [searchTerm, setSearchTerm] = useState('');\n  const [selectedIndex, setSelectedIndex] = useState(0);\n\n  useEffect(() => {\n    if (!isOpen) {\n      setSearchTerm('');\n      setSelectedIndex(0);\n    }\n  }, [isOpen]);\n  \n  const commandOptions = useMemo(() => {\n    const navigationCommands = [\n      { id: 'ai-feature-builder', name: 'Go to AI Builder', category: 'Navigation', icon: <span />, description: ''},\n    ];\n    \n    const featureCommands = ALL_FEATURES.map(f => ({...f, name: \\`Open: \\${f.name}\\`}));\n\n     return [\n      ...navigationCommands,\n      ...featureCommands,\n     ].filter(\n        (feature) =>\n          feature.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n          feature.category.toLowerCase().includes(searchTerm.toLowerCase())\n      );\n  }, [searchTerm]);\n\n  useEffect(() => {\n    setSelectedIndex(0);\n  }, [commandOptions.length]);\n\n  useEffect(() => {\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (!isOpen) return;\n      if (e.key === 'ArrowDown') {\n        e.preventDefault();\n        setSelectedIndex((prev) => (prev + 1) % commandOptions.length);\n      } else if (e.key === 'ArrowUp') {\n        e.preventDefault();\n        setSelectedIndex((prev) => (prev - 1 + commandOptions.length) % commandOptions.length);\n      } else if (e.key === 'Enter') {\n        e.preventDefault();\n        const selected = commandOptions[selectedIndex];\n        if (selected) {\n          onSelect(selected.id as ViewType);\n        }\n      }\n    };\n    window.addEventListener('keydown', handleKeyDown);\n    return () => window.removeEventListener('keydown', handleKeyDown);\n  }, [isOpen, commandOptions, selectedIndex, onSelect]);\n\n  if (!isOpen) return null;\n\n  return (\n    <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-start justify-center pt-20\" onClick={onClose}>\n      <div\n        className=\"w-full max-w-xl bg-surface border border-border rounded-lg shadow-2xl overflow-hidden\"\n        onClick={(e) => e.stopPropagation()}\n      >\n        <input\n          type=\"text\"\n          placeholder=\"Type a command or search...\"\n          value={searchTerm}\n          onChange={(e) => setSearchTerm(e.target.value)}\n          autoFocus\n          className=\"w-full p-4 bg-surface text-text-primary text-lg focus:outline-none border-b border-border\"\n        />\n        <ul className=\"max-h-96 overflow-y-auto p-2\">\n          {commandOptions.length > 0 ? (\n            commandOptions.map((item, index) => (\n              <li\n                key={item.id + index}\n                onMouseDown={() => {\n                   onSelect(item.id as ViewType);\n                }}\n                className={\\`flex items-center justify-between p-3 rounded-md cursor-pointer \\${\n                  selectedIndex === index ? 'bg-primary/10 text-primary' : 'hover:bg-gray-100'\n                }\\`}\n              >\n                <div className=\"flex items-center space-x-3\">\n                    <div className=\"text-text-secondary\">{item.icon}</div>\n                    <span className=\"text-text-primary\">{item.name}</span>\n                </div>\n                <span className=\"text-xs text-text-secondary bg-gray-100 px-2 py-1 rounded\">{item.category}</span>\n              </li>\n            ))\n          ) : (\n            <li className=\"p-4 text-center text-text-secondary\">No results found.</li>\n          )}\n        </ul>\n      </div>\n    </div>\n  );\n};`,\n  'components/ErrorBoundary.tsx': `import React from 'react';\nimport { logError } from '../services/telemetryService.ts';\nimport { debugErrorStream } from '../services/aiService.ts';\nimport { SparklesIcon } from './icons.tsx';\nimport { MarkdownRenderer, LoadingSpinner } from './shared/index.tsx';\n\ninterface Props {\n  children: React.ReactNode;\n}\n\ninterface State {\n  hasError: boolean;\n  error: Error | null;\n  aiHelp: string;\n  isAiLoading: boolean;\n}\n\nexport class ErrorBoundary extends React.Component<Props, State> {\n  constructor(props: Props) {\n    super(props);\n    this.state = { hasError: false, error: null, aiHelp: '', isAiLoading: false };\n  }\n\n  static getDerivedStateFromError(error: Error): Partial<State> {\n    return { hasError: true, error };\n  }\n\n  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n    logError(error, { componentStack: errorInfo.componentStack });\n  }\n  \n  handleRevert = () => {\n    window.location.reload();\n  };\n\n  handleAskAi = async () => {\n    if (!this.state.error) return;\n\n    this.setState({ isAiLoading: true, aiHelp: '' });\n    try {\n        const stream = debugErrorStream(this.state.error);\n        let fullResponse = '';\n        for await (const chunk of stream) {\n            fullResponse += chunk;\n            this.setState({ aiHelp: fullResponse });\n        }\n    } catch (e) {\n        this.setState({ aiHelp: 'Sorry, the AI assistant could not be reached.' });\n        logError(e as Error, { context: 'AI Error Debugging' });\n    } finally {\n        this.setState({ isAiLoading: false });\n    }\n};\n\n  render() {\n    if (this.state.hasError) {\n      return (\n        <div className=\"w-full h-full flex flex-col items-center justify-center p-4 sm:p-6 lg:p-8 bg-background text-text-primary\">\n            <div className=\"w-full max-w-4xl bg-surface border border-border rounded-lg p-6 shadow-2xl grid grid-cols-1 md:grid-cols-2 gap-6\">\n                <div className=\"flex flex-col\">\n                    <h1 className=\"text-2xl font-bold text-red-600 mb-2\">An Unexpected Error Occurred</h1>\n                    <p className=\"text-text-secondary mb-4\">A component has crashed. You can try reloading or ask the AI for debugging help.</p>\n                    \n                    <details className=\"text-left bg-gray-50 dark:bg-slate-900 p-2 rounded-md max-w-xl text-xs font-mono mb-4 flex-grow overflow-auto border border-border\">\n                        <summary className=\"cursor-pointer\">Error Details</summary>\n                        <pre className=\"mt-2 whitespace-pre-wrap\">{this.state.error?.stack}</pre>\n                    </details>\n                    \n                    <div className=\"flex gap-4 mt-auto\">\n                        <button\n                            onClick={this.handleRevert}\n                            className=\"flex-1 px-4 py-2 bg-yellow-400 text-yellow-900 font-bold rounded-md hover:bg-yellow-300 transition-colors\"\n                        >\n                            Reload Application\n                        </button>\n                         <button\n                            onClick={this.handleAskAi}\n                            disabled={this.state.isAiLoading}\n                            className=\"btn-primary flex-1 px-4 py-2 flex items-center justify-center gap-2\"\n                        >\n                            <SparklesIcon />\n                            {this.state.isAiLoading ? 'Analyzing...' : 'Ask AI for Help'}\n                        </button>\n                    </div>\n                </div>\n\n                <div className=\"flex flex-col bg-gray-50 dark:bg-slate-900 rounded-lg p-4 border border-border\">\n                    <h2 className=\"text-lg font-bold text-text-primary mb-2\">AI Assistant</h2>\n                    <div className=\"flex-grow overflow-y-auto\">\n                        {this.state.isAiLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div>}\n                        {this.state.aiHelp && <MarkdownRenderer content={this.state.aiHelp} />}\n                        {!this.state.isAiLoading && !this.state.aiHelp && <p className=\"text-text-secondary text-center pt-10\">Click \"Ask AI\" to get debugging suggestions.</p>}\n                    </div>\n                </div>\n            </div>\n        </div>\n      );\n    }\n\n    return this.props.children;\n  }\n}\n`,\n  'components/FeatureGrid.tsx': `\n\nimport React, { useState, useMemo } from 'react';\nimport type { Feature } from '../types.ts';\n\ninterface FeatureCardProps {\n  feature: Feature;\n  onClick: () => void;\n}\n\nconst FeatureCard: React.FC<FeatureCardProps> = ({ feature, onClick }) => {\n  return (\n    <div\n      onClick={onClick}\n      className=\"bg-slate-800/50 p-4 rounded-lg border border-slate-700/50 flex flex-col justify-between transition-all duration-200 hover:bg-slate-800 hover:border-slate-700 hover:shadow-lg hover:shadow-cyan-500/10 cursor-pointer\"\n    >\n      <div>\n        <div className=\"flex items-center space-x-3 mb-2\">\n          <div className=\"text-cyan-400\">{feature.icon}</div>\n          <h3 className=\"font-bold text-slate-200\">{feature.name}</h3>\n        </div>\n        <p className=\"text-sm text-slate-400\">{feature.description}</p>\n      </div>\n      <div className=\"text-xs text-slate-500 mt-4\">{feature.category}</div>\n    </div>\n  );\n};\n\n\nexport const FeatureGrid: React.FC<{ features: Feature[], onFeatureSelect?: (id: string) => void }> = ({ features, onFeatureSelect }) => {\n  const [searchTerm, setSearchTerm] = useState('');\n\n  const filteredFeatures = useMemo(() => {\n    const featureList = features || [];\n    if (!searchTerm) return featureList;\n    return featureList.filter(\n      (feature) =>\n        feature.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n        feature.description.toLowerCase().includes(searchTerm.toLowerCase()) ||\n        feature.category.toLowerCase().includes(searchTerm.toLowerCase())\n    );\n  }, [searchTerm, features]);\n\n  return (\n    <div className=\"p-4 sm:p-6 lg:p-8 h-full\">\n      <div className=\"mb-8 text-center\">\n        <h1 className=\"text-4xl font-extrabold text-slate-100 tracking-tight\">DevCore AI Toolkit</h1>\n        <p className=\"mt-2 text-lg text-slate-400\">A focused toolkit for modern development, powered by AI.</p>\n        <div className=\"mt-6 max-w-xl mx-auto\">\n          <input\n            type=\"text\"\n            placeholder=\"Search features...\"\n            value={searchTerm}\n            onChange={(e) => setSearchTerm(e.target.value)}\n            className=\"w-full px-4 py-2 rounded-lg bg-slate-800 border border-slate-700 focus:ring-2 focus:ring-cyan-500 focus:outline-none transition-shadow\"\n          />\n        </div>\n      </div>\n      <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4\">\n        {filteredFeatures.map((feature) => (\n          <FeatureCard key={feature.id} feature={feature} onClick={() => onFeatureSelect?.(feature.id)} />\n        ))}\n      </div>\n    </div>\n  );\n};`,\n  'components/LoginView.tsx': `import React from 'react';\nimport { signInWithGoogle } from '../services/googleAuthService.ts';\n\nexport const LoginView: React.FC = () => {\n    return (\n        <div className=\"h-full w-full flex items-center justify-center bg-background\">\n            <div className=\"text-center bg-surface p-8 rounded-lg border border-border max-w-md shadow-lg animate-pop-in\">\n                <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" className=\"text-primary mx-auto mb-4\">\n                    <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n                </svg>\n                <h1 className=\"text-2xl font-bold text-text-primary\">Welcome to DevCore AI</h1>\n                <p className=\"text-text-secondary my-4\">\n                    Please sign in with your Google account to securely access your workspace tools and manage API connections.\n                </p>\n                <button \n                    onClick={signInWithGoogle} \n                    className=\"btn-primary w-full px-6 py-3 flex items-center justify-center gap-2 mx-auto\"\n                >\n                    Sign in with Google\n                </button>\n            </div>\n        </div>\n    );\n};`,\n  'components/SettingsView.tsx': `import React from 'react';\nimport { useGlobalState } from '../contexts/GlobalStateContext.tsx';\nimport { clearAllFiles } from '../services/dbService.ts';\nimport { useLocalStorage } from '../hooks/useLocalStorage.ts';\nimport { useTheme } from '../hooks/useTheme.ts';\nimport { ALL_FEATURES } from './features/index.ts';\nimport { TrashIcon, SunIcon, MoonIcon } from './icons.tsx';\n\nconst ToggleSwitch: React.FC<{ checked: boolean, onChange: () => void }> = ({ checked, onChange }) => {\n    return (\n        <button\n            role=\"switch\"\n            aria-checked={checked}\n            onClick={onChange}\n            className={\\`\\${checked ? 'bg-primary' : 'bg-gray-300 dark:bg-slate-600'} relative inline-flex h-6 w-11 items-center rounded-full transition-colors\\`}\n        >\n            <span className={\\`\\${checked ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition-transform\\`} />\n        </button>\n    );\n};\n\nexport const SettingsView: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const [themeState, toggleTheme, , clearCustomTheme] = useTheme();\n    const [, setSnippets] = useLocalStorage('devcore_snippets', []);\n    const [, setNotes] = useLocalStorage('devcore_moodboard', []);\n    const [, setDevNotes] = useLocalStorage('devcore_notes', []);\n    const [, setPersonalities] = useLocalStorage('devcore_ai_personalities', []);\n\n    const handleClearGeneratedFiles = async () => {\n        if (window.confirm(\"Are you sure you want to delete all AI-generated files? This cannot be undone.\")) {\n            await clearAllFiles();\n            alert(\"Generated files cleared.\");\n        }\n    };\n    \n    const handleClearSnippets = () => {\n        if (window.confirm(\"Are you sure you want to delete all saved snippets? This cannot be undone.\")) {\n            setSnippets([]);\n            alert(\"Snippets cleared.\");\n        }\n    };\n\n    const handleClearNotes = () => {\n        if (window.confirm(\"Are you sure you want to delete all notes and moodboard items? This cannot be undone.\")) {\n            setNotes([]);\n            setDevNotes([]);\n            alert(\"Notes & Moodboard cleared.\");\n        }\n    };\n    \n    const handleClearPersonalities = () => {\n        if (window.confirm(\"Are you sure you want to delete all AI Personalities? This cannot be undone.\")) {\n            setPersonalities([]);\n            alert(\"AI Personalities cleared.\");\n        }\n    }\n\n    return (\n        <div className=\"w-full text-text-primary\">\n            <header className=\"sticky top-0 z-10 p-4 sm:p-6 lg:p-8 border-b border-border bg-surface/80 backdrop-blur-sm\">\n                <div className=\"max-w-4xl mx-auto w-full\">\n                    <h1 className=\"text-4xl font-extrabold tracking-tight\">Settings</h1>\n                    <p className=\"mt-2 text-lg text-text-secondary\">Manage application preferences and data.</p>\n                </div>\n            </header>\n\n            <div className=\"p-4 sm:p-6 lg:p-8 space-y-8 max-w-4xl mx-auto w-full\">\n                 {/* Appearance Section */}\n                <section>\n                    <h2 className=\"text-2xl font-bold border-b border-border pb-2 mb-4\">Appearance</h2>\n                    <div className=\"flex items-center justify-between p-4 bg-surface border border-border rounded-lg\">\n                        <div>\n                            <p className=\"font-medium\">Theme</p>\n                            <p className=\"text-sm text-text-secondary\">Switch between light and dark mode.</p>\n                        </div>\n                        <div className=\"flex items-center gap-2\">\n                            <SunIcon />\n                            <ToggleSwitch checked={themeState.mode === 'dark'} onChange={toggleTheme} />\n                            <MoonIcon />\n                        </div>\n                    </div>\n                    <div className=\"flex items-center justify-between p-4 bg-surface border border-border rounded-lg mt-4\">\n                        <div>\n                            <p className=\"font-medium\">Custom Theme</p>\n                            <p className=\"text-sm text-text-secondary\">Revert to the default application theme.</p>\n                        </div>\n                        <div className=\"flex items-center gap-2\">\n                            <button onClick={clearCustomTheme} disabled={!themeState.customColors} className=\"px-4 py-2 text-sm rounded-md bg-gray-100 dark:bg-slate-700 hover:bg-gray-200 dark:hover:bg-slate-600 disabled:opacity-50 disabled:cursor-not-allowed\">\n                                Revert to Default\n                            </button>\n                        </div>\n                    </div>\n                </section>\n                \n                 {/* Feature Visibility Section */}\n                <section>\n                    <h2 className=\"text-2xl font-bold border-b border-border pb-2 mb-4\">Feature Visibility</h2>\n                     <p className=\"text-sm text-text-secondary mb-4\">\n                        Hide or show features in the main sidebar. This does not disable them; they can still be accessed via the AI Command Center.\n                    </p>\n                    <div className=\"space-y-2\">\n                        {ALL_FEATURES.filter(f => !['ai-command-center', 'connections', 'project-explorer'].includes(f.id)).map(feature => {\n                            const isVisible = !state.hiddenFeatures.includes(feature.id);\n                            return (\n                                <div key={feature.id} className=\"flex items-center justify-between p-4 bg-surface border border-border rounded-lg\">\n                                    <div>\n                                        <p className=\"font-medium\">{feature.name}</p>\n                                        <p className=\"text-sm text-text-secondary\">{feature.description}</p>\n                                    </div>\n                                    <ToggleSwitch \n                                        checked={isVisible}\n                                        onChange={() => dispatch({ type: 'TOGGLE_FEATURE_VISIBILITY', payload: { featureId: feature.id } })}\n                                    />\n                                </div>\n                            );\n                        })}\n                    </div>\n                </section>\n                \n                {/* Data Management Section */}\n                <section>\n                    <h2 className=\"text-2xl font-bold border-b border-border pb-2 mb-4\">Data Management</h2>\n                    <div className=\"space-y-4\">\n                         <div className=\"flex items-center justify-between p-4 bg-surface border border-red-500/20 rounded-lg\">\n                             <div>\n                                <p className=\"font-medium text-red-700 dark:text-red-400\">Clear Generated Files</p>\n                                <p className=\"text-sm text-text-secondary\">Removes all files created by the AI Feature Builder.</p>\n                             </div>\n                             <button onClick={handleClearGeneratedFiles} className=\"flex items-center gap-2 px-4 py-2 rounded-md bg-red-500/10 text-red-600 hover:bg-red-500/20 transition-colors\">\n                                <TrashIcon /> Clear\n                             </button>\n                         </div>\n                         <div className=\"flex items-center justify-between p-4 bg-surface border border-red-500/20 rounded-lg\">\n                             <div>\n                                <p className=\"font-medium text-red-700 dark:text-red-400\">Clear Snippet Vault</p>\n                                <p className=\"text-sm text-text-secondary\">Removes all saved code snippets.</p>\n                             </div>\n                             <button onClick={handleClearSnippets} className=\"flex items-center gap-2 px-4 py-2 rounded-md bg-red-500/10 text-red-600 hover:bg-red-500/20 transition-colors\">\n                                <TrashIcon /> Clear\n                             </button>\n                         </div>\n                         <div className=\"flex items-center justify-between p-4 bg-surface border border-red-500/20 rounded-lg\">\n                             <div>\n                                <p className=\"font-medium text-red-700 dark:text-red-400\">Clear Notes & Whiteboard</p>\n                                <p className=\"text-sm text-text-secondary\">Removes all items from Dev Notes and Digital Whiteboard.</p>\n                             </div>\n                             <button onClick={handleClearNotes} className=\"flex items-center gap-2 px-4 py-2 rounded-md bg-red-500/10 text-red-600 hover:bg-red-500/20 transition-colors\">\n                                <TrashIcon /> Clear\n                             </button>\n                         </div>\n                         <div className=\"flex items-center justify-between p-4 bg-surface border border-red-500/20 rounded-lg\">\n                             <div>\n                                <p className=\"font-medium text-red-700 dark:text-red-400\">Clear AI Personalities</p>\n                                <p className=\"text-sm text-text-secondary\">Removes all custom AI personalities.</p>\n                             </div>\n                             <button onClick={handleClearPersonalities} className=\"flex items-center gap-2 px-4 py-2 rounded-md bg-red-500/10 text-red-600 hover:bg-red-500/20 transition-colors\">\n                                <TrashIcon /> Clear\n                             </button>\n                         </div>\n                    </div>\n                </section>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/StatusBar.tsx': `import React, { useState, useEffect } from 'react';\nimport { GitBranchIcon, BellIcon } from './icons.tsx';\n\ntype BgImageStatus = 'loading' | 'loaded' | 'error';\n\nconst StatusMessage: React.FC<{ status: BgImageStatus }> = ({ status }) => {\n    const [visible, setVisible] = useState(true);\n\n    useEffect(() => {\n        setVisible(true);\n        if (status === 'error') {\n            const timer = setTimeout(() => setVisible(false), 5000);\n            return () => clearTimeout(timer);\n        }\n    }, [status]);\n\n    if (!visible || status === 'loaded') {\n        return null;\n    }\n\n    if (status === 'loading') {\n        return (\n            <div className=\"flex items-center space-x-2\">\n                <div className=\"w-2 h-2 rounded-full bg-primary animate-pulse\"></div>\n                <span>Generating background...</span>\n            </div>\n        );\n    }\n\n    if (status === 'error') {\n        return (\n            <div className=\"flex items-center space-x-2 text-yellow-600\">\n                <span>Background failed. Using fallback.</span>\n            </div>\n        );\n    }\n\n    return null;\n};\n\nconst Clock: React.FC = () => {\n    const [time, setTime] = useState(() => new Date());\n\n    useEffect(() => {\n        const timerId = setInterval(() => {\n            setTime(new Date());\n        }, 1000);\n\n        return () => clearInterval(timerId);\n    }, []);\n\n    return <span>{time.toLocaleTimeString()}</span>\n}\n\n\nexport const StatusBar: React.FC<{ bgImageStatus: BgImageStatus }> = ({ bgImageStatus }) => {\n  return (\n    <footer className=\"w-full bg-surface/70 backdrop-blur-sm border-t border-border px-4 py-1 flex items-center justify-between text-xs text-text-secondary\">\n      <div className=\"flex items-center space-x-4\">\n        <div className=\"flex items-center space-x-1 cursor-pointer hover:text-primary transition-colors\">\n          <GitBranchIcon />\n          <span>main</span>\n        </div>\n        <StatusMessage status={bgImageStatus} />\n      </div>\n      <div className=\"flex items-center space-x-4\">\n        <Clock />\n        <span className=\"hidden sm:block\">Ready</span>\n        <div className=\"flex items-center space-x-1 cursor-pointer hover:text-primary transition-colors\">\n          <BellIcon />\n          <span>0</span>\n        </div>\n        <span className=\"hidden sm:block\">\n          Powered by Gemini\n        </span>\n      </div>\n    </footer>\n  );\n};`,\n  'components/desktop/.placeholder': ``,\n  'components/desktop/DesktopView.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { FeatureDock } from './FeatureDock.tsx';\nimport { Window } from './Window.tsx';\nimport { Taskbar } from './Taskbar.tsx';\nimport { ALL_FEATURES } from '../features/index.ts';\nimport type { Feature, ViewType } from '../../types.ts';\nimport { ActionManager } from '../ActionManager.tsx';\n\ninterface WindowState {\n  id: string;\n  position: { x: number; y: number };\n  size: { width: number; height: number };\n  zIndex: number;\n  isMinimized: boolean;\n}\n\nconst Z_INDEX_BASE = 10;\n\nexport const DesktopView: React.FC<{ openFeatureId?: string, onNavigate: (view: ViewType, props?: any) => void; }> = ({ openFeatureId, onNavigate }) => {\n    const [windows, setWindows] = useState<Record<string, WindowState>>({});\n    const [activeId, setActiveId] = useState<string | null>(null);\n    const [nextZIndex, setNextZIndex] = useState(Z_INDEX_BASE);\n    \n    const openWindow = useCallback((featureId: string) => {\n        if (!featureId) return;\n        const newZIndex = nextZIndex + 1;\n        setNextZIndex(newZIndex);\n        setActiveId(featureId);\n\n        setWindows(prev => {\n            const existingWindow = prev[featureId];\n            if (existingWindow) {\n                return {\n                    ...prev,\n                    [featureId]: {\n                        ...existingWindow,\n                        isMinimized: false,\n                        zIndex: newZIndex,\n                    }\n                };\n            }\n\n            const openWindowsCount = Object.values(prev).filter(w => !w.isMinimized).length;\n            const newWindow: WindowState = {\n                id: featureId,\n                position: { x: 50 + openWindowsCount * 30, y: 50 + openWindowsCount * 30 },\n                size: { width: 800, height: 600 },\n                zIndex: newZIndex,\n                isMinimized: false,\n            };\n            return { ...prev, [featureId]: newWindow };\n        });\n    }, [nextZIndex]);\n    \n    useEffect(() => {\n        if(openFeatureId) {\n            openWindow(openFeatureId);\n            // Reset the view in global state so it doesn't re-trigger\n            onNavigate('dashboard', {});\n        }\n    }, [openFeatureId, openWindow, onNavigate]);\n\n    const closeWindow = (id: string) => {\n        setWindows(prev => {\n            const newState = { ...prev };\n            delete newState[id];\n            return newState;\n        });\n        if (activeId === id) {\n            setActiveId(null);\n        }\n    };\n\n    const minimizeWindow = (id: string) => {\n        setWindows(prev => ({\n            ...prev,\n            [id]: { ...prev[id], isMinimized: true }\n        }));\n        setActiveId(null);\n    };\n\n    const focusWindow = (id: string) => {\n        if (id === activeId) return;\n        const newZIndex = nextZIndex + 1;\n        setNextZIndex(newZIndex);\n        setActiveId(id);\n        setWindows(prev => ({\n            ...prev,\n            [id]: { ...prev[id], zIndex: newZIndex }\n        }));\n    };\n    \n    const updateWindowState = (id: string, updates: Partial<WindowState>) => {\n        setWindows(prev => ({\n            ...prev,\n            [id]: { ...prev[id], ...updates }\n        }));\n    }\n\n    const openWindows = Object.values(windows).filter(w => !w.isMinimized);\n    const minimizedWindows = Object.values(windows).filter(w => w.isMinimized);\n    const featuresMap = new Map(ALL_FEATURES.map(f => [f.id, f]));\n\n    return (\n        <div className=\"h-full flex flex-row bg-transparent w-full\">\n            <FeatureDock onOpen={openWindow} />\n            <div className=\"flex-grow relative overflow-hidden\">\n                {openWindows.map(win => {\n                    const feature = featuresMap.get(win.id);\n                    if (!feature) return null;\n                    return (\n                        <Window\n                            key={win.id}\n                            feature={feature}\n                            state={win}\n                            isActive={win.id === activeId}\n                            onClose={() => closeWindow(win.id)}\n                            onMinimize={() => minimizeWindow(win.id)}\n                            onFocus={() => focusWindow(win.id)}\n                            onUpdate={updateWindowState}\n                        />\n                    );\n                })}\n                <ActionManager />\n            </div>\n            <Taskbar\n                minimizedWindows={minimizedWindows.map(w => featuresMap.get(w.id)).filter(Boolean) as Feature[]}\n                onRestore={openWindow}\n            />\n        </div>\n    );\n};`,\n  'components/desktop/FeatureDock.tsx': `import React from 'react';\nimport { ALL_FEATURES } from '../features/index.ts';\nimport type { Feature } from '../../types.ts';\n\ninterface FeatureButtonProps {\n    feature: Feature;\n    onOpen: (id: string) => void;\n}\n\nconst FeatureButton: React.FC<FeatureButtonProps> = ({ feature, onOpen }) => {\n    return (\n        <button\n            onClick={() => onOpen(feature.id)}\n            className=\"w-24 h-24 flex flex-col items-center justify-center p-2 rounded-lg bg-slate-800/50 hover:bg-slate-700/80 transition-colors group\"\n            title={feature.name}\n        >\n            <div className=\"text-cyan-400 group-hover:scale-110 transition-transform\">{feature.icon}</div>\n            <span className=\"text-xs text-slate-300 mt-2 text-center w-full break-words\">{feature.name}</span>\n        </button>\n    );\n};\n\ninterface FeatureDockProps {\n    onOpen: (id: string) => void;\n}\n\nexport const FeatureDock: React.FC<FeatureDockProps> = ({ onOpen }) => {\n    return (\n        <div className=\"h-96 flex-shrink-0 bg-slate-900/50 backdrop-blur-sm border-b border-slate-800 p-3 overflow-y-auto\">\n            <div className=\"flex flex-wrap gap-3 justify-center\">\n                {ALL_FEATURES.map(feature => (\n                    <FeatureButton key={feature.id} feature={feature} onOpen={onOpen} />\n                ))}\n            </div>\n        </div>\n    );\n};\n`,\n  'components/desktop/Taskbar.tsx': `import React from 'react';\nimport type { Feature } from '../../types.ts';\n\ninterface TaskbarProps {\n  minimizedWindows: Feature[];\n  onRestore: (id: string) => void;\n}\n\nexport const Taskbar: React.FC<TaskbarProps> = ({ minimizedWindows, onRestore }) => {\n  if (minimizedWindows.length === 0) {\n    return null;\n  }\n\n  return (\n    <div className=\"absolute bottom-0 left-20 right-0 h-10 bg-slate-900/80 backdrop-blur-sm border-t border-slate-700 flex items-center px-2 gap-2 z-[999]\">\n      {minimizedWindows.map(feature => (\n        <button\n          key={feature.id}\n          onClick={() => onRestore(feature.id)}\n          className=\"h-8 px-3 flex items-center gap-2 rounded-md bg-slate-700 hover:bg-slate-600 text-slate-200 text-sm\"\n          title={\\`Restore \\${feature.name}\\`}\n        >\n          <div className=\"w-4 h-4\">{feature.icon}</div>\n          <span>{feature.name}</span>\n        </button>\n      ))}\n    </div>\n  );\n};\n`,\n  'components/desktop/Window.tsx': `import React, { Suspense, useRef, useState } from 'react';\nimport type { Feature } from '../../types.ts';\nimport { FEATURES_MAP } from '../features/index.ts';\nimport { LoadingIndicator } from '../../App.tsx';\nimport { MinimizeIcon, XMarkIcon } from '../icons.tsx';\n\ninterface WindowState {\n  id: string;\n  position: { x: number; y: number };\n  size: { width: number; height: number };\n  zIndex: number;\n  isMinimized: boolean;\n}\n\ninterface WindowProps {\n  feature: Feature;\n  state: WindowState;\n  isActive: boolean;\n  onClose: (id: string) => void;\n  onMinimize: (id: string) => void;\n  onFocus: (id: string) => void;\n  onUpdate: (id: string, updates: Partial<WindowState>) => void;\n}\n\nexport const Window: React.FC<WindowProps> = ({ feature, state, isActive, onClose, onMinimize, onFocus, onUpdate }) => {\n  const dragStartPos = useRef<{ x: number; y: number } | null>(null);\n  const initialPos = useRef<{ x: number; y: number } | null>(null);\n  \n  const FeatureComponent = FEATURES_MAP.get(feature.id)?.component;\n\n  const handleDragStart = (e: React.MouseEvent<HTMLDivElement>) => {\n    e.preventDefault();\n    onFocus(feature.id);\n    dragStartPos.current = { x: e.clientX, y: e.clientY };\n    initialPos.current = { x: state.position.x, y: state.position.y };\n    window.addEventListener('mousemove', handleDragMove);\n    window.addEventListener('mouseup', handleDragEnd);\n  };\n\n  const handleDragMove = (e: MouseEvent) => {\n    if (!dragStartPos.current || !initialPos.current) return;\n    const dx = e.clientX - dragStartPos.current.x;\n    const dy = e.clientY - dragStartPos.current.y;\n    onUpdate(feature.id, { position: { x: initialPos.current.x + dx, y: initialPos.current.y + dy }});\n  };\n\n  const handleDragEnd = () => {\n    dragStartPos.current = null;\n    initialPos.current = null;\n    window.removeEventListener('mousemove', handleDragMove);\n    window.removeEventListener('mouseup', handleDragEnd);\n  };\n  \n  return (\n    <div\n      className={\\`absolute bg-slate-800/70 backdrop-blur-md border rounded-lg shadow-2xl shadow-black/50 flex flex-col transition-all duration-100 \\${isActive ? 'border-cyan-500/50' : 'border-slate-700/50'}\\`}\n      style={{\n        left: state.position.x,\n        top: state.position.y,\n        width: state.size.width,\n        height: state.size.height,\n        zIndex: state.zIndex\n      }}\n      onMouseDown={() => onFocus(feature.id)}\n    >\n      <header\n        className={\\`flex items-center justify-between h-8 px-2 border-b \\${isActive ? 'bg-slate-700/50 border-slate-600' : 'bg-slate-800/50 border-slate-700'} rounded-t-lg cursor-move\\`}\n        onMouseDown={handleDragStart}\n      >\n        <div className=\"flex items-center gap-2 text-xs\">\n           <div className=\"w-4 h-4\">{feature.icon}</div>\n           <span>{feature.name}</span>\n        </div>\n        <div className=\"flex items-center gap-1\">\n          <button onClick={() => onMinimize(feature.id)} className=\"p-1 rounded hover:bg-slate-600\"><MinimizeIcon /></button>\n          <button onClick={() => onClose(feature.id)} className=\"p-1 rounded hover:bg-red-500/50\"><XMarkIcon className=\"w-4 h-4\"/></button>\n        </div>\n      </header>\n      <main className=\"flex-1 overflow-auto bg-slate-800/50 rounded-b-lg\">\n        {FeatureComponent ? (\n          <Suspense fallback={<LoadingIndicator/>}>\n            <FeatureComponent />\n          </Suspense>\n        ) : (\n            <div className=\"p-4 text-red-400\">Error: Component not found for {feature.name}</div>\n        )}\n      </main>\n    </div>\n  );\n};`,\n  'components/features/AccessibilityAuditor.tsx': `import React, { useState, useRef } from 'react';\nimport { suggestA11yFix } from '../../services/index.ts';\nimport { runAxeAudit, AxeResult } from '../../services/auditing/accessibilityService.ts';\nimport { EyeIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nexport const AccessibilityAuditor: React.FC = () => {\n    const [url, setUrl] = useState('https://react.dev');\n    const [auditUrl, setAuditUrl] = useState('');\n    const [results, setResults] = useState<AxeResult | null>(null);\n    const [isLoading, setIsLoading] = useState(false);\n    const [isLoadingAi, setIsLoadingAi] = useState<string | null>(null);\n    const [aiFixes, setAiFixes] = useState<Record<string, string>>({});\n    const iframeRef = useRef<HTMLIFrameElement>(null);\n\n    const handleAudit = () => {\n        const targetUrl = url.startsWith('http') ? url : \\`https://\\${url}\\`;\n        setAuditUrl(targetUrl);\n        setIsLoading(true);\n        setResults(null);\n        setAiFixes({});\n    };\n    \n    const handleIframeLoad = async () => {\n        if (isLoading && iframeRef.current) {\n            try {\n                const auditResults = await runAxeAudit(iframeRef.current.contentWindow!.document);\n                setResults(auditResults);\n            } catch (error) {\n                console.error(error);\n                alert('Could not audit this page. This may be due to security restrictions (CORS).');\n            } finally {\n                setIsLoading(false);\n            }\n        }\n    };\n    \n    const handleGetFix = async (issue: any) => {\n        const issueId = issue.id;\n        setIsLoadingAi(issueId);\n        try {\n            const fix = await suggestA11yFix(issue);\n            setAiFixes(prev => ({...prev, [issueId]: fix}));\n        } catch(e) {\n            setAiFixes(prev => ({...prev, [issueId]: 'Could not get suggestion.'}));\n        } finally {\n            setIsLoadingAi(null);\n        }\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><EyeIcon /><span className=\"ml-3\">Automated Accessibility Auditor</span></h1><p className=\"text-text-secondary mt-1\">Audit a live URL for accessibility issues and get AI-powered fixes.</p></header>\n            <div className=\"flex gap-2 mb-4\"><input type=\"text\" value={url} onChange={e => setUrl(e.target.value)} placeholder=\"https://example.com\" className=\"flex-grow p-2 border rounded\"/><button onClick={handleAudit} disabled={isLoading} className=\"btn-primary px-6 py-2\">{isLoading ? 'Auditing...' : 'Audit'}</button></div>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"bg-background border-2 border-dashed border-border rounded-lg overflow-hidden\"><iframe ref={iframeRef} src={auditUrl} title=\"Audit Target\" className=\"w-full h-full bg-white\" onLoad={handleIframeLoad} sandbox=\"allow-scripts allow-same-origin\"/></div>\n                <div className=\"bg-surface p-4 border border-border rounded-lg flex flex-col\">\n                    <h3 className=\"text-lg font-bold mb-2\">Audit Results</h3>\n                    <div className=\"flex-grow overflow-y-auto pr-2\">\n                        {isLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner/></div>}\n                        {results && (results.violations.length === 0 ? <p>No violations found!</p> :\n                            results.violations.map((v, i) => (\n                                <div key={v.id + i} className=\"p-3 mb-2 bg-background border border-border rounded\">\n                                    <p className=\"font-bold text-red-600\">{v.help}</p>\n                                    <p className=\"text-sm my-1\">{v.description}</p>\n                                    <button onClick={() => handleGetFix(v)} disabled={!!isLoadingAi} className=\"text-xs flex items-center gap-1 text-primary font-semibold\"><SparklesIcon/> {isLoadingAi === v.id ? 'Getting fix...' : 'Ask AI for a fix'}</button>\n                                    {aiFixes[v.id] && <div className=\"mt-2 text-xs border-t pt-2\"><MarkdownRenderer content={aiFixes[v.id]}/></div>}\n                                </div>\n                            ))\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiCodeExplainer.tsx': `import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react';\nimport mermaid from 'mermaid';\nimport { explainCodeStructured, generateMermaidJs } from '../../services/index.ts';\nimport type { StructuredExplanation } from '../../types.ts';\nimport { useTheme } from '../../hooks/useTheme.ts';\nimport { CpuChipIcon } from '../icons.tsx';\nimport { MarkdownRenderer, LoadingSpinner } from '../shared/index.tsx';\n\nconst exampleCode = \\`const bubbleSort = (arr) => {\n  for (let i = 0; i < arr.length; i++) {\n    for (let j = 0; j < arr.length - i - 1; j++) {\n      if (arr[j] > arr[j + 1]) {\n        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];\n      }\n    }\n  }\n  return arr;\n};\\`;\n\ntype ExplanationTab = 'summary' | 'lineByLine' | 'complexity' | 'suggestions' | 'flowchart';\n\nconst simpleSyntaxHighlight = (code: string) => {\n    const escapedCode = code\n        .replace(/&/g, '&amp;')\n        .replace(/</g, '&lt;')\n        .replace(/>/g, '&gt;');\n\n    return escapedCode\n        .replace(/\\\\b(const|let|var|function|return|if|for|=>|import|from|export|default)\\\\b/g, '<span class=\"text-indigo-400 font-semibold\">\\$1</span>')\n        .replace(/(\\\\\\`|'|\")(.*?)(\\\\\\`|'|\")/g, '<span class=\"text-emerald-400\">\\$1\\$2\\$3</span>')\n        .replace(/(\\\\/\\\\/.*)/g, '<span class=\"text-gray-400 italic\">\\$1</span>')\n        .replace(/(\\\\{|\\\\}|\\\\(|\\\\)|\\\\[|\\\\])/g, '<span class=\"text-gray-400\">\\$1</span>');\n};\n\nmermaid.initialize({ startOnLoad: false, securityLevel: 'loose' });\n\nexport const AiCodeExplainer: React.FC<{ initialCode?: string }> = ({ initialCode }) => {\n    const [code, setCode] = useState<string>(initialCode || exampleCode);\n    const [explanation, setExplanation] = useState<StructuredExplanation | null>(null);\n    const [mermaidCode, setMermaidCode] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    const [activeTab, setActiveTab] = useState<ExplanationTab>('summary');\n    const [themeState] = useTheme();\n    const textareaRef = useRef<HTMLTextAreaElement>(null);\n    const preRef = useRef<HTMLPreElement>(null);\n    const mermaidContainerRef = useRef<HTMLDivElement>(null);\n\n    const handleExplain = useCallback(async (codeToExplain: string) => {\n        if (!codeToExplain.trim()) {\n            setError('Please enter some code to explain.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setExplanation(null);\n        setMermaidCode('');\n        setActiveTab('summary');\n        try {\n            const [explanationResult, mermaidResult] = await Promise.all([\n                explainCodeStructured(codeToExplain),\n                generateMermaidJs(codeToExplain)\n            ]);\n            setExplanation(explanationResult);\n            setMermaidCode(mermaidResult.replace(/\\`\\`\\`mermaid\\\\n|\\`\\`\\`/g, ''));\n\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to get explanation: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n    \n    useEffect(() => {\n        if (initialCode) {\n            setCode(initialCode);\n            handleExplain(initialCode);\n        }\n    }, [initialCode, handleExplain]);\n\n    useEffect(() => {\n        const renderMermaid = async () => {\n             if (activeTab === 'flowchart' && mermaidCode && mermaidContainerRef.current) {\n                try {\n                    mermaid.initialize({ startOnLoad: false, theme: themeState.mode === 'dark' ? 'dark' : 'neutral', securityLevel: 'loose' });\n                    mermaidContainerRef.current.innerHTML = ''; // Clear previous\n                    const { svg } = await mermaid.render(\\`mermaid-graph-\\${Date.now()}\\`, mermaidCode);\n                    mermaidContainerRef.current.innerHTML = svg;\n                } catch (e) {\n                    console.error(\"Mermaid rendering error:\", e);\n                    mermaidContainerRef.current.innerHTML = \\`<p class=\"text-red-500\">Error rendering flowchart.</p>\\`;\n                }\n            }\n        }\n        renderMermaid();\n    }, [activeTab, mermaidCode, themeState.mode]);\n\n\n    const handleScroll = () => {\n        if (preRef.current && textareaRef.current) {\n            preRef.current.scrollTop = textareaRef.current.scrollTop;\n            preRef.current.scrollLeft = textareaRef.current.scrollLeft;\n        }\n    };\n\n    const highlightedCode = useMemo(() => simpleSyntaxHighlight(code), [code]);\n\n    const renderTabContent = () => {\n        if (!explanation) return null;\n        switch(activeTab) {\n            case 'summary':\n                return <MarkdownRenderer content={explanation.summary} />;\n            case 'lineByLine':\n                return (\n                    <div className=\"space-y-3\">\n                        {explanation.lineByLine.map((item, index) => (\n                            <div key={index} className=\"p-3 bg-background rounded-md border border-border\">\n                                <p className=\"font-mono text-xs text-primary mb-1\">Lines: {item.lines}</p>\n                                <p className=\"text-sm\">{item.explanation}</p>\n                            </div>\n                        ))}\n                    </div>\n                );\n            case 'complexity':\n                return (\n                    <div>\n                        <p><strong>Time Complexity:</strong> <span className=\"font-mono text-amber-600\">{explanation.complexity.time}</span></p>\n                        <p><strong>Space Complexity:</strong> <span className=\"font-mono text-amber-600\">{explanation.complexity.space}</span></p>\n                    </div>\n                );\n            case 'suggestions':\n                return (\n                     <ul className=\"list-disc list-inside space-y-2\">\n                        {explanation.suggestions.map((item, index) => <li key={index}>{item}</li>)}\n                    </ul>\n                );\n            case 'flowchart':\n                return (\n                    <div ref={mermaidContainerRef} className=\"w-full h-full flex items-center justify-center\">\n                        <LoadingSpinner />\n                    </div>\n                );\n        }\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex-shrink-0\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <CpuChipIcon />\n                    <span className=\"ml-3\">AI Code Explainer</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Get a detailed, structured analysis of any code snippet.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 md:grid-cols-2 gap-6 min-h-0\">\n                \n                {/* Left Column: Code Input */}\n                <div className=\"flex flex-col min-h-0 md:col-span-1\">\n                    <label htmlFor=\"code-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Your Code</label>\n                    <div className=\"relative flex-grow bg-surface border border-border rounded-md focus-within:ring-2 focus-within:ring-primary overflow-hidden\">\n                        <textarea\n                            ref={textareaRef}\n                            id=\"code-input\"\n                            value={code}\n                            onChange={(e) => setCode(e.target.value)}\n                            onScroll={handleScroll}\n                            placeholder=\"Paste your code here...\"\n                            spellCheck=\"false\"\n                            className=\"absolute inset-0 w-full h-full p-4 bg-transparent resize-none font-mono text-sm text-transparent caret-primary outline-none z-10\"\n                        />\n                        <pre \n                            ref={preRef}\n                            aria-hidden=\"true\"\n                            className=\"absolute inset-0 w-full h-full p-4 font-mono text-sm text-text-primary pointer-events-none z-0 whitespace-pre-wrap overflow-auto no-scrollbar\"\n                            dangerouslySetInnerHTML={{ __html: highlightedCode + '\\\\n' }}\n                        />\n                    </div>\n                    <div className=\"mt-4 flex-shrink-0\">\n                        <button\n                            onClick={() => handleExplain(code)}\n                            disabled={isLoading}\n                            className=\"btn-primary w-full flex items-center justify-center px-6 py-3\"\n                        >\n                            {isLoading ? <LoadingSpinner/> : 'Analyze Code'}\n                        </button>\n                    </div>\n                </div>\n\n                {/* Right Column: AI Analysis */}\n                <div className=\"flex flex-col min-h-0 md:col-span-1\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">AI Analysis</label>\n                    <div className=\"relative flex-grow flex flex-col bg-surface border border-border rounded-md overflow-hidden\">\n                        <div className=\"flex-shrink-0 flex border-b border-border\">\n                           {(['summary', 'lineByLine', 'complexity', 'suggestions', 'flowchart'] as ExplanationTab[]).map(tab => (\n                               <button key={tab} onClick={() => setActiveTab(tab)} disabled={!explanation}\n                                className={\\`px-4 py-2 text-sm font-medium capitalize transition-colors \\${activeTab === tab ? 'bg-background text-primary font-semibold' : 'text-text-secondary hover:bg-gray-100 dark:hover:bg-slate-700 disabled:text-gray-400 dark:disabled:text-slate-500'}\\`}>\n                                   {tab.replace(/([A-Z])/g, ' \\$1')}\n                               </button>\n                           ))}\n                        </div>\n                        <div className=\"p-4 flex-grow overflow-y-auto\">\n                            {isLoading && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                            {error && <p className=\"text-red-500\">{error}</p>}\n                            {explanation && !isLoading && renderTabContent()}\n                            {!isLoading && !explanation && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">The analysis will appear here.</div>}\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiCodeMigrator.tsx': `\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport { migrateCodeStream } from '../../services/index.ts';\nimport { ArrowPathIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nconst languages = ['SASS', 'CSS', 'JavaScript', 'TypeScript', 'Python', 'Go', 'React', 'Vue', 'Angular', 'Tailwind CSS'];\n\nconst exampleCode = \\`// SASS\n\\$primary-color: #333;\n\nbody {\n  color: \\$primary-color;\n  font-family: sans-serif;\n}\\`;\n\nexport const AiCodeMigrator: React.FC<{ inputCode?: string, fromLang?: string, toLang?: string }> = ({ inputCode: initialCode, fromLang: initialFrom, toLang: initialTo }) => {\n    const [inputCode, setInputCode] = useState<string>(initialCode || exampleCode);\n    const [outputCode, setOutputCode] = useState<string>('');\n    const [fromLang, setFromLang] = useState(initialFrom || 'SASS');\n    const [toLang, setToLang] = useState(initialTo || 'CSS');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleMigrate = useCallback(async (code: string, from: string, to: string) => {\n        if (!code.trim()) {\n            setError('Please enter some code to migrate.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setOutputCode('');\n        try {\n            const stream = migrateCodeStream(code, from, to);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setOutputCode(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to migrate code: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        if (initialCode && initialFrom && initialTo) {\n            setInputCode(initialCode);\n            setFromLang(initialFrom);\n            setToLang(initialTo);\n            handleMigrate(initialCode, initialFrom, initialTo);\n        }\n    }, [initialCode, initialFrom, initialTo, handleMigrate]);\n\n    const LanguageSelector: React.FC<{ value: string, onChange: (val: string) => void }> = ({ value, onChange }) => (\n        <select value={value} onChange={e => onChange(e.target.value)} className=\"w-full px-3 py-2 rounded-md bg-surface border border-border\">\n            {languages.map(lang => <option key={lang} value={lang}>{lang}</option>)}\n        </select>\n    );\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><ArrowPathIcon /><span className=\"ml-3\">AI Code Migrator</span></h1>\n                <p className=\"text-text-secondary mt-1\">Translate code between languages, frameworks, and syntax styles.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col min-h-0\">\n                <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6 flex-grow min-h-0\">\n                    <div className=\"flex flex-col h-full\">\n                        <div className=\"mb-2\">\n                            <label className=\"text-sm font-medium text-text-secondary\">From:</label>\n                            <LanguageSelector value={fromLang} onChange={setFromLang} />\n                        </div>\n                        <textarea\n                            value={inputCode}\n                            onChange={(e) => setInputCode(e.target.value)}\n                            placeholder=\"Paste your source code here...\"\n                            className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\"\n                        />\n                    </div>\n                    <div className=\"flex flex-col h-full\">\n                        <div className=\"mb-2\">\n                            <label className=\"text-sm font-medium text-text-secondary\">To:</label>\n                            <LanguageSelector value={toLang} onChange={setToLang} />\n                        </div>\n                        <div className=\"flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto\">\n                           {isLoading && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                            {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                            {outputCode && !isLoading && <MarkdownRenderer content={outputCode} />}\n                            {!isLoading && !outputCode && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">Migrated code will appear here.</div>}\n                        </div>\n                    </div>\n                </div>\n                 <button\n                    onClick={() => handleMigrate(inputCode, fromLang, toLang)}\n                    disabled={isLoading}\n                    className=\"btn-primary mt-4 w-full max-w-sm mx-auto flex items-center justify-center px-6 py-3\"\n                >\n                    {isLoading ? <LoadingSpinner /> : 'Migrate Code'}\n                </button>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiCodingChallenge.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { generateCodingChallengeStream } from '../../services/index.ts';\nimport { BeakerIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nexport const AiCodingChallenge: React.FC = () => {\n    const [challenge, setChallenge] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleGenerate = useCallback(async () => {\n        setIsLoading(true);\n        setError('');\n        setChallenge('');\n        try {\n            const stream = generateCodingChallengeStream(null);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setChallenge(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate challenge: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        // Generate a challenge on initial load for a better user experience\n        handleGenerate();\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, []);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex justify-between items-center\">\n                <div>\n                    <h1 className=\"text-3xl font-bold flex items-center\">\n                        <BeakerIcon />\n                        <span className=\"ml-3\">AI Coding Challenge Generator</span>\n                    </h1>\n                    <p className=\"text-text-secondary mt-1\">Generate a unique coding problem to test your skills.</p>\n                </div>\n                <button\n                    onClick={handleGenerate}\n                    disabled={isLoading}\n                    className=\"btn-primary flex items-center justify-center px-6 py-3\"\n                >\n                    {isLoading ? <LoadingSpinner /> : 'Generate New Challenge'}\n                </button>\n            </header>\n            <div className=\"flex-grow p-4 bg-surface border border-border rounded-md overflow-y-auto\">\n                {isLoading && (\n                     <div className=\"flex items-center justify-center h-full\">\n                        <LoadingSpinner />\n                     </div>\n                )}\n                {error && <p className=\"text-red-500\">{error}</p>}\n                {challenge && !isLoading && (\n                    <MarkdownRenderer content={challenge} />\n                )}\n                 {!isLoading && !challenge && !error && (\n                    <div className=\"text-text-secondary h-full flex items-center justify-center\">\n                        Click \"Generate New Challenge\" to start.\n                    </div>\n                )}\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiCommandCenter.tsx': `import React, { useState, useCallback } from 'react';\nimport { Type, FunctionDeclaration } from \"@google/genai\";\nimport { logError } from '../../services/telemetryService.ts';\nimport { getInferenceFunction, CommandResponse } from '../../services/aiService.ts';\nimport { FEATURE_TAXONOMY } from '../../services/taxonomyService.ts';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\nimport { CommandLineIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { ALL_FEATURE_IDS } from '../../constants.tsx';\nimport { executeWorkspaceAction, ACTION_REGISTRY } from '../../services/workspaceConnectorService.ts';\n\nconst baseFunctionDeclarations: FunctionDeclaration[] = [\n    {\n        name: 'navigateTo',\n        description: 'Navigates to a specific feature page.',\n        parameters: {\n            type: Type.OBJECT,\n            properties: {\n                featureId: { \n                    type: Type.STRING, \n                    description: 'The ID of the feature to navigate to.',\n                    enum: ALL_FEATURE_IDS\n                },\n            },\n            required: ['featureId'],\n        },\n    },\n    {\n        name: 'runFeatureWithInput',\n        description: 'Navigates to a feature and passes initial data to it.',\n        parameters: {\n            type: Type.OBJECT,\n            properties: {\n                 featureId: { \n                    type: Type.STRING, \n                    description: 'The ID of the feature to run.',\n                    enum: ALL_FEATURE_IDS\n                },\n                props: {\n                    type: Type.OBJECT,\n                    description: 'An object containing the initial properties for the feature, based on its required inputs.',\n                    properties: {\n                        initialCode: { type: Type.STRING },\n                        initialPrompt: { type: Type.STRING },\n                        beforeCode: { type: Type.STRING },\n                        afterCode: { type: Type.STRING },\n                        logInput: { type: Type.STRING },\n                        diff: { type: Type.STRING },\n                        codeInput: { type: Type.STRING },\n                        jsonInput: { type: Type.STRING },\n                    }\n                }\n            },\n            required: ['featureId', 'props']\n        }\n    }\n];\n\n// Dynamically add the workspace action\nconst functionDeclarations: FunctionDeclaration[] = [\n    ...baseFunctionDeclarations,\n    {\n        name: 'runWorkspaceAction',\n        description: 'Executes a defined action on a connected workspace service like Jira, Slack, or GitHub.',\n        parameters: {\n            type: Type.OBJECT,\n            properties: {\n                 actionId: {\n                    type: Type.STRING,\n                    description: 'The unique identifier for the action to execute.',\n                    enum: [ ...ACTION_REGISTRY.keys() ]\n                },\n                params: {\n                    type: Type.OBJECT,\n                    description: 'An object containing the parameters for the action, matching its required inputs.'\n                }\n            },\n            required: ['actionId', 'params']\n        }\n    }\n]\n\nconst knowledgeBase = FEATURE_TAXONOMY.map(f => \\`- \\${f.name} (\\${f.id}): \\${f.description} Inputs: \\${f.inputs}\\`).join('\\\\n');\n\nconst ExamplePromptButton: React.FC<{ text: string, onClick: (text: string) => void }> = ({ text, onClick }) => (\n    <button\n        onClick={() => onClick(text)}\n        className=\"px-3 py-1.5 bg-surface border border-border rounded-full text-xs hover:bg-gray-100 dark:hover:bg-slate-700 transition-colors\"\n    >\n        {text}\n    </button>\n)\n\nexport const AiCommandCenter: React.FC = () => {\n    const { dispatch } = useGlobalState();\n    const [prompt, setPrompt] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [lastResponse, setLastResponse] = useState('');\n\n    const handleCommand = useCallback(async () => {\n        if (!prompt.trim()) return;\n\n        setIsLoading(true);\n        setLastResponse('');\n\n        try {\n            const response: CommandResponse = await getInferenceFunction(prompt, functionDeclarations, knowledgeBase);\n            \n            if (response.functionCalls && response.functionCalls.length > 0) {\n                const call = response.functionCalls[0];\n                const { name, args } = call;\n\n                setLastResponse(\\`Understood! Executing command: \\${name}\\`);\n\n                switch (name) {\n                    case 'navigateTo':\n                        dispatch({ type: 'SET_VIEW', payload: { view: args.featureId }});\n                        break;\n                    case 'runFeatureWithInput':\n                         dispatch({ type: 'SET_VIEW', payload: { view: args.featureId, props: args.props } });\n                        break;\n                    case 'runWorkspaceAction':\n                        try {\n                            const result = await executeWorkspaceAction(args.actionId, args.params);\n                            setLastResponse(\\`Action '\\${args.actionId}' executed successfully.\\\\n\\\\nResult: \\\\\\`\\\\\\`\\\\\\`json\\\\n\\${JSON.stringify(result, null, 2)}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`);\n                        } catch (e) {\n                            setLastResponse(\\`Action failed: \\${e instanceof Error ? e.message : 'Unknown error'}\\`);\n                        }\n                        break;\n                    default:\n                        setLastResponse(\\`Unknown command: \\${name}\\`);\n                }\n                 setPrompt('');\n            } else {\n                 setLastResponse(response.text);\n            }\n\n        } catch (err) {\n            logError(err as Error, { prompt });\n            setLastResponse(err instanceof Error ? err.message : 'An unknown error occurred.');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [prompt, dispatch]);\n\n    const handleKeyDown = (e: React.KeyboardEvent) => {\n        if (e.key === 'Enter' && !e.shiftKey) {\n            e.preventDefault();\n            handleCommand();\n        }\n    };\n    \n    const handleExampleClick = (text: string) => {\n        setPrompt(text);\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 text-center\">\n                <h1 className=\"text-4xl font-extrabold tracking-tight flex items-center justify-center\">\n                    <CommandLineIcon />\n                    <span className=\"ml-3\">AI Command Center</span>\n                </h1>\n                <p className=\"mt-2 text-lg text-text-secondary\">What would you like to do?</p>\n            </header>\n            \n            <div className=\"flex-grow flex flex-col justify-end max-w-3xl w-full mx-auto\">\n                {lastResponse && (\n                    <div className=\"mb-4 p-4 bg-surface rounded-lg text-text-primary border border-border\">\n                        <p><strong>AI:</strong> {lastResponse}</p>\n                    </div>\n                )}\n                 <div className=\"relative\">\n                    <textarea\n                        value={prompt}\n                        onChange={e => setPrompt(e.target.value)}\n                        onKeyDown={handleKeyDown}\n                        disabled={isLoading}\n                        placeholder='Try \"explain this code: const a = 1;\" or \"open the theme designer\"'\n                        className=\"w-full p-4 pr-28 rounded-lg bg-surface border border-border focus:ring-2 focus:ring-primary focus:outline-none resize-none shadow-sm\"\n                        rows={2}\n                    />\n                    <button\n                        onClick={handleCommand}\n                        disabled={isLoading}\n                        className=\"btn-primary absolute right-3 top-1/2 -translate-y-1/2 px-4 py-2\"\n                    >\n                       {isLoading ? <LoadingSpinner/> : 'Send'}\n                    </button>\n                </div>\n                 <div className=\"flex flex-wrap items-center justify-center gap-2 mt-4\">\n                    <ExamplePromptButton text=\"Open Theme Designer\" onClick={handleExampleClick} />\n                    <ExamplePromptButton text=\"Generate a commit for a bug fix\" onClick={handleExampleClick} />\n                    <ExamplePromptButton text=\"Create a regex for email validation\" onClick={handleExampleClick} />\n                </div>\n                 <p className=\"text-xs text-text-secondary text-center mt-2\">Press Enter to send, Shift+Enter for new line.</p>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiCommitGenerator.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { generateCommitMessageStream } from '../../services/index.ts';\nimport { downloadFile } from '../../services/fileUtils.ts';\nimport { GitBranchIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\nconst exampleDiff = \\`diff --git a/src/components/Button.tsx b/src/components/Button.tsx\nindex 1b2c3d4..5e6f7g8 100644\n--- a/src/components/Button.tsx\n+++ b/src/components/Button.tsx\n@@ -1,7 +1,7 @@\n import React from 'react';\n\n interface ButtonProps {\n-  text: string;\n+  label: string;\n   onClick: () => void;\n }\n\\`;\n\nexport const AiCommitGenerator: React.FC<{ diff?: string }> = ({ diff: initialDiff }) => {\n    const [diff, setDiff] = useState<string>(initialDiff || exampleDiff);\n    const [message, setMessage] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleGenerate = useCallback(async (diffToAnalyze: string) => {\n        if (!diffToAnalyze.trim()) {\n            setError('Please paste a diff to generate a message.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setMessage('');\n        try {\n            const stream = generateCommitMessageStream(diffToAnalyze);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setMessage(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate message: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        if (initialDiff) {\n            setDiff(initialDiff);\n            handleGenerate(initialDiff);\n        }\n    }, [initialDiff, handleGenerate]);\n    \n    const handleCopy = () => {\n        navigator.clipboard.writeText(message);\n    };\n    \n    const handleDownload = () => {\n        downloadFile(message, 'commit_message.txt', 'text/plain');\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <GitBranchIcon />\n                    <span className=\"ml-3\">AI Commit Message Generator</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Paste your diff and let Gemini craft the perfect commit message.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"diff-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Git Diff</label>\n                    <textarea\n                        id=\"diff-input\"\n                        value={diff}\n                        onChange={(e) => setDiff(e.target.value)}\n                        placeholder=\"Paste your git diff here...\"\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm text-text-primary focus:ring-2 focus:ring-primary focus:outline-none\"\n                    />\n                </div>\n                <div className=\"flex-shrink-0\">\n                    <button\n                        onClick={() => handleGenerate(diff)}\n                        disabled={isLoading}\n                        className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Generate Commit Message'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <div className=\"flex justify-between items-center mb-2\">\n                        <label className=\"text-sm font-medium text-text-secondary\">Generated Message</label>\n                        {message && !isLoading && (\n                            <div className=\"flex items-center gap-2\">\n                                <button onClick={handleCopy} className=\"px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">Copy</button>\n                                <button onClick={handleDownload} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">\n                                    <ArrowDownTrayIcon className=\"w-4 h-4\" /> Download\n                                </button>\n                            </div>\n                        )}\n                    </div>\n                    <div className=\"relative flex-grow p-4 bg-surface border border-border rounded-md overflow-y-auto\">\n                        {isLoading && (\n                             <div className=\"flex items-center justify-center h-full\">\n                                <LoadingSpinner />\n                             </div>\n                        )}\n                        {error && <p className=\"text-red-500\">{error}</p>}\n                        {message && !isLoading && (\n                           <pre className=\"whitespace-pre-wrap font-sans text-text-primary\">{message}</pre>\n                        )}\n                         {!isLoading && !message && !error && (\n                            <div className=\"text-text-secondary h-full flex items-center justify-center\">\n                                The commit message will appear here.\n                            </div>\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiFeatureBuilder.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport type { GeneratedFile } from '../../types.ts';\nimport { generateFeature, generateFullStackFeature, generateUnitTestsStream, generateCommitMessageStream, generateDockerfile } from '../../services/aiService.ts';\nimport { saveFile, getAllFiles, clearAllFiles } from '../../services/dbService.ts';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { CpuChipIcon, DocumentTextIcon, BeakerIcon, GitBranchIcon, CloudIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\ntype SupplementalTab = 'TESTS' | 'COMMIT' | 'DEPLOYMENT' | 'CODE';\ntype OutputTab = GeneratedFile | SupplementalTab;\n\nexport const AiFeatureBuilder: React.FC = () => {\n    const [prompt, setPrompt] = useState<string>('A simple \"Hello World\" React component with a button that shows an alert.');\n    const [framework] = useState('React');\n    const [styling] = useState('Tailwind CSS');\n    const [includeBackend, setIncludeBackend] = useState(false);\n\n    const [generatedFiles, setGeneratedFiles] = useState<GeneratedFile[]>([]);\n    const [unitTests, setUnitTests] = useState<string>('');\n    const [commitMessage, setCommitMessage] = useState<string>('');\n    const [dockerfile, setDockerfile] = useState<string>('');\n\n    const [activeTab, setActiveTab] = useState<OutputTab>('CODE');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    \n    useEffect(() => {\n        const loadFiles = async () => {\n            const files = await getAllFiles();\n            setGeneratedFiles(files);\n            if (files.length > 0) setActiveTab(files[0]);\n        };\n        loadFiles();\n    }, []);\n\n    const handleGenerate = useCallback(async () => {\n        if (!prompt.trim()) { setError('Please enter a feature description.'); return; }\n        setIsLoading(true);\n        setError('');\n        await clearAllFiles();\n        setGeneratedFiles([]); setUnitTests(''); setCommitMessage(''); setDockerfile(''); setActiveTab('CODE');\n\n        try {\n            const resultFiles = includeBackend\n                ? await generateFullStackFeature(prompt, framework, styling)\n                : await generateFeature(prompt, framework, styling);\n            \n            for (const file of resultFiles) { await saveFile(file); }\n            setGeneratedFiles(resultFiles);\n\n            if (resultFiles.length > 0) {\n                const componentFile = resultFiles.find(f => f.filePath.endsWith('.tsx') || f.filePath.endsWith('.jsx'));\n                setActiveTab(componentFile || resultFiles[0]);\n\n                const testStream = generateUnitTestsStream(componentFile?.content || resultFiles[0].content);\n                const diffContext = resultFiles.map(f => \\`File: \\${f.filePath}\\\\n\\\\n\\${f.content}\\`).join('\\\\n---\\\\n');\n                const commitStream = generateCommitMessageStream(diffContext);\n                \n                let tests = ''; for await (const chunk of testStream) { tests += chunk; setUnitTests(tests); }\n                let commit = ''; for await (const chunk of commitStream) { commit += chunk; setCommitMessage(commit); }\n                \n                if (!includeBackend) {\n                    const dockerfileStream = generateDockerfile(framework);\n                    let docker = ''; for await (const chunk of dockerfileStream) { docker += chunk; setDockerfile(docker); }\n                }\n            }\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'Failed to generate feature.');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [prompt, framework, styling, includeBackend]);\n    \n    const renderContent = () => {\n        if (typeof activeTab === 'string') {\n            switch (activeTab) {\n                case 'TESTS': return <MarkdownRenderer content={unitTests} />;\n                case 'COMMIT': return <pre className=\"w-full h-full p-4 whitespace-pre-wrap font-sans text-sm\">{commitMessage}</pre>;\n                case 'DEPLOYMENT': return <MarkdownRenderer content={dockerfile} />;\n                default: return <div className=\"p-4\">Select a file</div>;\n            }\n        }\n        return <MarkdownRenderer content={'\\`\\`\\`tsx\\\\n' + activeTab.content + '\\\\n\\`\\`\\`'} />;\n    }\n\n    return (\n        <div className=\"h-full flex flex-col text-text-primary bg-surface\">\n            <header className=\"p-4 border-b border-border flex-shrink-0\">\n                <h1 className=\"text-xl font-bold flex items-center\"><CpuChipIcon /><span className=\"ml-3\">AI Feature Builder</span></h1>\n            </header>\n            <div className=\"flex-grow flex min-h-0\">\n                <main className=\"flex-1 flex flex-col min-w-0\">\n                    <div className=\"flex-grow flex flex-col bg-background\">\n                         <div className=\"border-b border-border flex items-center bg-surface overflow-x-auto\">\n                            {generatedFiles.map(file => (\n                                <button key={file.filePath} onClick={() => setActiveTab(file)} className={\\`flex-shrink-0 flex items-center gap-2 px-4 py-2 text-sm \\${activeTab === file ? 'bg-background border-b-2 border-primary text-text-primary' : 'text-text-secondary hover:bg-gray-50'}\\`}><DocumentTextIcon /> {file.filePath}</button>\n                            ))}\n                            {unitTests && <button onClick={() => setActiveTab('TESTS')} className={\\`flex-shrink-0 flex items-center gap-2 px-4 py-2 text-sm \\${activeTab === 'TESTS' ? 'bg-background border-b-2 border-primary text-text-primary' : 'text-text-secondary hover:bg-gray-50'}\\`}><BeakerIcon /> Tests</button>}\n                            {commitMessage && <button onClick={() => setActiveTab('COMMIT')} className={\\`flex-shrink-0 flex items-center gap-2 px-4 py-2 text-sm \\${activeTab === 'COMMIT' ? 'bg-background border-b-2 border-primary text-text-primary' : 'text-text-secondary hover:bg-gray-50'}\\`}><GitBranchIcon /> Commit</button>}\n                            {dockerfile && !includeBackend && <button onClick={() => setActiveTab('DEPLOYMENT')} className={\\`flex-shrink-0 flex items-center gap-2 px-4 py-2 text-sm \\${activeTab === 'DEPLOYMENT' ? 'bg-background border-b-2 border-primary text-text-primary' : 'text-text-secondary hover:bg-gray-50'}\\`}><CloudIcon /> Dockerfile</button>}\n                        </div>\n                        <div className=\"flex-grow p-2 overflow-auto\">\n                            {isLoading && !generatedFiles.length ? <div className=\"flex justify-center items-center h-full\"><LoadingSpinner/></div> : renderContent()}\n                        </div>\n                    </div>\n                    \n                    <div className=\"flex-shrink-0 p-4 border-t border-border bg-surface\">\n                         <div className=\"flex items-center gap-2 mb-2\">\n                            <label className=\"flex items-center gap-2 text-sm\"><input type=\"checkbox\" checked={includeBackend} onChange={e => setIncludeBackend(e.target.checked)} /> Include Backend (Cloud Function + Firestore)</label>\n                        </div>\n                        <textarea value={prompt} onChange={(e) => setPrompt(e.target.value)} placeholder=\"e.g., A user profile card with an avatar, name, and bio.\" className=\"w-full p-2 bg-background border border-border rounded-md resize-none text-sm h-20\"/>\n                         <div className=\"flex gap-2 mt-2\">\n                             <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary flex-grow flex items-center justify-center gap-2 px-4 py-2\">\n                                {isLoading ? <><LoadingSpinner /> Generating...</> : 'Generate Feature'}\n                            </button>\n                         </div>\n                         {error && <p className=\"text-red-600 text-xs mt-2 text-center\">{error}</p>}\n                    </div>\n                </main>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/AiImageGenerator.tsx': `import React, { useState, useCallback, useRef } from 'react';\nimport { generateImage, generateImageFromImageAndText } from '../../services/aiService.ts';\nimport { fileToBase64, blobToDataURL } from '../../services/fileUtils.ts';\nimport { ImageGeneratorIcon, SparklesIcon, ArrowDownTrayIcon, XMarkIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\nconst surprisePrompts = [\n    'A majestic lion wearing a crown, painted in the style of Van Gogh.',\n    'A futuristic cityscape on another planet with two moons in the sky.',\n    'A cozy, magical library inside a giant tree.',\n    'A surreal image of a ship sailing on a sea of clouds.',\n    'An astronaut riding a space-themed bicycle on the moon.',\n];\n\ninterface UploadedImage {\n    base64: string;\n    dataUrl: string;\n    mimeType: string;\n}\n\nexport const AiImageGenerator: React.FC = () => {\n    const [prompt, setPrompt] = useState<string>('A photorealistic image of a futuristic city at sunset, with flying cars.');\n    const [uploadedImage, setUploadedImage] = useState<UploadedImage | null>(null);\n    const [generatedImageUrl, setGeneratedImageUrl] = useState<string | null>(null);\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    const fileInputRef = useRef<HTMLInputElement>(null);\n\n    const handleGenerate = useCallback(async () => {\n        if (!prompt.trim()) {\n            setError('Please enter a prompt to generate an image.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setGeneratedImageUrl(null);\n        try {\n            let resultUrl: string;\n            if (uploadedImage) {\n                resultUrl = await generateImageFromImageAndText(prompt, uploadedImage.base64, uploadedImage.mimeType);\n            } else {\n                resultUrl = await generateImage(prompt);\n            }\n            setGeneratedImageUrl(resultUrl);\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate image: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [prompt, uploadedImage]);\n\n    const handleSurpriseMe = () => {\n        const randomPrompt = surprisePrompts[Math.floor(Math.random() * surprisePrompts.length)];\n        setPrompt(randomPrompt);\n    };\n\n    const processImageBlob = async (blob: Blob) => {\n        try {\n            const [dataUrl, base64] = await Promise.all([\n                blobToDataURL(blob),\n                fileToBase64(blob as File)\n            ]);\n            setUploadedImage({ dataUrl, base64, mimeType: blob.type });\n        } catch (e) {\n            setError('Could not process the image.');\n        }\n    };\n\n    const handlePaste = useCallback(async (event: React.ClipboardEvent) => {\n        const items = event.clipboardData.items;\n        for (const item of items) {\n            if (item.type.indexOf('image') !== -1) {\n                const blob = item.getAsFile();\n                if (blob) {\n                    await processImageBlob(blob);\n                    return;\n                }\n            }\n        }\n    }, []);\n\n    const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {\n        const file = event.target.files?.[0];\n        if (file) {\n            await processImageBlob(file);\n        }\n    };\n    \n    const handleDownload = () => {\n        if (!generatedImageUrl) return;\n        const link = document.createElement('a');\n        link.href = generatedImageUrl;\n        link.download = \\`\\${prompt.slice(0, 30).replace(/\\\\s/g, '_')}.png\\`;\n        document.body.appendChild(link);\n        link.click();\n        document.body.removeChild(link);\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <ImageGeneratorIcon />\n                    <span className=\"ml-3\">AI Image Generator</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Generate images from text, or provide an image for inspiration.</p>\n            </header>\n            \n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                {/* Left Column: Inputs */}\n                <div className=\"flex flex-col gap-4\">\n                    <div>\n                        <label htmlFor=\"prompt-input\" className=\"text-sm font-medium text-text-secondary\">Your Prompt</label>\n                        <textarea\n                            id=\"prompt-input\"\n                            value={prompt}\n                            onChange={(e) => setPrompt(e.target.value)}\n                            placeholder=\"e.g., A cute cat wearing a wizard hat\"\n                            className=\"w-full p-3 mt-1 rounded-md bg-surface border border-border focus:ring-2 focus:ring-primary focus:outline-none resize-y\"\n                            rows={3}\n                        />\n                    </div>\n                    \n                    <div className=\"flex flex-col flex-grow min-h-[200px]\">\n                         <label className=\"text-sm font-medium text-text-secondary mb-1\">Inspiration Image (Optional)</label>\n                         <div onPaste={handlePaste} className=\"relative flex-grow flex flex-col items-center justify-center bg-surface p-4 rounded-lg border-2 border-dashed border-border focus:outline-none focus:border-primary\" tabIndex={0}>\n                            {uploadedImage ? (\n                                <>\n                                    <img src={uploadedImage.dataUrl} alt=\"Uploaded content\" className=\"max-w-full max-h-full object-contain rounded-md shadow-lg\" />\n                                    <button onClick={() => setUploadedImage(null)} className=\"absolute top-2 right-2 p-1 bg-black/30 text-white rounded-full hover:bg-black/50\"><XMarkIcon /></button>\n                                </>\n                            ) : (\n                                <div className=\"text-center text-text-secondary\">\n                                    <h2 className=\"text-lg font-bold text-text-primary\">Paste an image here</h2>\n                                    <p className=\"text-sm\">(Cmd/Ctrl + V)</p>\n                                    <p className=\"text-xs my-1\">or</p>\n                                    <button onClick={() => fileInputRef.current?.click()} className=\"text-sm font-semibold text-primary hover:underline\">Upload File</button>\n                                    <input type=\"file\" ref={fileInputRef} onChange={handleFileChange} accept=\"image/*\" className=\"hidden\"/>\n                                </div>\n                            )}\n                         </div>\n                    </div>\n                    \n                    <div className=\"flex gap-2\">\n                        <button\n                            onClick={handleGenerate}\n                            disabled={isLoading}\n                            className=\"btn-primary w-full flex items-center justify-center px-6 py-3\"\n                        >\n                            {isLoading ? <LoadingSpinner /> : 'Generate Image'}\n                        </button>\n                        <button\n                            onClick={handleSurpriseMe}\n                            disabled={isLoading}\n                            className=\"px-4 py-3 bg-surface border border-border rounded-md hover:bg-gray-100 transition-colors\"\n                            title=\"Surprise Me!\"\n                        >\n                            <SparklesIcon />\n                        </button>\n                    </div>\n                </div>\n\n                {/* Right Column: Output */}\n                <div className=\"flex flex-col h-full\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Generated Image</label>\n                    <div className=\"flex-grow flex items-center justify-center bg-background border-2 border-dashed border-border rounded-lg p-4 relative overflow-auto\">\n                        {isLoading && <LoadingSpinner />}\n                        {error && <p className=\"text-red-500 text-center\">{error}</p>}\n                        {generatedImageUrl && !isLoading && (\n                            <>\n                                <img src={generatedImageUrl} alt={prompt || \"Generated by AI\"} className=\"max-w-full max-h-full object-contain rounded-md shadow-lg\" />\n                                <button \n                                  onClick={handleDownload}\n                                  className=\"absolute top-4 right-4 p-2 bg-black/30 text-white rounded-full hover:bg-black/50 backdrop-blur-sm\"\n                                  title=\"Download Image\"\n                                >\n                                    <ArrowDownTrayIcon />\n                                </button>\n                            </>\n                        )}\n                        {!isLoading && !generatedImageUrl && !error && (\n                            <div className=\"text-center text-text-secondary\">\n                                <p>Your generated image will appear here.</p>\n                            </div>\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiPersonalityForge.tsx': `import React, { useState, useEffect, useRef } from 'react';\nimport { SparklesIcon, PlusIcon, TrashIcon, ArrowDownTrayIcon, ArrowUpOnSquareIcon } from '../icons.tsx';\nimport { useAiPersonalities } from '../../hooks/useAiPersonalities.ts';\nimport { formatSystemPromptToString } from '../../utils/promptUtils.ts';\nimport { streamContent } from '../../services/index.ts';\nimport { downloadJson } from '../../services/fileUtils.ts';\nimport type { SystemPrompt } from '../../types.ts';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\n\nconst defaultNewPrompt: Omit<SystemPrompt, 'id' | 'name'> = {\n    persona: 'You are a helpful assistant.',\n    rules: [],\n    outputFormat: 'markdown',\n    exampleIO: [],\n};\n\nexport const AiPersonalityForge: React.FC = () => {\n    const [personalities, setPersonalities] = useAiPersonalities();\n    const [activeId, setActiveId] = useState<string | null>(null);\n    const { addNotification } = useNotification();\n    const fileInputRef = useRef<HTMLInputElement>(null);\n\n    // Testbed State\n    const [testbedInput, setTestbedInput] = useState('');\n    const [chatHistory, setChatHistory] = useState<{ role: 'user' | 'model'; content: string }[]>([]);\n    const [isStreaming, setIsStreaming] = useState(false);\n\n    const activePersonality = personalities.find(p => p.id === activeId);\n\n    useEffect(() => {\n        if (!activeId && personalities.length > 0) {\n            setActiveId(personalities[0].id);\n        }\n    }, [personalities, activeId]);\n    \n    const handleUpdate = (field: keyof SystemPrompt, value: any) => {\n        if (!activePersonality) return;\n        const updated = { ...activePersonality, [field]: value };\n        setPersonalities(personalities.map(p => (p.id === activeId ? updated : p)));\n    };\n\n    const handleAddNew = () => {\n        const newId = Date.now().toString();\n        const newPersonality: SystemPrompt = { ...defaultNewPrompt, id: newId, name: 'Untitled Personality' };\n        setPersonalities([...personalities, newPersonality]);\n        setActiveId(newId);\n    };\n\n    const handleDelete = (id: string) => {\n        if (window.confirm('Are you sure you want to delete this personality?')) {\n            setPersonalities(personalities.filter(p => p.id !== id));\n            if (activeId === id) {\n                setActiveId(personalities.length > 1 ? personalities[0].id : null);\n            }\n        }\n    };\n    \n    const handleTestbedSend = async () => {\n        if (!testbedInput.trim() || !activePersonality || isStreaming) return;\n        \n        const systemInstruction = formatSystemPromptToString(activePersonality);\n        const newHistory = [...chatHistory, { role: 'user' as const, content: testbedInput }];\n        setChatHistory(newHistory);\n        setTestbedInput('');\n        setIsStreaming(true);\n\n        try {\n            const stream = streamContent(testbedInput, systemInstruction, 0.7);\n            let fullResponse = '';\n            setChatHistory(prev => [...prev, { role: 'model', content: '' }]);\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setChatHistory(prev => {\n                    const last = prev[prev.length - 1];\n                    if (last.role === 'model') {\n                        return [...prev.slice(0, -1), { role: 'model', content: fullResponse }];\n                    }\n                    return prev;\n                });\n            }\n        } catch (e) {\n            const errorMsg = e instanceof Error ? e.message : 'An error occurred';\n            setChatHistory(prev => [...prev, { role: 'model', content: \\`**Error:** \\${errorMsg}\\` }]);\n        } finally {\n            setIsStreaming(false);\n        }\n    };\n    \n    const handleExport = () => {\n        if (!activePersonality) return;\n        downloadJson(activePersonality, \\`\\${activePersonality.name.replace(/\\\\s+/g, '_')}.json\\`);\n        addNotification('Personality exported!', 'success');\n    };\n\n    const handleImport = (e: React.ChangeEvent<HTMLInputElement>) => {\n        const file = e.target.files?.[0];\n        if (!file) return;\n        const reader = new FileReader();\n        reader.onload = (event) => {\n            try {\n                const imported = JSON.parse(event.target?.result as string) as SystemPrompt;\n                // Basic validation\n                if (imported.id && imported.name && imported.persona) {\n                    setPersonalities(prev => [...prev.filter(p => p.id !== imported.id), imported]);\n                    setActiveId(imported.id);\n                    addNotification('Personality imported!', 'success');\n                } else {\n                     addNotification('Invalid personality file.', 'error');\n                }\n            } catch {\n                 addNotification('Failed to parse JSON file.', 'error');\n            }\n        };\n        reader.readAsText(file);\n    };\n\n    return (\n        <div className=\"h-full flex text-text-primary\">\n            {/* Sidebar */}\n            <aside className=\"w-64 bg-surface border-r border-border flex flex-col\">\n                <div className=\"p-4 border-b border-border\">\n                    <h2 className=\"text-lg font-bold\">Personalities</h2>\n                </div>\n                <div className=\"flex-grow overflow-y-auto\">\n                    {personalities.map(p => (\n                        <div key={p.id} onClick={() => setActiveId(p.id)} className={\\`group flex justify-between items-center p-3 text-sm cursor-pointer \\${activeId === p.id ? 'bg-primary/10 text-primary' : 'hover:bg-gray-100 dark:hover:bg-slate-700'}\\`}>\n                            <span className=\"truncate\">{p.name}</span>\n                            <button onClick={(e) => { e.stopPropagation(); handleDelete(p.id)}} className=\"opacity-0 group-hover:opacity-100 text-text-secondary hover:text-red-500\"><TrashIcon /></button>\n                        </div>\n                    ))}\n                </div>\n                <div className=\"p-4 border-t border-border space-y-2\">\n                    <button onClick={handleAddNew} className=\"btn-primary w-full py-2 text-sm flex items-center justify-center gap-2\"><PlusIcon /> New</button>\n                    <div className=\"flex gap-2\">\n                         <button onClick={() => fileInputRef.current?.click()} className=\"flex-1 py-2 text-sm bg-gray-100 dark:bg-slate-700 rounded-md flex items-center justify-center gap-2\"><ArrowUpOnSquareIcon/> Import</button>\n                         <button onClick={handleExport} className=\"flex-1 py-2 text-sm bg-gray-100 dark:bg-slate-700 rounded-md flex items-center justify-center gap-2\"><ArrowDownTrayIcon/> Export</button>\n                         <input type=\"file\" ref={fileInputRef} onChange={handleImport} accept=\".json\" className=\"hidden\"/>\n                    </div>\n                </div>\n            </aside>\n            {/* Main Content */}\n            {activePersonality ? (\n                 <div className=\"flex-1 grid grid-cols-2 gap-px bg-border\">\n                    {/* Editor */}\n                    <div className=\"bg-background p-4 flex flex-col gap-4 overflow-y-auto\">\n                        <div><label className=\"font-bold\">Name</label><input type=\"text\" value={activePersonality.name} onChange={e => handleUpdate('name', e.target.value)} className=\"w-full mt-1 p-2 bg-surface border rounded\"/></div>\n                        <div><label className=\"font-bold\">Persona</label><textarea value={activePersonality.persona} onChange={e => handleUpdate('persona', e.target.value)} className=\"w-full mt-1 p-2 bg-surface border rounded h-24\"/></div>\n                        <div><label className=\"font-bold\">Rules (one per line)</label><textarea value={activePersonality.rules.join('\\\\n')} onChange={e => handleUpdate('rules', e.target.value.split('\\\\n'))} className=\"w-full mt-1 p-2 bg-surface border rounded h-32\"/></div>\n                        <div><label className=\"font-bold\">Output Format</label><select value={activePersonality.outputFormat} onChange={e => handleUpdate('outputFormat', e.target.value)} className=\"w-full mt-1 p-2 bg-surface border rounded\"><option>markdown</option><option>json</option><option>text</option></select></div>\n                        <div>\n                            <h3 className=\"font-bold mb-2\">Examples</h3>\n                            {activePersonality.exampleIO.map((ex, i) => (\n                                <div key={i} className=\"grid grid-cols-2 gap-2 mb-2 p-2 border rounded bg-surface\">\n                                    <textarea placeholder=\"User Input\" value={ex.input} onChange={e => handleUpdate('exampleIO', activePersonality.exampleIO.map((item, idx) => idx === i ? {...item, input: e.target.value} : item))} className=\"h-20 p-1 bg-background border rounded\"/>\n                                    <textarea placeholder=\"Model Output\" value={ex.output} onChange={e => handleUpdate('exampleIO', activePersonality.exampleIO.map((item, idx) => idx === i ? {...item, output: e.target.value} : item))} className=\"h-20 p-1 bg-background border rounded\"/>\n                                </div>\n                            ))}\n                            <button onClick={() => handleUpdate('exampleIO', [...activePersonality.exampleIO, {input: '', output: ''}])} className=\"text-sm text-primary\">+ Add Example</button>\n                        </div>\n                    </div>\n                    {/* Testbed */}\n                    <div className=\"bg-background p-4 flex flex-col\">\n                        <h2 className=\"text-lg font-bold mb-2 border-b pb-2\">Live Testbed</h2>\n                        <div className=\"flex-grow overflow-y-auto space-y-4 pr-2\">\n                           {chatHistory.map((msg, i) => (\n                               <div key={i} className={\\`p-3 rounded-lg \\${msg.role === 'user' ? 'bg-primary/10' : 'bg-surface'}\\`}>\n                                    <strong className=\"capitalize\">{msg.role}</strong>\n                                    <MarkdownRenderer content={msg.content} />\n                               </div>\n                           ))}\n                           {isStreaming && <div className=\"flex justify-center\"><LoadingSpinner/></div>}\n                        </div>\n                        <div className=\"flex gap-2 mt-4\">\n                            <input value={testbedInput} onChange={e => setTestbedInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleTestbedSend()} className=\"flex-grow p-2 bg-surface border rounded\" placeholder=\"Test your AI...\"/>\n                            <button onClick={handleTestbedSend} disabled={isStreaming} className=\"btn-primary px-4\">Send</button>\n                        </div>\n                    </div>\n                </div>\n            ) : (\n                <div className=\"flex-1 flex items-center justify-center text-text-secondary\">Select or create a personality to begin.</div>\n            )}\n        </div>\n    );\n};`,\n  'components/features/AiPullRequestAssistant.tsx': `\nimport React, { useState, useMemo, useCallback } from 'react';\nimport * as Diff from 'diff';\nimport { generatePrSummaryStructured, generateTechnicalSpecFromDiff, downloadFile } from '../../services/index.ts';\nimport { createDocument, insertText } from '../../services/workspaceService.ts';\nimport type { StructuredPrSummary } from '../../types.ts';\nimport { AiPullRequestAssistantIcon, DocumentIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\n\nconst exampleBefore = \\`function Greeter(props) {\n  return <h1>Hello, {props.name}!</h1>;\n}\\`;\nconst exampleAfter = \\`function Greeter({ name, enthusiasmLevel = 1 }) {\n  const punctuation = '!'.repeat(enthusiasmLevel);\n  return <h1>Hello, {name}{punctuation}</h1>;\n}\\`;\n\nexport const AiPullRequestAssistant: React.FC = () => {\n    const [beforeCode, setBeforeCode] = useState<string>(exampleBefore);\n    const [afterCode, setAfterCode] = useState<string>(exampleAfter);\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [isExporting, setIsExporting] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    const [summary, setSummary] = useState<StructuredPrSummary | null>(null);\n\n    const { addNotification } = useNotification();\n    const { state } = useGlobalState();\n    const { user } = state;\n\n    const diff = useMemo(() => Diff.createPatch('component.tsx', beforeCode, afterCode), [beforeCode, afterCode]);\n\n    const handleGenerateSummary = useCallback(async () => {\n        if (!beforeCode.trim() && !afterCode.trim()) {\n            setError('Please provide code to generate a summary.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setSummary(null);\n        \n        try {\n            const result: StructuredPrSummary = await generatePrSummaryStructured(diff);\n            setSummary(result);\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate summary: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [diff, beforeCode, afterCode]);\n\n    const handleExportToDocs = async () => {\n        if (!summary || !user) {\n            addNotification('Please generate a summary first and ensure you are signed in.', 'error');\n            return;\n        }\n        setIsExporting(true);\n        try {\n            const specContent = await generateTechnicalSpecFromDiff(diff, summary);\n            const doc = await createDocument(\\`Tech Spec: \\${summary.title}\\`);\n            await insertText(doc.documentId, specContent);\n            addNotification('Successfully exported to Google Docs!', 'success');\n            window.open(doc.webViewLink, '_blank');\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            addNotification(\\`Failed to export: \\${errorMessage}\\`, 'error');\n        } finally {\n            setIsExporting(false);\n        }\n    };\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <AiPullRequestAssistantIcon />\n                    <span className=\"ml-3\">AI Pull Request Assistant</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Generate a PR summary from code changes and export a full tech spec.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                {/* Left side: Inputs and Generator */}\n                <div className=\"flex flex-col gap-4 min-h-0\">\n                    <div className=\"flex flex-col flex-1 min-h-0\">\n                        <label htmlFor=\"before-code\" className=\"text-sm font-medium text-text-secondary mb-2\">Before</label>\n                        <textarea id=\"before-code\" value={beforeCode} onChange={e => setBeforeCode(e.target.value)} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\" />\n                    </div>\n                    <div className=\"flex flex-col flex-1 min-h-0\">\n                        <label htmlFor=\"after-code\" className=\"text-sm font-medium text-text-secondary mb-2\">After</label>\n                        <textarea id=\"after-code\" value={afterCode} onChange={e => setAfterCode(e.target.value)} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\" />\n                    </div>\n                    <button onClick={handleGenerateSummary} disabled={isLoading} className=\"btn-primary w-full flex items-center justify-center px-6 py-3\">\n                        {isLoading ? <LoadingSpinner /> : 'Generate Summary'}\n                    </button>\n                    {error && <p className=\"text-red-500 text-xs text-center\">{error}</p>}\n                </div>\n\n                {/* Right side: Summary and Export */}\n                <div className=\"flex flex-col gap-4 min-h-0\">\n                    <div className=\"flex flex-col bg-surface border border-border p-4 rounded-lg flex-grow min-h-0\">\n                        <h3 className=\"text-lg font-bold mb-2\">Generated Summary</h3>\n                        <div className=\"flex-grow overflow-y-auto pr-2 space-y-2\">\n                            {summary ? (\n                                <>\n                                    <input type=\"text\" readOnly value={summary.title} className=\"w-full font-bold p-2 bg-background rounded\"/>\n                                    <textarea readOnly value={summary.summary} className=\"w-full h-24 p-2 bg-background rounded resize-none\"/>\n                                    <div>\n                                        <h4 className=\"font-semibold\">Changes:</h4>\n                                        <ul className=\"list-disc list-inside text-sm\">\n                                            {summary.changes.map((c, i) => <li key={i}>{c}</li>)}\n                                        </ul>\n                                    </div>\n                                </>\n                            ) : (\n                                <div className=\"text-text-secondary h-full flex items-center justify-center\">\n                                    {isLoading ? <LoadingSpinner /> : 'PR summary will appear here.'}\n                                </div>\n                            )}\n                        </div>\n                         {summary && user && (\n                            <div className=\"mt-4 pt-4 border-t border-border\">\n                                <button onClick={handleExportToDocs} disabled={isExporting} className=\"w-full btn-primary bg-blue-600 flex items-center justify-center gap-2 py-2\">\n                                    {isExporting ? <LoadingSpinner /> : <><DocumentIcon /> Export to Google Docs</>}\n                                </button>\n                            </div>\n                         )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/AiStyleTransfer.tsx': `import React, { useState, useCallback } from 'react';\nimport { transferCodeStyleStream } from '../../services/index.ts';\nimport { SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleCode = \\`function my_func(x,y){return x+y;}\\`;\nconst exampleStyleGuide = \\`- Use camelCase for function names.\n- Add a space after commas in argument lists.\n- Use semicolons at the end of statements.\\`;\n\nexport const AiStyleTransfer: React.FC = () => {\n    const [inputCode, setInputCode] = useState<string>(exampleCode);\n    const [styleGuide, setStyleGuide] = useState<string>(exampleStyleGuide);\n    const [outputCode, setOutputCode] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleGenerate = useCallback(async () => {\n        if (!inputCode.trim() || !styleGuide.trim()) {\n            setError('Please provide both code and a style guide.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setOutputCode('');\n        try {\n            const stream = transferCodeStyleStream({ code: inputCode, styleGuide });\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setOutputCode(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to transfer style: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [inputCode, styleGuide]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <SparklesIcon />\n                    <span className=\"ml-3\">AI Code Style Transfer</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Rewrite code to match a specific style guide using AI.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"input-code\" className=\"text-sm font-medium text-text-secondary mb-2\">Original Code</label>\n                    <textarea\n                        id=\"input-code\"\n                        value={inputCode}\n                        onChange={(e) => setInputCode(e.target.value)}\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-y font-mono text-sm\"\n                    />\n                </div>\n                 <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"style-guide\" className=\"text-sm font-medium text-text-secondary mb-2\">Style Guide</label>\n                    <textarea\n                        id=\"style-guide\"\n                        value={styleGuide}\n                        onChange={(e) => setStyleGuide(e.target.value)}\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-y font-mono text-sm\"\n                    />\n                </div>\n                 <div className=\"flex-shrink-0\">\n                    <button\n                        onClick={handleGenerate}\n                        disabled={isLoading}\n                        className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Rewrite Code'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Rewritten Code</label>\n                    <div className=\"flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && !outputCode && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                        {outputCode && <MarkdownRenderer content={outputCode} />}\n                         {!isLoading && !outputCode && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">Rewritten code will appear here.</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AiUnitTestGenerator.tsx': `import React, { useState, useCallback } from 'react';\nimport { generateUnitTestsStream, downloadFile } from '../../services/index.ts';\nimport { BeakerIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleCode = \\`import React from 'react';\n\nexport const Greeting = ({ name }) => {\n  if (!name) {\n    return <div>Hello, Guest!</div>;\n  }\n  return <div>Hello, {name}!</div>;\n};\\`;\n\nexport const AiUnitTestGenerator: React.FC = () => {\n    const [code, setCode] = useState<string>(exampleCode);\n    const [tests, setTests] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleGenerate = useCallback(async () => {\n        if (!code.trim()) {\n            setError('Please enter some code to generate tests for.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setTests('');\n        try {\n            const stream = generateUnitTestsStream(code);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setTests(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate tests: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [code]);\n    \n    const cleanCodeForDownload = (markdown: string) => {\n        return markdown.replace(/^\\`\\`\\`(?:\\\\w+\\\\n)?/, '').replace(/\\`\\`\\`\\$/, '');\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <BeakerIcon />\n                    <span className=\"ml-3\">AI Unit Test Generator</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Provide a function or component and let AI write the tests.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"code-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Source Code</label>\n                    <textarea\n                        id=\"code-input\"\n                        value={code}\n                        onChange={(e) => setCode(e.target.value)}\n                        placeholder=\"Paste your source code here...\"\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm focus:ring-2 focus:ring-primary focus:outline-none\"\n                    />\n                </div>\n                <div className=\"flex-shrink-0\">\n                    <button\n                        onClick={handleGenerate}\n                        disabled={isLoading}\n                        className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Generate Unit Tests'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <div className=\"flex justify-between items-center mb-2\">\n                        <label className=\"text-sm font-medium text-text-secondary\">Generated Tests</label>\n                        {tests && !isLoading && (\n                            <div className=\"flex items-center gap-2\">\n                                <button onClick={() => navigator.clipboard.writeText(cleanCodeForDownload(tests))} className=\"px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">Copy Code</button>\n                                <button onClick={() => downloadFile(cleanCodeForDownload(tests), 'tests.tsx', 'text/typescript')} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">\n                                    <ArrowDownTrayIcon className=\"w-4 h-4\" /> Download\n                                </button>\n                            </div>\n                        )}\n                    </div>\n                    <div className=\"flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && !tests && (\n                            <div className=\"flex items-center justify-center h-full\">\n                                <LoadingSpinner />\n                            </div>\n                        )}\n                        {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                        {tests && <MarkdownRenderer content={tests} />}\n                        {!isLoading && !tests && !error && (\n                            <div className=\"text-text-secondary h-full flex items-center justify-center\">\n                                The generated tests will appear here.\n                            </div>\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/ApiMockGenerator.tsx': `import React, { useState, useEffect, useCallback } from 'react';\nimport { generateMockData } from '../../services/aiService.ts';\nimport { startMockServer, stopMockServer, setMockRoutes, isMockServerRunning } from '../../services/mocking/mockServer.ts';\nimport { saveMockCollection, getAllMockCollections } from '../../services/mocking/db.ts';\nimport { ServerStackIcon, SparklesIcon, PlusIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\ninterface MockCollection {\n    id: string;\n    schemaDescription: string;\n    data: any[];\n}\n\ninterface MockRoute {\n    id: number;\n    path: string;\n    method: 'GET' | 'POST';\n    collectionId: string;\n}\n\nconst exampleSchema = \"a user with an id, name, email, and a nested address object containing a city and country\";\n\nexport const ApiMockGenerator: React.FC = () => {\n    const [schema, setSchema] = useState(exampleSchema);\n    const [count, setCount] = useState(5);\n    const [collectionName, setCollectionName] = useState('users');\n    const [collections, setCollections] = useState<MockCollection[]>([]);\n    const [generatedData, setGeneratedData] = useState<any[] | null>(null);\n    const [isLoading, setIsLoading] = useState(false);\n    const [isServerLoading, setIsServerLoading] = useState(false);\n    const [error, setError] = useState('');\n    const [isServerRunning, setIsServerRunning] = useState(isMockServerRunning());\n    const [routes, setRoutes] = useState<MockRoute[]>([{ id: 1, path: '/api/users', method: 'GET', collectionId: 'users' }]);\n\n    useEffect(() => {\n        const loadCollections = async () => {\n            const storedCollections = await getAllMockCollections();\n            setCollections(storedCollections);\n        };\n        loadCollections();\n    }, []);\n\n    const handleGenerate = async () => {\n        if (!schema.trim() || !collectionName.trim()) {\n            setError('Schema description and collection name are required.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        try {\n            const data = await generateMockData(schema, count);\n            setGeneratedData(data);\n            const collectionId = collectionName.toLowerCase().replace(/\\\\s/g, '-');\n            await saveMockCollection({ id: collectionId, schemaDescription: schema, data });\n            setCollections(await getAllMockCollections());\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'Failed to generate data.');\n        } finally {\n            setIsLoading(false);\n        }\n    };\n\n    const handleServerToggle = async () => {\n        setIsServerLoading(true);\n        if (isServerRunning) {\n            await stopMockServer();\n            setIsServerRunning(false);\n        } else {\n            try {\n                await startMockServer();\n                setIsServerRunning(true);\n                updateRoutesOnServer();\n            } catch (err) {\n                setError(err instanceof Error ? err.message : 'Could not start server.');\n            }\n        }\n        setIsServerLoading(false);\n    };\n\n    const updateRoutesOnServer = useCallback(() => {\n        const mockRoutes = routes.map(route => {\n            const collection = collections.find(c => c.id === route.collectionId);\n            return {\n                path: route.path,\n                method: route.method,\n                response: {\n                    status: 200,\n                    body: collection ? collection.data : { message: \\`No data found for collection '\\${route.collectionId}'.\\` }\n                }\n            };\n        });\n        setMockRoutes(mockRoutes as any);\n    }, [routes, collections]);\n\n\n    useEffect(() => {\n        if (isServerRunning) {\n            updateRoutesOnServer();\n        }\n    }, [routes, collections, isServerRunning, updateRoutesOnServer]);\n\n    const handleRouteUpdate = (id: number, field: keyof MockRoute, value: string) => {\n        setRoutes(routes.map(r => r.id === id ? { ...r, [field]: value } : r));\n    };\n\n    const handleAddRoute = () => {\n        const newRoute: MockRoute = {\n            id: Date.now(),\n            path: '/api/new-route',\n            method: 'GET',\n            collectionId: collections.length > 0 ? collections[0].id : ''\n        };\n        setRoutes([...routes, newRoute]);\n    };\n    \n    const getServerStatusText = () => {\n        if (isServerLoading) return 'Starting...';\n        return isServerRunning ? 'Server Running' : 'Server Stopped';\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex justify-between items-start\">\n                <div>\n                    <h1 className=\"text-3xl font-bold flex items-center\"><ServerStackIcon /><span className=\"ml-3\">AI API Mock Server</span></h1>\n                    <p className=\"text-text-secondary mt-1\">Generate and serve mock API data locally using a service worker.</p>\n                </div>\n                <button onClick={handleServerToggle} disabled={isServerLoading} className={\\`px-4 py-2 rounded-md font-semibold flex items-center gap-2 \\${isServerRunning ? 'bg-green-100 text-green-700' : 'bg-gray-100'}\\`}>\n                    <span className={\\`w-3 h-3 rounded-full \\${isServerRunning ? 'bg-green-500' : 'bg-gray-400'} \\${isServerLoading ? 'animate-pulse' : ''}\\`}></span>\n                    {getServerStatusText()}\n                </button>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-3 gap-6 min-h-0\">\n                <div className=\"lg:col-span-1 flex flex-col gap-4 bg-surface p-4 border border-border rounded-lg\">\n                    <h3 className=\"text-lg font-bold\">1. Generate Data</h3>\n                    <div><label className=\"text-sm\">Describe the data schema</label><textarea value={schema} onChange={e => setSchema(e.target.value)} className=\"w-full mt-1 p-2 bg-background border border-border rounded\" rows={4}/></div>\n                    <div className=\"flex gap-2\">\n                        <div className=\"flex-grow\"><label className=\"text-sm\">Collection Name</label><input type=\"text\" value={collectionName} onChange={e => setCollectionName(e.target.value)} className=\"w-full mt-1 p-2 bg-background border border-border rounded\"/></div>\n                        <div><label className=\"text-sm\">Count</label><input type=\"number\" value={count} onChange={e => setCount(Number(e.target.value))} className=\"w-20 mt-1 p-2 bg-background border border-border rounded\"/></div>\n                    </div>\n                    <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary py-2 flex items-center justify-center gap-2\">{isLoading ? <LoadingSpinner/> : <><SparklesIcon/> Generate & Save</>}</button>\n                    {error && <p className=\"text-red-500 text-xs\">{error}</p>}\n                </div>\n\n                <div className=\"lg:col-span-2 flex flex-col gap-4 min-h-0\">\n                   <div className=\"bg-surface p-4 border border-border rounded-lg flex-grow flex flex-col min-h-0\">\n                        <h3 className=\"text-lg font-bold mb-2\">2. View Data & Configure Routes</h3>\n                        <div className=\"flex-grow grid grid-cols-2 gap-4 min-h-0\">\n                            <div className=\"overflow-y-auto\">\n                                <h4 className=\"font-semibold text-sm mb-1\">Saved Collections</h4>\n                                {collections.map(c => <div key={c.id} className=\"text-xs p-2 bg-background rounded border border-border mb-1\">{c.id} ({c.data.length} items)</div>)}\n                                <h4 className=\"font-semibold text-sm mb-1 mt-2\">Last Generated Data</h4>\n                                <pre className=\"text-xs p-2 bg-background rounded border border-border whitespace-pre-wrap\">{generatedData ? JSON.stringify(generatedData, null, 2) : 'No data generated yet.'}</pre>\n                            </div>\n                            <div className=\"overflow-y-auto\">\n                                <h4 className=\"font-semibold text-sm mb-1\">Mock Routes</h4>\n                                {routes.map((r) => (\n                                <div key={r.id} className=\"grid grid-cols-3 gap-1 items-center mb-1\">\n                                    <input type=\"text\" value={r.path} onChange={e => handleRouteUpdate(r.id, 'path', e.target.value)} className=\"col-span-2 p-1 text-xs bg-background border rounded\" />\n                                    <select value={r.collectionId} onChange={e => handleRouteUpdate(r.id, 'collectionId', e.target.value)} className=\"p-1 text-xs bg-background border rounded\">\n                                        <option value=\"\">Select Collection</option>\n                                        {collections.map(c => <option key={c.id} value={c.id}>{c.id}</option>)}\n                                    </select>\n                                </div>\n                                ))}\n                                <button onClick={handleAddRoute} className=\"text-xs mt-2 p-1 bg-gray-100 rounded hover:bg-gray-200\"><PlusIcon/></button>\n                            </div>\n                        </div>\n                   </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AsyncCallTreeViewer.tsx': `\n\nimport React, { useState, useMemo } from 'react';\nimport { ChartBarIcon } from '../icons.tsx';\n\ninterface CallNode {\n    name: string;\n    duration: number;\n    children?: CallNode[];\n}\n\nconst exampleJson = \\`{\n    \"name\": \"startApp\",\n    \"duration\": 500,\n    \"children\": [\n        {\n            \"name\": \"fetchUserData\",\n            \"duration\": 300,\n            \"children\": [\n                { \"name\": \"authenticate\", \"duration\": 100 },\n                { \"name\": \"fetchProfile\", \"duration\": 150 }\n            ]\n        },\n        {\n            \"name\": \"loadInitialAssets\",\n            \"duration\": 450,\n            \"children\": [\n                { \"name\": \"loadImage.png\", \"duration\": 200 },\n                { \"name\": \"loadScript.js\", \"duration\": 250 }\n            ]\n        }\n    ]\n}\\`;\n\n\nconst TreeNode: React.FC<{ node: CallNode, level: number, maxDuration: number }> = ({ node, level, maxDuration }) => {\n    const [isOpen, setIsOpen] = React.useState(true);\n    const hasChildren = node.children && node.children.length > 0;\n\n    return (\n        <div className=\"my-1\">\n            <div\n                className=\"flex items-center p-2 rounded-md hover:bg-gray-100\"\n                style={{ paddingLeft: \\`\\${level * 20 + 8}px\\` }}\n            >\n                {hasChildren && (\n                    <button onClick={() => setIsOpen(!isOpen)} className={\\`mr-2 text-text-secondary w-4 h-4 flex-shrink-0 transform transition-transform \\${isOpen ? 'rotate-90' : ''}\\`}>\n                       ▶\n                    </button>\n                )}\n                 {!hasChildren && <div className=\"w-6 mr-2 flex-shrink-0\" />}\n                 <div className=\"flex-grow flex items-center justify-between gap-4\">\n                    <span className=\"truncate\">{node.name}</span>\n                    <div className=\"flex items-center gap-2 flex-shrink-0\">\n                         <div className=\"w-24 h-4 bg-gray-200 rounded-full overflow-hidden\">\n                            <div className=\"h-4 bg-primary\" style={{ width: \\`\\${(node.duration / maxDuration) * 100}%\\` }}/>\n                         </div>\n                        <span className=\"text-primary w-16 text-right\">{node.duration.toFixed(0)}ms</span>\n                    </div>\n                </div>\n            </div>\n            {isOpen && hasChildren && (\n                <div>\n                    {node.children!.map((child, index) => (\n                        <TreeNode key={index} node={child} level={level + 1} maxDuration={maxDuration} />\n                    ))}\n                </div>\n            )}\n        </div>\n    );\n};\n\n\nexport const AsyncCallTreeViewer: React.FC = () => {\n    const [jsonInput, setJsonInput] = useState(exampleJson);\n    const [error, setError] = useState('');\n\n    const { treeData, maxDuration } = useMemo(() => {\n        try {\n            const data: CallNode = JSON.parse(jsonInput);\n             let max = 0;\n            const findMax = (node: CallNode) => {\n                if (node.duration > max) max = node.duration;\n                if (node.children) node.children.forEach(findMax);\n            };\n            findMax(data);\n            setError('');\n            return { treeData: data, maxDuration: max };\n        } catch (e) {\n            setError('Invalid JSON format.');\n            return { treeData: null, maxDuration: 0 };\n        }\n    }, [jsonInput]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl flex items-center\">\n                    <ChartBarIcon />\n                    <span className=\"ml-3\">Async Call Tree Viewer</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Paste a JSON structure to visualize an asynchronous function call tree.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col h-2/5 min-h-[200px]\">\n                    <label htmlFor=\"json-input\" className=\"text-sm font-medium text-text-secondary mb-2\">JSON Input</label>\n                    <textarea\n                        id=\"json-input\"\n                        value={jsonInput}\n                        onChange={e => setJsonInput(e.target.value)}\n                        className={\\`flex-grow p-4 bg-surface border \\${error ? 'border-red-500' : 'border-border'} rounded-md resize-y font-mono text-sm\\`}\n                        spellCheck=\"false\"\n                    />\n                    {error && <p className=\"text-red-500 text-xs mt-1\">{error}</p>}\n                </div>\n                <div className=\"flex flex-col flex-grow min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Visual Tree</label>\n                    <div className=\"flex-grow bg-surface p-4 rounded-lg text-sm overflow-y-auto border border-border\">\n                        {treeData ? <TreeNode node={treeData} level={0} maxDuration={maxDuration} /> : <div className=\"text-text-secondary\">{error || 'Enter valid JSON to see the tree.'}</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/AudioToCode.tsx': `import React, { useState, useRef, useCallback } from 'react';\nimport { transcribeAudioToCodeStream, blobToBase64 } from '../../services/index.ts';\nimport { MicrophoneIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nexport const AudioToCode: React.FC = () => {\n    const [isRecording, setIsRecording] = useState(false);\n    const [isLoading, setIsLoading] = useState(false);\n    const [code, setCode] = useState('');\n    const [error, setError] = useState('');\n    const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n    const audioChunksRef = useRef<Blob[]>([]);\n\n    const handleStartRecording = async () => {\n        setError('');\n        setCode('');\n        if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\n            setError('Audio recording is not supported by your browser.');\n            return;\n        }\n        try {\n            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n            mediaRecorderRef.current = new MediaRecorder(stream);\n            mediaRecorderRef.current.ondataavailable = event => {\n                audioChunksRef.current.push(event.data);\n            };\n            mediaRecorderRef.current.onstop = handleTranscribe;\n            mediaRecorderRef.current.start();\n            setIsRecording(true);\n        } catch (err) {\n            setError('Microphone access was denied. Please enable it in your browser settings.');\n        }\n    };\n\n    const handleStopRecording = () => {\n        if (mediaRecorderRef.current && isRecording) {\n            mediaRecorderRef.current.stop();\n            mediaRecorderRef.current.stream.getTracks().forEach(track => track.stop());\n            setIsRecording(false);\n            setIsLoading(true);\n        }\n    };\n\n    const handleTranscribe = useCallback(async () => {\n        if (audioChunksRef.current.length === 0) {\n            setIsLoading(false);\n            return;\n        }\n        const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/webm' });\n        audioChunksRef.current = [];\n        try {\n            const base64Audio = await blobToBase64(audioBlob);\n            const stream = transcribeAudioToCodeStream(base64Audio, 'audio/webm');\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setCode(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to transcribe audio: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 text-center\">\n                <h1 className=\"text-3xl font-bold flex items-center justify-center\">\n                    <MicrophoneIcon />\n                    <span className=\"ml-3\">AI Audio-to-Code</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Speak your programming ideas and watch them turn into code.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col items-center gap-6 min-h-0\">\n                <div className=\"flex flex-col items-center justify-center bg-surface p-6 rounded-lg w-full max-w-lg border border-border\">\n                     <button\n                        onClick={isRecording ? handleStopRecording : handleStartRecording}\n                        className={\\`w-24 h-24 rounded-full flex items-center justify-center text-white font-bold text-lg transition-all \\${isRecording ? 'bg-red-500 animate-pulse' : 'bg-primary'}\\`}\n                        disabled={isLoading}\n                    >\n                        {isLoading ? <LoadingSpinner/> : isRecording ? 'Stop' : 'Record'}\n                    </button>\n                    <p className=\"mt-4 text-text-secondary\">\n                        {isLoading ? 'Transcribing...' : isRecording ? 'Recording in progress...' : 'Click to start recording'}\n                    </p>\n                </div>\n                 <div className=\"flex flex-col h-full w-full max-w-3xl\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Generated Code</label>\n                    <div className=\"flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto min-h-[200px]\">\n                        {isLoading && !code && (\n                            <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>\n                        )}\n                        {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                        {code && <MarkdownRenderer content={code} />}\n                        {!isLoading && !code && !error && (\n                            <div className=\"text-text-secondary h-full flex items-center justify-center\">Code will appear here.</div>\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/BugReproducer.tsx': `import React, { useState, useCallback } from 'react';\nimport { generateBugReproductionTestStream } from '../../services/aiService.ts';\nimport { BugAntIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleStackTrace = \\`TypeError: Cannot read properties of undefined (reading 'name')\n    at UserProfile (UserProfile.jsx:5:21)\n    at renderWithHooks (react-dom.development.js:14985:18)\n    at mountIndeterminateComponent (react-dom.development.js:17811:13)\n    at beginWork (react-dom.development.js:19049:16)\\`;\n\nexport const BugReproducer: React.FC = () => {\n    const [stackTrace, setStackTrace] = useState(exampleStackTrace);\n    const [context, setContext] = useState('// The UserProfile component code:\\\\nconst UserProfile = ({ user }) => <div>{user.name}</div>;');\n    const [generatedTest, setGeneratedTest] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleGenerate = useCallback(async () => {\n        if (!stackTrace.trim()) {\n            setError('Please provide a stack trace.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setGeneratedTest('');\n        try {\n            const stream = generateBugReproductionTestStream(stackTrace, context);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setGeneratedTest(fullResponse);\n            }\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unknown error occurred.');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [stackTrace, context]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <BugAntIcon />\n                    <span className=\"ml-3\">Automated Bug Reproducer</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Paste a stack trace to automatically generate a failing unit test.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"flex flex-col gap-4\">\n                    <div className=\"flex flex-col flex-1 min-h-0\">\n                        <label htmlFor=\"stack-trace\" className=\"text-sm font-medium mb-2\">Stack Trace</label>\n                        <textarea id=\"stack-trace\" value={stackTrace} onChange={e => setStackTrace(e.target.value)} className=\"flex-grow p-2 bg-surface border rounded font-mono text-xs\"/>\n                    </div>\n                     <div className=\"flex flex-col flex-1 min-h-0\">\n                        <label htmlFor=\"context\" className=\"text-sm font-medium mb-2\">Relevant Code / Context (Optional)</label>\n                        <textarea id=\"context\" value={context} onChange={e => setContext(e.target.value)} className=\"flex-grow p-2 bg-surface border rounded font-mono text-xs\"/>\n                    </div>\n                    <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary w-full py-3\">{isLoading ? <LoadingSpinner/> : 'Generate Test'}</button>\n                </div>\n                <div className=\"flex flex-col\">\n                    <label className=\"text-sm font-medium mb-2\">Generated Test File</label>\n                    <div className=\"flex-grow p-1 bg-background border rounded overflow-auto\">\n                        {isLoading && !generatedTest && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"text-red-500 p-4\">{error}</p>}\n                        {generatedTest && <MarkdownRenderer content={generatedTest} />}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/ChangelogGenerator.tsx': `import React, { useState, useCallback } from 'react';\nimport { generateChangelogFromLogStream } from '../../services/aiService.ts';\nimport { GitBranchIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleLog = \\`commit 3a4b5c...\nAuthor: Dev One <dev.one@example.com>\nDate:   Mon Jul 15 11:30:00 2024 -0400\n\n    feat: add user login page\n\ncommit 1a2b3c...\nAuthor: Dev Two <dev.two@example.com>\nDate:   Mon Jul 15 10:00:00 2024 -0400\n\n    fix: correct typo in header\n\\`;\n\nexport const ChangelogGenerator: React.FC = () => {\n    const [log, setLog] = useState(exampleLog);\n    const [changelog, setChangelog] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleGenerate = useCallback(async () => {\n        if (!log.trim()) {\n            setError('Please paste your git log output.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setChangelog('');\n        try {\n            const stream = generateChangelogFromLogStream(log);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setChangelog(fullResponse);\n            }\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unknown error occurred.');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [log]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <GitBranchIcon />\n                    <span className=\"ml-3\">AI Changelog Generator</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Generate a markdown changelog from your raw git log.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"commit-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Raw Git Log</label>\n                    <textarea\n                        id=\"commit-input\"\n                        value={log}\n                        onChange={(e) => setLog(e.target.value)}\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\"\n                    />\n                </div>\n                <div className=\"flex-shrink-0\">\n                    <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center px-6 py-3\">\n                        {isLoading ? <LoadingSpinner /> : 'Generate Changelog'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Generated Changelog.md</label>\n                    <div className=\"relative flex-grow p-4 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && !changelog && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"text-red-500\">{error}</p>}\n                        {changelog && <MarkdownRenderer content={changelog} />}\n                        {!isLoading && changelog && <button onClick={() => navigator.clipboard.writeText(changelog)} className=\"absolute top-2 right-2 px-2 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">Copy</button>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CiCdPipelineGenerator.tsx': `import React, { useState } from 'react';\nimport { generateCiCdConfig } from '../../services/index.ts';\nimport { PaperAirplaneIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nconst platforms = ['GitHub Actions', 'GitLab CI', 'CircleCI', 'Jenkins'];\nconst exampleDescription = \"Install Node.js dependencies, run linting and tests, build the production app, and then deploy to Vercel.\";\n\nexport const CiCdPipelineGenerator: React.FC = () => {\n    const [platform, setPlatform] = useState(platforms[0]);\n    const [description, setDescription] = useState(exampleDescription);\n    const [config, setConfig] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleGenerate = async () => {\n        if (!description.trim()) {\n            setError('Please provide a description of the pipeline stages.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        try {\n            const result = await generateCiCdConfig(platform, description);\n            setConfig(result);\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'Failed to generate config.');\n        } finally {\n            setIsLoading(false);\n        }\n    };\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><PaperAirplaneIcon /><span className=\"ml-3\">AI CI/CD Pipeline Architect</span></h1>\n                <p className=\"text-text-secondary mt-1\">Describe your deployment process and get a modern configuration file.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                 <div className=\"flex flex-col flex-1 min-h-0\">\n                    <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4 mb-4\">\n                        <div><label className=\"block text-sm\">Platform</label><select value={platform} onChange={e => setPlatform(e.target.value)} className=\"w-full mt-1 p-2 bg-surface border rounded\"><option>GitHub Actions</option><option>GitLab CI</option><option>CircleCI</option></select></div>\n                        <div className=\"md:col-span-2\"><label className=\"block text-sm\">Describe Stages</label><input type=\"text\" value={description} onChange={e => setDescription(e.target.value)} className=\"w-full mt-1 p-2 bg-surface border rounded\"/></div>\n                    </div>\n                     <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center py-2\"><SparklesIcon /> {isLoading ? 'Generating...' : 'Generate Configuration'}</button>\n                </div>\n                 <div className=\"flex flex-col flex-grow min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Generated Configuration File</label>\n                    <div className=\"relative flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && !config && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                        {config && <MarkdownRenderer content={config} />}\n                         {!isLoading && !config && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">Generated config will appear here.</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CodeDiffGhost.tsx': `import React, { useState, useEffect, useRef } from 'react';\nimport { EyeIcon } from '../icons.tsx';\n\nconst initialOldCode = \\`function UserProfile({ user }) {\n  return (\n    <div className=\"profile\">\n      <h1>{user.name}</h1>\n      <p>{user.email}</p>\n    </div>\n  );\n}\\`;\n\nconst initialNewCode = \\`function UserProfile({ user }) {\n  const { name, email, avatar } = user;\n  return (\n    <div className=\"profile-card\">\n      <img src={avatar} alt={name} />\n      <h2>{name}</h2>\n      <a href={\\\\\\`mailto:\\\\\\${email}\\\\\\`}>{email}</a>\n    </div>\n  );\n}\\`;\n\nexport const CodeDiffGhost: React.FC = () => {\n    const [oldCode, setOldCode] = useState(initialOldCode);\n    const [newCode, setNewCode] = useState(initialNewCode);\n    const [typedCode, setTypedCode] = useState('');\n    const [isRunning, setIsRunning] = useState(false);\n    const intervalRef = useRef<number | null>(null);\n\n    const startAnimation = () => {\n        if (intervalRef.current) clearInterval(intervalRef.current);\n        setIsRunning(true);\n        setTypedCode('');\n        \n        intervalRef.current = window.setInterval(() => {\n            setTypedCode(prev => {\n                if (prev.length < newCode.length) {\n                    return newCode.substring(0, prev.length + 1);\n                }\n                if (intervalRef.current) clearInterval(intervalRef.current);\n                setIsRunning(false);\n                return newCode;\n            });\n        }, 15);\n    };\n\n    useEffect(() => {\n        return () => {\n            if (intervalRef.current) clearInterval(intervalRef.current);\n        };\n    }, []);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl flex items-center\">\n                    <EyeIcon />\n                    <span className=\"ml-3\">Code Diff Ghost</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Visualize code changes with a \"ghost typing\" effect.</p>\n            </header>\n            <div className=\"flex justify-center mb-4\">\n                <button\n                    onClick={startAnimation}\n                    disabled={isRunning}\n                    className=\"btn-primary px-6 py-2\"\n                >\n                    {isRunning ? 'Visualizing...' : 'Show Changes'}\n                </button>\n            </div>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 h-full overflow-hidden font-mono text-sm\">\n                <div className=\"flex flex-col h-full\">\n                    <label htmlFor=\"before-code\" className=\"text-sm font-medium text-text-secondary mb-2\">Before</label>\n                    <textarea\n                        id=\"before-code\"\n                        value={oldCode}\n                        onChange={e => setOldCode(e.target.value)}\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md text-red-600 whitespace-pre-wrap resize-none\"\n                        spellCheck=\"false\"\n                    />\n                </div>\n                 <div className=\"flex flex-col h-full\">\n                    <label htmlFor=\"after-code\" className=\"text-sm font-medium text-text-secondary mb-2\">After</label>\n                     <div className=\"relative flex-grow\">\n                        <textarea\n                            id=\"after-code\"\n                            value={newCode}\n                            onChange={e => setNewCode(e.target.value)}\n                            className=\"absolute inset-0 w-full h-full p-4 bg-surface border border-border rounded-md text-emerald-700 whitespace-pre-wrap resize-none z-0\"\n                            spellCheck=\"false\"\n                        />\n                        {(isRunning || typedCode) && (\n                            <pre className=\"absolute inset-0 w-full h-full p-4 bg-surface pointer-events-none text-emerald-700 whitespace-pre-wrap z-10\">\n                                {typedCode}{isRunning && <span className=\"animate-pulse\">|</span>}\n                            </pre>\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CodeFormatter.tsx': `import React, { useState, useCallback } from 'react';\nimport { formatCodeStream } from '../../services/index.ts';\nimport { CodeBracketSquareIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleCode = \\`const MyComponent = (props) => {\n  const {name, items}=props\n    if(!items || items.length === 0){\n  return <p>No items found for {name}</p>;\n    }\n  return <ul>{items.map(item=> <li key={item.id}>{item.name}</li>)}</ul>\n}\\`;\n\nexport const CodeFormatter: React.FC = () => {\n    const [inputCode, setInputCode] = useState<string>(exampleCode);\n    const [formattedCode, setFormattedCode] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleFormat = useCallback(async () => {\n        if (!inputCode.trim()) {\n            setError('Please enter some code to format.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setFormattedCode('');\n        try {\n            const stream = formatCodeStream(inputCode);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setFormattedCode(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to format code: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [inputCode]);\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <CodeBracketSquareIcon />\n                    <span className=\"ml-3\">AI Code Formatter</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Clean up your code with AI-powered formatting, like a smart Prettier.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col min-h-0\">\n                <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6 flex-grow min-h-0\">\n                    <div className=\"flex flex-col h-full\">\n                        <label htmlFor=\"code-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Input</label>\n                        <textarea\n                            id=\"code-input\"\n                            value={inputCode}\n                            onChange={(e) => setInputCode(e.target.value)}\n                            placeholder=\"Paste your unformatted code here...\"\n                            className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\"\n                        />\n                    </div>\n                    <div className=\"flex flex-col h-full\">\n                        <label className=\"text-sm font-medium text-text-secondary mb-2\">Output</label>\n                        <div className=\"flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto\">\n                           {isLoading && !formattedCode && (\n                                <div className=\"flex items-center justify-center h-full\">\n                                    <LoadingSpinner />\n                                </div>\n                            )}\n                            {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                            {formattedCode && <MarkdownRenderer content={formattedCode} />}\n                            {!isLoading && !formattedCode && !error && (\n                                <div className=\"text-text-secondary h-full flex items-center justify-center\">\n                                    Formatted code will appear here.\n                                </div>\n                            )}\n                        </div>\n                    </div>\n                </div>\n                 <button\n                    onClick={handleFormat}\n                    disabled={isLoading}\n                    className=\"btn-primary mt-4 w-full max-w-sm mx-auto flex items-center justify-center px-6 py-3\"\n                >\n                    {isLoading ? <LoadingSpinner /> : 'Format Code'}\n                </button>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CodeReviewBot.tsx': `import React, { useState, useCallback } from 'react';\nimport { reviewCodeStream } from '../../services/index.ts';\nimport { useAiPersonalities } from '../../hooks/useAiPersonalities.ts';\nimport { formatSystemPromptToString } from '../../utils/promptUtils.ts';\nimport { CpuChipIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleCode = \\`function UserList(users) {\n  if (users.length = 0) {\n    return \"no users\";\n  } else {\n    return (\n      users.map(u => {\n        return <li>{u.name}</li>\n      })\n    )\n  }\n}\\`;\n\nexport const CodeReviewBot: React.FC = () => {\n    const [code, setCode] = useState<string>(exampleCode);\n    const [review, setReview] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    const [personalities] = useAiPersonalities();\n    const [selectedPersonalityId, setSelectedPersonalityId] = useState<string>('default');\n\n    const handleGenerate = useCallback(async () => {\n        if (!code.trim()) {\n            setError('Please enter some code to review.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setReview('');\n\n        let systemInstruction: string | undefined = undefined;\n        if (selectedPersonalityId !== 'default') {\n            const personality = personalities.find(p => p.id === selectedPersonalityId);\n            if (personality) {\n                systemInstruction = formatSystemPromptToString(personality);\n            }\n        }\n\n        try {\n            const stream = reviewCodeStream(code, systemInstruction);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setReview(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to get review: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [code, selectedPersonalityId, personalities]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <CpuChipIcon />\n                    <span className=\"ml-3\">AI Code Review Bot</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Get an automated code review from Gemini.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"code-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Code to Review</label>\n                    <textarea\n                        id=\"code-input\"\n                        value={code}\n                        onChange={(e) => setCode(e.target.value)}\n                        placeholder=\"Paste your code here...\"\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\"\n                    />\n                </div>\n                 <div className=\"flex-shrink-0 flex items-center justify-center gap-4\">\n                     <div className=\"w-full max-w-xs\">\n                        <label htmlFor=\"personality-select\" className=\"text-sm font-medium text-text-secondary\">Reviewer Personality</label>\n                        <select\n                            id=\"personality-select\"\n                            value={selectedPersonalityId}\n                            onChange={e => setSelectedPersonalityId(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-surface border border-border rounded-md text-sm\"\n                        >\n                            <option value=\"default\">Default</option>\n                            {personalities.map(p => (\n                                <option key={p.id} value={p.id}>{p.name}</option>\n                            ))}\n                        </select>\n                     </div>\n                    <button\n                        onClick={handleGenerate}\n                        disabled={isLoading}\n                        className=\"btn-primary self-end h-[42px] w-full max-w-xs flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Request Review'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">AI Feedback</label>\n                    <div className=\"flex-grow p-4 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && !review && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"text-red-500\">{error}</p>}\n                        {review && <MarkdownRenderer content={review} />}\n                         {!isLoading && !review && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">Review will appear here.</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CodeSpellChecker.tsx': `import React, { useState, useMemo } from 'react';\nimport { BeakerIcon } from '../icons.tsx';\n\nconst commonTypos = [\n    'funtion', 'functoin', 'funciton', 'contructor', 'cosntructor',\n    'consle', 'conosle', 'cosnole', 'varable', 'varaible', 'vairable',\n    'docment', 'docuemnt', 'docmunet', 'componnet', 'componenet', 'compnent',\n    'retunr', 'retrun', 'asnyc', 'asycn', 'awai', 'awiat', 'promse',\n    'resolv', 'rejct', 'catach', 'thne', 'lenght', 'lengt', 'prperty',\n    'undefinded', 'nul', 'booleon', 'numbar', 'srtring', 'arrya', 'objcet',\n    'elemnt', 'attriubte', 'eveent', 'listner', 'handeler', 'clieck',\n    'submitt', 'resposne', 'requset', 'stauts', 'eror', 'sucess',\n    'implemnt', 'overide', 'extned', 'pbulic', 'prvate', 'procted',\n    'statci', 'abstact', 'interace', 'enmu', 'moduel', 'packge',\n    'importt', 'exprot', 'defualt', 'namspace', 'tyep', 'clsas',\n    'whiel', 'swich', 'cse', 'brek', 'contiune', 'thrwo', 'finnaly'\n];\n\nconst typoRegex = new RegExp(\\`\\\\\\\\b(\\${commonTypos.join('|')})\\\\\\\\b\\`, 'gi');\n\nconst HighlightedText: React.FC<{ text: string }> = React.memo(({ text }) => {\n    const parts = useMemo(() => {\n        return text.split(typoRegex).map((part, i) => {\n            if (typoRegex.test(part)) {\n                return <span key={i} className=\"underline decoration-red-500 decoration-wavy\" title={\\`Possible typo\\`}>{part}</span>;\n            }\n            return part;\n        });\n    }, [text]);\n\n    return <>{parts}</>;\n});\n\nexport const CodeSpellChecker: React.FC = () => {\n    const [code, setCode] = useState('funtion myFunction() {\\\\n  consle.log(\"Hello World\");\\\\n  const myVarable = docment.getElementById(\"root\");\\\\n  // This is a React componnet\\\\n}');\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl flex items-center\">\n                    <BeakerIcon />\n                    <span className=\"ml-3\">Code Spell Checker</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">A simple tool that finds and highlights common typos in code.</p>\n            </header>\n            <div className=\"relative flex-grow font-mono text-sm bg-surface border border-border rounded-lg p-4 overflow-auto\">\n                <textarea\n                    value={code}\n                    onChange={(e) => setCode(e.target.value)}\n                    className=\"absolute inset-0 w-full h-full p-4 bg-transparent text-transparent caret-primary resize-none z-10\"\n                    spellCheck=\"false\"\n                />\n                <pre className=\"absolute inset-0 w-full h-full p-4 pointer-events-none whitespace-pre-wrap\" aria-hidden=\"true\">\n                    <HighlightedText text={code} />\n                </pre>\n            </div>\n             <p className=\"text-xs text-text-secondary mt-2 text-center\">This checker uses a predefined list of common typos and does not use AI.</p>\n        </div>\n    );\n};`,\n  'components/features/ColorPaletteGenerator.tsx': `import React, { useState, useCallback } from 'react';\nimport { HexColorPicker } from 'react-colorful';\nimport { generateColorPalette, downloadFile } from '../../services/index.ts';\nimport { SparklesIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\ninterface PreviewColors {\n    cardBg: string;\n    pillBg: string;\n    pillText: string;\n    buttonBg: string;\n}\n\nconst PreviewCard: React.FC<{ palette: string[], colors: PreviewColors, setColors: React.Dispatch<React.SetStateAction<PreviewColors>> }> = ({ palette, colors, setColors }) => {\n    \n    const ColorSelector: React.FC<{ label: string, value: string, onChange: (val: string) => void }> = ({ label, value, onChange }) => (\n        <div className=\"flex items-center justify-between text-sm\">\n            <label className=\"text-text-primary\">{label}</label>\n            <div className=\"flex items-center gap-2\">\n                {palette.map(color => (\n                     <button \n                        key={color}\n                        onClick={() => onChange(color)}\n                        className={\\`w-5 h-5 rounded-full border border-gray-300 \\${value === color ? 'ring-2 ring-primary ring-offset-1' : ''}\\`}\n                        style={{ backgroundColor: color }}\n                        title={color}\n                     />\n                ))}\n            </div>\n        </div>\n    );\n    \n    return (\n        <div className=\"bg-surface p-4 rounded-lg border border-border w-full max-w-sm\">\n            <h3 className=\"text-lg font-bold mb-4 text-text-primary\">Live Preview</h3>\n            <div className=\"p-8 rounded-xl mb-4\" style={{ backgroundColor: colors.cardBg }}>\n                <div className=\"px-4 py-1 rounded-full text-center text-sm inline-block\" style={{ backgroundColor: colors.pillBg, color: colors.pillText }}>\n                    New Feature\n                </div>\n                <div className=\"mt-8 text-center\">\n                     <button className=\"px-6 py-2 rounded-lg font-bold\" style={{ backgroundColor: colors.buttonBg, color: colors.cardBg }}>\n                        Get Started\n                    </button>\n                </div>\n            </div>\n            <div className=\"space-y-3\">\n                <ColorSelector label=\"Card Background\" value={colors.cardBg} onChange={val => setColors(c => ({...c, cardBg: val}))} />\n                <ColorSelector label=\"Pill Background\" value={colors.pillBg} onChange={val => setColors(c => ({...c, pillBg: val}))} />\n                <ColorSelector label=\"Pill Text\" value={colors.pillText} onChange={val => setColors(c => ({...c, pillText: val}))} />\n                <ColorSelector label=\"Button Background\" value={colors.buttonBg} onChange={val => setColors(c => ({...c, buttonBg: val}))} />\n            </div>\n        </div>\n    );\n};\n\nexport const ColorPaletteGenerator: React.FC = () => {\n    const [baseColor, setBaseColor] = useState(\"#0047AB\");\n    const [palette, setPalette] = useState<string[]>(['#F0F2F5', '#CCD3E8', '#99AADD', '#6688D1', '#3366CC', '#0047AB']);\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    const [previewColors, setPreviewColors] = useState<PreviewColors>({\n        cardBg: '#F0F2F5', pillBg: '#CCD3E8', pillText: '#0047AB', buttonBg: '#0047AB'\n    });\n    \n    const handleGenerate = useCallback(async () => {\n        setIsLoading(true);\n        setError('');\n        try {\n            const result = await generateColorPalette(baseColor);\n            setPalette(result.colors);\n            setPreviewColors({\n                cardBg: result.colors[0],\n                pillBg: result.colors[2],\n                pillText: result.colors[5],\n                buttonBg: result.colors[5],\n            })\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to generate palette: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [baseColor]);\n    \n    const downloadColors = () => {\n        const cssContent = \\`:root {\\\\n\\${palette.map((c, i) => \\`  --color-palette-\\${i+1}: \\${c};\\`).join('\\\\n')}\\\\n}\\`;\n        downloadFile(cssContent, 'palette.css', 'text/css');\n    };\n    \n    const downloadCard = () => {\n        const htmlContent = \\`\n<div class=\"card\">\n  <div class=\"pill\">New Feature</div>\n  <button class=\"button\">Get Started</button>\n</div>\n        \\`;\n        const cssContent = \\`\n.card {\n  background-color: \\${previewColors.cardBg};\n  padding: 2rem;\n  border-radius: 1rem;\n  text-align: center;\n}\n.pill {\n  background-color: \\${previewColors.pillBg};\n  color: \\${previewColors.pillText};\n  display: inline-block;\n  padding: 0.25rem 1rem;\n  border-radius: 9999px;\n  text-align: center;\n  font-size: 0.875rem;\n}\n.button {\n  margin-top: 2rem;\n  background-color: \\${previewColors.buttonBg};\n  color: \\${previewColors.cardBg};\n  padding: 0.5rem 1.5rem;\n  border-radius: 0.5rem;\n  font-weight: bold;\n  border: none;\n  cursor: pointer;\n}\n        \\`;\n        const combined = \\`<!-- HTML -->\\\\n\\${htmlContent}\\\\n\\\\n<!-- CSS -->\\\\n<style>\\\\n\\${cssContent}\\\\n</style>\\`;\n        downloadFile(combined, 'preview-card.html', 'text/html');\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 text-center\">\n                <h1 className=\"text-3xl font-bold flex items-center justify-center\">\n                    <SparklesIcon />\n                    <span className=\"ml-3\">AI Color Palette Generator</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Pick a base color, let Gemini design a palette, and preview it on a UI card.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col lg:flex-row items-center justify-center gap-8\">\n                <div className=\"flex flex-col items-center gap-4\">\n                     <HexColorPicker color={baseColor} onChange={setBaseColor} className=\"!w-64 !h-64\"/>\n                     <div className=\"p-2 bg-surface rounded-md font-mono text-lg border border-border\" style={{color: baseColor}}>{baseColor}</div>\n                      <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary w-full flex items-center justify-center px-6 py-3\">\n                        {isLoading ? <LoadingSpinner /> : 'Generate Palette'}\n                    </button>\n                    {error && <p className=\"text-red-500 text-sm mt-2\">{error}</p>}\n                </div>\n                <div className=\"flex flex-col gap-2 w-full max-w-sm\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Generated Palette:</label>\n                    {isLoading ? (\n                         <div className=\"flex items-center justify-center h-48\"><LoadingSpinner /></div>\n                    ) : (\n                        palette.map((color) => (\n                            <div key={color} className=\"group flex items-center justify-between p-4 rounded-md shadow-sm border border-border\" style={{ backgroundColor: color }}>\n                                <span className=\"font-mono font-bold text-black/70 mix-blend-overlay\">{color}</span>\n                                <button onClick={() => navigator.clipboard.writeText(color)} className=\"opacity-0 group-hover:opacity-100 transition-opacity bg-white/30 hover:bg-white/50 px-3 py-1 rounded text-xs text-black font-semibold backdrop-blur-sm\">Copy</button>\n                            </div>\n                        ))\n                    )}\n                    <div className=\"flex gap-2 mt-2\">\n                        <button onClick={downloadColors} className=\"flex-1 flex items-center justify-center gap-2 text-sm py-2 bg-gray-100 border border-border rounded-md hover:bg-gray-200\"><ArrowDownTrayIcon className=\"w-4 h-4\"/> Download Colors</button>\n                        <button onClick={downloadCard} className=\"flex-1 flex items-center justify-center gap-2 text-sm py-2 bg-gray-100 border border-border rounded-md hover:bg-gray-200\"><ArrowDownTrayIcon className=\"w-4 h-4\"/> Download Card</button>\n                    </div>\n                </div>\n                {!isLoading && <PreviewCard palette={palette} colors={previewColors} setColors={setPreviewColors} />}\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CommandPaletteTrigger.tsx': `import React from 'react';\nimport { CommandLineIcon } from '../icons.tsx';\n\nexport const CommandPaletteTrigger: React.FC = () => {\n    return (\n        <div className=\"flex flex-col items-center justify-center h-full p-8 text-center text-text-secondary\">\n            <div className=\"text-6xl mb-4 text-primary\" aria-hidden=\"true\">\n                <CommandLineIcon />\n            </div>\n            <h1 className=\"text-3xl font-bold text-text-primary mb-2\">\n                Command Palette\n            </h1>\n            <p className=\"text-lg mb-4 max-w-md\">\n                The Command Palette provides quick keyboard access to all features and commands.\n            </p>\n            <div className=\"bg-surface text-primary border border-border rounded-lg px-6 py-4 animate-pulse shadow-sm\">\n                <p className=\"font-semibold text-text-primary\">Press <kbd className=\"mx-1 font-sans px-2 py-1.5 text-xs font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded-lg\">Ctrl</kbd> + <kbd className=\"mx-1 font-sans px-2 py-1.5 text-xs font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded-lg\">K</kbd> to open.</p>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/Connections.tsx': `import React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { validateToken } from '../../services/authService.ts';\nimport { ACTION_REGISTRY, executeWorkspaceAction } from '../../services/workspaceConnectorService.ts';\nimport { RectangleGroupIcon, GithubIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { signInWithGoogle } from '../../services/googleAuthService.ts';\nimport { useVaultModal } from '../../contexts/VaultModalContext.tsx';\n\nconst ServiceConnectionCard: React.FC<{\n    serviceName: string;\n    icon: React.ReactNode;\n    fields: { id: string; label: string; placeholder: string }[];\n    onConnect: (credentials: Record<string, string>) => Promise<void>;\n    onDisconnect: () => Promise<void>;\n    status: string;\n    isLoading: boolean;\n}> = ({ serviceName, icon, fields, onConnect, onDisconnect, status, isLoading }) => {\n    const [creds, setCreds] = useState<Record<string, string>>({});\n\n    const handleConnect = () => {\n        onConnect(creds);\n    };\n\n    const isConnected = status.startsWith('Connected');\n\n    return (\n        <div className=\"bg-surface border border-border rounded-lg p-6\">\n            <div className=\"flex items-center justify-between\">\n                <div className=\"flex items-center gap-4\">\n                    <div className=\"w-10 h-10\">{icon}</div>\n                    <div>\n                        <h3 className=\"text-lg font-bold text-text-primary\">{serviceName}</h3>\n                        <p className={\\`text-sm \\${isConnected ? 'text-green-600' : 'text-text-secondary'}\\`}>{status}</p>\n                    </div>\n                </div>\n                {isConnected && (\n                    <button onClick={onDisconnect} className=\"px-4 py-2 bg-red-500/10 text-red-600 font-semibold rounded-lg hover:bg-red-500/20\">\n                        Disconnect\n                    </button>\n                )}\n            </div>\n            {!isConnected && (\n                <div className=\"mt-4 pt-4 border-t border-border space-y-2\">\n                    {fields.map(field => (\n                        <div key={field.id}>\n                            <label className=\"text-xs text-text-secondary\">{field.label}</label>\n                            <input\n                                type={field.id.includes('token') || field.id.includes('pat') ? 'password' : 'text'}\n                                value={creds[field.id] || ''}\n                                onChange={e => setCreds(prev => ({ ...prev, [field.id]: e.target.value }))}\n                                placeholder={field.placeholder}\n                                className=\"w-full mt-1 p-2 bg-background border border-border rounded-md text-sm\"\n                            />\n                        </div>\n                    ))}\n                    <button onClick={handleConnect} disabled={isLoading} className=\"btn-primary w-full mt-2 py-2 flex items-center justify-center\">\n                        {isLoading ? <LoadingSpinner /> : 'Connect'}\n                    </button>\n                </div>\n            )}\n        </div>\n    );\n};\n\n\nexport const WorkspaceConnectorHub: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const { user, githubUser, vaultState } = state;\n    const { addNotification } = useNotification();\n    const { requestUnlock, requestCreation } = useVaultModal();\n    const [loadingStates, setLoadingStates] = useState<Record<string, boolean>>({});\n    const [connectionStatuses, setConnectionStatuses] = useState<Record<string, string>>({});\n    \n    // Manual action state\n    const [selectedActionId, setSelectedActionId] = useState<string>([...ACTION_REGISTRY.keys()][0]);\n    const [actionParams, setActionParams] = useState<Record<string, any>>({});\n    const [isExecuting, setIsExecuting] = useState(false);\n    const [actionResult, setActionResult] = useState<string>('');\n\n    const services = useMemo(() => {\n        const serviceMap = new Map();\n        ACTION_REGISTRY.forEach(action => {\n            if (!serviceMap.has(action.service)) {\n                serviceMap.set(action.service, {\n                    name: action.service,\n                    actions: [],\n                });\n            }\n            serviceMap.get(action.service).actions.push(action);\n        });\n        return Array.from(serviceMap.values());\n    }, []);\n\n    const checkConnections = useCallback(async () => {\n        if (!user || !vaultState.isUnlocked) return;\n        \n        const checkCred = async (credId: string, serviceName: string, successMessage: string) => {\n             const token = await vaultService.getDecryptedCredential(credId);\n             setConnectionStatuses(s => ({ ...s, [serviceName]: token ? successMessage : 'Not Connected' }));\n        };\n\n        await checkCred('github_pat', 'GitHub', githubUser ? \\`Connected as \\${githubUser.login}\\`: 'Connected');\n        await checkCred('jira_pat', 'Jira', 'Connected');\n        await checkCred('slack_bot_token', 'Slack', 'Connected');\n\n    }, [user, vaultState.isUnlocked, githubUser]);\n\n    useEffect(() => {\n        checkConnections();\n    }, [checkConnections]);\n    \n    const withVault = useCallback(async (callback: () => Promise<void>) => {\n        if (!vaultState.isInitialized) {\n            const created = await requestCreation();\n            if (!created) { addNotification('Vault setup is required.', 'error'); return; }\n        }\n        if (!vaultState.isUnlocked) {\n            const unlocked = await requestUnlock();\n            if (!unlocked) { addNotification('Vault must be unlocked to manage connections.', 'error'); return; }\n        }\n        await callback();\n    }, [vaultState, requestCreation, requestUnlock, addNotification]);\n\n\n    const handleConnect = async (serviceName: string, credentials: Record<string, string>) => {\n        await withVault(async () => {\n            setLoadingStates(s => ({ ...s, [serviceName]: true }));\n            try {\n                for (const [key, value] of Object.entries(credentials)) {\n                    if (value) await vaultService.saveCredential(key, value);\n                }\n                if (serviceName === 'GitHub' && credentials.github_pat) {\n                     const githubProfile = await validateToken(credentials.github_pat);\n                     dispatch({ type: 'SET_GITHUB_USER', payload: githubProfile });\n                     await vaultService.saveCredential('github_user', JSON.stringify(githubProfile));\n                }\n                addNotification(\\`\\${serviceName} connected successfully!\\`, 'success');\n                checkConnections();\n            } catch (e) {\n                addNotification(\\`Failed to connect \\${serviceName}: \\${e instanceof Error ? e.message : 'Unknown error'}\\`, 'error');\n            } finally {\n                setLoadingStates(s => ({ ...s, [serviceName]: false }));\n            }\n        });\n    };\n    \n    const handleDisconnect = async (serviceName: string, credIds: string[]) => {\n       await withVault(async () => {\n            setLoadingStates(s => ({ ...s, [serviceName]: true }));\n            try {\n                for (const id of credIds) {\n                     await vaultService.saveCredential(id, ''); // Overwrite with empty string\n                }\n                 if (serviceName === 'GitHub') {\n                     dispatch({ type: 'SET_GITHUB_USER', payload: null });\n                     await vaultService.saveCredential('github_user', '');\n                }\n                addNotification(\\`\\${serviceName} disconnected.\\`, 'info');\n                checkConnections();\n            } catch(e) {\n                addNotification(\\`Failed to disconnect \\${serviceName}.\\`, 'error');\n            } finally {\n                 setLoadingStates(s => ({ ...s, [serviceName]: false }));\n            }\n       });\n    };\n    \n    const handleExecuteAction = async () => {\n        await withVault(async () => {\n            setIsExecuting(true);\n            setActionResult('');\n            try {\n                const result = await executeWorkspaceAction(selectedActionId, actionParams);\n                setActionResult(JSON.stringify(result, null, 2));\n                addNotification('Action executed successfully!', 'success');\n            } catch(e) {\n                setActionResult(\\`Error: \\${e instanceof Error ? e.message : 'Unknown Error'}\\`);\n                addNotification('Action failed.', 'error');\n            } finally {\n                setIsExecuting(false);\n            }\n        });\n    };\n\n    const handleSignIn = () => {\n        signInWithGoogle();\n        // The result is handled by the global callback set in App.tsx\n    };\n\n    const selectedAction = ACTION_REGISTRY.get(selectedActionId);\n    const actionParameters = selectedAction ? selectedAction.getParameters() : {};\n\n    if (!user) {\n        return (\n            <div className=\"h-full flex items-center justify-center\">\n                <div className=\"text-center bg-surface p-8 rounded-lg border border-border max-w-md\">\n                    <h2 className=\"text-xl font-bold\">Sign In Required</h2>\n                    <p className=\"text-text-secondary my-4\">Please sign in with your Google account to manage workspace connections.</p>\n                    <button onClick={handleSignIn} disabled={loadingStates.google} className=\"btn-primary px-6 py-3 flex items-center justify-center gap-2 mx-auto\">\n                        {loadingStates.google ? <LoadingSpinner/> : 'Sign in with Google'}\n                    </button>\n                </div>\n            </div>\n        );\n    }\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n             <header className=\"mb-8\">\n                <h1 className=\"text-4xl font-extrabold tracking-tight flex items-center\"><RectangleGroupIcon /><span className=\"ml-3\">Workspace Connector Hub</span></h1>\n                <p className=\"mt-2 text-lg text-text-secondary\">Connect to your development services to unlock cross-platform AI actions.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-8 min-h-0\">\n                <div className=\"flex flex-col gap-6 overflow-y-auto pr-4\">\n                    <h2 className=\"text-2xl font-bold\">Service Connections</h2>\n                    <ServiceConnectionCard \n                        serviceName=\"GitHub\"\n                        icon={<GithubIcon />}\n                        fields={[{ id: 'github_pat', label: 'Personal Access Token', placeholder: 'ghp_...' }]}\n                        onConnect={(creds) => handleConnect('GitHub', creds)}\n                        onDisconnect={() => handleDisconnect('GitHub', ['github_pat'])}\n                        status={connectionStatuses.GitHub || 'Checking...'}\n                        isLoading={loadingStates.GitHub}\n                    />\n                     {/* Placeholder cards for Jira and Slack */}\n                    <ServiceConnectionCard \n                        serviceName=\"Jira\"\n                        icon={<div className=\"w-10 h-10 bg-[#0052CC] rounded flex items-center justify-center text-white font-bold text-xl\">J</div>}\n                        fields={[\n                            { id: 'jira_domain', label: 'Jira Domain', placeholder: 'your-company.atlassian.net' },\n                            { id: 'jira_email', label: 'Your Jira Email', placeholder: 'you@example.com' },\n                            { id: 'jira_pat', label: 'API Token', placeholder: 'Your API Token' },\n                        ]}\n                        onConnect={(creds) => handleConnect('Jira', creds)}\n                        onDisconnect={() => handleDisconnect('Jira', ['jira_domain', 'jira_email', 'jira_pat'])}\n                        status={connectionStatuses.Jira || 'Checking...'}\n                        isLoading={loadingStates.Jira}\n                    />\n                    <ServiceConnectionCard \n                        serviceName=\"Slack\"\n                        icon={<div className=\"w-10 h-10 bg-[#4A154B] rounded flex items-center justify-center text-white font-bold text-2xl\">#</div>}\n                        fields={[{ id: 'slack_bot_token', label: 'Bot User OAuth Token', placeholder: 'xoxb-...' }]}\n                        onConnect={(creds) => handleConnect('Slack', creds)}\n                        onDisconnect={() => handleDisconnect('Slack', ['slack_bot_token'])}\n                        status={connectionStatuses.Slack || 'Checking...'}\n                        isLoading={loadingStates.Slack}\n                    />\n                </div>\n                <div className=\"flex flex-col gap-6 bg-surface p-6 border border-border rounded-lg\">\n                    <h2 className=\"text-2xl font-bold\">Manual Action Runner</h2>\n                    <div className=\"space-y-4\">\n                         <div>\n                            <label className=\"text-sm font-medium\">Action</label>\n                            <select value={selectedActionId} onChange={e => setSelectedActionId(e.target.value)} className=\"w-full mt-1 p-2 bg-background border rounded\">\n                                {services.map(service => (\n                                    <optgroup label={service.name} key={service.name}>\n                                        {service.actions.map((action: any) => (\n                                            <option key={action.id} value={action.id}>{action.description}</option>\n                                        ))}\n                                    </optgroup>\n                                ))}\n                            </select>\n                        </div>\n                        {Object.entries(actionParameters).map(([key, param]: [string, any]) => (\n                            <div key={key}>\n                                <label className=\"text-sm font-medium\">{key} {param.required && '*'}</label>\n                                <input \n                                    type={param.type}\n                                    value={actionParams[key] || ''}\n                                    onChange={e => setActionParams(p => ({...p, [key]: e.target.value}))}\n                                    placeholder={param.default || ''}\n                                    className=\"w-full mt-1 p-2 bg-background border rounded\"\n                                />\n                            </div>\n                        ))}\n                        <button onClick={handleExecuteAction} disabled={isExecuting} className=\"btn-primary w-full py-2 flex items-center justify-center gap-2\">\n                           {isExecuting ? <LoadingSpinner/> : <><SparklesIcon /> Execute Action</>}\n                        </button>\n                    </div>\n                    <div>\n                        <label className=\"text-sm font-medium\">Result</label>\n                        <pre className=\"w-full h-48 mt-1 p-2 bg-background border rounded overflow-auto text-xs\">{actionResult || 'Action results will appear here.'}</pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CronJobBuilder.tsx': `import React, { useState, useMemo, useCallback, useEffect } from 'react';\nimport { CommandLineIcon, SparklesIcon } from '../icons.tsx';\nimport { generateCronFromDescription, CronParts } from '../../services/index.ts';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\nconst CronPartSelector: React.FC<{ label: string, value: string, onChange: (value: string) => void, options: (string|number)[] }> = ({ label, value, onChange, options }) => {\n    return (\n        <div>\n            <label className=\"block text-sm font-medium text-text-secondary\">{label}</label>\n            <select value={value} onChange={e => onChange(e.target.value)} className=\"w-full mt-1 px-3 py-2 rounded-md bg-surface border border-border\">\n                <option value=\"*\">* (every)</option>\n                {options.map(o => <option key={o} value={o}>{o}</option>)}\n            </select>\n        </div>\n    );\n};\n\nexport const CronJobBuilder: React.FC<{ initialPrompt?: string }> = ({ initialPrompt }) => {\n    const [minute, setMinute] = useState('0');\n    const [hour, setHour] = useState('17');\n    const [dayOfMonth, setDayOfMonth] = useState('*');\n    const [month, setMonth] = useState('*');\n    const [dayOfWeek, setDayOfWeek] = useState('1-5');\n    const [aiPrompt, setAiPrompt] = useState(initialPrompt || 'every weekday at 5pm');\n    const [isLoading, setIsLoading] = useState(false);\n    \n    const cronExpression = useMemo(() => {\n        return \\`\\${minute} \\${hour} \\${dayOfMonth} \\${month} \\${dayOfWeek}\\`;\n    }, [minute, hour, dayOfMonth, month, dayOfWeek]);\n\n    const handleAiGenerate = useCallback(async (p: string) => {\n        if (!p) return;\n        setIsLoading(true);\n        try {\n            const result: CronParts = await generateCronFromDescription(p);\n            setMinute(result.minute);\n            setHour(result.hour);\n            setDayOfMonth(result.dayOfMonth);\n            setMonth(result.month);\n            setDayOfWeek(result.dayOfWeek);\n        } catch (e) {\n            console.error(e);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        if (initialPrompt) {\n            setAiPrompt(initialPrompt);\n            handleAiGenerate(initialPrompt);\n        }\n    }, [initialPrompt, handleAiGenerate]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <CommandLineIcon />\n                    <span className=\"ml-3\">AI Cron Job Builder</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Visually construct a cron expression or describe it in plain English.</p>\n            </header>\n             <div className=\"flex gap-2 mb-6\">\n                <input type=\"text\" value={aiPrompt} onChange={e => setAiPrompt(e.target.value)} placeholder=\"Describe a schedule...\" className=\"flex-grow px-3 py-1.5 rounded-md bg-surface border border-border text-sm\"/>\n                <button onClick={() => handleAiGenerate(aiPrompt)} disabled={isLoading} className=\"btn-primary px-4 py-1.5 flex items-center gap-2\">\n                    {isLoading ? <LoadingSpinner /> : <SparklesIcon />} AI Generate\n                </button>\n            </div>\n            <div className=\"grid grid-cols-2 md:grid-cols-5 gap-4 mb-6\">\n                <CronPartSelector label=\"Minute\" value={minute} onChange={setMinute} options={Array.from({length: 60}, (_, i) => i)} />\n                <CronPartSelector label=\"Hour\" value={hour} onChange={setHour} options={Array.from({length: 24}, (_, i) => i)} />\n                <CronPartSelector label=\"Day (Month)\" value={dayOfMonth} onChange={setDayOfMonth} options={Array.from({length: 31}, (_, i) => i + 1)} />\n                <CronPartSelector label=\"Month\" value={month} onChange={setMonth} options={Array.from({length: 12}, (_, i) => i + 1)} />\n                <CronPartSelector label=\"Day (Week)\" value={dayOfWeek} onChange={setDayOfWeek} options={Array.from({length: 7}, (_, i) => i)} />\n            </div>\n            <div className=\"bg-surface p-4 rounded-lg text-center border border-border\">\n                <p className=\"text-text-secondary text-sm\">Generated Expression</p>\n                <p className=\"font-mono text-primary text-2xl mt-1\">{cronExpression}</p>\n                 <button onClick={() => navigator.clipboard.writeText(cronExpression)} className=\"mt-4 px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy</button>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/CssGridEditor.tsx': `import React, { useState, useMemo } from 'react';\nimport { CodeBracketSquareIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { downloadFile } from '../../services/index.ts';\n\nconst initialSettings = { rows: 3, cols: 4, rowGap: 1, colGap: 1 };\n\nexport const CssGridEditor: React.FC = () => {\n    const [rows, setRows] = useState(initialSettings.rows);\n    const [cols, setCols] = useState(initialSettings.cols);\n    const [rowGap, setRowGap] = useState(initialSettings.rowGap);\n    const [colGap, setColGap] = useState(initialSettings.colGap);\n\n    const gridStyle = {\n        display: 'grid',\n        gridTemplateColumns: \\`repeat(\\${cols}, 1fr)\\`,\n        gridTemplateRows: \\`repeat(\\${rows}, 1fr)\\`,\n        gap: \\`\\${rowGap}rem \\${colGap}rem\\`,\n        height: '100%',\n        width: '100%'\n    };\n\n    const cssCode = useMemo(() => {\n        return \\`.grid-container {\n  display: grid;\n  grid-template-columns: repeat(\\${cols}, 1fr);\n  grid-template-rows: repeat(\\${rows}, 1fr);\n  gap: \\${rowGap}rem \\${colGap}rem;\n}\\`;\n    }, [rows, cols, rowGap, colGap]);\n    \n    const handleCopy = () => {\n        navigator.clipboard.writeText(cssCode);\n    };\n    \n    const handleDownload = () => {\n        downloadFile(cssCode, 'grid.css', 'text/css');\n    };\n\n    const handleReset = () => {\n        setRows(initialSettings.rows);\n        setCols(initialSettings.cols);\n        setRowGap(initialSettings.rowGap);\n        setColGap(initialSettings.colGap);\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <CodeBracketSquareIcon />\n                    <span className=\"ml-3\">CSS Grid Visual Editor</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Configure your grid layout and copy the generated CSS.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-3 gap-6 min-h-0\">\n                <div className=\"lg:col-span-1 flex flex-col gap-4 bg-surface border border-border p-6 rounded-lg overflow-y-auto\">\n                    <div className=\"flex justify-between items-center\">\n                        <h3 className=\"text-xl font-bold\">Controls</h3>\n                        <button onClick={handleReset} className=\"text-xs px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md\">Reset</button>\n                    </div>\n                    <div className=\"space-y-4\">\n                        <div>\n                            <label htmlFor=\"rows\" className=\"block text-sm font-medium text-text-secondary\">Rows ({rows})</label>\n                            <input id=\"rows\" type=\"range\" min=\"1\" max=\"12\" value={rows} onChange={e => setRows(Number(e.target.value))} className=\"w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer\" />\n                        </div>\n                        <div>\n                            <label htmlFor=\"cols\" className=\"block text-sm font-medium text-text-secondary\">Columns ({cols})</label>\n                            <input id=\"cols\" type=\"range\" min=\"1\" max=\"12\" value={cols} onChange={e => setCols(Number(e.target.value))} className=\"w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer\" />\n                        </div>\n                         <div>\n                            <label htmlFor=\"rowGap\" className=\"block text-sm font-medium text-text-secondary\">Row Gap ({rowGap}rem)</label>\n                            <input id=\"rowGap\" type=\"range\" min=\"0\" max=\"8\" step=\"0.25\" value={rowGap} onChange={e => setRowGap(Number(e.target.value))} className=\"w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer\" />\n                        </div>\n                         <div>\n                            <label htmlFor=\"colGap\" className=\"block text-sm font-medium text-text-secondary\">Column Gap ({colGap}rem)</label>\n                            <input id=\"colGap\" type=\"range\" min=\"0\" max=\"8\" step=\"0.25\" value={colGap} onChange={e => setColGap(Number(e.target.value))} className=\"w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer\" />\n                        </div>\n                    </div>\n                     <div className=\"flex-grow mt-4 flex flex-col min-h-[150px]\">\n                        <div className=\"flex justify-between items-center mb-2\">\n                            <label className=\"text-sm font-medium text-text-secondary\">Generated CSS</label>\n                            <div className=\"flex gap-2\">\n                                <button onClick={handleCopy} className=\"px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy</button>\n                                <button onClick={handleDownload} className=\"flex items-center gap-1 px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\"><ArrowDownTrayIcon className=\"w-4 h-4\"/> Download</button>\n                            </div>\n                        </div>\n                        <div className=\"relative flex-grow\">\n                            <pre className=\"bg-background p-4 rounded-md text-primary text-sm overflow-auto h-full w-full absolute\">{cssCode}</pre>\n                        </div>\n                    </div>\n                </div>\n                <div className=\"lg:col-span-2 bg-background rounded-lg p-4 border-2 border-dashed border-border\">\n                    <div style={gridStyle}>\n                        {Array.from({ length: rows * cols }).map((_, i) => (\n                            <div key={i} className=\"bg-primary/10 rounded-lg border-2 border-dashed border-primary/50 flex items-center justify-center text-primary\">\n                                <span className=\"text-xs opacity-70\">{i + 1}</span>\n                            </div>\n                        ))}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/DeploymentPreview.tsx': `import React, { useState, useEffect, useRef } from 'react';\nimport { getAllFiles, getFileByPath } from '../../services/dbService.ts';\nimport type { GeneratedFile } from '../../types.ts';\nimport { CloudIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\nexport const DeploymentPreview: React.FC = () => {\n    const [files, setFiles] = useState<GeneratedFile[]>([]);\n    const [isLoading, setIsLoading] = useState(true);\n    const [error, setError] = useState('');\n    const iframeRef = useRef<HTMLIFrameElement>(null);\n\n    useEffect(() => {\n        const loadAndRender = async () => {\n            setIsLoading(true);\n            setError('');\n            try {\n                const allFiles = await getAllFiles();\n                if (allFiles.length === 0) {\n                    setError('No files generated by AI Feature Builder found.');\n                    setFiles([]);\n                    setIsLoading(false);\n                    return;\n                }\n                setFiles(allFiles);\n\n                let indexHtmlFile = allFiles.find(f => f.filePath.endsWith('index.html'));\n                if (!indexHtmlFile) {\n                    setError('No index.html file found in the generated files.');\n                    setIsLoading(false);\n                    return;\n                }\n\n                let content = indexHtmlFile.content;\n                \n                // Create blob URLs for all assets and replace relative paths\n                const blobUrlMap = new Map<string, string>();\n                for (const file of allFiles) {\n                    const mimeType = file.filePath.endsWith('.css') ? 'text/css' : 'application/javascript';\n                    const blob = new Blob([file.content], { type: mimeType });\n                    blobUrlMap.set(file.filePath, URL.createObjectURL(blob));\n                }\n                \n                // Replace relative paths in index.html\n                content = content.replace(/(href|src)=[\"'](\\\\.?\\\\/)?([^\"']+)[\"']/g, (match, attr, prefix, path) => {\n                    const blobUrl = blobUrlMap.get(path);\n                    return blobUrl ? \\`\\${attr}=\"\\${blobUrl}\"\\` : match;\n                });\n\n                if (iframeRef.current) {\n                    iframeRef.current.srcdoc = content;\n                }\n\n            } catch (err) {\n                setError(err instanceof Error ? err.message : 'Failed to load files.');\n            } finally {\n                setIsLoading(false);\n            }\n        };\n\n        loadAndRender();\n        \n        // Cleanup blob URLs on unmount\n        return () => {\n             // This is a bit tricky since we don't have the map here, but the browser will clean them up.\n        };\n    }, []);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><CloudIcon /><span className=\"ml-3\">Static Deployment Previewer</span></h1>\n                <p className=\"text-text-secondary mt-1\">Live preview of the static site generated by the AI Feature Builder.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-3 gap-6 min-h-0\">\n                <div className=\"lg:col-span-1 bg-surface p-4 border border-border rounded-lg overflow-y-auto\">\n                    <h3 className=\"font-bold mb-2\">File List</h3>\n                    <ul className=\"text-sm space-y-1\">\n                        {files.map(f => <li key={f.filePath} className=\"truncate p-1 bg-background rounded\">{f.filePath}</li>)}\n                    </ul>\n                </div>\n                <div className=\"lg:col-span-2 bg-background border-2 border-dashed border-border rounded-lg overflow-hidden\">\n                    {isLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner/></div>}\n                    {error && <div className=\"flex justify-center items-center h-full text-red-500\">{error}</div>}\n                    {!isLoading && !error && <iframe ref={iframeRef} title=\"Deployment Preview\" className=\"w-full h-full bg-white\"/>}\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/DevNotesStickyPanel.tsx': `import React from 'react';\n\nexport const DevNotesStickyPanel: React.FC = () => {\n    return (\n        <div className=\"p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700\">\n            <h4 className=\"font-bold\">Developer Notes</h4>\n            <p>This is a placeholder component for developer notes.</p>\n        </div>\n    );\n};\n`,\n  'components/features/DigitalWhiteboard.tsx': `import React, { useState, useCallback } from 'react';\nimport { SparklesIcon, DigitalWhiteboardIcon } from '../icons.tsx';\nimport { useLocalStorage } from '../../hooks/useLocalStorage.ts';\nimport { summarizeNotesStream } from '../../services/index.ts';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { MarkdownRenderer } from '../shared/index.tsx';\n\ninterface Note {\n    id: number;\n    text: string;\n    x: number;\n    y: number;\n    color: string;\n}\n\nconst colors = ['bg-yellow-400', 'bg-green-400', 'bg-blue-400', 'bg-pink-400', 'bg-purple-400', 'bg-orange-400'];\nconst textColors = ['text-yellow-900', 'text-green-900', 'text-blue-900', 'text-pink-900', 'text-purple-900', 'text-orange-900'];\n\nexport const DigitalWhiteboard: React.FC = () => {\n    const [notes, setNotes] = useLocalStorage<Note[]>('devcore_whiteboard_notes', []);\n    const [dragging, setDragging] = useState<{ id: number; offsetX: number; offsetY: number } | null>(null);\n    const [isSummarizing, setIsSummarizing] = useState(false);\n    const [summary, setSummary] = useState('');\n\n    const handleSummarize = useCallback(async () => {\n        if (notes.length === 0) return;\n        setIsSummarizing(true);\n        setSummary('');\n        try {\n            const allNotesText = notes.map((n: Note) => \\`- \\${n.text}\\`).join('\\\\n');\n            const stream = summarizeNotesStream(allNotesText);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setSummary(fullResponse);\n            }\n        } catch (error) {\n            console.error(error);\n            setSummary('Sorry, an error occurred while summarizing.');\n        } finally {\n            setIsSummarizing(false);\n        }\n    }, [notes]);\n\n    const addNote = () => {\n        const newNote: Note = {\n            id: Date.now(),\n            text: 'New idea...',\n            x: 50,\n            y: 50,\n            color: colors[notes.length % colors.length],\n        };\n        setNotes([...notes, newNote]);\n    };\n    \n    const deleteNote = (id: number, e: React.MouseEvent) => {\n        e.stopPropagation();\n        setNotes(notes.filter((n) => n.id !== id));\n    };\n\n    const updateNote = (id: number, updates: Partial<Note>) => {\n        setNotes(notes.map((n) => n.id === id ? { ...n, ...updates } : n));\n    };\n\n    const onMouseDown = (e: React.MouseEvent<HTMLDivElement>, id: number) => {\n        const target = e.target as HTMLElement;\n        if (target.tagName === 'TEXTAREA' || target.dataset.role === 'button') return;\n        \n        const noteElement = e.currentTarget;\n        const rect = noteElement.getBoundingClientRect();\n        setDragging({ id, offsetX: e.clientX - rect.left, offsetY: e.clientY - rect.top });\n    };\n\n    const onMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n        if (!dragging) return;\n        const boardRect = e.currentTarget.getBoundingClientRect();\n        updateNote(dragging.id, {\n            x: e.clientX - dragging.offsetX - boardRect.left,\n            y: e.clientY - dragging.offsetY - boardRect.top\n        });\n    };\n\n    const onMouseUp = () => setDragging(null);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex justify-between items-center\">\n                 <div>\n                    <h1 className=\"text-3xl font-bold flex items-center\"><DigitalWhiteboardIcon /><span className=\"ml-3\">Digital Whiteboard</span></h1>\n                    <p className=\"text-text-secondary mt-1\">Organize your ideas with interactive sticky notes and AI summaries.</p>\n                </div>\n                <div className=\"flex gap-2\">\n                    <button onClick={handleSummarize} disabled={isSummarizing || notes.length === 0} className=\"btn-primary flex items-center gap-2 px-4 py-2\">\n                        <SparklesIcon/> {isSummarizing ? 'Summarizing...' : 'AI Summarize'}\n                    </button>\n                    <button onClick={addNote} className=\"btn-primary px-6 py-2\">Add Note</button>\n                </div>\n            </header>\n            <div\n                className=\"relative flex-grow bg-background border-2 border-dashed border-border rounded-lg overflow-hidden\"\n                onMouseMove={onMouseMove} onMouseUp={onMouseUp} onMouseLeave={onMouseUp}\n            >\n                {notes.map((note) => (\n                    <div\n                        key={note.id}\n                        className={\\`group absolute w-56 h-56 p-2 flex flex-col shadow-lg cursor-grab active:cursor-grabbing rounded-md transition-transform duration-100 border border-black/40 \\${note.color} \\${textColors[colors.indexOf(note.color)]}\\`}\n                        style={{ top: note.y, left: note.x, transform: dragging?.id === note.id ? 'scale(1.05)' : 'scale(1)' }}\n                        onMouseDown={e => onMouseDown(e, note.id)}\n                    >\n                        <button data-role=\"button\" onClick={(e) => deleteNote(note.id, e)} className=\"absolute -top-2 -right-2 w-6 h-6 rounded-full bg-gray-700 text-white font-bold text-xs flex items-center justify-center opacity-0 group-hover:opacity-100 hover:bg-red-500 transition-all\">&times;</button>\n                        <textarea\n                            value={note.text}\n                            onChange={(e) => updateNote(note.id, { text: e.target.value })}\n                            className=\"w-full h-full bg-transparent resize-none focus:outline-none font-medium p-1\"\n                        />\n                        <div data-role=\"button\" className=\"flex-shrink-0 flex justify-center gap-1 p-1 opacity-0 group-hover:opacity-100 transition-opacity\">\n                            {colors.map((c, i) => <button key={c} onClick={() => updateNote(note.id, { color: c })} className={\\`w-4 h-4 rounded-full \\${c} border border-black/20 \\${note.color === c ? 'ring-2 ring-offset-1 ring-black/50' : ''}\\`}/>)}\n                        </div>\n                    </div>\n                ))}\n            </div>\n             {(isSummarizing || summary) && (\n                 <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center\" onClick={() => setSummary('')}>\n                    <div className=\"w-full max-w-2xl bg-surface border border-border rounded-lg shadow-2xl p-6\" onClick={e => e.stopPropagation()}>\n                        <h2 className=\"text-xl font-bold mb-4\">AI Summary of Notes</h2>\n                        {isSummarizing && !summary ? <LoadingSpinner /> : <MarkdownRenderer content={summary} />}\n                    </div>\n                </div>\n            )}\n        </div>\n    );\n};`,\n  'components/features/EnvManager.tsx': `import React, { useState } from 'react';\nimport { downloadEnvFile } from '../../services/fileUtils.ts';\nimport { DocumentTextIcon, PlusIcon, TrashIcon, ArrowDownTrayIcon } from '../icons.tsx';\n\ninterface EnvVar {\n    id: number;\n    key: string;\n    value: string;\n}\n\nexport const EnvManager: React.FC = () => {\n    const [envVars, setEnvVars] = useState<EnvVar[]>([\n        { id: 1, key: 'VITE_API_URL', value: 'https://api.example.com' },\n        { id: 2, key: 'VITE_ENABLE_FEATURE_X', value: 'true' },\n    ]);\n\n    const handleAdd = () => {\n        setEnvVars([...envVars, { id: Date.now(), key: '', value: '' }]);\n    };\n\n    const handleUpdate = (id: number, field: 'key' | 'value', val: string) => {\n        setEnvVars(envVars.map(v => v.id === id ? { ...v, [field]: val } : v));\n    };\n\n    const handleRemove = (id: number) => {\n        setEnvVars(envVars.filter(v => v.id !== id));\n    };\n    \n    const handleDownload = () => {\n        const envObject = envVars.reduce((acc, v) => {\n            if (v.key) acc[v.key] = v.value;\n            return acc;\n        }, {} as Record<string, string>);\n        downloadEnvFile(envObject);\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><DocumentTextIcon /><span className=\"ml-3\">Environment Variable Manager</span></h1>\n                <p className=\"text-text-secondary mt-1\">Create and manage your \\`.env\\` files with a simple interface.</p>\n            </header>\n            <div className=\"flex-grow bg-surface p-6 rounded-lg border border-border w-full max-w-4xl mx-auto overflow-y-auto\">\n                <div className=\"space-y-3\">\n                    <div className=\"grid grid-cols-12 gap-4 font-semibold text-sm text-text-secondary px-2\">\n                        <div className=\"col-span-5\">Key</div>\n                        <div className=\"col-span-6\">Value</div>\n                        <div className=\"col-span-1\"></div>\n                    </div>\n                    {envVars.map((v, index) => (\n                        <div key={v.id} className=\"grid grid-cols-12 gap-4 items-center\">\n                            <div className=\"col-span-5\">\n                                <input\n                                    type=\"text\"\n                                    value={v.key}\n                                    onChange={e => handleUpdate(v.id, 'key', e.target.value)}\n                                    placeholder={\\`KEY_\\${index + 1}\\`}\n                                    className=\"w-full p-2 bg-background border border-border rounded-md font-mono text-sm\"\n                                />\n                            </div>\n                            <div className=\"col-span-6\">\n                                <input\n                                    type=\"text\"\n                                    value={v.value}\n                                    onChange={e => handleUpdate(v.id, 'value', e.target.value)}\n                                    placeholder=\"value\"\n                                    className=\"w-full p-2 bg-background border border-border rounded-md font-mono text-sm\"\n                                />\n                            </div>\n                            <div className=\"col-span-1\">\n                                <button onClick={() => handleRemove(v.id)} className=\"p-2 text-text-secondary hover:text-red-500 rounded-md\"><TrashIcon /></button>\n                            </div>\n                        </div>\n                    ))}\n                </div>\n                 <div className=\"mt-4 pt-4 border-t border-border flex justify-between items-center\">\n                    <button onClick={handleAdd} className=\"flex items-center gap-2 px-4 py-2 bg-gray-100 text-sm font-semibold rounded-md hover:bg-gray-200\">\n                        <PlusIcon /> Add Variable\n                    </button>\n                    <button onClick={handleDownload} disabled={envVars.length === 0} className=\"btn-primary flex items-center gap-2 px-4 py-2\">\n                        <ArrowDownTrayIcon /> Download .env File\n                    </button>\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/FontPairingTool.tsx': `// This feature is an alias for the Typography Lab.\n// Re-exporting it here to keep the codebase DRY while satisfying the feature registry.\nexport { TypographyLab as FontPairingTool } from './TypographyLab.tsx';`,\n  'components/features/FontPreviewPicker.tsx': `import React, { useState, useEffect } from 'react';\nimport { TypographyLabIcon } from '../icons.tsx';\n\nconst popularFonts = [\n    'Roboto', 'Open Sans', 'Lato', 'Montserrat', 'Oswald', 'Source Sans Pro', 'Raleway', 'Poppins', 'Nunito', 'Merriweather',\n    'Playfair Display', 'Lora', 'Noto Sans', 'Ubuntu', 'PT Sans', 'Slabo 27px', 'Great Vibes', 'EB Garamond'\n];\n\nexport const FontPreviewPicker: React.FC = () => {\n    const [text, setText] = useState('The quick brown fox jumps over the lazy dog.');\n    const [fontSize, setFontSize] = useState(24);\n\n    useEffect(() => {\n        const fontsToLoad = popularFonts.join('|').replace(/ /g, '+');\n        const linkId = 'font-picker-stylesheet';\n        let link = document.getElementById(linkId) as HTMLLinkElement;\n        if (!link) {\n            link = document.createElement('link');\n            link.id = linkId;\n            link.rel = 'stylesheet';\n            document.head.appendChild(link);\n        }\n        link.href = \\`https://fonts.googleapis.com/css?family=\\${fontsToLoad}:400,700&display=swap\\`;\n    }, []);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <TypographyLabIcon />\n                    <span className=\"ml-3\">Font Preview Picker</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Enter your text and see how it looks with different fonts.</p>\n            </header>\n\n            <div className=\"flex flex-col md:flex-row gap-4 mb-6\">\n                <div className=\"flex-grow\">\n                    <label htmlFor=\"preview-text\" className=\"text-sm font-medium\">Preview Text</label>\n                    <input\n                        id=\"preview-text\"\n                        type=\"text\"\n                        value={text}\n                        onChange={e => setText(e.target.value)}\n                        className=\"w-full mt-1 p-2 bg-surface border border-border rounded-md\"\n                    />\n                </div>\n                <div>\n                    <label htmlFor=\"font-size\" className=\"text-sm font-medium\">Font Size ({fontSize}px)</label>\n                    <input\n                        id=\"font-size\"\n                        type=\"range\"\n                        min=\"12\"\n                        max=\"72\"\n                        value={fontSize}\n                        onChange={e => setFontSize(Number(e.target.value))}\n                        className=\"w-full mt-1\"\n                    />\n                </div>\n            </div>\n\n            <div className=\"flex-grow bg-surface border border-border rounded-lg p-4 overflow-y-auto\">\n                <div className=\"space-y-4\">\n                    {popularFonts.map(font => (\n                        <div key={font} className=\"border-b border-border pb-2\">\n                            <p className=\"text-sm text-text-secondary\">{font}</p>\n                            <p style={{ fontFamily: \\`'\\${font}', sans-serif\\`, fontSize: \\`\\${fontSize}px\\` }}>\n                                {text}\n                            </p>\n                        </div>\n                    ))}\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/GmailAddonSimulator.tsx': `import React, { useState, useCallback } from 'react';\nimport { streamContent } from '../../services/aiService.ts';\nimport { MailIcon, SparklesIcon, XMarkIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nconst mockEmail = {\n    from: 'Alice <alice@example.com>',\n    to: 'Me <me@example.com>',\n    subject: 'Project Update & Question',\n    body: \\`Hey,\n\nJust wanted to give you a quick update. The new user authentication flow is complete and pushed to the staging server.\n\nI had a question about the next task regarding the database migration. The ticket says we need to migrate the 'users' table, but it's not clear on the required schema changes. Should I just add the new 'last_login' column or are there other modifications needed?\n\nLet me know when you have a chance.\n\nThanks,\nAlice\\`\n};\n\nexport const GmailAddonSimulator: React.FC = () => {\n    const [isComposeOpen, setComposeOpen] = useState(false);\n    const [generatedReply, setGeneratedReply] = useState('');\n    const [isGenerating, setIsGenerating] = useState(false);\n\n    const handleGenerateReply = useCallback(async () => {\n        setIsGenerating(true);\n        setGeneratedReply('');\n        setComposeOpen(true);\n        try {\n            const prompt = \\`Generate a professional and friendly reply to the following email. Acknowledge the update and answer the question by stating that only the 'last_login' column (as a DATETIME) is needed for now.\\\\n\\\\nEMAIL:\\\\n\\${mockEmail.body}\\`;\n            const stream = streamContent(prompt, \"You are a helpful assistant writing a professional email reply.\", 0.7);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setGeneratedReply(fullResponse);\n            }\n        } catch(e) {\n            setGeneratedReply(\\`Error: \\${e instanceof Error ? e.message : 'Could not generate reply.'}\\`);\n        }\n        finally {\n            setIsGenerating(false);\n        }\n    }, []);\n\n    const ComposeModal = () => (\n        <div className=\"absolute inset-0 bg-black/30 backdrop-blur-sm flex justify-center items-center p-4 z-20\">\n            <div className=\"w-full max-w-2xl h-[70vh] bg-surface rounded-lg shadow-2xl flex flex-col animate-pop-in\">\n                <header className=\"flex justify-between items-center p-3 bg-gray-100 dark:bg-slate-700 rounded-t-lg\">\n                    <h3 className=\"font-semibold text-sm\">New Message</h3>\n                    <button onClick={() => setComposeOpen(false)}><XMarkIcon /></button>\n                </header>\n                <div className=\"p-3 text-sm border-b border-border\">\n                    <p><span className=\"text-text-secondary\">To:</span> {mockEmail.from}</p>\n                </div>\n                <div className=\"p-3 text-sm border-b border-border\">\n                     <p><span className=\"text-text-secondary\">Subject:</span> Re: {mockEmail.subject}</p>\n                </div>\n                <div className=\"flex-grow p-3 overflow-y-auto\">\n                    {isGenerating ? <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div> : <MarkdownRenderer content={generatedReply} />}\n                </div>\n                 <footer className=\"p-3 border-t border-border\">\n                    <button className=\"btn-primary px-6 py-2\">Send</button>\n                 </footer>\n            </div>\n        </div>\n    );\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><MailIcon /><span className=\"ml-3\">Gmail Add-on Simulator</span></h1>\n                <p className=\"text-text-secondary mt-1\">A simulation of how contextual add-on scopes would work inside Gmail.</p>\n            </header>\n            <div className=\"relative flex-grow bg-surface border-2 border-dashed border-border rounded-lg p-6 flex items-center justify-center\">\n                {isComposeOpen && <ComposeModal />}\n                <div className=\"w-full max-w-4xl h-full bg-white dark:bg-slate-800 rounded-xl shadow-2xl flex flex-col overflow-hidden\">\n                    {/* Header */}\n                    <div className=\"flex-shrink-0 p-4 border-b border-border\">\n                        <h2 className=\"text-xl font-bold\">{mockEmail.subject}</h2>\n                        <div className=\"flex items-center gap-2 text-sm mt-2\">\n                             <img src=\"https://avatar.vercel.sh/alice\" alt=\"Alice\" className=\"w-8 h-8 rounded-full\" />\n                             <div>\n                                <p className=\"font-semibold\">{mockEmail.from.split('<')[0].trim()}</p>\n                                <p className=\"text-text-secondary text-xs\">to {mockEmail.to.split('<')[0].trim()}</p>\n                             </div>\n                        </div>\n                    </div>\n                    {/* Body */}\n                    <div className=\"flex-grow p-4 overflow-y-auto\">\n                        <pre className=\"whitespace-pre-wrap font-sans text-sm\">{mockEmail.body}</pre>\n                    </div>\n                    {/* Actions */}\n                    <div className=\"flex-shrink-0 p-4 border-t border-border bg-gray-50 dark:bg-slate-900/50 flex justify-between items-center\">\n                        <div className=\"text-xs text-text-secondary\">\n                            <strong>Disclaimer:</strong> This is a simulation. The requested scopes allow this app to read the current email and compose replies <strong>if it were running inside Gmail.</strong>\n                        </div>\n                        <button onClick={handleGenerateReply} disabled={isGenerating} className=\"btn-primary flex items-center justify-center gap-2 px-4 py-2\">\n                           <SparklesIcon /> AI Reply\n                        </button>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/IamPolicyGenerator.tsx': `import React, { useState, useCallback } from 'react';\nimport { generateIamPolicyStream } from '../../services/aiService.ts';\nimport { ShieldCheckIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nexport const IamPolicyGenerator: React.FC = () => {\n    const [description, setDescription] = useState('A user role that can read from S3 buckets but not write or delete.');\n    const [platform, setPlatform] = useState<'aws' | 'gcp'>('aws');\n    const [policy, setPolicy] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleGenerate = useCallback(async () => {\n        if (!description.trim()) {\n            setError('Please provide a description.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setPolicy('');\n        try {\n            const stream = generateIamPolicyStream(description, platform);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setPolicy(fullResponse);\n            }\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unknown error occurred.');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [description, platform]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <ShieldCheckIcon />\n                    <span className=\"ml-3\">IAM Policy Generator</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Generate AWS or GCP IAM policies from a natural language description.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"flex flex-col gap-4\">\n                     <div>\n                        <label htmlFor=\"platform\" className=\"text-sm font-medium mb-2 block\">Cloud Platform</label>\n                        <div className=\"flex gap-2 p-1 bg-surface rounded-lg border\">\n                            <button onClick={() => setPlatform('aws')} className={\\`flex-1 py-2 rounded-md text-sm \\${platform === 'aws' ? 'bg-primary text-text-on-primary' : ''}\\`}>AWS</button>\n                            <button onClick={() => setPlatform('gcp')} className={\\`flex-1 py-2 rounded-md text-sm \\${platform === 'gcp' ? 'bg-primary text-text-on-primary' : ''}\\`}>GCP</button>\n                        </div>\n                    </div>\n                    <div className=\"flex flex-col flex-1 min-h-0\">\n                        <label htmlFor=\"description\" className=\"text-sm font-medium mb-2\">Describe the desired permissions</label>\n                        <textarea id=\"description\" value={description} onChange={e => setDescription(e.target.value)} className=\"flex-grow p-2 bg-surface border rounded text-sm\"/>\n                    </div>\n                    <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary w-full py-3\">{isLoading ? <LoadingSpinner/> : 'Generate Policy'}</button>\n                </div>\n                <div className=\"flex flex-col\">\n                    <label className=\"text-sm font-medium mb-2\">Generated Policy (JSON)</label>\n                    <div className=\"flex-grow p-1 bg-background border rounded overflow-auto\">\n                        {isLoading && !policy && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"text-red-500 p-4\">{error}</p>}\n                        {policy && <MarkdownRenderer content={policy} />}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/IamPolicyVisualizer.tsx': `import React, { useState, useCallback, useMemo } from 'react';\nimport { testIamPermissions } from '../../services/gcpService.ts';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\nimport { GcpIcon, SparklesIcon, XMarkIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\ntype SimulationStatus = 'idle' | 'running' | 'completed' | 'error';\ntype NodeStatus = 'neutral' | 'pending' | 'success' | 'fail' | 'partial';\n\ninterface ResourceNode {\n    id: string; // The full resource name\n    name: string;\n    type: 'project' | 'bucket' | 'instance' | 'unknown';\n    status: NodeStatus;\n    results?: { permission: string; granted: boolean }[];\n}\n\nconst COMMON_ROLES = {\n    'Viewer': ['resourcemanager.projects.get', 'storage.objects.list', 'compute.instances.list'],\n    'Editor': ['storage.objects.create', 'storage.objects.delete', 'compute.instances.start', 'compute.instances.stop'],\n    'Storage Object Admin': ['storage.objects.create', 'storage.objects.delete', 'storage.objects.get', 'storage.objects.list', 'storage.objects.update'],\n};\n\nconst getResourceType = (resourceId: string): ResourceNode['type'] => {\n    if (resourceId.includes('/projects/')) return 'project';\n    if (resourceId.includes('/b/')) return 'bucket';\n    if (resourceId.includes('/instances/')) return 'instance';\n    return 'unknown';\n};\n\nexport const IamPolicyVisualizer: React.FC = () => {\n    const { state } = useGlobalState();\n    const [resources, setResources] = useState<ResourceNode[]>([]);\n    const [newResource, setNewResource] = useState('//cloudresourcemanager.googleapis.com/projects/your-gcp-project-id');\n    const [permissions, setPermissions] = useState('storage.objects.get\\\\nstorage.objects.create');\n    const [simulationStatus, setSimulationStatus] = useState<SimulationStatus>('idle');\n    const [error, setError] = useState('');\n    const [selectedNode, setSelectedNode] = useState<ResourceNode | null>(null);\n\n    const permissionList = useMemo(() => permissions.split('\\\\n').map(p => p.trim()).filter(Boolean), [permissions]);\n\n    const handleAddResource = () => {\n        if (newResource.trim() && !resources.find(r => r.id === newResource)) {\n            setResources(prev => [...prev, {\n                id: newResource,\n                name: newResource.split('/').pop() || newResource,\n                type: getResourceType(newResource),\n                status: 'neutral',\n            }]);\n            setNewResource('');\n        }\n    };\n\n    const handleRunSimulation = useCallback(async () => {\n        if (!state.user) {\n            setError('You must be signed in to run a simulation.');\n            return;\n        }\n        if (resources.length === 0 || permissionList.length === 0) {\n            setError('Please add at least one resource and one permission.');\n            return;\n        }\n\n        setSimulationStatus('running');\n        setError('');\n        setSelectedNode(null);\n        setResources(r => r.map(res => ({ ...res, status: 'pending', results: [] })));\n\n        const promises = resources.map(resource =>\n            testIamPermissions(resource.id, permissionList)\n                .then(result => ({ id: resource.id, success: true, data: result }))\n                .catch(err => ({ id: resource.id, success: false, error: err }))\n        );\n\n        const results = await Promise.allSettled(promises);\n\n        setResources(prevResources => prevResources.map(resource => {\n            const result: any = results.find((r: any) => r.value?.id === resource.id);\n            if (!result || !result.value.success) {\n                return { ...resource, status: 'fail' as NodeStatus };\n            }\n            \n            const grantedPermissions = result.value.data.permissions || [];\n            const permissionResults = permissionList.map(p => ({ permission: p, granted: grantedPermissions.includes(p) }));\n            const allGranted = permissionResults.every(r => r.granted);\n            const noneGranted = permissionResults.every(r => !r.granted);\n\n            let status: NodeStatus = 'partial';\n            if (allGranted) status = 'success';\n            if (noneGranted) status = 'fail';\n\n            return { ...resource, status, results: permissionResults };\n        }));\n\n        setSimulationStatus('completed');\n\n    }, [resources, permissionList, state.user]);\n    \n    const nodeColorClass: Record<NodeStatus, string> = {\n        neutral: 'border-slate-600',\n        pending: 'border-yellow-500 animate-pulse',\n        success: 'border-green-500',\n        fail: 'border-red-500',\n        partial: 'border-orange-500',\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary bg-background\">\n            {selectedNode && (\n                <div className=\"fixed inset-0 bg-black/60 z-50 flex items-center justify-center\" onClick={() => setSelectedNode(null)}>\n                    <div className=\"bg-surface rounded-lg shadow-xl p-6 w-full max-w-lg animate-pop-in\" onClick={e => e.stopPropagation()}>\n                        <h3 className=\"text-lg font-bold truncate\">{selectedNode.name}</h3>\n                        <p className=\"text-xs text-text-secondary font-mono mb-4\">{selectedNode.id}</p>\n                        <ul className=\"space-y-2 max-h-96 overflow-y-auto\">\n                            {selectedNode.results?.map(res => (\n                                <li key={res.permission} className={\\`flex items-center justify-between p-2 rounded text-sm \\${res.granted ? 'bg-green-500/10' : 'bg-red-500/10'}\\`}>\n                                    <span className=\"font-mono\">{res.permission}</span>\n                                    <span className={\\`font-bold \\${res.granted ? 'text-green-500' : 'text-red-500'}\\`}>{res.granted ? 'GRANTED' : 'DENIED'}</span>\n                                </li>\n                            ))}\n                        </ul>\n                    </div>\n                </div>\n            )}\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><GcpIcon /><span className=\"ml-3\">GCP IAM Policy Visualizer</span></h1><p className=\"text-text-secondary mt-1\">Visually test and audit GCP IAM permissions in real-time across your resources.</p></header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-3 gap-6 min-h-0\">\n                <aside className=\"lg:col-span-1 bg-surface p-4 rounded-lg border border-border flex flex-col gap-4\">\n                    <h3 className=\"text-xl font-bold\">Simulation Controls</h3>\n                    <div><label className=\"text-sm font-semibold\">1. Add Resource</label><div className=\"flex gap-1 mt-1\"><input value={newResource} onChange={e => setNewResource(e.target.value)} placeholder=\"Full GCP resource name...\" className=\"flex-grow p-2 bg-background border rounded text-xs\" /><button onClick={handleAddResource} className=\"btn-primary px-3 text-sm\">+</button></div></div>\n                    <div><label className=\"text-sm font-semibold\">2. Define Permission Set</label><select onChange={e => setPermissions(COMMON_ROLES[e.target.value as keyof typeof COMMON_ROLES]?.join('\\\\n') || '')} className=\"w-full mt-1 p-2 bg-background border rounded text-xs mb-1\"><option>Load common role...</option>{Object.keys(COMMON_ROLES).map(r => <option key={r}>{r}</option>)}</select><textarea value={permissions} onChange={e => setPermissions(e.target.value)} placeholder=\"One permission per line...\" className=\"w-full h-32 p-2 bg-background border rounded text-xs font-mono\"/></div>\n                    <button onClick={handleRunSimulation} disabled={simulationStatus === 'running'} className=\"btn-primary py-3 flex items-center justify-center gap-2\"><SparklesIcon /> {simulationStatus === 'running' ? 'Simulating...' : 'Run Simulation'}</button>\n                    {error && <p className=\"text-red-500 text-xs text-center\">{error}</p>}\n                </aside>\n                <main className=\"lg:col-span-2 bg-gray-50 dark:bg-slate-900/50 rounded-lg p-4 border-2 border-dashed border-border overflow-auto relative\">\n                    <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4\">\n                        {resources.map(res => (\n                            <div key={res.id} onClick={() => res.results && setSelectedNode(res)} className={\\`p-4 bg-surface rounded-lg border-4 transition-colors duration-500 \\${nodeColorClass[res.status]} \\${res.results ? 'cursor-pointer hover:scale-105' : ''}\\`}>\n                                <h4 className=\"font-bold truncate\">{res.name}</h4>\n                                <p className=\"text-xs text-text-secondary capitalize\">{res.type}</p>\n                            </div>\n                        ))}\n                    </div>\n                    {resources.length === 0 && <div className=\"absolute inset-0 flex items-center justify-center text-text-secondary\">Add resources to begin your simulation.</div>}\n                </main>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/JsonTreeNavigator.tsx': `import React, { useState } from 'react';\nimport { FileCodeIcon } from '../icons.tsx';\n\ninterface JsonNodeProps {\n    data: any;\n    nodeKey: string;\n    isRoot?: boolean;\n}\n\nconst JsonNode: React.FC<JsonNodeProps> = ({ data, nodeKey, isRoot = false }) => {\n    const [isOpen, setIsOpen] = useState(isRoot);\n    const isObject = typeof data === 'object' && data !== null;\n\n    const toggleOpen = () => setIsOpen(!isOpen);\n\n    if (!isObject) {\n        return (\n            <div className=\"ml-4 pl-4 border-l border-border\">\n                <span className=\"text-purple-700\">{nodeKey}: </span>\n                <span className={typeof data === 'string' ? 'text-green-700' : 'text-orange-700'}>\n                    {typeof data === 'string' ? \\`\"\\${data}\"\\` : String(data)}\n                </span>\n            </div>\n        );\n    }\n\n    const entries = Object.entries(data);\n    const bracket = Array.isArray(data) ? '[]' : '{}';\n\n    return (\n        <div className={\\`ml-4 \\${!isRoot ? 'pl-4 border-l border-border' : ''}\\`}>\n            <button onClick={toggleOpen} className=\"flex items-center cursor-pointer hover:bg-gray-100 rounded px-1\">\n                <span className={\\`transform transition-transform \\${isOpen ? 'rotate-90' : 'rotate-0'}\\`}>▶</span>\n                <span className=\"ml-1 text-purple-700\">{nodeKey}:</span>\n                <span className=\"ml-2 text-text-secondary\">{bracket[0]}</span>\n                {!isOpen && <span className=\"text-text-secondary\">...{bracket[1]}</span>}\n            </button>\n            {isOpen && (\n                <div>\n                    {entries.map(([key, value]) => (\n                        <JsonNode key={key} nodeKey={key} data={value} />\n                    ))}\n                    <div className=\"text-text-secondary ml-4\">{bracket[1]}</div>\n                </div>\n            )}\n        </div>\n    );\n};\n\nexport const JsonTreeNavigator: React.FC<{ initialData?: object }> = ({ initialData }) => {\n    const defaultJson = '{\\\\n  \"id\": \"devcore-001\",\\\\n  \"active\": true,\\\\n  \"features\": [\\\\n    \"ai-explainer\",\\\\n    \"api-tester\"\\\\n  ],\\\\n  \"config\": {\\\\n    \"theme\": \"dark\",\\\\n    \"version\": 1\\\\n  }\\\\n}';\n    const [jsonInput, setJsonInput] = useState(initialData ? JSON.stringify(initialData, null, 2) : defaultJson);\n    const [parsedData, setParsedData] = useState<any>(() => {\n        try {\n            return JSON.parse(jsonInput);\n        } catch {\n            return null;\n        }\n    });\n    const [error, setError] = useState('');\n\n    const parseJson = (input: string) => {\n        try {\n            const parsed = JSON.parse(input);\n            setParsedData(parsed);\n            setError('');\n        } catch (e) {\n            if (e instanceof Error) setError(e.message);\n            setParsedData(null);\n        }\n    };\n\n    const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n        setJsonInput(e.target.value);\n        parseJson(e.target.value);\n    }\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <FileCodeIcon />\n                    <span className=\"ml-3\">JSON Tree Navigator</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Paste your JSON data to visualize it as a collapsible tree.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col h-2/5 min-h-[200px]\">\n                    <label htmlFor=\"json-input\" className=\"text-sm font-medium text-text-secondary mb-2\">JSON Input</label>\n                    <textarea\n                        id=\"json-input\"\n                        value={jsonInput}\n                        onChange={handleInputChange}\n                        className={\\`flex-grow p-4 bg-surface border \\${error ? 'border-red-500' : 'border-border'} rounded-md resize-y font-mono text-sm focus:ring-2 focus:ring-primary focus:outline-none\\`}\n                    />\n                    {error && <p className=\"text-red-500 text-xs mt-1\">{error}</p>}\n                </div>\n                 <div className=\"flex flex-col flex-grow min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Tree View</label>\n                    <div className=\"flex-grow p-4 bg-surface border border-border rounded-md overflow-y-auto font-mono text-sm\">\n                        {parsedData ? <JsonNode data={parsedData} nodeKey=\"root\" isRoot /> : <div className=\"text-text-secondary\">Enter valid JSON to view</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/LogicFlowBuilder.tsx': `import React, { useState, useRef, useMemo, useCallback } from 'react';\nimport { ALL_FEATURES } from './index.ts';\nimport { FEATURE_TAXONOMY } from '../../services/taxonomyService.ts';\nimport { generatePipelineCode } from '../../services/aiService.ts';\nimport type { Feature } from '../../types.ts';\nimport { MapIcon, SparklesIcon, XMarkIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\ninterface Node {\n    id: number;\n    featureId: string;\n    x: number;\n    y: number;\n}\n\ninterface Link {\n    from: number;\n    to: number;\n}\n\nconst featuresMap = new Map(ALL_FEATURES.map(f => [f.id, f]));\nconst taxonomyMap = new Map(FEATURE_TAXONOMY.map(f => [f.id, f]));\n\nconst FeaturePaletteItem: React.FC<{ feature: Feature, onDragStart: (e: React.DragEvent, featureId: string) => void }> = ({ feature, onDragStart }) => (\n    <div\n        draggable\n        onDragStart={e => onDragStart(e, feature.id)}\n        className=\"p-3 rounded-md bg-gray-50 border border-border flex items-center gap-3 cursor-grab hover:bg-gray-100 transition-colors\"\n    >\n        <div className=\"text-primary flex-shrink-0\">{feature.icon}</div>\n        <div>\n            <h4 className=\"font-bold text-sm text-text-primary\">{feature.name}</h4>\n            <p className=\"text-xs text-text-secondary\">{feature.category}</p>\n        </div>\n    </div>\n);\n\nconst NodeComponent: React.FC<{\n    node: Node;\n    feature: Feature;\n    onMouseDown: (e: React.MouseEvent, id: number) => void;\n    onLinkStart: (e: React.MouseEvent, id: number) => void;\n    onLinkEnd: (e: React.MouseEvent, id: number) => void;\n}> = ({ node, feature, onMouseDown, onLinkStart, onLinkEnd }) => (\n    <div\n        className=\"absolute w-52 bg-surface rounded-lg shadow-md border-2 border-border cursor-grab active:cursor-grabbing flex flex-col\"\n        style={{ left: node.x, top: node.y, transform: 'translate(-50%, -50%)' }}\n        onMouseDown={e => onMouseDown(e, node.id)}\n        onMouseUp={e => onLinkEnd(e, node.id)}\n    >\n        <div className=\"p-2 flex items-center gap-2 border-b border-border\">\n            <div className=\"w-5 h-5 text-primary\">{feature.icon}</div>\n            <span className=\"text-sm font-semibold truncate text-text-primary\">{feature.name}</span>\n        </div>\n        <div className=\"relative p-3 text-xs text-text-secondary min-h-[40px] flex items-center justify-center\">\n            Workflow Node\n            <div\n                onMouseDown={e => onLinkStart(e, node.id)}\n                className=\"absolute right-[-9px] top-1/2 -translate-y-1/2 w-4 h-4 bg-primary rounded-full border-2 border-surface cursor-crosshair hover:scale-125 transition-transform\"\n                title=\"Drag to connect\"\n            />\n        </div>\n    </div>\n);\n\nconst SVGGrid: React.FC = React.memo(() => (\n    <svg width=\"100%\" height=\"100%\" className=\"absolute inset-0\">\n        <defs>\n            <pattern id=\"smallGrid\" width=\"10\" height=\"10\" patternUnits=\"userSpaceOnUse\">\n                <path d=\"M 10 0 L 0 0 0 10\" fill=\"none\" stroke=\"rgba(0, 0, 0, 0.05)\" strokeWidth=\"0.5\"/>\n            </pattern>\n            <pattern id=\"grid\" width=\"50\" height=\"50\" patternUnits=\"userSpaceOnUse\">\n                <rect width=\"50\" height=\"50\" fill=\"url(#smallGrid)\"/>\n                <path d=\"M 50 0 L 0 0 0 50\" fill=\"none\" stroke=\"rgba(0, 0, 0, 0.1)\" strokeWidth=\"1\"/>\n            </pattern>\n        </defs>\n        <rect width=\"100%\" height=\"100%\" fill=\"url(#grid)\" />\n    </svg>\n));\n\nexport const LogicFlowBuilder: React.FC = () => {\n    const [nodes, setNodes] = useState<Node[]>([]);\n    const [links, setLinks] = useState<Link[]>([]);\n    const [draggingNode, setDraggingNode] = useState<{ id: number; offsetX: number; offsetY: number } | null>(null);\n    const [linking, setLinking] = useState<{ from: number; fromPos: { x: number; y: number }; toPos: { x: number; y: number } } | null>(null);\n    const [generatedCode, setGeneratedCode] = useState('');\n    const [isGenerating, setIsGenerating] = useState(false);\n    const canvasRef = useRef<HTMLDivElement>(null);\n    \n    const handleGenerateCode = useCallback(async () => {\n        setIsGenerating(true);\n        setGeneratedCode('');\n        \n        const sortedNodeIds: number[] = [];\n        const inDegree = new Map<number, number>();\n        nodes.forEach(node => inDegree.set(node.id, 0));\n        links.forEach(link => inDegree.set(link.to, (inDegree.get(link.to) || 0) + 1));\n        \n        const queue = nodes.filter(node => inDegree.get(node.id) === 0).map(n => n.id);\n        \n        while(queue.length > 0) {\n            const u = queue.shift()!;\n            sortedNodeIds.push(u);\n            links.filter(l => l.from === u).forEach(l => {\n                inDegree.set(l.to, (inDegree.get(l.to) || 0) - 1);\n                if(inDegree.get(l.to) === 0) queue.push(l.to);\n            })\n        }\n        \n        const flowDescription = sortedNodeIds.map((id, index) => {\n            const node = nodes.find(n => n.id === id)!;\n            const featureInfo = taxonomyMap.get(node.featureId);\n            return \\`Step \\${index + 1}: Execute the '\\${featureInfo?.name}' tool. Description: \\${featureInfo?.description}. Inputs: \\${featureInfo?.inputs}.\\`;\n        }).join('\\\\n');\n\n        try {\n            const code = await generatePipelineCode(flowDescription);\n            setGeneratedCode(code);\n        } catch (e) {\n            setGeneratedCode(\\`// Error generating code: \\${e instanceof Error ? e.message : 'Unknown error'}\\`);\n        } finally {\n            setIsGenerating(false);\n        }\n\n    }, [nodes, links]);\n\n    const handleDragStart = (e: React.DragEvent, featureId: string) => {\n        e.dataTransfer.setData('application/json', JSON.stringify({ featureId }));\n    };\n\n    const handleDrop = (e: React.DragEvent) => {\n        e.preventDefault();\n        if (!canvasRef.current) return;\n        const { featureId } = JSON.parse(e.dataTransfer.getData('application/json'));\n        const canvasRect = canvasRef.current.getBoundingClientRect();\n        const newNode: Node = {\n            id: Date.now(),\n            featureId,\n            x: e.clientX - canvasRect.left,\n            y: e.clientY - canvasRect.top,\n        };\n        setNodes(prev => [...prev, newNode]);\n    };\n\n    const handleNodeMouseDown = (e: React.MouseEvent, id: number) => {\n        const node = nodes.find(n => n.id === id);\n        if (!node || (e.target as HTMLElement).title === 'Drag to connect') return;\n        const canvasRect = canvasRef.current!.getBoundingClientRect();\n        setDraggingNode({ id, offsetX: e.clientX - canvasRect.left - node.x, offsetY: e.clientY - canvasRect.top - node.y });\n    };\n\n    const handleCanvasMouseMove = (e: React.MouseEvent) => {\n        if (!canvasRef.current) return;\n        const canvasRect = canvasRef.current.getBoundingClientRect();\n        const mouseX = e.clientX - canvasRect.left;\n        const mouseY = e.clientY - canvasRect.top;\n\n        if (draggingNode) {\n            setNodes(nodes.map(n => n.id === draggingNode.id ? { ...n, x: mouseX - draggingNode.offsetX, y: mouseY - draggingNode.offsetY } : n));\n        }\n        if (linking) {\n            setLinking({ ...linking, toPos: { x: mouseX, y: mouseY } });\n        }\n    };\n\n    const handleCanvasMouseUp = () => {\n        setDraggingNode(null);\n        setLinking(null);\n    };\n\n    const handleLinkStart = (e: React.MouseEvent, id: number) => {\n        e.stopPropagation();\n        const fromNode = nodes.find(n => n.id === id);\n        if (!fromNode) return;\n        setLinking({ from: id, fromPos: { x: fromNode.x, y: fromNode.y }, toPos: { x: fromNode.x, y: fromNode.y } });\n    };\n\n    const handleLinkEnd = (e: React.MouseEvent, id: number) => {\n        e.stopPropagation();\n        if (linking && linking.from !== id) {\n            setLinks(prev => [...prev, { from: linking.from, to: id }]);\n        }\n        setLinking(null);\n    };\n\n    const nodePositions = useMemo(() => new Map(nodes.map(n => [n.id, { x: n.x, y: n.y }])), [nodes]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex justify-between items-start\">\n                <div>\n                    <h1 className=\"text-3xl font-bold flex items-center\"><MapIcon /><span className=\"ml-3\">Logic Flow Builder</span></h1>\n                    <p className=\"text-text-secondary mt-1\">Visually build application logic flows and generate pipeline code.</p>\n                </div>\n                <button onClick={handleGenerateCode} disabled={isGenerating || nodes.length === 0} className=\"btn-primary flex items-center gap-2 px-4 py-2\">\n                    <SparklesIcon /> {isGenerating ? 'Generating...' : 'Generate Code'}\n                </button>\n            </header>\n            <div className=\"flex-grow flex gap-6 min-h-0\">\n                <aside className=\"w-72 flex-shrink-0 bg-surface border border-border p-4 rounded-lg flex flex-col\">\n                    <h3 className=\"font-bold mb-3 text-lg\">Features</h3>\n                    <div className=\"flex-grow overflow-y-auto space-y-3 pr-2\">\n                        {ALL_FEATURES.map(feature => <FeaturePaletteItem key={feature.id} feature={feature} onDragStart={handleDragStart} />)}\n                    </div>\n                </aside>\n                <main\n                    ref={canvasRef}\n                    className=\"flex-grow relative bg-background border-2 border-dashed border-border rounded-lg overflow-hidden\"\n                    onDrop={handleDrop}\n                    onDragOver={e => e.preventDefault()}\n                    onMouseMove={handleCanvasMouseMove}\n                    onMouseUp={handleCanvasMouseUp}\n                    onMouseLeave={handleCanvasMouseUp}\n                >\n                    <SVGGrid />\n                    <svg width=\"100%\" height=\"100%\" className=\"absolute inset-0 pointer-events-none\">\n                        {links.map((link, i) => {\n                            const fromNode = nodePositions.get(link.from);\n                            const toNode = nodePositions.get(link.to);\n                            if (!fromNode || !toNode) return null;\n                            return <line key={i} x1={fromNode.x} y1={fromNode.y} x2={toNode.x} y2={toNode.y} stroke=\"var(--color-primary)\" strokeWidth=\"2\" markerEnd=\"url(#arrow)\" />;\n                        })}\n                        {linking && <line x1={linking.fromPos.x} y1={linking.fromPos.y} x2={linking.toPos.x} y2={linking.toPos.y} stroke=\"var(--color-primary)\" strokeWidth=\"2\" strokeDasharray=\"5,5\" />}\n                        <defs><marker id=\"arrow\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"6\" markerHeight=\"6\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--color-primary)\" /></marker></defs>\n                    </svg>\n                    {nodes.map(node => {\n                        const feature = featuresMap.get(node.featureId);\n                        return feature ? <NodeComponent key={node.id} node={node} feature={feature} onMouseDown={handleNodeMouseDown} onLinkStart={handleLinkStart} onLinkEnd={handleLinkEnd} /> : null;\n                    })}\n                </main>\n            </div>\n            {(isGenerating || generatedCode) && (\n                <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center\" onClick={() => setGeneratedCode('')}>\n                    <div className=\"w-full max-w-3xl h-3/4 bg-surface border border-border rounded-lg shadow-2xl p-6 flex flex-col\" onClick={e => e.stopPropagation()}>\n                        <div className=\"flex justify-between items-center mb-4\">\n                            <h2 className=\"text-xl font-bold\">Generated Pipeline Code</h2>\n                            <button onClick={() => setGeneratedCode('')}><XMarkIcon/></button>\n                        </div>\n                        <div className=\"flex-grow bg-background border border-border rounded-md overflow-auto\">\n                            {isGenerating && !generatedCode ? <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div> : <MarkdownRenderer content={'\\`\\`\\`javascript\\\\n' + generatedCode + '\\\\n\\`\\`\\`'} />}\n                        </div>\n                    </div>\n                </div>\n            )}\n        </div>\n    );\n};`,\n  'components/features/MarkdownSlides.tsx': `\n\nimport React, { useState, useMemo, useEffect, useRef, useCallback } from 'react';\nimport { marked } from 'marked';\nimport { PhotoIcon } from '../icons.tsx';\n\nconst exampleMarkdown = \\`# Slide 1: Welcome\n\nThis is a slide deck generated from Markdown.\n\n- Use standard markdown syntax\n- Like lists, headers, and **bold** text.\n\n---\n\n# Slide 2: Features\n\nNavigate using the buttons below.\n\n\\\\\\`\\\\\\`\\\\\\`javascript\nconsole.log(\"Code blocks work too!\");\n\\\\\\`\\\\\\`\\\\\\`\n\n---\n\n# Slide 3: The End\n\nEasy to create and present.\n\\`;\n\nexport const MarkdownSlides: React.FC = () => {\n    const [markdown, setMarkdown] = useState(exampleMarkdown);\n    const [currentSlide, setCurrentSlide] = useState(0);\n    const [slideHtml, setSlideHtml] = useState<string | TrustedHTML>('');\n    const presentationRef = useRef<HTMLDivElement>(null);\n\n    const slides = useMemo(() => markdown.split(/^-{3,}\\\\s*\\$/m), [markdown]);\n\n    useEffect(() => {\n        const parse = async () => {\n            const currentSlideContent = slides[currentSlide] || '';\n            const html = await marked.parse(currentSlideContent);\n            setSlideHtml(html);\n        };\n        parse();\n    }, [slides, currentSlide]);\n\n    const goToNext = useCallback(() => setCurrentSlide(s => Math.min(s + 1, slides.length - 1)), [slides.length]);\n    const goToPrev = useCallback(() => setCurrentSlide(s => Math.max(s - 1, 0)), []);\n\n    const handleFullscreen = () => {\n        presentationRef.current?.requestFullscreen();\n    };\n    \n    useEffect(() => {\n        const handleKeyDown = (e: KeyboardEvent) => {\n            if (document.fullscreenElement === presentationRef.current) {\n                if (e.key === 'ArrowRight' || e.key === ' ') goToNext();\n                if (e.key === 'ArrowLeft') goToPrev();\n            }\n        };\n        document.addEventListener('keydown', handleKeyDown);\n        return () => document.removeEventListener('keydown', handleKeyDown);\n    }, [goToNext, goToPrev]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><PhotoIcon /><span className=\"ml-3\">Markdown to Slides</span></h1>\n                <p className=\"text-text-secondary mt-1\">Write markdown, present it as a slideshow. Use '---' to separate slides.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 h-full overflow-hidden\">\n                <div className=\"flex flex-col h-full\">\n                     <label htmlFor=\"md-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Markdown Editor</label>\n                     <textarea id=\"md-input\" value={markdown} onChange={e => setMarkdown(e.target.value)} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm focus:ring-2 focus:ring-primary focus:outline-none\"/>\n                </div>\n                 <div ref={presentationRef} className=\"flex flex-col h-full bg-surface fullscreen:bg-background border border-border rounded-md\">\n                    <div className=\"flex-shrink-0 flex justify-end items-center p-2 border-b border-border gap-2\">\n                        <button onClick={handleFullscreen} className=\"px-3 py-1 bg-gray-100 dark:bg-slate-700 rounded-md text-xs hover:bg-gray-200 dark:hover:bg-slate-600\">Fullscreen</button>\n                    </div>\n                    <div className=\"relative flex-grow flex flex-col justify-center items-center p-8 overflow-y-auto\">\n                        <div className=\"prose prose-lg max-w-none w-full\" dangerouslySetInnerHTML={{ __html: slideHtml }} />\n                         <button onClick={goToPrev} disabled={currentSlide === 0} className=\"absolute left-4 top-1/2 -translate-y-1/2 p-2 bg-gray-200/50 dark:bg-slate-700/50 rounded-full disabled:opacity-30 hover:bg-gray-300/50 dark:hover:bg-slate-600/50\">◀</button>\n                         <button onClick={goToNext} disabled={currentSlide === slides.length - 1} className=\"absolute right-4 top-1/2 -translate-y-1/2 p-2 bg-gray-200/50 dark:bg-slate-700/50 rounded-full disabled:opacity-30 hover:bg-gray-300/50 dark:hover:bg-slate-600/50\">▶</button>\n                         <div className=\"absolute bottom-4 right-4 text-xs bg-black/50 px-2 py-1 rounded-md text-white\">\n                            {currentSlide + 1} / {slides.length}\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/MetaTagEditor.tsx': `import React, { useState, useMemo } from 'react';\nimport { CodeBracketSquareIcon } from '../icons.tsx';\n\ninterface MetaData {\n    title: string;\n    description: string;\n    image: string;\n    url: string;\n}\n\nconst SocialCardPreview: React.FC<{ meta: MetaData }> = ({ meta }) => (\n    <div className=\"w-full max-w-md mx-auto bg-surface border border-border rounded-2xl overflow-hidden shadow-lg\">\n        <div className=\"h-52 bg-gray-100 flex items-center justify-center\">\n            {meta.image ? <img src={meta.image} alt=\"Preview\" className=\"w-full h-full object-cover\" onError={(e) => e.currentTarget.style.display='none'}/> : <span className=\"text-text-secondary\">Image Preview</span>}\n        </div>\n        <div className=\"p-4\">\n            <p className=\"text-xs text-text-secondary truncate\">{new URL(meta.url || 'https://example.com').hostname}</p>\n            <h3 className=\"font-bold text-text-primary truncate mt-1\">{meta.title || 'Your Title Here'}</h3>\n            <p className=\"text-sm text-text-secondary mt-1 line-clamp-2\">{meta.description || 'A concise description of your content will appear here.'}</p>\n        </div>\n    </div>\n);\n\nexport const MetaTagEditor: React.FC = () => {\n    const [meta, setMeta] = useState<MetaData>({\n        title: 'DevCore AI Toolkit', description: 'The ultimate toolkit for modern developers, powered by Gemini.',\n        image: 'https://storage.googleapis.com/maker-studio-project-images-prod/programming_power_on_a_laptop_3a8f0bb1_39a9_4c2b_81f0_a74551480f2c.png',\n        url: 'https://devcore.example.com'\n    });\n\n    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n        setMeta({ ...meta, [e.target.name]: e.target.value });\n    };\n\n    const generatedHtml = useMemo(() => {\n        return \\`<!-- Primary Meta Tags -->\n<title>\\${meta.title}</title>\n<meta name=\"title\" content=\"\\${meta.title}\" />\n<meta name=\"description\" content=\"\\${meta.description}\" />\n<!-- Open Graph / Facebook -->\n<meta property=\"og:type\" content=\"website\" />\n<meta property=\"og:url\" content=\"\\${meta.url}\" />\n<meta property=\"og:title\" content=\"\\${meta.title}\" />\n<meta property=\"og:description\" content=\"\\${meta.description}\" />\n<meta property=\"og:image\" content=\"\\${meta.image}\" />\n<!-- Twitter -->\n<meta property=\"twitter:card\" content=\"summary_large_image\" />\n<meta property=\"twitter:url\" content=\"\\${meta.url}\" />\n<meta property=\"twitter:title\" content=\"\\${meta.title}\" />\n<meta property=\"twitter:description\" content=\"\\${meta.description}\" />\n<meta property=\"twitter:image\" content=\"\\${meta.image}\" />\\`;\n    }, [meta]);\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><CodeBracketSquareIcon /><span className=\"ml-3\">Meta Tag Editor</span></h1><p className=\"text-text-secondary mt-1\">Generate SEO & social media meta tags with a live preview.</p></header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6 min-h-0\">\n                <div className=\"xl:col-span-1 flex flex-col gap-4 bg-surface border border-border p-6 rounded-lg overflow-y-auto\">\n                    <h3 className=\"text-xl font-bold\">Metadata</h3>\n                    <div><label className=\"block text-sm\">Title</label><input type=\"text\" name=\"title\" value={meta.title} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                    <div><label className=\"block text-sm\">Description</label><input type=\"text\" name=\"description\" value={meta.description} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                    <div><label className=\"block text-sm\">Canonical URL</label><input type=\"text\" name=\"url\" value={meta.url} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                    <div><label className=\"block text-sm\">Social Image URL</label><input type=\"text\" name=\"image\" value={meta.image} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                </div>\n                <div className=\"xl:col-span-1 flex flex-col\">\n                     <label className=\"text-sm font-medium text-text-secondary mb-2\">Generated HTML</label>\n                     <div className=\"relative flex-grow\"><pre className=\"w-full h-full bg-background p-4 rounded-md text-primary text-sm overflow-auto\">{generatedHtml}</pre><button onClick={() => navigator.clipboard.writeText(generatedHtml)} className=\"absolute top-2 right-2 px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy</button></div>\n                </div>\n                 <div className=\"hidden xl:flex flex-col items-center justify-center\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Live Preview</label>\n                    <SocialCardPreview meta={meta} />\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/NetworkVisualizer.tsx': `import React, { useState, useEffect, useMemo } from 'react';\nimport { ChartBarIcon } from '../icons.tsx';\n\ntype SortKey = 'name' | 'initiatorType' | 'transferSize' | 'duration';\ntype SortDirection = 'asc' | 'desc';\n\nconst SummaryCard: React.FC<{ title: string, value: string | number }> = ({ title, value }) => (\n    <div className=\"bg-surface border border-border p-3 rounded-lg text-center\">\n        <p className=\"text-xs text-text-secondary\">{title}</p>\n        <p className=\"text-xl font-bold text-text-primary\">{value}</p>\n    </div>\n);\n\nexport const NetworkVisualizer: React.FC = () => {\n    const [requests, setRequests] = useState<PerformanceResourceTiming[]>([]);\n    const [sortKey, setSortKey] = useState<SortKey>('duration');\n    const [sortDirection, setSortDirection] = useState<SortDirection>('desc');\n\n    useEffect(() => {\n        const entries = performance.getEntriesByType(\"resource\") as PerformanceResourceTiming[];\n        setRequests(entries);\n    }, []);\n    \n    const sortedRequests = useMemo(() => {\n        return [...requests].sort((a, b) => {\n            const valA = a[sortKey];\n            const valB = b[sortKey];\n            if (valA < valB) return sortDirection === 'asc' ? -1 : 1;\n            if (valA > valB) return sortDirection === 'asc' ? 1 : -1;\n            return 0;\n        });\n    }, [requests, sortKey, sortDirection]);\n\n    const { totalSize, totalDuration, maxDuration } = useMemo(() => {\n        const totalSize = requests.reduce((acc, req) => acc + req.transferSize, 0);\n        const maxFinish = Math.max(...requests.map(r => r.startTime + r.duration), 0);\n        return { totalSize, totalDuration: maxFinish, maxDuration: Math.max(...requests.map(r => r.duration), 0) };\n    }, [requests]);\n\n    const handleSort = (key: SortKey) => {\n        setSortDirection(sortKey === key && sortDirection === 'desc' ? 'asc' : 'desc');\n        setSortKey(key);\n    };\n    \n    const formatBytes = (bytes: number) => {\n        if (bytes === 0) return '0 B';\n        const k = 1024; const sizes = ['B', 'KB', 'MB'];\n        const i = Math.floor(Math.log(bytes) / Math.log(k));\n        return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];\n    };\n\n    const SortableHeader: React.FC<{ skey: SortKey, label: string; className?: string }> = ({ skey, label, className }) => (\n        <th onClick={() => handleSort(skey)} className={\\`p-2 text-left cursor-pointer hover:bg-gray-100 \\${className}\\`}>\n            {label} {sortKey === skey && (sortDirection === 'asc' ? '▲' : '▼')}\n        </th>\n    );\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><ChartBarIcon /><span className=\"ml-3\">Network Visualizer</span></h1><p className=\"text-text-secondary mt-1\">Inspect network resources with a summary and waterfall chart.</p></header>\n            <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4 mb-4\">\n                <SummaryCard title=\"Total Requests\" value={requests.length} />\n                <SummaryCard title=\"Total Transferred\" value={formatBytes(totalSize)} />\n                <SummaryCard title=\"Finish Time\" value={\\`\\${totalDuration.toFixed(0)}ms\\`} />\n                <SummaryCard title=\"Longest Request\" value={\\`\\${maxDuration.toFixed(0)}ms\\`} />\n            </div>\n            <div className=\"flex-grow overflow-auto bg-surface rounded-lg border border-border\">\n                <table className=\"w-full text-sm text-left table-fixed\">\n                    <thead className=\"sticky top-0 bg-surface z-10\"><tr className=\"border-b border-border\">\n                        <SortableHeader skey=\"name\" label=\"Name\" className=\"w-2/5\"/>\n                        <SortableHeader skey=\"initiatorType\" label=\"Type\" className=\"w-1/5\" />\n                        <SortableHeader skey=\"transferSize\" label=\"Size\" className=\"w-1/5\"/>\n                        <SortableHeader skey=\"duration\" label=\"Time / Waterfall\" className=\"w-1/5\"/>\n                    </tr></thead>\n                    <tbody>{sortedRequests.map((req, i) => (<tr key={i} className=\"border-b border-border hover:bg-gray-50\">\n                        <td className=\"p-2 text-primary truncate\" title={req.name}>{req.name.split('/').pop()}</td>\n                        <td className=\"p-2\">{req.initiatorType}</td>\n                        <td className=\"p-2\">{formatBytes(req.transferSize)}</td>\n                        <td className=\"p-2\"><div className=\"flex items-center\">\n                            <span className=\"w-12\">{req.duration.toFixed(0)}ms</span>\n                            <div className=\"flex-grow h-4 bg-gray-200 rounded overflow-hidden\">\n                                <div className=\"h-4 bg-primary rounded\" style={{ marginLeft: \\`\\${(req.startTime / totalDuration) * 100}%\\`, width: \\`\\${(req.duration / totalDuration) * 100}%\\` }} title={\\`Start: \\${req.startTime.toFixed(0)}ms\\`}></div>\n                            </div>\n                        </div></td>\n                    </tr>))}</tbody>\n                </table>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/OneClickRefactor.tsx': `import React, { useState, useCallback } from 'react';\nimport * as Diff from 'diff';\nimport { applySpecificRefactor, refactorForPerformance, refactorForReadability, generateJsDoc, convertToFunctionalComponent } from '../../services/aiService.ts';\nimport { SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\ntype RefactorAction = 'readability' | 'performance' | 'jsdoc' | 'functional' | 'custom';\n\nconst exampleCode = \\`const MyComponent = ({ data }) => {\n  // A less readable component\n  let transformedData = [];\n  for (let i = 0; i < data.length; i++) {\n    if (data[i].value > 50) {\n      let item = { ...data[i], status: 'high' };\n      transformedData.push(item);\n    }\n  }\n  return (\n    <div>\n      {transformedData.map(d => <p key={d.id}>{d.name}</p>)}\n    </div>\n  );\n}\\`;\n\nconst DiffViewer: React.FC<{ oldCode: string, newCode: string }> = ({ oldCode, newCode }) => {\n    const diff = Diff.diffLines(oldCode, newCode);\n\n    return (\n        <pre className=\"whitespace-pre-wrap font-mono text-xs\">\n            {diff.map((part, index) => {\n                const color = part.added ? 'bg-green-500/20' : part.removed ? 'bg-red-500/20' : 'bg-transparent';\n                return <div key={index} className={color}>{part.value}</div>;\n            })}\n        </pre>\n    );\n};\n\n\nexport const OneClickRefactor: React.FC = () => {\n    const [code, setCode] = useState(exampleCode);\n    const [refactoredCode, setRefactoredCode] = useState('');\n    const [loadingAction, setLoadingAction] = useState<RefactorAction | null>(null);\n\n    const handleRefactor = useCallback(async (action: RefactorAction) => {\n        if (!code.trim()) return;\n        setLoadingAction(action);\n        setRefactoredCode('');\n\n        let stream;\n        switch(action) {\n            case 'readability':\n                stream = refactorForReadability(code);\n                break;\n            case 'performance':\n                stream = refactorForPerformance(code);\n                break;\n            case 'jsdoc':\n                stream = generateJsDoc(code);\n                break;\n            case 'functional':\n                stream = convertToFunctionalComponent(code);\n                break;\n            default:\n                setLoadingAction(null);\n                return;\n        }\n\n        try {\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setRefactoredCode(fullResponse.replace(/^\\`\\`\\`(?:\\\\w+\\\\n)?/, '').replace(/\\`\\`\\`\\$/, ''));\n            }\n        } catch (e) {\n            console.error(e);\n            setRefactoredCode(\\`// Error during refactoring: \\${e instanceof Error ? e.message : 'Unknown error'}\\`);\n        } finally {\n            setLoadingAction(null);\n        }\n    }, [code]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <SparklesIcon />\n                    <span className=\"ml-3\">One-Click Refactor</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Apply common refactoring patterns to your code with a single click.</p>\n            </header>\n            <div className=\"flex items-center justify-center flex-wrap gap-2 mb-4 p-4 bg-surface rounded-lg border border-border\">\n                <button onClick={() => handleRefactor('readability')} disabled={!!loadingAction} className=\"btn-primary px-3 py-1.5 text-sm\">{loadingAction === 'readability' ? <LoadingSpinner/> : 'Improve Readability'}</button>\n                <button onClick={() => handleRefactor('performance')} disabled={!!loadingAction} className=\"btn-primary px-3 py-1.5 text-sm\">{loadingAction === 'performance' ? <LoadingSpinner/> : 'Boost Performance'}</button>\n                <button onClick={() => handleRefactor('jsdoc')} disabled={!!loadingAction} className=\"btn-primary px-3 py-1.5 text-sm\">{loadingAction === 'jsdoc' ? <LoadingSpinner/> : 'Add JSDoc'}</button>\n                <button onClick={() => handleRefactor('functional')} disabled={!!loadingAction} className=\"btn-primary px-3 py-1.5 text-sm\">{loadingAction === 'functional' ? <LoadingSpinner/> : 'To Functional Component'}</button>\n            </div>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"flex flex-col\">\n                    <label className=\"text-sm font-medium mb-2\">Original Code</label>\n                    <textarea value={code} onChange={e => setCode(e.target.value)} className=\"flex-grow p-2 bg-surface border rounded font-mono text-xs\"/>\n                </div>\n                 <div className=\"flex flex-col\">\n                    <label className=\"text-sm font-medium mb-2\">Refactored Code</label>\n                    <div className=\"flex-grow p-2 bg-background border rounded overflow-auto\">\n                        {loadingAction ? <div className=\"flex justify-center items-center h-full\"><LoadingSpinner/></div> : <DiffViewer oldCode={code} newCode={refactoredCode} />}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/PerformanceProfiler.tsx': `import React, { useState, useCallback } from 'react';\nimport { analyzePerformanceTrace } from '../../services/index.ts';\nimport { startTracing, stopTracing, TraceEntry } from '../../services/profiling/performanceService.ts';\nimport { parseViteStats, BundleStatsNode } from '../../services/profiling/bundleAnalyzer.ts';\nimport { ChartBarIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nconst FlameChart: React.FC<{ trace: TraceEntry[] }> = ({ trace }) => {\n    if (trace.length === 0) return <p className=\"text-text-secondary\">No trace data collected.</p>;\n    const maxTime = Math.max(...trace.map(t => t.startTime + t.duration));\n    return (\n        <div className=\"space-y-1 font-mono text-xs\">\n            {trace.filter(t => t.entryType === 'measure').map((entry, i) => (\n                <div key={i} className=\"group relative h-6 bg-primary/20 rounded\">\n                    <div className=\"h-full bg-primary\" style={{ marginLeft: \\`\\${(entry.startTime / maxTime) * 100}%\\`, width: \\`\\${(entry.duration / maxTime) * 100}%\\` }}></div>\n                    <div className=\"absolute inset-0 px-2 flex items-center text-primary font-bold\">{entry.name} ({entry.duration.toFixed(1)}ms)</div>\n                </div>\n            ))}\n        </div>\n    );\n};\n\nexport const PerformanceProfiler: React.FC = () => {\n    const [activeTab, setActiveTab] = useState<'runtime' | 'bundle'>('runtime');\n    const [isTracing, setIsTracing] = useState(false);\n    const [trace, setTrace] = useState<TraceEntry[]>([]);\n    const [bundleStats, setBundleStats] = useState<string>('');\n    const [bundleTree, setBundleTree] = useState<BundleStatsNode | null>(null);\n    const [isLoadingAi, setIsLoadingAi] = useState(false);\n    const [aiAnalysis, setAiAnalysis] = useState('');\n\n    const handleTraceToggle = () => {\n        if (isTracing) {\n            const collectedTrace = stopTracing();\n            setTrace(collectedTrace);\n            setIsTracing(false);\n        } else {\n            setTrace([]);\n            startTracing();\n            setIsTracing(true);\n        }\n    };\n\n    const handleAnalyzeBundle = () => {\n        try {\n            setBundleTree(parseViteStats(bundleStats));\n        } catch (e) {\n            alert(e instanceof Error ? e.message : 'Parsing failed.');\n        }\n    };\n    \n    const handleAiAnalysis = async () => {\n        const dataToAnalyze = activeTab === 'runtime' ? trace : bundleTree;\n        if (!dataToAnalyze || (Array.isArray(dataToAnalyze) && dataToAnalyze.length === 0)) {\n            alert('No data to analyze.');\n            return;\n        }\n        setIsLoadingAi(true);\n        setAiAnalysis('');\n        try {\n            const analysis = await analyzePerformanceTrace(dataToAnalyze);\n            setAiAnalysis(analysis);\n        } catch (e) {\n            setAiAnalysis('Error getting analysis from AI.');\n        } finally {\n            setIsLoadingAi(false);\n        }\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><ChartBarIcon /><span className=\"ml-3\">AI Performance Profiler</span></h1><p className=\"text-text-secondary mt-1\">Analyze runtime performance and bundle sizes with AI insights.</p></header>\n            <div className=\"flex border-b border-border mb-4\"><button onClick={() => setActiveTab('runtime')} className={\\`px-4 py-2 text-sm \\${activeTab === 'runtime' ? 'border-b-2 border-primary' : ''}\\`}>Runtime Performance</button><button onClick={() => setActiveTab('bundle')} className={\\`px-4 py-2 text-sm \\${activeTab === 'bundle' ? 'border-b-2 border-primary' : ''}\\`}>Bundle Analysis</button></div>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"bg-surface p-4 border border-border rounded-lg flex flex-col\">\n                    {activeTab === 'runtime' ? (\n                        <>\n                            <button onClick={handleTraceToggle} className=\"btn-primary mb-4 py-2\">{isTracing ? 'Stop Tracing' : 'Start Tracing'}</button>\n                            <div className=\"flex-grow overflow-y-auto\"><FlameChart trace={trace} /></div>\n                        </>\n                    ) : (\n                         <>\n                            <textarea value={bundleStats} onChange={e => setBundleStats(e.target.value)} placeholder=\"Paste your stats.json content here\" className=\"w-full h-48 p-2 bg-background border rounded font-mono text-xs mb-2\"/>\n                            <button onClick={handleAnalyzeBundle} className=\"btn-primary py-2\">Analyze Bundle</button>\n                            <div className=\"flex-grow overflow-y-auto mt-2\">\n                                <pre className=\"text-xs\">{bundleTree ? JSON.stringify(bundleTree, null, 2) : 'Analysis will appear here.'}</pre>\n                            </div>\n                        </>\n                    )}\n                </div>\n                 <div className=\"bg-surface p-4 border border-border rounded-lg flex flex-col\">\n                    <button onClick={handleAiAnalysis} disabled={isLoadingAi} className=\"btn-primary flex items-center justify-center gap-2 py-2 mb-4\"><SparklesIcon />{isLoadingAi ? 'Analyzing...' : 'Get AI Optimization Suggestions'}</button>\n                    <div className=\"flex-grow bg-background border border-border rounded p-2 overflow-y-auto\">\n                        {isLoadingAi ? <div className=\"flex justify-center items-center h-full\"><LoadingSpinner/></div> : <MarkdownRenderer content={aiAnalysis} />}\n                    </div>\n                 </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/PrGenerator.tsx': `// This feature is an alias for the more comprehensively named AiPullRequestAssistant.\n// Re-exporting it here to keep the codebase DRY while satisfying the feature registry.\nexport { AiPullRequestAssistant as PrGenerator } from './AiPullRequestAssistant.tsx';`,\n  'components/features/PrSummaryGenerator.tsx': `// This feature is an alias for the more comprehensively named AiPullRequestAssistant.\n// Re-exporting it here to keep the codebase DRY while satisfying the feature registry.\nexport { AiPullRequestAssistant as PrSummaryGenerator } from './AiPullRequestAssistant.tsx';`,\n  'components/features/ProjectExplorer.tsx': `import React, { useState, useEffect, useCallback } from 'react';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { useOctokit } from '../../contexts/OctokitContext.tsx';\nimport { getRepos, getRepoTree, getFileContent, commitFiles } from '../../services/githubService.ts';\nimport { generateCommitMessageStream } from '../../services/index.ts';\nimport type { Repo, FileNode } from '../../types.ts';\nimport { FolderIcon, DocumentIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport * as Diff from 'diff';\n\nconst FileTree: React.FC<{ node: FileNode, onFileSelect: (path: string, name: string) => void, activePath: string | null }> = ({ node, onFileSelect, activePath }) => {\n    const [isOpen, setIsOpen] = useState(true);\n\n    if (node.type === 'file') {\n        const isActive = activePath === node.path;\n        return (\n            <div\n                className={\\`flex items-center space-x-2 pl-4 py-1 cursor-pointer rounded \\${isActive ? 'bg-primary/10 text-primary' : 'hover:bg-gray-100 dark:hover:bg-slate-700'}\\`}\n                onClick={() => onFileSelect(node.path, node.name)}\n            >\n                <DocumentIcon />\n                <span>{node.name}</span>\n            </div>\n        );\n    }\n\n    return (\n        <div>\n            <div\n                className=\"flex items-center space-x-2 py-1 cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-700 rounded\"\n                onClick={() => setIsOpen(!isOpen)}\n            >\n                <div className={\\`transform transition-transform \\${isOpen ? 'rotate-90' : ''}\\`}>▶</div>\n                <FolderIcon />\n                <span className=\"font-semibold\">{node.name}</span>\n            </div>\n            {isOpen && node.children && (\n                <div className=\"pl-4 border-l border-border ml-3\">\n                    {node.children.map(child => <FileTree key={child.path} node={child} onFileSelect={onFileSelect} activePath={activePath} />)}\n                </div>\n            )}\n        </div>\n    );\n};\n\nexport const ProjectExplorer: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const { user, githubUser, selectedRepo, projectFiles } = state;\n    const { addNotification } = useNotification();\n    const { octokit, reinitialize } = useOctokit();\n    const [repos, setRepos] = useState<Repo[]>([]);\n    const [isLoading, setIsLoading] = useState<'repos' | 'tree' | 'file' | 'commit' | null>(null);\n    const [error, setError] = useState('');\n    const [activeFile, setActiveFile] = useState<{ path: string; name: string; originalContent: string; editedContent: string} | null>(null);\n    \n    const handleApiError = useCallback((err: any) => {\n        if (err.status === 401) {\n            dispatch({ type: 'SET_GITHUB_USER', payload: null });\n            addNotification('GitHub token is invalid or expired. Please update it in the Connections Hub.', 'error');\n            setError('GitHub authentication failed. Please update your token.');\n        } else {\n            setError(err instanceof Error ? err.message : 'An unexpected error occurred.');\n        }\n    }, [dispatch, addNotification]);\n    \n    useEffect(() => {\n        if (!octokit && githubUser) {\n            reinitialize();\n        }\n    }, [octokit, githubUser, reinitialize]);\n\n    useEffect(() => {\n        const loadRepos = async () => {\n            if (user && githubUser && octokit) {\n                setIsLoading('repos');\n                setError('');\n                try {\n                    const userRepos = await getRepos(octokit);\n                    setRepos(userRepos);\n                } catch (err) {\n                    handleApiError(err);\n                } finally {\n                    setIsLoading(null);\n                }\n            } else {\n                setRepos([]);\n            }\n        };\n        loadRepos();\n    }, [user, githubUser, octokit, handleApiError]);\n\n    const loadTree = useCallback(async (repoToLoad: { owner: { login: string }, name: string, full_name: string }) => {\n        if (user && githubUser && octokit) {\n            setIsLoading('tree');\n            setError('');\n            setActiveFile(null);\n            try {\n                const tree = await getRepoTree(octokit, repoToLoad.owner.login, repoToLoad.name);\n                dispatch({ type: 'LOAD_PROJECT_FILES', payload: tree });\n            } catch (err) {\n                handleApiError(err);\n            } finally {\n                setIsLoading(null);\n            }\n        }\n    }, [user, githubUser, octokit, dispatch, handleApiError]);\n\n    // Re-fetches the tree if a repo is selected from a previous session\n    useEffect(() => {\n        if (selectedRepo && octokit && (!projectFiles || projectFiles.name !== selectedRepo.repo)) {\n             loadTree({\n                name: selectedRepo.repo,\n                full_name: selectedRepo.full_name,\n                owner: { login: selectedRepo.owner }\n            });\n        }\n    }, [selectedRepo, projectFiles, octokit, loadTree]);\n\n    const handleFileSelect = async (path: string, name: string) => {\n        if (!selectedRepo || !octokit) return;\n        setIsLoading('file');\n        try {\n            const content = await getFileContent(octokit, selectedRepo.owner, selectedRepo.repo, path);\n            setActiveFile({ path, name, originalContent: content, editedContent: content });\n        } catch (err) {\n            handleApiError(err);\n        } finally {\n            setIsLoading(null);\n        }\n    };\n\n    const handleCommit = async () => {\n        if (!activeFile || !selectedRepo || !octokit || activeFile.originalContent === activeFile.editedContent) return;\n\n        setIsLoading('commit');\n        setError('');\n        try {\n            const diff = Diff.createPatch(activeFile.path, activeFile.originalContent, activeFile.editedContent);\n            \n            const stream = generateCommitMessageStream(diff);\n            let commitMessage = '';\n            for await (const chunk of stream) { commitMessage += chunk; }\n            \n            const finalMessage = window.prompt(\"Confirm or edit commit message:\", commitMessage);\n            if (!finalMessage) {\n                setIsLoading(null);\n                return;\n            }\n\n            await commitFiles(\n                octokit,\n                selectedRepo.owner,\n                selectedRepo.repo,\n                [{ path: activeFile.path, content: activeFile.editedContent }],\n                finalMessage\n            );\n            \n            addNotification(\\`Successfully committed to \\${selectedRepo.repo}\\`, 'success');\n            setActiveFile(prev => prev ? { ...prev, originalContent: prev.editedContent } : null);\n\n        } catch (err) {\n            handleApiError(err);\n        } finally {\n            setIsLoading(null);\n        }\n    };\n    \n    if (!user) {\n        return (\n            <div className=\"h-full flex flex-col items-center justify-center text-center text-text-secondary p-4\">\n                <FolderIcon />\n                <h2 className=\"text-lg font-semibold mt-2\">Please Sign In</h2>\n                <p>Sign in to explore your repositories.</p>\n            </div>\n        );\n    }\n    \n    if (!githubUser) {\n         return (\n            <div className=\"h-full flex flex-col items-center justify-center text-center text-text-secondary p-4\">\n                <FolderIcon />\n                <h2 className=\"text-lg font-semibold mt-2\">Connect to GitHub</h2>\n                <p>Please go to the \"Connections\" tab and provide a Personal Access Token to explore your repositories.</p>\n            </div>\n        );\n    }\n\n    const hasChanges = activeFile ? activeFile.originalContent !== activeFile.editedContent : false;\n\n    return (\n        <div className=\"h-full flex flex-col text-text-primary\">\n            <header className=\"p-4 border-b border-border flex-shrink-0\">\n                <h1 className=\"text-xl font-bold flex items-center\"><FolderIcon /><span className=\"ml-3\">Project Explorer</span></h1>\n                <div className=\"mt-2\">\n                    <select\n                        value={selectedRepo?.full_name ?? ''}\n                        onChange={e => {\n                            const repo = repos.find(r => r.full_name === e.target.value);\n                            if (repo) {\n                                dispatch({ type: 'SET_SELECTED_REPO', payload: { owner: repo.owner.login, repo: repo.name, full_name: repo.full_name, name: repo.name } });\n                            }\n                        }}\n                        className=\"w-full p-2 bg-surface border border-border rounded-md text-sm\"\n                    >\n                        <option value=\"\" disabled>{isLoading === 'repos' ? 'Loading...' : 'Select a repository'}</option>\n                        {repos.map(r => <option key={r.id} value={r.full_name}>{r.full_name}</option>)}\n                    </select>\n                </div>\n                {error && <p className=\"text-red-500 text-xs mt-2\">{error}</p>}\n            </header>\n            <div className=\"flex-grow flex min-h-0\">\n                <aside className=\"w-1/3 bg-background border-r border-border p-4 overflow-y-auto\">\n                    {isLoading === 'tree' && <div className=\"flex justify-center\"><LoadingSpinner /></div>}\n                    {projectFiles && <FileTree node={projectFiles} onFileSelect={handleFileSelect} activePath={activeFile?.path ?? null} />}\n                </aside>\n                <main className=\"flex-1 bg-surface flex flex-col\">\n                     <div className=\"flex justify-between items-center p-2 border-b border-border bg-gray-50 dark:bg-slate-800\">\n                        <span className=\"text-sm font-semibold\">{activeFile?.name || 'No file selected'}</span>\n                        <button onClick={handleCommit} disabled={!hasChanges || isLoading === 'commit'} className=\"btn-primary px-4 py-1 text-sm flex items-center justify-center min-w-[100px]\">\n                           {isLoading === 'commit' ? <LoadingSpinner/> : 'Commit'}\n                        </button>\n                     </div>\n                     {isLoading === 'file' ? <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div> :\n                        <textarea \n                            value={activeFile?.editedContent ?? 'Select a file to view its content.'}\n                            onChange={e => setActiveFile(prev => prev ? { ...prev, editedContent: e.target.value } : null)}\n                            disabled={!activeFile}\n                            className=\"w-full h-full p-4 text-sm font-mono bg-transparent resize-none focus:outline-none\"\n                        />\n                    }\n                </main>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/ProjectMoodboard.tsx': `import React, { useState } from 'react';\nimport { PhotoIcon } from '../icons.tsx';\nimport { useLocalStorage } from '../../hooks/useLocalStorage.ts';\n\ninterface MoodboardItem {\n    id: number;\n    text: string;\n    x: number;\n    y: number;\n    color: string;\n}\n\nconst colors = ['bg-yellow-200', 'bg-green-200', 'bg-blue-200', 'bg-pink-200', 'bg-purple-200', 'bg-orange-200'];\nconst textColors = ['text-yellow-800', 'text-green-800', 'text-blue-800', 'text-pink-800', 'text-purple-800', 'text-orange-800'];\n\nexport const ProjectMoodboard: React.FC = () => {\n    const [items, setItems] = useLocalStorage<MoodboardItem[]>('devcore_moodboard_items', []);\n    const [dragging, setDragging] = useState<{ id: number; offsetX: number; offsetY: number } | null>(null);\n\n    const addItem = () => {\n        const newItem: MoodboardItem = {\n            id: Date.now(),\n            text: 'New Idea',\n            x: 50,\n            y: 50,\n            color: colors[items.length % colors.length],\n        };\n        setItems([...items, newItem]);\n    };\n    \n    const deleteItem = (id: number, e: React.MouseEvent) => {\n        e.stopPropagation();\n        setItems(items.filter((n) => n.id !== id));\n    };\n\n    const updateItem = (id: number, updates: Partial<MoodboardItem>) => {\n        setItems(items.map((n) => n.id === id ? { ...n, ...updates } : n));\n    };\n\n    const onMouseDown = (e: React.MouseEvent<HTMLDivElement>, id: number) => {\n        if ((e.target as HTMLElement).tagName === 'TEXTAREA') return;\n        const noteElement = e.currentTarget;\n        const rect = noteElement.getBoundingClientRect();\n        setDragging({ id, offsetX: e.clientX - rect.left, offsetY: e.clientY - rect.top });\n    };\n\n    const onMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n        if (!dragging) return;\n        const boardRect = e.currentTarget.getBoundingClientRect();\n        updateItem(dragging.id, {\n            x: e.clientX - dragging.offsetX - boardRect.left,\n            y: e.clientY - dragging.offsetY - boardRect.top\n        });\n    };\n\n    const onMouseUp = () => setDragging(null);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6 flex justify-between items-center\">\n                 <div>\n                    <h1 className=\"text-3xl font-bold flex items-center\"><PhotoIcon /><span className=\"ml-3\">Project Moodboard</span></h1>\n                    <p className=\"text-text-secondary mt-1\">A visual space to gather ideas, images, and notes.</p>\n                </div>\n                <button onClick={addItem} className=\"btn-primary px-6 py-2\">Add Item</button>\n            </header>\n            <div\n                className=\"relative flex-grow bg-background border-2 border-dashed border-border rounded-lg overflow-hidden\"\n                onMouseMove={onMouseMove} onMouseUp={onMouseUp} onMouseLeave={onMouseUp}\n            >\n                {items.map((item) => (\n                    <div\n                        key={item.id}\n                        className={\\`group absolute w-48 h-48 p-2 flex flex-col shadow-lg cursor-grab active:cursor-grabbing rounded-md transition-transform duration-100 border border-black/20 \\${item.color} \\${textColors[colors.indexOf(item.color)]}\\`}\n                        style={{ top: item.y, left: item.x, transform: dragging?.id === item.id ? 'scale(1.05)' : 'scale(1)' }}\n                        onMouseDown={e => onMouseDown(e, item.id)}\n                    >\n                        <button onClick={(e) => deleteItem(item.id, e)} className=\"absolute -top-2 -right-2 w-6 h-6 rounded-full bg-gray-700 text-white font-bold text-xs flex items-center justify-center opacity-0 group-hover:opacity-100 hover:bg-red-500 transition-all\">&times;</button>\n                        <textarea\n                            value={item.text}\n                            onChange={(e) => updateItem(item.id, { text: e.target.value })}\n                            className=\"w-full h-full bg-transparent resize-none focus:outline-none font-medium p-1\"\n                        />\n                    </div>\n                ))}\n            </div>\n        </div>\n    );\n};`,\n  'components/features/PromptCraftPad.tsx': `import React, { useState, useEffect, useMemo } from 'react';\nimport { SparklesIcon } from '../icons.tsx';\nimport { useLocalStorage } from '../../hooks/useLocalStorage.ts';\n\ninterface Prompt {\n    id: number;\n    name: string;\n    text: string;\n}\n\nexport const PromptCraftPad: React.FC = () => {\n    const [prompts, setPrompts] = useLocalStorage<Prompt[]>('devcore_prompts', [\n        { id: 1, name: 'React Component Generator', text: 'Generate a React component named {name} that {description}. Style it with Tailwind CSS.'}\n    ]);\n    const [activePrompt, setActivePrompt] = useState<Prompt | null>(prompts[0] || null);\n    const [editingId, setEditingId] = useState<number | null>(null);\n    const [tempName, setTempName] = useState('');\n    const [variables, setVariables] = useState<Record<string, string>>({});\n\n    const variableNames = useMemo(() => {\n        if (!activePrompt) return [];\n        return [...activePrompt.text.matchAll(/\\\\{(\\\\w+)\\\\}/g)].map(match => match[1]);\n    }, [activePrompt]);\n\n    const renderedPrompt = useMemo(() => {\n        if (!activePrompt) return '';\n        return variableNames.reduce((acc, varName) => {\n            return acc.replace(new RegExp(\\`\\\\\\\\{\\${varName}\\\\\\\\}\\`, 'g'), variables[varName] || \\`{\\${varName}}\\`);\n        }, activePrompt.text);\n    }, [activePrompt, variables, variableNames]);\n    \n    useEffect(() => {\n        if(!activePrompt && prompts.length > 0) setActivePrompt(prompts[0]);\n        if (activePrompt) setActivePrompt(prompts.find((p: Prompt) => p.id === activePrompt.id) || null);\n    }, [prompts, activePrompt]);\n\n    const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n        if (!activePrompt) return;\n        const updatedPrompt = { ...activePrompt, text: e.target.value };\n        setPrompts(prompts.map((p: Prompt) => p.id === updatedPrompt.id ? updatedPrompt : p));\n    };\n    \n    const handleNameUpdate = (id: number, newName: string) => {\n        setPrompts(prompts.map((p: Prompt) => p.id === id ? {...p, name: newName} : p));\n        setEditingId(null);\n    };\n\n    const handleAddNew = () => {\n        const newPrompt = { id: Date.now(), name: 'New Untitled Prompt', text: '' };\n        setPrompts([...prompts, newPrompt]);\n        setActivePrompt(newPrompt);\n    };\n    \n    const handleDelete = (id: number) => {\n        setPrompts(prompts.filter((p: Prompt) => p.id !== id));\n        if(activePrompt?.id === id) setActivePrompt(prompts.length > 1 ? prompts[0] : null);\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><SparklesIcon /><span className=\"ml-3\">Prompt Craft Pad</span></h1><p className=\"text-text-secondary mt-1\">Create, save, and manage your favorite AI prompts.</p></header>\n            <div className=\"flex-grow flex gap-6 min-h-0\">\n                <aside className=\"w-1/3 bg-surface border border-border p-4 rounded-lg flex flex-col\">\n                    <h3 className=\"font-bold mb-2\">My Prompts</h3>\n                    <ul className=\"space-y-2 flex-grow overflow-y-auto\">{prompts.map((p: Prompt) => (<li key={p.id} className=\"group flex items-center justify-between\"><div className={\\`w-full text-left rounded-md \\${activePrompt?.id === p.id ? 'bg-primary/10' : ''}\\`}><button onClick={() => setActivePrompt(p)} onDoubleClick={() => {setEditingId(p.id); setTempName(p.name);}} className={\\`w-full text-left px-3 py-2 \\${activePrompt?.id === p.id ? 'text-primary' : 'hover:bg-gray-100'}\\`}> {editingId === p.id ? <input autoFocus value={tempName} onChange={e => setTempName(e.target.value)} onBlur={() => handleNameUpdate(p.id, tempName)} onKeyDown={e => e.key === 'Enter' && handleNameUpdate(p.id, tempName)} className=\"bg-gray-100 text-text-primary w-full\"/> : p.name} </button></div><button onClick={() => handleDelete(p.id)} className=\"ml-2 p-1 text-text-secondary hover:text-red-500 opacity-0 group-hover:opacity-100\">&times;</button></li>))}</ul>\n                    <div className=\"mt-4 pt-4 border-t border-border\"><button onClick={handleAddNew} className=\"btn-primary w-full text-sm py-2\">Add New Prompt</button></div>\n                </aside>\n                <main className=\"w-2/3 flex flex-col gap-4\">\n                    {activePrompt ? (<>\n                        <textarea value={activePrompt.text} onChange={handleTextChange} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm focus:ring-2 focus:ring-primary focus:outline-none\"/>\n                        {variableNames.length > 0 && <div className=\"flex-shrink-0 bg-surface border border-border p-4 rounded-lg\"><h4 className=\"font-bold mb-2\">Test Variables</h4><div className=\"grid grid-cols-2 gap-2\">{variableNames.map(v => (<div key={v}><label className=\"text-xs\">{v}</label><input type=\"text\" value={variables[v] || ''} onChange={e => setVariables({...variables, [v]: e.target.value})} className=\"w-full bg-background border border-border px-2 py-1 rounded text-sm\"/></div>))}</div><h4 className=\"font-bold mt-4 mb-2\">Live Preview</h4><p className=\"text-sm p-2 bg-background rounded border border-border\">{renderedPrompt}</p></div>}\n                    </>) : (<div className=\"flex-grow flex items-center justify-center bg-background rounded-lg text-text-secondary border border-border\">Select a prompt or create a new one.</div>)}\n                </main>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/PwaManifestEditor.tsx': `import React, { useState, useMemo } from 'react';\nimport { CodeBracketSquareIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { downloadFile } from '../../services/fileUtils.ts';\n\ninterface ManifestData {\n    name: string;\n    short_name: string;\n    start_url: string;\n    scope: string;\n    display: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser';\n    orientation: 'any' | 'natural' | 'landscape' | 'portrait';\n    background_color: string;\n    theme_color: string;\n}\n\nconst HomeScreenPreview: React.FC<{ manifest: ManifestData }> = ({ manifest }) => (\n    <div className=\"w-full max-w-xs mx-auto flex flex-col items-center\">\n        <div className=\"w-72 h-[550px] bg-gray-800 rounded-[40px] border-[10px] border-black shadow-2xl p-4 flex flex-col\">\n            <div className=\"flex-shrink-0 h-6 flex justify-between items-center px-4\">\n                <span className=\"text-xs font-bold\" style={{color: manifest.theme_color}}>9:41</span>\n                <div className=\"w-16 h-4 bg-black rounded-full\" />\n                <span className=\"text-xs font-bold\" style={{color: manifest.theme_color}}>100%</span>\n            </div>\n            <div className=\"flex-grow grid grid-cols-4 gap-4 p-4\">\n                <div className=\"flex flex-col items-center gap-1\">\n                    <div className=\"w-14 h-14 bg-white rounded-xl flex items-center justify-center text-3xl\" style={{backgroundColor: manifest.background_color}}>\n                        <span style={{color: manifest.theme_color}}>{manifest.short_name[0]}</span>\n                    </div>\n                    <p className=\"text-xs text-center text-white truncate w-full\">{manifest.short_name}</p>\n                </div>\n            </div>\n        </div>\n         <p className=\"text-xs text-text-secondary mt-2 text-center\">Home Screen Preview</p>\n    </div>\n);\n\n\nexport const PwaManifestEditor: React.FC = () => {\n    const [manifest, setManifest] = useState<ManifestData>({\n        name: 'DevCore Progressive Web App', short_name: 'DevCore', start_url: '/', scope: '/',\n        display: 'standalone', orientation: 'any', background_color: '#F5F7FA', theme_color: '#0047AB',\n    });\n\n    const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {\n        setManifest({ ...manifest, [e.target.name]: e.target.value });\n    };\n\n    const generatedJson = useMemo(() => {\n        const fullManifest = { ...manifest, icons: [{\"src\": \"icon-192.png\", \"type\": \"image/png\", \"sizes\": \"192x192\"}, {\"src\": \"icon-512.png\", \"type\": \"image/png\", \"sizes\": \"512x512\"}] };\n        return JSON.stringify(fullManifest, null, 2);\n    }, [manifest]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><CodeBracketSquareIcon /><span className=\"ml-3\">PWA Manifest Editor</span></h1><p className=\"text-text-secondary mt-1\">Configure and generate the \\`manifest.json\\` file for your PWA.</p></header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6 min-h-0\">\n                <div className=\"xl:col-span-1 flex flex-col gap-4 bg-surface border border-border p-6 rounded-lg overflow-y-auto\">\n                    <h3 className=\"text-xl font-bold\">Configuration</h3>\n                    <div><label className=\"block text-sm\">App Name</label><input type=\"text\" name=\"name\" value={manifest.name} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                    <div><label className=\"block text-sm\">Short Name</label><input type=\"text\" name=\"short_name\" value={manifest.short_name} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                    <div><label className=\"block text-sm\">Start URL</label><input type=\"text\" name=\"start_url\" value={manifest.start_url} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                    <div><label className=\"block text-sm\">Scope</label><input type=\"text\" name=\"scope\" value={manifest.scope} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"/></div>\n                    <div><label className=\"block text-sm\">Display Mode</label><select name=\"display\" value={manifest.display} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"><option>standalone</option><option>fullscreen</option><option>minimal-ui</option><option>browser</option></select></div>\n                    <div><label className=\"block text-sm\">Orientation</label><select name=\"orientation\" value={manifest.orientation} onChange={handleChange} className=\"w-full mt-1 p-2 rounded bg-background border border-border\"><option>any</option><option>natural</option><option>landscape</option><option>portrait</option></select></div>\n                     <div className=\"flex gap-4\">\n                        <div className=\"w-1/2\"><label className=\"block text-sm\">Background Color</label><input type=\"color\" name=\"background_color\" value={manifest.background_color} onChange={handleChange} className=\"w-full mt-1 h-10 rounded bg-background border border-border\"/></div>\n                        <div className=\"w-1/2\"><label className=\"block text-sm\">Theme Color</label><input type=\"color\" name=\"theme_color\" value={manifest.theme_color} onChange={handleChange} className=\"w-full mt-1 h-10 rounded bg-background border border-border\"/></div>\n                     </div>\n                </div>\n                <div className=\"xl:col-span-1 flex flex-col\">\n                    <div className=\"flex justify-between items-center mb-2\">\n                         <label className=\"text-sm font-medium text-text-secondary\">Generated manifest.json</label>\n                         <button onClick={() => downloadFile(generatedJson, 'manifest.json', 'application/json')} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">\n                            <ArrowDownTrayIcon className=\"w-4 h-4\"/> Download\n                        </button>\n                    </div>\n                     <div className=\"relative flex-grow\"><pre className=\"w-full h-full bg-background p-4 rounded-md text-primary text-sm overflow-auto\">{generatedJson}</pre></div>\n                </div>\n                <div className=\"hidden xl:flex flex-col items-center justify-center\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Live Preview</label>\n                    <HomeScreenPreview manifest={manifest} />\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/RegexSandbox.tsx': `import React, { useState, useMemo, useCallback, useEffect } from 'react';\nimport { generateRegExStream } from '../../services/aiService.ts';\nimport { BeakerIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\nconst commonPatterns = [\n    { name: 'Email', pattern: '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\\\\\.[a-zA-Z]{2,}/g' },\n    { name: 'URL', pattern: '/https?:\\\\\\\\/\\\\\\\\/(www\\\\\\\\.)?[-a-zA-Z0-9@:%._\\\\\\\\+~#=]{1,256}\\\\\\\\.[a-zA-Z0-9()]{1,6}\\\\\\\\b([-a-zA-Z0-9()@:%_\\\\\\\\+.~#?&//=]*)/g' },\n    { name: 'IPv4 Address', pattern: '/((25[0-5]|(2[0-4]|1\\\\\\\\d|[1-9]|)\\\\\\\\d)\\\\\\\\.?\\\\\\\\b){4}/g' },\n    { name: 'Date (YYYY-MM-DD)', pattern: '/\\\\\\\\d{4}-\\\\\\\\d{2}-\\\\\\\\d{2}/g' },\n];\n\nconst CheatSheet = () => (\n    <div className=\"bg-surface border border-border p-4 rounded-lg\">\n        <h3 className=\"text-lg font-bold mb-2\">Regex Cheat Sheet</h3>\n        <div className=\"grid grid-cols-2 gap-x-4 gap-y-1 text-xs font-mono\">\n            <p><span className=\"text-primary\">.</span> - Any character</p>\n            <p><span className=\"text-primary\">\\\\d</span> - Any digit</p>\n            <p><span className=\"text-primary\">\\\\w</span> - Word character</p>\n            <p><span className=\"text-primary\">\\\\s</span> - Whitespace</p>\n            <p><span className=\"text-primary\">[abc]</span> - a, b, or c</p>\n            <p><span className=\"text-primary\">[^abc]</span> - Not a, b, or c</p>\n            <p><span className=\"text-primary\">*</span> - 0 or more</p>\n            <p><span className=\"text-primary\">+</span> - 1 or more</p>\n            <p><span className=\"text-primary\">?</span> - 0 or one</p>\n            <p><span className=\"text-primary\">^</span> - Start of string</p>\n            <p><span className=\"text-primary\">\\$</span> - End of string</p>\n            <p><span className=\"text-primary\">\\\\b</span> - Word boundary</p>\n        </div>\n    </div>\n);\n\nexport const RegexSandbox: React.FC<{ initialPrompt?: string }> = ({ initialPrompt }) => {\n    const [pattern, setPattern] = useState<string>('/\\\\\\\\b([A-Z][a-z]+)\\\\\\\\s(\\\\\\\\w+)\\\\\\\\b/g');\n    const [testString, setTestString] = useState<string>('The quick Brown Fox jumps over the Lazy Dog.');\n    const [aiPrompt, setAiPrompt] = useState<string>(initialPrompt || 'find capitalized words and the word after');\n    const [isAiLoading, setIsAiLoading] = useState<boolean>(false);\n\n    const { matches, error } = useMemo(() => {\n        try {\n            const patternParts = pattern.match(/^\\\\/(.*)\\\\/([gimyus]*)\\$/);\n            if (!patternParts) return { matches: null, error: 'Invalid regex literal. Use /pattern/flags.' };\n            const [, regexBody, regexFlags] = patternParts;\n            const regex = new RegExp(regexBody, regexFlags);\n            return { matches: [...testString.matchAll(regex)], error: null };\n        } catch (e) { return { matches: null, error: e instanceof Error ? e.message : 'Unknown error.' }; }\n    }, [pattern, testString]);\n    \n    const handleGenerateRegex = useCallback(async (p: string) => {\n        if (!p) return;\n        setIsAiLoading(true);\n        try {\n            const stream = generateRegExStream(p);\n            let fullResponse = '';\n            for await (const chunk of stream) { fullResponse += chunk; }\n            setPattern(fullResponse.trim().replace(/^\\`+|\\`+\\$/g, ''));\n        } finally { setIsAiLoading(false); }\n    }, []);\n\n    useEffect(() => { if (initialPrompt) handleGenerateRegex(initialPrompt); }, [initialPrompt, handleGenerateRegex]);\n\n    const highlightedString = useMemo(() => {\n        if (!matches || matches.length === 0 || error) return testString;\n        let lastIndex = 0;\n        const parts: (string | JSX.Element)[] = [];\n        matches.forEach((match, i) => {\n            if (match.index === undefined) return;\n            parts.push(testString.substring(lastIndex, match.index));\n            parts.push(<mark key={i} className=\"bg-primary/20 text-primary rounded px-1\">{match[0]}</mark>);\n            lastIndex = match.index + match[0].length;\n        });\n        parts.push(testString.substring(lastIndex));\n        return parts;\n    }, [matches, testString, error]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><BeakerIcon /><span className=\"ml-3\">RegEx Sandbox</span></h1><p className=\"text-text-secondary mt-1\">Test your regular expressions and generate them with AI.</p></header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-3 gap-6 min-h-0\">\n                <div className=\"lg:col-span-2 flex flex-col gap-4\">\n                    <div className=\"flex gap-2\"><input type=\"text\" value={aiPrompt} onChange={(e) => setAiPrompt(e.target.value)} placeholder=\"Describe the pattern to find...\" className=\"flex-grow px-3 py-1.5 rounded-md bg-surface border border-border text-sm focus:ring-2 focus:ring-primary\" /><button onClick={() => handleGenerateRegex(aiPrompt)} disabled={isAiLoading} className=\"btn-primary px-4 py-1.5 flex items-center\">{isAiLoading ? <LoadingSpinner/> : 'Generate'}</button></div>\n                    <div><label htmlFor=\"regex-pattern\" className=\"text-sm font-medium text-text-secondary\">Regular Expression</label><input id=\"regex-pattern\" type=\"text\" value={pattern} onChange={(e) => setPattern(e.target.value)} className={\\`w-full mt-1 px-3 py-2 rounded-md bg-surface border \\${error ? 'border-red-500' : 'border-border'} font-mono text-sm focus:ring-2 focus:ring-primary\\`} />{error && <p className=\"text-red-500 text-xs mt-1\">{error}</p>}</div>\n                    <div className=\"flex flex-col flex-grow min-h-0\"><label htmlFor=\"test-string\" className=\"text-sm font-medium text-text-secondary\">Test String</label><textarea id=\"test-string\" value={testString} onChange={(e) => setTestString(e.target.value)} className=\"w-full mt-1 p-3 rounded-md bg-surface border border-border font-mono text-sm resize-y h-32\" /><div className=\"mt-2 p-3 bg-background rounded-md border border-border min-h-[50px] whitespace-pre-wrap\">{highlightedString}</div></div>\n                    <div className=\"flex-shrink-0\"><h3 className=\"text-lg font-bold\">Match Groups ({matches?.length || 0})</h3><div className=\"mt-2 p-2 bg-surface rounded-md overflow-y-auto max-h-48 font-mono text-xs border border-border\">{matches && matches.length > 0 ? (matches.map((match, i) => (<details key={i} className=\"p-2 border-b border-border\"><summary className=\"cursor-pointer text-green-700\">Match {i + 1}: \"{match[0]}\"</summary><div className=\"pl-4 mt-1\">{Array.from(match).map((group, gIndex) => <p key={gIndex} className=\"text-text-secondary\">Group {gIndex}: <span className=\"text-amber-700\">{String(group)}</span></p>)}</div></details>))) : (<p className=\"text-text-secondary text-sm p-2\">No matches found.</p>)}</div></div>\n                </div>\n                <div className=\"lg:col-span-1 space-y-4\">\n                    <CheatSheet />\n                    <div className=\"bg-surface border border-border p-4 rounded-lg\">\n                        <h3 className=\"text-lg font-bold mb-2\">Common Patterns</h3>\n                        <div className=\"flex flex-col items-start gap-2\">\n                            {commonPatterns.map(p => (\n                                <button key={p.name} onClick={() => setPattern(p.pattern)} className=\"text-left text-sm text-primary hover:underline\">\n                                    {p.name}\n                                </button>\n                            ))}\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/ResponsiveTester.tsx': `import React, { useState, useEffect } from 'react';\nimport { EyeIcon } from '../icons.tsx';\n\nconst devices = {\n    'iPhone 12': { width: 390, height: 844 },\n    'Pixel 5': { width: 393, height: 851 },\n    'iPad Air': { width: 820, height: 1180 },\n    'Surface Duo': { width: 540, height: 720 },\n    'Laptop': { width: 1366, height: 768 },\n    'Desktop': { width: 1920, height: 1080 },\n    'Auto': { width: '100%', height: '100%' },\n};\n\ntype DeviceName = keyof typeof devices;\n\nexport const ResponsiveTester: React.FC = () => {\n    const [url, setUrl] = useState('https://react.dev');\n    const [displayUrl, setDisplayUrl] = useState(url);\n    const [size, setSize] = useState<{width: number | string, height: number | string}>(devices['Auto']);\n\n    useEffect(() => {\n        const handleResize = () => {\n            if (size.width === '100%') {\n                setSize({ width: '100%', height: '100%' });\n            }\n        };\n        window.addEventListener('resize', handleResize);\n        return () => window.removeEventListener('resize', handleResize);\n    }, [size.width]);\n\n    const handleUrlSubmit = (e: React.FormEvent) => {\n        e.preventDefault();\n        setDisplayUrl(url.startsWith('http') ? url : \\`https://\\${url}\\`);\n    };\n\n    const handleRotate = () => {\n        if(typeof size.width === 'number' && typeof size.height === 'number') {\n            setSize({ width: size.height, height: size.width });\n        }\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><EyeIcon /><span className=\"ml-3\">Responsive Tester</span></h1><p className=\"text-text-secondary mt-1\">Preview your web pages at different screen sizes.</p></header>\n            <form onSubmit={handleUrlSubmit} className=\"flex items-center gap-2 mb-2\">\n                <input type=\"text\" value={url} onChange={(e) => setUrl(e.target.value)} placeholder=\"https://example.com\" className=\"flex-grow px-4 py-2 rounded-md bg-surface border border-border focus:ring-2 focus:ring-primary focus:outline-none\"/>\n                <button type=\"submit\" className=\"btn-primary px-6 py-2\">Load</button>\n            </form>\n            <div className=\"bg-surface p-2 rounded-lg flex flex-wrap justify-center items-center gap-2 mb-4 border border-border\">\n                {Object.keys(devices).map(name => (\n                    <button key={name} onClick={() => setSize(devices[name as DeviceName])} className={\\`px-3 py-1 rounded-md text-sm \\${JSON.stringify(size) === JSON.stringify(devices[name as DeviceName]) ? 'bg-primary/10 text-primary font-semibold' : 'hover:bg-gray-100'}\\`}>{name}</button>\n                ))}\n                <div className=\"flex items-center gap-1 ml-4\">\n                    <input type=\"number\" value={typeof size.width === 'number' ? size.width : ''} onChange={e => setSize({ ...size, width: Number(e.target.value) })} className=\"w-20 px-2 py-1 bg-gray-100 border border-border rounded-md text-sm\"/>\n                    <span className=\"text-sm text-text-secondary\">x</span>\n                    <input type=\"number\" value={typeof size.height === 'number' ? size.height : ''} onChange={e => setSize({ ...size, height: Number(e.target.value) })} className=\"w-20 px-2 py-1 bg-gray-100 border border-border rounded-md text-sm\"/>\n                </div>\n                 <button onClick={handleRotate} className=\"px-3 py-1 rounded-md text-sm hover:bg-gray-100\" title=\"Rotate\">🔄</button>\n            </div>\n            <div className=\"flex-grow bg-background rounded-lg p-4 overflow-auto border border-border\">\n                <iframe key={displayUrl} src={displayUrl} style={{ width: size.width, height: size.height }} className=\"bg-white border-4 border-gray-300 rounded-md transition-all duration-300 shadow-lg mx-auto\" title=\"Responsive Preview\"/>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/SassScssCompiler.tsx': `import React, { useState, useMemo } from 'react';\nimport { CodeBracketSquareIcon } from '../icons.tsx';\n\nconst initialScss = \\`\\$primary-color: #0047AB;\n\\$font-size: 16px;\n\n.container {\n  padding: 20px;\n  background-color: #f0f0f0;\n\n  .title {\n    color: \\$primary-color;\n    font-size: \\$font-size * 1.5;\n\n    &:hover {\n      text-decoration: underline;\n    }\n  }\n  \n  > p {\n    margin-top: 10px;\n  }\n}\\`;\n\nconst escapeRegExp = (string: string): string => {\n    // \\$& means the whole matched string\n    return string.replace(/[.*+?^\\${}()|[\\\\]\\\\\\\\]/g, '\\\\\\\\\\$&');\n};\n\nconst compileScss = (scss: string): string => {\n    try {\n        let css = scss;\n        css = css.replace(/\\\\/\\\\/.*\\$/gm, '');\n        \n        const variables: Record<string, string> = {};\n        css = css.replace(/\\\\\\$([\\\\w-]+):\\\\s*(.*?);/g, (_, name, value) => {\n            variables[name] = value.trim(); return '';\n        });\n\n        for (let i = 0; i < 5; i++) {\n            Object.entries(variables).forEach(([name, value]) => {\n                css = css.replace(new RegExp(\\`\\\\\\\\\\$\\${escapeRegExp(name)}\\`, 'g'), value);\n            });\n        }\n        \n        css = css.replace(/([\\\\d.]+)(px|rem|em|%)\\\\s*([*\\\\/])\\\\s*([\\\\d.]+)/g, (_, n1, unit, op, n2) => {\n            const num1 = parseFloat(n1); const num2 = parseFloat(n2);\n            const result = op === '*' ? num1 * num2 : num1 / num2;\n            return \\`\\${result}\\${unit}\\`;\n        });\n\n        const processBlock = (block: string, parentSelector: string = ''): string => {\n            let currentCss = '';\n            let nestedCss = '';\n            const properties = [];\n            \n            const regex = /((?:[\\\\w-:.#&>+~*\\\\s,]+|\\\\([^)]*\\\\))\\\\s*\\\\{[^{}]*\\\\})|((?:[\\\\w-]+\\\\s*:[^;]+;))/g;\n            const content = block.substring(block.indexOf('{') + 1, block.lastIndexOf('}'));\n            let match;\n            while ((match = regex.exec(content)) !== null) {\n                if (match[1]) {\n                    const nestedSelector = match[1].substring(0, match[1].indexOf('{')).trim();\n                    const fullSelector = nestedSelector.includes('&') ? nestedSelector.replace(/&/g, parentSelector) : \\`\\${parentSelector} \\${nestedSelector}\\`.trim();\n                    nestedCss += processBlock(match[1], fullSelector);\n                } else if (match[2]) {\n                    properties.push(\\`  \\${match[2].trim()}\\`);\n                }\n            }\n            \n            if (properties.length > 0) {\n                currentCss = \\`\\${parentSelector} {\\\\n\\${properties.join('\\\\n')}\\\\n}\\\\n\\`;\n            }\n\n            return currentCss + nestedCss;\n        };\n        \n        let result = processBlock(\\`root{\\${css}}\\`, '').trim();\n        return result.replace(/root\\\\s*\\\\{\\\\s*\\\\}/, '').trim();\n\n    } catch(e) {\n        console.error(\"SCSS Compilation Error:\", e);\n        return \"/* Error compiling SCSS. Check console for details. */\";\n    }\n};\n\n\nexport const SassScssCompiler: React.FC = () => {\n    const [scss, setScss] = useState(initialScss);\n    const compiledCss = useMemo(() => compileScss(scss), [scss]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl flex items-center\"><CodeBracketSquareIcon /><span className=\"ml-3\">SASS/SCSS Compiler</span></h1>\n                <p className=\"text-text-secondary mt-1\">A real-time SASS/SCSS to CSS compiler.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"scss-input\" className=\"text-sm font-medium text-text-secondary mb-2\">SASS/SCSS Input</label>\n                    <textarea id=\"scss-input\" value={scss} onChange={(e) => setScss(e.target.value)} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-y font-mono text-sm text-pink-600\" spellCheck=\"false\" />\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Compiled CSS Output</label>\n                    <pre className=\"flex-grow p-4 bg-background border border-border rounded-md overflow-y-auto text-blue-700 font-mono text-sm whitespace-pre-wrap\">{compiledCss}</pre>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/SchemaDesigner.tsx': `import React, { useState, useRef } from 'react';\nimport { MapIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { downloadFile } from '../../services/fileUtils.ts';\n\ninterface Column { id: number; name: string; type: string; }\ninterface Table { id: number; name: string; columns: Column[]; x: number; y: number; }\n\nconst exportToSQL = (tables: Table[]) => {\n    return tables.map(table => {\n        const columnsSQL = table.columns.map(col => \\`  \"\\${col.name}\" \\${col.type.toUpperCase()}\\`).join(',\\\\n');\n        return \\`CREATE TABLE \"\\${table.name}\" (\\\\n\\${columnsSQL}\\\\n);\\`;\n    }).join('\\\\n\\\\n');\n};\n\nexport const SchemaDesigner: React.FC = () => {\n    const [tables, setTables] = useState<Table[]>([\n        { id: 1, name: 'users', columns: [{ id: 1, name: 'id', type: 'INTEGER PRIMARY KEY' }, {id: 2, name: 'username', type: 'VARCHAR(255)'}], x: 50, y: 50 },\n        { id: 2, name: 'posts', columns: [{ id: 1, name: 'id', type: 'INTEGER PRIMARY KEY' }, {id: 2, name: 'user_id', type: 'INTEGER'}, {id: 3, name: 'content', type: 'TEXT'}], x: 300, y: 100 },\n    ]);\n    const [dragging, setDragging] = useState<{ id: number; offsetX: number; offsetY: number } | null>(null);\n    const canvasRef = useRef<HTMLDivElement>(null);\n\n    const onMouseDown = (e: React.MouseEvent<HTMLDivElement>, id: number) => {\n        const tableElement = e.currentTarget;\n        const rect = tableElement.getBoundingClientRect();\n        setDragging({ id, offsetX: e.clientX - rect.left, offsetY: e.clientY - rect.top });\n    };\n\n    const onMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n        if (!dragging || !canvasRef.current) return;\n        const canvasRect = canvasRef.current.getBoundingClientRect();\n        setTables(tables.map(t => t.id === dragging.id ? { ...t, x: e.clientX - dragging.offsetX - canvasRect.left + canvasRef.current.scrollLeft, y: e.clientY - dragging.offsetY - canvasRect.top + canvasRef.current.scrollTop } : t));\n    };\n\n    const onMouseUp = () => setDragging(null);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><MapIcon /><span className=\"ml-3\">Schema Designer</span></h1><p className=\"text-text-secondary mt-1\">Visually design your database schema with drag-and-drop.</p></header>\n            <div className=\"flex-grow flex gap-6 min-h-0\">\n                <main ref={canvasRef} className=\"flex-grow relative bg-background rounded-lg border-2 border-dashed border-border overflow-auto\" onMouseMove={onMouseMove} onMouseUp={onMouseUp} onMouseLeave={onMouseUp}>\n                    {tables.map(table => (\n                        <div key={table.id} className={\\`absolute w-64 bg-surface rounded-lg shadow-xl border cursor-grab active:cursor-grabbing \\${dragging?.id === table.id ? 'border-primary' : 'border-border'}\\`} style={{ top: table.y, left: table.x }} onMouseDown={e => onMouseDown(e, table.id)}>\n                            <h3 className=\"font-bold text-primary text-lg p-2 bg-gray-50 rounded-t-lg border-b border-border\">{table.name}</h3>\n                            <div className=\"p-2 space-y-1 font-mono text-xs\">\n                                {table.columns.map(col => (<div key={col.id} className=\"flex justify-between items-center\"><span className=\"text-text-primary\">{col.name}</span><span className=\"text-text-secondary\">{col.type}</span></div>))}\n                            </div>\n                        </div>\n                    ))}\n                </main>\n                <aside className=\"w-80 flex-shrink-0 flex flex-col gap-4\">\n                    <div className=\"flex flex-col gap-2\">\n                         <button onClick={() => downloadFile(JSON.stringify(tables, null, 2), 'schema.json', 'application/json')} className=\"flex-1 text-sm py-2 bg-gray-100 border border-border rounded-md flex items-center justify-center gap-2 hover:bg-gray-200\">\n                            <ArrowDownTrayIcon className=\"w-4 h-4\"/> Download JSON\n                        </button>\n                         <button onClick={() => downloadFile(exportToSQL(tables), 'schema.sql', 'application/sql')} className=\"btn-primary flex-1 text-sm py-2 flex items-center justify-center gap-2\">\n                            <ArrowDownTrayIcon className=\"w-4 h-4\"/> Download SQL\n                         </button>\n                    </div>\n                    <div className=\"flex-grow bg-surface border border-border p-4 rounded-lg overflow-y-auto\">\n                        <h3 className=\"font-bold mb-2\">Editor</h3>\n                        <p className=\"text-xs text-text-secondary\">Schema editing coming soon!</p>\n                    </div>\n                </aside>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/ScreenshotToComponent.tsx': `import React, { useState, useCallback, useRef } from 'react';\nimport { generateComponentFromImageStream } from '../../services/index.ts';\nimport { PhotoIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\nimport { fileToBase64, blobToDataURL, downloadFile } from '../../services/fileUtils.ts';\n\nexport const ScreenshotToComponent: React.FC = () => {\n    const [previewImage, setPreviewImage] = useState<string | null>(null);\n    const [rawCode, setRawCode] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n    const fileInputRef = useRef<HTMLInputElement>(null);\n\n    const handleGenerate = async (base64Image: string) => {\n        setIsLoading(true);\n        setError('');\n        setRawCode('');\n        try {\n            const stream = generateComponentFromImageStream(base64Image);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setRawCode(fullResponse.replace(/^\\`\\`\\`(?:\\\\w+\\\\n)?/, '').replace(/\\`\\`\\`\\$/, ''));\n            }\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unknown error occurred.');\n        } finally {\n            setIsLoading(false);\n        }\n    };\n\n    const processImageBlob = async (blob: Blob) => {\n        try {\n            const [dataUrl, base64Image] = await Promise.all([blobToDataURL(blob), fileToBase64(blob as File)]);\n            setPreviewImage(dataUrl);\n            handleGenerate(base64Image);\n        } catch (e) {\n            setError('Could not process the image.');\n        }\n    };\n    \n    const handlePaste = useCallback(async (event: React.ClipboardEvent) => {\n        const items = event.clipboardData.items;\n        for (const item of items) {\n            if (item.type.indexOf('image') !== -1) {\n                const blob = item.getAsFile();\n                if (blob) await processImageBlob(blob);\n                return;\n            }\n        }\n    }, []);\n\n    const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {\n        const file = event.target.files?.[0];\n        if (file) await processImageBlob(file);\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><PhotoIcon /><span className=\"ml-3\">AI Screenshot-to-Component</span></h1><p className=\"text-text-secondary mt-1\">Paste or upload a screenshot of a UI element to generate React/Tailwind code.</p></header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div onPaste={handlePaste} className=\"flex flex-col items-center justify-center bg-surface p-6 rounded-lg border-2 border-dashed border-border focus:outline-none focus:border-primary overflow-y-auto\" tabIndex={0}>\n                    {previewImage ? (<img src={previewImage} alt=\"Pasted content\" className=\"max-w-full max-h-full object-contain rounded-md shadow-lg\" />) : (<div className=\"text-center text-text-secondary\">\n                            <h2 className=\"text-xl font-bold text-text-primary\">Paste an image here</h2>\n                            <p className=\"mb-2\">(Cmd/Ctrl + V)</p>\n                            <p className=\"text-sm\">or</p>\n                            <button onClick={() => fileInputRef.current?.click()} className=\"mt-2 btn-primary px-4 py-2 text-sm\">Upload File</button>\n                            <input type=\"file\" ref={fileInputRef} onChange={handleFileChange} accept=\"image/*\" className=\"hidden\"/>\n                        </div>)}\n                </div>\n                <div className=\"flex flex-col h-full\">\n                    <div className=\"flex justify-between items-center mb-2\">\n                        <label className=\"text-sm font-medium text-text-secondary\">Generated Code</label>\n                        {rawCode && !isLoading && (\n                            <div className=\"flex items-center gap-2\">\n                                <button onClick={() => navigator.clipboard.writeText(rawCode)} className=\"px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">Copy Code</button>\n                                <button onClick={() => downloadFile(rawCode, 'Component.tsx', 'text/typescript')} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">\n                                    <ArrowDownTrayIcon className=\"w-4 h-4\" /> Download\n                                </button>\n                            </div>\n                        )}\n                    </div>\n                    <div className=\"flex-grow bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && (<div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>)}\n                        {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                        {rawCode && !isLoading && <MarkdownRenderer content={\\`\\\\\\`\\\\\\`\\\\\\`tsx\\\\n\\${rawCode}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`} />}\n                        {!isLoading && !rawCode && !error && (<div className=\"text-text-secondary h-full flex items-center justify-center\">Generated component code will appear here.</div>)}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/SecurityScanner.tsx': `import React, { useState } from 'react';\nimport { analyzeCodeForVulnerabilities } from '../../services/aiService.ts';\nimport { runStaticScan, SecurityIssue } from '../../services/security/staticAnalysisService.ts';\nimport type { SecurityVulnerability } from '../../types.ts';\nimport { ShieldCheckIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleCode = \\`function UserProfile({ user }) {\n  // TODO: remove this temporary api key\n  const API_KEY = \"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx\";\n  const userContent = user.bio; // This might contain malicious scripts\n\n  return (\n    <div>\n      <h2>{user.name}</h2>\n      <div dangerouslySetInnerHTML={{ __html: userContent }} />\n    </div>\n  );\n}\\`;\n\nexport const SecurityScanner: React.FC = () => {\n    const [code, setCode] = useState(exampleCode);\n    const [localIssues, setLocalIssues] = useState<SecurityIssue[]>([]);\n    const [aiIssues, setAiIssues] = useState<SecurityVulnerability[]>([]);\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleScan = async () => {\n        if (!code.trim()) {\n            setError('Please enter code to scan.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setLocalIssues([]);\n        setAiIssues([]);\n        try {\n            // Run local scan first\n            const staticIssues = runStaticScan(code);\n            setLocalIssues(staticIssues);\n            \n            // Then run AI scan\n            const geminiIssues = await analyzeCodeForVulnerabilities(code);\n            setAiIssues(geminiIssues);\n\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An error occurred during scanning.');\n        } finally {\n            setIsLoading(false);\n        }\n    };\n\n    const SeverityBadge: React.FC<{ severity: string }> = ({ severity }) => {\n        const colors: Record<string, string> = {\n            'Critical': 'bg-red-500 text-white',\n            'High': 'bg-red-400 text-white',\n            'Medium': 'bg-yellow-400 text-yellow-900',\n            'Low': 'bg-blue-400 text-white',\n            'Informational': 'bg-gray-400 text-gray-900',\n        };\n        return <span className={\\`px-2 py-0.5 text-xs font-bold rounded-full \\${colors[severity] || 'bg-gray-300'}\\`}>{severity}</span>\n    }\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><ShieldCheckIcon /><span className=\"ml-3\">AI Security Co-Pilot</span></h1>\n                <p className=\"text-text-secondary mt-1\">Find vulnerabilities in your code with static analysis and AI.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"flex flex-col\">\n                    <label className=\"text-sm mb-2\">Code to Scan</label>\n                    <textarea value={code} onChange={e => setCode(e.target.value)} className=\"w-full flex-grow p-2 bg-surface border rounded font-mono text-xs\" />\n                    <button onClick={handleScan} disabled={isLoading} className=\"btn-primary w-full mt-4 py-2 flex justify-center items-center gap-2\">{isLoading ? <LoadingSpinner/> : 'Scan Code'}</button>\n                </div>\n                <div className=\"flex flex-col bg-surface p-4 border rounded-lg\">\n                    <h3 className=\"text-lg font-bold mb-2\">Scan Results</h3>\n                    {error && <p className=\"text-red-500\">{error}</p>}\n                    <div className=\"flex-grow overflow-y-auto pr-2 space-y-4\">\n                        {isLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner/></div>}\n                        {!isLoading && localIssues.length === 0 && aiIssues.length === 0 && <p className=\"text-text-secondary text-center mt-8\">No issues found. Run a scan to begin.</p>}\n                        \n                        {localIssues.length > 0 && <div>\n                            <h4 className=\"font-semibold text-sm mb-1\">Static Analysis Findings</h4>\n                            {localIssues.map((issue, i) => <div key={\\`local-\\${i}\\`} className=\"p-2 bg-background border rounded mb-2\"><p className=\"font-bold flex items-center gap-2\">{issue.type} <SeverityBadge severity={issue.severity} /></p><p className=\"text-xs\">Line {issue.line}: {issue.description}</p></div>)}\n                        </div>}\n\n                         {aiIssues.length > 0 && <div>\n                            <h4 className=\"font-semibold text-sm mb-1 flex items-center gap-1\"><SparklesIcon/> AI-Powered Findings</h4>\n                            {aiIssues.map((issue, i) => (\n                                <details key={\\`ai-\\${i}\\`} className=\"p-2 bg-background border rounded mb-2\">\n                                    <summary className=\"cursor-pointer font-bold flex items-center gap-2\">{issue.vulnerability} <SeverityBadge severity={issue.severity} /></summary>\n                                    <div className=\"mt-2 pt-2 border-t text-xs space-y-2\">\n                                        <p><strong>Description:</strong> {issue.description}</p>\n                                        <p><strong>Mitigation:</strong> {issue.mitigation}</p>\n                                        {issue.exploitSuggestion && (\n                                            <div>\n                                                <strong>Exploit Simulation:</strong>\n                                                <div className=\"mt-1 p-2 bg-gray-50 rounded\">\n                                                     <MarkdownRenderer content={'\\`\\`\\`bash\\\\n' + issue.exploitSuggestion + '\\\\n\\`\\`\\`'}/>\n                                                </div>\n                                            </div>\n                                        )}\n                                    </div>\n                                </details>\n                            ))}\n                        </div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/SnippetVault.tsx': `import React, { useState, useEffect, useMemo } from 'react';\nimport { LockClosedIcon, SparklesIcon, TrashIcon, ClipboardDocumentIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { useLocalStorage } from '../../hooks/useLocalStorage.ts';\nimport { enhanceSnippetStream, generateTagsForCode } from '../../services/aiService.ts';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { downloadFile } from '../../services/fileUtils.ts';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\n\ninterface Snippet {\n    id: number; name: string; code: string; language: string; tags: string[];\n}\n\nconst langToExt: Record<string, string> = {\n    javascript: 'js',\n    typescript: 'ts',\n    python: 'py',\n    css: 'css',\n    html: 'html',\n    json: 'json',\n    markdown: 'md',\n    plaintext: 'txt',\n};\n\nexport const SnippetVault: React.FC = () => {\n    const [snippets, setSnippets] = useLocalStorage<Snippet[]>('devcore_snippets', [{ id: 1, name: 'React Hook Boilerplate', language: 'javascript', code: \\`import { useState } from 'react';\\\\n\\\\nconst useCustomHook = () => {\\\\n  const [value, setValue] = useState(null);\\\\n  return { value, setValue };\\\\n};\\`, tags: ['react', 'hook'] }]);\n    const [activeSnippet, setActiveSnippet] = useState<Snippet | null>(null);\n    const [isEnhancing, setIsEnhancing] = useState(false);\n    const [searchTerm, setSearchTerm] = useState('');\n    const [isEditingName, setIsEditingName] = useState(false);\n    const { addNotification } = useNotification();\n\n    const filteredSnippets = useMemo(() => {\n        if (!searchTerm) return snippets;\n        const lowerSearch = searchTerm.toLowerCase();\n        return snippets.filter((s: Snippet) => \n            s.name.toLowerCase().includes(lowerSearch) || \n            s.code.toLowerCase().includes(lowerSearch) ||\n            (s.tags && s.tags.some(t => t.toLowerCase().includes(lowerSearch)))\n        );\n    }, [snippets, searchTerm]);\n\n    useEffect(() => {\n        if (!activeSnippet && filteredSnippets.length > 0) setActiveSnippet(filteredSnippets[0]);\n        if (activeSnippet) setActiveSnippet(snippets.find((s: Snippet) => s.id === activeSnippet.id) || null);\n    }, [snippets, activeSnippet, filteredSnippets]);\n\n    const updateSnippet = (snippet: Snippet) => {\n        setSnippets(snippets.map((s: Snippet) => s.id === snippet.id ? snippet : s));\n        setActiveSnippet(snippet);\n    };\n\n    const handleEnhance = async () => {\n        if (!activeSnippet) return;\n        setIsEnhancing(true);\n        try {\n            const stream = enhanceSnippetStream(activeSnippet.code);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                updateSnippet({ ...activeSnippet, code: fullResponse.replace(/^\\`\\`\\`(?:\\\\w+\\\\n)?/, '').replace(/\\`\\`\\`\\$/, '') });\n            }\n        } finally { setIsEnhancing(false); }\n    };\n    \n    const handleAiTagging = async (snippet: Snippet) => {\n        if (!snippet.code.trim()) return;\n        try {\n            const suggestedTags = await generateTagsForCode(snippet.code);\n            const newTags = [...new Set([...(snippet.tags || []), ...suggestedTags])];\n            updateSnippet({...snippet, tags: newTags});\n            addNotification('AI tags added!', 'success');\n        } catch(e) {\n            console.error(\"AI tagging failed:\", e);\n            addNotification('AI tagging failed.', 'error');\n        }\n    };\n\n    const handleAddNew = () => {\n        const newSnippet: Snippet = { id: Date.now(), name: 'New Snippet', language: 'plaintext', code: '', tags: [] };\n        setSnippets([...snippets, newSnippet]);\n        setActiveSnippet(newSnippet);\n    };\n    \n    const handleDelete = (id: number) => {\n        setSnippets(snippets.filter((s: Snippet) => s.id !== id));\n        if(activeSnippet?.id === id) setActiveSnippet(filteredSnippets.length > 1 ? filteredSnippets[0] : null);\n    };\n    \n    const handleDownload = () => {\n        if(!activeSnippet) return;\n        const extension = langToExt[activeSnippet.language] || 'txt';\n        const filename = \\`\\${activeSnippet.name.replace(/\\\\s/g, '_')}.\\${extension}\\`;\n        downloadFile(activeSnippet.code, filename);\n    }\n\n    const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n        if (activeSnippet) updateSnippet({...activeSnippet, name: e.target.value});\n    };\n    \n    const handleTagsChange = (e: React.KeyboardEvent<HTMLInputElement>) => {\n        if (e.key === 'Enter' && activeSnippet) {\n            const newTag = e.currentTarget.value.trim();\n            if (newTag && !activeSnippet.tags.includes(newTag)) {\n                updateSnippet({...activeSnippet, tags: [...(activeSnippet.tags ?? []), newTag]});\n            }\n            e.currentTarget.value = '';\n        }\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><LockClosedIcon /><span className=\"ml-3\">Snippet Vault</span></h1><p className=\"text-text-secondary mt-1\">Store, search, tag, and enhance your reusable code snippets with AI.</p></header>\n            <div className=\"flex-grow flex gap-6 min-h-0\">\n                <aside className=\"w-1/3 bg-surface border border-border p-4 rounded-lg flex flex-col\">\n                    <input type=\"text\" placeholder=\"Search snippets...\" value={searchTerm} onChange={e => setSearchTerm(e.target.value)} className=\"w-full px-3 py-1.5 mb-3 rounded-md bg-background border border-border text-sm\"/>\n                    <ul className=\"space-y-2 flex-grow overflow-y-auto pr-2\">{filteredSnippets.map((s: Snippet) => (<li key={s.id} className=\"group flex items-center justify-between\"><button onClick={() => setActiveSnippet(s)} className={\\`w-full text-left px-3 py-2 rounded-md \\${activeSnippet?.id === s.id ? 'bg-primary/10 text-primary' : 'hover:bg-gray-100 dark:hover:bg-slate-700'}\\`}>{s.name}</button><div className=\"flex opacity-0 group-hover:opacity-100 transition-opacity\"><button onClick={() => {navigator.clipboard.writeText(s.code); addNotification(\"Copied snippet!\", \"success\")}} className=\"ml-2 p-1 text-text-secondary hover:text-primary\" title=\"Copy\"><ClipboardDocumentIcon /></button><button onClick={() => handleDelete(s.id)} className=\"ml-2 p-1 text-text-secondary hover:text-red-500\" title=\"Delete\"><TrashIcon/></button></div></li>))}</ul>\n                    <div className=\"mt-4 pt-4 border-t border-border\"><button onClick={handleAddNew} className=\"btn-primary w-full text-sm py-2\">Add New Snippet</button></div>\n                </aside>\n                <main className=\"w-2/3 flex flex-col\">\n                    {activeSnippet ? (<>\n                        <div className=\"flex justify-between items-center mb-2\">\n                            {isEditingName ? <input type=\"text\" value={activeSnippet.name} onChange={handleNameChange} onBlur={() => setIsEditingName(false)} autoFocus className=\"text-lg font-bold bg-gray-100 dark:bg-slate-700 rounded px-2\"/> : <h3 onDoubleClick={() => setIsEditingName(true)} className=\"text-lg font-bold cursor-pointer\">{activeSnippet.name}</h3>}\n                            <div className=\"flex gap-2\">\n                                <button onClick={() => handleAiTagging(activeSnippet)} className=\"flex items-center gap-2 px-3 py-1 bg-teal-500/80 text-white font-bold text-xs rounded-md\"><SparklesIcon /> AI Tag</button>\n                                <button onClick={handleEnhance} disabled={isEnhancing} className=\"flex items-center gap-2 px-3 py-1 bg-purple-500/80 text-white font-bold text-xs rounded-md disabled:bg-gray-400\"><SparklesIcon /> AI Enhance</button>\n                                <button onClick={handleDownload} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 dark:bg-slate-700 text-xs rounded-md\"><ArrowDownTrayIcon className=\"w-4 h-4\"/> Download</button>\n                            </div>\n                        </div>\n                        <textarea value={activeSnippet.code} onChange={e => updateSnippet({...activeSnippet, code: e.target.value})} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm focus:ring-2 focus:ring-primary focus:outline-none\"/>\n                        <div className=\"mt-2 text-xs text-text-secondary\">\n                           <div className=\"flex items-center gap-2 flex-wrap\">\n                             <span className=\"font-bold\">Tags:</span> {(activeSnippet.tags ?? []).map(t => <span key={t} className=\"bg-gray-200 dark:bg-slate-700 px-2 py-0.5 rounded-full\">{t}</span>)}\n                             <input type=\"text\" placeholder=\"+ Add tag\" onKeyDown={handleTagsChange} className=\"bg-transparent border-b border-border focus:outline-none focus:border-primary w-24 text-xs px-1\"/>\n                           </div>\n                        </div>\n                    </>) : (<div className=\"flex-grow flex items-center justify-center bg-background border border-border rounded-lg text-text-secondary\">Select a snippet or create a new one.</div>)}\n                </main>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/SvgPathEditor.tsx': `import React, { useState, useRef } from 'react';\nimport { CodeBracketSquareIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { downloadFile } from '../../services/fileUtils.ts';\n\nconst initialPath = \"M 20 80 Q 100 20 180 80 T 340 80\";\n\nconst parsePath = (d: string) => {\n    const commands = d.match(/[a-df-z][^a-df-z]*/ig) || [];\n    return commands.map((cmdStr, i) => {\n        const command = cmdStr[0];\n        const args = cmdStr.slice(1).trim().split(/[\\\\s,]+/).map(parseFloat).filter(n => !isNaN(n));\n        const points = [];\n        for (let j = 0; j < args.length; j += 2) {\n            points.push({ x: args[j], y: args[j + 1] });\n        }\n        return { id: i, command, points };\n    });\n};\n\nconst buildPath = (parsed: any[]) => {\n    return parsed.map(cmd => \\`\\${cmd.command} \\${cmd.points.map((p:any) => \\`\\${p.x} \\${p.y}\\`).join(' ')}\\`).join(' ');\n};\n\nexport const SvgPathEditor: React.FC = () => {\n    const [pathData, setPathData] = useState(initialPath);\n    const svgRef = useRef<SVGSVGElement>(null);\n    const [draggingPoint, setDraggingPoint] = useState<any>(null);\n    const parsedPath = parsePath(pathData);\n\n    const handleMouseDown = (e: React.MouseEvent, cmdIndex: number, pointIndex: number) => {\n        e.stopPropagation();\n        setDraggingPoint({ cmdIndex, pointIndex });\n    };\n\n    const handleMouseMove = (e: React.MouseEvent) => {\n        if (!draggingPoint || !svgRef.current) return;\n        const pt = new DOMPoint(e.clientX, e.clientY);\n        const svgPoint = pt.matrixTransform(svgRef.current.getScreenCTM()?.inverse());\n        \n        const newParsedPath = parsedPath.map((cmd, cIdx) => {\n            if (cIdx === draggingPoint.cmdIndex) {\n                const newPoints = cmd.points.map((p, pIdx) => {\n                    if (pIdx === draggingPoint.pointIndex) {\n                        return { x: Math.round(svgPoint.x), y: Math.round(svgPoint.y) };\n                    }\n                    return p;\n                });\n                return { ...cmd, points: newPoints };\n            }\n            return cmd;\n        });\n        setPathData(buildPath(newParsedPath));\n    };\n    \n    const handleMouseUp = () => setDraggingPoint(null);\n    \n    const handleAddPoint = (e: React.MouseEvent) => {\n        if (!svgRef.current) return;\n        const pt = new DOMPoint(e.clientX, e.clientY);\n        const svgPoint = pt.matrixTransform(svgRef.current.getScreenCTM()?.inverse());\n        const newPathData = \\`\\${pathData} L \\${Math.round(svgPoint.x)} \\${Math.round(svgPoint.y)}\\`;\n        setPathData(newPathData);\n    };\n\n    const handleDownload = () => {\n        const svgContent = \\`<svg viewBox=\"0 0 400 160\" xmlns=\"http://www.w3.org/2000/svg\">\n  <path d=\"\\${pathData}\" stroke=\"black\" fill=\"transparent\" stroke-width=\"2\"/>\n</svg>\\`;\n        downloadFile(svgContent, 'path.svg', 'image/svg+xml');\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\"><h1 className=\"text-3xl font-bold flex items-center\"><CodeBracketSquareIcon /><span className=\"ml-3\">SVG Path Editor</span></h1><p className=\"text-text-secondary mt-1\">Visually create and manipulate SVG path data by dragging points.</p></header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 h-full overflow-hidden\">\n                <div className=\"flex flex-col h-full overflow-y-auto\">\n                    <div className=\"flex justify-between items-center mb-2\">\n                        <label htmlFor=\"path-input\" className=\"text-sm font-medium text-text-secondary\">Path Data (d attribute)</label>\n                         <button onClick={handleDownload} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">\n                            <ArrowDownTrayIcon className=\"w-4 h-4\"/> Download SVG\n                        </button>\n                    </div>\n                    <textarea id=\"path-input\" value={pathData} onChange={(e) => setPathData(e.target.value)} className=\"h-24 p-4 bg-surface border border-border rounded-md resize-y font-mono text-sm text-primary\" />\n                     <div className=\"flex-grow mt-4 p-4 bg-surface border-2 border-dashed border-border rounded-md overflow-hidden flex items-center justify-center min-h-[200px]\">\n                        <svg ref={svgRef} viewBox=\"0 0 400 160\" className=\"w-full h-full cursor-crosshair\" onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} onMouseLeave={handleMouseUp} onDoubleClick={handleAddPoint}>\n                           <rect width=\"400\" height=\"160\" fill=\"var(--color-background)\" />\n                            <path d={pathData} stroke=\"var(--color-primary)\" fill=\"transparent\" strokeWidth=\"2\" />\n                            {parsedPath.flatMap((cmd, cmdIndex) => \n                                cmd.points.map((p, pointIndex) => (\n                                    <circle\n                                        key={\\`\\${cmd.id}-\\${pointIndex}\\`}\n                                        cx={p.x}\n                                        cy={p.y}\n                                        r=\"5\"\n                                        fill={cmd.command.toLowerCase() === 'c' || cmd.command.toLowerCase() === 'q' || cmd.command.toLowerCase() === 's' || cmd.command.toLowerCase() === 't' ? '#fde047' : '#f87171'}\n                                        stroke=\"var(--color-surface)\"\n                                        strokeWidth=\"2\"\n                                        className=\"cursor-move hover:stroke-primary\"\n                                        onMouseDown={(e) => handleMouseDown(e, cmdIndex, pointIndex)}\n                                    />\n                                ))\n                            )}\n                        </svg>\n                    </div>\n                    <p className=\"text-xs text-center text-text-secondary mt-2\">Double-click on the canvas to add a new point.</p>\n                </div>\n                <div className=\"flex flex-col h-full\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Parsed Commands</label>\n                    <div className=\"flex-grow p-2 bg-background border border-border rounded-md overflow-y-auto font-mono text-xs space-y-2\">\n                        {parsedPath.map(cmd => (\n                            <div key={cmd.id} className=\"p-2 bg-surface rounded\">\n                                <span className=\"font-bold text-amber-600\">{cmd.command}</span>\n                                <span className=\"text-text-secondary\"> {cmd.points.map(p => \\`(\\${p.x},\\${p.y})\\`).join(' ')}</span>\n                            </div>\n                        ))}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/TechDebtSonar.tsx': `import React, { useState, useCallback } from 'react';\nimport { detectCodeSmells } from '../../services/aiService.ts';\nimport type { CodeSmell } from '../../types.ts';\nimport { MagnifyingGlassIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\nconst exampleCode = \\`class DataProcessor {\n    process(data) {\n        // Long method with multiple responsibilities\n        if (data.type === 'A') {\n            const results = [];\n            for (let i = 0; i < data.items.length; i++) {\n                // complex logic\n                const item = data.items[i];\n                if(item.value > 100) {\n                   results.push({ ...item, status: 'processed' });\n                }\n            }\n            return results;\n        } else {\n            // Duplicated logic\n            const results = [];\n            for (let i = 0; i < data.items.length; i++) {\n                const item = data.items[i];\n                 if(item.value > 100) {\n                   results.push({ ...item, status: 'processed_special' });\n                }\n            }\n            return results;\n        }\n    }\n}\\`;\n\nexport const TechDebtSonar: React.FC = () => {\n    const [code, setCode] = useState(exampleCode);\n    const [smells, setSmells] = useState<CodeSmell[]>([]);\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleScan = useCallback(async () => {\n        if (!code.trim()) {\n            setError('Please provide code to scan.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setSmells([]);\n        try {\n            const result = await detectCodeSmells(code);\n            setSmells(result);\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unknown error occurred.');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [code]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <MagnifyingGlassIcon />\n                    <span className=\"ml-3\">Tech Debt Sonar</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Scan code to find code smells and areas with high complexity.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"flex flex-col\">\n                    <label className=\"text-sm font-medium mb-2\">Code to Analyze</label>\n                    <textarea value={code} onChange={e => setCode(e.target.value)} className=\"flex-grow p-2 bg-surface border rounded font-mono text-xs\"/>\n                    <button onClick={handleScan} disabled={isLoading} className=\"btn-primary w-full mt-4 py-3\">{isLoading ? <LoadingSpinner/> : 'Scan for Code Smells'}</button>\n                </div>\n                <div className=\"flex flex-col\">\n                    <label className=\"text-sm font-medium mb-2\">Detected Smells</label>\n                    <div className=\"flex-grow p-2 bg-background border rounded overflow-auto\">\n                        {isLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"text-red-500 p-4\">{error}</p>}\n                        {!isLoading && smells.length === 0 && <p className=\"text-text-secondary text-center pt-8\">No smells detected, or scan not run.</p>}\n                        {smells.length > 0 && (\n                            <div className=\"space-y-3\">\n                                {smells.map((smell, i) => (\n                                    <div key={i} className=\"p-3 bg-surface border border-border rounded-lg\">\n                                        <div className=\"flex justify-between items-center\">\n                                            <h4 className=\"font-bold text-primary\">{smell.smell}</h4>\n                                            <span className=\"text-xs font-mono bg-gray-100 dark:bg-slate-700 px-2 py-1 rounded\">Line: {smell.line}</span>\n                                        </div>\n                                        <p className=\"text-sm mt-1\">{smell.explanation}</p>\n                                    </div>\n                                ))}\n                            </div>\n                        )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/features/TerraformGenerator.tsx': `import React, { useState, useCallback } from 'react';\nimport { generateTerraformConfig } from '../../services/index.ts';\nimport { CpuChipIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nexport const TerraformGenerator: React.FC = () => {\n    const [description, setDescription] = useState('An S3 bucket for static website hosting');\n    const [cloud, setCloud] = useState<'aws' | 'gcp'>('aws');\n    const [config, setConfig] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleGenerate = useCallback(async () => {\n        if (!description.trim()) {\n            setError('Please provide a description.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setConfig('');\n        try {\n            // Context is stubbed for now but demonstrates future capability\n            const context = 'User might have existing VPCs. Check before creating new ones.';\n            const result = await generateTerraformConfig(cloud, description, context);\n            setConfig(result);\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'Failed to generate config.');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [description, cloud]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><CpuChipIcon /><span className=\"ml-3\">AI Terraform Generator</span></h1>\n                <p className=\"text-text-secondary mt-1\">Generate infrastructure-as-code from a description, with context from your cloud provider.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                 <div className=\"flex flex-col flex-1 min-h-0\">\n                     <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4 mb-4\">\n                        <div>\n                            <label className=\"block text-sm\">Cloud Provider</label>\n                            <select value={cloud} onChange={e => setCloud(e.target.value as 'aws' | 'gcp')} className=\"w-full mt-1 p-2 bg-surface border rounded\">\n                                <option value=\"aws\">AWS</option>\n                                <option value=\"gcp\">GCP</option>\n                            </select>\n                        </div>\n                        <div className=\"md:col-span-2\">\n                            <label className=\"block text-sm\">Describe the infrastructure</label>\n                            <input type=\"text\" value={description} onChange={e => setDescription(e.target.value)} className=\"w-full mt-1 p-2 bg-surface border rounded\"/>\n                        </div>\n                    </div>\n                     <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center py-2\"><SparklesIcon /> {isLoading ? 'Generating...' : 'Generate Configuration'}</button>\n                </div>\n                 <div className=\"flex flex-col flex-grow min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">Generated Terraform (.tf)</label>\n                    <div className=\"relative flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && !config && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                        {config && <MarkdownRenderer content={config} />}\n                         {!isLoading && !config && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">Generated config will appear here.</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/ThemeDesigner.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { SparklesIcon, ArrowDownTrayIcon, PhotoIcon } from '../icons.tsx';\nimport { generateSemanticTheme } from '../../services/index.ts';\nimport { fileToBase64 } from '../../services/fileUtils.ts';\nimport type { SemanticColorTheme, ColorTheme } from '../../types.ts';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { useTheme } from '../../hooks/useTheme.ts';\n\nconst ColorDisplay: React.FC<{ name: string; color: { name: string; value: string; } }> = ({ name, color }) => (\n    <div className=\"flex items-center justify-between p-2 bg-background rounded-md border border-border\">\n        <div className=\"flex items-center gap-3\">\n            <div className=\"w-6 h-6 rounded-full border border-border\" style={{ backgroundColor: color.value }} />\n            <div>\n                <p className=\"text-sm font-semibold text-text-primary capitalize\">{name}</p>\n                <p className=\"text-xs text-text-secondary\">{color.name}</p>\n            </div>\n        </div>\n        <span className=\"font-mono text-sm text-text-secondary\">{color.value}</span>\n    </div>\n);\n\nconst AccessibilityCheck: React.FC<{ name: string, check: { ratio: number; score: string; } }> = ({ name, check }) => {\n    const scoreColor = check.score === 'AAA' ? 'text-green-600' : check.score === 'AA' ? 'text-emerald-600' : 'text-red-600';\n    return (\n        <div className=\"flex items-center justify-between p-2 bg-background rounded-md border border-border text-sm\">\n            <p className=\"text-text-secondary\">{name}</p>\n            <div className=\"flex items-center gap-2\">\n                <span className=\"font-mono\">{check.ratio.toFixed(2)}</span>\n                <span className={\\`font-bold px-2 py-0.5 rounded-full text-xs \\${scoreColor} \\${scoreColor.replace('text-', 'bg-')}/10\\`}>{check.score}</span>\n            </div>\n        </div>\n    );\n}\n\nexport const ThemeDesigner: React.FC = () => {\n    const [theme, setTheme] = useState<SemanticColorTheme | null>(null);\n    const [prompt, setPrompt] = useState('A calming, minimalist theme for a blog');\n    const [image, setImage] = useState<{ base64: string, name: string } | null>(null);\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n    const [, , applyCustomTheme] = useTheme();\n\n    const handleGenerate = useCallback(async () => {\n        const textPart = { text: \\`Generate a theme based on this description: \"\\${prompt}\"\\` };\n        const imagePart = image ? { inlineData: { mimeType: 'image/png', data: image.base64 } } : null;\n        const parts = imagePart ? [textPart, imagePart] : [textPart];\n\n        setIsLoading(true); setError('');\n        try {\n            const newTheme = await generateSemanticTheme({ parts });\n            setTheme(newTheme);\n        } catch (err) {\n            setError(err instanceof Error ? err.message : \"An unknown error occurred.\");\n        } finally {\n            setIsLoading(false);\n        }\n    }, [prompt, image]);\n    \n    const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n        const file = e.target.files?.[0];\n        if (file) {\n            const base64 = await fileToBase64(file);\n            setImage({ base64, name: file.name });\n            setPrompt(\\`A theme based on the uploaded image: \\${file.name}\\`);\n        }\n    };\n    \n    useEffect(() => { handleGenerate(); }, []);\n\n    const handleApplyTheme = () => {\n        if (!theme) return;\n        const colorsToApply: ColorTheme = {\n            primary: theme.palette.primary.value,\n            background: theme.theme.background.value,\n            surface: theme.theme.surface.value,\n            textPrimary: theme.theme.textPrimary.value,\n            textSecondary: theme.theme.textSecondary.value,\n            textOnPrimary: theme.theme.textOnPrimary.value,\n            border: theme.theme.border.value,\n        };\n        applyCustomTheme(colorsToApply, theme.mode);\n    };\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><SparklesIcon /><span className=\"ml-3\">AI Theme Designer</span></h1>\n                <p className=\"text-text-secondary mt-1\">Generate a full design system from a description or image.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 md:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"md:col-span-1 flex flex-col gap-4 bg-surface border border-border p-6 rounded-lg overflow-y-auto\">\n                    <h3 className=\"text-xl font-bold\">Describe or Upload</h3>\n                    <textarea value={prompt} onChange={e => setPrompt(e.target.value)} className=\"p-2 bg-background border border-border rounded-md resize-none text-sm h-24\" placeholder=\"e.g., A light, airy theme for a blog\" />\n                     <div className=\"relative border border-dashed border-border rounded-lg p-4 text-center\">\n                        <input type=\"file\" onChange={handleFileChange} className=\"absolute inset-0 w-full h-full opacity-0 cursor-pointer\" />\n                        <PhotoIcon/>\n                        <p className=\"text-sm mt-1\">{image ? \\`Image: \\${image.name}\\` : 'Upload an image (optional)'}</p>\n                    </div>\n                    <div className=\"flex gap-2\">\n                        <button onClick={handleGenerate} disabled={isLoading} className=\"btn-primary flex-grow flex items-center justify-center gap-2 px-4 py-2\">\n                            {isLoading ? <LoadingSpinner /> : 'Generate New Theme'}\n                        </button>\n                         <button onClick={handleApplyTheme} disabled={isLoading || !theme} className=\"px-4 py-2 bg-emerald-600 text-white font-bold rounded-md hover:opacity-90 transition-all disabled:opacity-50 shadow-md\">\n                            Apply to App\n                        </button>\n                    </div>\n                    {error && <p className=\"text-red-500 text-xs text-center\">{error}</p>}\n\n                    {theme && !isLoading && (\n                        <div className=\"mt-4 border-t border-border pt-4 space-y-4\">\n                            <div><h3 className=\"text-lg font-bold mb-2\">Palette</h3><div className=\"space-y-2\"><ColorDisplay name=\"Primary\" color={theme.palette.primary}/><ColorDisplay name=\"Secondary\" color={theme.palette.secondary}/><ColorDisplay name=\"Accent\" color={theme.palette.accent}/><ColorDisplay name=\"Neutral\" color={theme.palette.neutral}/></div></div>\n                            <div><h3 className=\"text-lg font-bold mb-2\">Theme Roles</h3><div className=\"space-y-2\"><ColorDisplay name=\"Background\" color={theme.theme.background}/><ColorDisplay name=\"Surface\" color={theme.theme.surface}/><ColorDisplay name=\"Text Primary\" color={theme.theme.textPrimary}/><ColorDisplay name=\"Text Secondary\" color={theme.theme.textSecondary}/><ColorDisplay name=\"Text on Primary\" color={theme.theme.textOnPrimary}/><ColorDisplay name=\"Border\" color={theme.theme.border}/></div></div>\n                            <div><h3 className=\"text-lg font-bold mb-2\">Accessibility (WCAG 2.1)</h3><div className=\"space-y-2\"><AccessibilityCheck name=\"Primary on Surface\" check={theme.accessibility.primaryOnSurface}/><AccessibilityCheck name=\"Text on Surface\" check={theme.accessibility.textPrimaryOnSurface}/><AccessibilityCheck name=\"Subtle Text on Surface\" check={theme.accessibility.textSecondaryOnSurface}/><AccessibilityCheck name=\"Text on Primary\" check={theme.accessibility.textOnPrimaryOnPrimary}/></div></div>\n                        </div>\n                    )}\n                </div>\n                <div className=\"md:col-span-1 rounded-lg p-8 overflow-y-auto border border-border\" style={{ backgroundColor: theme?.theme.background.value, color: theme?.theme.textPrimary.value }}>\n                     <h3 className=\"text-2xl font-bold mb-6\">Live Preview</h3>\n                     {theme ? (\n                         <div className=\"p-6 rounded-lg grid grid-cols-1 md:grid-cols-2 gap-6\" style={{ backgroundColor: theme.theme.surface.value }}>\n                            <div className=\"space-y-4\">\n                                <h4 className=\"text-lg font-bold\">Sample Card</h4>\n                                <p className=\"text-sm\" style={{color: theme.theme.textSecondary.value}}>This is a sample card to demonstrate the theme colors. It contains a primary button and some secondary text.</p>\n                                <button className=\"px-4 py-2 rounded-md font-bold transition-colors\" style={{ backgroundColor: theme.palette.primary.value, color: theme.theme.textOnPrimary.value }}>Primary Button</button>\n                            </div>\n                             <div className=\"space-y-4\">\n                                <input type=\"text\" placeholder=\"Text input\" className=\"w-full px-3 py-2 rounded-md border\" style={{backgroundColor: theme.theme.background.value, borderColor: theme.theme.border.value, color: theme.theme.textPrimary.value}} />\n                                <div className=\"p-3 border rounded\" style={{borderColor: theme.theme.border.value, color: theme.theme.textSecondary.value}}>\n                                    <p>A bordered container.</p>\n                                </div>\n                             </div>\n                         </div>\n                     ) : <div className=\"flex items-center justify-center h-full text-text-secondary\">Theme preview will appear here.</div>}\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/TypographyLab.tsx': `import React, { useState, useEffect } from 'react';\nimport { TypographyLabIcon } from '../icons.tsx';\n\nconst popularFonts = [\n    'Roboto', 'Open Sans', 'Lato', 'Montserrat', 'Oswald', 'Source Sans Pro', 'Raleway', 'Poppins', 'Nunito', 'Merriweather',\n    'Playfair Display', 'Lora', 'Noto Sans', 'Ubuntu', 'PT Sans', 'Slabo 27px'\n];\n\nexport const TypographyLab: React.FC = () => {\n    const [headingFont, setHeadingFont] = useState('Oswald');\n    const [bodyFont, setBodyFont] = useState('Roboto');\n\n    useEffect(() => {\n        const fontsToLoad = [headingFont, bodyFont].filter(Boolean).join('|');\n        if (fontsToLoad) {\n            const linkId = 'font-pairing-stylesheet';\n            let link = document.getElementById(linkId) as HTMLLinkElement;\n            if (!link) {\n                link = document.createElement('link');\n                link.id = linkId;\n                link.rel = 'stylesheet';\n                document.head.appendChild(link);\n            }\n            link.href = \\`https://fonts.googleapis.com/css?family=\\${fontsToLoad.replace(/ /g, '+')}:400,700&display=swap\\`;\n        }\n    }, [headingFont, bodyFont]);\n    \n    const FontSelector: React.FC<{ label: string, value: string, onChange: (font: string) => void }> = ({ label, value, onChange }) => (\n        <div>\n            <label className=\"block text-sm font-medium text-text-secondary\">{label}</label>\n            <select value={value} onChange={e => onChange(e.target.value)} className=\"w-full mt-1 px-3 py-2 rounded-md bg-surface border border-border\">\n                {popularFonts.map(font => <option key={font} value={font}>{font}</option>)}\n            </select>\n        </div>\n    );\n\n    const headingImport = \\`@import url('https://fonts.googleapis.com/css?family=\\${headingFont.replace(/ /g, '+')}:700&display=swap');\\`;\n    const bodyImport = \\`@import url('https://fonts.googleapis.com/css?family=\\${bodyFont.replace(/ /g, '+')}:400&display=swap');\\`;\n    const headingRule = \\`font-family: '\\${headingFont}', sans-serif;\\`;\n    const bodyRule = \\`font-family: '\\${bodyFont}', sans-serif;\\`;\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <TypographyLabIcon />\n                    <span className=\"ml-3\">Typography Lab</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Preview font pairings and get the necessary CSS rules.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-3 gap-6 min-h-0\">\n                <div className=\"lg:col-span-1 flex flex-col gap-4 bg-surface border border-border p-6 rounded-lg\">\n                    <h3 className=\"text-xl font-bold\">Controls</h3>\n                    <FontSelector label=\"Heading Font\" value={headingFont} onChange={setHeadingFont} />\n                    <FontSelector label=\"Body Font\" value={bodyFont} onChange={setBodyFont} />\n                    <div className=\"space-y-2 mt-4 pt-4 border-t border-border\">\n                        <label className=\"block text-sm font-medium text-text-secondary\">CSS Rules</label>\n                        <div className=\"relative\"><pre className=\"bg-background p-2 rounded-md text-primary text-xs overflow-x-auto\">{headingImport}</pre><button onClick={() => navigator.clipboard.writeText(headingImport)} className=\"absolute top-1 right-1 px-2 py-0.5 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy</button></div>\n                        <div className=\"relative\"><pre className=\"bg-background p-2 rounded-md text-primary text-xs overflow-x-auto\">{headingRule}</pre><button onClick={() => navigator.clipboard.writeText(headingRule)} className=\"absolute top-1 right-1 px-2 py-0.5 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy</button></div>\n                        <div className=\"relative\"><pre className=\"bg-background p-2 rounded-md text-primary text-xs overflow-x-auto\">{bodyImport}</pre><button onClick={() => navigator.clipboard.writeText(bodyImport)} className=\"absolute top-1 right-1 px-2 py-0.5 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy</button></div>\n                        <div className=\"relative\"><pre className=\"bg-background p-2 rounded-md text-primary text-xs overflow-x-auto\">{bodyRule}</pre><button onClick={() => navigator.clipboard.writeText(bodyRule)} className=\"absolute top-1 right-1 px-2 py-0.5 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy</button></div>\n                    </div>\n                </div>\n                <div className=\"lg:col-span-2 bg-background border border-border rounded-lg p-8 overflow-y-auto\">\n                    <h2 className=\"text-4xl font-bold mb-4\" style={{ fontFamily: \\`'\\${headingFont}', sans-serif\\` }}>\n                        The Quick Brown Fox Jumps Over the Lazy Dog\n                    </h2>\n                    <p className=\"text-lg\" style={{ fontFamily: \\`'\\${bodyFont}', sans-serif\\` }}>\n                        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat.\n                    </p>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/VisualGitTree.tsx': `import React, { useState, useCallback, useEffect, useMemo } from 'react';\nimport { GitBranchIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { generateChangelogFromLogStream } from '../../services/aiService.ts';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\nimport { downloadFile } from '../../services/fileUtils.ts';\n\nconst exampleLog = \\`* commit 3a4b5c6d7e8f9g0h1i2j3k4l5m6n7o8p9q0r (HEAD -> main, origin/main)\n|\\\\\\\\  Merge: 1a2b3c4 2d3e4f5\n| | Author: Dev One <dev.one@example.com>\n| | Date:   Mon Jul 15 11:30:00 2024 -0400\n| |\n| |     feat: Implement collapsible sidebar navigation\n| |\n* | commit 2d3e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u (feature/new-sidebar)\n| | Author: Dev Two <dev.two@example.com>\n| | Date:   Mon Jul 15 10:00:00 2024 -0400\n| |\n| |     feat: Add icons to sidebar items\n| |\n* | commit 1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r\n|/  Author: Dev One <dev.one@example.com>\n|   Date:   Fri Jul 12 16:45:00 2024 -0400\n|\n|       fix: Correct user authentication bug\\`;\n\nconst CommitGraph = ({ logInput }: { logInput: string }) => {\n    const commits = useMemo(() => {\n        const lines = logInput.split('\\\\n');\n        const parsedCommits: any[] = [];\n        let currentCommit: any = null;\n\n        lines.forEach(line => {\n            const commitMatch = line.match(/^.?[\\\\\\\\|/ ]*\\\\* commit (\\\\w+)(.*)/);\n            if (commitMatch) {\n                if (currentCommit) parsedCommits.push(currentCommit);\n                currentCommit = {\n                    hash: commitMatch[1],\n                    shortHash: commitMatch[1].substring(0, 7),\n                    refs: commitMatch[2].trim(),\n                    message: '',\n                    author: '',\n                };\n            } else if (currentCommit) {\n                 if (line.includes('Author:')) currentCommit.author = line.split('Author:')[1].trim();\n                 else if (line.trim().length > 0 && !line.match(/^[\\\\\\\\|/ ]*[\\\\\\\\|/ ]/)) {\n                     currentCommit.message += line.trim() + ' ';\n                 }\n            }\n        });\n        if (currentCommit) parsedCommits.push(currentCommit);\n        \n        return parsedCommits.map((c, i) => ({ ...c, x: 50, y: 50 + i * 60 }));\n    }, [logInput]);\n\n    return (\n         <svg width=\"100%\" height={50 + commits.length * 60} className=\"min-h-[200px]\">\n            {commits.map((commit, i) => {\n                const parent = commits[i + 1];\n                return (\n                    <g key={commit.hash}>\n                        {parent && <line x1={commit.x} y1={commit.y} x2={parent.x} y2={parent.y} stroke=\"var(--color-border)\" strokeWidth=\"2\" />}\n                        <g className=\"group cursor-pointer\">\n                            <circle cx={commit.x} cy={commit.y} r=\"8\" fill=\"var(--color-primary)\" stroke=\"var(--color-surface)\" strokeWidth=\"3\" />\n                            <foreignObject x={commit.x + 20} y={commit.y - 25} width=\"350\" height=\"50\">\n                                <div className=\"text-sm p-1\">\n                                    <p className=\"font-bold truncate text-text-primary\">{commit.message}</p>\n                                    <p className=\"text-xs text-text-secondary font-mono\">{commit.shortHash} <span className=\"text-amber-600\">{commit.refs}</span></p>\n                                </div>\n                            </foreignObject>\n                            <title>{\\`Commit: \\${commit.hash}\\\\nAuthor: \\${commit.author}\\\\n\\\\n\\${commit.message}\\`}</title>\n                        </g>\n                    </g>\n                );\n            })}\n        </svg>\n    );\n};\n\nexport const VisualGitTree: React.FC<{ logInput?: string }> = ({ logInput: initialLogInput }) => {\n    const [logInput, setLogInput] = useState(initialLogInput || exampleLog);\n    const [analysis, setAnalysis] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleAnalyze = useCallback(async (logToAnalyze: string) => {\n        if (!logToAnalyze.trim()) {\n            setError('Please paste git log output.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setAnalysis('');\n        try {\n            const stream = generateChangelogFromLogStream(logToAnalyze);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setAnalysis(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to analyze log: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        if (initialLogInput) {\n            setLogInput(initialLogInput);\n            handleAnalyze(initialLogInput);\n        }\n    }, [initialLogInput, handleAnalyze]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <GitBranchIcon />\n                    <span className=\"ml-3\">Visual Git Tree</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Paste your \\`git log --graph\\` output to visualize the history and get an AI summary.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 h-full overflow-hidden\">\n                <div className=\"flex flex-col h-full\">\n                    <label htmlFor=\"log-input\" className=\"text-sm font-medium text-text-secondary mb-2\">Git Log Output</label>\n                    <textarea\n                        id=\"log-input\"\n                        value={logInput}\n                        onChange={(e) => setLogInput(e.target.value)}\n                        placeholder=\"Paste your git log output here...\"\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\"\n                    />\n                    <button\n                        onClick={() => handleAnalyze(logInput)}\n                        disabled={isLoading}\n                        className=\"btn-primary mt-4 w-full flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Analyze & Summarize'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col h-full gap-4\">\n                    <div className=\"flex flex-col h-1/2\">\n                        <label className=\"text-sm font-medium text-text-secondary mb-2\">Commit Graph</label>\n                        <div className=\"flex-grow p-2 bg-surface border border-border rounded-md overflow-auto\">\n                            <CommitGraph logInput={logInput} />\n                        </div>\n                    </div>\n                     <div className=\"flex flex-col h-1/2\">\n                        <div className=\"flex justify-between items-center mb-2\">\n                            <label className=\"text-sm font-medium text-text-secondary\">AI Summary</label>\n                            {analysis && !isLoading && (\n                                <button onClick={() => downloadFile(analysis, 'summary.md', 'text/markdown')} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">\n                                    <ArrowDownTrayIcon className=\"w-4 h-4\"/> Download Summary\n                                </button>\n                            )}\n                        </div>\n                        <div className=\"flex-grow p-4 bg-background border border-border rounded-md overflow-y-auto\">\n                            {isLoading && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                            {error && <p className=\"text-red-500\">{error}</p>}\n                            {analysis && !isLoading && <MarkdownRenderer content={analysis} />}\n                            {!isLoading && !analysis && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">AI summary will appear here.</div>}\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/WeeklyDigestGenerator.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { generateWeeklyDigest } from '../../services/index.ts';\nimport { getCommitHistory } from '../../services/githubService.ts';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\nimport { useOctokit } from '../../contexts/OctokitContext.tsx';\nimport { MailIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\n\nconst dummyTelemetry = {\n    avgPageLoad: 120,\n    errorRate: '0.5%',\n    uptime: '99.98%'\n};\n\nexport const WeeklyDigestGenerator: React.FC = () => {\n    const { addNotification } = useNotification();\n    const { state } = useGlobalState();\n    const { selectedRepo } = state;\n    const { octokit, reinitialize } = useOctokit();\n\n    const [emailHtml, setEmailHtml] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    \n    // Re-check for Octokit client if it's not available initially\n    useEffect(() => {\n        if (!octokit) {\n            reinitialize();\n        }\n    }, [octokit, reinitialize]);\n\n    const handleGenerate = useCallback(async () => {\n        if (!selectedRepo || !octokit) {\n            addNotification('Please select a repository and ensure GitHub is connected.', 'error');\n            return;\n        }\n\n        setIsLoading(true);\n        setEmailHtml('');\n        try {\n            const [owner, repo] = selectedRepo.full_name.split('/');\n            const commits = await getCommitHistory(octokit, owner, repo);\n            const commitLogs = commits.map(c => c.commit.message).join('\\\\n');\n            \n            const html = await generateWeeklyDigest(commitLogs, dummyTelemetry);\n            setEmailHtml(html);\n            addNotification('Digest content generated!', 'success');\n        } catch (e) {\n            addNotification(e instanceof Error ? e.message : 'Failed to generate digest', 'error');\n        } finally {\n            setIsLoading(false);\n        }\n    }, [addNotification, octokit, selectedRepo]);\n\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\"><MailIcon /><span className=\"ml-3\">Weekly Digest Generator</span></h1>\n                <p className=\"text-text-secondary mt-1\">Generate an AI-powered weekly summary based on project data.</p>\n            </header>\n\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                <div className=\"bg-surface p-4 border border-border rounded-lg flex flex-col items-center justify-center text-center\">\n                    <h3 className=\"text-lg font-bold\">Generate Digest</h3>\n                    <p className=\"text-sm text-text-secondary my-4\">\n                        This tool will use the commit history from your selected repository ({selectedRepo ? selectedRepo.full_name : 'none selected'}) to generate a summary. The send functionality has been removed due to updated permissions.\n                    </p>\n                    <div className=\"flex flex-col gap-4 w-full max-w-xs\">\n                        <button onClick={handleGenerate} disabled={isLoading || !selectedRepo || !octokit} className=\"btn-primary flex items-center justify-center gap-2 py-3\">\n                            {isLoading ? <LoadingSpinner /> : <><SparklesIcon /> Generate Digest</>}\n                        </button>\n                    </div>\n                </div>\n\n                <div className=\"bg-surface p-4 border border-border rounded-lg flex flex-col\">\n                    <h3 className=\"text-lg font-bold mb-2\">Email Preview</h3>\n                    <div className=\"flex-grow bg-white border rounded overflow-hidden\">\n                        {isLoading && <div className=\"flex justify-center items-center h-full\"><LoadingSpinner /></div>}\n                        {emailHtml && <iframe srcDoc={emailHtml} title=\"Email Preview\" className=\"w-full h-full\" />}\n                        {!isLoading && !emailHtml && <div className=\"flex justify-center items-center h-full text-text-secondary\">Preview will appear here.</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/WorkerThreadDebugger.tsx': `import React, { useState, useCallback, useEffect } from 'react';\nimport { BugAntIcon, ArrowDownTrayIcon } from '../icons.tsx';\nimport { analyzeConcurrencyStream } from '../../services/index.ts';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\nimport { downloadFile } from '../../services/fileUtils.ts';\n\nconst exampleCode = \\`// main.js\nconst worker = new Worker('worker.js');\n\n// This object is sent back and forth.\n// A race condition can occur because both threads\n// read the counter, increment it, and send it back.\n// The final value depends on which thread's message\n// is processed last.\nconst data = { counter: 0 };\n\nworker.onmessage = function(e) {\n  // Main thread reads and updates\n  data.counter = e.data.counter;\n  console.log('Main received:', data.counter);\n  data.counter++;\n  worker.postMessage(data);\n};\n\n// Start the process\nconsole.log('Main starting with:', data.counter);\ndata.counter++;\nworker.postMessage(data);\n\n\n// worker.js\n// onmessage = function(e) {\n//   // Worker reads and updates\n//   let receivedCounter = e.data.counter;\n//   console.log('Worker received:', receivedCounter);\n//   receivedCounter++;\n//   postMessage({ counter: receivedCounter });\n// }\n\\`;\n\nexport const WorkerThreadDebugger: React.FC<{ codeInput?: string }> = ({ codeInput: initialCode }) => {\n    const [codeInput, setCodeInput] = useState(initialCode || exampleCode);\n    const [analysis, setAnalysis] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n    const [error, setError] = useState('');\n\n    const handleAnalyze = useCallback(async (codeToAnalyze: string) => {\n        if (!codeToAnalyze.trim()) {\n            setError('Please paste some code to analyze.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setAnalysis('');\n        try {\n            const stream = analyzeConcurrencyStream(codeToAnalyze);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setAnalysis(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to analyze code: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    useEffect(() => {\n        if (initialCode) {\n            setCodeInput(initialCode);\n            handleAnalyze(initialCode);\n        }\n    }, [initialCode, handleAnalyze]);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <BugAntIcon />\n                    <span className=\"ml-3\">AI Concurrency Analyzer</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Analyze JavaScript code for potential Web Worker concurrency issues.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"code-input\" className=\"text-sm font-medium text-text-secondary mb-2\">JavaScript Code</label>\n                    <textarea\n                        id=\"code-input\"\n                        value={codeInput}\n                        onChange={(e) => setCodeInput(e.target.value)}\n                        placeholder=\"Paste your worker-related JS code here...\"\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\"\n                    />\n                </div>\n                 <div className=\"flex-shrink-0\">\n                    <button\n                        onClick={() => handleAnalyze(codeInput)}\n                        disabled={isLoading}\n                        className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Analyze Code'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <div className=\"flex justify-between items-center mb-2\">\n                        <label className=\"text-sm font-medium text-text-secondary\">AI Analysis</label>\n                        {analysis && !isLoading && (\n                             <button onClick={() => downloadFile(analysis, 'analysis.md', 'text/markdown')} className=\"flex items-center gap-1 px-3 py-1 bg-gray-100 text-xs rounded-md hover:bg-gray-200\">\n                                <ArrowDownTrayIcon className=\"w-4 h-4\"/> Download\n                            </button>\n                        )}\n                    </div>\n                    <div className=\"flex-grow p-4 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"text-red-500\">{error}</p>}\n                        {analysis && !isLoading && <MarkdownRenderer content={analysis} />}\n                        {!isLoading && !analysis && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">Analysis will appear here.</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/WorkspaceConnectorHub.tsx': `import React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { validateToken } from '../../services/authService.ts';\nimport { ACTION_REGISTRY, executeWorkspaceAction } from '../../services/workspaceConnectorService.ts';\nimport { RectangleGroupIcon, GithubIcon, SparklesIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { signInWithGoogle } from '../../services/googleAuthService.ts';\nimport { useVaultModal } from '../../contexts/VaultModalContext.tsx';\n\nconst ServiceConnectionCard: React.FC<{\n    serviceName: string;\n    icon: React.ReactNode;\n    fields: { id: string; label: string; placeholder: string }[];\n    onConnect: (credentials: Record<string, string>) => Promise<void>;\n    onDisconnect: () => Promise<void>;\n    status: string;\n    isLoading: boolean;\n}> = ({ serviceName, icon, fields, onConnect, onDisconnect, status, isLoading }) => {\n    const [creds, setCreds] = useState<Record<string, string>>({});\n\n    const handleConnect = () => {\n        onConnect(creds);\n    };\n\n    const isConnected = status.startsWith('Connected');\n\n    return (\n        <div className=\"bg-surface border border-border rounded-lg p-6\">\n            <div className=\"flex items-center justify-between\">\n                <div className=\"flex items-center gap-4\">\n                    <div className=\"w-10 h-10\">{icon}</div>\n                    <div>\n                        <h3 className=\"text-lg font-bold text-text-primary\">{serviceName}</h3>\n                        <p className={\\`text-sm \\${isConnected ? 'text-green-600' : 'text-text-secondary'}\\`}>{status}</p>\n                    </div>\n                </div>\n                {isConnected && (\n                    <button onClick={onDisconnect} className=\"px-4 py-2 bg-red-500/10 text-red-600 font-semibold rounded-lg hover:bg-red-500/20\">\n                        Disconnect\n                    </button>\n                )}\n            </div>\n            {!isConnected && (\n                <div className=\"mt-4 pt-4 border-t border-border space-y-2\">\n                    {fields.map(field => (\n                        <div key={field.id}>\n                            <label className=\"text-xs text-text-secondary\">{field.label}</label>\n                            <input\n                                type={field.id.includes('token') || field.id.includes('pat') ? 'password' : 'text'}\n                                value={creds[field.id] || ''}\n                                onChange={e => setCreds(prev => ({ ...prev, [field.id]: e.target.value }))}\n                                placeholder={field.placeholder}\n                                className=\"w-full mt-1 p-2 bg-background border border-border rounded-md text-sm\"\n                            />\n                        </div>\n                    ))}\n                    <button onClick={handleConnect} disabled={isLoading} className=\"btn-primary w-full mt-2 py-2 flex items-center justify-center\">\n                        {isLoading ? <LoadingSpinner /> : 'Connect'}\n                    </button>\n                </div>\n            )}\n        </div>\n    );\n};\n\n\nexport const WorkspaceConnectorHub: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const { user, githubUser, vaultState } = state;\n    const { addNotification } = useNotification();\n    const { requestUnlock, requestCreation } = useVaultModal();\n    const [loadingStates, setLoadingStates] = useState<Record<string, boolean>>({});\n    const [connectionStatuses, setConnectionStatuses] = useState<Record<string, string>>({});\n    \n    // Manual action state\n    const [selectedActionId, setSelectedActionId] = useState<string>([...ACTION_REGISTRY.keys()][0]);\n    const [actionParams, setActionParams] = useState<Record<string, any>>({});\n    const [isExecuting, setIsExecuting] = useState(false);\n    const [actionResult, setActionResult] = useState<string>('');\n\n    const services = useMemo(() => {\n        const serviceMap = new Map();\n        ACTION_REGISTRY.forEach(action => {\n            if (!serviceMap.has(action.service)) {\n                serviceMap.set(action.service, {\n                    name: action.service,\n                    actions: [],\n                });\n            }\n            serviceMap.get(action.service).actions.push(action);\n        });\n        return Array.from(serviceMap.values());\n    }, []);\n\n    const checkConnections = useCallback(async () => {\n        if (!user || !vaultState.isUnlocked) return;\n        \n        const checkCred = async (credId: string, serviceName: string, successMessage: string) => {\n             const token = await vaultService.getDecryptedCredential(credId);\n             setConnectionStatuses(s => ({ ...s, [serviceName]: token ? successMessage : 'Not Connected' }));\n        };\n\n        await checkCred('github_pat', 'GitHub', githubUser ? \\`Connected as \\${githubUser.login}\\`: 'Connected');\n        await checkCred('jira_pat', 'Jira', 'Connected');\n        await checkCred('slack_bot_token', 'Slack', 'Connected');\n\n    }, [user, vaultState.isUnlocked, githubUser]);\n\n    useEffect(() => {\n        checkConnections();\n    }, [checkConnections]);\n    \n    const withVault = useCallback(async (callback: () => Promise<void>) => {\n        if (!vaultState.isInitialized) {\n            const created = await requestCreation();\n            if (!created) { addNotification('Vault setup is required.', 'error'); return; }\n        }\n        if (!vaultState.isUnlocked) {\n            const unlocked = await requestUnlock();\n            if (!unlocked) { addNotification('Vault must be unlocked to manage connections.', 'error'); return; }\n        }\n        await callback();\n    }, [vaultState, requestCreation, requestUnlock, addNotification]);\n\n\n    const handleConnect = async (serviceName: string, credentials: Record<string, string>) => {\n        await withVault(async () => {\n            setLoadingStates(s => ({ ...s, [serviceName]: true }));\n            try {\n                for (const [key, value] of Object.entries(credentials)) {\n                    if (value) await vaultService.saveCredential(key, value);\n                }\n                if (serviceName === 'GitHub' && credentials.github_pat) {\n                     const githubProfile = await validateToken(credentials.github_pat);\n                     dispatch({ type: 'SET_GITHUB_USER', payload: githubProfile });\n                     await vaultService.saveCredential('github_user', JSON.stringify(githubProfile));\n                }\n                addNotification(\\`\\${serviceName} connected successfully!\\`, 'success');\n                checkConnections();\n            } catch (e) {\n                addNotification(\\`Failed to connect \\${serviceName}: \\${e instanceof Error ? e.message : 'Unknown error'}\\`, 'error');\n            } finally {\n                setLoadingStates(s => ({ ...s, [serviceName]: false }));\n            }\n        });\n    };\n    \n    const handleDisconnect = async (serviceName: string, credIds: string[]) => {\n       await withVault(async () => {\n            setLoadingStates(s => ({ ...s, [serviceName]: true }));\n            try {\n                for (const id of credIds) {\n                     await vaultService.saveCredential(id, ''); // Overwrite with empty string\n                }\n                 if (serviceName === 'GitHub') {\n                     dispatch({ type: 'SET_GITHUB_USER', payload: null });\n                     await vaultService.saveCredential('github_user', '');\n                }\n                addNotification(\\`\\${serviceName} disconnected.\\`, 'info');\n                checkConnections();\n            } catch(e) {\n                addNotification(\\`Failed to disconnect \\${serviceName}.\\`, 'error');\n            } finally {\n                 setLoadingStates(s => ({ ...s, [serviceName]: false }));\n            }\n       });\n    };\n    \n    const handleExecuteAction = async () => {\n        await withVault(async () => {\n            setIsExecuting(true);\n            setActionResult('');\n            try {\n                const result = await executeWorkspaceAction(selectedActionId, actionParams);\n                setActionResult(JSON.stringify(result, null, 2));\n                addNotification('Action executed successfully!', 'success');\n            } catch(e) {\n                setActionResult(\\`Error: \\${e instanceof Error ? e.message : 'Unknown Error'}\\`);\n                addNotification('Action failed.', 'error');\n            } finally {\n                setIsExecuting(false);\n            }\n        });\n    };\n\n    const handleSignIn = () => {\n        signInWithGoogle();\n        // The result is handled by the global callback set in App.tsx\n    };\n\n    const selectedAction = ACTION_REGISTRY.get(selectedActionId);\n    const actionParameters = selectedAction ? selectedAction.getParameters() : {};\n\n    if (!user) {\n        return (\n            <div className=\"h-full flex items-center justify-center\">\n                <div className=\"text-center bg-surface p-8 rounded-lg border border-border max-w-md\">\n                    <h2 className=\"text-xl font-bold\">Sign In Required</h2>\n                    <p className=\"text-text-secondary my-4\">Please sign in with your Google account to manage workspace connections.</p>\n                    <button onClick={handleSignIn} className=\"btn-primary px-6 py-3 flex items-center justify-center gap-2 mx-auto\">\n                        Sign in with Google\n                    </button>\n                </div>\n            </div>\n        );\n    }\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n             <header className=\"mb-8\">\n                <h1 className=\"text-4xl font-extrabold tracking-tight flex items-center\"><RectangleGroupIcon /><span className=\"ml-3\">Workspace Connector Hub</span></h1>\n                <p className=\"mt-2 text-lg text-text-secondary\">Connect to your development services to unlock cross-platform AI actions.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-8 min-h-0\">\n                <div className=\"flex flex-col gap-6 overflow-y-auto pr-4\">\n                    <h2 className=\"text-2xl font-bold\">Service Connections</h2>\n                    <ServiceConnectionCard \n                        serviceName=\"GitHub\"\n                        icon={<GithubIcon />}\n                        fields={[{ id: 'github_pat', label: 'Personal Access Token', placeholder: 'ghp_...' }]}\n                        onConnect={(creds) => handleConnect('GitHub', creds)}\n                        onDisconnect={() => handleDisconnect('GitHub', ['github_pat'])}\n                        status={connectionStatuses.GitHub || 'Checking...'}\n                        isLoading={loadingStates.GitHub}\n                    />\n                     {/* Placeholder cards for Jira and Slack */}\n                    <ServiceConnectionCard \n                        serviceName=\"Jira\"\n                        icon={<div className=\"w-10 h-10 bg-[#0052CC] rounded flex items-center justify-center text-white font-bold text-xl\">J</div>}\n                        fields={[\n                            { id: 'jira_domain', label: 'Jira Domain', placeholder: 'your-company.atlassian.net' },\n                            { id: 'jira_email', label: 'Your Jira Email', placeholder: 'you@example.com' },\n                            { id: 'jira_pat', label: 'API Token', placeholder: 'Your API Token' },\n                        ]}\n                        onConnect={(creds) => handleConnect('Jira', creds)}\n                        onDisconnect={() => handleDisconnect('Jira', ['jira_domain', 'jira_email', 'jira_pat'])}\n                        status={connectionStatuses.Jira || 'Checking...'}\n                        isLoading={loadingStates.Jira}\n                    />\n                    <ServiceConnectionCard \n                        serviceName=\"Slack\"\n                        icon={<div className=\"w-10 h-10 bg-[#4A154B] rounded flex items-center justify-center text-white font-bold text-2xl\">#</div>}\n                        fields={[{ id: 'slack_bot_token', label: 'Bot User OAuth Token', placeholder: 'xoxb-...' }]}\n                        onConnect={(creds) => handleConnect('Slack', creds)}\n                        onDisconnect={() => handleDisconnect('Slack', ['slack_bot_token'])}\n                        status={connectionStatuses.Slack || 'Checking...'}\n                        isLoading={loadingStates.Slack}\n                    />\n                </div>\n                <div className=\"flex flex-col gap-6 bg-surface p-6 border border-border rounded-lg\">\n                    <h2 className=\"text-2xl font-bold\">Manual Action Runner</h2>\n                    <div className=\"space-y-4\">\n                         <div>\n                            <label className=\"text-sm font-medium\">Action</label>\n                            <select value={selectedActionId} onChange={e => setSelectedActionId(e.target.value)} className=\"w-full mt-1 p-2 bg-background border rounded\">\n                                {services.map(service => (\n                                    <optgroup label={service.name} key={service.name}>\n                                        {service.actions.map((action: any) => (\n                                            <option key={action.id} value={action.id}>{action.description}</option>\n                                        ))}\n                                    </optgroup>\n                                ))}\n                            </select>\n                        </div>\n                        {Object.entries(actionParameters).map(([key, param]: [string, any]) => (\n                            <div key={key}>\n                                <label className=\"text-sm font-medium\">{key} {param.required && '*'}</label>\n                                <input \n                                    type={param.type}\n                                    value={actionParams[key] || ''}\n                                    onChange={e => setActionParams(p => ({...p, [key]: e.target.value}))}\n                                    placeholder={param.default || ''}\n                                    className=\"w-full mt-1 p-2 bg-background border rounded\"\n                                />\n                            </div>\n                        ))}\n                        <button onClick={handleExecuteAction} disabled={isExecuting} className=\"btn-primary w-full py-2 flex items-center justify-center gap-2\">\n                           {isExecuting ? <LoadingSpinner/> : <><SparklesIcon /> Execute Action</>}\n                        </button>\n                    </div>\n                    <div>\n                        <label className=\"text-sm font-medium\">Result</label>\n                        <pre className=\"w-full h-48 mt-1 p-2 bg-background border rounded overflow-auto text-xs\">{actionResult || 'Action results will appear here.'}</pre>\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/XbrlConverter.tsx': `import React, { useState, useCallback } from 'react';\nimport { convertJsonToXbrlStream } from '../../services/aiService.ts';\nimport { XbrlConverterIcon } from '../icons.tsx';\nimport { LoadingSpinner, MarkdownRenderer } from '../shared/index.tsx';\n\nconst exampleJson = \\`{\n  \"company\": \"ExampleCorp\",\n  \"year\": 2024,\n  \"quarter\": 2,\n  \"revenue\": {\n    \"amount\": 1500000,\n    \"currency\": \"USD\"\n  },\n  \"profit\": {\n    \"amount\": 250000,\n    \"currency\": \"USD\"\n  }\n}\\`;\n\nexport const XbrlConverter: React.FC<{ jsonInput?: string }> = ({ jsonInput: initialJsonInput }) => {\n    const [jsonInput, setJsonInput] = useState<string>(initialJsonInput || exampleJson);\n    const [xbrlOutput, setXbrlOutput] = useState<string>('');\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n\n    const handleConvert = useCallback(async (jsonToConvert: string) => {\n        if (!jsonToConvert.trim()) {\n            setError('Please enter valid JSON to convert.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setXbrlOutput('');\n        try {\n            const stream = convertJsonToXbrlStream(jsonToConvert);\n            let fullResponse = '';\n            for await (const chunk of stream) {\n                fullResponse += chunk;\n                setXbrlOutput(fullResponse);\n            }\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(\\`Failed to convert: \\${errorMessage}\\`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, []);\n\n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <XbrlConverterIcon />\n                    <span className=\"ml-3\">JSON to XBRL Converter</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Convert JSON data into a simplified XBRL-like XML format using AI.</p>\n            </header>\n            <div className=\"flex-grow flex flex-col gap-4 min-h-0\">\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label htmlFor=\"json-input\" className=\"text-sm font-medium text-text-secondary mb-2\">JSON Input</label>\n                    <textarea\n                        id=\"json-input\"\n                        value={jsonInput}\n                        onChange={(e) => setJsonInput(e.target.value)}\n                        placeholder=\"Paste your JSON here...\"\n                        className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\"\n                    />\n                </div>\n                 <div className=\"flex-shrink-0\">\n                    <button\n                        onClick={() => handleConvert(jsonInput)}\n                        disabled={isLoading}\n                        className=\"btn-primary w-full max-w-xs mx-auto flex items-center justify-center px-6 py-3\"\n                    >\n                        {isLoading ? <LoadingSpinner /> : 'Convert to XBRL'}\n                    </button>\n                </div>\n                <div className=\"flex flex-col flex-1 min-h-0\">\n                    <label className=\"text-sm font-medium text-text-secondary mb-2\">XBRL-like XML Output</label>\n                    <div className=\"relative flex-grow p-1 bg-background border border-border rounded-md overflow-y-auto\">\n                        {isLoading && !xbrlOutput && <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div>}\n                        {error && <p className=\"p-4 text-red-500\">{error}</p>}\n                        {xbrlOutput && <MarkdownRenderer content={'\\`\\`\\`xml\\\\n' + xbrlOutput.replace(/\\`\\`\\`xml\\\\n|\\`\\`\\`/g, '') + '\\\\n\\`\\`\\`'} />}\n                        {!isLoading && xbrlOutput && <button onClick={() => navigator.clipboard.writeText(xbrlOutput)} className=\"absolute top-2 right-2 px-2 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-xs\">Copy XML</button>}\n                        {!isLoading && !xbrlOutput && !error && <div className=\"text-text-secondary h-full flex items-center justify-center\">Output will appear here.</div>}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};`,\n  'components/features/index.ts': `import React from 'react';\nimport type { Feature } from '../../types.ts';\nimport { RAW_FEATURES } from '../../constants.tsx';\nimport { lazyWithRetry } from '../../services/componentLoader.ts';\n\nconst componentMap: Record<string, React.FC<any>> = {\n    'ai-command-center': lazyWithRetry(() => import('./AiCommandCenter.tsx'), 'AiCommandCenter'),\n    'project-explorer': lazyWithRetry(() => import('./ProjectExplorer.tsx'), 'ProjectExplorer'),\n    'workspace-connector-hub': lazyWithRetry(() => import('./WorkspaceConnectorHub.tsx'), 'WorkspaceConnectorHub'),\n    'ai-code-explainer': lazyWithRetry(() => import('./AiCodeExplainer.tsx'), 'AiCodeExplainer'),\n    'ai-feature-builder': lazyWithRetry(() => import('./AiFeatureBuilder.tsx'), 'AiFeatureBuilder'),\n    'regex-sandbox': lazyWithRetry(() => import('./RegexSandbox.tsx'), 'RegexSandbox'),\n    'portable-snippet-vault': lazyWithRetry(() => import('./SnippetVault.tsx'), 'SnippetVault'),\n    'css-grid-editor': lazyWithRetry(() => import('./CssGridEditor.tsx'), 'CssGridEditor'),\n    'ai-commit-generator': lazyWithRetry(() => import('./AiCommitGenerator.tsx'), 'AiCommitGenerator'),\n    'json-tree-navigator': lazyWithRetry(() => import('./JsonTreeNavigator.tsx'), 'JsonTreeNavigator'),\n    'xbrl-converter': lazyWithRetry(() => import('./XbrlConverter.tsx'), 'XbrlConverter'),\n    'ai-unit-test-generator': lazyWithRetry(() => import('./AiUnitTestGenerator.tsx'), 'AiUnitTestGenerator'),\n    'prompt-craft-pad': lazyWithRetry(() => import('./PromptCraftPad.tsx'), 'PromptCraftPad'),\n    'linter-formatter': lazyWithRetry(() => import('./CodeFormatter.tsx'), 'CodeFormatter'),\n    'schema-designer': lazyWithRetry(() => import('./SchemaDesigner.tsx'), 'SchemaDesigner'),\n    'pwa-manifest-editor': lazyWithRetry(() => import('./PwaManifestEditor.tsx'), 'PwaManifestEditor'),\n    'markdown-slides-generator': lazyWithRetry(() => import('./MarkdownSlides.tsx'), 'MarkdownSlides'),\n    'screenshot-to-component': lazyWithRetry(() => import('./ScreenshotToComponent.tsx'), 'ScreenshotToComponent'),\n    'digital-whiteboard': lazyWithRetry(() => import('./DigitalWhiteboard.tsx'), 'DigitalWhiteboard'),\n    'theme-designer': lazyWithRetry(() => import('./ThemeDesigner.tsx'), 'ThemeDesigner'),\n    'svg-path-editor': lazyWithRetry(() => import('./SvgPathEditor.tsx'), 'SvgPathEditor'),\n    'ai-style-transfer': lazyWithRetry(() => import('./AiStyleTransfer.tsx'), 'AiStyleTransfer'),\n    'ai-coding-challenge': lazyWithRetry(() => import('./AiCodingChallenge.tsx'), 'AiCodingChallenge'),\n    'typography-lab': lazyWithRetry(() => import('./TypographyLab.tsx'), 'TypographyLab'),\n    'code-review-bot': lazyWithRetry(() => import('./CodeReviewBot.tsx'), 'CodeReviewBot'),\n    'ai-pull-request-assistant': lazyWithRetry(() => import('./AiPullRequestAssistant.tsx'), 'AiPullRequestAssistant'),\n    'changelog-generator': lazyWithRetry(() => import('./ChangelogGenerator.tsx'), 'ChangelogGenerator'),\n    'cron-job-builder': lazyWithRetry(() => import('./CronJobBuilder.tsx'), 'CronJobBuilder'),\n    'ai-code-migrator': lazyWithRetry(() => import('./AiCodeMigrator.tsx'), 'AiCodeMigrator'),\n    'visual-git-tree': lazyWithRetry(() => import('./VisualGitTree.tsx'), 'VisualGitTree'),\n    'worker-thread-debugger': lazyWithRetry(() => import('./WorkerThreadDebugger.tsx'), 'WorkerThreadDebugger'),\n    'ai-image-generator': lazyWithRetry(() => import('./AiImageGenerator.tsx'), 'AiImageGenerator'),\n    'async-call-tree-viewer': lazyWithRetry(() => import('./AsyncCallTreeViewer.tsx'), 'AsyncCallTreeViewer'),\n    'audio-to-code': lazyWithRetry(() => import('./AudioToCode.tsx'), 'AudioToCode'),\n    'code-diff-ghost': lazyWithRetry(() => import('./CodeDiffGhost.tsx'), 'CodeDiffGhost'),\n    'code-spell-checker': lazyWithRetry(() => import('./CodeSpellChecker.tsx'), 'CodeSpellChecker'),\n    'color-palette-generator': lazyWithRetry(() => import('./ColorPaletteGenerator.tsx'), 'ColorPaletteGenerator'),\n    'logic-flow-builder': lazyWithRetry(() => import('./LogicFlowBuilder.tsx'), 'LogicFlowBuilder'),\n    'meta-tag-editor': lazyWithRetry(() => import('./MetaTagEditor.tsx'), 'MetaTagEditor'),\n    'network-visualizer': lazyWithRetry(() => import('./NetworkVisualizer.tsx'), 'NetworkVisualizer'),\n    'responsive-tester': lazyWithRetry(() => import('./ResponsiveTester.tsx'), 'ResponsiveTester'),\n    'sass-scss-compiler': lazyWithRetry(() => import('./SassScssCompiler.tsx'), 'SassScssCompiler'),\n    'env-manager': lazyWithRetry(() => import('./EnvManager.tsx'), 'EnvManager'),\n    'performance-profiler': lazyWithRetry(() => import('./PerformanceProfiler.tsx'), 'PerformanceProfiler'),\n    'a11y-auditor': lazyWithRetry(() => import('./AccessibilityAuditor.tsx'), 'AccessibilityAuditor'),\n    'ci-cd-generator': lazyWithRetry(() => import('./CiCdPipelineGenerator.tsx'), 'CiCdPipelineGenerator'),\n    'deployment-preview': lazyWithRetry(() => import('./DeploymentPreview.tsx'), 'DeploymentPreview'),\n    'security-scanner': lazyWithRetry(() => import('./SecurityScanner.tsx'), 'SecurityScanner'),\n    'terraform-generator': lazyWithRetry(() => import('./TerraformGenerator.tsx'), 'TerraformGenerator'),\n    'ai-personality-forge': lazyWithRetry(() => import('./AiPersonalityForge.tsx'), 'AiPersonalityForge'),\n    'weekly-digest-generator': lazyWithRetry(() => import('./WeeklyDigestGenerator.tsx'), 'WeeklyDigestGenerator'),\n    'one-click-refactor': lazyWithRetry(() => import('./OneClickRefactor.tsx'), 'OneClickRefactor'),\n    'bug-reproducer': lazyWithRetry(() => import('./BugReproducer.tsx'), 'BugReproducer'),\n    'tech-debt-sonar': lazyWithRetry(() => import('./TechDebtSonar.tsx'), 'TechDebtSonar'),\n    'iam-policy-generator': lazyWithRetry(() => import('./IamPolicyGenerator.tsx'), 'IamPolicyGenerator'),\n    'iam-policy-visualizer': lazyWithRetry(() => import('./IamPolicyVisualizer.tsx'), 'IamPolicyVisualizer'),\n    'gmail-addon-simulator': lazyWithRetry(() => import('./GmailAddonSimulator.tsx'), 'GmailAddonSimulator'),\n    'pr-summary-generator': lazyWithRetry(() => import('./PrSummaryGenerator.tsx'), 'PrSummaryGenerator'),\n    'project-moodboard': lazyWithRetry(() => import('./ProjectMoodboard.tsx'), 'ProjectMoodboard'),\n    'font-preview-picker': lazyWithRetry(() => import('./FontPreviewPicker.tsx'), 'FontPreviewPicker'),\n    'font-pairing-tool': lazyWithRetry(() => import('./FontPairingTool.tsx'), 'FontPairingTool'),\n};\n\nexport const ALL_FEATURES: Feature[] = RAW_FEATURES.map(feature => ({\n    ...feature,\n    component: componentMap[feature.id],\n}));\n\nexport const FEATURES_MAP = new Map(ALL_FEATURES.map(f => [f.id, f]));`,\n  'components/features/manifest.ts': `// This file can be used to export feature metadata or related constants.\n// For now, it's a placeholder.\nexport {};\n`,\n  'components/features/shared/.placeholder': ``,\n  'components/features/shared/LoadingSpinner.tsx': `\nimport React from 'react';\n\nexport const LoadingSpinner: React.FC = () => (\n    <div className=\"flex items-center justify-center space-x-1\" aria-label=\"Loading\">\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n    </div>\n);\n`,\n  'components/features/shared/index.tsx': `import React, { useState, useEffect } from 'react';\nimport { marked } from 'marked';\n\nexport const LoadingSpinner: React.FC = () => (\n    <div className=\"flex items-center justify-center space-x-1\" aria-label=\"Loading\">\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n    </div>\n);\n\ninterface MarkdownRendererProps {\n    content: string;\n}\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content }) => {\n    const [sanitizedHtml, setSanitizedHtml] = useState<string | TrustedHTML>('');\n\n    useEffect(() => {\n        const parse = async () => {\n            if (content) {\n                const html = await marked.parse(content);\n                setSanitizedHtml(html);\n            } else {\n                setSanitizedHtml('');\n            }\n        };\n        parse();\n    }, [content]);\n\n    return (\n        <div\n            className=\"prose prose-sm max-w-none prose-headings:text-text-primary prose-p:text-text-primary prose-strong:text-text-primary prose-code:text-primary prose-code:before:content-none prose-code:after:content-none prose-pre:bg-gray-50 prose-pre:border prose-pre:border-border prose-pre:p-4 prose-pre:m-0\"\n            dangerouslySetInnerHTML={{ __html: sanitizedHtml }}\n        />\n    );\n};\n`,\n  'components/icons.tsx': `\n\nimport React from 'react';\n\nconst IconWrapper: React.FC<{children: React.ReactNode; className?: string}> = ({ children, className }) => (\n    <div className={className ?? 'w-6 h-6'}>{children}</div>\n);\n\n// --- From InterfaceIcons.tsx ---\nexport const CpuChipIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 3v1.5M4.5 8.25H3m18 0h-1.5M8.25 21v-1.5M4.5 15.75H3m18 0h-1.5M21 8.25v7.5A2.25 2.25 0 0 1 18.75 18H5.25A2.25 2.25 0 0 1 3 15.75v-7.5A2.25 2.25 0 0 1 5.25 6h13.5A2.25 2.25 0 0 1 21 8.25ZM12 18V6\" /></svg></IconWrapper>;\nexport const DocumentIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\" /></svg></IconWrapper>;\nexport const FolderIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z\" /></svg></IconWrapper>;\nexport const LinkIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244\" /></svg></IconWrapper>;\nexport const ArchiveBoxIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m20.25 7.5-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z\" /></svg></IconWrapper>;\nexport const ClipboardDocumentIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876C9.083 2.25 6.105 5.106 6.105 9.125v3.375c0 .621.504 1.125 1.125 1.125h9.75Z\" /></svg></IconWrapper>;\nexport const ArrowDownTrayIcon: React.FC<{className?: string}> = ({className}) => <IconWrapper className={className}><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3\" /></svg></IconWrapper>;\nexport const XMarkIcon: React.FC<{className?: string}> = ({className}) => <IconWrapper className={className}><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" /></svg></IconWrapper>;\nexport const PlusIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\" /></svg></IconWrapper>;\nexport const TrashIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.134-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.067-2.09 1.02-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0\" /></svg></IconWrapper>;\nexport const PencilIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125\" /></svg></IconWrapper>;\nexport const MagnifyingGlassIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z\" /></svg></IconWrapper>;\nexport const Cog6ToothIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.594 3.94c.09-.542.56-1.008 1.11-1.212l2.39-1.062a1.25 1.25 0 0 1 1.415.602l.62 1.24a1.25 1.25 0 0 0 1.282.693l2.394-.852a1.25 1.25 0 0 1 1.415 1.415l-.852 2.394a1.25 1.25 0 0 0 .693 1.282l1.24.62a1.25 1.25 0 0 1 .602 1.415l-1.062 2.39a1.25 1.25 0 0 0-1.212 1.11l-.22 1.319a1.25 1.25 0 0 1-1.393 1.053l-2.32-.82a1.25 1.25 0 0 0-1.353 0l-2.32.82a1.25 1.25 0 0 1-1.393-1.053l-.22-1.319a1.25 1.25 0 0 0-1.212-1.11l-1.062-2.39a1.25 1.25 0 0 1 .602-1.415l1.24-.62a1.25 1.25 0 0 0 .693-1.282l-.852-2.394a1.25 1.25 0 0 1 1.415-1.415l2.394.852a1.25 1.25 0 0 0 1.282-.693l.62-1.24a1.25 1.25 0 0 1 1.415-.602l-2.39 1.062a1.25 1.25 0 0 0-1.11 1.212Z\" /><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z\" /></svg></IconWrapper>;\nexport const HomeIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h7.5\" /></svg></IconWrapper>;\nexport const ChevronDownIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m19.5 8.25-7.5 7.5-7.5-7.5\" /></svg></IconWrapper>;\nexport const SunIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z\" /></svg></IconWrapper>;\nexport const MoonIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z\" /></svg></IconWrapper>;\nexport const ArrowLeftOnRectangleIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m-3 0-3-3m0 0 3-3m-3 3H5\" /></svg></IconWrapper>;\nexport const ArrowUpOnSquareIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 8.25H7.5a2.25 2.25 0 0 0-2.25 2.25v9a2.25 2.25 0 0 0 2.25 2.25h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25H15m0-3-3-3m0 0-3 3m3-3v12\" /></svg></IconWrapper>;\nconst WindowIconWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (<div className=\"w-4 h-4\">{children}</div>);\nexport const MinimizeIcon: React.FC = () => <WindowIconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={3} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 12h14\" /></svg></WindowIconWrapper>;\nexport const MaximizeIcon: React.FC = () => <WindowIconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={3} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 4.5h15v15h-15z\" /></svg></WindowIconWrapper>;\nexport const RestoreIcon: React.FC = () => <WindowIconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={3} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.5 8.5h11v11h-11z M4.5 4.5h11v11h-11z\" /></svg></WindowIconWrapper>;\n\n// --- From FeatureIcons.tsx ---\nexport const FileCodeIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\" /></svg></IconWrapper>;\nexport const GitBranchIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 3v4a3 3 0 0 0 3 3h4a3 3 0 0 0 3-3V3M6 21v-4a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3v4M12 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4z\" /></svg></IconWrapper>;\nexport const SparklesIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456Z\" /></svg></IconWrapper>;\nexport const EyeIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.036 12.322a1.012 1.012 0 0 1 0-.639l4.368-7.28A1.012 1.012 0 0 1 7.105 4.5h9.79a1.012 1.012 0 0 1 .701.293l4.368 7.28c.15.25.228.538.228.828s-.078.578-.228.828l-4.368 7.28a1.012 1.012 0 0 1-.701.293h-9.79a1.012 1.012 0 0 1-.701-.293l-4.368-7.28Z\" /><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z\" /></svg></IconWrapper>;\nexport const MapIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 6.75V15m6-6v8.25m.5-10.5h-7a.5.5 0 0 0-.5.5v13.5a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 .5-.5V4.25a.5.5 0 0 0-.5-.5Z\" /></svg></IconWrapper>;\nexport const BeakerIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c.139-.02.28-.032.427-.032.147 0 .288.012.427.032M5 14.5h14M14.25 3.104v5.714c0 .822-.394 1.573-.986 2.05l-2.014.915a2.25 2.25 0 0 0-.659 1.591v5.714m-3.468-18.222.01.001\" /></svg></IconWrapper>;\nexport const CommandLineIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6.75 7.5 3 11.25l3.75 3.75M17.25 7.5 21 11.25l-3.75 3.75\" /></svg></IconWrapper>;\nexport const LockClosedIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.5 10.5V6.75a4.5 4.5 0 0 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z\" /></svg></IconWrapper>;\nexport const CodeBracketSquareIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.25 9.75 16.5 12l-2.25 2.25m-4.5 0L7.5 12l2.25-2.25M6 20.25h12A2.25 2.25 0 0 0 20.25 18V6A2.25 2.25 0 0 0 18 3.75H6A2.25 2.25 0 0 0 3.75 6v12A2.25 2.25 0 0 0 6 20.25Z\" /></svg></IconWrapper>;\nexport const PhotoIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z\" /></svg></IconWrapper>;\nexport const BellIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0\" /></svg></IconWrapper>;\nexport const ChartBarIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625Zm6.75-5.25c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V3.375Z\" /></svg></IconWrapper>;\nexport const BugAntIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m15.182 16.318A4.5 4.5 0 0 0 18 12a4.5 4.5 0 0 0-3.818-4.318m-3.564 4.318a4.5 4.5 0 0 1 3.564 0M6 12a4.5 4.5 0 0 1 3.818-4.318M12 12a4.5 4.5 0 0 1-3.818-4.318m0 8.636a4.5 4.5 0 0 1 3.818 0M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm0 0a8.949 8.949 0 0 0 5.482-1.611m-10.964 0A8.949 8.949 0 0 1 12 21Zm0 0a8.949 8.949 0 0 0-5.482-1.611m10.964 0A8.949 8.949 0 0 0 12 21Zm-5.482 1.61a8.973 8.973 0 0 1-2.18-1.001m10.342 0a8.973 8.973 0 0 0-2.18-1.001m-6-1.611a8.973 8.973 0 0 1-2.18-1.001M18 12a8.973 8.973 0 0 0-2.18-1.001m-6 0a8.973 8.973 0 0 1-2.18-1.001M6 12a8.973 8.973 0 0 0-2.18-1.001m10.342 0a8.973 8.973 0 0 0-2.18-1.001M12 3a8.973 8.973 0 0 1 2.18 1.001m-4.36 0A8.973 8.973 0 0 1 12 3m0 18a8.973 8.973 0 0 0 2.18-1.001m-4.36 0A8.973 8.973 0 0 0 12 21Zm0-18a8.973 8.973 0 0 0-2.18-1.001m4.36 0A8.973 8.973 0 0 0 12 3Z\" /></svg></IconWrapper>;\nexport const TerminalIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6.75 7.5l3.75 3.75L6.75 15m6-7.5h4.5\" /></svg></IconWrapper>;\nexport const ServerStackIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 20.25h12m-7.5-3.75v3.75m3.75-3.75v3.75M12 3c-5.12 0-9.25 4.13-9.25 9.25s4.13 9.25 9.25 9.25 9.25-4.13 9.25-9.25S17.12 3 12 3Z\" /></svg></IconWrapper>;\nexport const CloudIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 15a4.5 4.5 0 0 0 4.5 4.5H18a3.75 3.75 0 0 0 1.332-7.257 3 3 0 0 0-5.056-2.287 4.5 4.5 0 0 0-8.25-2.287 4.5 4.5 0 0 0-1.25 8.25Z\" /></svg></IconWrapper>;\nexport const PaperAirplaneIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5\" /></svg></IconWrapper>;\nexport const ShieldCheckIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.286Z\" /></svg></IconWrapper>;\nexport const ArrowPathIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 11.667 0l3.181-3.183m-4.991-2.691V5.25a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75\" /></svg></IconWrapper>;\nexport const RectangleGroupIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 7.125A2.25 2.25 0 0 1 4.5 4.875h15A2.25 2.25 0 0 1 21.75 7.125v10.5A2.25 2.25 0 0 1 19.5 19.875h-15A2.25 2.25 0 0 1 2.25 17.625v-10.5ZM11.25 4.875v10.5a2.25 2.25 0 0 1-2.25 2.25h-1.5a2.25 2.25 0 0 1-2.25-2.25v-10.5a2.25 2.25 0 0 1 2.25-2.25h1.5a2.25 2.25 0 0 1 2.25 2.25Z\" /></svg></IconWrapper>;\nexport const MusicalNoteIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 9V4.5M9 9c0 .54.06.913.175 1.313M9 9H4.5M9.175 10.313C9.06 10.087 9 9.85 9 9.6V4.5a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 .75.75v5.1a.75.75 0 0 1-.75.75h-.625a.75.75 0 0 1-.75-.75V9.75\" /></svg></IconWrapper>;\nexport const VideoCameraIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9A2.25 2.25 0 0 0 13.5 5.25h-9A2.25 2.25 0 0 0 2.25 7.5v9A2.25 2.25 0 0 0 4.5 18.75Z\" /></svg></IconWrapper>;\nexport const DocumentTextIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\" /></svg></IconWrapper>;\nexport const PaintBrushIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\" /></svg></IconWrapper>;\nexport const PuzzlePieceIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.25 6.087c0-1.036-.84-1.875-1.875-1.875s-1.875.84-1.875 1.875v.563c-1.036 0-1.875.84-1.875 1.875v1.5c0 1.036.84 1.875 1.875 1.875h1.5c1.036 0 1.875-.84 1.875-1.875v-1.5c0-1.036-.84-1.875-1.875-1.875v-.563Zm-4.5 0v.563c-1.036 0-1.875.84-1.875 1.875v1.5c0 1.036.84 1.875 1.875 1.875h1.5c1.036 0 1.875-.84 1.875-1.875v-1.5c0-1.036-.84-1.875-1.875-1.875v-.563a1.875 1.875 0 0 0-3.75 0Z\" /></svg></IconWrapper>;\nexport const MicrophoneIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 18.75a6 6 0 0 0 6-6v-1.5m-6 7.5a6 6 0 0 1-6-6v-1.5m12 4.5v-1.5a6 6 0 0 0-12 0v1.5m12 0v-1.5a6 6 0 0 0-12 0v1.5m6 3.75a3 3 0 0 1-3-3V6.75a3 3 0 0 1 6 0v6a3 3 0 0 1-3 3Z\" /></svg></IconWrapper>;\nexport const MailIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75\" /></svg></IconWrapper>;\n\n\n// --- From CustomFeatureIcons.tsx ---\nexport const CommandCenterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 9V5l-7 7 7 7v-4.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/><path d=\"M14 14.5V19l7-7-7-7v4.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/><circle cx=\"12\" cy=\"12\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/></svg></IconWrapper>;\nexport const ProjectExplorerIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 9.75h16.5m-16.5 4.5h16.5m-16.5 4.5h16.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z\" /></svg></IconWrapper>;\nexport const ConnectionsIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\"><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244\" /></svg></IconWrapper>;\nexport const CodeExplainerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"/><path d=\"M14 2v6h6\"/><circle cx=\"12\" cy=\"15\" r=\"3\"/><path d=\"M12 18v2\"/></svg></IconWrapper>;\nexport const FeatureBuilderIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5\"/><path d=\"M2 12l10 5 10-5\"/><path d=\"M17 8.5l-5 2.5-5-2.5\"/><path d=\"M12 17.5V14\"/></svg></IconWrapper>;\nexport const CodeMigratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 22H5a2 2 0 01-2-2V4a2 2 0 012-2h5\"/><path d=\"M14 2h5a2 2 0 012 2v16a2 2 0 01-2 2h-5\"/><path d=\"M7 8h2m-2 4h4m-4 4h2\"/></svg></IconWrapper>;\nexport const ThemeDesignerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 2a10 10 0 000 20z\"/><path d=\"M22 12c-5.523 0-10-4.477-10-10\"/></svg></IconWrapper>;\nexport const SnippetVaultIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\" ry=\"2\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M8 12h8m-4-4v8\"/></svg></IconWrapper>;\nexport const DigitalWhiteboardIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" /><path d=\"M7 8h4m-4 4h8m-8 4h6\" /></svg></IconWrapper>;\nexport const UnitTestGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M4.5 12.5l3-3 3 3 6-6\"/><path d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"/></svg></IconWrapper>;\nexport const CommitGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2\"/><rect x=\"8\" y=\"2\" width=\"8\" height=\"4\" rx=\"1\" ry=\"1\"/></svg></IconWrapper>;\nexport const GitLogAnalyzerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M6 3v18\"/><path d=\"M18 3v18\"/><path d=\"M12 3v18\"/><circle cx=\"6\" cy=\"6\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/><circle cx=\"12\" cy=\"12\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/><circle cx=\"18\" cy=\"18\" r=\"3\" fill=\"currentColor\" opacity=\"0.4\"/></svg></IconWrapper>;\nexport const ConcurrencyAnalyzerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M18 6l-6 6-6-6\"/><path d=\"M18 18l-6-6-6 6\"/></svg></IconWrapper>;\nexport const RegexSandboxIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M15 4l-8 16\"/><path d=\"M22 12H2\"/><path d=\"M10 3L6 21\"/></svg></IconWrapper>;\nexport const PromptCraftPadIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\"/></svg></IconWrapper>;\nexport const CodeFormatterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M3 6h3m-3 6h3m-3 6h3M9 6h12M9 12h12M9 18h12\"/></svg></IconWrapper>;\nexport const JsonTreeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 21v-4a2 2 0 012-2h8\"/><path d=\"M10 17H5a2 2 0 01-2-2V5a2 2 0 012-2h8a2 2 0 012 2v2\"/><rect x=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"2\" ry=\"2\" opacity=\"0.2\"/></svg></IconWrapper>;\nexport const XbrlConverterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M8 8l-4 4 4 4m8-8l4 4-4-4\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/><path d=\"M14.5 5.5l-5 13\" strokeLinecap=\"round\"/></svg></IconWrapper>;\nexport const CssGridEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"/></svg></IconWrapper>;\nexport const SchemaDesignerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M4 7V4h16v3\"/><path d=\"M4 12h16\"/><path d=\"M4 17h16\"/><rect x=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"2\" ry=\"2\" opacity=\"0.2\"/></svg></IconWrapper>;\nexport const PwaManifestEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 22a10 10 0 100-20 10 10 0 000 20z\"/><path d=\"M12 12l4-4m-4 8l-4-4\"/></svg></IconWrapper>;\nexport const MarkdownSlidesIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M20 3H4a2 2 0 00-2 2v14a2 2 0 002 2h16a2 2 0 002-2V5a2 2 0 00-2-2z\"/><path d=\"M9 16V8h6\"/></svg></IconWrapper>;\nexport const ScreenshotToComponentIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4\"/><path d=\"M7 10l5-5 5 5m-5 8v-13\"/></svg></IconWrapper>;\nexport const TypographyLabIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M4 7V4h16v3\"/><path d=\"M4 17h16\"/><rect x=\"2\" y=\"2\" width=\"20\" height=\"20\" rx=\"2\" ry=\"2\" opacity=\"0.2\"/></svg></IconWrapper>;\nexport const SvgPathEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 20.9l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 20.9z\"/></svg></IconWrapper>;\nexport const StyleTransferIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 2.69l.94-2.69.94 2.69L16.5 3l-2.69.94L13 6.58 12 4l-1 2.58L8.31 4 5.62 3l2.69.94.94 2.69.94-2.69z\"/><path d=\"M12 2.69l.94-2.69.94 2.69L16.5 3l-2.69.94L13 6.58 12 4l-1 2.58L8.31 4 5.62 3l2.69.94.94 2.69.94-2.69zM12 2.69l.94-2.69.94 2.69L16.5 3l-2.69.94L13 6.58 12 4l-1 2.58L8.31 4 5.62 3l2.69.94.94 2.69.94-2.69zM3.5 13.5c0-4.694 3.806-8.5 8.5-8.5s8.5 3.806 8.5 8.5-3.806 8.5-8.5 8.5-8.5-3.806-8.5-8.5z\"/></svg></IconWrapper>;\nexport const CodingChallengeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 8V6m0 12v-2m-4-6H6m12 0h-2m-2-4l-1.5-1.5M18 18l-1.5-1.5M6 18l1.5-1.5M6 6l1.5 1.5\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg></IconWrapper>;\nexport const CodeReviewBotIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 20V10m0 0V4m0 6h8m-8 0H4\"/><path d=\"M12 20a8 8 0 100-16 8 8 0 000 16z\"/></svg></IconWrapper>;\nexport const AiPullRequestAssistantIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M13 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V9z\"/><path d=\"M13 2v7h7\"/><path d=\"M17.5 2.5l-2-2m2 2l2-2m-2 2v4\"/></svg></IconWrapper>;\nexport const ChangelogGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"/><path d=\"M14 2v6h6\"/><path d=\"M16 13H8m8 4H8m-1-8l-2-2-2 2\"/></svg></IconWrapper>;\nexport const CronJobBuilderIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"/></svg></IconWrapper>;\nexport const AsyncCallTreeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M3 6h18M3 12h18M3 18h18\"/><path d=\"M6 3v18m12-18v18\"/></svg></IconWrapper>;\nexport const AudioToCodeIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z\"/><path d=\"M19 10v2a7 7 0 01-14 0v-2\"/><path d=\"M12 19v4\"/></svg></IconWrapper>;\nexport const CodeDiffGhostIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M16 16l-4-4 4-4m-8 8l4-4-4-4\"/></svg></IconWrapper>;\nexport const CodeSpellCheckerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.72\"/><path d=\"M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.72-1.72\"/></svg></IconWrapper>;\nexport const ColorPaletteGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\"/></svg></IconWrapper>;\nexport const LogicFlowBuilderIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M3 6h18m-9 6H3m9 6H3\"/><path d=\"M8 3v18m8-18v18\"/></svg></IconWrapper>;\nexport const MetaTagEditorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z\"/><path d=\"M7 7h.01\"/></svg></IconWrapper>;\nexport const NetworkVisualizerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M18 10h4V6h-4V2l-4 4 4 4zM6 14H2v4h4v4l4-4-4-4z\"/><path d=\"M10 14v-4h4v4\"/></svg></IconWrapper>;\nexport const ResponsiveTesterIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"/><path d=\"M21 12a9 9 0 00-9-9m9 9a9 9 0 01-9 9\"/></svg></IconWrapper>;\nexport const SassCompilerIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M21.168 18.168A10 10 0 118.832 2.832m12.336 15.336L8.832 2.832\"/></svg></IconWrapper>;\nexport const ImageGeneratorIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><path d=\"M21 15l-5-5L5 21\"/></svg></IconWrapper>;\nexport const GithubIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path fillRule=\"evenodd\" d=\"M12 2C6.477 2 2 6.477 2 12c0 4.418 2.865 8.168 6.839 9.492.5.092.682-.217.682-.482 0-.237-.009-.868-.014-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.031-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.03 1.595 1.03 2.688 0 3.848-2.338 4.695-4.566 4.942.359.308.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.001 10.001 0 0022 12c0-5.523-4.477-10-10-10z\" clipRule=\"evenodd\" /></svg></IconWrapper>;\nexport const HuggingFaceIcon: React.FC = () => <IconWrapper><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20.25,4.01A2.25,2.25,0,0,0,18,1.76H6A2.25,2.25,0,0,0,3.75,4.01V15.5A2.25,2.25,0,0,0,6,17.75H8.6l3.4,3.4,3.4-3.4H18a2.25,2.25,0,0,0,2.25-2.25V4.01ZM8.5,12.06a1,1,0,0,1,1,1,1,1,0,0,1-2,0,1,1,0,0,1,1-1Zm4.9,0a1,1,0,0,1,1,1,1,1,0,0,1-2,0,1,1,0,0,1,1-1Zm2.6,3.44a3.25,3.25,0,0,1-6,0,.75.75,0,0,1,1.5,0,1.75,1.75,0,0,0,3,0,.75.75,0,0,1,1.5,0Z\"/></svg></IconWrapper>;\nexport const GcpIcon: React.FC = () => <IconWrapper><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"><path d=\"M12 2L2 7l10 5 10-5-10-5z\" fill=\"#4285F4\" stroke=\"none\"/><path d=\"M2 12l10 5 10-5-10-5-10 5z\" fill=\"#34A853\" stroke=\"none\" opacity=\"0.7\"/><path d=\"M12 22L2 17l10-5 10 5-10 5z\" fill=\"#FBBC05\" stroke=\"none\" opacity=\"0.7\"/></svg></IconWrapper>;\n`,\n  'components/shared/.placeholder': ``,\n  'components/shared/LoadingSpinner.tsx': `\nimport React from 'react';\n\nexport const LoadingSpinner: React.FC = () => (\n    <div className=\"flex items-center justify-center space-x-1\" aria-label=\"Loading\">\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n    </div>\n);\n`,\n  'components/shared/Notification.tsx': `// This file is intentionally left blank. \n// The NotificationProvider in contexts/NotificationContext.tsx handles rendering.\n// This simplifies the architecture by co-locating the rendering logic with the state management.\nexport {};\n`,\n  'components/shared/index.tsx': `import React, { useState, useEffect } from 'react';\nimport { marked } from 'marked';\n\nexport const LoadingSpinner: React.FC = () => (\n    <div className=\"flex items-center justify-center space-x-1\" aria-label=\"Loading\">\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n        <div className=\"w-2 h-2 rounded-full bg-current animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n    </div>\n);\n\ninterface MarkdownRendererProps {\n    content: string;\n}\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content }) => {\n    const [sanitizedHtml, setSanitizedHtml] = useState<string | TrustedHTML>('');\n\n    useEffect(() => {\n        const parse = async () => {\n            if (content) {\n                const html = await marked.parse(content);\n                setSanitizedHtml(html);\n            } else {\n                setSanitizedHtml('');\n            }\n        };\n        parse();\n    }, [content]);\n\n    return (\n        <div\n            className=\"prose prose-sm max-w-none prose-headings:text-text-primary prose-p:text-text-primary prose-strong:text-text-primary prose-code:text-primary prose-code:before:content-none prose-code:after:content-none prose-pre:bg-gray-50 prose-pre:border prose-pre:border-border prose-pre:p-4 prose-pre:m-0\"\n            dangerouslySetInnerHTML={{ __html: sanitizedHtml }}\n        />\n    );\n};\n`,\n  'components/vault/.placeholder': ``,\n  'components/vault/CreateMasterPasswordModal.tsx': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { useState } from 'react';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { LoadingSpinner } from '../shared/LoadingSpinner.tsx';\n\ninterface Props {\n    onSuccess: () => void;\n    onCancel: () => void;\n}\n\nexport const CreateMasterPasswordModal: React.FC<Props> = ({ onSuccess, onCancel }) => {\n    const [password, setPassword] = useState('');\n    const [confirmPassword, setConfirmPassword] = useState('');\n    const [error, setError] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n\n    const handleSubmit = async (e: React.FormEvent) => {\n        e.preventDefault();\n        setError('');\n\n        if (password.length < 8) {\n            setError('Password must be at least 8 characters long.');\n            return;\n        }\n        if (password !== confirmPassword) {\n            setError('Passwords do not match.');\n            return;\n        }\n\n        setIsLoading(true);\n        try {\n            await vaultService.initializeVault(password);\n            onSuccess();\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unexpected error occurred.');\n            setIsLoading(false);\n        }\n    };\n\n    return (\n        <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n            <div className=\"bg-surface border border-border rounded-lg shadow-2xl w-full max-w-md m-4 p-6 animate-pop-in\">\n                <h2 className=\"text-xl font-bold mb-2\">Create Master Password</h2>\n                <p className=\"text-sm text-text-secondary mb-4\">\n                    This password encrypts your API keys locally on your device. It is never stored or sent anywhere.\n                    <strong> If you forget it, your data will be unrecoverable.</strong>\n                </p>\n                <form onSubmit={handleSubmit} className=\"space-y-4\">\n                    <div>\n                        <label className=\"block text-sm font-medium\">New Master Password</label>\n                        <input\n                            type=\"password\"\n                            value={password}\n                            onChange={(e) => setPassword(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                            autoFocus\n                        />\n                    </div>\n                    <div>\n                        <label className=\"block text-sm font-medium\">Confirm Password</label>\n                        <input\n                            type=\"password\"\n                            value={confirmPassword}\n                            onChange={(e) => setConfirmPassword(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                        />\n                    </div>\n                    {error && <p className=\"text-red-500 text-sm\">{error}</p>}\n                    <div className=\"flex justify-end gap-2 pt-2\">\n                        <button type=\"button\" onClick={onCancel} className=\"px-4 py-2 bg-gray-100 rounded-md\">Cancel</button>\n                        <button type=\"submit\" disabled={isLoading} className=\"btn-primary px-4 py-2 min-w-[120px] flex justify-center\">\n                            {isLoading ? <LoadingSpinner /> : 'Create Vault'}\n                        </button>\n                    </div>\n                </form>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/vault/UnlockVaultModal.tsx': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { useState } from 'react';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { LoadingSpinner } from '../shared/LoadingSpinner.tsx';\n\ninterface Props {\n    onSuccess: () => void;\n    onCancel: () => void;\n}\n\nexport const UnlockVaultModal: React.FC<Props> = ({ onSuccess, onCancel }) => {\n    const [password, setPassword] = useState('');\n    const [error, setError] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n\n    const handleSubmit = async (e: React.FormEvent) => {\n        e.preventDefault();\n        setError('');\n        setIsLoading(true);\n\n        try {\n            await vaultService.unlockVault(password);\n            onSuccess();\n        } catch (err) {\n            setError(err instanceof Error ? err.message : 'An unexpected error occurred.');\n            setIsLoading(false);\n        }\n    };\n\n    return (\n        <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n            <div className=\"bg-surface border border-border rounded-lg shadow-2xl w-full max-w-sm m-4 p-6 animate-pop-in\">\n                <h2 className=\"text-xl font-bold mb-2\">Unlock Vault</h2>\n                <p className=\"text-sm text-text-secondary mb-4\">\n                    Enter your Master Password to access your encrypted API keys for this session.\n                </p>\n                <form onSubmit={handleSubmit} className=\"space-y-4\">\n                    <div>\n                        <label className=\"block text-sm font-medium\">Master Password</label>\n                        <input\n                            type=\"password\"\n                            value={password}\n                            onChange={(e) => setPassword(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                            autoFocus\n                        />\n                    </div>\n                    {error && <p className=\"text-red-500 text-sm\">{error}</p>}\n                    <div className=\"flex justify-end gap-2 pt-2\">\n                        <button type=\"button\" onClick={onCancel} className=\"px-4 py-2 bg-gray-100 rounded-md\">Cancel</button>\n                        <button type=\"submit\" disabled={isLoading} className=\"btn-primary px-4 py-2 min-w-[100px] flex justify-center\">\n                            {isLoading ? <LoadingSpinner /> : 'Unlock'}\n                        </button>\n                    </div>\n                </form>\n            </div>\n        </div>\n    );\n};\n`,\n  'components/vault/VaultProvider.tsx': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { useState, useCallback, useMemo } from 'react';\nimport { VaultModalContext } from '../../contexts/VaultModalContext.tsx';\nimport { CreateMasterPasswordModal } from './CreateMasterPasswordModal.tsx';\nimport { UnlockVaultModal } from './UnlockVaultModal.tsx';\nimport * as vaultService from '../../services/vaultService.ts';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\n\ntype PromiseResolver = (value: boolean) => void;\n\nexport const VaultProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n    const { dispatch } = useGlobalState();\n    const [isCreateModalOpen, setCreateModalOpen] = useState(false);\n    const [isUnlockModalOpen, setUnlockModalOpen] = useState(false);\n    const [createPromise, setCreatePromise] = useState<{ resolve: PromiseResolver } | null>(null);\n    const [unlockPromise, setUnlockPromise] = useState<{ resolve: PromiseResolver } | null>(null);\n\n    const requestCreation = useCallback(() => {\n        return new Promise<boolean>((resolve) => {\n            setCreatePromise({ resolve });\n            setCreateModalOpen(true);\n        });\n    }, []);\n\n    const requestUnlock = useCallback(() => {\n        return new Promise<boolean>((resolve) => {\n            setUnlockPromise({ resolve });\n            setUnlockModalOpen(true);\n        });\n    }, []);\n\n    const handleCreateSuccess = () => {\n        dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: true, isUnlocked: true } });\n        createPromise?.resolve(true);\n        setCreateModalOpen(false);\n        setCreatePromise(null);\n    };\n\n    const handleCreateCancel = () => {\n        createPromise?.resolve(false);\n        setCreateModalOpen(false);\n        setCreatePromise(null);\n    };\n\n    const handleUnlockSuccess = () => {\n        dispatch({ type: 'SET_VAULT_STATE', payload: { isUnlocked: true } });\n        unlockPromise?.resolve(true);\n        setUnlockModalOpen(false);\n        setUnlockPromise(null);\n    };\n\n    const handleUnlockCancel = () => {\n        unlockPromise?.resolve(false);\n        setUnlockModalOpen(false);\n        setUnlockPromise(null);\n    };\n\n    const contextValue = useMemo(() => ({ requestUnlock, requestCreation }), [requestUnlock, requestCreation]);\n\n    return (\n        <VaultModalContext.Provider value={contextValue}>\n            {children}\n            {isCreateModalOpen && (\n                <CreateMasterPasswordModal\n                    onSuccess={handleCreateSuccess}\n                    onCancel={handleCreateCancel}\n                />\n            )}\n            {isUnlockModalOpen && (\n                <UnlockVaultModal\n                    onSuccess={handleUnlockSuccess}\n                    onCancel={handleUnlockCancel}\n                />\n            )}\n        </VaultModalContext.Provider>\n    );\n};\n`,\n  'constants.tsx': `\n\nimport React from 'react';\nimport {\n    CommandCenterIcon, CodeExplainerIcon, FeatureBuilderIcon, CodeMigratorIcon, ThemeDesignerIcon, SnippetVaultIcon,\n    UnitTestGeneratorIcon, CommitGeneratorIcon, GitLogAnalyzerIcon, ConcurrencyAnalyzerIcon, RegexSandboxIcon,\n    PromptCraftPadIcon, CodeFormatterIcon, JsonTreeIcon, CssGridEditorIcon, SchemaDesignerIcon, PwaManifestEditorIcon,\n    MarkdownSlidesIcon, ScreenshotToComponentIcon, SvgPathEditorIcon, StyleTransferIcon, CodingChallengeIcon,\n    CodeReviewBotIcon, ChangelogGeneratorIcon, CronJobBuilderIcon,\n    AsyncCallTreeIcon, AudioToCodeIcon, CodeDiffGhostIcon, CodeSpellCheckerIcon, ColorPaletteGeneratorIcon, LogicFlowBuilderIcon,\n    MetaTagEditorIcon, NetworkVisualizerIcon, ResponsiveTesterIcon, SassCompilerIcon, ImageGeneratorIcon, XbrlConverterIcon,\n    DigitalWhiteboardIcon, TypographyLabIcon, AiPullRequestAssistantIcon, ProjectExplorerIcon,\n    ServerStackIcon, DocumentTextIcon, ChartBarIcon, EyeIcon, PaperAirplaneIcon, CloudIcon, ShieldCheckIcon, CpuChipIcon, SparklesIcon,\n    MailIcon, BugAntIcon, MagnifyingGlassIcon, RectangleGroupIcon, GcpIcon, HomeIcon, PhotoIcon\n} from './components/icons.tsx';\n\nexport const CHROME_VIEW_IDS = ['features-list'] as const;\n\nexport const FEATURE_CATEGORIES = ['Core', 'AI Tools', 'Frontend', 'Testing', 'Database', 'Data', 'Productivity', 'Git', 'Local Dev', 'Performance & Auditing', 'Deployment & CI/CD', 'Security', 'Workflow', 'Cloud'] as const;\nexport type FeatureCategory = typeof FEATURE_CATEGORIES[number];\n\nexport type SlotCategory = FeatureCategory;\nexport const SLOTS: SlotCategory[] = ['Core', 'AI Tools', 'Frontend', 'Testing', 'Git', 'Productivity'];\n\ninterface RawFeature {\n    id: string;\n    name: string;\n    description: string;\n    icon: React.ReactNode;\n    category: FeatureCategory;\n}\n\nexport const RAW_FEATURES: RawFeature[] = [\n    // --- Domain 1: Local Development & Testing Parity ---\n    { id: \"env-manager\", name: \".env Manager\", description: \"A graphical interface for creating and managing .env files.\", icon: <DocumentTextIcon />, category: \"Local Dev\" },\n\n    // --- Domain 2: Performance & Optimization Intelligence ---\n    { id: \"performance-profiler\", name: \"AI Performance Profiler\", description: \"Analyze runtime traces and bundle stats with AI-powered advice.\", icon: <ChartBarIcon />, category: \"Performance & Auditing\" },\n    { id: \"a11y-auditor\", name: \"Accessibility Auditor\", description: \"Audit a live URL for accessibility issues and get AI-powered fixes.\", icon: <EyeIcon />, category: \"Performance & Auditing\" },\n    { id: \"tech-debt-sonar\", name: \"Tech Debt Sonar\", description: \"Scan code to find code smells and areas with high complexity.\", icon: <MagnifyingGlassIcon />, category: \"Performance & Auditing\" },\n\n    // --- Domain 3: Deployment & CI/CD Automation ---\n    { id: \"ci-cd-generator\", name: \"AI CI/CD Architect\", description: \"Generate CI/CD config files from a natural language description.\", icon: <PaperAirplaneIcon />, category: \"Deployment & CI/CD\" },\n    { id: \"deployment-preview\", name: \"Static Deployment Preview\", description: \"See a live preview of files generated by the AI Feature Builder.\", icon: <CloudIcon />, category: \"Deployment & CI/CD\" },\n    { id: \"terraform-generator\", name: \"AI Terraform Generator\", description: \"Generate Terraform config from a description and cloud context.\", icon: <CpuChipIcon />, category: \"Deployment & CI/CD\" },\n\n    // --- Domain 4: Security & Vulnerability Scanning ---\n    { id: \"security-scanner\", name: \"AI Security Scanner\", description: \"Find common vulnerabilities in code with static analysis and AI.\", icon: <ShieldCheckIcon />, category: \"Security\" },\n    { id: \"iam-policy-generator\", name: \"IAM Policy Generator\", description: \"Generate AWS or GCP IAM policies from a natural language description.\", icon: <ShieldCheckIcon />, category: \"Security\" },\n    { id: \"iam-policy-visualizer\", name: \"GCP IAM Policy Visualizer\", description: \"Visually test and audit GCP IAM permissions in real-time across your resources.\", icon: <GcpIcon />, category: \"Cloud\" },\n\n    // --- Existing Features (Re-categorized and Ordered) ---\n    { id: \"ai-command-center\", name: \"AI Command Center\", description: \"Use natural language to navigate and control the toolkit.\", icon: <CommandCenterIcon />, category: \"Core\" },\n    { id: \"project-explorer\", name: \"Project Explorer\", description: \"Manage and edit files from your connected repositories.\", icon: <ProjectExplorerIcon />, category: \"Core\" },\n    { id: \"workspace-connector-hub\", name: \"Workspace Connector Hub\", description: \"Connect to services like Jira, Slack & GitHub to orchestrate actions with AI.\", icon: <RectangleGroupIcon />, category: \"Workflow\" },\n    { id: \"linter-formatter\", name: \"AI Code Formatter\", description: \"AI-powered, real-time code formatting.\", icon: <CodeFormatterIcon />, category: \"Core\" },\n    { id: \"json-tree-navigator\", name: \"JSON Tree Navigator\", description: \"Navigate large JSON objects as a collapsible tree.\", icon: <JsonTreeIcon />, category: \"Core\" },\n    \n    { id: \"ai-image-generator\", name: \"AI Image Generator\", description: \"Generate high-quality images from a text prompt.\", icon: <ImageGeneratorIcon />, category: \"AI Tools\" },\n    { id: \"ai-code-explainer\", name: \"AI Code Explainer\", description: \"Get a structured analysis of code, including complexity.\", icon: <CodeExplainerIcon />, category: \"AI Tools\" },\n    { id: \"ai-feature-builder\", name: \"AI Feature Builder\", description: \"Generate code, tests, and commit messages from a prompt or API schema.\", icon: <FeatureBuilderIcon />, category: \"AI Tools\" },\n    { id: \"ai-personality-forge\", name: \"AI Personality Forge\", description: \"Architect, test, and save complex system prompts to create different 'AI personalities'.\", icon: <SparklesIcon />, category: \"AI Tools\" },\n    { id: \"ai-code-migrator\", name: \"AI Code Migrator\", description: \"Translate code between languages & frameworks.\", icon: <CodeMigratorIcon />, category: \"AI Tools\" },\n    { id: \"theme-designer\", name: \"AI Theme Designer\", description: \"Generate, fine-tune, and export UI color themes from a text description or image.\", icon: <ThemeDesignerIcon />, category: \"AI Tools\" },\n    { id: \"one-click-refactor\", name: \"One-Click Refactor\", description: \"Apply common refactoring patterns to your code with a single click.\", icon: <SparklesIcon />, category: \"AI Tools\" },\n    { id: \"ai-commit-generator\", name: \"AI Commit Message Generator\", description: \"Smart, conventional commits via AI.\", icon: <CommitGeneratorIcon />, category: \"AI Tools\" },\n    { id: \"prompt-craft-pad\", name: \"Prompt Craft Pad\", description: \"Save, edit, and manage your custom AI prompts with variable testing.\", icon: <PromptCraftPadIcon />, category: \"AI Tools\" },\n    { id: \"screenshot-to-component\", name: \"Screenshot to Component\", description: \"Turn UI screenshots into functional component code.\", icon: <ScreenshotToComponentIcon />, category: \"AI Tools\" },\n    { id: \"ai-style-transfer\", name: \"AI Code Style Transfer\", description: \"Rewrite code to match a specific style guide.\", icon: <StyleTransferIcon />, category: \"AI Tools\" },\n    { id: \"ai-coding-challenge\", name: \"AI Coding Challenge Generator\", description: \"Generate unique coding exercises.\", icon: <CodingChallengeIcon />, category: \"AI Tools\" },\n    { id: \"code-review-bot\", name: \"AI Code Review Bot\", description: \"Get an automated code review with one-click refactoring.\", icon: <CodeReviewBotIcon />, category: \"AI Tools\" },\n    { id: \"ai-pull-request-assistant\", name: \"AI Pull Request Assistant\", description: \"Generate a structured PR summary from code diffs and populate a full template.\", icon: <AiPullRequestAssistantIcon />, category: \"AI Tools\" },\n    { id: \"pr-summary-generator\", name: \"PR Summary Generator\", description: \"Generate a structured PR summary from code diffs.\", icon: <AiPullRequestAssistantIcon />, category: \"AI Tools\" },\n    { id: \"audio-to-code\", name: \"AI Audio-to-Code\", description: \"Speak your programming ideas and watch them turn into code.\", icon: <AudioToCodeIcon />, category: \"AI Tools\" },\n    \n    { id: \"css-grid-editor\", name: \"CSS Grid Visual Editor\", description: \"Drag-based layout builder for CSS Grid.\", icon: <CssGridEditorIcon />, category: \"Frontend\" },\n    { id: \"pwa-manifest-editor\", name: \"PWA Manifest Editor\", description: \"Configure and preview Progressive Web App manifests with a home screen simulator.\", icon: <PwaManifestEditorIcon />, category: \"Frontend\" },\n    { id: \"typography-lab\", name: \"Typography Lab\", description: \"Preview font pairings and get CSS import rules.\", icon: <TypographyLabIcon />, category: \"Frontend\" },\n    { id: \"font-preview-picker\", name: \"Font Preview Picker\", description: \"Preview custom text with different fonts.\", icon: <TypographyLabIcon />, category: \"Frontend\" },\n    { id: \"font-pairing-tool\", name: \"Font Pairing Tool\", description: \"Experiment with different font pairings for headings and body text.\", icon: <TypographyLabIcon />, category: \"Frontend\" },\n    { id: \"svg-path-editor\", name: \"SVG Path Editor\", description: \"Visually create and manipulate SVG path data with an interactive canvas.\", icon: <SvgPathEditorIcon />, category: \"Frontend\" },\n    { id: \"color-palette-generator\", name: \"AI Color Palette Generator\", description: \"Pick a base color and let Gemini design a beautiful palette.\", icon: <ColorPaletteGeneratorIcon />, category: \"Frontend\" },\n    { id: \"meta-tag-editor\", name: \"Meta Tag Editor\", description: \"Generate SEO/social media meta tags with a live social card preview.\", icon: <MetaTagEditorIcon />, category: \"Frontend\" },\n    { id: \"responsive-tester\", name: \"Responsive Tester\", description: \"Preview your web pages at different screen sizes and custom resolutions.\", icon: <ResponsiveTesterIcon />, category: \"Frontend\" },\n    { id: \"sass-scss-compiler\", name: \"SASS/SCSS Compiler\", description: \"A real-time SASS/SCSS to CSS compiler.\", icon: <SassCompilerIcon />, category: \"Frontend\" },\n    \n    { id: \"ai-unit-test-generator\", name: \"AI Unit Test Generator\", description: \"Generate unit tests from source code.\", icon: <UnitTestGeneratorIcon />, category: \"Testing\" },\n    { id: \"bug-reproducer\", name: \"Bug Reproducer\", description: \"Paste a stack trace to automatically generate a failing unit test.\", icon: <BugAntIcon />, category: \"Testing\" },\n    { id: \"worker-thread-debugger\", name: \"AI Concurrency Analyzer\", description: \"Analyze JS for Web Worker issues like race conditions.\", icon: <ConcurrencyAnalyzerIcon />, category: \"Testing\" },\n    { id: \"regex-sandbox\", name: \"RegEx Sandbox\", description: \"Visually test regular expressions, generate them with AI, and inspect match groups.\", icon: <RegexSandboxIcon />, category: \"Testing\" },\n    { id: \"async-call-tree-viewer\", name: \"Async Call Tree Viewer\", description: \"Visualize a tree of asynchronous function calls from JSON data.\", icon: <AsyncCallTreeIcon />, category: \"Testing\" },\n    { id: \"code-spell-checker\", name: \"Code Spell Checker\", description: \"A spell checker that finds common typos in code.\", icon: <CodeSpellCheckerIcon />, category: \"Testing\" },\n    { id: \"network-visualizer\", name: \"Network Visualizer\", description: \"Inspect network resources with a summary and visual waterfall chart.\", icon: <NetworkVisualizerIcon />, category: \"Testing\" },\n    \n    { id: \"visual-git-tree\", name: \"Visual Git Tree\", description: \"Visually trace your git commit history with an interactive graph and an AI-powered summary.\", icon: <GitLogAnalyzerIcon />, category: \"Git\" },\n    { id: \"changelog-generator\", name: \"AI Changelog Generator\", description: \"Auto-build changelogs from raw git logs.\", icon: <ChangelogGeneratorIcon />, category: \"Git\" },\n    { id: \"code-diff-ghost\", name: \"Code Diff Ghost\", description: \"Visualize code changes with a 'ghost typing' effect.\", icon: <CodeDiffGhostIcon />, category: \"Git\" },\n    \n    { id: \"cron-job-builder\", name: \"AI Cron Job Builder\", description: \"Visually tool to configure cron jobs, with AI.\", icon: <CronJobBuilderIcon />, category: \"Deployment & CI/CD\" },\n    \n    { id: \"portable-snippet-vault\", name: \"Snippet Vault\", description: \"Store, search, tag, and enhance reusable code snippets with AI.\", icon: <SnippetVaultIcon />, category: \"Productivity\" },\n    { id: \"digital-whiteboard\", name: \"Digital Whiteboard\", description: \"Organize ideas with interactive sticky notes and get AI-powered summaries.\", icon: <DigitalWhiteboardIcon />, category: \"Productivity\" },\n    { id: \"project-moodboard\", name: \"Project Moodboard\", description: \"A visual space to gather ideas, images, and notes.\", icon: <PhotoIcon />, category: \"Productivity\" },\n    { id: \"markdown-slides-generator\", name: \"Markdown Slides\", description: \"Turn markdown into a fullscreen presentation with an interactive overlay.\", icon: <MarkdownSlidesIcon />, category: \"Productivity\" },\n    { id: \"weekly-digest-generator\", name: \"Weekly Digest Generator\", description: \"Generate and send a weekly project summary email via Gmail.\", icon: <MailIcon />, category: \"Productivity\" },\n    { id: \"gmail-addon-simulator\", name: \"Gmail Add-on Simulator\", description: \"A simulation of how contextual add-on scopes would work inside Gmail.\", icon: <MailIcon />, category: \"Productivity\" },\n    \n    { id: \"schema-designer\", name: \"Schema Designer\", description: \"Visually design a database schema with a drag-and-drop interface and SQL export.\", icon: <SchemaDesignerIcon />, category: \"Database\" },\n    { id: \"xbrl-converter\", name: \"XBRL Converter\", description: \"Convert JSON data to a simplified XBRL-like XML format using AI.\", icon: <XbrlConverterIcon />, category: \"Data\" },\n    { id: \"logic-flow-builder\", name: \"Logic Flow Builder\", description: \"A visual tool for building application logic flows.\", icon: <LogicFlowBuilderIcon />, category: \"Workflow\" },\n];\n\nexport const ALL_FEATURE_IDS = RAW_FEATURES.map(f => f.id);`,\n  'contexts/.placeholder': ``,\n  'contexts/GlobalStateContext.tsx': `import React, { createContext, useReducer, useContext, useEffect } from 'react';\nimport type { ViewType, AppUser, GitHubUser, FileNode } from '../types.ts';\n\n// State shape\ninterface GlobalState {\n  activeView: ViewType;\n  viewProps: any;\n  hiddenFeatures: string[];\n  user: AppUser | null;\n  githubUser: GitHubUser | null;\n  projectFiles: FileNode | null;\n  // Fix: Expand selectedRepo to include full_name and name for consistent usage across components\n  selectedRepo: { owner: string; repo: string; full_name: string; name: string; } | null;\n  vaultState: {\n    isInitialized: boolean;\n    isUnlocked: boolean;\n  };\n  isApiKeyMissing: boolean;\n}\n\n// Action types\ntype Action =\n  | { type: 'SET_VIEW'; payload: { view: ViewType, props?: any } }\n  | { type: 'TOGGLE_FEATURE_VISIBILITY'; payload: { featureId: string } }\n  | { type: 'SET_APP_USER', payload: AppUser | null }\n  | { type: 'SET_GITHUB_USER', payload: GitHubUser | null }\n  | { type: 'LOAD_PROJECT_FILES'; payload: FileNode | null }\n  // Fix: Expand selectedRepo payload to include full_name and name\n  | { type: 'SET_SELECTED_REPO'; payload: { owner: string; repo: string; full_name: string; name: string; } | null }\n  | { type: 'SET_VAULT_STATE'; payload: Partial<{ isInitialized: boolean, isUnlocked: boolean }> }\n  | { type: 'SET_API_KEY_MISSING', payload: boolean };\n\n\nconst initialState: GlobalState = {\n  activeView: 'project-explorer',\n  viewProps: {},\n  hiddenFeatures: [],\n  user: null,\n  githubUser: null,\n  projectFiles: null,\n  selectedRepo: null,\n  vaultState: {\n    isInitialized: false,\n    isUnlocked: false,\n  },\n  isApiKeyMissing: false,\n};\n\nconst reducer = (state: GlobalState, action: Action): GlobalState => {\n  switch (action.type) {\n    case 'SET_VIEW':\n      return { ...state, activeView: action.payload.view, viewProps: action.payload.props || {} };\n    case 'TOGGLE_FEATURE_VISIBILITY': {\n        const { featureId } = action.payload;\n        const isHidden = state.hiddenFeatures.includes(featureId);\n        const newHiddenFeatures = isHidden\n            ? state.hiddenFeatures.filter(id => id !== featureId)\n            : [...state.hiddenFeatures, featureId];\n        return { ...state, hiddenFeatures: newHiddenFeatures };\n    }\n    case 'SET_APP_USER':\n        if (action.payload === null) { // User logged out\n            return {\n                ...initialState, // Reset to initial state on logout\n                user: null,\n            }\n        }\n        return { ...state, user: action.payload };\n    case 'SET_GITHUB_USER':\n        return {\n            ...state,\n            githubUser: action.payload,\n             // Reset repo-specific data if disconnected\n            selectedRepo: action.payload ? state.selectedRepo : null,\n            projectFiles: action.payload ? state.projectFiles : null,\n        }\n    case 'LOAD_PROJECT_FILES':\n      return { ...state, projectFiles: action.payload };\n    case 'SET_SELECTED_REPO':\n      return { ...state, selectedRepo: action.payload, projectFiles: null }; // Reset files on repo change\n    case 'SET_VAULT_STATE':\n        return {\n            ...state,\n            vaultState: { ...state.vaultState, ...action.payload },\n        };\n    case 'SET_API_KEY_MISSING':\n        return { ...state, isApiKeyMissing: action.payload };\n    default:\n      return state;\n  }\n};\n\nconst GlobalStateContext = createContext<{\n  state: GlobalState;\n  dispatch: React.Dispatch<Action>;\n}>({\n  state: initialState,\n  dispatch: () => null,\n});\n\nconst LOCAL_STORAGE_KEY = 'devcore_snapshot';\nconst CONSENT_KEY = 'devcore_ls_consent';\n\nexport const GlobalStateProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n    const canPersist = (() => {\n        try {\n            return localStorage.getItem(CONSENT_KEY) === 'granted';\n        } catch (e) {\n            return false;\n        }\n    })();\n\n    const [state, dispatch] = useReducer(reducer, initialState, (initial) => {\n        if (!canPersist) return initial;\n        \n        try {\n            const storedStateJSON = localStorage.getItem(LOCAL_STORAGE_KEY);\n            if (!storedStateJSON) return initial;\n            \n            const storedState = JSON.parse(storedStateJSON);\n            const hydratedState = { ...initial };\n\n            // Hydrate state from local storage\n            if (storedState.selectedRepo) hydratedState.selectedRepo = storedState.selectedRepo;\n            if (storedState.activeView) hydratedState.activeView = storedState.activeView;\n            if (storedState.viewProps) hydratedState.viewProps = storedState.viewProps;\n            if (storedState.hiddenFeatures) hydratedState.hiddenFeatures = storedState.hiddenFeatures;\n            \n            return hydratedState;\n        } catch (error) {\n            console.error(\"Failed to parse state from localStorage\", error);\n            return initial;\n        }\n    });\n\n    useEffect(() => {\n        if (!canPersist) return;\n\n        const handler = setTimeout(() => {\n            try {\n                const stateToSave = { \n                    selectedRepo: state.selectedRepo,\n                    activeView: state.activeView,\n                    viewProps: state.viewProps,\n                    hiddenFeatures: state.hiddenFeatures, \n                };\n                localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(stateToSave));\n            } catch (error) {\n                console.error(\"Failed to save state to localStorage\", error);\n            }\n        }, 500);\n\n        return () => clearTimeout(handler);\n    }, [state, canPersist]);\n\n    return (\n        <GlobalStateContext.Provider value={{ state, dispatch }}>\n            {children}\n        </GlobalStateContext.Provider>\n    );\n};\n\nexport const useGlobalState = () => useContext(GlobalStateContext);`,\n  'contexts/NotificationContext.tsx': `import React, { createContext, useContext, useState, useCallback } from 'react';\n\ntype NotificationType = 'success' | 'error' | 'info';\n\ninterface Notification {\n  id: number;\n  message: string;\n  type: NotificationType;\n}\n\ninterface NotificationContextType {\n  addNotification: (message: string, type?: NotificationType) => void;\n}\n\nconst NotificationContext = createContext<NotificationContextType | undefined>(undefined);\n\nexport const useNotification = () => {\n  const context = useContext(NotificationContext);\n  if (!context) {\n    throw new Error('useNotification must be used within a NotificationProvider');\n  }\n  return context;\n};\n\nexport const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n  const [notifications, setNotifications] = useState<Notification[]>([]);\n\n  const addNotification = useCallback((message: string, type: NotificationType = 'info') => {\n    const id = Date.now();\n    setNotifications(prev => [...prev, { id, message, type }]);\n    setTimeout(() => {\n      setNotifications(prev => prev.filter(n => n.id !== id));\n    }, 4000);\n  }, []);\n  \n  const typeStyles = {\n    success: 'bg-emerald-500 border-emerald-600',\n    error: 'bg-red-500 border-red-600',\n    info: 'bg-sky-500 border-sky-600'\n  };\n\n  return (\n    <NotificationContext.Provider value={{ addNotification }}>\n      {children}\n      <div className=\"fixed bottom-4 right-4 z-[100] space-y-2 w-full max-w-sm\">\n        {notifications.map(notification => (\n           <div key={notification.id} role=\"alert\" className={\\`relative animate-pop-in shadow-lg rounded-lg text-white font-medium p-4 border-b-4 \\${typeStyles[notification.type]}\\`}>\n               {notification.message}\n           </div>\n        ))}\n      </div>\n    </NotificationContext.Provider>\n  );\n};`,\n  'contexts/OctokitContext.tsx': `import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';\nimport type { Octokit } from 'octokit';\nimport { initializeOctokit } from '../services/authService.ts';\nimport { getDecryptedCredential } from '../services/vaultService.ts';\nimport { useGlobalState } from './GlobalStateContext.tsx';\nimport { useVaultModal } from './VaultModalContext.tsx';\nimport { useNotification } from './NotificationContext.tsx';\n\ninterface OctokitContextType {\n    octokit: Octokit | null;\n    reinitialize: () => Promise<void>;\n}\n\nconst OctokitContext = createContext<OctokitContextType | undefined>(undefined);\n\nexport const useOctokit = (): OctokitContextType => {\n    const context = useContext(OctokitContext);\n    if (!context) {\n        throw new Error('useOctokit must be used within an OctokitProvider');\n    }\n    return context;\n};\n\nexport const OctokitProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n    const [octokit, setOctokit] = useState<Octokit | null>(null);\n    const { state, dispatch } = useGlobalState();\n    const { user, vaultState } = state;\n    const { requestUnlock } = useVaultModal();\n    const { addNotification } = useNotification();\n    \n    const initialize = useCallback(async () => {\n        if (!user) {\n            setOctokit(null);\n            return;\n        }\n\n        let isVaultUnlocked = vaultState.isUnlocked;\n\n        if (!isVaultUnlocked) {\n            const unlocked = await requestUnlock();\n            if (!unlocked) {\n                setOctokit(null);\n                return;\n            }\n        }\n\n        try {\n            const token = await getDecryptedCredential('github_pat');\n            if (token) {\n                const client = initializeOctokit(token);\n                setOctokit(client);\n            } else {\n                setOctokit(null); // No token stored, so no client.\n            }\n        } catch (e) {\n            if (e instanceof Error && e.message.includes('Decryption failed')) {\n                 dispatch({ type: 'SET_VAULT_STATE', payload: { isUnlocked: false } });\n            }\n            addNotification('Failed to initialize GitHub client.', 'error');\n            setOctokit(null);\n        }\n\n    }, [user, vaultState.isUnlocked, requestUnlock, addNotification, dispatch]);\n\n    useEffect(() => {\n        // Initialize when the user logs in or vault state changes to unlocked\n        if (user && vaultState.isUnlocked) {\n            initialize();\n        } else {\n            setOctokit(null);\n        }\n    }, [user, vaultState.isUnlocked, initialize]);\n\n    return (\n        <OctokitContext.Provider value={{ octokit, reinitialize: initialize }}>\n            {children}\n        </OctokitContext.Provider>\n    );\n};`,\n  'contexts/VaultModalContext.tsx': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport React, { createContext, useContext } from 'react';\n\ninterface VaultModalContextType {\n    requestUnlock: () => Promise<boolean>;\n    requestCreation: () => Promise<boolean>;\n}\n\nexport const VaultModalContext = createContext<VaultModalContextType | undefined>(undefined);\n\nexport const useVaultModal = (): VaultModalContextType => {\n    const context = useContext(VaultModalContext);\n    if (!context) {\n        throw new Error('useVaultModal must be used within a VaultProvider');\n    }\n    return context;\n};\n`,\n  'githubService.ts': `import type { Octokit } from 'octokit';\nimport type { Repo, FileNode } from './types.ts';\nimport { logEvent, logError, measurePerformance } from './services/index.ts';\n\n// --- Repository-Level Functions ---\n\n/**\n * Fetches the repositories for the authenticated user.\n * @param octokit An authenticated Octokit instance.\n * @returns A promise that resolves to an array of Repo objects.\n */\nexport const getRepos = async (octokit: Octokit): Promise<Repo[]> => {\n    return measurePerformance('getRepos', async () => {\n        logEvent('getRepos_start');\n        try {\n            const { data } = await octokit.request('GET /user/repos', {\n                type: 'owner',\n                sort: 'updated',\n                per_page: 100,\n            });\n            logEvent('getRepos_success', { count: data.length });\n            return data as Repo[];\n        } catch (error) {\n            logError(error as Error, { context: 'getRepos' });\n            throw new Error(\\`Failed to fetch repositories: \\${(error as Error).message}\\`);\n        }\n    });\n};\n\n/**\n * Deletes a repository. This is a destructive action.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @returns A promise that resolves when the deletion is complete.\n */\nexport const deleteRepo = async (octokit: Octokit, owner: string, repo: string): Promise<void> => {\n     return measurePerformance('deleteRepo', async () => {\n        logEvent('deleteRepo_start', { owner, repo });\n        try {\n            await octokit.request('DELETE /repos/{owner}/{repo}', {\n                owner,\n                repo,\n            });\n            logEvent('deleteRepo_success', { owner, repo });\n        } catch (error) {\n            logError(error as Error, { context: 'deleteRepo', owner, repo });\n            throw new Error(\\`Failed to delete repository: \\${(error as Error).message}\\`);\n        }\n    });\n};\n\n// --- File and Tree Functions ---\n\n/**\n * Fetches the file tree for a repository recursively.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @returns A promise that resolves to the root FileNode of the repository.\n */\nexport const getRepoTree = async (octokit: Octokit, owner: string, repo: string): Promise<FileNode> => {\n     return measurePerformance('getRepoTree', async () => {\n        logEvent('getRepoTree_start', { owner, repo });\n        try {\n            const { data: repoData } = await octokit.request('GET /repos/{owner}/{repo}', { owner, repo });\n            const defaultBranch = repoData.default_branch;\n\n            const { data: branch } = await octokit.request('GET /repos/{owner}/{repo}/branches/{branch}', {\n                owner,\n                repo,\n                branch: defaultBranch,\n            });\n            const treeSha = branch.commit.commit.tree.sha;\n            \n            const { data: treeData } = await octokit.request('GET /repos/{owner}/{repo}/git/trees/{tree_sha}', {\n                owner,\n                repo,\n                tree_sha: treeSha,\n                recursive: 'true',\n            });\n\n            const root: FileNode = { name: repo, type: 'folder', path: '', children: [] };\n            \n            treeData.tree.forEach((item: any) => {\n                const pathParts = item.path.split('/');\n                let currentNode = root;\n\n                pathParts.forEach((part) => {\n                    if (!currentNode.children) {\n                        currentNode.children = [];\n                    }\n                    let childNode = currentNode.children.find(child => child.name === part);\n\n                    if (!childNode) {\n                        childNode = {\n                            name: part,\n                            path: item.path,\n                            type: item.type === 'tree' ? 'folder' : 'file',\n                        };\n                        if(item.type === 'tree') childNode.children = [];\n                        currentNode.children.push(childNode);\n                    }\n                    currentNode = childNode;\n                });\n            });\n\n            logEvent('getRepoTree_success', { owner, repo, items: treeData.tree.length });\n            return root;\n        } catch (error) {\n            logError(error as Error, { context: 'getRepoTree', owner, repo });\n            throw new Error(\\`Failed to fetch repository tree: \\${(error as Error).message}\\`);\n        }\n    });\n};\n\n/**\n * Fetches the content of a specific file from a repository.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @param path The full path to the file within the repository.\n * @returns A promise that resolves to the string content of the file.\n */\nexport const getFileContent = async (octokit: Octokit, owner: string, repo: string, path: string): Promise<string> => {\n    return measurePerformance('getFileContent', async () => {\n        logEvent('getFileContent_start', { owner, repo, path });\n        try {\n            const { data } = await octokit.request('GET /repos/{owner}/{repo}/contents/{path}', {\n                owner,\n                repo,\n                path,\n            });\n\n            if (Array.isArray(data) || data.type !== 'file' || typeof data.content !== 'string') {\n                 throw new Error(\"Path did not point to a valid file or content was missing.\");\n            }\n\n            // The content is Base64 encoded, so we need to decode it.\n            const content = atob(data.content);\n            logEvent('getFileContent_success', { owner, repo, path });\n            return content;\n        } catch (error) {\n             logError(error as Error, { context: 'getFileContent', owner, repo, path });\n             throw new Error(\\`Failed to fetch file content: \\${(error as Error).message}\\`);\n        }\n    });\n};\n\n// --- Commit and Branching Functions ---\n\n/**\n * Commits one or more files to a repository in a single commit.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @param files An array of file objects with path and content.\n * @param message The commit message.\n * @param branch The branch to commit to (defaults to 'main').\n * @returns A promise that resolves with the URL of the new commit.\n */\nexport const commitFiles = async (\n    octokit: Octokit,\n    owner: string,\n    repo: string,\n    files: { path: string; content: string }[],\n    message: string,\n    branch: string = 'main'\n): Promise<string> => {\n    return measurePerformance('commitFiles', async () => {\n        logEvent('commitFiles_start', { owner, repo, fileCount: files.length, branch });\n\n        try {\n            // 1. Get the latest commit SHA and base tree SHA\n            const { data: refData } = await octokit.request('GET /repos/{owner}/{repo}/git/ref/{ref}', {\n                owner,\n                repo,\n                ref: \\`heads/\\${branch}\\`,\n            });\n            const latestCommitSha = refData.object.sha;\n            const { data: commitData } = await octokit.request('GET /repos/{owner}/{repo}/git/commits/{commit_sha}', {\n                owner,\n                repo,\n                commit_sha: latestCommitSha,\n            });\n            const baseTreeSha = commitData.tree.sha;\n\n            // 2. Create blobs for all new file contents\n            const blobPromises = files.map(file =>\n                octokit.request('POST /repos/{owner}/{repo}/git/blobs', {\n                    owner,\n                    repo,\n                    content: file.content,\n                    encoding: 'utf-8',\n                })\n            );\n            const blobs = await Promise.all(blobPromises);\n            \n            // 3. Create the tree object\n            const tree = blobs.map((blob, index) => ({\n                path: files[index].path,\n                mode: '100644' as const, // file mode\n                type: 'blob' as const,\n                sha: blob.data.sha,\n            }));\n\n            // 4. Create a new tree\n            const { data: newTree } = await octokit.request('POST /repos/{owner}/{repo}/git/trees', {\n                owner,\n                repo,\n                base_tree: baseTreeSha,\n                tree,\n            });\n\n            // 5. Create a new commit\n            const { data: newCommit } = await octokit.request('POST /repos/{owner}/{repo}/git/commits', {\n                owner,\n                repo,\n                message,\n                tree: newTree.sha,\n                parents: [latestCommitSha],\n            });\n\n            // 6. Update the branch reference (fast-forward)\n            await octokit.request('PATCH /repos/{owner}/{repo}/git/refs/{ref}', {\n                owner,\n                repo,\n                ref: \\`heads/\\${branch}\\`,\n                sha: newCommit.sha,\n            });\n\n            logEvent('commitFiles_success', { commitUrl: newCommit.html_url });\n            return newCommit.html_url;\n\n        } catch (error) {\n            logError(error as Error, { context: 'commitFiles', owner, repo, branch });\n            throw new Error(\\`Failed to commit files: \\${(error as Error).message}\\`);\n        }\n    });\n};`,\n  'globals.d.ts': `// globals.d.ts\ndeclare global {\n  /**\n   * Loads the Pyodide WebAssembly module.\n   * @param config Optional configuration for Pyodide.\n   */\n  function loadPyodide(config?: { indexURL?: string }): Promise<any>;\n\n  interface Window {\n    google?: {\n      accounts: {\n        id: {\n          disableAutoSelect: () => void;\n        };\n        // Fix: Add oauth2 property to the google.accounts type definition to resolve TypeScript error in googleAuthService.ts.\n        oauth2: {\n          initTokenClient: (config: any) => any;\n          revoke: (token: string, callback: (response: any) => void) => void;\n        };\n      };\n    };\n  }\n}\n\n// This export statement is required to make the file a module.\nexport {};`,\n  'hooks/.placeholder': ``,\n  'hooks/useAiPersonalities.ts': `import { useLocalStorage } from './useLocalStorage.ts';\nimport type { SystemPrompt } from '../types.ts';\n\nconst defaultPersonalities: SystemPrompt[] = [\n    {\n        id: '1',\n        name: 'Default Reviewer',\n        persona: 'You are a senior software engineer performing a code review. You are meticulous, helpful, and provide constructive feedback.',\n        rules: ['Be clear and concise.', 'Provide code examples for suggestions.', 'Explain the \"why\" behind your suggestions.'],\n        outputFormat: 'markdown',\n        exampleIO: []\n    },\n    {\n        id: '2',\n        name: 'Sarcastic Senior Dev',\n        persona: 'You are a cynical, sarcastic, but brilliant senior software engineer. Your feedback is brutally honest and often humorous, but always technically correct.',\n        rules: ['Use a sarcastic tone.', 'Point out rookie mistakes without mercy.', 'Your code suggestions must be flawless.'],\n        outputFormat: 'markdown',\n        exampleIO: [\n            {\n                input: 'I wrote this function: \\`function add(a,b){return a+b}\\`',\n                output: 'Wow, a function that adds two numbers. Groundbreaking. Did you consider that maybe, just maybe, you should add a semicolon at the end? \\`function add(a, b) { return a + b; };\\`'\n            }\n        ]\n    }\n];\n\n\n/**\n * A custom hook to access the list of saved AI personalities.\n * @returns An array of SystemPrompt objects.\n */\nexport const useAiPersonalities = (): [SystemPrompt[], (value: SystemPrompt[] | ((val: SystemPrompt[]) => SystemPrompt[])) => void] => {\n    const [personalities, setPersonalities] = useLocalStorage<SystemPrompt[]>('devcore_ai_personalities', defaultPersonalities);\n    return [personalities, setPersonalities];\n};`,\n  'hooks/useLocalStorage.ts': `import { useState } from 'react';\n\nexport const useLocalStorage = <T,>(key: string, initialValue: T) => {\n    const [storedValue, setStoredValue] = useState<T>(() => {\n        try {\n            const consent = window.localStorage.getItem('devcore_ls_consent');\n            if (consent !== 'granted') return initialValue;\n\n            const item = window.localStorage.getItem(key);\n            return item ? JSON.parse(item) : initialValue;\n        } catch (error) {\n            console.error(\\`Error reading localStorage key “\\${key}”:\\`, error);\n            return initialValue;\n        }\n    });\n\n    const setValue = (value: T | ((val: T) => T)) => {\n        try {\n            const consent = window.localStorage.getItem('devcore_ls_consent');\n            if (consent !== 'granted') {\n                // If consent is not granted, only update the in-memory state\n                const valueToStore = value instanceof Function ? value(storedValue) : value;\n                setStoredValue(valueToStore);\n                return;\n            };\n\n            const valueToStore = value instanceof Function ? value(storedValue) : value;\n            setStoredValue(valueToStore);\n            window.localStorage.setItem(key, JSON.stringify(valueToStore));\n        } catch (error) {\n            console.error(\\`Error setting localStorage key “\\${key}”:\\`, error);\n        }\n    };\n\n    return [storedValue, setValue] as const;\n};`,\n  'hooks/useTheme.ts': `import { useEffect } from 'react';\nimport { useLocalStorage } from './useLocalStorage.ts';\nimport type { ThemeState, ColorTheme, Theme } from '../types.ts';\n\nconst defaultThemeState: ThemeState = {\n    mode: 'light',\n    customColors: null,\n};\n\nconst applyColors = (colors: ColorTheme | null) => {\n    const root = window.document.documentElement;\n    if (colors) {\n        root.style.setProperty('--color-primary', colors.primary);\n        root.style.setProperty('--color-background', colors.background);\n        root.style.setProperty('--color-surface', colors.surface);\n        root.style.setProperty('--color-text-primary', colors.textPrimary);\n        root.style.setProperty('--color-text-secondary', colors.textSecondary);\n        root.style.setProperty('--color-text-on-primary', colors.textOnPrimary);\n        root.style.setProperty('--color-border', colors.border);\n        const rgb = colors.primary.match(/\\\\w\\\\w/g)?.map(x => parseInt(x, 16));\n        if (rgb) {\n             root.style.setProperty('--color-primary-rgb', rgb.join(', '));\n        }\n    } else {\n        // Clear inline styles to revert to CSS-defined variables\n        root.style.removeProperty('--color-primary');\n        root.style.removeProperty('--color-background');\n        root.style.removeProperty('--color-surface');\n        root.style.removeProperty('--color-text-primary');\n        root.style.removeProperty('--color-text-secondary');\n        root.style.removeProperty('--color-text-on-primary');\n        root.style.removeProperty('--color-border');\n        root.style.removeProperty('--color-primary-rgb');\n    }\n}\n\nexport const useTheme = (): [ThemeState, () => void, (colors: ColorTheme, mode: Theme) => void, () => void] => {\n    const [themeState, setThemeState] = useLocalStorage<ThemeState>('devcore_theme_state', defaultThemeState);\n\n    useEffect(() => {\n        const root = window.document.documentElement;\n        root.classList.remove('light', 'dark');\n        root.classList.add(themeState.mode);\n        applyColors(themeState.customColors);\n    }, [themeState]);\n\n    const toggleTheme = () => {\n        setThemeState(prev => ({\n            ...prev,\n            mode: prev.mode === 'light' ? 'dark' : 'light'\n        }));\n    };\n    \n    const applyCustomTheme = (colors: ColorTheme, mode: Theme) => {\n        setThemeState({ mode, customColors: colors });\n    };\n\n    const clearCustomTheme = () => {\n        // We keep the mode, but clear custom colors\n        setThemeState(prev => ({ ...prev, customColors: null }));\n    };\n\n    return [themeState, toggleTheme, applyCustomTheme, clearCustomTheme];\n};\n`,\n  'index.css': `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n  --color-primary: #0047AB; /* Cobalt Blue */\n  --color-primary-rgb: 0, 71, 171;\n  --color-background: #F5F7FA; /* Light silver-blue */\n  --color-surface: #FFFFFF;\n  --color-text-primary: #111827; /* Gray 900 */\n  --color-text-secondary: #6B7280; /* Gray 500 */\n  --color-text-on-primary: #FFFFFF;\n  --color-border: #E5E7EB; /* Gray 200 */\n}\n\n.dark {\n  --color-primary: #38bdf8; /* sky-400 */\n  --color-primary-rgb: 56, 189, 248;\n  --color-background: #0f172a; /* slate-900 */\n  --color-surface: #1e293b; /* slate-800 */\n  --color-text-primary: #f8fafc; /* slate-50 */\n  --color-text-secondary: #94a3b8; /* slate-400 */\n  --color-text-on-primary: #0f172a; /* slate-900 */\n  --color-border: #334155; /* slate-700 */\n}\n\n/* Custom global styles */\nbody {\n  @apply bg-background text-text-primary transition-colors duration-300;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\nhtml.dark body {\n    background-image: none;\n}\n\n\n#root {\n  position: relative;\n  z-index: 1;\n}\n\n#root::before {\n  content: 'CitiBank demo business inc';\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%) rotate(-30deg);\n  font-family: theme('fontFamily.serif');\n  font-size: clamp(2rem, 8vw, 6rem); /* Responsive font size */\n  font-weight: bold;\n  color: theme('colors.gold');\n  opacity: 0.08;\n  pointer-events: none;\n  z-index: -1;\n  white-space: nowrap;\n}\n\nh1, h2, h3, h4, h5, h6 {\n  @apply font-serif text-text-primary;\n}\n\nh1 {\n  @apply text-text-primary;\n}\n\n/* Update primary buttons for a professional look */\n.btn-primary {\n  @apply bg-primary text-text-on-primary font-bold rounded-md hover:opacity-90 transition-all disabled:opacity-50 shadow-md;\n}\n\n/* Custom scrollbars for the new light theme */\n::-webkit-scrollbar {\n  width: 8px;\n  height: 8px;\n}\n::-webkit-scrollbar-track {\n  @apply bg-gray-100 dark:bg-slate-800;\n}\n::-webkit-scrollbar-thumb {\n  @apply bg-gray-400 dark:bg-slate-600 rounded;\n}\n::-webkit-scrollbar-thumb:hover {\n  @apply bg-gray-500 dark:bg-slate-500;\n}\n\n/* Base transitions for interactive elements */\nbutton, a, input, textarea, select {\n  transition: all 0.2s ease-in-out;\n}\n\n/* Keyframe Animations */\n@keyframes fadeIn {\n  from { opacity: 0; }\n  to { opacity: 1; }\n}\n\n@keyframes shake {\n  10%, 90% { transform: translateX(-1px); }\n  20%, 80% { transform: translateX(2px); }\n  30%, 50%, 70% { transform: translateX(-3px); }\n  40%, 60% { transform: translateX(3px); }\n}\n\n@keyframes pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95) translateY(10px);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1) translateY(0);\n  }\n}\n\n.fade-in { animation: fadeIn 0.5s ease-in-out forwards; }\n.animate-shake { animation: shake 0.4s ease-in-out; }\n.animate-pop-in { animation: pop-in 0.3s ease-out forwards; }\n\n/* For hiding scrollbar but keeping functionality */\n.no-scrollbar::-webkit-scrollbar { display: none; }\n.no-scrollbar { \n  -ms-overflow-style: none; \n  scrollbar-width: none; \n  scroll-behavior: smooth;\n}`,\n  'index.html': `<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Citibank Demo Business Inc</title>\n    <script src=\"https://apis.google.com/js/api.js\"></script>\n    <style>\n      html, body, #root {\n        margin: 0;\n        padding: 0;\n        height: 100%;\n        width: 100%;\n        overflow: hidden;\n      }\n    </style>\n  <link rel=\"stylesheet\" href=\"/index.css\">\n<script type=\"importmap\">\n{\n  \"imports\": {\n    \"react/\": \"https://aistudiocdn.com/react@^19.1.1/\",\n    \"react\": \"https://aistudiocdn.com/react@^19.1.1\",\n    \"react-dom/\": \"https://aistudiocdn.com/react-dom@^19.1.1/\",\n    \"vite\": \"https://aistudiocdn.com/vite@^7.1.3\",\n    \"path\": \"https://aistudiocdn.com/path@^0.12.7\",\n    \"url\": \"https://aistudiocdn.com/url@^0.11.4\",\n    \"marked\": \"https://aistudiocdn.com/marked@^16.2.0\",\n    \"@google/genai\": \"https://aistudiocdn.com/@google/genai@^1.15.0\",\n    \"react-colorful\": \"https://aistudiocdn.com/react-colorful@^5.6.1\",\n    \"mermaid\": \"https://aistudiocdn.com/mermaid@^11.10.1\",\n    \"idb\": \"https://aistudiocdn.com/idb@^8.0.3\",\n    \"axe-core\": \"https://aistudiocdn.com/axe-core@^4.10.3\",\n    \"@tailwindcss/typography\": \"https://aistudiocdn.com/@tailwindcss/typography@^0.5.16\",\n    \"diff\": \"https://aistudiocdn.com/diff@^8.0.2\",\n    \"octokit\": \"https://aistudiocdn.com/octokit@^5.0.3\",\n    \"jszip\": \"https://aistudiocdn.com/jszip@^3.10.1\",\n    \"fs\": \"https://aistudiocdn.com/fs@^0.0.1-security\"\n  }\n}\n</script>\n</head>\n  <body>\n    <div id=\"root\"></div>\n    <script id=\"gsi-client\" src=\"https://accounts.google.com/gsi/client\" async defer></script>\n    <script type=\"module\" src=\"/index.tsx\"></script>\n  </body>\n</html>`,\n  'index.tsx': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App.tsx';\nimport { GlobalStateProvider } from './contexts/GlobalStateContext.tsx';\nimport './index.css';\n\nconst rootElement = document.getElementById('root');\nif (!rootElement) {\n  throw new Error(\"Could not find root element to mount to\");\n}\n\nconst root = ReactDOM.createRoot(rootElement);\nroot.render(\n  <React.StrictMode>\n    <GlobalStateProvider>\n        <App />\n    </GlobalStateProvider>\n  </React.StrictMode>\n);`,\n  'metadata.json': `{\n  \"name\": \"slowassshit\",\n  \"description\": \"A scaffolded project with a professional directory structure for building scalable and maintainable front-end applications.\",\n  \"requestFramePermissions\": []\n}`,\n  'package.json': `{\n  \"name\": \"devcore-ai-toolkit\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"prebuild\": \"node --loader ts-node/esm ./scripts/generateSourceRegistry.ts\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\"\n  },\n  \"dependencies\": {\n    \"@google/genai\": \"^1.12.0\",\n    \"axe-core\": \"^4.9.1\",\n    \"diff\": \"^5.2.0\",\n    \"idb\": \"^8.0.0\",\n    \"jszip\": \"^3.10.1\",\n    \"marked\": \"^13.0.2\",\n    \"mermaid\": \"^10.9.1\",\n    \"octokit\": \"^4.0.2\",\n    \"react\": \"^18.2.0\",\n    \"react-colorful\": \"^5.6.1\",\n    \"react-dom\": \"^18.2.0\"\n  },\n  \"devDependencies\": {\n    \"@tailwindcss/typography\": \"^0.5.13\",\n    \"@types/diff\": \"^5.2.1\",\n    \"@types/jszip\": \"^3.4.1\",\n    \"@types/marked\": \"^6.0.0\",\n    \"@types/node\": \"^20.14.9\",\n    \"@types/react\": \"^18.2.0\",\n    \"@types/react-dom\": \"^18.2.0\",\n    \"autoprefixer\": \"^10.4.19\",\n    \"postcss\": \"^8.4.38\",\n    \"tailwindcss\": \"^3.4.3\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.5.2\",\n    \"vite\": \"^7.1.2\"\n  }\n}`,\n  'postcss.config.js': `export default {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n`,\n  'public/.placeholder': ``,\n  'public/mock-service-worker.js': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nconst MOCK_ROUTES = new Map();\n\nself.addEventListener('install', (event) => {\n  self.skipWaiting();\n});\n\nself.addEventListener('activate', (event) => {\n  event.waitUntil(self.clients.claim());\n});\n\nself.addEventListener('message', (event) => {\n  if (event.data.type === 'SET_ROUTES') {\n    const routes = event.data.routes || [];\n    MOCK_ROUTES.clear();\n    routes.forEach(route => {\n        // Simple wildcard support\n        const regex = new RegExp('^' + route.path.replace(/\\\\*/g, '.*') + '\\$');\n        MOCK_ROUTES.set(regex, {\n            method: route.method,\n            response: route.response,\n        });\n    });\n  }\n});\n\nself.addEventListener('fetch', (event) => {\n  const url = new URL(event.request.url);\n  const path = url.pathname;\n  const method = event.request.method;\n\n  for (const [routeRegex, routeInfo] of MOCK_ROUTES.entries()) {\n    if (routeRegex.test(path) && routeInfo.method === method) {\n      event.respondWith(\n        new Response(JSON.stringify(routeInfo.response.body), {\n          status: routeInfo.response.status,\n          headers: { 'Content-Type': 'application/json', ...routeInfo.response.headers },\n        })\n      );\n      return;\n    }\n  }\n\n  // If no mock route matches, fall back to the network.\n  event.respondWith(fetch(event.request));\n});\n`,\n  'services/aiProviderState.ts': ``,\n  'services/aiService.ts': `import { GoogleGenAI, Type, GenerateContentResponse, FunctionDeclaration, Modality } from \"@google/genai\";\nimport type { GeneratedFile, StructuredPrSummary, StructuredExplanation, ColorTheme, SemanticColorTheme, StructuredReview, SlideSummary, SecurityVulnerability, CodeSmell } from '../types.ts';\nimport { logError } from './telemetryService.ts';\nimport { getDecryptedCredential, isUnlocked, isVaultInitialized } from './vaultService.ts';\n\nlet ai: GoogleGenAI | null = null;\n\nexport async function isApiKeyConfigured(): Promise<boolean> {\n    const envKey = process.env.GEMINI_API_KEY;\n    if (envKey && envKey !== 'undefined' && envKey !== '') return true;\n    \n    // Only check vault if it's initialized and unlocked.\n    if (await isVaultInitialized() && isUnlocked()) {\n        try {\n            const vaultKey = await getDecryptedCredential('gemini_api_key');\n            return !!vaultKey;\n        } catch (e) {\n            console.error(\"Could not check for API key in vault:\", e);\n            return false;\n        }\n    }\n    return false;\n}\n\nexport async function initializeAiClient(): Promise<GoogleGenAI> {\n    if (ai) return ai;\n\n    let apiKey = process.env.GEMINI_API_KEY;\n    \n    if (!apiKey || apiKey === 'undefined' || apiKey === '') {\n        try {\n             apiKey = await getDecryptedCredential('gemini_api_key');\n        } catch(e) {\n             throw new Error(\"Vault is locked. Cannot retrieve API Key.\");\n        }\n    }\n    \n    if (!apiKey) {\n      throw new Error(\"Gemini API key not found. Please provide it when prompted.\");\n    }\n    \n    ai = new GoogleGenAI({ apiKey });\n    return ai;\n}\n\nconst getAi = async () => {\n    if (!ai) {\n        return await initializeAiClient();\n    }\n    return ai;\n}\n\n\nconst sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));\n\n// --- Unified AI Helpers ---\n\nexport async function* streamContent(prompt: string | { parts: any[] }, systemInstruction: string, temperature = 0.5) {\n    try {\n        const aiClient = await getAi();\n        const response = await aiClient.models.generateContentStream({\n            model: 'gemini-2.5-flash',\n            contents: prompt as any,\n            config: { systemInstruction, temperature }\n        });\n\n        for await (const chunk of response) {\n            yield chunk.text;\n        }\n    } catch (error) {\n        console.error(\"Error streaming from AI model:\", error);\n        logError(error as Error, { prompt, systemInstruction });\n        if (error instanceof Error) {\n            yield \\`An error occurred while communicating with the AI model: \\${error.message}\\`;\n        } else {\n            yield \"An unknown error occurred while generating the response.\";\n        }\n    }\n}\n\nexport async function generateContent(prompt: string, systemInstruction: string, temperature = 0.5): Promise<string> {\n    try {\n        const aiClient = await getAi();\n        const response = await aiClient.models.generateContent({\n            model: 'gemini-2.5-flash',\n            contents: prompt,\n            config: { systemInstruction, temperature }\n        });\n        return response.text;\n    } catch (error) {\n         console.error(\"Error generating content from AI model:\", error);\n        logError(error as Error, { prompt, systemInstruction });\n        throw error;\n    }\n}\n\n\nexport async function generateJson<T>(prompt: any, systemInstruction: string, schema: any, temperature = 0.2): Promise<T> {\n    try {\n        const aiClient = await getAi();\n        const response = await aiClient.models.generateContent({\n            model: \"gemini-2.5-flash\",\n            contents: prompt,\n            config: {\n                systemInstruction,\n                responseMimeType: \"application/json\",\n                responseSchema: schema,\n                temperature,\n            }\n        });\n        return JSON.parse(response.text.trim());\n    } catch (error) {\n        console.error(\"Error generating JSON from AI model:\", error);\n        logError(error as Error, { prompt, systemInstruction });\n        throw error;\n    }\n}\n\n\n// --- Unified Feature Functions (Streaming) ---\n\nexport const explainCodeStream = (code: string) => streamContent(\n    \\`Please explain the following code snippet:\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an expert software engineer providing a clear, concise explanation of code.\"\n);\n\nexport const generateRegExStream = (description: string) => streamContent(\n    \\`Generate a single valid JavaScript regex literal (e.g., /abc/gi) for the following description. Respond with ONLY the regex literal and nothing else: \"\\${description}\"\\`,\n    \"You are an expert in regular expressions. You only output valid JavaScript regex literals.\",\n    0.7\n);\n\nexport const generateCommitMessageStream = (diff: string) => streamContent(\n    \\`Generate a conventional commit message for the following context of new files being added:\\\\n\\\\n\\${diff}\\`,\n    \"You are an expert programmer who writes excellent, conventional commit messages. The response should be only the commit message text.\",\n    0.8\n);\n\nexport const generateUnitTestsStream = (code: string) => streamContent(\n    \\`Generate Vitest unit tests for this React component code:\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`tsx\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are a software quality engineer specializing in writing comprehensive and clear unit tests using Vitest and React Testing Library.\",\n    0.6\n);\n\nexport const formatCodeStream = (code: string) => streamContent(\n    \\`Format this code:\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`javascript\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are a code formatter. Your only purpose is to format code. Respond with only the formatted code, enclosed in a single markdown block.\",\n    0.2\n);\n\nexport const generateComponentFromImageStream = (base64Image: string) => streamContent(\n    {\n        parts: [\n            { text: \"Generate a single-file React component using Tailwind CSS that looks like this image. Respond with only the code in a markdown block.\" },\n            { inlineData: { mimeType: 'image/png', data: base64Image } }\n        ]\n    },\n    \"You are an expert frontend developer specializing in React and Tailwind CSS. You create clean, functional components from screenshots.\"\n);\n\nexport const transcribeAudioToCodeStream = (base64Audio: string, mimeType: string) => streamContent(\n    {\n        parts: [\n            { text: \"Transcribe my speech into a code snippet. If I describe a function or component, write it out.\" },\n            { inlineData: { mimeType, data: base64Audio } }\n        ]\n    },\n    \"You are an expert programmer. You listen to a user's voice and transcribe their ideas into code.\"\n);\n\nexport const transferCodeStyleStream = (args: { code: string, styleGuide: string }) => streamContent(\n    \\`Rewrite the following code to match the provided style guide.\\\\n\\\\nStyle Guide:\\\\n\\${args.styleGuide}\\\\n\\\\nCode to rewrite:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${args.code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an AI assistant that rewrites code to match a specific style guide. Respond with only the rewritten code in a markdown block.\",\n    0.3\n);\n\nexport const generateCodingChallengeStream = (_: any) => streamContent(\n    \\`Generate a new, interesting coding challenge suitable for an intermediate developer. Include a clear problem description, one or two examples, and any constraints. Format it in markdown.\\`,\n    \"You are an AI that creates unique and interesting coding challenges for software developers.\",\n    0.9\n);\n\nexport const reviewCodeStream = (code: string, systemInstruction?: string) => streamContent(\n    \\`Please perform a detailed code review on the following code snippet. Identify potential bugs, suggest improvements for readability and performance, and point out any anti-patterns. Structure your feedback with clear headings.\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    systemInstruction || \"You are a senior software engineer performing a code review. You are meticulous, helpful, and provide constructive feedback.\",\n    0.6\n);\n\nexport const generateChangelogFromLogStream = (log: string) => streamContent(\n    \\`Analyze this git log and create a changelog:\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${log}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are a git expert and project manager. Analyze the provided git log and generate a clean, categorized changelog in Markdown format. Group changes under 'Features' and 'Fixes'.\",\n    0.6\n);\n\nexport const enhanceSnippetStream = (code: string) => streamContent(\n    \\`Enhance this code snippet. Add comments, improve variable names, and refactor for clarity or performance if possible.\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are a senior software engineer who excels at improving code. Respond with only the enhanced code in a markdown block.\",\n    0.5\n);\n\nexport const summarizeNotesStream = (notes: string) => streamContent(\n    \\`Summarize these developer notes into a bulleted list of key points and action items:\\\\n\\\\n\\${notes}\\`,\n    \"You are a productivity assistant who is an expert at summarizing technical notes.\",\n    0.7\n);\n\nexport const migrateCodeStream = (code: string, from: string, to: string) => streamContent(\n    \\`Translate this \\${from} code to \\${to}. Respond with only the translated code in a markdown block.\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \\`You are an expert polyglot programmer who specializes in migrating code between languages and frameworks.\\`,\n    0.4\n);\n\nexport const analyzeConcurrencyStream = (code: string) => streamContent(\n    \\`Analyze this JavaScript code for potential concurrency issues, especially related to Web Workers. Identify race conditions, deadlocks, or inefficient data passing.\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`javascript\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an expert in JavaScript concurrency, web workers, and multi-threaded programming concepts.\",\n    0.6\n);\n\nexport const debugErrorStream = (error: Error) => streamContent(\n    \\`I encountered an error in my React application. Here are the details:\\\\n    \\\\n    Message: \\${error.message}\\\\n    \\\\n    Stack Trace:\\\\n    \\${error.stack}\\\\n    \\\\n    Please analyze this error. Provide a brief explanation of the likely cause, followed by a bulleted list of potential solutions or debugging steps. Structure your response in clear, concise markdown.\\`,\n    \"You are an expert software engineer specializing in debugging React applications. You provide clear, actionable advice to help developers solve errors.\"\n);\n\nexport const convertJsonToXbrlStream = (json: string) => streamContent(\n    \\`Convert the following JSON to a simplified, XBRL-like XML format. Use meaningful tags based on the JSON keys. The root element should be <xbrl>. Do not include XML declarations or namespaces.\\\\n\\\\nJSON:\\\\n\\${json}\\`,\n    \"You are an expert in data formats who converts JSON to clean, XBRL-like XML.\"\n);\n\n// --- New Streaming Functions ---\n\nexport const refactorForPerformance = (code: string) => streamContent(\n    \\`Refactor the following code for maximum performance. Focus on algorithmic efficiency, efficient data structures, and avoiding unnecessary computations. Respond with only the refactored code in a markdown block.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an expert software engineer specializing in code performance optimization.\"\n);\n\nexport const refactorForReadability = (code: string) => streamContent(\n    \\`Refactor the following code for maximum readability. Focus on clear variable names, breaking down complex functions, and adding helpful comments. Respond with only the refactored code in a markdown block.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an expert software engineer who writes exceptionally clean and readable code.\"\n);\n\nexport const convertToFunctionalComponent = (classComponent: string) => streamContent(\n    \\`Convert the following React class component to a functional component using hooks (useState, useEffect, etc.). Ensure all lifecycle methods are correctly mapped. Respond with only the refactored code in a markdown block.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${classComponent}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are a React expert specializing in modernizing codebases by converting class components to functional components with hooks.\"\n);\n\nexport const generateJsDoc = (code: string) => streamContent(\n    \\`Generate a complete JSDoc block for the following function or component. Include descriptions for the function, its parameters, and what it returns. Respond with only the JSDoc block and the original function.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an AI assistant that writes comprehensive and accurate JSDoc documentation.\"\n);\n\nexport const translateComments = (code: string, targetLanguage: string) => streamContent(\n    \\`Translate only the code comments in the following snippet to \\${targetLanguage}. Do not alter the code itself. Respond with the full code snippet including the translated comments.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an AI assistant that translates code comments into different languages without changing any of the code.\"\n);\n\nexport const generateDockerfile = (framework: string) => streamContent(\n    \\`Generate a basic, multi-stage Dockerfile for a \\${framework} project. The Dockerfile should be production-ready, including build and serve stages. Respond with only the Dockerfile content in a markdown block.\\`,\n    \"You are a DevOps expert specializing in containerization with Docker.\"\n);\n\nexport const convertCssToTailwind = (css: string) => streamContent(\n    \\`Convert the following CSS code to Tailwind CSS utility classes. Provide the equivalent HTML structure with the Tailwind classes. Respond with only the HTML in a markdown block.\\\\n\\\\nCSS:\\\\n\\\\\\`\\\\\\`\\\\\\`css\\\\n\\${css}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an expert in Tailwind CSS and modern CSS practices.\"\n);\n\nexport const applySpecificRefactor = (code: string, instruction: string) => streamContent(\n    \\`Apply this specific refactoring instruction to the code: \"\\${instruction}\". Respond with only the complete, refactored code in a markdown block.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an AI assistant that precisely applies refactoring instructions to code.\"\n);\n\nexport const generateBugReproductionTestStream = (stackTrace: string, context?: string) => streamContent(\n    \\`Generate a minimal, runnable unit test (using Vitest) that reproduces the bug described by the following stack trace. Respond with only the code in a markdown block.\\\\n\\\\nStack Trace:\\\\n\\${stackTrace}\\\\n\\\\n\\${context ? \\`Additional Context:\\\\n\\${context}\\` : ''}\\`,\n    \"You are a senior software engineer specializing in debugging and automated testing. You create concise, effective unit tests to reproduce bugs.\"\n);\n\nexport const generateIamPolicyStream = (description: string, platform: 'aws' | 'gcp') => streamContent(\n    \\`Generate a valid \\${platform.toUpperCase()} IAM policy in JSON format based on this description: \"\\${description}\". Respond with only the JSON policy in a markdown block.\\`,\n    \"You are a cloud security expert specializing in IAM policies for AWS and GCP.\"\n);\n\n\n// --- Simple Generate Content ---\nexport const generatePipelineCode = (flow: string): Promise<string> => generateContent(\\`Based on the following described workflow, generate a single asynchronous JavaScript function that orchestrates the steps. Use placeholder functions for the actual tool logic. The workflow is: \\${flow}\\`, \"You are an expert software architect who writes clean, asynchronous JavaScript code to orchestrate complex workflows based on a description.\", 0.5);\n\nexport const generateCiCdConfig = (platform: string, description: string): Promise<string> => generateContent(\n    \\`Generate a CI/CD configuration file for \\${platform} based on this description: \"\\${description}\". Respond with only the YAML/config file content inside a markdown block.\\`,\n    \"You are a DevOps expert specializing in CI/CD pipelines.\"\n);\n\nexport const analyzePerformanceTrace = (trace: object): Promise<string> => generateContent(\n    \\`Analyze the following performance trace data and provide optimization suggestions in markdown format. Data: \\${JSON.stringify(trace, null, 2)}\\`,\n    \"You are an expert performance engineer.\"\n);\n\nexport const suggestA11yFix = (issue: object): Promise<string> => generateContent(\n    \\`Explain this accessibility issue and suggest a code fix in markdown. Issue: \\${JSON.stringify(issue, null, 2)}\\`,\n    \"You are an expert in web accessibility (a11y).\"\n);\n\nexport const createApiDocumentation = (apiCode: string): Promise<string> => generateContent(\n    \\`Generate Markdown documentation for the following API endpoint code. Include the endpoint, HTTP method, parameters, and example request/response.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${apiCode}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are a technical writer who creates clear and concise API documentation.\"\n);\n\nexport const jsonToTypescriptInterface = (json: string): Promise<string> => generateContent(\n    \\`Generate a TypeScript interface from this JSON object. Respond with only the TypeScript code in a markdown block.\\\\n\\\\nJSON:\\\\n\\${json}\\`,\n    \"You are an expert in TypeScript and data modeling.\"\n);\n\nexport const suggestAlternativeLibraries = (code: string): Promise<string> => generateContent(\n    \\`Analyze the following code, particularly its import statements and common patterns (like date manipulation). Suggest modern, more efficient library alternatives where applicable (e.g., suggest 'date-fns' or 'dayjs' over 'moment.js'). Explain why.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are a senior software engineer with deep knowledge of the JavaScript ecosystem.\"\n);\n\nexport const explainRegex = (regex: string): Promise<string> => generateContent(\n    \\`Provide a step-by-step explanation of what each part of this regular expression does: \\\\\\`\\${regex}\\\\\\`\\`,\n    \"You are an expert in regular expressions who can explain complex patterns simply.\"\n);\n\nexport const generateMermaidJs = (code: string): Promise<string> => generateContent(\n    \\`Generate a Mermaid.js flowchart string that represents the logic of the following code. Respond with only the Mermaid.js code in a markdown block (e.g., \\\\\\`\\\\\\`\\\\\\`mermaid\\\\n...\\\\n\\\\\\`\\\\\\`\\\\\\`).\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`,\n    \"You are an expert in code analysis and can visualize logic flows using Mermaid.js.\"\n);\n\nexport const generateWeeklyDigest = (commitLogs: string, telemetryData: object): Promise<string> => generateContent(\n    \\`Generate a concise, professional weekly summary email in HTML format based on the following data.\n    \n    Commit Logs:\n    \\\\\\`\\\\\\`\\\\\\`\n    \\${commitLogs}\n    \\\\\\`\\\\\\`\\\\\\`\n    \n    Performance Telemetry:\n    \\\\\\`\\\\\\`\\\\\\`json\n    \\${JSON.stringify(telemetryData, null, 2)}\n    \\\\\\`\\\\\\`\\\\\\`\n    \n    The email should have sections for \"New Features\", \"Bug Fixes\", and \"Performance Notes\". It should be visually clean and easy to read.\\`,\n    \"You are an AI assistant that generates weekly engineering progress reports in HTML format.\"\n);\n\nexport const generateTechnicalSpecFromDiff = (diff: string, summary: StructuredPrSummary): Promise<string> => generateContent(\n    \\`Generate a comprehensive technical specification document in Markdown format based on the following pull request information.\n\nThe spec should include the following sections:\n- **Problem:** A brief description of the issue being addressed.\n- **Solution:** A detailed explanation of the changes made.\n- **Technical Details:** An overview of the implementation, including any new functions, components, or patterns.\n- **Impact:** How this change affects other parts of the application.\n\n**PR Title:** \\${summary.title}\n**PR Summary:** \\${summary.summary}\n\n**Code Diff:**\n\\\\\\`\\\\\\`\\\\\\`diff\n\\${diff}\n\\\\\\`\\\\\\`\\\\\\`\n\\`,\n    \"You are an expert programmer who writes excellent, clear, and comprehensive technical specification documents from pull request data.\"\n);\n\n// --- STRUCTURED JSON ---\n\nexport const explainCodeStructured = async (code: string): Promise<StructuredExplanation> => {\n    const systemInstruction = \"You are an expert software engineer providing a structured analysis of a code snippet. In the summary, identify any imported dependencies and explain their purpose within the code.\";\n    const prompt = \\`Analyze this code: \\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const schema = { type: Type.OBJECT, properties: { summary: { type: Type.STRING }, lineByLine: { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { lines: { type: Type.STRING }, explanation: { type: Type.STRING } }, required: [\"lines\", \"explanation\"] } }, complexity: { type: Type.OBJECT, properties: { time: { type: Type.STRING }, space: { type: Type.STRING } }, required: [\"time\", \"space\"] }, suggestions: { type: Type.ARRAY, items: { type: Type.STRING } } }, required: [\"summary\", \"lineByLine\", \"complexity\", \"suggestions\"] };\n    return generateJson(prompt, systemInstruction, schema);\n}\n\nexport const generateThemeFromDescription = async (description: string): Promise<ColorTheme> => {\n    const systemInstruction = \"You are a UI/UX design expert specializing in color theory. Generate a color theme based on the user's description. Provide hex codes for each color.\";\n    const prompt = \\`Generate a color theme for: \"\\${description}\"\\`;\n    const schema = { type: Type.OBJECT, properties: { primary: { type: Type.STRING }, background: { type: Type.STRING }, surface: { type: Type.STRING }, textPrimary: { type: Type.STRING }, textSecondary: { type: Type.STRING }, textOnPrimary: { type: Type.STRING }, border: { type: Type.STRING } }, required: [\"primary\", \"background\", \"surface\", \"textPrimary\", \"textSecondary\", \"textOnPrimary\", \"border\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateSemanticTheme = (prompt: { parts: any[] }): Promise<SemanticColorTheme> => {\n    const systemInstruction = \\`You are a world-class UI/UX designer with an expert understanding of color theory, accessibility, and branding.\n    Your task is to generate a comprehensive, semantically named color theme from a user's prompt (which could be text or an image).\n    - Determine if the theme should be 'light' or 'dark' mode.\n    - Palette colors should be harmonious and versatile.\n    - Theme colors must be derived from the palette and assigned to specific UI roles (background, text, border, etc.).\n    - 'textOnPrimary' MUST have a high contrast ratio against 'primary'.\n    - You MUST calculate the WCAG 2.1 contrast ratio for key text/background pairs and provide a score (AAA, AA, or Fail).\n    - Provide creative, evocative names for each color (e.g., \"Midnight Blue\", \"Dune Sand\").\\`;\n\n    const colorObjectSchema = {\n        type: Type.OBJECT,\n        properties: {\n            value: { type: Type.STRING, description: \"The hex code of the color, e.g., #RRGGBB\" },\n            name: { type: Type.STRING, description: \"A creative, evocative name for the color.\" }\n        },\n        required: [\"value\", \"name\"]\n    };\n\n    const accessibilityCheckSchema = {\n        type: Type.OBJECT,\n        properties: {\n            ratio: { type: Type.NUMBER, description: \"The calculated contrast ratio.\" },\n            score: { type: Type.STRING, enum: [\"AAA\", \"AA\", \"Fail\"], description: \"The WCAG 2.1 accessibility score.\" }\n        },\n        required: [\"ratio\", \"score\"]\n    };\n\n    const schema = {\n        type: Type.OBJECT,\n        properties: {\n            mode: {\n                type: Type.STRING, enum: [\"light\", \"dark\"],\n                description: \"The recommended UI mode for this theme, 'light' or 'dark'.\"\n            },\n            palette: {\n                type: Type.OBJECT,\n                description: \"A harmonious 4-color palette extracted from the prompt.\",\n                properties: {\n                    primary: colorObjectSchema,\n                    secondary: colorObjectSchema,\n                    accent: colorObjectSchema,\n                    neutral: colorObjectSchema,\n                },\n                required: [\"primary\", \"secondary\", \"accent\", \"neutral\"]\n            },\n            theme: {\n                type: Type.OBJECT,\n                description: \"Specific color assignments for UI elements, derived from the palette.\",\n                properties: {\n                    background: colorObjectSchema,\n                    surface: colorObjectSchema,\n                    textPrimary: colorObjectSchema,\n                    textSecondary: colorObjectSchema,\n                    textOnPrimary: colorObjectSchema,\n                    border: colorObjectSchema,\n                },\n                required: [\"background\", \"surface\", \"textPrimary\", \"textSecondary\", \"textOnPrimary\", \"border\"]\n            },\n            accessibility: {\n                type: Type.OBJECT,\n                description: \"WCAG 2.1 contrast ratio checks for common text/background pairings.\",\n                properties: {\n                    primaryOnSurface: accessibilityCheckSchema,\n                    textPrimaryOnSurface: accessibilityCheckSchema,\n                    textSecondaryOnSurface: accessibilityCheckSchema,\n                    textOnPrimaryOnPrimary: accessibilityCheckSchema,\n                },\n                required: [\"primaryOnSurface\", \"textPrimaryOnSurface\", \"textSecondaryOnSurface\", \"textOnPrimaryOnPrimary\"]\n            }\n        },\n        required: [\"mode\", \"palette\", \"theme\", \"accessibility\"]\n    };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\n\nexport const generatePrSummaryStructured = (diff: string): Promise<StructuredPrSummary> => {\n    const systemInstruction = \"You are an expert programmer who writes excellent PR summaries.\";\n    const prompt = \\`Generate a PR summary for the following diff:\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`diff\\\\n\\${diff}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const schema = { type: Type.OBJECT, properties: { title: { type: Type.STRING }, summary: { type: Type.STRING }, changes: { type: Type.ARRAY, items: { type: Type.STRING } } }, required: [\"title\", \"summary\", \"changes\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateFeature = (prompt: string, framework: string, styling: string): Promise<GeneratedFile[]> => {\n    const systemInstruction = \\`You are an AI that generates complete, production-ready components. Create all necessary files for the requested framework and styling option.\n    IMPORTANT: When the user's prompt is about maps, location, addresses, or stores, you MUST use the Google Maps JavaScript API. Generate a component that accepts an 'apiKey' prop and uses it to load the Maps script.\\`;\n    const userPrompt = \\`Generate the files for a \\${framework} component using \\${styling} for the following feature request: \"\\${prompt}\". Make sure to include a .tsx component file.\\`;\n    const schema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(userPrompt, systemInstruction, schema);\n};\n\nexport const generateFullStackFeature = (prompt: string, framework: string, styling: string): Promise<GeneratedFile[]> => {\n    const systemInstruction = \\`You are an AI that generates complete, production-ready full-stack features.\n    You must generate three files:\n    1. A frontend \\${framework} component using \\${styling}. File path should be 'Component.tsx'.\n    2. A backend Google Cloud Function in Node.js. File path should be a simple HTTP-triggered function.\n    3. Firestore Security Rules that allow public reads but only authenticated writes. File path should be 'firestore.rules'.\n    Ensure the frontend component knows how to call the cloud function.\n    IMPORTANT: When the user's prompt is about maps, location, addresses, or stores, you MUST prioritize using the Google Maps JavaScript API in the frontend component. Generate a component that accepts an 'apiKey' prop and uses it to load the Maps script.\\`;\n    const userPrompt = \\`Generate a full-stack feature for: \"\\${prompt}\"\\`;\n    const schema = {\n        type: Type.ARRAY,\n        items: {\n            type: Type.OBJECT,\n            properties: {\n                filePath: { type: Type.STRING, enum: ['Component.tsx', 'functions/index.js', 'firestore.rules'] },\n                content: { type: Type.STRING },\n                description: { type: Type.STRING }\n            },\n            required: [\"filePath\", \"content\", \"description\"]\n        }\n    };\n    return generateJson(userPrompt, systemInstruction, schema);\n};\n\nexport interface CronParts { minute: string; hour: string; dayOfMonth: string; month: string; dayOfWeek: string; }\nexport const generateCronFromDescription = (description: string): Promise<CronParts> => {\n    const systemInstruction = \"You are an expert in cron expressions. Convert the user's description into a valid cron expression parts.\";\n    const prompt = \\`Convert this schedule to a cron expression: \"\\${description}\"\\`;\n    const schema = { type: Type.OBJECT, properties: { minute: { type: Type.STRING }, hour: { type: Type.STRING }, dayOfMonth: { type: Type.STRING }, month: { type: Type.STRING }, dayOfWeek: { type: Type.STRING } }, required: [\"minute\", \"hour\", \"dayOfMonth\", \"month\", \"dayOfWeek\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateColorPalette = (baseColor: string): Promise<{ colors: string[] }> => {\n    const systemInstruction = \"You are a color theory expert. Generate a 6-color palette based on the given base color.\";\n    const prompt = \\`Generate a harmonious 6-color palette based on the color \\${baseColor}.\\`;\n    const schema = { type: Type.OBJECT, properties: { colors: { type: Type.ARRAY, items: { type: Type.STRING } } }, required: [\"colors\"] };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateMockData = (description: string, count: number): Promise<object[]> => {\n    const systemInstruction = \"You are an expert data scientist who creates realistic mock data based on a schema description. You must respond with only a valid JSON array of objects.\";\n    const prompt = \\`Generate an array of \\${count} mock data objects based on the following schema description. Respond with only the JSON array.\\\\n\\\\nSchema: \"\\${description}\"\\`;\n    const schema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: {} }}; // Freeform objects\n    return generateJson(prompt, systemInstruction, schema, 0.8);\n};\n\nexport const analyzeCodeForVulnerabilities = (code: string): Promise<SecurityVulnerability[]> => {\n    const systemInstruction = \"You are an expert security engineer. Analyze the code for vulnerabilities. For each vulnerability, provide a structured response including a potential cURL command or code snippet to demonstrate the exploit.\";\n    const prompt = \\`Analyze this code for security issues like XSS, injection, hardcoded secrets, etc. Provide detailed explanations, mitigation advice, and an exploit suggestion.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const schema = {\n        type: Type.ARRAY,\n        items: {\n            type: Type.OBJECT,\n            properties: {\n                vulnerability: { type: Type.STRING },\n                severity: { type: Type.STRING, enum: ['Critical', 'High', 'Medium', 'Low', 'Informational'] },\n                description: { type: Type.STRING },\n                mitigation: { type: Type.STRING },\n                exploitSuggestion: { type: Type.STRING, description: \"A cURL command, code snippet, or description of how to exploit the vulnerability.\" }\n            },\n            required: ['vulnerability', 'severity', 'description', 'mitigation', 'exploitSuggestion']\n        }\n    };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const sqlToApiEndpoints = (schema: string, framework: 'express' | 'fastify'): Promise<GeneratedFile[]> => {\n    const systemInstruction = \"You are an expert backend developer who generates boilerplate CRUD API endpoints from a SQL schema.\";\n    const prompt = \\`Generate boilerplate CRUD API endpoint files for a \\${framework} server based on the following SQL table schema. Create separate files for routes, controllers, and models.\\\\n\\\\nSQL:\\\\n\\\\\\`\\\\\\`\\\\\\`sql\\\\n\\${schema}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const filesSchema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(prompt, systemInstruction, filesSchema);\n};\n\nexport const detectCodeSmells = (code: string): Promise<CodeSmell[]> => {\n    const systemInstruction = \"You are an expert software engineer who identifies code smells like long methods, large classes, feature envy, etc.\";\n    const prompt = \\`Analyze the following code for code smells and provide explanations.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const schema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { smell: { type: Type.STRING }, line: { type: Type.INTEGER }, explanation: { type: Type.STRING } }, required: [\"smell\", \"line\", \"explanation\"] } };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateTagsForCode = (code: string): Promise<string[]> => {\n    const systemInstruction = \"You are an AI assistant that analyzes code and suggests relevant tags.\";\n    const prompt = \\`Generate 3-5 relevant, single-word, lowercase tags for this code snippet to help categorize it. Respond with only a JSON array of strings.\\\\n\\\\nCode:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const schema = { type: Type.ARRAY, items: { type: Type.STRING } };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const reviewCodeStructured = (code: string): Promise<StructuredReview> => {\n    const systemInstruction = \"You are a senior software engineer performing a meticulous code review. Provide a summary and a list of specific, actionable suggestions for improvement.\";\n    const prompt = \\`Review this code and provide structured feedback:\\\\n\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${code}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const schema = {\n        type: Type.OBJECT,\n        properties: {\n            summary: { type: Type.STRING, description: \"A high-level summary of the code quality, identifying the main issues.\" },\n            suggestions: {\n                type: Type.ARRAY,\n                items: {\n                    type: Type.OBJECT,\n                    properties: {\n                        suggestion: { type: Type.STRING, description: \"A concise description of the suggested change.\" },\n                        codeBlock: { type: Type.STRING, description: \"The exact block of code that should be replaced.\" },\n                        explanation: { type: Type.STRING, description: \"Why the change is recommended (e.g., performance, readability).\" }\n                    },\n                    required: [\"suggestion\", \"codeBlock\", \"explanation\"]\n                }\n            }\n        },\n        required: [\"summary\", \"suggestions\"]\n    };\n    return generateJson(prompt, systemInstruction, schema);\n};\n\nexport const generateClientFromApiSchema = (schema: string, framework: string): Promise<GeneratedFile[]> => {\n    const systemInstruction = \"You are an expert full-stack developer. Generate client-side code from an API schema.\";\n    const prompt = \\`Generate all necessary files for a \\${framework} client based on the following OpenAPI/GraphQL schema. This should include data-fetching hooks, type definitions, and basic display components.\\\\n\\\\nSchema:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${schema}\\\\n\\\\\\`\\\\\\`\\\\\\`\\`;\n    const filesSchema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(prompt, systemInstruction, filesSchema);\n};\n\nexport const generateTerraformConfig = (cloud: 'aws' | 'gcp', description: string, context?: string): Promise<string> => {\n    const systemInstruction = \\`You are a DevOps expert specializing in Terraform. Generate a complete .tf file based on the user's description.\\`;\n    const prompt = \\`Generate a Terraform configuration for \\${cloud}.\n    Description: \"\\${description}\"\n    \\${context ? \\`\\\\n\\\\nCloud Context (e.g., existing resources):\\\\n\\${context}\\` : ''}\n    Respond with only the HCL code in a markdown block.\\`;\n    return generateContent(prompt, systemInstruction);\n};\n\n\n// --- FUNCTION CALLING ---\nexport interface CommandResponse { text: string; functionCalls?: { name: string; args: any; }[]; }\nexport const getInferenceFunction = async (prompt: string, functionDeclarations: FunctionDeclaration[], knowledgeBase: string): Promise<CommandResponse> => {\n    try {\n        const aiClient = await getAi();\n        const response: GenerateContentResponse = await aiClient.models.generateContent({ model: \"gemini-2.5-flash\", contents: prompt, config: { systemInstruction: \\`You are a helpful assistant for a developer tool. You must decide which function to call to satisfy the user's request, based on your knowledge base. If no specific tool seems appropriate, respond with text.\\\\n\\\\nKnowledge Base:\\\\n\\${knowledgeBase}\\`, tools: [{ functionDeclarations }] } });\n        const functionCalls: { name: string, args: any }[] = [];\n        const parts = response.candidates?.[0]?.content?.parts ?? [];\n        for (const part of parts) { if (part.functionCall) { functionCalls.push({ name: part.functionCall.name, args: part.functionCall.args }); } }\n        return { text: response.text, functionCalls: functionCalls.length > 0 ? functionCalls : undefined };\n    } catch (error) {\n        logError(error as Error, { prompt });\n        throw error;\n    }\n};\n\n\n// --- IMAGE & VIDEO GENERATION ---\nexport const generateImage = async (prompt: string): Promise<string> => {\n    const aiClient = await getAi();\n    const response = await aiClient.models.generateImages({\n        model: 'imagen-4.0-generate-001',\n        prompt: prompt,\n        config: { numberOfImages: 1, outputMimeType: 'image/png' },\n    });\n    const base64ImageBytes: string = response.generatedImages[0].image.imageBytes;\n    return \\`data:image/png;base64,\\${base64ImageBytes}\\`;\n};\n\nexport const generateImageFromImageAndText = async (prompt: string, base64Image: string, mimeType: string): Promise<string> => {\n    const aiClient = await getAi();\n    const response = await aiClient.models.generateContent({\n        model: 'gemini-2.5-flash-image-preview',\n        contents: {\n            parts: [\n                { inlineData: { data: base64Image, mimeType: mimeType } },\n                { text: prompt },\n            ],\n        },\n        config: {\n            responseModalities: [Modality.IMAGE, Modality.TEXT],\n        },\n    });\n\n    for (const part of response.candidates[0].content.parts) {\n        if (part.inlineData) {\n            const base64ImageBytes: string = part.inlineData.data;\n            return \\`data:\\${part.inlineData.mimeType};base64,\\${base64ImageBytes}\\`;\n        }\n    }\n\n    throw new Error(\"AI did not return an image. It may have refused the request.\");\n};\n\n\nexport const generateMultiComponentFlowFromVideo = async (videoBase64: string, mimeType: string, onUpdate: (message: string) => void): Promise<GeneratedFile[]> => {\n    const aiClient = await getAi();\n    const systemInstruction = \"You are an expert frontend developer. Analyze the user flow in this screen recording and generate all the necessary React components and routing logic to replicate it. Create separate files for each component.\";\n    \n    onUpdate(\"Starting video analysis...\");\n    let operation = await aiClient.models.generateVideos({\n      model: 'veo-2.0-generate-001',\n      prompt: \"A short, silent video showing a user interacting with a web UI. Transcribe the actions and UI elements into a step-by-step description of the user flow.\",\n      config: { numberOfVideos: 1 }\n    });\n\n    onUpdate(\"Video processing initiated. This may take several minutes...\");\n    while (!operation.done) {\n      await sleep(10000);\n      onUpdate(\"Checking video status...\");\n      operation = await aiClient.operations.getVideosOperation({operation: operation});\n    }\n\n    onUpdate(\"Video processing complete. Generating code from flow...\");\n    // This is a conceptual placeholder. A real implementation would require a multimodal model that can output structured data from video.\n    const flowDescription = operation.response?.generatedVideos?.[0]?.video?.uri || \"A user clicks a list item, sees a detail page, and clicks a button.\";\n    \n    const filesSchema = { type: Type.ARRAY, items: { type: Type.OBJECT, properties: { filePath: { type: Type.STRING }, content: { type: Type.STRING }, description: { type: Type.STRING } }, required: [\"filePath\", \"content\", \"description\"] } };\n    return generateJson(flowDescription, systemInstruction, filesSchema);\n};`,\n  'services/auditing/.placeholder': ``,\n  'services/auditing/accessibilityService.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\nimport * as axe from 'axe-core';\n\n// Configure axe-core to be less noisy in the console\naxe.configure({\n    reporter: 'v2',\n    rules: [\n        { id: 'region', enabled: false } // A common false positive in isolated components\n    ]\n});\n\nexport type AxeResult = axe.AxeResults;\n\n/**\n * Runs an axe accessibility audit on a given HTML element.\n * @param context The element or selector string to run the audit on.\n * @returns A promise that resolves with the axe audit results.\n */\nexport const runAxeAudit = async (context: axe.ElementContext): Promise<AxeResult> => {\n    try {\n        const results = await axe.run(context, {\n             resultTypes: ['violations', 'incomplete']\n        });\n        return results;\n    } catch (error) {\n        console.error('Error running axe audit:', error);\n        throw new Error('Accessibility audit failed to execute.');\n    }\n};`,\n  'services/authService.ts': `import { Octokit } from 'octokit';\nimport type { GitHubUser as User } from '../types.ts';\nimport { logEvent } from './telemetryService.ts';\n\n/**\n * Creates a new Octokit instance with the provided token.\n * This function is now stateless and should be called with a plaintext token\n * that has been securely decrypted from the vault just before use.\n * @param token The plaintext GitHub Personal Access Token.\n * @returns A new Octokit instance.\n */\nexport const initializeOctokit = (token: string): Octokit => {\n    if (!token) {\n        throw new Error(\"Cannot initialize Octokit without a token.\");\n    }\n    logEvent('octokit_initialized');\n    return new Octokit({ auth: token, request: { headers: { 'X-GitHub-Api-Version': '2022-11-28' } } });\n};\n\n/**\n * Validates a plaintext token by fetching the user profile.\n * @param token The plaintext GitHub token to validate.\n * @returns A promise that resolves to the user's profile information.\n */\nexport const validateToken = async (token: string): Promise<User> => {\n    const tempOctokit = new Octokit({ auth: token });\n    const { data: user } = await tempOctokit.request('GET /user');\n    return user as unknown as User;\n};`,\n  'services/componentLoader.ts': `import React, { lazy } from 'react';\n\n/**\n * A wrapper around React.lazy to retry loading a component if it fails.\n * This is useful for handling \"chunk load failed\" errors that can occur\n * when a user has an old version of the site and a new version is deployed.\n *\n * @param componentImport A function that returns a dynamic import, e.g., () => import('./MyComponent')\n * @param exportName The named export of the component to be loaded.\n * @returns A lazy-loaded React component.\n */\nexport const lazyWithRetry = <T extends React.ComponentType<any>>(\n    componentImport: () => Promise<{ [key: string]: T }>,\n    exportName: string\n) => {\n    return lazy(async () => {\n        const MAX_RETRIES = 3;\n        const RETRY_DELAY_MS = 1000;\n\n        for (let i = 0; i < MAX_RETRIES; i++) {\n            try {\n                const module = await componentImport();\n                if (module[exportName]) {\n                    return { default: module[exportName] };\n                }\n                // This would be a developer error (wrong export name), not a chunk load error.\n                throw new Error(\\`Named export '\\${exportName}' not found in module.\\`);\n            } catch (error) {\n                console.error(error); // Log error for debugging\n                if (i < MAX_RETRIES - 1) {\n                    await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));\n                } else {\n                    // After all retries, force a page reload.\n                    // This is the most effective way to solve stale chunk issues after a new deployment.\n                    console.error(\"Failed to load component after multiple retries. Reloading page.\");\n                    window.location.reload();\n                    // Throw to allow an ErrorBoundary to catch this, although reload will likely intervene.\n                    throw error;\n                }\n            }\n        }\n        // This part of the code should not be reachable\n        throw new Error('Component failed to load and retries were exhausted.');\n    });\n};`,\n  'services/cryptoService.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nconst KEY_ALGORITHM = 'AES-GCM';\nconst KEY_LENGTH = 256;\nconst PBKDF2_ALGORITHM = 'PBKDF2';\nconst PBKDF2_HASH = 'SHA-256';\nconst PBKDF2_ITERATIONS = 100000;\nconst SALT_LENGTH_BYTES = 16;\nconst IV_LENGTH_BYTES = 12;\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\n/**\n * Derives a cryptographic key from a master password and a salt using PBKDF2.\n * @param password The master password string.\n * @param salt The salt as an ArrayBuffer.\n * @returns A promise that resolves to a CryptoKey.\n */\nexport const deriveKey = async (password: string, salt: ArrayBuffer): Promise<CryptoKey> => {\n    const masterKey = await crypto.subtle.importKey(\n        'raw',\n        textEncoder.encode(password),\n        { name: PBKDF2_ALGORITHM },\n        false,\n        ['deriveKey']\n    );\n\n    return await crypto.subtle.deriveKey(\n        {\n            name: PBKDF2_ALGORITHM,\n            salt,\n            iterations: PBKDF2_ITERATIONS,\n            hash: PBKDF2_HASH,\n        },\n        masterKey,\n        { name: KEY_ALGORITHM, length: KEY_LENGTH },\n        true,\n        ['encrypt', 'decrypt']\n    );\n};\n\n/**\n * Generates a cryptographically secure random salt.\n * @returns A new salt as an ArrayBuffer.\n */\nexport const generateSalt = (): ArrayBuffer => {\n    return crypto.getRandomValues(new Uint8Array(SALT_LENGTH_BYTES)).buffer;\n};\n\n/**\n * Encrypts a plaintext string using a derived key.\n * @param plaintext The string to encrypt.\n * @param key The CryptoKey to use for encryption.\n * @returns A promise that resolves to an object containing the encrypted data (ciphertext), and the initialization vector (iv).\n */\nexport const encrypt = async (plaintext: string, key: CryptoKey): Promise<{ ciphertext: ArrayBuffer, iv: Uint8Array }> => {\n    const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH_BYTES));\n    const encodedPlaintext = textEncoder.encode(plaintext);\n\n    const ciphertext = await crypto.subtle.encrypt(\n        {\n            name: KEY_ALGORITHM,\n            iv,\n        },\n        key,\n        encodedPlaintext\n    );\n\n    return { ciphertext, iv };\n};\n\n/**\n * Decrypts a ciphertext ArrayBuffer using a derived key and IV.\n * @param ciphertext The ArrayBuffer of the encrypted data.\n * @param key The CryptoKey to use for decryption.\n * @param iv The initialization vector used during encryption.\n * @returns A promise that resolves to the decrypted plaintext string.\n */\nexport const decrypt = async (ciphertext: ArrayBuffer, key: CryptoKey, iv: Uint8Array): Promise<string> => {\n    const decrypted = await crypto.subtle.decrypt(\n        {\n            name: KEY_ALGORITHM,\n            iv,\n        },\n        key,\n        ciphertext\n    );\n\n    return textDecoder.decode(decrypted);\n};\n`,\n  'services/dbService.ts': `import { openDB, DBSchema } from 'idb';\nimport type { GeneratedFile, EncryptedData } from '../types.ts';\n\nconst DB_NAME = 'devcore-db';\nconst DB_VERSION = 2;\nconst FILES_STORE_NAME = 'generated-files';\nconst VAULT_STORE_NAME = 'vault-data';\nconst ENCRYPTED_TOKENS_STORE_NAME = 'encrypted-tokens';\n\n\ninterface DevCoreDB extends DBSchema {\n  [FILES_STORE_NAME]: {\n    key: string;\n    value: GeneratedFile;\n    indexes: { 'by-filePath': string };\n  };\n  [VAULT_STORE_NAME]: {\n    key: string;\n    value: any;\n  };\n  [ENCRYPTED_TOKENS_STORE_NAME]: {\n    key: string;\n    value: EncryptedData;\n  };\n}\n\nconst dbPromise = openDB<DevCoreDB>(DB_NAME, DB_VERSION, {\n  upgrade(db, oldVersion) {\n    switch (oldVersion) {\n        case 0: {\n            const store = db.createObjectStore(FILES_STORE_NAME, {\n                keyPath: 'filePath',\n            });\n            store.createIndex('by-filePath', 'filePath');\n        }\n        // fall-through for new installations\n        case 1: {\n            if (!db.objectStoreNames.contains(VAULT_STORE_NAME)) {\n                db.createObjectStore(VAULT_STORE_NAME);\n            }\n            if (!db.objectStoreNames.contains(ENCRYPTED_TOKENS_STORE_NAME)) {\n                db.createObjectStore(ENCRYPTED_TOKENS_STORE_NAME, { keyPath: 'id' });\n            }\n        }\n    }\n  },\n});\n\n// --- Generated Files Store ---\nexport const saveFile = async (file: GeneratedFile): Promise<void> => {\n  const db = await dbPromise;\n  await db.put(FILES_STORE_NAME, file);\n};\n\nexport const getAllFiles = async (): Promise<GeneratedFile[]> => {\n  const db = await dbPromise;\n  return db.getAll(FILES_STORE_NAME);\n};\n\nexport const getFileByPath = async (filePath: string): Promise<GeneratedFile | undefined> => {\n  const db = await dbPromise;\n  return db.get(FILES_STORE_NAME, filePath);\n};\n\nexport const clearAllFiles = async (): Promise<void> => {\n  const db = await dbPromise;\n  await db.clear(FILES_STORE_NAME);\n};\n\n// --- Vault Store ---\nexport const saveVaultData = async (key: string, value: any): Promise<void> => {\n  const db = await dbPromise;\n  await db.put(VAULT_STORE_NAME, value, key);\n};\n\nexport const getVaultData = async (key: string): Promise<any | undefined> => {\n  const db = await dbPromise;\n  return db.get(VAULT_STORE_NAME, key);\n};\n\n// --- Encrypted Tokens Store ---\nexport const saveEncryptedToken = async (data: EncryptedData): Promise<void> => {\n  const db = await dbPromise;\n  await db.put(ENCRYPTED_TOKENS_STORE_NAME, data);\n};\n\nexport const getEncryptedToken = async (id: string): Promise<EncryptedData | undefined> => {\n  const db = await dbPromise;\n  return db.get(ENCRYPTED_TOKENS_STORE_NAME, id);\n};\n\nexport const getAllEncryptedTokenIds = async (): Promise<string[]> => {\n    const db = await dbPromise;\n    return db.getAllKeys(ENCRYPTED_TOKENS_STORE_NAME);\n};\n\n\n// --- Global Actions ---\nexport const clearAllData = async (): Promise<void> => {\n    const db = await dbPromise;\n    await db.clear(FILES_STORE_NAME);\n    await db.clear(VAULT_STORE_NAME);\n    await db.clear(ENCRYPTED_TOKENS_STORE_NAME);\n}`,\n  'services/fileUtils.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\n/**\n * A robust way to convert an ArrayBuffer to a Base64 string.\n * @param buffer The ArrayBuffer to convert.\n * @returns The Base64 encoded string.\n */\nconst arrayBufferToBase64 = (buffer: ArrayBuffer): string => {\n    let binary = '';\n    const bytes = new Uint8Array(buffer);\n    const len = bytes.byteLength;\n    for (let i = 0; i < len; i++) {\n        binary += String.fromCharCode(bytes[i]);\n    }\n    return window.btoa(binary);\n};\n\n/**\n * Converts a Blob object to a Base64 encoded string.\n * This implementation uses readAsArrayBuffer for greater robustness across environments.\n * @param blob The Blob object to convert.\n * @returns A promise that resolves with the Base64 string.\n */\nexport const blobToBase64 = (blob: Blob): Promise<string> => {\n    return new Promise((resolve, reject) => {\n        const reader = new FileReader();\n        reader.onloadend = () => {\n            resolve(arrayBufferToBase64(reader.result as ArrayBuffer));\n        };\n        reader.onerror = (error) => reject(error);\n        reader.readAsArrayBuffer(blob);\n    });\n};\n\n/**\n * Converts a File object to a Base64 encoded string.\n * This function is an alias for blobToBase64.\n * @param file The File object to convert.\n * @returns A promise that resolves with the Base64 string.\n */\nexport const fileToBase64 = (file: File): Promise<string> => {\n    return blobToBase64(file);\n};\n\n/**\n * Converts a Blob object to a Data URL string.\n * This implementation uses readAsArrayBuffer for greater robustness across environments.\n * This function keeps the Data URL prefix (e.g., \"data:image/png;base64,\").\n * @param blob The Blob object to convert.\n * @returns A promise that resolves with the Data URL string.\n */\nexport const blobToDataURL = (blob: Blob): Promise<string> => {\n    return new Promise((resolve, reject) => {\n        const reader = new FileReader();\n        reader.onloadend = () => {\n            const base64 = arrayBufferToBase64(reader.result as ArrayBuffer);\n            resolve(\\`data:\\${blob.type};base64,\\${base64}\\`);\n        };\n        reader.onerror = (error) => reject(error);\n        reader.readAsArrayBuffer(blob);\n    });\n};\n\n/**\n * Triggers a browser download for the given content.\n * @param content The string content to download.\n * @param filename The name of the file.\n * @param mimeType The MIME type of the file.\n */\nexport const downloadFile = (content: string, filename: string, mimeType: string = 'text/plain') => {\n    const blob = new Blob([content], { type: mimeType });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement('a');\n    a.href = url;\n    a.download = filename;\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n};\n\n/**\n * Generates and triggers a download for a .env formatted file.\n * @param env A record of key-value pairs for the environment variables.\n */\nexport const downloadEnvFile = (env: Record<string, string>): void => {\n    const content = Object.entries(env)\n        .map(([key, value]) => \\`\\${key}=\\${JSON.stringify(value)}\\`)\n        .join('\\\\n');\n    downloadFile(content, '.env', 'text/plain');\n};\n\n/**\n * Generates and triggers a download for a JSON file.\n * @param data The JavaScript object to stringify and download.\n * @param filename The name of the file.\n */\nexport const downloadJson = (data: object, filename: string): void => {\n    const content = JSON.stringify(data, null, 2);\n    downloadFile(content, filename, 'application/json');\n};`,\n  'services/gcpService.ts': `import { ensureGapiClient } from './googleApiService.ts';\nimport { logError, measurePerformance } from './telemetryService.ts';\n\ndeclare var gapi: any;\n\n/**\n * Tests a set of permissions against a specified GCP resource.\n * @param resource The full resource name of the GCP resource (e.g., '//cloudresourcemanager.googleapis.com/projects/my-project').\n * @param permissions An array of permission strings to test (e.g., ['storage.objects.create', 'storage.objects.get']).\n * @returns A promise that resolves with the API response, containing the set of permissions the caller is allowed.\n */\nexport const testIamPermissions = async (resource: string, permissions: string[]): Promise<{ permissions: string[] }> => {\n    return measurePerformance('gcp.testIamPermissions', async () => {\n        try {\n            const isReady = await ensureGapiClient();\n            if (!isReady) throw new Error(\"Google API client not ready.\");\n\n            // The resource name for IAM API is slightly different\n            const iamResourcePath = resource.startsWith('//') ? resource.substring(2) : resource;\n\n            const response = await gapi.client.iam.permissions.testIamPermissions({\n                resource: iamResourcePath,\n                resource_body: { permissions }\n            });\n\n            return response.result;\n        } catch (error) {\n            logError(error as Error, {\n                service: 'gcpService',\n                function: 'testIamPermissions',\n                resource\n            });\n            // Re-throw a more user-friendly error\n            const gapiError = error as any;\n            if (gapiError.result?.error?.message) {\n                 throw new Error(\\`GCP API Error: \\${gapiError.result.error.message}\\`);\n            }\n            throw error;\n        }\n    });\n};`,\n  'services/geminiService.ts': ``,\n  'services/githubService.ts': `import type { Octokit } from 'octokit';\nimport type { Repo, FileNode } from '../types.ts';\nimport { logEvent, logError, measurePerformance } from './index.ts';\n\n// --- Repository-Level Functions ---\n\n/**\n * Fetches the repositories for the authenticated user.\n * @param octokit An authenticated Octokit instance.\n * @returns A promise that resolves to an array of Repo objects.\n */\nexport const getRepos = async (octokit: Octokit): Promise<Repo[]> => {\n    return measurePerformance('getRepos', async () => {\n        logEvent('getRepos_start');\n        try {\n            const { data } = await octokit.request('GET /user/repos', {\n                type: 'owner',\n                sort: 'updated',\n                per_page: 100,\n            });\n            logEvent('getRepos_success', { count: data.length });\n            return data as Repo[];\n        } catch (error) {\n            logError(error as Error, { context: 'getRepos' });\n            throw error;\n        }\n    });\n};\n\n/**\n * Deletes a repository. This is a destructive action.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @returns A promise that resolves when the deletion is complete.\n */\nexport const deleteRepo = async (octokit: Octokit, owner: string, repo: string): Promise<void> => {\n     return measurePerformance('deleteRepo', async () => {\n        logEvent('deleteRepo_start', { owner, repo });\n        try {\n            await octokit.request('DELETE /repos/{owner}/{repo}', {\n                owner,\n                repo,\n            });\n            logEvent('deleteRepo_success', { owner, repo });\n        } catch (error) {\n            logError(error as Error, { context: 'deleteRepo', owner, repo });\n            throw error;\n        }\n    });\n};\n\n/**\n * Fetches the last 30 commits for a repository.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @returns A promise that resolves to an array of commit objects.\n */\nexport const getCommitHistory = async (octokit: Octokit, owner: string, repo: string): Promise<any[]> => {\n    return measurePerformance('getCommitHistory', async () => {\n        logEvent('getCommitHistory_start', { owner, repo });\n        try {\n            const { data } = await octokit.request('GET /repos/{owner}/{repo}/commits', {\n                owner,\n                repo,\n                per_page: 30,\n            });\n            logEvent('getCommitHistory_success', { count: data.length });\n            return data;\n        } catch (error) {\n            logError(error as Error, { context: 'getCommitHistory' });\n            throw error;\n        }\n    });\n};\n\n// --- File and Tree Functions ---\n\n/**\n * Fetches the file tree for a repository recursively.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @returns A promise that resolves to the root FileNode of the repository.\n */\nexport const getRepoTree = async (octokit: Octokit, owner: string, repo: string): Promise<FileNode> => {\n     return measurePerformance('getRepoTree', async () => {\n        logEvent('getRepoTree_start', { owner, repo });\n        try {\n            const { data: repoData } = await octokit.request('GET /repos/{owner}/{repo}', { owner, repo });\n            const defaultBranch = repoData.default_branch;\n\n            const { data: branch } = await octokit.request('GET /repos/{owner}/{repo}/branches/{branch}', {\n                owner,\n                repo,\n                branch: defaultBranch,\n            });\n            const treeSha = branch.commit.commit.tree.sha;\n            \n            const { data: treeData } = await octokit.request('GET /repos/{owner}/{repo}/git/trees/{tree_sha}', {\n                owner,\n                repo,\n                tree_sha: treeSha,\n                recursive: 'true',\n            });\n\n            const root: FileNode = { name: repo, type: 'folder', path: '', children: [] };\n            \n            treeData.tree.forEach((item: any) => {\n                const pathParts = item.path.split('/');\n                let currentNode = root;\n\n                pathParts.forEach((part, index) => {\n                    if (!currentNode.children) {\n                        currentNode.children = [];\n                    }\n                    const currentPath = pathParts.slice(0, index + 1).join('/');\n                    let childNode = currentNode.children.find(child => child.name === part && child.path === currentPath);\n\n                    if (!childNode) {\n                        childNode = {\n                            name: part,\n                            path: item.path,\n                            type: item.type === 'tree' ? 'folder' : 'file',\n                        };\n                        if(item.type === 'tree') {\n                            childNode.children = [];\n                            childNode.path = currentPath; \n                        }\n                        currentNode.children.push(childNode);\n                    }\n                    currentNode = childNode;\n                });\n            });\n\n            logEvent('getRepoTree_success', { owner, repo, items: treeData.tree.length });\n            return root;\n        } catch (error) {\n            logError(error as Error, { context: 'getRepoTree', owner, repo });\n            throw new Error(\\`Failed to fetch repository tree: \\${(error as Error).message}\\`);\n        }\n    });\n};\n\n/**\n * Fetches the content of a specific file from a repository.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @param path The full path to the file within the repository.\n * @returns A promise that resolves to the string content of the file.\n */\nexport const getFileContent = async (octokit: Octokit, owner: string, repo: string, path: string): Promise<string> => {\n    return measurePerformance('getFileContent', async () => {\n        logEvent('getFileContent_start', { owner, repo, path });\n        try {\n            const { data } = await octokit.request('GET /repos/{owner}/{repo}/contents/{path}', {\n                owner,\n                repo,\n                path,\n            });\n\n            if (Array.isArray(data) || data.type !== 'file' || typeof data.content !== 'string') {\n                 throw new Error(\"Path did not point to a valid file or content was missing.\");\n            }\n\n            // The content is Base64 encoded, so we need to decode it.\n            const content = atob(data.content);\n            logEvent('getFileContent_success', { owner, repo, path });\n            return content;\n        } catch (error) {\n             logError(error as Error, { context: 'getFileContent', owner, repo, path });\n             throw new Error(\\`Failed to fetch file content: \\${(error as Error).message}\\`);\n        }\n    });\n};\n\n// --- Commit and Branching Functions ---\n\n/**\n * Commits one or more files to a repository in a single commit.\n * @param octokit An authenticated Octokit instance.\n * @param owner The repository owner's login.\n * @param repo The repository name.\n * @param files An array of file objects with path and content.\n * @param message The commit message.\n * @param branch The branch to commit to (defaults to 'main').\n * @returns A promise that resolves with the URL of the new commit.\n */\nexport const commitFiles = async (\n    octokit: Octokit,\n    owner: string,\n    repo: string,\n    files: { path: string; content: string }[],\n    message: string,\n    branch: string = 'main'\n): Promise<string> => {\n    return measurePerformance('commitFiles', async () => {\n        logEvent('commitFiles_start', { owner, repo, fileCount: files.length, branch });\n\n        try {\n            // 1. Get the latest commit SHA and base tree SHA\n            const { data: refData } = await octokit.request('GET /repos/{owner}/{repo}/git/ref/{ref}', {\n                owner,\n                repo,\n                ref: \\`heads/\\${branch}\\`,\n            });\n            const latestCommitSha = refData.object.sha;\n            const { data: commitData } = await octokit.request('GET /repos/{owner}/{repo}/git/commits/{commit_sha}', {\n                owner,\n                repo,\n                commit_sha: latestCommitSha,\n            });\n            const baseTreeSha = commitData.tree.sha;\n\n            // 2. Create blobs for all new file contents\n            const blobPromises = files.map(file =>\n                octokit.request('POST /repos/{owner}/{repo}/git/blobs', {\n                    owner,\n                    repo,\n                    content: file.content,\n                    encoding: 'utf-8',\n                })\n            );\n            const blobs = await Promise.all(blobPromises);\n            \n            // 3. Create the tree object\n            const tree = blobs.map((blob, index) => ({\n                path: files[index].path,\n                mode: '100644' as const, // file mode\n                type: 'blob' as const,\n                sha: blob.data.sha,\n            }));\n\n            // 4. Create a new tree\n            const { data: newTree } = await octokit.request('POST /repos/{owner}/{repo}/git/trees', {\n                owner,\n                repo,\n                base_tree: baseTreeSha,\n                tree,\n            });\n\n            // 5. Create a new commit\n            const { data: newCommit } = await octokit.request('POST /repos/{owner}/{repo}/git/commits', {\n                owner,\n                repo,\n                message,\n                tree: newTree.sha,\n                parents: [latestCommitSha],\n            });\n\n            // 6. Update the branch reference (fast-forward)\n            await octokit.request('PATCH /repos/{owner}/{repo}/git/refs/{ref}', {\n                owner,\n                repo,\n                ref: \\`heads/\\${branch}\\`,\n                sha: newCommit.sha,\n            });\n\n            logEvent('commitFiles_success', { commitUrl: newCommit.html_url });\n            return newCommit.html_url;\n\n        } catch (error) {\n            logError(error as Error, { context: 'commitFiles', owner, repo, branch });\n            throw new Error(\\`Failed to commit files: \\${(error as Error).message}\\`);\n        }\n    });\n};`,\n  'services/googleApiService.ts': `// services/googleApiService.ts\nconst API_KEY = process.env.GEMINI_API_KEY;\nconst CLIENT_ID = \"555179712981-36hlicm802genhfo9iq1ufnp1n8cikt9.apps.googleusercontent.com\";\n\ndeclare global { interface Window { gapi: any; } }\n\nlet gapiInitialized = false;\n\nconst loadGapiScript = () => new Promise<void>((resolve, reject) => {\n    if (window.gapi) {\n        window.gapi.load('client', resolve);\n        return;\n    };\n    const script = document.createElement('script');\n    script.src = 'https://apis.google.com/js/api.js';\n    script.onload = () => window.gapi.load('client', resolve);\n    script.onerror = reject;\n    document.body.appendChild(script);\n});\n\nexport const ensureGapiClient = async (): Promise<boolean> => {\n    if (gapiInitialized) return true;\n    \n    try {\n        await loadGapiScript();\n\n        await window.gapi.client.init({\n            apiKey: API_KEY,\n            clientId: CLIENT_ID,\n            discoveryDocs: [\n                \"https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest\",\n                \"https://docs.googleapis.com/\\$discovery/rest?version=v1\",\n                \"https://www.googleapis.com/discovery/v1/apis/drive/v3/rest\",\n                \"https://iam.googleapis.com/\\$discovery/rest?version=v1\"\n            ],\n        });\n\n        const accessToken = sessionStorage.getItem('google_access_token');\n        if (!accessToken) {\n            console.error(\"GAPI: Access token not found. User may need to sign in again.\");\n            return false;\n        }\n        \n        window.gapi.client.setToken({ access_token: accessToken });\n        gapiInitialized = true;\n        return true;\n    } catch (error) {\n        console.error(\"GAPI client initialization failed:\", error);\n        gapiInitialized = false;\n        return false;\n    }\n};`,\n  'services/googleAuthService.ts': `import type { AppUser } from '../types.ts';\nimport { logError } from './telemetryService.ts';\n\ndeclare global {\n  const google: any;\n}\n\nconst GOOGLE_CLIENT_ID = \"555179712981-36hlicm802genhfo9iq1ufnp1n8cikt9.apps.googleusercontent.com\";\n\nconst SCOPES = [\n    'openid',\n    'https://www.googleapis.com/auth/userinfo.profile',\n    'https://www.googleapis.com/auth/userinfo.email',\n    'https://www.googleapis.com/auth/drive.appdata',\n    'https://www.googleapis.com/auth/drive.install',\n    'https://www.googleapis.com/auth/drive.file',\n    'https://www.googleapis.com/auth/iam.test',\n    'https://www.googleapis.com/auth/gmail.addons.current.action.compose',\n    'https://www.googleapis.com/auth/gmail.addons.current.message.action'\n].join(' ');\n\nlet tokenClient: any;\nlet onUserChangedCallback: (user: AppUser | null) => void = () => {};\n\nconst getGoogleUserProfile = async (accessToken: string) => {\n    const response = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {\n        headers: { Authorization: \\`Bearer \\${accessToken}\\` },\n    });\n    if (!response.ok) {\n        throw new Error('Failed to fetch user profile');\n    }\n    return response.json();\n};\n\nexport function initGoogleAuth(callback: (user: AppUser | null) => void) {\n  if (!GOOGLE_CLIENT_ID) {\n    console.error('Google Client ID not configured.');\n    return;\n  }\n  onUserChangedCallback = callback;\n  \n  tokenClient = google.accounts.oauth2.initTokenClient({\n    client_id: GOOGLE_CLIENT_ID,\n    scope: SCOPES,\n    callback: async (tokenResponse: any) => {\n      if (tokenResponse && tokenResponse.access_token) {\n        sessionStorage.setItem('google_access_token', tokenResponse.access_token);\n        try {\n            const profile = await getGoogleUserProfile(tokenResponse.access_token);\n            const appUser: AppUser = {\n                uid: profile.sub, // 'sub' is the standard OIDC field for user ID\n                displayName: profile.name,\n                email: profile.email,\n                photoURL: profile.picture,\n                tier: 'free',\n            };\n            onUserChangedCallback(appUser);\n        } catch (error) {\n            logError(error as Error, { context: 'googleAuthInitCallback' });\n            onUserChangedCallback(null);\n        }\n      } else {\n        logError(new Error('Google sign-in failed: No access token received.'), { tokenResponse });\n        onUserChangedCallback(null);\n      }\n    },\n  });\n}\n\nexport function signInWithGoogle() {\n  if (tokenClient) {\n    tokenClient.requestAccessToken({ prompt: 'consent' });\n  } else {\n    logError(new Error(\"Google Token Client not initialized.\"));\n  }\n}\n\nexport function signOutUser() {\n  const token = sessionStorage.getItem('google_access_token');\n  // Always remove the token from session storage to ensure local logout\n  sessionStorage.removeItem('google_access_token');\n  \n  // Attempt to revoke the token with Google as a best-effort\n  if (token && window.google?.accounts?.oauth2?.revoke) {\n    try {\n      google.accounts.oauth2.revoke(token, (response: any) => {\n        if (response && response.error) {\n          console.warn('Google token revocation failed:', response.error);\n          logError(new Error('Google token revocation failed'), { error: response.error });\n        } else {\n          console.log('Google token revoked successfully.');\n        }\n      });\n    } catch (error) {\n        console.error(\"Error calling google.accounts.oauth2.revoke:\", error);\n        logError(error as Error, { context: 'signOutUser' });\n    }\n  }\n  \n  // Always update the application's state to reflect logout\n  onUserChangedCallback(null);\n}`,\n  'services/index.ts': `\n\nexport * from './aiService.ts';\nexport * from './fileUtils.ts';\nexport * from './telemetryService.ts';\nexport * from './dbService.ts';\nexport * from './googleAuthService.ts';\nexport * from './githubService.ts';\nexport * from './componentLoader.ts';\nexport * from './taxonomyService.ts';\nexport * from './profiling/performanceService.ts';\nexport * from './profiling/bundleAnalyzer.ts';\nexport * from './auditing/accessibilityService.ts';\nexport * from './security/staticAnalysisService.ts';\nexport * from './googleApiService.ts';\nexport * from './workspaceService.ts';\nexport * from './gcpService.ts';\nexport * from './workspaceConnectorService.ts';`,\n  'services/mocking/.placeholder': ``,\n  'services/mocking/db.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport { openDB, DBSchema } from 'idb';\n\nconst DB_NAME = 'devcore-mock-db';\nconst DB_VERSION = 1;\nconst STORE_NAME = 'mock-collections';\n\ninterface MockDB extends DBSchema {\n  [STORE_NAME]: {\n    key: string;\n    value: {\n        id: string;\n        schemaDescription: string;\n        data: any[];\n    };\n  };\n}\n\nconst dbPromise = openDB<MockDB>(DB_NAME, DB_VERSION, {\n  upgrade(db) {\n    db.createObjectStore(STORE_NAME, { keyPath: 'id' });\n  },\n});\n\nexport const saveMockCollection = async (collection: { id: string; schemaDescription: string; data: any[] }): Promise<void> => {\n  const db = await dbPromise;\n  await db.put(STORE_NAME, collection);\n};\n\nexport const getMockCollection = async (id: string): Promise<{ id: string; schemaDescription: string; data: any[] } | undefined> => {\n  const db = await dbPromise;\n  return db.get(STORE_NAME, id);\n};\n\nexport const getAllMockCollections = async (): Promise<{ id: string; schemaDescription: string; data: any[] }[]> => {\n    const db = await dbPromise;\n    return db.getAll(STORE_NAME);\n}\n\nexport const deleteMockCollection = async (id: string): Promise<void> => {\n  const db = await dbPromise;\n  await db.delete(STORE_NAME, id);\n};\n`,\n  'services/mocking/mockServer.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nconst SERVICE_WORKER_URL = '/mock-service-worker.js';\nlet registration: ServiceWorkerRegistration | null = null;\n\nexport const startMockServer = (): Promise<void> => {\n    return new Promise(async (resolve, reject) => {\n        if (!('serviceWorker' in navigator)) {\n            return reject(new Error('Service workers are not supported in this browser.'));\n        }\n        \n        try {\n            registration = await navigator.serviceWorker.register(SERVICE_WORKER_URL);\n            \n            if (registration.installing) {\n                registration.installing.addEventListener('statechange', () => {\n                    if (registration.installing?.state === 'installed') {\n                        // The new worker is installed, now wait for it to activate\n                    }\n                });\n            }\n\n            if (registration.active) {\n                 console.log('Mock Service Worker already active.');\n                 return resolve();\n            }\n\n            // Wait for the worker to become active\n            await navigator.serviceWorker.ready;\n            console.log('Mock Service Worker registered and ready with scope:', registration.scope);\n            resolve();\n            \n        } catch (error) {\n            console.error('Mock Service Worker registration failed:', error);\n            reject(new Error('Could not start mock server.'));\n        }\n    });\n};\n\nexport const stopMockServer = async (): Promise<void> => {\n    const reg = await navigator.serviceWorker.getRegistration();\n    if (reg) {\n        await reg.unregister();\n        registration = null;\n        console.log('Mock Service Worker unregistered.');\n    }\n};\n\nexport const isMockServerRunning = (): boolean => {\n    // Check registration and controller status to determine if server is active.\n    return !!registration && !!navigator.serviceWorker.controller;\n};\n\ninterface MockRoute {\n    path: string; // e.g., /api/users/*\n    method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n    response: {\n        status: number;\n        body: any;\n        headers?: Record<string, string>;\n    }\n}\n\nexport const setMockRoutes = (routes: MockRoute[]): void => {\n    if (navigator.serviceWorker.controller) {\n        navigator.serviceWorker.controller.postMessage({\n            type: 'SET_ROUTES',\n            routes\n        });\n        console.log('Mock routes sent to service worker:', routes);\n    } else {\n        console.warn('Mock server is not active. Routes were not set.');\n    }\n};`,\n  'services/profiling/.placeholder': ``,\n  'services/profiling/bundleAnalyzer.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nexport interface BundleStatsNode {\n    name: string;\n    value: number;\n    children?: BundleStatsNode[];\n}\n\n// This is a simplified parser for Vite's \\`stats.json\\` output.\n// A real-world implementation would need to handle different formats (Webpack, Rollup, etc.).\nexport const parseViteStats = (statsJson: string): BundleStatsNode => {\n    try {\n        const stats = JSON.parse(statsJson);\n        const root: BundleStatsNode = { name: 'root', value: 0, children: [] };\n\n        if (stats.output) { // Vite 5+ stats format\n             Object.entries(stats.output).forEach(([path, chunk]: [string, any]) => {\n                const node: BundleStatsNode = {\n                    name: path,\n                    value: chunk.size,\n                };\n                root.children?.push(node);\n                root.value += chunk.size;\n            });\n        }\n\n        return root;\n    } catch (error) {\n        console.error(\"Failed to parse bundle stats:\", error);\n        throw new Error(\"Invalid stats JSON format.\");\n    }\n};\n`,\n  'services/profiling/performanceService.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nexport interface TraceEntry {\n    name: string;\n    startTime: number;\n    duration: number;\n    entryType: 'mark' | 'measure';\n}\n\nlet isTracing = false;\nconst TRACE_PREFIX = 'devcore-trace-';\n\nexport const startTracing = (): void => {\n    if (isTracing) {\n        console.warn('Tracing is already active.');\n        return;\n    }\n    performance.clearMarks();\n    performance.clearMeasures();\n    isTracing = true;\n    console.log('Performance tracing started.');\n};\n\nexport const stopTracing = (): TraceEntry[] => {\n    if (!isTracing) {\n        console.warn('Tracing is not active.');\n        return [];\n    }\n    isTracing = false;\n    console.log('Performance tracing stopped.');\n\n    const entries = performance.getEntries().filter(\n        entry => entry.name.startsWith(TRACE_PREFIX)\n    );\n\n    performance.clearMarks();\n    performance.clearMeasures();\n\n    return entries.map(entry => ({\n        name: entry.name.replace(TRACE_PREFIX, ''),\n        startTime: entry.startTime,\n        duration: entry.duration,\n        entryType: entry.entryType as 'mark' | 'measure',\n    }));\n};\n\nexport const mark = (name: string): void => {\n    if (!isTracing) return;\n    performance.mark(\\`\\${TRACE_PREFIX}\\${name}\\`);\n};\n\nexport const measure = (name: string, startMark: string, endMark: string): void => {\n    if (!isTracing) return;\n    try {\n        performance.measure(\\`\\${TRACE_PREFIX}\\${name}\\`, \\`\\${TRACE_PREFIX}\\${startMark}\\`, \\`\\${TRACE_PREFIX}\\${endMark}\\`);\n    } catch (e) {\n        console.error(\\`Failed to measure '\\${name}'\\`, e);\n    }\n};\n`,\n  'services/security/.placeholder': ``,\n  'services/security/staticAnalysisService.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nexport interface SecurityIssue {\n    line: number;\n    type: string;\n    description: string;\n    severity: 'High' | 'Medium' | 'Low';\n}\n\nconst rules = [\n    {\n        name: 'Hardcoded Secret',\n        regex: /(key|secret|token|password)['\"]?\\\\s*[:=]\\\\s*['\"]([a-zA-Z0-9-_.]{16,})['\"]/gi,\n        description: 'A hardcoded secret or API key was found. These should be stored in environment variables.',\n        severity: 'High' as const,\n    },\n    {\n        name: 'dangerouslySetInnerHTML',\n        regex: /dangerouslySetInnerHTML/g,\n        description: 'Use of dangerouslySetInnerHTML can open your application to XSS attacks. Ensure the source is sanitized.',\n        severity: 'Medium' as const,\n    },\n    {\n        name: 'eval() usage',\n        regex: /eval\\\\(/g,\n        description: 'The use of eval() is a major security risk as it can execute arbitrary code.',\n        severity: 'High' as const,\n    },\n    {\n        name: 'Insecure URL',\n        regex: /http:\\\\/\\\\//g,\n        description: 'Found an insecure \"http://\" URL. Use \"https://\" for all external resources.',\n        severity: 'Low' as const,\n    }\n];\n\nexport const runStaticScan = (code: string): SecurityIssue[] => {\n    const issues: SecurityIssue[] = [];\n    const lines = code.split('\\\\n');\n\n    lines.forEach((line, index) => {\n        rules.forEach(rule => {\n            if (rule.regex.test(line)) {\n                issues.push({\n                    line: index + 1,\n                    type: rule.name,\n                    description: rule.description,\n                    severity: rule.severity,\n                });\n            }\n        });\n    });\n\n    return issues;\n};\n`,\n  'services/sourceRegistry.ts': `// This file is a registry of all source code files in the application.\n// It's used by the ActionManager to create a downloadable zip of the entire app source.\n\nexport const sourceFiles: Record<string, string> = {\n  'index.html': \\`<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Citibank Demo Business Inc</title>\n    <script src=\"https://apis.google.com/js/api.js\"></script>\n    <style>\n      html, body, #root {\n        margin: 0;\n        padding: 0;\n        height: 100%;\n        width: 100%;\n        overflow: hidden;\n      }\n    </style>\n  <link rel=\"stylesheet\" href=\"/index.css\">\n</head>\n  <body>\n    <div id=\"root\"></div>\n    <script id=\"gsi-client\" src=\"https://accounts.google.com/gsi/client\" async defer></script>\n    <script type=\"module\" src=\"/index.tsx\"></script>\n  </body>\n</html>\\`,\n  'index.tsx': \\`/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App.tsx';\nimport { GlobalStateProvider } from './contexts/GlobalStateContext.tsx';\nimport './index.css';\n\nconst rootElement = document.getElementById('root');\nif (!rootElement) {\n  throw new Error(\"Could not find root element to mount to\");\n}\n\nconst root = ReactDOM.createRoot(rootElement);\nroot.render(\n  <React.StrictMode>\n    <GlobalStateProvider>\n      <App />\n    </GlobalStateProvider>\n  </React.StrictMode>\n);\\`,\n  'App.tsx': \\`\nimport React, { Suspense, useCallback, useMemo, useState, useEffect } from 'react';\nimport { ErrorBoundary } from './components/ErrorBoundary.tsx';\nimport { useGlobalState } from './contexts/GlobalStateContext.tsx';\nimport { logEvent } from './services/telemetryService.ts';\nimport { ALL_FEATURES, FEATURES_MAP } from './components/features/index.ts';\nimport type { ViewType, SidebarItem, AppUser } from './types.ts';\nimport { ActionManager } from './components/ActionManager.tsx';\nimport { LeftSidebar } from './components/LeftSidebar.tsx';\nimport { StatusBar } from './components/StatusBar.tsx';\nimport { CommandPalette } from './components/CommandPalette.tsx';\nimport { SettingsView } from './components/SettingsView.tsx';\nimport { Cog6ToothIcon, HomeIcon, FolderIcon, RectangleGroupIcon } from './components/icons.tsx';\nimport { AiCommandCenter } from './components/features/AiCommandCenter.tsx';\nimport { NotificationProvider } from './contexts/NotificationContext.tsx';\nimport { useTheme } from './hooks/useTheme.ts';\nimport { VaultProvider } from './components/vault/VaultProvider.tsx';\nimport { initGoogleAuth } from './services/googleAuthService.ts';\n\n\nexport const LoadingIndicator: React.FC = () => (\n    <div className=\"w-full h-full flex items-center justify-center bg-surface\">\n        <div className=\"flex items-center justify-center space-x-2\">\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0s' }}></div>\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n            <span className=\"text-text-secondary ml-2\">Loading Feature...</span>\n        </div>\n    </div>\n);\n\ninterface LocalStorageConsentModalProps {\n  onAccept: () => void;\n  onDecline: () => void;\n}\n\nconst LocalStorageConsentModal: React.FC<LocalStorageConsentModalProps> = ({ onAccept, onDecline }) => {\n  return (\n    <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n      <div \n        className=\"bg-surface border border-border rounded-2xl shadow-2xl shadow-black/50 w-full max-w-md m-4 p-8 text-center animate-pop-in\"\n      >\n        <h2 className=\"text-2xl mb-4\">Store Data Locally?</h2>\n        <p className=\"text-text-secondary mb-6\">\n          This application uses your browser's local storage to save your settings and remember your progress between sessions. This data stays on your computer and is not shared.\n        </p>\n        <div className=\"flex justify-center gap-4\">\n          <button\n            onClick={onDecline}\n            className=\"px-6 py-2 bg-surface border border-border text-text-primary font-bold rounded-md hover:bg-gray-100 dark:hover:bg-slate-700 transition-colors\"\n          >\n            Decline\n          </button>\n          <button\n            onClick={onAccept}\n            className=\"btn-primary px-6 py-2\"\n          >\n            Accept\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nconst AppContent: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const { activeView, viewProps, hiddenFeatures } = state;\n    const [isCommandPaletteOpen, setCommandPaletteOpen] = useState(false);\n  \n    useEffect(() => {\n      const handleKeyDown = (e: KeyboardEvent) => {\n          if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n              e.preventDefault();\n              setCommandPaletteOpen(isOpen => !isOpen);\n          }\n      };\n      window.addEventListener('keydown', handleKeyDown);\n      return () => window.removeEventListener('keydown', handleKeyDown);\n    }, []);\n  \n    const handleViewChange = useCallback((view: ViewType, props: any = {}) => {\n      dispatch({ type: 'SET_VIEW', payload: { view, props } });\n      logEvent('view_changed', { view });\n      setCommandPaletteOpen(false);\n    }, [dispatch]);\n  \n    const sidebarItems: SidebarItem[] = useMemo(() => {\n        const coreFeatures = ['ai-command-center', 'project-explorer', 'workspace-connector-hub'];\n        return [\n            { id: 'ai-command-center', label: 'Command Center', icon: <HomeIcon />, view: 'ai-command-center' },\n            { id: 'project-explorer', label: 'Project Explorer', icon: <FolderIcon />, view: 'project-explorer' },\n            { id: 'workspace-connector-hub', label: 'Workspace Hub', icon: <RectangleGroupIcon />, view: 'workspace-connector-hub' },\n            ...ALL_FEATURES\n                .filter(feature => !hiddenFeatures.includes(feature.id) && !coreFeatures.includes(feature.id))\n                .map(feature => ({\n                    id: feature.id,\n                    label: feature.name,\n                    icon: feature.icon,\n                    view: feature.id as ViewType,\n                })),\n            { id: 'settings', label: 'Settings', icon: <Cog6ToothIcon />, view: 'settings' },\n        ];\n    }, [hiddenFeatures]);\n  \n    const ActiveComponent = useMemo(() => {\n        if (activeView === 'settings') return SettingsView;\n        return FEATURES_MAP.get(activeView as string)?.component ?? AiCommandCenter;\n    }, [activeView]);\n    \n    return (\n        <div className=\"relative flex h-full w-full\">\n            <LeftSidebar items={sidebarItems} activeView={state.activeView} onNavigate={handleViewChange} />\n            <div className=\"flex-1 flex min-w-0\">\n                <div className=\"flex-1 flex flex-col min-w-0\">\n                    <main className=\"relative flex-1 min-w-0 bg-surface/50 dark:bg-slate-900/50 overflow-y-auto\">\n                        <ErrorBoundary>\n                            <Suspense fallback={<LoadingIndicator />}>\n                                <div key={activeView} className=\"fade-in w-full h-full\">\n                                    <ActiveComponent {...viewProps} />\n                                </div>\n                            </Suspense>\n                        </ErrorBoundary>\n                        <ActionManager />\n                    </main>\n                    <StatusBar bgImageStatus=\"loaded\" />\n                </div>\n            </div>\n            <CommandPalette isOpen={isCommandPaletteOpen} onClose={() => setCommandPaletteOpen(false)} onSelect={handleViewChange} />\n        </div>\n    )\n}\n\n\nconst App: React.FC = () => {\n    const [showConsentModal, setShowConsentModal] = useState(false);\n    const { dispatch } = useGlobalState();\n    useTheme(); // Initialize theme hook\n\n    useEffect(() => {\n      try {\n          const consent = localStorage.getItem('devcore_ls_consent');\n          if (!consent) {\n              setShowConsentModal(true);\n          }\n      } catch (e) {\n          console.warn(\"Could not access localStorage.\", e);\n      }\n    }, []);\n\n    useEffect(() => {\n        const handleUserChanged = (user: AppUser | null) => {\n            dispatch({ type: 'SET_APP_USER', payload: user });\n        };\n\n        const init = () => {\n            if (window.google) {\n                initGoogleAuth(handleUserChanged);\n            }\n        };\n\n        const gsiScript = document.getElementById('gsi-client');\n        if (window.google) {\n            init();\n        } else if (gsiScript) {\n            gsiScript.addEventListener('load', init);\n            return () => gsiScript.removeEventListener('load', init);\n        }\n    }, [dispatch]);\n  \n    const handleAcceptConsent = () => {\n      try {\n          localStorage.setItem('devcore_ls_consent', 'granted');\n          window.location.reload();\n      } catch (e) {\n          console.error(\"Could not write to localStorage.\", e);\n          setShowConsentModal(false);\n      }\n    };\n  \n    const handleDeclineConsent = () => {\n      try {\n          localStorage.setItem('devcore_ls_consent', 'denied');\n      } catch (e) {\n          console.error(\"Could not write to localStorage.\", e);\n      }\n      setShowConsentModal(false);\n    };\n\n    return (\n        <div className=\"h-screen w-screen font-sans overflow-hidden bg-background\">\n            <NotificationProvider>\n                <VaultProvider>\n                    {showConsentModal && <LocalStorageConsentModal onAccept={handleAcceptConsent} onDecline={handleDeclineConsent} />}\n                    <AppContent />\n                </VaultProvider>\n            </NotificationProvider>\n        </div>\n    );\n};\n\nexport default App;\n\\`,\n  // Add all other application files here...\n  'index.css': \\`@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n  --color-primary: #0047AB; /* Cobalt Blue */\n  --color-primary-rgb: 0, 71, 171;\n  --color-background: #F5F7FA; /* Light silver-blue */\n  --color-surface: #FFFFFF;\n  --color-text-primary: #111827; /* Gray 900 */\n  --color-text-secondary: #6B7280; /* Gray 500 */\n  --color-text-on-primary: #FFFFFF;\n  --color-border: #E5E7EB; /* Gray 200 */\n}\n\n.dark {\n  --color-primary: #38bdf8; /* sky-400 */\n  --color-primary-rgb: 56, 189, 248;\n  --color-background: #0f172a; /* slate-900 */\n  --color-surface: #1e293b; /* slate-800 */\n  --color-text-primary: #f8fafc; /* slate-50 */\n  --color-text-secondary: #94a3b8; /* slate-400 */\n  --color-text-on-primary: #0f172a; /* slate-900 */\n  --color-border: #334155; /* slate-700 */\n}\n\n/* Custom global styles */\nbody {\n  @apply bg-background text-text-primary transition-colors duration-300;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\nhtml.dark body {\n    background-image: none;\n}\n\n\n#root {\n  position: relative;\n  z-index: 1;\n}\n\n#root::before {\n  content: 'CitiBank demo business inc';\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%) rotate(-30deg);\n  font-family: theme('fontFamily.serif');\n  font-size: clamp(2rem, 8vw, 6rem); /* Responsive font size */\n  font-weight: bold;\n  color: theme('colors.gold');\n  opacity: 0.08;\n  pointer-events: none;\n  z-index: -1;\n  white-space: nowrap;\n}\n\nh1, h2, h3, h4, h5, h6 {\n  @apply font-serif text-text-primary;\n}\n\nh1 {\n  @apply text-text-primary;\n}\n\n/* Update primary buttons for a professional look */\n.btn-primary {\n  @apply bg-primary text-text-on-primary font-bold rounded-md hover:opacity-90 transition-all disabled:opacity-50 shadow-md;\n}\n\n/* Custom scrollbars for the new light theme */\n::-webkit-scrollbar {\n  width: 8px;\n  height: 8px;\n}\n::-webkit-scrollbar-track {\n  @apply bg-gray-100 dark:bg-slate-800;\n}\n::-webkit-scrollbar-thumb {\n  @apply bg-gray-400 dark:bg-slate-600 rounded;\n}\n::-webkit-scrollbar-thumb:hover {\n  @apply bg-gray-500 dark:bg-slate-500;\n}\n\n/* Base transitions for interactive elements */\nbutton, a, input, textarea, select {\n  transition: all 0.2s ease-in-out;\n}\n\n/* Keyframe Animations */\n@keyframes fadeIn {\n  from { opacity: 0; }\n  to { opacity: 1; }\n}\n\n@keyframes shake {\n  10%, 90% { transform: translateX(-1px); }\n  20%, 80% { transform: translateX(2px); }\n  30%, 50%, 70% { transform: translateX(-3px); }\n  40%, 60% { transform: translateX(3px); }\n}\n\n@keyframes pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95) translateY(10px);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1) translateY(0);\n  }\n}\n\n.fade-in { animation: fadeIn 0.5s ease-in-out forwards; }\n.animate-shake { animation: shake 0.4s ease-in-out; }\n.animate-pop-in { animation: pop-in 0.3s ease-out forwards; }\n\n/* For hiding scrollbar but keeping functionality */\n.no-scrollbar::-webkit-scrollbar { display: none; }\n.no-scrollbar { \n  -ms-overflow-style: none; \n  scrollbar-width: none; \n  scroll-behavior: smooth;\n}\\`,\n  'tailwind.config.js': \\`import typography from '@tailwindcss/typography';\n\n/** @type {import('tailwindcss').Config} */\nexport default {\n  darkMode: 'class',\n  content: [\n    \"./index.html\",\n    \"./App.tsx\",\n    \"./index.tsx\",\n    \"./constants.ts\",\n    \"./types.ts\",\n    \"./components/**/*.{js,ts,jsx,tsx}\",\n    \"./contexts/**/*.{js,ts,jsx,tsx}\",\n    \"./hooks/**/*.{js,ts,jsx,tsx}\",\n    \"./services/**/*.{js,ts,jsx,tsx}\",\n  ],\n  theme: {\n    extend: {\n      fontFamily: {\n        sans: ['Inter', 'sans-serif'],\n        serif: ['\"EB Garamond\"', 'serif'],\n        calligraphy: ['\"Great Vibes\"', 'cursive'],\n      },\n      colors: {\n        'primary': 'var(--color-primary)',\n        'background': 'var(--color-background)',\n        'surface': 'var(--color-surface)',\n        'text': {\n          'primary': 'var(--color-text-primary)',\n          'secondary': 'var(--color-text-secondary)',\n          'on-primary': 'var(--color-text-on-primary)',\n        },\n        'border': 'var(--color-border)',\n        'gold': '#B8860B', // DarkGoldenRod - better for watermark\n      },\n       boxShadow: {\n        'focus-primary': '0 0 0 3px rgba(var(--color-primary-rgb), 0.4)',\n        'md': '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',\n      },\n    },\n  },\n  plugins: [\n     typography,\n  ],\n}\\`,\n  'vite.config.ts': \\`\n\nimport path from 'path';\nimport { defineConfig, loadEnv } from 'vite';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineConfig(({ mode }) => {\n    const env = loadEnv(mode, '.', '');\n\n    return {\n      optimizeDeps: {\n        exclude: [\n          'axe-core'\n        ]\n      },\n      define: {\n        // The API key is injected into the app during the build process.\n        // It's crucial that this variable is set in your deployment environment.\n        'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),\n        'process.env.GOOGLE_CLIENT_ID': JSON.stringify(env.GOOGLE_CLIENT_ID),\n      },\n      resolve: {\n        alias: {\n          '@': path.resolve(__dirname, '.'),\n        }\n      },\n      server: {\n        // Disable CORS to mitigate vulnerability where malicious sites can request source files.\n        cors: false,\n      },\n      build: {\n        outDir: 'web', // Emit assets to a 'web' directory.\n        sourcemap: true, // Enable source maps for easier debugging in production.\n        rollupOptions: {\n          output: {\n            // Improve caching by splitting vendor code into separate chunks.\n            manualChunks(id) {\n              if (id.includes('node_modules')) {\n                return id.toString().split('node_modules/')[1].split('/')[0].toString();\n              }\n            }\n          }\n        }\n      }\n    };\n});\\`,\n'components/features/ProjectExplorer.tsx': \\`import React, { useState, useEffect, useCallback } from 'react';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { initializeOctokit } from '../../services/authService.ts';\nimport { getDecryptedCredential } from '../../services/vaultService.ts';\nimport { getRepos, getRepoTree, getFileContent, commitFiles } from '../../services/githubService.ts';\nimport { generateCommitMessageStream } from '../../services/index.ts';\nimport type { Repo, FileNode } from '../../types.ts';\nimport { FolderIcon, DocumentIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport * as Diff from 'diff';\n\nconst FileTree: React.FC<{ node: FileNode, onFileSelect: (path: string, name: string) => void, activePath: string | null }> = ({ node, onFileSelect, activePath }) => {\n    const [isOpen, setIsOpen] = useState(true);\n\n    if (node.type === 'file') {\n        const isActive = activePath === node.path;\n        return (\n            <div\n                className={\\\\\\`flex items-center space-x-2 pl-4 py-1 cursor-pointer rounded \\\\\\${isActive ? 'bg-primary/10 text-primary' : 'hover:bg-gray-100 dark:hover:bg-slate-700'}\\\\\\`}\n                onClick={() => onFileSelect(node.path, node.name)}\n            >\n                <DocumentIcon />\n                <span>{node.name}</span>\n            </div>\n        );\n    }\n\n    return (\n        <div>\n            <div\n                className=\"flex items-center space-x-2 py-1 cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-700 rounded\"\n                onClick={() => setIsOpen(!isOpen)}\n            >\n                <div className={\\\\\\`transform transition-transform \\\\\\${isOpen ? 'rotate-90' : ''}\\\\\\`}>▶</div>\n                <FolderIcon />\n                <span className=\"font-semibold\">{node.name}</span>\n            </div>\n            {isOpen && node.children && (\n                <div className=\"pl-4 border-l border-border ml-3\">\n                    {node.children.map(child => <FileTree key={child.path} node={child} onFileSelect={onFileSelect} activePath={activePath} />)}\n                </div>\n            )}\n        </div>\n    );\n};\n\nexport const ProjectExplorer: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const { user, githubUser, selectedRepo, projectFiles } = state;\n    const { addNotification } = useNotification();\n    const [repos, setRepos] = useState<Repo[]>([]);\n    const [isLoading, setIsLoading] = useState<'repos' | 'tree' | 'file' | 'commit' | null>(null);\n    const [error, setError] = useState('');\n    const [activeFile, setActiveFile] = useState<{ path: string; name: string; originalContent: string; editedContent: string} | null>(null);\n    \n    const getApiClient = useCallback(async () => {\n        if (!user) {\n            throw new Error(\"You must be logged in to use the Project Explorer.\");\n        }\n        // NOTE: This assumes the vault is unlocked. A more robust implementation\n        // might use the useVaultModal hook to prompt for unlock if needed.\n        const token = await getDecryptedCredential('github_pat');\n        if (!token) {\n            throw new Error(\"GitHub token not found. Please add it on the Connections page.\");\n        }\n        return initializeOctokit(token);\n    }, [user]);\n\n\n    useEffect(() => {\n        const loadRepos = async () => {\n            if (user && githubUser) {\n                setIsLoading('repos');\n                setError('');\n                try {\n                    const octokit = await getApiClient();\n                    const userRepos = await getRepos(octokit);\n                    setRepos(userRepos);\n                } catch (err) {\n                    setError(err instanceof Error ? err.message : 'Failed to load repositories');\n                } finally {\n                    setIsLoading(null);\n                }\n            } else {\n                setRepos([]);\n            }\n        };\n        loadRepos();\n    }, [user, githubUser, getApiClient]);\n\n    useEffect(() => {\n        const loadTree = async () => {\n             if (selectedRepo && user && githubUser) {\n                setIsLoading('tree');\n                setError('');\n                setActiveFile(null);\n                try {\n                    const octokit = await getApiClient();\n                    const tree = await getRepoTree(octokit, selectedRepo.owner, selectedRepo.repo);\n                    dispatch({ type: 'LOAD_PROJECT_FILES', payload: tree });\n                } catch (err) {\n                     setError(err instanceof Error ? err.message : 'Failed to load repository tree');\n                } finally {\n                    setIsLoading(null);\n                }\n            }\n        };\n        loadTree();\n    }, [selectedRepo, user, githubUser, dispatch, getApiClient]);\n\n    const handleFileSelect = async (path: string, name: string) => {\n        if (!selectedRepo) return;\n        setIsLoading('file');\n        try {\n            const octokit = await getApiClient();\n            const content = await getFileContent(octokit, selectedRepo.owner, selectedRepo.repo, path);\n            setActiveFile({ path, name, originalContent: content, editedContent: content });\n        } catch (err) {\n            setError((err as Error).message);\n        } finally {\n            setIsLoading(null);\n        }\n    };\n\n    const handleCommit = async () => {\n        if (!activeFile || !selectedRepo || activeFile.originalContent === activeFile.editedContent) return;\n\n        setIsLoading('commit');\n        setError('');\n        try {\n            const diff = Diff.createPatch(activeFile.path, activeFile.originalContent, activeFile.editedContent);\n            \n            const stream = generateCommitMessageStream(diff);\n            let commitMessage = '';\n            for await (const chunk of stream) { commitMessage += chunk; }\n            \n            const finalMessage = window.prompt(\"Confirm or edit commit message:\", commitMessage);\n            if (!finalMessage) {\n                setIsLoading(null);\n                return;\n            }\n\n            const octokit = await getApiClient();\n            await commitFiles(\n                octokit,\n                selectedRepo.owner,\n                selectedRepo.repo,\n                [{ path: activeFile.path, content: activeFile.editedContent }],\n                finalMessage\n            );\n            \n            addNotification(\\\\\\`Successfully committed to \\\\\\${selectedRepo.repo}\\\\\\`, 'success');\n            setActiveFile(prev => prev ? { ...prev, originalContent: prev.editedContent } : null);\n\n        } catch (err) {\n            const message = err instanceof Error ? err.message : 'Failed to commit changes';\n            setError(message);\n            addNotification(message, 'error');\n        } finally {\n            setIsLoading(null);\n        }\n    };\n    \n    if (!user) {\n        return (\n            <div className=\"h-full flex flex-col items-center justify-center text-center text-text-secondary p-4\">\n                <FolderIcon />\n                <h2 className=\"text-lg font-semibold mt-2\">Please Sign In</h2>\n                <p>Sign in via the \"Connections\" tab to explore your repositories.</p>\n            </div>\n        );\n    }\n    \n    if (!githubUser) {\n         return (\n            <div className=\"h-full flex flex-col items-center justify-center text-center text-text-secondary p-4\">\n                <FolderIcon />\n                <h2 className=\"text-lg font-semibold mt-2\">Connect to GitHub</h2>\n                <p>Please go to the \"Connections\" tab and provide a Personal Access Token to explore your repositories.</p>\n            </div>\n        );\n    }\n\n    const hasChanges = activeFile ? activeFile.originalContent !== activeFile.editedContent : false;\n\n    return (\n        <div className=\"h-full flex flex-col text-text-primary\">\n            <header className=\"p-4 border-b border-border flex-shrink-0\">\n                <h1 className=\"text-xl font-bold flex items-center\"><FolderIcon /><span className=\"ml-3\">Project Explorer</span></h1>\n                <div className=\"mt-2\">\n                    <select\n                        value={selectedRepo ? \\\\\\`\\\\\\${selectedRepo.owner}/\\\\\\${selectedRepo.repo}\\\\\\` : ''}\n                        onChange={e => {\n                            const [owner, repo] = e.target.value.split('/');\n                            dispatch({ type: 'SET_SELECTED_REPO', payload: { owner, repo } });\n                        }}\n                        className=\"w-full p-2 bg-surface border border-border rounded-md text-sm\"\n                    >\n                        <option value=\"\" disabled>{isLoading === 'repos' ? 'Loading...' : 'Select a repository'}</option>\n                        {repos.map(r => <option key={r.id} value={r.full_name}>{r.full_name}</option>)}\n                    </select>\n                </div>\n                {error && <p className=\"text-red-500 text-xs mt-2\">{error}</p>}\n            </header>\n            <div className=\"flex-grow flex min-h-0\">\n                <aside className=\"w-1/3 bg-background border-r border-border p-4 overflow-y-auto\">\n                    {isLoading === 'tree' && <div className=\"flex justify-center\"><LoadingSpinner /></div>}\n                    {projectFiles && <FileTree node={projectFiles} onFileSelect={handleFileSelect} activePath={activeFile?.path ?? null} />}\n                </aside>\n                <main className=\"flex-1 bg-surface flex flex-col\">\n                     <div className=\"flex justify-between items-center p-2 border-b border-border bg-gray-50 dark:bg-slate-800\">\n                        <span className=\"text-sm font-semibold\">{activeFile?.name || 'No file selected'}</span>\n                        <button onClick={handleCommit} disabled={!hasChanges || isLoading === 'commit'} className=\"btn-primary px-4 py-1 text-sm flex items-center justify-center min-w-[100px]\">\n                           {isLoading === 'commit' ? <LoadingSpinner/> : 'Commit'}\n                        </button>\n                     </div>\n                     {isLoading === 'file' ? <div className=\"flex items-center justify-center h-full\"><LoadingSpinner /></div> :\n                        <textarea \n                            value={activeFile?.editedContent ?? 'Select a file to view its content.'}\n                            onChange={e => setActiveFile(prev => prev ? { ...prev, editedContent: e.target.value } : null)}\n                            disabled={!activeFile}\n                            className=\"w-full h-full p-4 text-sm font-mono bg-transparent resize-none focus:outline-none\"\n                        />\n                    }\n                </main>\n            </div>\n        </div>\n    );\n};\\`,\n};`,\n  'services/taxonomyService.ts': `export interface FeatureTaxonomy {\n    id: string;\n    name: string;\n    description: string;\n    category: string;\n    inputs: string;\n}\n\nexport const FEATURE_TAXONOMY: FeatureTaxonomy[] = [\n    {\n        id: \"ai-command-center\",\n        name: \"AI Command Center\",\n        description: \"The main entry point. Use natural language to navigate and control the entire toolkit. Can call other tools.\",\n        category: \"Core\",\n        inputs: \"A natural language prompt describing what the user wants to do. Examples: 'explain this code: ...', 'design a theme with space vibes'.\"\n    },\n    {\n        id: \"workspace-connector-hub\",\n        name: \"Workspace Connector Hub\",\n        description: \"A central hub to execute actions on connected third-party services like Jira, Slack, GitHub, Vercel, and more. This is the primary tool for inter-service orchestration. The AI should use the 'runWorkspaceAction' function to interact with it.\",\n        category: \"Workflow\",\n        inputs: \"A natural language command describing a sequence of actions. Examples: 'create a jira ticket and post to slack', 'deploy the \\`dev\\` branch to vercel', 'summarize the last 5 commits and create a Confluence page'.\"\n    },\n    {\n        id: \"ai-code-explainer\",\n        name: \"AI Code Explainer\",\n        description: \"Accepts a code snippet and provides a detailed, structured analysis including summary, line-by-line breakdown, complexity, suggestions, and a visual flowchart.\",\n        category: \"AI Tools\",\n        inputs: \"A string containing a code snippet.\"\n    },\n    {\n        id: \"theme-designer\",\n        name: \"AI Theme Designer\",\n        description: \"Generates a complete UI color theme, including a semantic palette and accessibility scores, from a simple text description or an uploaded image.\",\n        category: \"AI Tools\",\n        inputs: \"A string describing the desired aesthetic (e.g., 'a calm, minimalist theme for a blog') or an image file.\"\n    },\n    {\n        id: \"regex-sandbox\",\n        name: \"RegEx Sandbox\",\n        description: \"Generates a regular expression from a natural language description. Also allows testing expressions against a string.\",\n        category: \"Testing\",\n        inputs: \"A string describing the pattern to match. Example: 'find all email addresses'.\"\n    },\n    {\n        id: \"ai-pull-request-assistant\",\n        name: \"AI Pull Request Assistant\",\n        description: \"Takes 'before' and 'after' code snippets, calculates the diff, generates a structured pull request summary (title, description, changes), and populates a full PR template.\",\n        category: \"AI Tools\",\n        inputs: \"Two strings: 'beforeCode' and 'afterCode'.\"\n    },\n     {\n        id: \"visual-git-tree\",\n        name: \"AI Git Log Analyzer\",\n        description: \"Intelligently parses a raw 'git log' output to create a categorized and well-formatted changelog, separating new features from bug fixes.\",\n        category: \"Git\",\n        inputs: \"A string containing the raw output of a 'git log' command.\"\n    },\n    {\n        id: \"cron-job-builder\",\n        name: \"AI Cron Job Builder\",\n        description: \"Generates a valid cron expression from a natural language description of a schedule.\",\n        category: \"Deployment\",\n        inputs: \"A string describing a schedule. Example: 'every weekday at 5pm'.\"\n    },\n    {\n        id: \"ai-code-migrator\",\n        name: \"AI Code Migrator\",\n        description: \"Translate code between languages & frameworks.\",\n        category: \"AI Tools\",\n        inputs: \"A string of code to convert, a string for the source language, and a string for the target language. e.g. 'migrate this SASS to CSS: ...'\"\n    },\n    {\n        id: \"ai-commit-generator\",\n        name: \"AI Commit Message Generator\",\n        description: \"Generates a conventional commit message from a git diff.\",\n        category: \"AI Tools\",\n        inputs: \"A string containing a git diff.\"\n    },\n    {\n        id: \"worker-thread-debugger\",\n        name: \"AI Concurrency Analyzer\",\n        description: \"Analyzes JavaScript code for potential Web Worker concurrency issues like race conditions.\",\n        category: \"Testing\",\n        inputs: \"A string of JavaScript code to analyze for concurrency issues.\"\n    },\n    {\n        id: \"xbrl-converter\",\n        name: \"XBRL Converter\",\n        description: \"Converts a JSON object into a simplified XBRL-like XML format.\",\n        category: \"Data\",\n        inputs: \"A string containing valid JSON.\"\n    },\n    {\n        id: \"api-mock-generator\",\n        name: \"API Mock Server\",\n        description: \"Generates mock API data from a description and serves it locally using a service worker.\",\n        category: \"Local Dev\",\n        inputs: \"A text description of a data schema (e.g., 'a user with id, name, and email').\"\n    },\n    {\n        id: \"env-manager\",\n        name: \".env Manager\",\n        description: \"A graphical interface for creating and managing .env files.\",\n        category: \"Local Dev\",\n        inputs: \"Key-value pairs for environment variables.\"\n    },\n    {\n        id: \"performance-profiler\",\n        name: \"AI Performance Profiler\",\n        description: \"Analyze runtime performance traces and bundle stats to get AI-powered optimization advice.\",\n        category: \"Performance & Auditing\",\n        inputs: \"Runtime performance data or pasted bundle statistics JSON.\"\n    },\n    {\n        id: \"a11y-auditor\",\n        name: \"Accessibility Auditor\",\n        description: \"Audit a live URL for accessibility issues and get AI-powered suggestions for fixes.\",\n        category: \"Performance & Auditing\",\n        inputs: \"A URL to a website or web application.\"\n    },\n    {\n        id: \"ci-cd-generator\",\n        name: \"AI CI/CD Pipeline Architect\",\n        description: \"Generate CI/CD configuration files (e.g., GitHub Actions YAML) from a natural language description.\",\n        category: \"Deployment & CI/CD\",\n        inputs: \"A text description of deployment stages (e.g., 'install, test, build, deploy').\"\n    },\n    {\n        id: \"deployment-preview\",\n        name: \"Static Deployment Previewer\",\n        description: \"See a live preview of files generated by the AI Feature Builder as if they were statically deployed.\",\n        category: \"Deployment & CI/CD\",\n        inputs: \"Files stored in the app's local database from the AI Feature Builder.\"\n    },\n    {\n        id: \"security-scanner\",\n        name: \"AI Security Scanner\",\n        description: \"Perform static analysis on code snippets to find common vulnerabilities and get AI-driven mitigation advice.\",\n        category: \"Security\",\n        inputs: \"A string containing a code snippet.\"\n    },\n    {\n        id: \"gmail-addon-simulator\",\n        name: \"Gmail Add-on Simulator\",\n        description: \"A simulation of how this app could use contextual Gmail Add-on scopes to read the current email and compose replies with AI assistance.\",\n        category: \"Productivity\",\n        inputs: \"A mock email context. No user input required to launch the simulation.\"\n    },\n    {\n        id: \"iam-policy-visualizer\",\n        name: \"GCP IAM Policy Visualizer\",\n        description: \"Visually test what a user can and cannot do across a set of Google Cloud resources.\",\n        category: \"Cloud\",\n        inputs: \"A list of full GCP resource names and a list of permission strings to test.\"\n    }\n];`,\n  'services/telemetryService.ts': `\n\nconst isTelemetryEnabled = true; // Could be controlled by a setting\n\nconst sanitizePayload = (payload: Record<string, any>): Record<string, any> => {\n    const sanitized: Record<string, any> = {};\n    for (const key in payload) {\n        if (Object.prototype.hasOwnProperty.call(payload, key)) {\n            const value = payload[key];\n            // Truncate long strings to avoid polluting the console (e.g., base64 data)\n            if (typeof value === 'string' && value.length > 500) {\n                sanitized[key] = \\`\\${value.substring(0, 100)}... (truncated)\\`;\n            } else {\n                sanitized[key] = value;\n            }\n        }\n    }\n    return sanitized;\n};\n\n\nexport const logEvent = (eventName: string, payload: Record<string, any> = {}) => {\n  if (!isTelemetryEnabled) return;\n\n  console.log(\n    \\`%c[TELEMETRY EVENT]%c \\${eventName}\\`,\n    'color: #84cc16; font-weight: bold;',\n    'color: inherit;',\n    sanitizePayload(payload)\n  );\n};\n\nexport const logError = (error: Error, context: Record<string, any> = {}) => {\n  if (!isTelemetryEnabled) return;\n\n  console.error(\n    \\`%c[TELEMETRY ERROR]%c \\${error.message}\\`,\n    'color: #ef4444; font-weight: bold;',\n    'color: inherit;',\n    {\n      error,\n      context: sanitizePayload(context),\n      stack: error.stack,\n    }\n  );\n};\n\nexport const measurePerformance = async <T>(\n  metricName: string,\n  operation: () => Promise<T>\n): Promise<T> => {\n  const start = performance.now();\n  try {\n    const result = await operation();\n    const end = performance.now();\n    const duration = end - start;\n\n    if (isTelemetryEnabled) {\n      console.log(\n        \\`%c[TELEMETRY PERF]%c \\${metricName}\\`,\n        'color: #3b82f6; font-weight: bold;',\n        'color: inherit;',\n        { duration: \\`\\${duration.toFixed(2)}ms\\` }\n      );\n    }\n    return result;\n  } catch (error) {\n    const end = performance.now();\n    const duration = end - start;\n     if (isTelemetryEnabled) {\n        console.warn(\n          \\`%c[TELEMETRY PERF FAILED]%c \\${metricName}\\`,\n          'color: #f97316; font-weight: bold;',\n          'color: inherit;',\n          { duration: \\`\\${duration.toFixed(2)}ms\\`, error }\n        );\n      }\n    throw error;\n  }\n};`,\n  'services/vaultService.ts': `/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\nimport * as crypto from './cryptoService.ts';\nimport * as db from './dbService.ts';\nimport type { EncryptedData } from '../types.ts';\n\nlet sessionKey: CryptoKey | null = null;\n\nexport const isVaultInitialized = async (): Promise<boolean> => {\n    const salt = await db.getVaultData('pbkdf2-salt');\n    return !!salt;\n};\n\nexport const initializeVault = async (masterPassword: string): Promise<void> => {\n    if (await isVaultInitialized()) {\n        throw new Error(\"Vault is already initialized.\");\n    }\n    const salt = crypto.generateSalt();\n    await db.saveVaultData('pbkdf2-salt', salt);\n    sessionKey = await crypto.deriveKey(masterPassword, salt);\n};\n\nexport const isUnlocked = (): boolean => {\n    return sessionKey !== null;\n};\n\nexport const unlockVault = async (masterPassword: string): Promise<void> => {\n    const salt = await db.getVaultData('pbkdf2-salt');\n    if (!salt) {\n        throw new Error(\"Vault not initialized.\");\n    }\n    try {\n        sessionKey = await crypto.deriveKey(masterPassword, salt);\n    } catch (e) {\n        console.error(\"Key derivation failed, likely incorrect password\", e);\n        throw new Error(\"Invalid Master Password.\");\n    }\n};\n\nexport const lockVault = (): void => {\n    sessionKey = null;\n};\n\nexport const saveCredential = async (id: string, plaintext: string): Promise<void> => {\n    if (!sessionKey) {\n        throw new Error(\"Vault is locked. Cannot save credential.\");\n    }\n    const { ciphertext, iv } = await crypto.encrypt(plaintext, sessionKey);\n    const encryptedData: EncryptedData = {\n        id,\n        ciphertext,\n        iv\n    };\n    await db.saveEncryptedToken(encryptedData);\n};\n\nexport const getDecryptedCredential = async (id: string): Promise<string | null> => {\n    if (!sessionKey) {\n        throw new Error(\"Vault is locked. Cannot retrieve credential.\");\n    }\n    const encryptedData = await db.getEncryptedToken(id);\n    if (!encryptedData) {\n        return null;\n    }\n    try {\n        return await crypto.decrypt(encryptedData.ciphertext, sessionKey, encryptedData.iv);\n    } catch (e) {\n        console.error(\\`Decryption failed for \\${id}\\`, e);\n        lockVault(); // Relock the vault on decryption failure as a security measure\n        throw new Error(\"Decryption failed. The vault has been locked.\");\n    }\n};\n\nexport const listCredentials = async (): Promise<string[]> => {\n    return db.getAllEncryptedTokenIds();\n};\n\nexport const resetVault = async (): Promise<void> => {\n    await db.clearAllData();\n    lockVault();\n}`,\n  'services/workspaceConnectorService.ts': `import * as vaultService from './vaultService.ts';\nimport { logError, logEvent } from './telemetryService.ts';\nimport { getDecryptedCredential } from './vaultService.ts';\n\n// Interface for any action\nexport interface WorkspaceAction {\n  id: string; // e.g., 'jira_create_ticket'\n  service: 'Jira' | 'Slack' | 'GitHub'; // etc.\n  description: string;\n  // Function to define the necessary input fields for this action\n  getParameters: () => { [key: string]: { type: 'string' | 'number', required: boolean, default?: string } };\n  // The actual logic to execute the action\n  execute: (params: any) => Promise<any>;\n}\n\n// THE REGISTRY: This is the pattern for all services.\nexport const ACTION_REGISTRY: Map<string, WorkspaceAction> = new Map();\n\n// --- JIRA EXAMPLE ---\nACTION_REGISTRY.set('jira_create_ticket', {\n  id: 'jira_create_ticket',\n  service: 'Jira',\n  description: 'Creates a new issue in a Jira project.',\n  getParameters: () => ({\n    projectKey: { type: 'string', required: true },\n    summary: { type: 'string', required: true },\n    description: { type: 'string', required: false },\n    issueType: { type: 'string', required: true, default: 'Task' }\n  }),\n  execute: async (params) => {\n    const domain = await getDecryptedCredential('jira_domain');\n    const token = await getDecryptedCredential('jira_pat');\n    const email = await getDecryptedCredential('jira_email');\n\n    if (!domain || !token || !email) {\n        throw new Error(\"Jira credentials not found in vault. Please connect Jira in the Workspace Connector Hub.\");\n    }\n    \n    // The Atlassian Document Format for the description field\n    const descriptionDoc = {\n      type: 'doc',\n      version: 1,\n      content: [\n        {\n          type: 'paragraph',\n          content: [\n            {\n              text: params.description || '',\n              type: 'text'\n            }\n          ]\n        }\n      ]\n    };\n\n    const response = await fetch(\\`https://\\${domain}/rest/api/3/issue\\`, {\n      method: 'POST',\n      headers: {\n        'Authorization': \\`Basic \\${btoa(\\`\\${email}:\\${token}\\`)}\\`,\n        'Accept': 'application/json',\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify({\n        fields: {\n           project: { key: params.projectKey },\n           summary: params.summary,\n           description: descriptionDoc,\n           issuetype: { name: params.issueType || 'Task' }\n        }\n      })\n    });\n    if (!response.ok) {\n        const errorBody = await response.text();\n        throw new Error(\\`Jira API Error (\\${response.status}): \\${errorBody}\\`);\n    }\n    return response.json();\n  }\n});\n\n// --- SLACK EXAMPLE ---\nACTION_REGISTRY.set('slack_post_message', {\n  id: 'slack_post_message',\n  service: 'Slack',\n  description: 'Posts a message to a Slack channel.',\n  getParameters: () => ({\n    channel: { type: 'string', required: true }, // e.g., #engineering or C1234567\n    text: { type: 'string', required: true }\n  }),\n  execute: async (params) => {\n    const token = await getDecryptedCredential('slack_bot_token');\n    if (!token) {\n        throw new Error(\"Slack credentials not found in vault. Please connect Slack in the Workspace Connector Hub.\");\n    }\n    const response = await fetch('https://slack.com/api/chat.postMessage', {\n        method: 'POST',\n        headers: {\n            'Authorization': \\`Bearer \\${token}\\`,\n            'Content-Type': 'application/json; charset=utf-8'\n        },\n        body: JSON.stringify({\n            channel: params.channel,\n            text: params.text\n        })\n    });\n     if (!response.ok) {\n        const errorBody = await response.json();\n        throw new Error(\\`Slack API Error: \\${errorBody.error}\\`);\n    }\n    return response.json();\n  }\n});\n\n\n// --- CENTRAL EXECUTION FUNCTION ---\nexport async function executeWorkspaceAction(actionId: string, params: any): Promise<any> {\n    const action = ACTION_REGISTRY.get(actionId);\n    if (!action) {\n        throw new Error(\\`Action \"\\${actionId}\" not found.\\`);\n    }\n    logEvent('workspace_action_execute', { actionId });\n    try {\n        const result = await action.execute(params);\n        logEvent('workspace_action_success', { actionId });\n        return result;\n    } catch (error) {\n        logError(error as Error, { context: 'executeWorkspaceAction', actionId });\n        throw error;\n    }\n}`,\n  'services/workspaceService.ts': `\n\nimport { ensureGapiClient } from './googleApiService.ts';\nimport { logError } from './telemetryService.ts';\nimport type { SlideSummary } from '../types.ts';\n\ndeclare var gapi: any;\n\n// --- Docs Service ---\nexport const createDocument = async (title: string): Promise<{ documentId: string; webViewLink: string }> => {\n    try {\n        const isReady = await ensureGapiClient();\n        if (!isReady) throw new Error(\"Google API client not ready.\");\n        \n        await gapi.client.load('https://docs.googleapis.com/\\$discovery/rest?version=v1');\n\n        const response = await gapi.client.docs.documents.create({ title });\n        const doc = response.result;\n        return { documentId: doc.documentId, webViewLink: \\`https://docs.google.com/document/d/\\${doc.documentId}/edit\\` };\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'createDocument' });\n        throw error;\n    }\n};\n\nexport const insertText = async (documentId: string, text: string): Promise<void> => {\n     try {\n        const isReady = await ensureGapiClient();\n        if (!isReady) throw new Error(\"Google API client not ready.\");\n\n        await gapi.client.load('https://docs.googleapis.com/\\$discovery/rest?version=v1');\n\n        await gapi.client.docs.documents.batchUpdate({\n            documentId,\n            resource: {\n                requests: [{\n                    insertText: {\n                        text: text,\n                        location: { index: 1 }\n                    }\n                }]\n            }\n        });\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'insertText' });\n        throw error;\n    }\n};\n\n// --- Drive Service ---\n\nconst getDriveClient = async () => {\n    const isReady = await ensureGapiClient();\n    if (!isReady) throw new Error(\"Google API client not ready.\");\n    await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/drive/v3/rest');\n    return gapi.client.drive;\n};\n\nexport const findOrCreateFolder = async (folderName: string): Promise<string> => {\n    try {\n        const drive = await getDriveClient();\n        const query = \\`mimeType='application/vnd.google-apps.folder' and name='\\${folderName}' and trashed=false\\`;\n        const response = await drive.files.list({ q: query, fields: 'files(id, name)' });\n        \n        if (response.result.files && response.result.files.length > 0) {\n            return response.result.files[0].id;\n        } else {\n            const fileMetadata = {\n                name: folderName,\n                mimeType: 'application/vnd.google-apps.folder'\n            };\n            const createResponse = await drive.files.create({ resource: fileMetadata, fields: 'id' });\n            return createResponse.result.id;\n        }\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'findOrCreateFolder' });\n        throw error;\n    }\n};\n\nexport const uploadFile = async (folderId: string, fileName: string, content: string, mimeType: string): Promise<any> => {\n    try {\n        await getDriveClient(); // Ensures client is loaded\n        \n        const metadata = {\n            name: fileName,\n            parents: [folderId],\n            mimeType,\n        };\n        \n        const form = new FormData();\n        form.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));\n        form.append('file', new Blob([content], { type: mimeType }));\n\n        const token = sessionStorage.getItem('google_access_token');\n        if (!token) throw new Error(\"Not authenticated\");\n\n        const res = await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {\n            method: 'POST',\n            headers: {\n                Authorization: \\`Bearer \\${token}\\`\n            },\n            body: form\n        });\n        \n        if (!res.ok) {\n            const errorBody = await res.json();\n            throw new Error(\\`Failed to upload file: \\${errorBody.error.message}\\`);\n        }\n\n        return await res.json();\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'uploadFile' });\n        throw error;\n    }\n};\n\n// Stubs for other Workspace services\nexport const appendRowToSheet = async (sheetId: string, rowData: any[]) => { console.log('appendRowToSheet called', sheetId, rowData); };\nexport const createTask = async (listId: string, title: string, notes: string) => { console.log('createTask called', listId, title, notes); };\nexport const createCalendarEvent = async (title: string, description: string, date: string) => { console.log('createCalendarEvent called', title, description, date); };`,\n  'tailwind.config.js': `import typography from '@tailwindcss/typography';\n\n/** @type {import('tailwindcss').Config} */\nexport default {\n  darkMode: 'class',\n  content: [\n    \"./index.html\",\n    \"./App.tsx\",\n    \"./index.tsx\",\n    \"./constants.tsx\",\n    \"./types.ts\",\n    \"./components/**/*.{js,ts,jsx,tsx}\",\n    \"./contexts/**/*.{js,ts,jsx,tsx}\",\n    \"./hooks/**/*.{js,ts,jsx,tsx}\",\n    \"./services/**/*.{js,ts,jsx,tsx}\",\n  ],\n  theme: {\n    extend: {\n      fontFamily: {\n        sans: ['Inter', 'sans-serif'],\n        serif: ['\"EB Garamond\"', 'serif'],\n        calligraphy: ['\"Great Vibes\"', 'cursive'],\n      },\n      colors: {\n        'primary': 'var(--color-primary)',\n        'background': 'var(--color-background)',\n        'surface': 'var(--color-surface)',\n        'text': {\n          'primary': 'var(--color-text-primary)',\n          'secondary': 'var(--color-text-secondary)',\n          'on-primary': 'var(--color-text-on-primary)',\n        },\n        'border': 'var(--color-border)',\n        'gold': '#B8860B', // DarkGoldenRod - better for watermark\n      },\n       boxShadow: {\n        'focus-primary': '0 0 0 3px rgba(var(--color-primary-rgb), 0.4)',\n        'md': '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',\n      },\n    },\n  },\n  plugins: [\n     typography,\n  ],\n}`,\n  'tsconfig.json': `\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"experimentalDecorators\": true,\n    \"useDefineForClassFields\": false,\n    \"module\": \"ES2022\",\n    \"lib\": [\n      \"ES2022\",\n      \"DOM\",\n      \"DOM.Iterable\"\n    ],\n    \"skipLibCheck\": true,\n    \"moduleResolution\": \"bundler\",\n    \"isolatedModules\": true,\n    \"moduleDetection\": \"force\",\n    \"allowJs\": true,\n    \"jsx\": \"react-jsx\",\n    \"paths\": {\n      \"@/*\": [\n        \"./*\"\n      ]\n    },\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true\n  }\n}`,\n  'tsconfig.server.json': `\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"CommonJS\",\n    \"moduleResolution\": \"node\",\n    \"outDir\": \"./\",\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true\n  }\n}\n`,\n  'types.ts': `import type React from 'react';\nimport { CHROME_VIEW_IDS, FEATURE_CATEGORIES } from './constants.tsx';\n\nexport type ChromeViewType = typeof CHROME_VIEW_IDS[number];\nexport type FeatureId = string;\nexport type FeatureCategory = typeof FEATURE_CATEGORIES[number];\n\nexport interface Feature {\n  id: FeatureId;\n  name: string;\n  description: string;\n  icon: React.ReactNode;\n  category: FeatureCategory;\n  component: React.FC<any>;\n  aiConfig?: {\n    model: string;\n    systemInstruction?: string;\n  };\n}\n\nexport type ViewType = FeatureId | ChromeViewType;\n\nexport interface GeneratedFile {\n  filePath: string;\n  content: string;\n  description: string;\n}\n\nexport interface SidebarItem {\n  id: string;\n  label: string;\n  icon: React.ReactNode;\n  view: ViewType;\n  props?: any;\n  action?: () => void;\n}\n\nexport interface StructuredPrSummary {\n    title: string;\n    summary: string;\n    changes: string[];\n}\n\nexport interface AppUser {\n  uid: string;\n  displayName: string | null;\n  email: string | null;\n  photoURL: string | null;\n  tier: 'free' | 'pro';\n}\n\nexport interface GitHubUser {\n  login: string;\n  id: number;\n  avatar_url: string;\n  html_url: string;\n  name: string | null;\n  email: string | null;\n}\n\nexport interface FileNode {\n  name: string;\n  type: 'file' | 'folder';\n  path: string;\n  content?: string;\n  children?: FileNode[];\n}\n\nexport type Theme = 'light' | 'dark';\n\nexport interface StructuredExplanation {\n    summary: string;\n    lineByLine: { lines: string; explanation: string }[];\n    complexity: { time: string; space: string };\n    suggestions: string[];\n}\n\nexport interface ColorTheme {\n    primary: string;\n    background: string;\n    surface: string;\n    textPrimary: string;\n    textSecondary: string;\n    textOnPrimary: string;\n    border: string;\n}\n\nexport interface ThemeState {\n    mode: Theme;\n    customColors: ColorTheme | null;\n}\n\nexport interface SemanticColorTheme {\n    mode: 'light' | 'dark';\n    palette: {\n        primary: { value: string; name: string; };\n        secondary: { value: string; name: string; };\n        accent: { value: string; name: string; };\n        neutral: { value: string; name: string; };\n    };\n    theme: {\n        background: { value: string; name: string; };\n        surface: { value: string; name: string; };\n        textPrimary: { value: string; name: string; };\n        textSecondary: { value: string; name: string; };\n        textOnPrimary: { value: string; name: string; };\n        border: { value: string; name: string; };\n    };\n    accessibility: {\n        primaryOnSurface: { ratio: number; score: string; };\n        textPrimaryOnSurface: { ratio: number; score:string; };\n        textSecondaryOnSurface: { ratio: number; score: string; };\n        textOnPrimaryOnPrimary: { ratio: number; score: string; };\n    };\n}\n\nexport interface SlideSummary {\n    title: string;\n    body: string;\n}\n\nexport interface Repo {\n  id: number;\n  name: string;\n  full_name: string;\n  private: boolean;\n  html_url: string;\n  description: string | null;\n  // Fix: Add owner property to match GitHub API response shape\n  owner: { login: string; };\n}\n\n// --- Code Review Types ---\nexport interface StructuredReviewSuggestion {\n    suggestion: string;\n    codeBlock: string;\n    explanation: string;\n}\n\nexport interface StructuredReview {\n    summary: string;\n    suggestions: StructuredReviewSuggestion[];\n}\n\n// --- AI Personality Forge Types ---\nexport interface SystemPrompt {\n  id: string;\n  name: string;\n  persona: string;\n  rules: string[];\n  outputFormat: 'json' | 'markdown' | 'text';\n  exampleIO: { input: string; output: string }[];\n}\n\n// --- Vault Types ---\nexport interface EncryptedData {\n    id: string;\n    ciphertext: ArrayBuffer;\n    iv: Uint8Array;\n}\n\n// --- New Types for Implemented Features ---\nexport interface SecurityVulnerability {\n    vulnerability: string;\n    severity: 'Critical' | 'High' | 'Medium' | 'Low' | 'Informational';\n    description: string;\n    mitigation: string;\n    exploitSuggestion?: string;\n}\n\nexport interface CodeSmell {\n    smell: string;\n    line: number;\n    explanation: string;\n}`,\n  'utils/.placeholder': ``,\n  'utils/promptUtils.ts': `import type { SystemPrompt } from '../types.ts';\n\n/**\n * Converts a structured SystemPrompt object into a single string\n * that can be used as the \\`systemInstruction\\` for the Gemini API.\n * @param prompt The SystemPrompt object.\n * @returns A formatted string representing the system prompt.\n */\nexport const formatSystemPromptToString = (prompt: SystemPrompt): string => {\n    if (!prompt) return \"You are a helpful assistant.\";\n\n    let instruction = \\`**PERSONA:**\\\\n\\${prompt.persona}\\\\n\\\\n\\`;\n\n    if (prompt.rules && prompt.rules.length > 0) {\n        instruction += \\`**RULES:**\\\\n\\${prompt.rules.map(rule => \\`- \\${rule}\\`).join('\\\\n')}\\\\n\\\\n\\`;\n    }\n\n    if (prompt.outputFormat) {\n        instruction += \\`**OUTPUT FORMAT:**\\\\nYou must respond in \\${prompt.outputFormat} format.\\\\n\\\\n\\`;\n    }\n\n    if (prompt.exampleIO && prompt.exampleIO.length > 0) {\n        instruction += \\`**EXAMPLES:**\\\\n\\`;\n        prompt.exampleIO.forEach(ex => {\n            if (ex.input && ex.output) {\n                instruction += \\`User Input:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${ex.input}\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\`;\n                instruction += \\`Your Output:\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n\\${ex.output}\\\\n\\\\\\`\\\\\\`\\\\\\`\\\\n---\\\\n\\`;\n            }\n        });\n    }\n\n    return instruction.trim();\n};`,\n  'vite.config.ts': `import path from 'path';\nimport { defineConfig, loadEnv } from 'vite';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineConfig(({ mode }) => {\n    const env = loadEnv(mode, '.', '');\n\n    return {\n      base: './',\n      optimizeDeps: {\n        exclude: [\n          'axe-core'\n        ]\n      },\n      define: {\n        // The Google Client ID is still needed for the auth library to initialize.\n        'process.env.GOOGLE_CLIENT_ID': JSON.stringify(env.GOOGLE_CLIENT_ID),\n        // The Gemini key is now handled at runtime, so we ensure the variable exists but may be empty.\n        'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),\n      },\n      resolve: {\n        alias: {\n          '@': path.resolve(__dirname, '.'),\n        }\n      },\n      server: {\n        // Disable CORS to mitigate vulnerability where malicious sites can request source files.\n        cors: false,\n      },\n      build: {\n        outDir: 'web', // Emit assets to a 'web' directory.\n        sourcemap: true, // Enable source maps for easier debugging in production.\n        rollupOptions: {\n          output: {\n            // Use relative paths for chunks to ensure module resolution works\n            // in environments that inline scripts as data: URIs, which breaks\n            // root-relative pathing.\n            entryFileNames: \\`assets/[name]-[hash].js\\`,\n            chunkFileNames: \\`assets/[name]-[hash].js\\`,\n            assetFileNames: \\`assets/[name]-[hash].[ext]\\`,\n            // Improve caching by splitting vendor code into separate chunks.\n            manualChunks(id) {\n              if (id.includes('node_modules')) {\n                return id.toString().split('node_modules/')[1].split('/')[0].toString();\n              }\n            }\n          }\n        }\n      }\n    };\n});`,\n};\n","import React, { useState } from 'react';\nimport JSZip from 'jszip';\nimport { getAllFiles } from '../services/dbService.ts';\nimport { ArrowDownTrayIcon } from './icons.tsx';\nimport { LoadingSpinner } from './shared/index.tsx';\nimport { sourceFiles } from '../services/sourceRegistry.ts';\n\nexport const ActionManager: React.FC = () => {\n    const [isLoading, setIsLoading] = useState<string | null>(null);\n\n    const handleDownloadSource = async () => {\n        setIsLoading('zip');\n        try {\n            const zip = new JSZip();\n\n            for (const [filePath, content] of Object.entries(sourceFiles)) {\n                zip.file(filePath, content);\n            }\n\n            const generatedFiles = await getAllFiles();\n            if (generatedFiles.length > 0) {\n                const generatedFolder = zip.folder('generated');\n                generatedFiles.forEach(file => {\n                    generatedFolder?.file(file.filePath, file.content);\n                });\n            }\n            \n            const zipBlob = await zip.generateAsync({ type: 'blob' });\n            const link = document.createElement('a');\n            link.href = URL.createObjectURL(zipBlob);\n            link.download = 'devcore-ai-toolkit-source.zip';\n            document.body.appendChild(link);\n            link.click();\n            document.body.removeChild(link);\n        } catch (error) {\n            console.error(\"Failed to create ZIP file\", error);\n            alert(`Error creating ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`);\n        } finally {\n            setIsLoading(null);\n        }\n    };\n\n    return (\n        <div className=\"absolute top-6 right-6 z-10\">\n            <button\n                onClick={handleDownloadSource}\n                disabled={!!isLoading}\n                className=\"w-14 h-14 bg-primary text-text-on-primary rounded-full flex items-center justify-center shadow-lg hover:opacity-90 transition-colors disabled:bg-slate-600\"\n                aria-label=\"Download App Source Code & Generated Files\"\n                title=\"Download App Source Code & Generated Files\"\n            >\n                {isLoading === 'zip' ? <LoadingSpinner /> : <ArrowDownTrayIcon />}\n            </button>\n        </div>\n    );\n};","import React, { useState, useCallback, useEffect } from 'react';\nimport { FeatureDock } from './FeatureDock.tsx';\nimport { Window } from './Window.tsx';\nimport { Taskbar } from './Taskbar.tsx';\nimport { ALL_FEATURES } from '../features/index.ts';\nimport type { Feature, ViewType } from '../../types.ts';\nimport { ActionManager } from '../ActionManager.tsx';\n\ninterface WindowState {\n  id: string;\n  position: { x: number; y: number };\n  size: { width: number; height: number };\n  zIndex: number;\n  isMinimized: boolean;\n}\n\nconst Z_INDEX_BASE = 10;\n\nexport const DesktopView: React.FC<{ openFeatureId?: string, onNavigate: (view: ViewType, props?: any) => void; }> = ({ openFeatureId, onNavigate }) => {\n    const [windows, setWindows] = useState<Record<string, WindowState>>({});\n    const [activeId, setActiveId] = useState<string | null>(null);\n    const [nextZIndex, setNextZIndex] = useState(Z_INDEX_BASE);\n    \n    const openWindow = useCallback((featureId: string) => {\n        if (!featureId) return;\n        const newZIndex = nextZIndex + 1;\n        setNextZIndex(newZIndex);\n        setActiveId(featureId);\n\n        setWindows(prev => {\n            const existingWindow = prev[featureId];\n            if (existingWindow) {\n                return {\n                    ...prev,\n                    [featureId]: {\n                        ...existingWindow,\n                        isMinimized: false,\n                        zIndex: newZIndex,\n                    }\n                };\n            }\n\n            const openWindowsCount = Object.values(prev).filter(w => !w.isMinimized).length;\n            const newWindow: WindowState = {\n                id: featureId,\n                position: { x: 50 + openWindowsCount * 30, y: 50 + openWindowsCount * 30 },\n                size: { width: 800, height: 600 },\n                zIndex: newZIndex,\n                isMinimized: false,\n            };\n            return { ...prev, [featureId]: newWindow };\n        });\n    }, [nextZIndex]);\n    \n    useEffect(() => {\n        if(openFeatureId) {\n            openWindow(openFeatureId);\n            // Reset the view in global state so it doesn't re-trigger\n            onNavigate('dashboard', {});\n        }\n    }, [openFeatureId, openWindow, onNavigate]);\n\n    const closeWindow = (id: string) => {\n        setWindows(prev => {\n            const newState = { ...prev };\n            delete newState[id];\n            return newState;\n        });\n        if (activeId === id) {\n            setActiveId(null);\n        }\n    };\n\n    const minimizeWindow = (id: string) => {\n        setWindows(prev => ({\n            ...prev,\n            [id]: { ...prev[id], isMinimized: true }\n        }));\n        setActiveId(null);\n    };\n\n    const focusWindow = (id: string) => {\n        if (id === activeId) return;\n        const newZIndex = nextZIndex + 1;\n        setNextZIndex(newZIndex);\n        setActiveId(id);\n        setWindows(prev => ({\n            ...prev,\n            [id]: { ...prev[id], zIndex: newZIndex }\n        }));\n    };\n    \n    const updateWindowState = (id: string, updates: Partial<WindowState>) => {\n        setWindows(prev => ({\n            ...prev,\n            [id]: { ...prev[id], ...updates }\n        }));\n    }\n\n    const openWindows = Object.values(windows).filter(w => !w.isMinimized);\n    const minimizedWindows = Object.values(windows).filter(w => w.isMinimized);\n    const featuresMap = new Map(ALL_FEATURES.map(f => [f.id, f]));\n\n    return (\n        <div className=\"h-full flex flex-row bg-transparent w-full\">\n            <FeatureDock onOpen={openWindow} />\n            <div className=\"flex-grow relative overflow-hidden\">\n                {openWindows.map(win => {\n                    const feature = featuresMap.get(win.id);\n                    if (!feature) return null;\n                    return (\n                        <Window\n                            key={win.id}\n                            feature={feature}\n                            state={win}\n                            isActive={win.id === activeId}\n                            onClose={() => closeWindow(win.id)}\n                            onMinimize={() => minimizeWindow(win.id)}\n                            onFocus={() => focusWindow(win.id)}\n                            onUpdate={updateWindowState}\n                        />\n                    );\n                })}\n                <ActionManager />\n            </div>\n            <Taskbar\n                minimizedWindows={minimizedWindows.map(w => featuresMap.get(w.id)).filter(Boolean) as Feature[]}\n                onRestore={openWindow}\n            />\n        </div>\n    );\n};","import React, { useState } from 'react';\nimport { useGlobalState } from '../contexts/GlobalStateContext.tsx';\nimport { useVaultModal } from '../contexts/VaultModalContext.tsx';\nimport { saveCredential } from '../services/vaultService.ts';\nimport { initializeAiClient } from '../services/aiService.ts';\nimport { LoadingSpinner } from './shared/LoadingSpinner.tsx';\nimport { useNotification } from '../contexts/NotificationContext.tsx';\n\nexport const ApiKeyPromptModal: React.FC = () => {\n    const { dispatch } = useGlobalState();\n    const { requestUnlock } = useVaultModal();\n    const { addNotification } = useNotification();\n    const [apiKey, setApiKey] = useState('');\n    const [isLoading, setIsLoading] = useState(false);\n\n    const handleSubmit = async (e: React.FormEvent) => {\n        e.preventDefault();\n        if (!apiKey.trim()) {\n            addNotification('Please enter an API key.', 'error');\n            return;\n        }\n\n        setIsLoading(true);\n\n        try {\n            // Ensure the vault is unlocked before saving\n            const unlocked = await requestUnlock();\n            if (!unlocked) {\n                addNotification('Vault must be unlocked to save the API key.', 'error');\n                setIsLoading(false);\n                return;\n            }\n\n            // Save the key and re-initialize the AI client\n            await saveCredential('gemini_api_key', apiKey);\n            await initializeAiClient();\n\n            addNotification('API Key saved successfully!', 'success');\n            dispatch({ type: 'SET_API_KEY_MISSING', payload: false });\n\n        } catch (error) {\n            addNotification(error instanceof Error ? error.message : 'An unknown error occurred.', 'error');\n        } finally {\n            setIsLoading(false);\n        }\n    };\n\n    return (\n        <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n            <div className=\"bg-surface border border-border rounded-lg shadow-2xl w-full max-w-md m-4 p-6 animate-pop-in\">\n                <h2 className=\"text-xl font-bold mb-2\">Enter Gemini API Key</h2>\n                <p className=\"text-sm text-text-secondary mb-4\">\n                    Your Gemini API key is required to power the AI features. It will be stored securely and encrypted in your browser's local storage.\n                </p>\n                <form onSubmit={handleSubmit} className=\"space-y-4\">\n                    <div>\n                        <label htmlFor=\"api-key-input\" className=\"block text-sm font-medium\">API Key</label>\n                        <input\n                            id=\"api-key-input\"\n                            type=\"password\"\n                            value={apiKey}\n                            onChange={(e) => setApiKey(e.target.value)}\n                            className=\"w-full mt-1 p-2 bg-background border border-border rounded-md\"\n                            required\n                            autoFocus\n                        />\n                    </div>\n                    <div className=\"flex justify-end gap-2 pt-2\">\n                        <button type=\"submit\" disabled={isLoading} className=\"btn-primary px-4 py-2 min-w-[100px] flex justify-center\">\n                            {isLoading ? <LoadingSpinner /> : 'Save & Continue'}\n                        </button>\n                    </div>\n                </form>\n            </div>\n        </div>\n    );\n};","import { Octokit } from 'octokit';\nimport type { GitHubUser as User } from '../types.ts';\nimport { logEvent } from './telemetryService.ts';\n\n/**\n * Creates a new Octokit instance with the provided token.\n * This function is now stateless and should be called with a plaintext token\n * that has been securely decrypted from the vault just before use.\n * @param token The plaintext GitHub Personal Access Token.\n * @returns A new Octokit instance.\n */\nexport const initializeOctokit = (token: string): Octokit => {\n    if (!token) {\n        throw new Error(\"Cannot initialize Octokit without a token.\");\n    }\n    logEvent('octokit_initialized');\n    return new Octokit({ auth: token, request: { headers: { 'X-GitHub-Api-Version': '2022-11-28' } } });\n};\n\n/**\n * Validates a plaintext token by fetching the user profile.\n * @param token The plaintext GitHub token to validate.\n * @returns A promise that resolves to the user's profile information.\n */\nexport const validateToken = async (token: string): Promise<User> => {\n    const tempOctokit = new Octokit({ auth: token });\n    const { data: user } = await tempOctokit.request('GET /user');\n    return user as unknown as User;\n};","import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';\nimport type { Octokit } from 'octokit';\nimport { initializeOctokit } from '../services/authService.ts';\nimport { getDecryptedCredential } from '../services/vaultService.ts';\nimport { useGlobalState } from './GlobalStateContext.tsx';\nimport { useVaultModal } from './VaultModalContext.tsx';\nimport { useNotification } from './NotificationContext.tsx';\n\ninterface OctokitContextType {\n    octokit: Octokit | null;\n    reinitialize: () => Promise<void>;\n}\n\nconst OctokitContext = createContext<OctokitContextType | undefined>(undefined);\n\nexport const useOctokit = (): OctokitContextType => {\n    const context = useContext(OctokitContext);\n    if (!context) {\n        throw new Error('useOctokit must be used within an OctokitProvider');\n    }\n    return context;\n};\n\nexport const OctokitProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n    const [octokit, setOctokit] = useState<Octokit | null>(null);\n    const { state, dispatch } = useGlobalState();\n    const { user, vaultState } = state;\n    const { requestUnlock } = useVaultModal();\n    const { addNotification } = useNotification();\n    \n    const initialize = useCallback(async () => {\n        if (!user) {\n            setOctokit(null);\n            return;\n        }\n\n        let isVaultUnlocked = vaultState.isUnlocked;\n\n        if (!isVaultUnlocked) {\n            const unlocked = await requestUnlock();\n            if (!unlocked) {\n                setOctokit(null);\n                return;\n            }\n        }\n\n        try {\n            const token = await getDecryptedCredential('github_pat');\n            if (token) {\n                const client = initializeOctokit(token);\n                setOctokit(client);\n            } else {\n                setOctokit(null); // No token stored, so no client.\n            }\n        } catch (e) {\n            if (e instanceof Error && e.message.includes('Decryption failed')) {\n                 dispatch({ type: 'SET_VAULT_STATE', payload: { isUnlocked: false } });\n            }\n            addNotification('Failed to initialize GitHub client.', 'error');\n            setOctokit(null);\n        }\n\n    }, [user, vaultState.isUnlocked, requestUnlock, addNotification, dispatch]);\n\n    useEffect(() => {\n        // Initialize when the user logs in or vault state changes to unlocked\n        if (user && vaultState.isUnlocked) {\n            initialize();\n        } else {\n            setOctokit(null);\n        }\n    }, [user, vaultState.isUnlocked, initialize]);\n\n    return (\n        <OctokitContext.Provider value={{ octokit, reinitialize: initialize }}>\n            {children}\n        </OctokitContext.Provider>\n    );\n};","import React, { Suspense, useCallback, useState, useEffect } from 'react';\nimport { ErrorBoundary } from './components/ErrorBoundary.tsx';\nimport { useGlobalState } from './contexts/GlobalStateContext.tsx';\nimport { logEvent } from './services/telemetryService.ts';\nimport type { ViewType, AppUser } from './types.ts';\nimport { CommandPalette } from './components/CommandPalette.tsx';\nimport { NotificationProvider } from './contexts/NotificationContext.tsx';\nimport { useTheme } from './hooks/useTheme.ts';\nimport { VaultProvider } from './components/vault/VaultProvider.tsx';\nimport { initGoogleAuth } from './services/googleAuthService.ts';\nimport { LoginView } from './components/LoginView.tsx';\nimport { DesktopView } from './components/desktop/DesktopView.tsx';\nimport { isApiKeyConfigured, initializeAiClient } from './services/aiService.ts';\nimport { ApiKeyPromptModal } from './components/ApiKeyPromptModal.tsx';\nimport { OctokitProvider } from './contexts/OctokitContext.tsx';\nimport { useVaultModal } from './contexts/VaultModalContext.tsx';\nimport { isVaultInitialized } from './services/vaultService.ts';\n\n\nexport const LoadingIndicator: React.FC = () => (\n    <div className=\"w-full h-full flex items-center justify-center bg-surface\">\n        <div className=\"flex items-center justify-center space-x-2\">\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0s' }}></div>\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0.2s' }}></div>\n            <div className=\"w-4 h-4 rounded-full bg-primary animate-pulse\" style={{ animationDelay: '0.4s' }}></div>\n            <span className=\"text-text-secondary ml-2\">Loading...</span>\n        </div>\n    </div>\n);\n\ninterface LocalStorageConsentModalProps {\n  onAccept: () => void;\n  onDecline: () => void;\n}\n\nconst LocalStorageConsentModal: React.FC<LocalStorageConsentModalProps> = ({ onAccept, onDecline }) => {\n  return (\n    <div className=\"fixed inset-0 bg-gray-900/80 backdrop-blur-sm z-50 flex items-center justify-center fade-in\">\n      <div \n        className=\"bg-surface border border-border rounded-2xl shadow-2xl shadow-black/50 w-full max-w-md m-4 p-8 text-center animate-pop-in\"\n      >\n        <h2 className=\"text-2xl mb-4\">Store Data Locally?</h2>\n        <p className=\"text-text-secondary mb-6\">\n          This application uses your browser's local storage to save your settings and remember your progress between sessions. This data stays on your computer and is not shared.\n        </p>\n        <div className=\"flex justify-center gap-4\">\n          <button\n            onClick={onDecline}\n            className=\"px-6 py-2 bg-surface border border-border text-text-primary font-bold rounded-md hover:bg-gray-100 dark:hover:bg-slate-700 transition-colors\"\n          >\n            Decline\n          </button>\n          <button\n            onClick={onAccept}\n            className=\"btn-primary px-6 py-2\"\n          >\n            Accept\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nconst AppContent: React.FC = () => {\n    const { state, dispatch } = useGlobalState();\n    const { activeView } = state;\n    const [isCommandPaletteOpen, setCommandPaletteOpen] = useState(false);\n  \n    useEffect(() => {\n      const handleKeyDown = (e: KeyboardEvent) => {\n          if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n              e.preventDefault();\n              setCommandPaletteOpen(isOpen => !isOpen);\n          }\n      };\n      window.addEventListener('keydown', handleKeyDown);\n      return () => window.removeEventListener('keydown', handleKeyDown);\n    }, []);\n  \n    const handleViewChange = useCallback((view: ViewType, props: any = {}) => {\n      logEvent('view_changed', { view });\n      dispatch({ type: 'SET_VIEW', payload: { view, props } });\n      setCommandPaletteOpen(false);\n    }, [dispatch]);\n  \n    return (\n        <OctokitProvider>\n            <div className=\"relative flex h-full w-full bg-slate-800\" style={{\n                backgroundImage: 'radial-gradient(circle at top left, var(--color-primary), transparent 60%), radial-gradient(circle at bottom right, #38bdf8, transparent 50%)',\n                backgroundBlendMode: 'multiply',\n            }}>\n                <ErrorBoundary>\n                    <Suspense fallback={<LoadingIndicator />}>\n                        <DesktopView openFeatureId={activeView} onNavigate={handleViewChange} />\n                    </Suspense>\n                </ErrorBoundary>\n                <CommandPalette isOpen={isCommandPaletteOpen} onClose={() => setCommandPaletteOpen(false)} onSelect={handleViewChange} />\n            </div>\n        </OctokitProvider>\n    )\n}\n\nconst AppShell: React.FC = () => {\n    const [consent, setConsent] = useState<'pending' | 'granted' | 'denied'>();\n    const { state, dispatch } = useGlobalState();\n    const { user, vaultState, isApiKeyMissing } = state;\n    const { requestCreation } = useVaultModal();\n    useTheme();\n\n    useEffect(() => {\n      try {\n          const consentStatus = localStorage.getItem('devcore_ls_consent');\n          if (!consentStatus) {\n              setConsent('pending');\n          } else {\n              setConsent(consentStatus as 'granted' | 'denied');\n          }\n      } catch (e) {\n          console.warn(\"Could not access localStorage.\", e);\n          setConsent('denied');\n      }\n    }, []);\n    \n    // Onboarding flow effect\n    useEffect(() => {\n        const runOnboardingChecks = async () => {\n            if (consent !== 'granted' || !user) return;\n            \n            // Check if vault needs to be created\n            const vaultExists = await isVaultInitialized();\n            if (!vaultExists) {\n                dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: false, isUnlocked: false } });\n                const created = await requestCreation();\n                if (created) {\n                     dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: true, isUnlocked: true } });\n                } else {\n                    return; // Stop flow if vault creation is cancelled\n                }\n            } else {\n                 dispatch({ type: 'SET_VAULT_STATE', payload: { isInitialized: true } });\n            }\n\n            // After vault is confirmed to exist/be created, check for API key\n            const keyConfigured = await isApiKeyConfigured();\n            if (!keyConfigured) {\n                dispatch({ type: 'SET_API_KEY_MISSING', payload: true });\n            } else {\n                dispatch({ type: 'SET_API_KEY_MISSING', payload: false });\n                initializeAiClient(); // Attempt initialization\n            }\n        };\n        runOnboardingChecks();\n\n    }, [consent, user, requestCreation, dispatch]);\n\n\n    useEffect(() => {\n        const handleUserChanged = (appUser: AppUser | null) => {\n            dispatch({ type: 'SET_APP_USER', payload: appUser });\n        };\n\n        const initAuth = () => {\n            if (window.google) {\n                initGoogleAuth(handleUserChanged);\n            }\n        };\n\n        const gsiScript = document.getElementById('gsi-client');\n        if (window.google) {\n            initAuth();\n        } else if (gsiScript) {\n            gsiScript.addEventListener('load', initAuth);\n            return () => gsiScript.removeEventListener('load', initAuth);\n        }\n    }, [dispatch]);\n  \n    const handleAcceptConsent = () => {\n      try {\n          localStorage.setItem('devcore_ls_consent', 'granted');\n          window.location.reload(); // Reload to re-evaluate storage access\n      } catch (e) {\n          console.error(\"Could not write to localStorage.\", e);\n          setConsent('denied');\n      }\n    };\n  \n    const handleDeclineConsent = () => {\n      try {\n          localStorage.setItem('devcore_ls_consent', 'denied');\n      } catch (e) {\n          console.error(\"Could not write to localStorage.\", e);\n      }\n      setConsent('denied');\n    };\n    \n    const renderContent = () => {\n        if (consent === 'pending') {\n            return <LocalStorageConsentModal onAccept={handleAcceptConsent} onDecline={handleDeclineConsent} />;\n        }\n        if (consent === 'denied') {\n            return <div className=\"w-full h-full flex items-center justify-center p-8 text-center\">Local storage access is required for this application to function. Please reload and accept the prompt.</div>\n        }\n        if (!user) {\n            return <LoginView />;\n        }\n        if (!vaultState.isInitialized || !vaultState.isUnlocked) {\n             // The VaultProvider modals will handle prompting for creation/unlock\n             return <LoadingIndicator />;\n        }\n        if (isApiKeyMissing) {\n            return <ApiKeyPromptModal />;\n        }\n         // Only show main app if user is logged in, vault is handled, and key is present.\n        if (user && vaultState.isUnlocked && !isApiKeyMissing) {\n            return <AppContent />;\n        }\n        // Default to a loading state while checks are running\n        return <LoadingIndicator />;\n    };\n\n    return renderContent();\n};\n\n\nconst App: React.FC = () => {\n    return (\n        <div className=\"h-screen w-screen font-sans overflow-hidden bg-background\">\n            <NotificationProvider>\n                <VaultProvider>\n                    <AppShell />\n                </VaultProvider>\n            </NotificationProvider>\n        </div>\n    );\n};\n\nexport default App;","/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App.tsx';\nimport { GlobalStateProvider } from './contexts/GlobalStateContext.tsx';\nimport './index.css';\n\nconst rootElement = document.getElementById('root');\nif (!rootElement) {\n  throw new Error(\"Could not find root element to mount to\");\n}\n\nconst root = ReactDOM.createRoot(rootElement);\nroot.render(\n  <React.StrictMode>\n    <GlobalStateProvider>\n        <App />\n    </GlobalStateProvider>\n  </React.StrictMode>\n);"],"file":"index-CX7Qxd1D.js"}