import fs from 'node:fs'; import path from 'node:path'; import {skillDir,slug} from './lib.mjs'; export function copyStatic(from,to){ const source=fs.realpathSync(from); if(!fs.existsSync(path.join(source,'index.html')))throw new Error('Choose a built static folder containing index.html.'); function validate(dir){for(const e of fs.readdirSync(dir,{withFileTypes:true})){ if(e.isSymbolicLink())throw new Error('Static bundle contains a symlink: '+e.name); if(/^(\.env(?:\..*)?|\.git|node_modules)$|\.(pem|key|keystore|jks|p12)$/i.test(e.name))throw new Error('Exclude credentials/development folders from static output: '+e.name); if(e.isDirectory())validate(path.join(dir,e.name)); }} validate(source);fs.cpSync(source,to,{recursive:true,errorOnExist:true,force:false}); } export function createWebProject(root,name,staticFolder=null){ slug(name);const to=path.join(root,'creations',name); if(fs.existsSync(to))throw new Error('Creation already exists; edit it in place: '+to); const pkg='dev.chloe.creations.'+name.replaceAll('-',''); // Stage in a sibling so a rejected import never leaves a half-created app. fs.mkdirSync(path.dirname(to),{recursive:true});const temp=fs.mkdtempSync(path.join(path.dirname(to),'.import-')); try{ fs.cpSync(path.join(skillDir,'assets/web-app'),temp,{recursive:true}); if(staticFolder){fs.rmSync(path.join(temp,'assets/www'),{recursive:true,force:true});copyStatic(staticFolder,path.join(temp,'assets/www'));} for(const file of ['AndroidManifest.xml','src/WebActivity.java']){const p=path.join(temp,file);fs.writeFileSync(p,fs.readFileSync(p,'utf8').replaceAll('PACKAGE_ID',pkg).replaceAll('APP_LABEL',name.split('-').map(s=>s[0].toUpperCase()+s.slice(1)).join(' ')));} fs.writeFileSync(path.join(temp,'creation.json'),JSON.stringify({name,package:pkg,workspace:'../..',version:1},null,2)+'\n'); fs.renameSync(temp,to); }catch(e){fs.rmSync(temp,{recursive:true,force:true});throw e;} console.log(JSON.stringify({created:to,package:pkg,next:'node '+path.join(to,'build.mjs')},null,2));return to; }