{"version":3,"sources":["/home/pitok/Projects/framework-bun/packages/buntok-core/dist/cli/index.cjs","../../src/cli/commands/build.ts","../../src/cli/commands/check.ts","../../src/cli/commands/create.ts","../../src/cli/generators/barrel.ts","../../src/cli/utils.ts","../../src/cli/generators/controller.ts","../../src/cli/generators/model.ts","../../src/cli/project.ts","../../src/cli/generators/repository.ts","../../src/cli/generators/schema.ts","../../src/cli/generators/service.ts","../../src/cli/routes-scan.ts","../../src/cli/commands/db.ts","../../src/cli/commands/db-seed.ts","../../src/cli/commands/debug-routes.ts","../../src/cli/commands/dev.ts","../../src/cli/env.ts","../../src/cli/commands/init.ts","../../src/cli/commands/make-docs.ts","../../src/cli/commands/make-factory.ts","../../src/cli/commands/make-middleware.ts","../../src/cli/commands/make-seeder.ts","../../src/cli/commands/make-test.ts","../../src/cli/commands/make-test-e2e.ts","../../src/cli/index.ts"],"names":["join","existsSync","readFileSync","getDrizzleType","getTypeORMType","getPrismaType","resolve","execSync","createInterface","mkdirSync","fs"],"mappings":"AAAA;AACA;AACE;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACF,yDAA8B;AAC9B;AACA;ACpCA,4BAAqB;AACrB,wBAA2B;AAE3B,MAAA,SAAsB,YAAA,CAAA,EAAe;AACpC,EAAA,MAAM,YAAA,EAAc,OAAA,CAAQ,GAAA,CAAI,CAAA;AAChC,EAAA,MAAM,WAAA,EAAa,wBAAA,WAAK,EAAa,WAAW,CAAA;AAChD,EAAA,MAAM,OAAA,EAAS,wBAAA,WAAK,EAAa,SAAS,CAAA;AAE1C,EAAA,GAAA,CAAI,CAAC,4BAAA,UAAqB,CAAA,EAAG;AAC5B,IAAA,OAAA,CAAQ,KAAA,CAAM,2CAAsC,CAAA;AACpD,IAAA,OAAA,CAAQ,SAAA,EAAW,CAAA;AACnB,IAAA,MAAA;AAAA,EACD;AAGA,EAAA,IAAI,SAAA,EAAqB,CAAC,CAAA;AAC1B,EAAA,MAAM,QAAA,EAAU,wBAAA,WAAK,EAAa,cAAc,CAAA;AAChD,EAAA,GAAA,CAAI,4BAAA,OAAkB,CAAA,EAAG;AACxB,IAAA,MAAM,IAAA,EAAM,MAAM,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA,CAAE,IAAA,CAAK,CAAA;AACzC,IAAA,SAAA,EAAW;AAAA,MACV,GAAG,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,aAAA,GAAgB,CAAC,CAAC,CAAA;AAAA,MACrC,GAAG,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,gBAAA,GAAmB,CAAC,CAAC;AAAA,IACzC,CAAA;AAAA,EACD;AAGA,EAAA,MAAM,SAAA,EAAW;AAAA,IAChB,gBAAA;AAAA,IACA,SAAA;AAAA,IACA,cAAA;AAAA,IACA,oBAAA;AAAA,IACA,yBAAA;AAAA,IACA,0BAAA;AAAA,IACA,qCAAA;AAAA,IACA,+BAAA;AAAA,IACA,yCAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,EACD,CAAA;AAEA,EAAA,MAAM,SAAA,EAAW,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,QAAA,EAAU,GAAG,QAAQ,CAAC,CAAC,CAAA;AAExD,EAAA,OAAA,CAAQ,GAAA,CAAI,8CAAuC,CAAA;AAEnD,EAAA,MAAM,OAAA,EAAS,MAAM,GAAA,CAAI,KAAA,CAAM;AAAA,IAC9B,WAAA,EAAa,CAAC,UAAU,CAAA;AAAA,IACxB,MAAA,EAAQ,MAAA;AAAA,IACR,MAAA,EAAQ,KAAA;AAAA,IACR,QAAA,EAAU,wBAAA,WAAK,EAAa,eAAe,CAAA;AAAA,IAC3C;AAAA,EACD,CAAC,CAAA;AAED,EAAA,GAAA,CAAI,CAAC,MAAA,CAAO,OAAA,EAAS;AACpB,IAAA,OAAA,CAAQ,KAAA,CAAM,qCAAgC,CAAA;AAC9C,IAAA,IAAA,CAAA,MAAW,IAAA,GAAO,MAAA,CAAO,IAAA,EAAM;AAC9B,MAAA,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA;AAAA,IAClB;AACA,IAAA,OAAA,CAAQ,SAAA,EAAW,CAAA;AACnB,IAAA,MAAA;AAAA,EACD;AAEA,EAAA,OAAA,CAAQ,GAAA,CAAI,iEAAuD,CAAA;AACnE,EAAA,OAAA,CAAQ,GAAA,CAAI,iFAAiF,CAAA;AAC9F;AD2BA;AACA;AE5FA;AACA;AAUA,SAAS,SAAA,CAAU,GAAA,EAAqB;AAEvC,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,oBAAA,EAAsB,EAAE,CAAA;AAC5C;AAEA,SAAS,aAAA,CAAc,MAAA,EAA2B;AACjD,EAAA,MAAM,MAAA,EAAQ,SAAA,CAAU,MAAM,CAAA;AAC9B,EAAA,MAAM,MAAA,EAAQ,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA;AAC9B,EAAA,MAAM,OAAA,EAAoB,CAAC,CAAA;AAE3B,EAAA,IAAA,CAAA,MAAW,KAAA,GAAQ,KAAA,EAAO;AAGzB,IAAA,MAAM,MAAA,EACL,IAAA,CAAK,KAAA,CAAM,6CAA6C,EAAA,GACxD,IAAA,CAAK,KAAA,CAAM,2CAA2C,CAAA;AACvD,IAAA,GAAA,CAAI,MAAA,GAAS,KAAA,CAAM,CAAC,EAAA,GAAK,KAAA,CAAM,CAAC,EAAA,GAAK,KAAA,CAAM,CAAC,EAAA,GAAK,KAAA,CAAM,CAAC,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,EAAG;AACtE,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACX,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA;AAAA,QACb,IAAA,EAAM,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,CAAC,CAAA,EAAG,EAAE,CAAA;AAAA,QAClC,GAAA,EAAK,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,CAAC,CAAA,EAAG,EAAE,CAAA;AAAA,QACjC,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA;AAAA,QACb,OAAA,EAAS,KAAA,CAAM,CAAC;AAAA,MACjB,CAAC,CAAA;AAAA,IACF;AAAA,EACD;AAEA,EAAA,OAAO,MAAA;AACR;AAEA,SAAS,cAAA,CAAe,MAAA,EAA6B;AACpD,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,EAAA,GAAM,CAAA,CAAE,IAAI,CAAC,CAAC,CAAA;AAC9C;AAEA,MAAA,SAAsB,YAAA,CAAa,MAAA,EAAkB,CAAC,CAAA,EAAkB;AACvE,EAAA,MAAM,IAAA,EAAM,OAAA,CAAQ,GAAA,CAAI,CAAA;AACxB,EAAA,MAAM,aAAA,EAAeA,wBAAAA,GAAK,EAAK,eAAe,CAAA;AAC9C,EAAA,MAAM,OAAA,EAAS,KAAA,CAAM,QAAA,CAAS,QAAQ,CAAA;AACtC,EAAA,MAAM,QAAA,EAAU,KAAA,CAAM,QAAA,CAAS,SAAS,CAAA;AAExC,EAAA,GAAA,CAAI,CAACC,4BAAAA,YAAuB,CAAA,EAAG;AAC9B,IAAA,GAAA,CAAI,MAAA,EAAQ;AACX,MAAA,OAAA,CAAQ,GAAA;AAAA,QACP,IAAA,CAAK,SAAA,CAAU;AAAA,UACd,OAAA,EAAS,KAAA;AAAA,UACT,KAAA,EAAO,mDAAA;AAAA,UACP,MAAA,EAAQ,CAAC,CAAA;AAAA,UACT,UAAA,EAAY,CAAA;AAAA,UACZ,SAAA,EAAW;AAAA,QACZ,CAAC;AAAA,MACF,CAAA;AAAA,IACD,EAAA,KAAO;AACN,MAAA,OAAA,CAAQ,KAAA;AAAA,QACP;AAAA,MACD,CAAA;AAAA,IACD;AACA,IAAA,OAAA,CAAQ,SAAA,EAAW,CAAA;AACnB,IAAA,MAAA;AAAA,EACD;AAEA,EAAA,GAAA,CAAI,CAAC,MAAA,EAAQ;AACZ,IAAA,GAAA,CAAI,OAAA,EAAS;AACZ,MAAA,OAAA,CAAQ,GAAA,CAAI,2BAA2B,CAAA;AAAA,IACxC,EAAA,KAAO;AACN,MAAA,OAAA,CAAQ,GAAA,CAAI,0CAA0C,CAAA;AAAA,IACvD;AAAA,EACD;AAEA,EAAA,MAAM,KAAA,EAAO,GAAA,CAAI,SAAA;AAAA,IAChB,CAAC,MAAA,EAAQ,KAAA,EAAO,UAAA,EAAY,UAAA,EAAY,WAAA,EAAa,YAAY,CAAA;AAAA,IACjE,EAAE,IAAI;AAAA,EACP,CAAA;AAEA,EAAA,MAAM,OAAA,kBAAS,IAAA,mBAAK,MAAA,6BAAQ,QAAA,mBAAS,IAAA,GAAK,EAAA;AAC1C,EAAA,MAAM,OAAA,EAAS,aAAA,CAAc,MAAM,CAAA;AACnC,EAAA,MAAM,MAAA,EAAQ,cAAA,CAAe,MAAM,CAAA;AACnC,EAAA,MAAM,WAAA,EAAa,MAAA,CAAO,MAAA;AAC1B,EAAA,MAAM,UAAA,EAAY,KAAA,CAAM,MAAA;AAExB,EAAA,GAAA,CAAI,IAAA,CAAK,SAAA,IAAa,CAAA,EAAG;AACxB,IAAA,GAAA,CAAI,MAAA,EAAQ;AACX,MAAA,OAAA,CAAQ,GAAA;AAAA,QACP,IAAA,CAAK,SAAA,CAAU;AAAA,UACd,OAAA,EAAS,IAAA;AAAA,UACT,MAAA,EAAQ,CAAC,CAAA;AAAA,UACT,UAAA,EAAY,CAAA;AAAA,UACZ,SAAA,EAAW;AAAA,QACZ,CAAC;AAAA,MACF,CAAA;AAAA,IACD,EAAA,KAAO;AACN,MAAA,GAAA,CAAI,OAAA,EAAS;AACZ,QAAA,OAAA,CAAQ,GAAA,CAAI,8BAAyB,CAAA;AAAA,MACtC,EAAA,KAAO;AACN,QAAA,OAAA,CAAQ,GAAA;AAAA,UACP,CAAA;AAAA;AAAA;AAAA,QACD,CAAA;AAAA,MACD;AAAA,IACD;AACA,IAAA,OAAA,CAAQ,SAAA,EAAW,CAAA;AACnB,IAAA,MAAA;AAAA,EACD;AAGA,EAAA,GAAA,CAAI,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,GAAA;AAAA,MACP,IAAA,CAAK,SAAA,CAAU;AAAA,QACd,OAAA,EAAS,KAAA;AAAA,QACT,MAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF,CAAA;AAAA,EACD,EAAA,KAAO;AAEN,IAAA,MAAM,UAAA,EAAY,EAAA;AAClB,IAAA,MAAM,YAAA,EAAc,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA;AAE7C,IAAA,IAAA,CAAA,MAAW,IAAA,GAAO,WAAA,EAAa;AAC9B,MAAA,MAAM,KAAA,EAAO,QAAA,EAAU,GAAA,CAAI,KAAA,EAAO,CAAA,QAAA,EAAW,GAAA,CAAI,IAAI,CAAA,OAAA,CAAA;AACrD,MAAA,MAAM,KAAA,EAAO,QAAA,EAAU,CAAA,EAAA;AACD,MAAA;AACC,MAAA;AACD,MAAA;AAEC,MAAA;AACxB,IAAA;AAEiB,IAAA;AACR,MAAA;AACP,QAAA;AAA4B,UAAA;AAC7B,MAAA;AACD,IAAA;AAGgB,IAAA;AACH,IAAA;AACJ,MAAA;AACP,QAAA;AAA4B,SAAA;AAAsD;AACnF,MAAA;AACM,IAAA;AACE,MAAA;AACP,QAAA;AAA2B,iBAAA;AAA+D;AAC3F,MAAA;AACD,IAAA;AACD,EAAA;AAEwB,EAAA;AACzB;AFoE8B;AACA;AGnOrBA;AACM;AACM;AHqOS;AACA;AItO7B;AAQ2B,EAAA;AAEH,EAAA;AACE,IAAA;AAC1B,EAAA;AAEqB,EAAA;AACK,IAAA;AAC1B,EAAA;AAEwB,EAAA;AACE,IAAA;AAC1B,EAAA;AAEoB,EAAA;AACX,IAAA;AACW,MAAA;AACK,MAAA;AACxB,IAAA;AACD,EAAA;AAE4B,EAAA;AAC7B;AJ4N8B;AACA;AK7PmB;AAEtC,EAAA;AAIX;AAEkD;AAG/C,EAAA;AAGH;AAEiD;AACpB,EAAA;AACJ,EAAA;AACzB;AAM2C;AAClC,EAAA;AACD,EAAA;AACF,EAAA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACD,EAAA;AACC,EAAA;AACD,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACC,EAAA;AACC,EAAA;AACA,EAAA;AACF,EAAA;AACA,EAAA;AACI,EAAA;AACF,EAAA;AACA,EAAA;AACG,EAAA;AACC,EAAA;AACL,EAAA;AACD,EAAA;AACP;AAEoB;AACnB,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AAM+C;AAC5B,EAAA;AACS,EAAA;AAEV,EAAA;AACH,EAAA;AACW,IAAA;AAG1B,EAAA;AAGyB,EAAA;AAEE,EAAA;AACA,EAAA;AACb,EAAA;AACf;AAmB0D;AAC/B,EAAA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACrB,EAAA;AACD,IAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACsB,IAAA;AACC,IAAA;AACxB,EAAA;AACD;ALkN8B;AACA;AMtUP;AACE,EAAA;AACzB;AAEwB;AACJ,EAAA;AACZ,EAAA;AACc,SAAA;AAAA;AAEL,KAAA;AACjB;AAEwB;AACC,EAAA;AACzB;AAES;AAKe,EAAA;AAChB,EAAA;AAAA;AAEa,SAAA;AAA+B;AAE1B,cAAA;AACL,cAAA;AACI,aAAA;AAAA,+BAAA;AACkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAU7B,4BAAA;AAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAOX,4BAAA;AAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAOX,4BAAA;AAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQX,4BAAA;AAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAOb,eAAA;AAAA;AAAA;AAAA;AAAA;AAK5B;AAES;AAOD,EAAA;AACa,SAAA;AACT;AAAA;AAEc,cAAA;AACL,cAAA;AACI,aAAA;AAA4C,+BAAA;AAE7C,UAAA;AAAW;AAAA;AAAA;AAInC;AAES;AAKD,EAAA;AAAA;AAAA;AAGa,cAAA;AACI,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BzB;AASC;AAMuB,EAAA;AAEN,EAAA;AACI,IAAA;AAChB,IAAA;AACA,IAAA;AAEiB,IAAA;AACf,MAAA;AACS,QAAA;AACH,QAAA;AACV,QAAA;AACI,MAAA;AACS,QAAA;AACH,QAAA;AACV,QAAA;AACI,MAAA;AACL,MAAA;AACc,QAAA;AACH,QAAA;AACV,QAAA;AACF,IAAA;AAGG,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AAEA,IAAA;AACJ,EAAA;AAEO,EAAA;AACR;ANkS8B;AACA;AOrerBA;AACY;AA8BL;AACf,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AAE0B;AAEJ;AACZ,EAAA;AACuB,EAAA;AACN,EAAA;AACP,IAAA;AACL,IAAA;AACN,MAAA;AACgB,MAAA;AACvB,MAAA;AACD,IAAA;AACyB,IAAA;AACb,MAAA;AACJ,MAAA;AACP,MAAA;AACD,IAAA;AACyB,IAAA;AACN,MAAA;AACX,MAAA;AACP,MAAA;AACD,IAAA;AACO,IAAA;AACR,EAAA;AACO,EAAA;AACR;AAGC;AAGkD,EAAA;AACtB,EAAA;AACxB,EAAA;AACoB,EAAA;AACX,IAAA;AACW,IAAA;AACG,IAAA;AACF,MAAA;AACA,MAAA;AACtB,QAAA;AACiB,QAAA;AAClB,MAAA;AACD,IAAA;AAC0B,IAAA;AACP,IAAA;AACpB,EAAA;AACO,EAAA;AACR;AAEuD;AAC5B,EAAA;AACF,EAAA;AACd,EAAA;AACK,EAAA;AACK,EAAA;AACQ,EAAA;AACrB,EAAA;AACN,IAAA;AACM,IAAA;AACoB,IAAA;AACR,IAAA;AACM,IAAA;AACC,IAAA;AACb,IAAA;AACS,IAAA;AACtB,EAAA;AACD;AAEkC;AACL,EAAA;AACb,EAAA;AACD,EAAA;AAEM,EAAA;AAGjB,IAAA;AAEmB,IAAA;AACtB,EAAA;AACoB,EAAA;AAEjB,IAAA;AAGoB,IAAA;AACT,MAAA;AACZ,MAAA;AACA,IAAA;AACF,EAAA;AACuB,EAAA;AACxB;AAGwD;AAC/B,EAAA;AACL,IAAA;AACK,IAAA;AACnB,IAAA;AACI,MAAA;AACA,IAAA;AACA,MAAA;AACR,IAAA;AACD,EAAA;AACO,EAAA;AACR;AAIC;AAGoB,EAAA;AACL,EAAA;AACQ,EAAA;AACI,EAAA;AACF,IAAA;AACzB,EAAA;AACO,EAAA;AACR;AAEmD;AAC1C,EAAA;AACH,EAAA;AACI,EAAA;AACF,EAAA;AACC,EAAA;AACC,EAAA;AACD,EAAA;AACC,EAAA;AACH,EAAA;AACA,EAAA;AACI,EAAA;AACJ,EAAA;AACC,EAAA;AACR;AAOgC;AACH,EAAA;AACH,EAAA;AACE,IAAA;AACZ,IAAA;AACJ,IAAA;AACF,IAAA;AACY,IAAA;AACP,IAAA;AACD,IAAA;AACX,MAAA;AACA,MAAA;AACkB,MAAA;AACA,MAAA;AACZ,MAAA;AACE,MAAA;AACI,MAAA;AACS,MAAA;AACrB,IAAA;AACF,EAAA;AACO,EAAA;AACR;AAGgC;AACJ,EAAA;AAC5B;AAEoC;AACd,EAAA;AACA,IAAA;AACd,MAAA;AACG,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACA,MAAA;AACG,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACA,MAAA;AACG,QAAA;AACC,MAAA;AACW,QAAA;AACD,QAAA;AACC,UAAA;AACnB,QAAA;AACO,QAAA;AACR,MAAA;AACD,IAAA;AACE,EAAA;AACI,EAAA;AACR;AAEiC;AACT,EAAA;AACI,EAAA;AACpB,EAAA;AACR;AAIC;AAGa,EAAA;AACY,EAAA;AACG,EAAA;AACF,IAAA;AACN,IAAA;AACK,IAAA;AACzB,EAAA;AACO,EAAA;AACR;AAEmC;AACT,EAAA;AAGH,EAAA;AACH,IAAA;AACV,MAAA;AACR,IAAA;AACoB,IAAA;AACd,MAAA;AACa,QAAA;AACb,QAAA;AACI,UAAA;AACa,QAAA;AACJ,QAAA;AACV,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACA,MAAA;AACA,MAAA;AACG,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACA,MAAA;AACG,QAAA;AACR,MAAA;AACQ,QAAA;AACT,IAAA;AACE,EAAA;AACiB,EAAA;AACrB;AAIC;AAGa,EAAA;AACY,EAAA;AACG,EAAA;AACF,IAAA;AACN,IAAA;AACK,IAAA;AACzB,EAAA;AACO,EAAA;AACR;AAEoC;AACf,EAAA;AACD,IAAA;AACM,MAAA;AACF,MAAA;AACd,MAAA;AACR,IAAA;AACoB,IAAA;AACd,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACG,QAAA;AACH,MAAA;AACG,QAAA;AACH,MAAA;AACA,MAAA;AACG,QAAA;AACR,MAAA;AACQ,QAAA;AACT,IAAA;AACE,EAAA;AACwB,EAAA;AAC5B;AAIC;AAGa,EAAA;AACY,EAAA;AACG,EAAA;AACD,IAAA;AACP,IAAA;AACI,IAAA;AACC,IAAA;AACzB,EAAA;AACO,EAAA;AACR;APsZ8B;AACA;AQ3vBrBA;AACY;AAQyB;AAE9B,EAAA;AACP,IAAA;AACR,EAAA;AACe,EAAA;AACP,IAAA;AACR,EAAA;AAEY,EAAA;AAIJ,IAAA;AACR,EAAA;AAGe,EAAA;AACV,IAAA;AACoBC,MAAAA;AACD,MAAA;AACb,MAAA;AACa,MAAA;AACD,MAAA;AACd,IAAA;AAER,IAAA;AACD,EAAA;AAEO,EAAA;AACR;AAGiC;AACJ,EAAA;AAC7B;AAGgC;AAC/B,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACD;AAM4C;AACf,EAAA;AACJ,EAAA;AACH,IAAA;AACrB,EAAA;AAC2B,EAAA;AACH,EAAA;AACnB,IAAA;AACSA,MAAAA;AACR,MAAA;AACI,QAAA;AACR,MAAA;AACO,IAAA;AAER,IAAA;AACD,EAAA;AACsB,EAAA;AACvB;AAG2B;AACd,EAAA;AACgB,EAAA;AACX,IAAA;AACA,IAAA;AACK,IAAA;AACpB,MAAA;AACwB,MAAA;AACzB,IAAA;AACD,EAAA;AACO,EAAA;AACR;AAM2D;AACtC,EAAA;AACQ,EAAA;AACA,EAAA;AACd,EAAA;AACW,EAAA;AACP,EAAA;AACI,EAAA;AACf,EAAA;AACR;AAOmC;AAKV,EAAA;AACG,EAAA;AACV,IAAA;AACjB,EAAA;AAEuB,EAAA;AACG,EAAA;AACT,IAAA;AACjB,EAAA;AAE2B,EAAA;AACH,EAAA;AACP,IAAA;AACjB,EAAA;AAGyB,EAAA;AACH,EAAA;AACR,IAAA;AACC,IAAA;AACI,IAAA;AACC,MAAA;AACI,MAAA;AACD,MAAA;AACtB,IAAA;AACD,EAAA;AAE4B,EAAA;AAC7B;AAG0C;AAClB,EAAA;AACK,EAAA;AACN,EAAA;AACI,EAAA;AACA,IAAA;AACN,MAAA;AACnB,IAAA;AACD,EAAA;AAC4B,EAAA;AACd,IAAA;AACP,EAAA;AACW,IAAA;AAClB,EAAA;AACsB,EAAA;AACvB;AAMgB;AAIK,EAAA;AACnB,IAAA;AACD,EAAA;AAC+B,EAAA;AAClB,EAAA;AACM,IAAA;AACO,MAAA;AACR,MAAA;AACM,QAAA;AACd,UAAA;AACM,YAAA;AACZ,UAAA;AACM,UAAA;AACM,YAAA;AACZ,UAAA;AACI,UAAA;AACL,QAAA;AACiB,QAAA;AAClB,MAAA;AACD,IAAA;AACD,EAAA;AACO,EAAA;AACR;AAOgC;AACP,EAAA;AACC,EAAA;AACAD,EAAAA;AACR,EAAA;AACE,IAAA;AACE,IAAA;AACrB,EAAA;AACyB,EAAA;AAC1B;AR6rB8B;AACA;ASv4BrB;AACS,EAAA;AACV,EAAA;AACkB,cAAA;AAAA;AAED,aAAA;AACI,2BAAA;AACD,kBAAA;AAAA;AAAA;AAAA,+CAAA;AAIA,kBAAA;AAAA;AAAA;AAGE,4BAAA;AACF,kBAAA;AAAA;AAAA;AAAA,iDAAA;AAIA,kBAAA;AAAA;AAAA;AAAA,6CAAA;AAIA,kBAAA;AAAA;AAAA;AAAA;AAIA,kBAAA;AAAA;AAAA;AAAA;AAI5B;AAES;AAID,EAAA;AAAA;AAEkB,cAAA;AAAA;AAED,aAAA;AACX,EAAA;AACO,SAAA;AACA,SAAA;AAAA;AAAA;AAGA,mBAAA;AAAU;AAAA;AAAA;AAI/B;AAES;AACD,EAAA;AAAA;AAEa,SAAA;AAAA;AAEI,aAAA;AAAA;AAEK,4BAAA;AAAU;AAAA;AAAA;AAAA,2CAAA;AAIuC;AAAA;AAAA;AAIjD,4BAAA;AAAU,oCAAA;AACQ;AAAA;AAAA;AAAA,wCAAA;AAII,oCAAA;AAC8B;AAAA;AAAA;AAAA;AAK5D,oBAAA;AAAkC;AAAA;AAAA;AAAA;AAAA,6DAAA;AAKiB;AAAA;AAAA;AAAA;AAKzE;AAES;AACD,EAAA;AACa,SAAA;AAAqC;AAEjC,aAAA;AAAA,6CAAA;AACgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAAA;AAUhB;AAAA;AAAA;AAAA,yCAAA;AAIY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAerD;AAQC;AAK2B,EAAA;AAEN,EAAA;AACf,IAAA;AACG,MAAA;AACH,IAAA;AACG,MAAA;AACH,IAAA;AACL,IAAA;AAEI,MAAA;AAEL,EAAA;AACD;ATq3B8B;AACA;AUxhCrBA;AACM;AACM;AAUpB;AAIU,EAAA;AAEN,0BAAA;AACG,EAAA;AAAA;AAEa,mBAAA;AACf;AAAA;AAAA;AAGe,mBAAA;AAAsC;AAE7B,kBAAA;AACA,kBAAA;AAA0C;AAExE;AAEsB;AAMF,EAAA;AACG,EAAA;AAEC,EAAA;AACf,IAAA;AACR,EAAA;AAEmB,EAAA;AACZ,EAAA;AACR;AVqgC8B;AACA;AW7iCP;AACE,EAAA;AACzB;AAEwB;AAChB,EAAA;AACc,SAAA;AAAA;AAEO,KAAA;AAC7B;AAEwB;AACC,EAAA;AACzB;AAGC;AAIqB,EAAA;AACf,IAAA;AACiBE,MAAAA;AACjB,IAAA;AACiBC,MAAAA;AACjB,IAAA;AACL,IAAA;AACsBC,MAAAA;AACvB,EAAA;AACD;AAGC;AAKoB,EAAA;AACb,EAAA;AACa,SAAA;AACT;AAAA;AAEc,cAAA;AACD,aAAA;AAAA,+BAAA;AAC+B;AAE5B,0BAAA;AACF,gBAAA;AAAA;AAAA;AAAA,8CAAA;AAII,4BAAA;AAAQ;AAAA;AAAA;AAAA;AAAA,mCAAA;AAMZ,gBAAA;AAAA;AAAA;AAAA,wDAAA;AAGuC;AAEvC,gBAAA;AAAA;AAAA;AAAA,6CAAA;AAG4B;AAE5B,gBAAA;AAAA;AAAA;AAAA;AAIA,gBAAA;AAAA;AAAA;AAAA;AAI1B;AAGC;AAKoB,EAAA;AACb,EAAA;AACa,SAAA;AACT;AAAA;AAEc,cAAA;AACD,aAAA;AAAsC,+BAAA;AAE3C,UAAA;AAAA;AAAA;AAAA;AAIpB;AAGC;AAMc,EAAA;AACO,IAAA;AACA,IAAA;AACnB,MAAA;AACA,MAAA;AACA,MAAA;AACD,IAAA;AAGG,IAAA;AAEJ,EAAA;AAEuB,EAAA;AAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBlC;AXihC8B;AACA;AYrqCrBJ;AACY;AAeH;AACjB,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AAE+C;AAC3C,EAAA;AACA,EAAA;AACsB,IAAA;AAClB,EAAA;AACP,IAAA;AACD,EAAA;AACoB,EAAA;AACK,IAAA;AACD,IAAA;AACG,IAAA;AACtB,IAAA;AACgB,MAAA;AACK,MAAA;AACjB,IAAA;AAER,IAAA;AACD,EAAA;AACD;AAE0B;AAEf,EAAA;AAGiB,EAAA;AACC,EAAA;AACrB,EAAA;AACR;AAEuB;AACF,EAAA;AACK,EAAA;AACG,EAAA;AAC7B;AAEqB;AACpB,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACD;AAGiC;AACA,EAAA;AACR,EAAA;AACvB,IAAA;AACD,EAAA;AACuB,EAAA;AAEtB,EAAA;AACsB,EAAA;AAIF,EAAA;AACM,IAAA;AACtB,IAAA;AACgB,IAAA;AAEI,MAAA;AACD,MAAA;AACL,MAAA;AACL,MAAA;AACX,QAAA;AACY,QAAA;AACO,QAAA;AACC,QAAA;AACD,QAAA;AACnB,MAAA;AACF,IAAA;AACD,EAAA;AAGuB,EAAA;AACgB,IAAA;AAC1B,MAAA;AACG,MAAA;AACF,MAAA;AACE,MAAA;AACG,MAAA;AAClB,IAAA;AACwB,IAAA;AACA,IAAA;AACN,MAAA;AACI,MAAA;AAEC,MAAA;AACV,MAAA;AACX,QAAA;AACY,QAAA;AACZ,QAAA;AACM,QAAA;AACA,QAAA;AACN,MAAA;AACF,IAAA;AACD,EAAA;AACO,EAAA;AACR;AAGyC;AACf,EAAA;AACA,EAAA;AACA,EAAA;AACP,EAAA;AACc,EAAA;AACN,EAAA;AACrB,IAAA;AACY,MAAA;AACR,IAAA;AAER,IAAA;AACD,EAAA;AACO,EAAA;AACR;AAQoC;AACrB,EAAA;AACc,EAAA;AACN,IAAA;AACG,IAAA;AACF,IAAA;AACI,IAAA;AAC3B,EAAA;AACoC,EAAA;AACT,EAAA;AACJ,IAAA;AACvB,EAAA;AACO,EAAA;AACR;AAIC;AAGkB,EAAA;AACU,EAAA;AACL,EAAA;AACV,IAAA;AAAA,gCAAA;AACa,IAAA;AACL,MAAA;AACG,MAAA;AACvB,IAAA;AACD,EAAA;AACO,EAAA;AACR;AZynC8B;AACA;AGzwCuB;AACrB,EAAA;AACxB,IAAA;AACG,IAAA;AACG,IAAA;AACJ,IAAA;AACH,IAAA;AACG,IAAA;AACD,IAAA;AACD,IAAA;AACP,EAAA;AAEyB,EAAA;AACD,IAAA;AACV,IAAA;AACP,MAAA;AACW,QAAA;AACD,QAAA;AACd,QAAA;AACI,MAAA;AACc,QAAA;AACJ,QAAA;AACd,QAAA;AACI,MAAA;AACiB,QAAA;AACP,QAAA;AACd,QAAA;AACI,MAAA;AACa,QAAA;AACH,QAAA;AACd,QAAA;AACI,MAAA;AACa,QAAA;AACjB,QAAA;AACI,MAAA;AACY,QAAA;AAChB,QAAA;AACI,MAAA;AACW,QAAA;AACf,QAAA;AACI,MAAA;AACkB,QAAA;AACtB,QAAA;AACA,QAAA;AACI,MAAA;AACU,QAAA;AACd,QAAA;AACI,MAAA;AACU,QAAA;AACd,QAAA;AACI,MAAA;AACU,QAAA;AACd,QAAA;AACF,IAAA;AACD,EAAA;AAGkB,EAAA;AACV,IAAA;AACR,EAAA;AAGO,EAAA;AACA,IAAA;AACG,IAAA;AACG,IAAA;AACJ,IAAA;AACH,IAAA;AACW,IAAA;AACD,IAAA;AACD,IAAA;AACE,IAAA;AACH,IAAA;AACd,EAAA;AACD;AAEoC;AACnB,EAAA;AACG,EAAA;AACQ,EAAA;AACJ,EAAA;AAED,EAAA;AACG,EAAA;AACFD,EAAAA;AACC,EAAA;AAGG,EAAA;AACRC,EAAAA;AACGA,EAAAA;AACJA,EAAAA;AAII,EAAA;AACH,EAAA;AACM,IAAA;AACP,MAAA;AACDC,MAAAA;AAEE,MAAA;AAGN,QAAA;AACV,QAAA;AACD,MAAA;AACD,IAAA;AACD,EAAA;AAMwB,EAAA;AAClB,EAAA;AAEiB,EAAA;AACX,EAAA;AAA+B;AAA6C;AAGnE,EAAA;AACK,IAAA;AACT,MAAA;AAChB,IAAA;AACD,EAAA;AAE2B,EAAA;AACO,EAAA;AACF,EAAA;AAI/B,EAAA;AAIoB,IAAA;AACH,MAAA;AACH,MAAA;AACD,MAAA;AAAqB,YAAA;AACd,MAAA;AACP,MAAA;AAA8B;AAC1C,MAAA;AACD,IAAA;AACyB,IAAA;AACL,MAAA;AACD,MAAA;AACM,MAAA;AAClB,IAAA;AACY,MAAA;AACnB,IAAA;AACD,EAAA;AAEkB,EAAA;AACX,IAAA;AACL,MAAA;AACC,QAAA;AACM,QAAA;AACN,QAAA;AACD,MAAA;AACD,IAAA;AACD,EAAA;AAEqB,EAAA;AACd,IAAA;AACL,MAAA;AACC,QAAA;AAEiB,QAAA;AACT,UAAA;AACN,QAAA;AACF,QAAA;AACD,MAAA;AACD,IAAA;AACD,EAAA;AAEwB,EAAA;AACjB,IAAA;AACL,MAAA;AACC,QAAA;AAEC,QAAA;AACO,UAAA;AACN,QAAA;AACF,QAAA;AACD,MAAA;AACD,IAAA;AACD,EAAA;AAEoB,EAAA;AAEa,IAAA;AACZ,IAAA;AACA,MAAA;AACG,MAAA;AAChB,IAAA;AACe,MAAA;AACP,MAAA;AACH,MAAA;AACC,QAAA;AACZ,MAAA;AACD,IAAA;AACqB,IAAA;AACC,MAAA;AACb,QAAA;AACP,MAAA;AACW,MAAA;AACE,QAAA;AACO,QAAA;AACd,MAAA;AACO,QAAA;AACd,MAAA;AACM,IAAA;AACO,MAAA;AACd,IAAA;AACD,EAAA;AAGuB,EAAA;AAIC,EAAA;AACJ,EAAA;AACI,IAAA;AACA,IAAA;AACX,IAAA;AACS,IAAA;AACtB,EAAA;AACoB,EAAA;AACN,IAAA;AACS,EAAA;AACH,IAAA;AACN,IAAA;AACO,IAAA;AACd,EAAA;AACiBA,IAAAA;AACR,IAAA;AAGQ,IAAA;AACb,MAAA;AACR,QAAA;AACkB,QAAA;AAA+B;AAAA;AAClD,MAAA;AACa,MAAA;AACO,MAAA;AACd,IAAA;AACO,MAAA;AACd,IAAA;AACD,EAAA;AAG4B,EAAA;AACP,IAAA;AACX,MAAA;AACP,QAAA;AACD,MAAA;AACD,IAAA;AACD,EAAA;AAGkB,EAAA;AACA,EAAA;AACDD,EAAAA;AACKC,IAAAA;AACK,IAAA;AACD,IAAA;AAIJ,IAAA;AAGC,IAAA;AACD,IAAA;AACH,IAAA;AAEI,IAAA;AACD,IAAA;AACH,IAAA;AAEM,IAAA;AACJ,IAAA;AACC,MAAA;AACT,IAAA;AACS,MAAA;AACT,IAAA;AACS,MAAA;AACrB,IAAA;AAEwB,IAAA;AACT,MAAA;AAGc,MAAA;AAEV,MAAA;AAIX,QAAA;AACD,QAAA;AAEc,UAAA;AACjB,YAAA;AACS,YAAA;AACI,cAAA;AACL,cAAA;AACR,YAAA;AACD,UAAA;AACD,QAAA;AAGU,QAAA;AAGW,QAAA;AACD,QAAA;AAEF,UAAA;AACF,UAAA;AACG,UAAA;AACZ,QAAA;AAEA,UAAA;AACc,UAAA;AACJ,YAAA;AAChB,UAAA;AACc,UAAA;AACf,QAAA;AAGM,QAAA;AACD,QAAA;AACU,UAAA;AACf,QAAA;AACM,MAAA;AAEI,QAAA;AACX,MAAA;AAGoB,MAAA;AACD,MAAA;AACE,MAAA;AAEH,QAAA;AACF,QAAA;AACG,QAAA;AACR,MAAA;AAEQ,QAAA;AACjB,UAAA;AACA,UAAA;AACD,QAAA;AACM,MAAA;AACQ,QAAA;AACf,MAAA;AAGsB,MAAA;AACH,QAAA;AAEjB,QAAA;AAIQ,QAAA;AAKV,MAAA;AAIkB,MAAA;AACX,QAAA;AACD,QAAA;AACY,UAAA;AACA,UAAA;AAEN,YAAA;AAGH,UAAA;AAGY,YAAA;AAEjB,YAAA;AAKQ,YAAA;AAIV,UAAA;AACD,QAAA;AACD,MAAA;AAEQ,MAAA;AAEJ,QAAA;AAEJ,MAAA;AAEmB,MAAA;AACb,IAAA;AACW,MAAA;AACT,MAAA;AACM,QAAA;AACd,MAAA;AACD,IAAA;AACD,EAAA;AAGuB,EAAA;AACF,IAAA;AACrB,EAAA;AAGoB,EAAA;AACC,EAAA;AACK,IAAA;AAC1B,EAAA;AAEoB,EAAA;AACP,IAAA;AAAA;AAAiE;AACvE,EAAA;AACM,IAAA;AAAA;AAAA;AAGb;AACA,EAAA;AACD;AHoqC8B;AACA;AapoDL;AAChBD;AACY;AACZ;AbsoDqB;AACA;Ac1oDrBA;AACM;AACA;AAGqB;AACR,EAAA;AACf,EAAA;AAEc,EAAA;AAED,EAAA;AAChB,IAAA;AACP,MAAA;AACD,IAAA;AACA,IAAA;AACD,EAAA;AAEuB,EAAA;AACG,EAAA;AACF,IAAA;AACxB,EAAA;AAE2B,EAAA;AACd,IAAA;AACZ,IAAA;AACD,EAAA;AAIC,EAAA;AACG;AACA;AAEH,EAAA;AAA4B,gCAAA;AAGJ,EAAA;AAChB;AAAA;AAAA;AAAA;AAAA;AAMN,IAAA;AACc,IAAA;AAAA,wCAAA;AAES,wBAAA;AACH,qBAAA;AAAA;AAAA,KAAA;AAIN,EAAA;AAAA;AAAA,6DAAA;AAEgD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWzC,EAAA;AACL,EAAA;AAEf,EAAA;AACc,IAAA;AACC,MAAA;AACE,MAAA;AACnB,IAAA;AAEwB,IAAA;AACV,MAAA;AACf,IAAA;AACC,EAAA;AAEwB,IAAA;AACR,MAAA;AACjB,IAAA;AACD,EAAA;AACD;Ad2nD8B;AACA;AatsDG;AACpB,EAAA;AACC,IAAA;AACZ,IAAA;AACD,EAAA;AAC4B,EAAA;AACxB,EAAA;AACoB,IAAA;AAChB,EAAA;AAEY,IAAA;AACpB,EAAA;AACD;AAEuB;AACK,EAAA;AACPK,EAAAA;AACI,IAAA;AACb,MAAA;AACM,MAAA;AACf,IAAA;AACD,EAAA;AACF;AAEuB;AACI,EAAA;AACJ,EAAA;AACvB;AAEwB;AACkB,EAAA;AAC/B,IAAA;AACH,IAAA;AACC,IAAA;AACC,IAAA;AACE,IAAA;AACF,IAAA;AACT,EAAA;AACwB,EAAA;AACF,EAAA;AACvB;AAEwB;AACkB,EAAA;AAC/B,IAAA;AACH,IAAA;AACC,IAAA;AACG,IAAA;AACF,IAAA;AACA,IAAA;AACT,EAAA;AACwB,EAAA;AACF,EAAA;AACvB;AAE4B;AACf,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBZ;AACD;AAE2C;AAOjB;AACAL,EAAAA;AACrB,EAAA;AACoBC,IAAAA;AAGJ,IAAA;AACZ,EAAA;AACA,IAAA;AACR,EAAA;AACD;AAEgC;AACN,EAAA;AAER,EAAA;AACL,IAAA;AACX,IAAA;AACD,EAAA;AAEoC,EAAA;AACR,EAAA;AACb,IAAA;AACH,IAAA;AACQ,IAAA;AACnB,IAAA;AACD,EAAA;AAE4B,EAAA;AAClB,EAAA;AACK,IAAA;AACA,IAAA;AACA,IAAA;AACK,IAAA;AACnB,IAAA;AACD,EAAA;AAEoB,EAAA;AACQ,EAAA;AAEhB,EAAA;AAIO,EAAA;AACGF,IAAAA;AACN,IAAA;AACF,MAAA;AACH,QAAA;AACP,UAAA;AACD,QAAA;AACA,QAAA;AACD,MAAA;AACuB,MAAA;AACvB,MAAA;AACD,IAAA;AACD,EAAA;AAGyB,EAAA;AACA,IAAA;AACvB,MAAA;AACD,IAAA;AACgB,IAAA;AACH,MAAA;AACZ,MAAA;AACD,IAAA;AACD,EAAA;AAEa,EAAA;AACP,IAAA;AACU,MAAA;AACd,MAAA;AACI,IAAA;AACW,MAAA;AACf,MAAA;AACI,IAAA;AACW,MAAA;AACf,MAAA;AACF,EAAA;AACD;Ab6qD8B;AACA;Aej2DrBM;AACqB;AAGN;AACP,EAAA;AACV,IAAA;AAAc,MAAA;AAAA;AACd,IAAA;AAAe,MAAA;AAAA;AACf,IAAA;AAAc,MAAA;AAAA;AACd,IAAA;AAAgB,MAAA;AAAA;AAChB,IAAA;AAAiB,MAAA;AAAA;AACjB,IAAA;AAAkB,MAAA;AAAA;AAClB,IAAA;AAAe,MAAA;AAAA;AACpB,IAAA;AAAgB,MAAA;AACjB,EAAA;AACD;AAEyB;AACC,EAAA;AACZ,IAAA;AACZ,IAAA;AACD,EAAA;AAGyB,EAAA;AACE,EAAA;AACF,EAAA;AACV,IAAA;AACU,IAAA;AACvB,EAAA;AACwB,EAAA;AAGX,EAAA;AACE,IAAA;AACO,IAAA;AACF,IAAA;AACJ,IAAA;AACN,EAAA;AAEM,EAAA;AACN,IAAA;AACS,IAAA;AACF,IAAA;AACP,IAAA;AACA,EAAA;AAEgB,EAAA;AACP,EAAA;AAGO,EAAA;AACP,IAAA;AACC,IAAA;AACK,IAAA;AAEd,IAAA;AACY,MAAA;AACL,MAAA;AACC,MAAA;AACD,MAAA;AACP,IAAA;AAEG,IAAA;AAChB,EAAA;AAGY,EAAA;AAA0B,QAAA;AACvC;AAE4B;AACc,EAAA;AACb,EAAA;AACT,IAAA;AACE,IAAA;AACI,IAAA;AACzB,EAAA;AAE4B,EAAA;AACH,EAAA;AAEb,EAAA;AAA6B,yBAAA;AACpB,EAAA;AACG,IAAA;AACA,IAAA;AACxB,EAAA;AACD;AAEsB;AACA,EAAA;AACK,EAAA;AAGE,EAAA;AAEhB,EAAA;AACG,IAAA;AACK,IAAA;AACnB,IAAA;AACD,EAAA;AAC0B,EAAA;AAEtB,EAAA;AAEa,IAAA;AACS,IAAA;AAGV,IAAA;AACQ,IAAA;AACZ,MAAA;AACJ,IAAA;AAEY,MAAA;AACG,QAAA;AACN,UAAA;AACb,UAAA;AACD,QAAA;AACD,MAAA;AACD,IAAA;AAEU,IAAA;AACK,MAAA;AACK,MAAA;AACnB,MAAA;AACD,IAAA;AAEmB,IAAA;AAEP,IAAA;AACM,MAAA;AACX,IAAA;AACgB,MAAA;AACH,MAAA;AACpB,IAAA;AACkB,EAAA;AACJ,IAAA;AACC,IAAA;AACA,MAAA;AACf,IAAA;AACmB,IAAA;AACpB,EAAA;AACD;Afs1D8B;AACA;AgBr+DrBA;AhBu+DqB;AACA;AiBx+DrBL;AACAD;AAGkB;AAGwC;AAC3C,EAAA;AACiB,EAAA;AAClBE,EAAAA;AACK,IAAA;AACR,IAAA;AACI,IAAA;AACG,IAAA;AACZ,IAAA;AACa,IAAA;AAChB,IAAA;AACgB,IAAA;AAGvB,IAAA;AAGqB,MAAA;AACxB,IAAA;AACc,IAAA;AACf,EAAA;AACO,EAAA;AACR;AAQqD;AACZ,EAAA;AACrB,EAAA;AACI,IAAA;AACvB,EAAA;AACuB,EAAA;AACxB;AASC;AAKqC,EAAA;AACV,EAAA;AACG,IAAA;AAC9B,EAAA;AAC2B,EAAA;AACF,EAAA;AAClB,EAAA;AACR;AAE0B;AACH,EAAA;AACjB,IAAA;AACkB,MAAA;AACd,IAAA;AACA,MAAA;AACR,IAAA;AACU,EAAA;AACZ;AAU2C;AACtC,EAAA;AACY,EAAA;AAEmB,EAAA;AACV,IAAA;AACC,IAAA;AAChB,MAAA;AACI,MAAA;AACC,MAAA;AACR,IAAA;AACP,EAAA;AAEI,EAAA;AACA,EAAA;AACmB,IAAA;AACG,MAAA;AACX,MAAA;AACF,MAAA;AACG,QAAA;AACA,QAAA;AACD,QAAA;AACG,QAAA;AACf,QAAA;AACD,MAAA;AACa,MAAA;AACb,IAAA;AACM,EAAA;AAEM,IAAA;AAAC,IAAA;AACf,EAAA;AAEa,EAAA;AACY,IAAA;AACV,IAAA;AACf,EAAA;AACD;AjBk8D8B;AACA;AgBvjEG;AACT,EAAA;AACC,EAAA;AAEE,EAAA;AAGE,EAAA;AAEhB,EAAA;AACG,IAAA;AACK,IAAA;AACnB,IAAA;AACD,EAAA;AAC0B,EAAA;AAGD,EAAA;AAIrB,EAAA;AACU,EAAA;AACD,IAAA;AACR,IAAA;AAEqB,MAAA;AAEG,MAAA;AACJ,QAAA;AACD,QAAA;AACrB,MAAA;AACiB,IAAA;AACD,MAAA;AACF,QAAA;AACA,QAAA;AACK,QAAA;AACnB,QAAA;AACD,MAAA;AACM,MAAA;AACP,IAAA;AACD,EAAA;AAKc,EAAA;AACgD,EAAA;AACnC,IAAA;AACf,MAAA;AACJ,MAAA;AACN,IAAA;AACuB,IAAA;AACjB,IAAA;AACR,EAAA;AAEqB,EAAA;AAEA,IAAA;AACnB,IAAA;AACK,IAAA;AACL,EAAA;AAEqB,EAAA;AAGA,EAAA;AACF,EAAA;AACE,IAAA;AACH,IAAA;AACP,IAAA;AACF,IAAA;AACV,EAAA;AAEiB,EAAA;AACR,IAAA;AACG,MAAA;AACY,MAAA;AACJ,MAAA;AACL,MAAA;AACF,MAAA;AACO,MAAA;AACpB,IAAA;AACD,EAAA;AAIiB,EAAA;AACH,IAAA;AACH,IAAA;AACe,IAAA;AACX,IAAA;AACf,EAAA;AAC2B,EAAA;AACZ,IAAA;AACd,EAAA;AAC2B,EAAA;AACb,IAAA;AACd,EAAA;AACwB,EAAA;AACX,IAAA;AACH,IAAA;AACV,EAAA;AAEW,EAAA;AACC,IAAA;AACA,IAAA;AACA,IAAA;AAAA;AAA4B;AAExB,IAAA;AACG,IAAA;AACb,EAAA;AACM,IAAA;AAAiD;AACjD,IAAA;AACA,IAAA;AAAA;AAA4B;AAExB,IAAA;AACH,IAAA;AACd,EAAA;AACD;AhBmiE8B;AACA;AkB/pErBD;AACM;AACNM;AACAC;AAEqB;AAET;AACAF,EAAAA;AACRE,IAAAA;AACK,MAAA;AACC,MAAA;AAChB,IAAA;AAEsB,IAAA;AACb,MAAA;AACU,MAAA;AACI,MAAA;AACA,MAAA;AACvB,IAAA;AACD,EAAA;AACF;AAEiD;AAC3C,EAAA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACC,EAAA;AACF,EAAA;AACP;AAEqB;AACf,EAAA;AACK,IAAA;AACG,IAAA;AACG,IAAA;AAChB,EAAA;AACO,EAAA;AACS,IAAA;AACE,IAAA;AAClB,EAAA;AACW,EAAA;AACD,IAAA;AACI,IAAA;AACA,IAAA;AACF,IAAA;AACC,IAAA;AACb,EAAA;AACQ,EAAA;AACE,IAAA;AACF,IAAA;AACE,MAAA;AACK,MAAA;AACK,QAAA;AACT,UAAA;AACF,UAAA;AACN,QAAA;AACD,MAAA;AACY,MAAA;AACI,QAAA;AAChB,MAAA;AACD,IAAA;AACD,EAAA;AACY,EAAA;AACA,IAAA;AACE,MAAA;AACI,MAAA;AACjB,IAAA;AACD,EAAA;AACD;AAG0B;AACR,EAAA;AAAA;AAEF,IAAA;AACN,IAAA;AACA,IAAA;AACS,IAAA;AACZ,IAAA;AACI,IAAA;AACY,IAAA;AAAA;AAGH,IAAA;AAClB,IAAA;AACsB,IAAA;AACd,IAAA;AAAA;AAGA,IAAA;AACkB,IAAA;AAC1B,IAAA;AACoB,IAAA;AACpB,IAAA;AACiB,IAAA;AACH,IAAA;AAAA;AAGP,IAAA;AACW,MAAA;AAClB,IAAA;AACD,EAAA;AACoB,EAAA;AACM,EAAA;AAC3B;AAEwB;AACA,EAAA;AACI,EAAA;AACC,EAAA;AACJ,IAAA;AACvB,IAAA;AACD,EAAA;AACgB,EAAA;AACf,IAAA;AACD,EAAA;AACgB,EAAA;AACf,IAAA;AACD,EAAA;AACqB,EAAA;AACpB,IAAA;AACD,EAAA;AACU,EAAA;AACT,IAAA;AACD,EAAA;AACW,EAAA;AACV,IAAA;AACD,EAAA;AACU,EAAA;AACT,IAAA;AACD,EAAA;AACS,EAAA;AACR,IAAA;AACD,EAAA;AACD;AAEuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWoB;AAEtBR,EAAAA;AACpB,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACD,EAAA;AACe,EAAA;AAGX,EAAA;AAEqB,IAAA;AACD,IAAA;AACA,IAAA;AACC,IAAA;AACjB,EAAA;AAER,EAAA;AAEO,EAAA;AACR;AAEqB;AACA,EAAA;AAEF,EAAA;AACT,IAAA;AACP,MAAA;AACD,IAAA;AACO,IAAA;AACR,EAAA;AAEsB,EAAA;AACC,EAAA;AAEC,EAAA;AACD,IAAA;AACvB,EAAA;AAEyBE,EAAAA;AACb,EAAA;AACL,EAAA;AACR;AAE2B;AACL,EAAA;AAEjB,EAAA;AACqB,EAAA;AACPA,IAAAA;AACX,EAAA;AACa,IAAA;AACO,IAAA;AAC3B,EAAA;AAEsB,EAAA;AAEV,EAAA;AACe,EAAA;AACH,IAAA;AACH,MAAA;AACnB,MAAA;AACD,IAAA;AACD,EAAA;AAEiB,EAAA;AACJ,IAAA;AACL,IAAA;AACR,EAAA;AAE4B,EAAA;AAChB,EAAA;AACL,EAAA;AACR;AAE2B;AAEN,EAAA;AACrB;AAEuB;AACI,EAAA;AAEX,EAAA;AAEW,IAAA;AACH,IAAA;AACR,IAAA;AACA,IAAA;AACJ,MAAA;AACK,MAAA;AACF,MAAA;AACL,MAAA;AACR,IAAA;AACc,IAAA;AACJ,MAAA;AACK,MAAA;AACF,MAAA;AACL,MAAA;AACR,IAAA;AACY,IAAA;AACL,IAAA;AACR,EAAA;AAG4B,EAAA;AAChB,EAAA;AACL,EAAA;AACR;AAEoB;AACI,EAAA;AAEC,EAAA;AACX,IAAA;AACL,IAAA;AACR,EAAA;AAGqB,EAAA;AACF,EAAA;AACM,EAAA;AACDA,IAAAA;AACP,IAAA;AACR,MAAA;AACA,MAAA;AACR,IAAA;AACwB,IAAA;AACzB,EAAA;AAEkB,EAAA;AACL,IAAA;AACR,IAAA;AACM,MAAA;AACH,QAAA;AACE,QAAA;AACP,MAAA;AACW,MAAA;AACL,IAAA;AACC,MAAA;AACP,QAAA;AACD,MAAA;AACD,IAAA;AACD,EAAA;AAEyB,EAAA;AACb,EAAA;AACL,EAAA;AACR;AAEyB;AACJ,EAAA;AACG,EAAA;AAEC,EAAA;AACX,IAAA;AACL,IAAA;AACR,EAAA;AAEyB,EAAA;AACJ,IAAA;AACrB,EAAA;AAEyB,EAAA;AACb,EAAA;AACL,EAAA;AACR;AAEyB;AACJ,EAAA;AACG,EAAA;AAEC,EAAA;AACX,IAAA;AACL,IAAA;AACR,EAAA;AAEyB,EAAA;AACJ,IAAA;AACrB,EAAA;AAEyB,EAAA;AACb,EAAA;AACL,EAAA;AACR;AAEqB;AACG,EAAA;AACG,EAAA;AAEX,EAAA;AACF,IAAA;AACL,IAAA;AACR,EAAA;AAEyB,EAAA;AACD,IAAA;AACxB,EAAA;AAE4B,EAAA;AAChB,EAAA;AACL,EAAA;AACR;AAEoB;AAAA;AAAA;AAAA;AAAA;AAMQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcC;AACnB,EAAA;AACE,EAAA;AACC,EAAA;AACb;AAE2B;AAAA;AAAA;AAAA;AAAA;AAMD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkCE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASL;AACF,EAAA;AACEF,EAAAA;AACT,EAAA;AAEY,EAAA;AACF,IAAA;AACX,IAAA;AACF,IAAA;AACJ,EAAA;AACM,IAAA;AACb,EAAA;AAEgB,EAAA;AACD,IAAA;AACF,IAAA;AACF,IAAA;AACJ,EAAA;AACM,IAAA;AACb,EAAA;AAEO,EAAA;AACR;AAEyB;AACFA,EAAAA;AAEP,EAAA;AACF,IAAA;AACL,IAAA;AACR,EAAA;AAEc,EAAA;AACF,EAAA;AACL,EAAA;AACR;AAE0B;AACD,EAAA;AAEC,EAAA;AACZ,IAAA;AACL,IAAA;AACR,EAAA;AAE0B,EAAA;AACd,EAAA;AAGW,EAAA;AACE,EAAA;AACD,IAAA;AACJ,IAAA;AACpB,EAAA;AAEO,EAAA;AACR;AAE4B;AACH,EAAA;AAEC,EAAA;AACZ,IAAA;AACL,IAAA;AACR,EAAA;AAE0B,EAAA;AACd,EAAA;AACL,EAAA;AACR;AAEyB;AACH,EAAA;AACK,EAAA;AAEHE,EAAAA;AACE,EAAA;AAED,EAAA;AACL,IAAA;AACK,IAAA;AACX,IAAA;AACL,IAAA;AACR,EAAA;AAEO,EAAA;AACR;AAE0B;AACFF,EAAAA;AACEA,EAAAA;AAEX,EAAA;AAEE,EAAA;AACD,IAAA;AACF,IAAA;AACF,IAAA;AACJ,EAAA;AACM,IAAA;AACb,EAAA;AAEgB,EAAA;AACD,IAAA;AACF,IAAA;AACF,IAAA;AACJ,EAAA;AACM,IAAA;AACb,EAAA;AAEO,EAAA;AACR;AAEoC;AACP,EAAA;AAEL,EAAA;AACL,EAAA;AACO,EAAA;AACH,EAAA;AACC,EAAA;AACI,EAAA;AACA,EAAA;AACD,EAAA;AACC,EAAA;AACA,EAAA;AAEH,EAAA;AACE,EAAA;AACX,IAAA;AACU,IAAA;AACvB,MAAA;AACA,MAAA;AACD,IAAA;AACe,IAAA;AACG,MAAA;AAClB,IAAA;AACM,EAAA;AACM,IAAA;AACb,EAAA;AAEmB,EAAA;AAEIA,EAAAA;AACP,EAAA;AACD,IAAA;AACU,IAAA;AACvB,MAAA;AACA,MAAA;AACD,IAAA;AACe,IAAA;AACG,MAAA;AAClB,IAAA;AACM,EAAA;AACM,IAAA;AACb,EAAA;AACD;AlBokE8B;AACA;AmBzrFrBS;AACAH;AAGa;AACT,EAAA;AAGA,EAAA;AAEc,EAAA;AAEtB,EAAA;AACS,IAAA;AAEU,IAAA;AACF,IAAA;AAEF,IAAA;AACP,MAAA;AACT,QAAA;AACD,MAAA;AACD,IAAA;AAEmB,IAAA;AAEF,IAAA;AACH,MAAA;AACM,MAAA;AACE,MAAA;AACR,MAAA;AACb,IAAA;AAEc,IAAA;AACN,MAAA;AACP,QAAA;AACD,MAAA;AACc,MAAA;AACf,IAAA;AAGwB,IAAA;AACH,IAAA;AAEDA,IAAAA;AACN,IAAA;AACN,IAAA;AACP,MAAA;AACD,IAAA;AAEc,IAAA;AACC,EAAA;AACD,IAAA;AACK,IAAA;AACL,IAAA;AACf,EAAA;AACD;AnB4qF8B;AACA;AoBruFrBL;AACM;AAmBN;AAMc,EAAA;AACM,EAAA;AAEhB,EAAA;AAER;AAAA;AAAA;AAAA,mCAAA;AAQsB,EAAA;AACN,IAAA;AACZ,IAAA;AACN,MAAA;AACU,MAAA;AACV,MAAA;AACD,IAAA;AACD,EAAA;AAEyB,EAAA;AAEhB,EAAA;AACoD;AACpC,EAAA;AAClB,EAAA;AACM,IAAA;AACZ,IAAA;AACA,IAAA;AACD,EAAA;AACD;AAEsB;AAIK,EAAA;AACH,EAAA;AACH,EAAA;AACK,EAAA;AACA,IAAA;AACA,IAAA;AACtB,EAAA;AAGwB,EAAA;AAGD,EAAA;AACV,IAAA;AACQ,MAAA;AACvB,IAAA;AACY,IAAA;AACb,EAAA;AAGe,EAAA;AACQ,EAAA;AACW,EAAA;AAGN,EAAA;AACd,EAAA;AAEI,EAAA;AACE,EAAA;AACnB,IAAA;AACA,IAAA;AACM,IAAA;AACqB,EAAA;AACT,EAAA;AAAsB;AAElB,aAAA;AACZ;AAAA;AAEO;AAAmB;AAAS;AAE1B,EAAA;AACE,EAAA;AAER,EAAA;AACD,IAAA;AAAA,sCAAA;AACa,IAAA;AACb,IAAA;AACO,IAAA;AACnB,IAAA;AACD,EAAA;AAGuB,EAAA;AACd,IAAA;AACP,MAAA;AACD,IAAA;AACmB,IAAA;AACnB,IAAA;AACD,EAAA;AAGwB,EAAA;AACH,EAAA;AACZ,IAAA;AACP,MAAA;AACD,IAAA;AACD,EAAA;AACY,EAAA;AAGA,EAAA;AAAyB,qBAAA;AAC7B,EAAA;AACgB,IAAA;AACxB,EAAA;AACc,EAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACb;ApBurF8B;AACA;AqBv0FrBA;AACM;AACND;AAImB;AACpB,EAAA;AAAA;AAEiB,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYzB;AAEsB;AACF,EAAA;AACE,EAAA;AACD,EAAA;AACR,EAAA;AAAgC,iBAAA;AAAsD;AAE3E,EAAA;AAEP,EAAA;AACH,IAAA;AACC,MAAA;AACN,IAAA;AACS,MAAA;AAChB,IAAA;AACD,EAAA;AAEsB,EAAA;AAEC,EAAA;AACd,IAAA;AACP,MAAA;AACD,IAAA;AACmB,IAAA;AACnB,IAAA;AACD,EAAA;AAEgB,EAAA;AAEJ,EAAA;AACC,IAAA;AACA,IAAA;AAAA;AAA8C;AACvC,IAAA;AACnB,IAAA;AACD,EAAA;AAEmB,EAAA;AAEE,EAAA;AACR,IAAA;AACb,EAAA;AAEY,EAAA;AAEA,EAAA;AAAA;AAAA;AAGU,qBAAA;AAAU;AAAA;AAGH,kBAAA;AAAA;AAE7B;AACD;ArB+zF8B;AACA;AsB34FrBC;AACM;AACND;AAMqB;AACZ,EAAA;AACG,EAAA;AACJ,EAAA;AACR,IAAA;AACY,SAAA;AAA0C;AAEnC,0BAAA;AACH,uBAAA;AAAU;AAEP,gBAAA;AACH,eAAA;AAAA;AAEN,sBAAA;AAAU;AAAA;AAG5B,EAAA;AACO,EAAA;AAAA;AAEoB,0BAAA;AACH,uBAAA;AAAU;AAAA;AAGP,kBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOT,sBAAA;AAAU;AAAA;AAG7B;AAES;AACQ,EAAA;AACR,IAAA;AACM,SAAA;AACM,SAAA;AAAgD;AAEzC,0BAAA;AACH,uBAAA;AAAU;AAEP,gBAAA;AACJ,kBAAA;AAAA;AAEL,sBAAA;AAAU;AAAA;AAG5B,EAAA;AACO,EAAA;AACO,SAAA;AAAA;AAEa,0BAAA;AACH,uBAAA;AAAU;AAAA;AAGR,qBAAA;AAAA;AAAA;AAAA;AAAA;AAKR,sBAAA;AAAU;AAAA;AAG7B;AAES;AACQ,EAAA;AACR,IAAA;AACY,SAAA;AACA,SAAA;AAAgD;AAEzC,0BAAA;AACH,uBAAA;AAAU;AAAA,2CAAA;AAGP,gBAAA;AAAA;AAAA;AAGT,sBAAA;AAAU;AAAA;AAG5B,EAAA;AACO,EAAA;AACa,SAAA;AAAqC;AAE9B,0BAAA;AACH,uBAAA;AAAU;AAAA,2CAAA;AAEoB;AAAA;AAAA;AAAA;AAAA;AAMpC,sBAAA;AAAU;AAAA;AAG7B;AAEsC;AACxB,EAAA;AACP,IAAA;AACG,MAAA;AACH,IAAA;AACG,MAAA;AACH,IAAA;AACL,IAAA;AACQ,MAAA;AACT,EAAA;AACD;AAEsB;AACF,EAAA;AACG,EAAA;AACG,EAAA;AACJ,EAAA;AACD,EAAA;AACR,EAAA;AAAA,+BAAA;AAA4I;AAEtI,EAAA;AAEO,EAAA;AACZ,IAAA;AACC,MAAA;AACN,IAAA;AACS,MAAA;AAChB,IAAA;AACD,EAAA;AAEsB,EAAA;AAEC,EAAA;AACd,IAAA;AACP,MAAA;AACD,IAAA;AACmB,IAAA;AACnB,IAAA;AACD,EAAA;AAEgB,EAAA;AAEJ,EAAA;AACC,IAAA;AACA,IAAA;AAAA;AAA8C;AACvC,IAAA;AACnB,IAAA;AACD,EAAA;AAEmB,EAAA;AAEE,EAAA;AACZ,IAAA;AACP,MAAA;AACD,IAAA;AACD,EAAA;AAEY,EAAA;AAEI,EAAA;AAEK,IAAA;AACJ,IAAA;AACP,MAAA;AACP,QAAA;AAAA,6BAAA;AACD,MAAA;AACM,MAAA;AACP,IAAA;AACD,EAAA;AACD;AtB83F8B;AACA;AuBljGrBC;AACM;AACND;AAYR;AAGyB,EAAA;AAEtB;AACoB,EAAA;AAIC,EAAA;AAChB,IAAA;AACY,SAAA;AAAyC;AAExC,UAAA;AACK,eAAA;AAAA;AAAA;AAGG,kBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoB7B,EAAA;AAEO,EAAA;AACa,SAAA;AACT;AACU,UAAA;AACK,eAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uEAAA;AAOwD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQrD,kBAAA;AAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAAA;AAgBW;AAAA;AAAA;AAAA;AAAA;AAAA;AAO5D;AAEsB;AACF,EAAA;AACE,EAAA;AACD,EAAA;AACR,EAAA;AAAA,kCAAA;AAA4F;AAG/E,EAAA;AACH,EAAA;AACHC,EAAAA;AACHA,EAAAA;AAEC,EAAA;AACR,IAAA;AACP,MAAA;AACD,IAAA;AACQ,IAAA;AACP,MAAA;AACD,IAAA;AACmB,IAAA;AACnB,IAAA;AACD,EAAA;AAE4BS,EAAAA;AACH,EAAA;AACX,IAAA;AACA,IAAA;AACd,EAAA;AAEiB,EAAA;AAEO,EAAA;AACX,IAAA;AACC,MAAA;AACN,IAAA;AACS,MAAA;AAChB,IAAA;AACD,EAAA;AAEsB,EAAA;AAEC,EAAA;AACd,IAAA;AACP,MAAA;AACD,IAAA;AACmB,IAAA;AACnB,IAAA;AACD,EAAA;AAEgB,EAAA;AAEJ,EAAA;AACC,IAAA;AACA,IAAA;AAAA;AAA8C;AACvC,IAAA;AACnB,IAAA;AACD,EAAA;AAEmB,EAAA;AAEE,EAAA;AACZ,IAAA;AACP,MAAA;AACD,IAAA;AACD,EAAA;AAEY,EAAA;AAEA,EAAA;AAAA;AAAA;AAAA;AAAA;AAKZ;AACD;AvBuhG8B;AACA;AwBpsGrBT;AACM;AACND;AAIgB;AACG,EAAA;AACpB,EAAA;AAAA;AAAA;AAGc,UAAA;AAAA,0CAAA;AAC2B,yCAAA;AACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAAA;AAUH,yCAAA;AACG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CAAA;AAaC,yCAAA;AACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQhD;AAEsB;AACF,EAAA;AACE,EAAA;AACD,EAAA;AACZ,EAAA;AACP,IAAA;AAAA,iCAAA;AAAiF;AAClF,EAAA;AAEiB,EAAA;AAEO,EAAA;AACX,IAAA;AACC,MAAA;AACN,IAAA;AACS,MAAA;AAChB,IAAA;AACD,EAAA;AAEsB,EAAA;AAEC,EAAA;AACd,IAAA;AACP,MAAA;AACD,IAAA;AACmB,IAAA;AACnB,IAAA;AACD,EAAA;AAEgB,EAAA;AAEJ,EAAA;AACC,IAAA;AACA,IAAA;AAAA;AAA8C;AACvC,IAAA;AACnB,IAAA;AACD,EAAA;AAEmB,EAAA;AAEE,EAAA;AACZ,IAAA;AACP,MAAA;AACD,IAAA;AACD,EAAA;AAEY,EAAA;AAEA,EAAA;AAAA;AAAA;AAAA;AAIZ;AACD;AxB4rG8B;AACA;AyBhxGP;AACV,EAAA;AACW,sBAAA;AACvB;AACD;AAEsB;AACT,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiEZ;AACD;AAE6B;AACF,EAAA;AACJ,EAAA;AACH,EAAA;AAEL,EAAA;AACD,IAAA;AACD,IAAA;AACQ,IAAA;AACnB,IAAA;AACD,EAAA;AAEiB,EAAA;AACX,IAAA;AACc,MAAA;AAClB,MAAA;AACI,IAAA;AACe,MAAA;AACnB,MAAA;AACI,IAAA;AACoB,MAAA;AACxB,MAAA;AACI,IAAA;AACkB,MAAA;AACtB,MAAA;AACI,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACO,MAAA;AACF,QAAA;AACP,UAAA;AACD,QAAA;AACmB,QAAA;AACnB,QAAA;AACD,MAAA;AACoB,MAAA;AACpB,MAAA;AACI,IAAA;AACiB,MAAA;AACrB,MAAA;AACI,IAAA;AACE,MAAA;AACN,MAAA;AACI,IAAA;AACkB,MAAA;AACtB,MAAA;AACI,IAAA;AACO,MAAA;AACF,QAAA;AACP,UAAA;AACD,QAAA;AACmB,QAAA;AACnB,QAAA;AACD,MAAA;AACM,MAAA;AACN,MAAA;AACI,IAAA;AACO,MAAA;AACF,QAAA;AACP,UAAA;AACD,QAAA;AACmB,QAAA;AACnB,QAAA;AACD,MAAA;AACsB,MAAA;AACtB,MAAA;AACI,IAAA;AACO,MAAA;AACF,QAAA;AACP,UAAA;AACD,QAAA;AACmB,QAAA;AACnB,QAAA;AACD,MAAA;AACM,MAAA;AACN,MAAA;AACI,IAAA;AACO,MAAA;AACF,QAAA;AACP,UAAA;AACD,QAAA;AACmB,QAAA;AACnB,QAAA;AACD,MAAA;AACwB,MAAA;AACxB,MAAA;AACI,IAAA;AACO,MAAA;AACF,QAAA;AACP,UAAA;AACD,QAAA;AACmB,QAAA;AACnB,QAAA;AACD,MAAA;AACM,MAAA;AACN,MAAA;AACQ,IAAA;AACS,MAAA;AAChB,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACD,MAAA;AAEgB,MAAA;AAED,QAAA;AAIf,MAAA;AACuB,MAAA;AAA4B,uBAAA;AACrC,MAAA;AACH,MAAA;AACQ,MAAA;AACnB,MAAA;AACD,IAAA;AACD,EAAA;AACD;AAEK;AzBywGyB;AACA;AACA","file":"/home/pitok/Projects/framework-bun/packages/buntok-core/dist/cli/index.cjs","sourcesContent":[null,"import { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\n\nexport async function buildCommand() {\n\tconst projectRoot = process.cwd();\n\tconst entryPoint = join(projectRoot, \"server.ts\");\n\tconst outDir = join(projectRoot, \".buntok\");\n\n\tif (!existsSync(entryPoint)) {\n\t\tconsole.error(\"\\x1b[31m❌ server.ts not found\\x1b[0m\");\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\t// Read user's package.json to know their dependencies\n\tlet userDeps: string[] = [];\n\tconst pkgPath = join(projectRoot, \"package.json\");\n\tif (existsSync(pkgPath)) {\n\t\tconst pkg = await Bun.file(pkgPath).json();\n\t\tuserDeps = [\n\t\t\t...Object.keys(pkg.dependencies || {}),\n\t\t\t...Object.keys(pkg.devDependencies || {}),\n\t\t];\n\t}\n\n\t// BunTok peer deps (optional, user installs these)\n\tconst peerDeps = [\n\t\t\"@apollo/server\",\n\t\t\"graphql\",\n\t\t\"graphql-yoga\",\n\t\t\"@opentelemetry/api\",\n\t\t\"@opentelemetry/sdk-node\",\n\t\t\"@opentelemetry/resources\",\n\t\t\"@opentelemetry/semantic-conventions\",\n\t\t\"@opentelemetry/sdk-trace-node\",\n\t\t\"@opentelemetry/exporter-trace-otlp-http\",\n\t\t\"ioredis\",\n\t\t\"bullmq\",\n\t\t\"amqplib\",\n\t];\n\n\tconst external = [...new Set([...peerDeps, ...userDeps])];\n\n\tconsole.log(\"\\x1b[36m🔨 Building project...\\x1b[0m\");\n\n\tconst result = await Bun.build({\n\t\tentrypoints: [entryPoint],\n\t\toutdir: outDir,\n\t\ttarget: \"bun\",\n\t\ttsconfig: join(projectRoot, \"tsconfig.json\"),\n\t\texternal,\n\t});\n\n\tif (!result.success) {\n\t\tconsole.error(\"\\x1b[31m❌ Build failed:\\x1b[0m\");\n\t\tfor (const log of result.logs) {\n\t\t\tconsole.error(log);\n\t\t}\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconsole.log(\"\\x1b[32m✅ Build successful → .buntok/server.js\\x1b[0m\");\n\tconsole.log(\"\\x1b[90m  Deploy: copy .buntok/ + node_modules/ + package.json to server\\x1b[0m\");\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\ninterface TSError {\n\tfile: string;\n\tline: number;\n\tcol: number;\n\tcode: string;\n\tmessage: string;\n}\n\nfunction stripAnsi(str: string): string {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape codes\n\treturn str.replace(/\\x1B\\[[0-9;]*[mK]/g, \"\");\n}\n\nfunction parseTSErrors(output: string): TSError[] {\n\tconst clean = stripAnsi(output);\n\tconst lines = clean.split(\"\\n\");\n\tconst errors: TSError[] = [];\n\n\tfor (const line of lines) {\n\t\t// Format without --pretty: \"file.ts(1,7): error TS2322: message\"\n\t\t// Format with --pretty: \"file.ts:1:7 - error TS2322: message\"\n\t\tconst match =\n\t\t\tline.match(/^(.+?)\\((\\d+),(\\d+)\\): error (TS\\d+): (.+)$/) ||\n\t\t\tline.match(/^(.+?):(\\d+):(\\d+) - error (TS\\d+): (.+)$/);\n\t\tif (match && match[1] && match[2] && match[3] && match[4] && match[5]) {\n\t\t\terrors.push({\n\t\t\t\tfile: match[1],\n\t\t\t\tline: Number.parseInt(match[2], 10),\n\t\t\t\tcol: Number.parseInt(match[3], 10),\n\t\t\t\tcode: match[4],\n\t\t\t\tmessage: match[5],\n\t\t\t});\n\t\t}\n\t}\n\n\treturn errors;\n}\n\nfunction getUniqueFiles(errors: TSError[]): string[] {\n\treturn [...new Set(errors.map((e) => e.file))];\n}\n\nexport async function checkCommand(flags: string[] = []): Promise<void> {\n\tconst cwd = process.cwd();\n\tconst tsconfigPath = join(cwd, \"tsconfig.json\");\n\tconst isJson = flags.includes(\"--json\");\n\tconst isPlain = flags.includes(\"--plain\");\n\n\tif (!existsSync(tsconfigPath)) {\n\t\tif (isJson) {\n\t\t\tconsole.log(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: \"tsconfig.json not found. Run `buntok init` first.\",\n\t\t\t\t\terrors: [],\n\t\t\t\t\terrorCount: 0,\n\t\t\t\t\tfileCount: 0,\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.error(\n\t\t\t\t\"\\x1b[31mError: tsconfig.json not found. Run `buntok init` first.\\x1b[0m\",\n\t\t\t);\n\t\t}\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tif (!isJson) {\n\t\tif (isPlain) {\n\t\t\tconsole.log(\"  Running type check...\\n\");\n\t\t} else {\n\t\t\tconsole.log(\"\\x1b[36m  Running type check...\\x1b[0m\\n\");\n\t\t}\n\t}\n\n\tconst proc = Bun.spawnSync(\n\t\t[\"bunx\", \"tsc\", \"--noEmit\", \"--pretty\", \"--project\", tsconfigPath],\n\t\t{ cwd },\n\t);\n\n\tconst output = proc.stdout?.toString() || \"\";\n\tconst errors = parseTSErrors(output);\n\tconst files = getUniqueFiles(errors);\n\tconst errorCount = errors.length;\n\tconst fileCount = files.length;\n\n\tif (proc.exitCode === 0) {\n\t\tif (isJson) {\n\t\t\tconsole.log(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\terrors: [],\n\t\t\t\t\terrorCount: 0,\n\t\t\t\t\tfileCount: 0,\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tif (isPlain) {\n\t\t\t\tconsole.log(\"\\n  ✓ No errors found\\n\");\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`\\n\\x1b[32m  ✓ No errors found\\x1b[0m\\n`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tprocess.exitCode = 0;\n\t\treturn;\n\t}\n\n\t// Errors found\n\tif (isJson) {\n\t\tconsole.log(\n\t\t\tJSON.stringify({\n\t\t\t\tsuccess: false,\n\t\t\t\terrors,\n\t\t\t\terrorCount,\n\t\t\t\tfileCount,\n\t\t\t}),\n\t\t);\n\t} else {\n\t\t// Show errors (limit to 50 for readability)\n\t\tconst maxErrors = 50;\n\t\tconst shownErrors = errors.slice(0, maxErrors);\n\n\t\tfor (const err of shownErrors) {\n\t\t\tconst file = isPlain ? err.file : `\\x1b[36m${err.file}\\x1b[0m`;\n\t\t\tconst line = isPlain ? `${err.line}` : `\\x1b[33m${err.line}\\x1b[0m`;\n\t\t\tconst col = isPlain ? `${err.col}` : `\\x1b[33m${err.col}\\x1b[0m`;\n\t\t\tconst code = isPlain ? err.code : `\\x1b[31m${err.code}\\x1b[0m`;\n\t\t\tconst msg = isPlain ? err.message : `\\x1b[31m${err.message}\\x1b[0m`;\n\n\t\t\tconsole.log(`${file}(${line},${col}): error ${code}: ${msg}`);\n\t\t}\n\n\t\tif (errorCount > maxErrors) {\n\t\t\tconsole.log(\n\t\t\t\t`\\n  ... and ${errorCount - maxErrors} more errors`,\n\t\t\t);\n\t\t}\n\n\t\t// Summary\n\t\tconst fileStr = fileCount === 1 ? \"file\" : \"files\";\n\t\tif (isPlain) {\n\t\t\tconsole.log(\n\t\t\t\t`\\n  ✗ ${errorCount} error${errorCount === 1 ? \"\" : \"s\"} in ${fileCount} ${fileStr}\\n`,\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.log(\n\t\t\t\t`\\n\\x1b[31m  ✗ ${errorCount} error${errorCount === 1 ? \"\" : \"s\"} in ${fileCount} ${fileStr}\\x1b[0m\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprocess.exitCode = proc.exitCode ?? 1;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { generateBarrel } from \"../generators/barrel.js\";\nimport { generateController } from \"../generators/controller.js\";\nimport {\n\tgetEntityModel,\n\tloadPrismaSchema,\n\tparseFieldsFlag,\n\tzodLinesForFields,\n} from \"../generators/model.js\";\nimport { generateRepository } from \"../generators/repository.js\";\nimport { generateSchemaFile } from \"../generators/schema.js\";\nimport { generateService } from \"../generators/service.js\";\nimport {\n\tcollectImportedControllers,\n\tdetectORM,\n\tensureImport,\n\tfindAppDeclEnd,\n\tfindEntryFile,\n\tfindInsertionIndex,\n\tformatWithBiome,\n\ttype ORM,\n} from \"../project.js\";\nimport { scanRoutes, warnDuplicateRoutes } from \"../routes-scan.js\";\nimport { toPascalCase } from \"../utils.js\";\n\ninterface CreateOptions {\n\trepo: boolean;\n\tservice: boolean;\n\tcontroller: boolean;\n\tschema: boolean;\n\tall: boolean;\n\tdryRun: boolean;\n\tforce: boolean;\n\tbase: boolean;\n\tfields?: string;\n\torm?: ORM;\n}\n\nfunction parseOptions(args: string[]): CreateOptions {\n\tconst options: CreateOptions = {\n\t\trepo: false,\n\t\tservice: false,\n\t\tcontroller: false,\n\t\tschema: false,\n\t\tall: true,\n\t\tdryRun: false,\n\t\tforce: false,\n\t\tbase: false,\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i] ?? \"\";\n\t\tswitch (arg) {\n\t\t\tcase \"--repo\":\n\t\t\t\toptions.repo = true;\n\t\t\t\toptions.all = false;\n\t\t\t\tbreak;\n\t\t\tcase \"--service\":\n\t\t\t\toptions.service = true;\n\t\t\t\toptions.all = false;\n\t\t\t\tbreak;\n\t\t\tcase \"--controller\":\n\t\t\t\toptions.controller = true;\n\t\t\t\toptions.all = false;\n\t\t\t\tbreak;\n\t\t\tcase \"--schema\":\n\t\t\t\toptions.schema = true;\n\t\t\t\toptions.all = false;\n\t\t\t\tbreak;\n\t\t\tcase \"--dry-run\":\n\t\t\t\toptions.dryRun = true;\n\t\t\t\tbreak;\n\t\t\tcase \"--force\":\n\t\t\t\toptions.force = true;\n\t\t\t\tbreak;\n\t\t\tcase \"--base\":\n\t\t\t\toptions.base = true;\n\t\t\t\tbreak;\n\t\t\tcase \"--fields\":\n\t\t\t\toptions.fields = args[i + 1];\n\t\t\t\ti++;\n\t\t\t\tbreak;\n\t\t\tcase \"--prisma\":\n\t\t\t\toptions.orm = \"prisma\";\n\t\t\t\tbreak;\n\t\t\tcase \"--drizzle\":\n\t\t\t\toptions.orm = \"drizzle\";\n\t\t\t\tbreak;\n\t\t\tcase \"--typeorm\":\n\t\t\t\toptions.orm = \"typeorm\";\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t// If any specific option is set, don't generate all\n\tif (!options.all) {\n\t\treturn options;\n\t}\n\n\t// Generate all by default\n\treturn {\n\t\trepo: true,\n\t\tservice: true,\n\t\tcontroller: true,\n\t\tschema: true,\n\t\tall: false,\n\t\tdryRun: options.dryRun,\n\t\tforce: options.force,\n\t\tbase: options.base,\n\t\tfields: options.fields,\n\t\torm: options.orm,\n\t};\n}\n\nexport async function createCommand(entityName: string, args: string[]) {\n\tconst options = parseOptions(args);\n\tconst pascalName = toPascalCase(entityName);\n\tconst orm = options.orm ?? detectORM();\n\tconst moduleDir = join(\"src/modules\", entityName);\n\n\tconst repoPath = join(moduleDir, `${entityName}.repository.ts`);\n\tconst servicePath = join(moduleDir, `${entityName}.service.ts`);\n\tconst controllerPath = join(moduleDir, `${entityName}.controller.ts`);\n\tconst schemaPath = join(moduleDir, `${entityName}.schema.ts`);\n\n\t// Cross-generator awareness: what already exists on disk?\n\tconst hasRepo = existsSync(repoPath);\n\tconst hasService = existsSync(servicePath);\n\tconst hasController = existsSync(controllerPath);\n\tconst hasSchema = existsSync(schemaPath);\n\n\t// Template style: explicit --base wins, otherwise follow existing module\n\t// files (a module built with BaseService/BaseController stays base-styled).\n\tlet useBase = options.base;\n\tif (!options.base) {\n\t\tfor (const existing of [servicePath, controllerPath]) {\n\t\t\tif (!existsSync(existing)) continue;\n\t\t\tconst source = readFileSync(existing, \"utf-8\");\n\t\t\tif (\n\t\t\t\tsource.includes(\"extends BaseService\") ||\n\t\t\t\tsource.includes(\"extends BaseController\")\n\t\t\t) {\n\t\t\t\tuseBase = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// A service generated with a repo (or next to an existing one) gets the\n\t// wired template; a controller generated next to an existing service does\n\t// too. `--base` (or a base-styled module on disk) always implies the\n\t// wired templates — the Base* variants carry @Dependencies themselves.\n\tconst serviceWithRepo = options.repo || hasRepo || useBase;\n\tconst controllerWithService = options.service || hasService || useBase;\n\n\tconst prefix = options.dryRun ? \"\\x1b[33m[DRY RUN]\\x1b[0m \" : \"\";\n\tconsole.log(`\\n${prefix}\\x1b[36mCreating ${pascalName} entity (orm: ${orm})...\\x1b[0m\\n`);\n\n\t// Ensure module directory exists (skip in dry-run)\n\tif (!options.dryRun) {\n\t\tif (!existsSync(moduleDir)) {\n\t\t\tawait fs.mkdir(moduleDir, { recursive: true });\n\t\t}\n\t}\n\n\tconst results: string[] = [];\n\tconst generatedFiles: string[] = [];\n\tconst tasks: Promise<void>[] = [];\n\n\t// Helper to generate file asynchronously\n\tconst generateFile = async (\n\t\tpath: string,\n\t\tcontentGenerator: () => string,\n\t\ttype: string,\n\t) => {\n\t\tif (options.dryRun) {\n\t\t\tconst content = contentGenerator();\n\t\t\tresults.push(`[DRY RUN] ${type}: ${path}`);\n\t\t\tconsole.log(`\\n\\x1b[90m--- ${path} ---\\x1b[0m`);\n\t\t\tconsole.log(content);\n\t\t\tconsole.log(`\\x1b[90m--- end ---\\x1b[0m\\n`);\n\t\t\treturn;\n\t\t}\n\t\tif (!existsSync(path) || options.force) {\n\t\t\tawait fs.writeFile(path, contentGenerator());\n\t\t\tresults.push(`✓ ${type}: ${path}`);\n\t\t\tgeneratedFiles.push(path);\n\t\t} else {\n\t\t\tresults.push(`• ${type}: ${path} (already exists)`);\n\t\t}\n\t};\n\n\tif (options.repo) {\n\t\ttasks.push(\n\t\t\tgenerateFile(\n\t\t\t\trepoPath,\n\t\t\t\t() => generateRepository(entityName, pascalName, orm, { base: useBase }),\n\t\t\t\t\"Repository\",\n\t\t\t),\n\t\t);\n\t}\n\n\tif (options.service) {\n\t\ttasks.push(\n\t\t\tgenerateFile(\n\t\t\t\tservicePath,\n\t\t\t\t() =>\n\t\t\t\t\tgenerateService(entityName, pascalName, serviceWithRepo, orm, {\n\t\t\t\t\t\tbase: useBase,\n\t\t\t\t\t}),\n\t\t\t\t\"Service\",\n\t\t\t),\n\t\t);\n\t}\n\n\tif (options.controller) {\n\t\ttasks.push(\n\t\t\tgenerateFile(\n\t\t\t\tcontrollerPath,\n\t\t\t\t() =>\n\t\t\t\t\tgenerateController(entityName, pascalName, controllerWithService, orm, {\n\t\t\t\t\t\tbase: useBase,\n\t\t\t\t\t}),\n\t\t\t\t\"Controller\",\n\t\t\t),\n\t\t);\n\t}\n\n\tif (options.schema) {\n\t\t// Model awareness: `--fields` wins, then the Prisma model, then placeholder\n\t\tlet zodLines: string[] | null = null;\n\t\tif (options.fields) {\n\t\t\tconst flagFields = parseFieldsFlag(options.fields);\n\t\t\tzodLines = flagFields.length > 0 ? zodLinesForFields(flagFields, null) : null;\n\t\t} else {\n\t\t\tconst prismaSchema = loadPrismaSchema();\n\t\t\tconst model = prismaSchema ? getEntityModel(entityName, prismaSchema) : null;\n\t\t\tif (model) {\n\t\t\t\tzodLines = zodLinesForFields(model.fields, prismaSchema);\n\t\t\t}\n\t\t}\n\t\tif (!options.dryRun) {\n\t\t\tconst result = await generateSchemaFile(entityName, moduleDir, options.force, {\n\t\t\t\tlines: zodLines,\n\t\t\t});\n\t\t\tif (result) {\n\t\t\t\tresults.push(`✓ Schema: ${result}`);\n\t\t\t\tgeneratedFiles.push(result);\n\t\t\t} else {\n\t\t\t\tresults.push(`• Schema: ${schemaPath} (already exists)`);\n\t\t\t}\n\t\t} else {\n\t\t\tresults.push(`[DRY RUN] Schema: ${schemaPath}`);\n\t\t}\n\t}\n\n\t// Execute all file generations concurrently\n\tawait Promise.all(tasks);\n\n\t// Barrel export: create when missing, otherwise append only the exports\n\t// that are not present yet (merge instead of skip).\n\tconst barrelPath = join(moduleDir, \"index.ts\");\n\tconst barrelParts = {\n\t\trepository: hasRepo || options.repo,\n\t\tservice: hasService || options.service,\n\t\tcontroller: hasController || options.controller,\n\t\tschema: hasSchema || options.schema,\n\t};\n\tif (options.dryRun) {\n\t\tresults.push(`[DRY RUN] Barrel: ${barrelPath}`);\n\t} else if (!existsSync(barrelPath)) {\n\t\tawait fs.writeFile(barrelPath, generateBarrel(entityName, pascalName, barrelParts));\n\t\tresults.push(`✓ Barrel: ${barrelPath}`);\n\t\tgeneratedFiles.push(barrelPath);\n\t} else {\n\t\tconst existingBarrel = readFileSync(barrelPath, \"utf-8\");\n\t\tconst wanted = generateBarrel(entityName, pascalName, barrelParts)\n\t\t\t.split(\"\\n\")\n\t\t\t.filter((line) => line.trim() && !existingBarrel.includes(line));\n\t\tif (wanted.length > 0) {\n\t\t\tawait fs.writeFile(\n\t\t\t\tbarrelPath,\n\t\t\t\t`${existingBarrel.trimEnd()}\\n${wanted.join(\"\\n\")}\\n`,\n\t\t\t);\n\t\t\tresults.push(`✓ Barrel: ${barrelPath} (+${wanted.length} export${wanted.length > 1 ? \"s\" : \"\"})`);\n\t\t\tgeneratedFiles.push(barrelPath);\n\t\t} else {\n\t\t\tresults.push(`• Barrel: ${barrelPath} (up to date)`);\n\t\t}\n\t}\n\n\t// Auto-format generated files with Biome if available (skip in dry-run)\n\tif (generatedFiles.length > 0 && !options.dryRun) {\n\t\tif (formatWithBiome(generatedFiles)) {\n\t\t\tconsole.log(\n\t\t\t\t\"\\x1b[90m✨ Auto-formatted generated files with Biome\\x1b[0m\\n\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// Auto-register in the app entry (skip in dry-run)\n\tconst entryFile = findEntryFile();\n\tconst indexPath = entryFile ?? join(\"src\", \"index.ts\");\n\tif (entryFile && existsSync(indexPath) && !options.dryRun && options.controller) {\n\t\tconst indexContent = readFileSync(indexPath, \"utf-8\");\n\t\tconst controllerName = `${pascalName}Controller`;\n\t\tconst controllerImport = `import { ${controllerName} } from \"@/modules/${entityName}\";`;\n\n\t\t// Determine registration type based on whether the generated controller\n\t\t// has @Dependencies (i.e. was generated with the wired service template)\n\t\tconst useContainer = controllerWithService;\n\n\t\t// Check if this controller is already registered\n\t\tconst rcSingleRegex = /app\\.registerController\\((\\w+)\\)\\s*;/;\n\t\tconst rcArrayRegex = /app\\.registerController\\(\\[([^\\]]*)\\]\\)\\s*;/;\n\t\tconst scanRegex = /(?:app\\.getContainer\\(\\)|container)\\.scan\\(\\[([^\\]]*)\\]\\)\\s*;/;\n\n\t\tconst rcSingleMatch = indexContent.match(rcSingleRegex);\n\t\tconst rcArrayMatch = indexContent.match(rcArrayRegex);\n\t\tconst scanMatch = indexContent.match(scanRegex);\n\n\t\tlet alreadyRegistered = false;\n\t\tif (useContainer && scanMatch?.[1]) {\n\t\t\talreadyRegistered = scanMatch[1].includes(controllerName);\n\t\t} else if (!useContainer && rcSingleMatch?.[1]) {\n\t\t\talreadyRegistered = rcSingleMatch[1] === controllerName;\n\t\t} else if (!useContainer && rcArrayMatch?.[1]) {\n\t\t\talreadyRegistered = rcArrayMatch[1].includes(controllerName);\n\t\t}\n\n\t\tif (!alreadyRegistered) {\n\t\t\tlet content = indexContent;\n\t\t\t// All new statements are collected first and spliced as one block so\n\t\t\t// they keep execution order and never stack on the same anchor.\n\t\t\tconst toInsert: string[] = [];\n\n\t\t\tif (useContainer) {\n\t\t\t\t// === container.scan() + registerController() flow ===\n\n\t\t\t\t// Step 1: Add Container import if missing\n\t\t\t\tconst containerImportRegex = /import\\s*\\{[^}]*Container[^}]*\\}\\s*from\\s*[\"']@buntok\\/core[\"']/;\n\t\t\t\tif (!containerImportRegex.test(content)) {\n\t\t\t\t\t// Add Container to existing @buntok/core import\n\t\t\t\t\tcontent = content.replace(\n\t\t\t\t\t\t/import\\s*\\{([^}]+)\\}\\s*from\\s*[\"']@buntok\\/core[\"']/,\n\t\t\t\t\t\t(_match, imports: string) => {\n\t\t\t\t\t\t\tif (imports.includes(\"Container\")) return _match;\n\t\t\t\t\t\t\treturn `import { ${imports.trim()}, Container } from \"@buntok/core\"`;\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Step 2: Add controller import if missing\n\t\t\t\tcontent = ensureImport(content, controllerImport);\n\n\t\t\t\t// Step 3: Add/merge container.scan()\n\t\t\t\tconst existingScan = content.match(scanRegex);\n\t\t\t\tif (existingScan?.[1]) {\n\t\t\t\t\t// Already has scan — merge\n\t\t\t\t\tconst existing = existingScan[1].trim();\n\t\t\t\t\tconst merged = existing ? `${existing}, ${controllerName}` : controllerName;\n\t\t\t\t\tcontent = content.replace(scanRegex, `container.scan([${merged}]);`);\n\t\t\t\t} else {\n\t\t\t\t\t// No scan found — collect all imported @Dependencies controllers\n\t\t\t\t\tconst allControllers = collectImportedControllers(content, true);\n\t\t\t\t\tif (!allControllers.includes(controllerName)) {\n\t\t\t\t\t\tallControllers.push(controllerName);\n\t\t\t\t\t}\n\t\t\t\t\ttoInsert.push(`container.scan([${allControllers.join(\", \")}]);`);\n\t\t\t\t}\n\n\t\t\t\t// Step 4: Add app.setContainer(container) if missing\n\t\t\t\tconst setContainerRegex = /app\\.setContainer\\s*\\(\\s*container\\s*\\)\\s*;/;\n\t\t\t\tif (!setContainerRegex.test(content)) {\n\t\t\t\t\ttoInsert.push(\"app.setContainer(container);\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// === registerController() flow ===\n\t\t\t\tcontent = ensureImport(content, controllerImport);\n\t\t\t}\n\n\t\t\t// Step 5: Add/merge registerController() — required for endpoint registration\n\t\t\tconst rcSingleNew = content.match(rcSingleRegex);\n\t\t\tconst rcArrayNew = content.match(rcArrayRegex);\n\t\t\tif (rcArrayNew?.[1]) {\n\t\t\t\t// Already has array — merge\n\t\t\t\tconst existing = rcArrayNew[1].trim();\n\t\t\t\tconst merged = existing ? `${existing}, ${controllerName}` : controllerName;\n\t\t\t\tcontent = content.replace(rcArrayRegex, `app.registerController([${merged}]);`);\n\t\t\t} else if (rcSingleNew?.[1]) {\n\t\t\t\t// Has single — convert to array\n\t\t\t\tcontent = content.replace(\n\t\t\t\t\trcSingleRegex,\n\t\t\t\t\t`app.registerController([${rcSingleNew[1]}, ${controllerName}]);`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\ttoInsert.push(`app.registerController([${controllerName}]);`);\n\t\t\t}\n\n\t\t\t// Single ordered splice of all pending statements\n\t\t\tif (toInsert.length > 0) {\n\t\t\t\tconst insertion = findInsertionIndex(content);\n\t\t\t\tconst prefix =\n\t\t\t\t\tinsertion.index > 0 && content[insertion.index - 1] !== \"\\n\"\n\t\t\t\t\t\t? \"\\n\"\n\t\t\t\t\t\t: \"\";\n\t\t\t\tcontent =\n\t\t\t\t\tcontent.slice(0, insertion.index) +\n\t\t\t\t\tprefix +\n\t\t\t\t\ttoInsert.join(\"\\n\\n\") +\n\t\t\t\t\t\"\\n\\n\" +\n\t\t\t\t\tcontent.slice(insertion.index);\n\t\t\t}\n\n\t\t\t// Step 6: declare the container right after the app declaration\n\t\t\t// (kept after the splice so it stays above every inserted statement)\n\t\t\tif (useContainer) {\n\t\t\t\tconst containerDeclRegex = /(?:const|let|var)\\s+container\\s*=\\s*new\\s+Container\\(\\)/;\n\t\t\t\tif (!containerDeclRegex.test(content)) {\n\t\t\t\t\tconst declEnd = findAppDeclEnd(content);\n\t\t\t\t\tif (declEnd !== null) {\n\t\t\t\t\t\tcontent =\n\t\t\t\t\t\t\tcontent.slice(0, declEnd) +\n\t\t\t\t\t\t\t\"\\nconst container = new Container();\" +\n\t\t\t\t\t\t\tcontent.slice(declEnd);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// No `const app = new App(...)` to anchor on — declare\n\t\t\t\t\t\t// the container directly above the inserted block.\n\t\t\t\t\t\tconst insertion = findInsertionIndex(content);\n\t\t\t\t\t\tconst prefix =\n\t\t\t\t\t\t\tinsertion.index > 0 &&\n\t\t\t\t\t\t\tcontent[insertion.index - 1] !== \"\\n\"\n\t\t\t\t\t\t\t\t? \"\\n\"\n\t\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\t\tcontent =\n\t\t\t\t\t\t\tcontent.slice(0, insertion.index) +\n\t\t\t\t\t\t\tprefix +\n\t\t\t\t\t\t\t\"const container = new Container();\\n\" +\n\t\t\t\t\t\t\tcontent.slice(insertion.index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconsole.log(\n\t\t\t\tuseContainer\n\t\t\t\t\t? `\\x1b[32m✔ Registered ${controllerName} in container.scan() + registerController()\\x1b[0m`\n\t\t\t\t\t: `\\x1b[32m✔ Registered ${controllerName} in ${entryFile}\\x1b[0m`,\n\t\t\t);\n\n\t\t\tawait fs.writeFile(indexPath, content);\n\t\t} else {\n\t\t\tconst location = useContainer ? \"container.scan()\" : \"registerController\";\n\t\t\tconsole.log(\n\t\t\t\t`\\x1b[90m• ${entryFile}: ${controllerName} already registered in ${location}\\x1b[0m`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Static route scan: warn when the new controller collides with existing routes\n\tif (!options.dryRun && options.controller) {\n\t\twarnDuplicateRoutes(scanRoutes());\n\t}\n\n\t// Print results\n\tconsole.log(options.dryRun ? \"\\x1b[33mWould generate:\\x1b[0m\" : \"\\x1b[32mGenerated files:\\x1b[0m\");\n\tfor (const result of results.sort()) {\n\t\tconsole.log(`  ${result}`);\n\t}\n\n\tif (options.dryRun) {\n\t\tconsole.log(`\\n\\x1b[33mRun without --dry-run to create these files.\\x1b[0m\\n`);\n\t} else {\n\t\tconsole.log(`\n\\x1b[36mNext steps:\\x1b[0m\n  1. Start dev server: \\x1b[33mbun run dev\\x1b[0m\n`);\n\t}\n}\n","export function generateBarrel(\n\tname: string,\n\tpascalName: string,\n\toptions: {\n\t\trepository: boolean;\n\t\tservice: boolean;\n\t\tcontroller: boolean;\n\t\tschema: boolean;\n\t},\n): string {\n\tconst exports: string[] = [];\n\n\tif (options.repository) {\n\t\texports.push(`export { ${pascalName}Repository } from \"./${name}.repository\";`);\n\t}\n\n\tif (options.service) {\n\t\texports.push(`export { ${pascalName}Service } from \"./${name}.service\";`);\n\t}\n\n\tif (options.controller) {\n\t\texports.push(`export { ${pascalName}Controller } from \"./${name}.controller\";`);\n\t}\n\n\tif (options.schema) {\n\t\texports.push(\n\t\t\t`export { Create${pascalName}Schema, Update${pascalName}Schema } from \"./${name}.schema\";`,\n\t\t\t`export type { Create${pascalName}Input, Update${pascalName}Input } from \"./${name}.schema\";`,\n\t\t);\n\t}\n\n\treturn exports.join(\"\\n\") + \"\\n\";\n}\n","export function toSnakeCase(str: string): string {\n\treturn str\n\t\t.replace(/([A-Z])/g, \"_$1\")\n\t\t.toLowerCase()\n\t\t.replace(/^_/, \"\")\n\t\t.replace(/-/g, \"_\");\n}\n\nexport function toPascalCase(str: string): string {\n\treturn str\n\t\t.split(/[-_\\s]+/)\n\t\t.filter(Boolean)\n\t\t.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join(\"\");\n}\n\nexport function toCamelCase(str: string): string {\n\tconst pascal = toPascalCase(str);\n\treturn pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\nexport function toKebabCase(str: string): string {\n\treturn toSnakeCase(str).replace(/_/g, \"-\");\n}\n\nconst IRREGULARS: Record<string, string> = {\n\tperson: \"people\",\n\tchild: \"children\",\n\tman: \"men\",\n\twoman: \"women\",\n\tmouse: \"mice\",\n\tgoose: \"geese\",\n\ttooth: \"teeth\",\n\tfoot: \"feet\",\n\tknife: \"knives\",\n\twife: \"wives\",\n\tlife: \"lives\",\n\tleaf: \"leaves\",\n\twolf: \"wolves\",\n\thalf: \"halves\",\n\tshelf: \"shelves\",\n\tpotato: \"potatoes\",\n\ttomato: \"tomatoes\",\n\thero: \"heroes\",\n\techo: \"echoes\",\n\tanalysis: \"analyses\",\n\tcrisis: \"crises\",\n\tthesis: \"theses\",\n\tdiagnosis: \"diagnoses\",\n\thypothesis: \"hypotheses\",\n\tbasis: \"bases\",\n\tquiz: \"quizzes\",\n};\n\nconst UNCOUNTABLE = new Set([\n\t\"sheep\",\n\t\"fish\",\n\t\"series\",\n\t\"species\",\n\t\"deer\",\n\t\"news\",\n\t\"information\",\n\t\"equipment\",\n\t\"money\",\n\t\"furniture\",\n\t\"software\",\n\t\"hardware\",\n\t\"feedback\",\n\t\"research\",\n]);\n\n/**\n * Minimal English pluralization for route/file names (zero-dep).\n * Handles irregulars, uncountables, consonant+-y, and -s/-x/-z/-ch/-sh endings.\n */\nexport function pluralize(word: string): string {\n\tconst lower = word.toLowerCase();\n\tif (UNCOUNTABLE.has(lower)) return word;\n\n\tconst irregular = IRREGULARS[lower];\n\tif (irregular) {\n\t\treturn /^[A-Z]/.test(word)\n\t\t\t? irregular.charAt(0).toUpperCase() + irregular.slice(1)\n\t\t\t: irregular;\n\t}\n\n\t// Already plural? (ends in plain -s, but not -ss/-us/-is which stay singular)\n\tif (/s$/i.test(word) && !/(ss|us|is)$/i.test(word)) return word;\n\n\tif (/(s|x|z|ch|sh)$/i.test(word)) return `${word}es`;\n\tif (/[^aeiou]y$/i.test(word)) return `${word.slice(0, -1)}ies`;\n\treturn `${word}s`;\n}\n\nexport interface EntityNames {\n\t/** Input as passed by the user, e.g. `blog-post` */\n\traw: string;\n\t/** User / BlogPost */\n\tpascal: string;\n\t/** user / blog_post */\n\tsnake: string;\n\t/** user / blog-post */\n\tkebab: string;\n\t/** user / blogPost */\n\tcamel: string;\n\t/** users / blog-posts (kebab, pluralized) */\n\troute: string;\n\t/** users / blog_posts (snake, pluralized) */\n\tpluralSnake: string;\n}\n\nexport function resolveNames(entity: string): EntityNames {\n\tconst snake = toSnakeCase(entity);\n\tconst kebab = snake.replace(/_/g, \"-\");\n\tconst pascal = toPascalCase(entity);\n\tconst camel = pascal.charAt(0).toLowerCase() + pascal.slice(1);\n\treturn {\n\t\traw: entity,\n\t\tpascal,\n\t\tsnake,\n\t\tkebab,\n\t\tcamel,\n\t\troute: pluralize(kebab),\n\t\tpluralSnake: pluralize(snake),\n\t};\n}\n","import { resolveNames, toCamelCase } from \"../utils.js\";\nimport type { ORM } from \"./repository.js\";\n\nexport interface ControllerOptions {\n\t/** Generate the BaseController-based variant. */\n\tbase?: boolean;\n\t/** Override the route prefix (default: pluralized entity name). */\n\troute?: string;\n}\n\nfunction getPrismaType(pascalName: string): string {\n\treturn `import type { ${pascalName} } from \"@prisma/client\";`;\n}\n\nfunction getDrizzleType(_entityName: string): string {\n\tconst pascalName = _entityName.charAt(0).toUpperCase() + _entityName.slice(1);\n\treturn `import type { InferSelectModel } from \"drizzle-orm\";\nimport { ${_entityName} } from \"@/lib/db/schema\";\n\ntype ${pascalName} = InferSelectModel<typeof ${_entityName}>;`;\n}\n\nfunction getTypeORMType(pascalName: string): string {\n\treturn `import type { ${pascalName} } from \"@/lib/entities/${pascalName}\";`;\n}\n\nfunction generatePlainController(\n\tentityName: string,\n\tpascalName: string,\n\troute: string,\n): string {\n\tconst serviceProp = `${toCamelCase(entityName)}Service`;\n\treturn `import { Dependencies, Controller, Get, Post, Put, Delete } from \"@buntok/core\";\nimport type { Context } from \"@buntok/core\";\nimport { ${pascalName}Service } from \"./${entityName}.service\";\n\n@Dependencies(${pascalName}Service)\n@Controller(\"/${route}\")\nexport class ${pascalName}Controller {\n  constructor(private readonly ${serviceProp}: ${pascalName}Service) {}\n\n  private parseId(id: string): string | number {\n    if (id === \"\") return id;\n    const num = Number(id);\n    return Number.isNaN(num) ? id : num;\n  }\n\n  @Get(\"/\")\n  async getAll(ctx: Context) {\n    const data = await this.${serviceProp}.getAll();\n    return ctx.success(data);\n  }\n\n  @Get(\"/:id\")\n  async getById(ctx: Context) {\n    const id = this.parseId(ctx.params.id ?? \"\");\n    const data = await this.${serviceProp}.getById(id);\n    return ctx.success(data);\n  }\n\n  @Post(\"/\")\n  async create(ctx: Context) {\n    const body = await ctx.body();\n    const data = await this.${serviceProp}.create(body);\n    return ctx.success(data, \"Created successfully!.\", 201);\n  }\n\n  @Put(\"/:id\")\n  async update(ctx: Context) {\n    const id = this.parseId(ctx.params.id ?? \"\");\n    const body = await ctx.body();\n    const data = await this.${serviceProp}.update(id, body);\n    return ctx.success(data);\n  }\n\n  @Delete(\"/:id\")\n  async delete(ctx: Context) {\n    const id = this.parseId(ctx.params.id ?? \"\");\n    await this.${serviceProp}.delete(id);\n    return ctx.status(204);\n  }\n}\n`;\n}\n\nfunction generateBaseController(\n\tentityName: string,\n\tpascalName: string,\n\troute: string,\n\ttypeImport: string,\n\ttypeRef: string,\n): string {\n\treturn `import { Dependencies, Controller, BaseController } from \"@buntok/core\";\nimport { ${pascalName}Service } from \"./${entityName}.service\";\n${typeImport}\n\n@Dependencies(${pascalName}Service)\n@Controller(\"/${route}\")\nexport class ${pascalName}Controller extends BaseController<${typeRef}> {\n  constructor(private readonly ${toCamelCase(entityName)}Service: ${pascalName}Service) {\n    super(${toCamelCase(entityName)}Service);\n  }\n}\n`;\n}\n\nfunction generateStubController(\n\tentityName: string,\n\tpascalName: string,\n\troute: string,\n): string {\n\treturn `import { Controller, Get, Post, Put, Delete } from \"@buntok/core\";\nimport type { Context } from \"@buntok/core\";\n\n@Controller(\"/${route}\")\nexport class ${pascalName}Controller {\n  @Get(\"/\")\n  async getAll(ctx: Context) {\n    return ctx.success([], \"Records retrieved successfully\");\n  }\n\n  @Get(\"/:id\")\n  async getById(ctx: Context) {\n    return ctx.success({ id: ctx.params.id }, \"Record retrieved successfully\");\n  }\n\n  @Post(\"/\")\n  async create(ctx: Context) {\n    const data = await ctx.body<any>();\n    return ctx.success(data, \"Record created successfully\", 201);\n  }\n\n  @Put(\"/:id\")\n  async update(ctx: Context) {\n    const data = await ctx.body<any>();\n    return ctx.success({ id: ctx.params.id, ...data }, \"Record updated successfully\");\n  }\n\n  @Delete(\"/:id\")\n  async delete(ctx: Context) {\n    return ctx.success(null, \"Record deleted successfully\");\n  }\n}\n`;\n}\n\n/**\n * Generate controller file content.\n * Default is plain (explicit CRUD endpoints delegating to the service);\n * `options.base` opts into the BaseController variant.\n * Route prefix is pluralized (`category` → `/categories`), overridable via `options.route`.\n */\nexport function generateController(\n\tentityName: string,\n\tpascalName: string,\n\twithService: boolean = true,\n\torm?: ORM,\n\toptions?: ControllerOptions,\n): string {\n\tconst route = options?.route ?? resolveNames(entityName).route;\n\n\tif (withService) {\n\t\tconst detectedOrm = orm ?? \"prisma\";\n\t\tlet typeImport: string;\n\t\tlet typeRef: string;\n\n\t\tswitch (detectedOrm) {\n\t\t\tcase \"drizzle\":\n\t\t\t\ttypeImport = getDrizzleType(entityName);\n\t\t\t\ttypeRef = pascalName;\n\t\t\t\tbreak;\n\t\t\tcase \"typeorm\":\n\t\t\t\ttypeImport = getTypeORMType(pascalName);\n\t\t\t\ttypeRef = pascalName;\n\t\t\t\tbreak;\n\t\t\tcase \"prisma\":\n\t\t\tdefault:\n\t\t\t\ttypeImport = getPrismaType(pascalName);\n\t\t\t\ttypeRef = pascalName;\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn options?.base\n\t\t\t? generateBaseController(\n\t\t\t\t\tentityName,\n\t\t\t\t\tpascalName,\n\t\t\t\t\troute,\n\t\t\t\t\ttypeImport,\n\t\t\t\t\ttypeRef,\n\t\t\t\t)\n\t\t\t: generatePlainController(entityName, pascalName, route);\n\t}\n\n\treturn generateStubController(entityName, pascalName, route);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Model-aware generation: a hand-rolled Prisma schema parser (zero deps)\n * with a universal `--fields` fallback for projects without Prisma.\n */\n\nexport interface FieldDef {\n\tname: string;\n\t/** Prisma scalar name (String, Int, ...) or a logical kind from `--fields`. */\n\ttype: string;\n\toptional: boolean;\n\tlist: boolean;\n\tisId: boolean;\n\tunique: boolean;\n\t/** Field has @default / @createdAt / @updatedAt → not part of create input. */\n\thasDefault: boolean;\n\tisEnum: boolean;\n}\n\nexport interface PrismaModel {\n\tname: string;\n\tfields: FieldDef[];\n}\n\nexport interface PrismaSchema {\n\tmodels: Map<string, PrismaModel>;\n\tenums: Map<string, string[]>;\n}\n\nconst SCALARS = new Set([\n\t\"String\",\n\t\"Int\",\n\t\"Float\",\n\t\"Decimal\",\n\t\"BigInt\",\n\t\"Boolean\",\n\t\"DateTime\",\n\t\"Json\",\n\t\"Bytes\",\n]);\n\nconst SCHEMA_CANDIDATES = [\"prisma/schema.prisma\", \"schema.prisma\"];\n\nfunction stripComments(source: string): string {\n\tlet out = \"\";\n\tlet inString: '\"' | \"'\" | null = null;\n\tfor (let i = 0; i < source.length; i++) {\n\t\tconst ch = source[i];\n\t\tif (inString) {\n\t\t\tout += ch;\n\t\t\tif (ch === inString && source[i - 1] !== \"\\\\\") inString = null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\"' || ch === \"'\") {\n\t\t\tinString = ch;\n\t\t\tout += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"/\" && source[i + 1] === \"/\") {\n\t\t\twhile (i < source.length && source[i] !== \"\\n\") i++;\n\t\t\tout += \"\\n\";\n\t\t\tcontinue;\n\t\t}\n\t\tout += ch;\n\t}\n\treturn out;\n}\n\nfunction extractBlocks(\n\tsource: string,\n\tkind: \"model\" | \"enum\",\n): { name: string; body: string }[] {\n\tconst blocks: { name: string; body: string }[] = [];\n\tconst re = new RegExp(`\\\\b${kind}\\\\s+([A-Za-z_]\\\\w*)\\\\s*\\\\{`, \"g\");\n\tlet match: RegExpExecArray | null;\n\twhile ((match = re.exec(source)) !== null) {\n\t\tlet depth = 0;\n\t\tlet i = re.lastIndex - 1;\n\t\tfor (; i < source.length; i++) {\n\t\t\tif (source[i] === \"{\") depth++;\n\t\t\telse if (source[i] === \"}\") {\n\t\t\t\tdepth--;\n\t\t\t\tif (depth === 0) break;\n\t\t\t}\n\t\t}\n\t\tblocks.push({ name: match[1] ?? \"\", body: source.slice(re.lastIndex, i) });\n\t\tre.lastIndex = i + 1;\n\t}\n\treturn blocks;\n}\n\nfunction parseFieldLine(line: string): FieldDef | null {\n\tconst trimmed = line.trim();\n\tif (!trimmed || trimmed.startsWith(\"@@\")) return null;\n\tconst m = /^([A-Za-z_]\\w*)\\s+([A-Za-z_]\\w*)(\\[\\])?(\\?)?/.exec(trimmed);\n\tif (!m) return null;\n\tconst [, name = \"\", fieldType = \"\", list, optional] = m;\n\tconst attrs = trimmed.slice(m[0].length);\n\treturn {\n\t\tname,\n\t\ttype: fieldType,\n\t\toptional: Boolean(optional),\n\t\tlist: Boolean(list),\n\t\tisId: /@id\\b/.test(attrs),\n\t\tunique: /@unique\\b/.test(attrs),\n\t\thasDefault: /@default\\b|@updatedAt\\b/.test(attrs),\n\t\tisEnum: !SCALARS.has(fieldType),\n\t};\n}\n\nexport function parsePrismaSchema(source: string): PrismaSchema {\n\tconst clean = stripComments(source);\n\tconst models = new Map<string, PrismaModel>();\n\tconst enums = new Map<string, string[]>();\n\n\tfor (const block of extractBlocks(clean, \"enum\")) {\n\t\t// Tokenize so both single-line and multi-line enum bodies work\n\t\tconst values = block.body\n\t\t\t.split(/\\s+/)\n\t\t\t.filter((t) => /^[A-Za-z_]\\w*$/.test(t));\n\t\tenums.set(block.name.toLowerCase(), values);\n\t}\n\tfor (const block of extractBlocks(clean, \"model\")) {\n\t\tconst fields = block.body\n\t\t\t.split(\"\\n\")\n\t\t\t.map(parseFieldLine)\n\t\t\t.filter((f): f is FieldDef => f !== null);\n\t\tmodels.set(block.name.toLowerCase(), {\n\t\t\tname: block.name,\n\t\t\tfields,\n\t\t});\n\t}\n\treturn { models, enums };\n}\n\n/** Locate and parse the project's Prisma schema; null when absent/unparsable. */\nexport function loadPrismaSchema(): PrismaSchema | null {\n\tfor (const candidate of SCHEMA_CANDIDATES) {\n\t\tconst path = join(process.cwd(), candidate);\n\t\tif (!existsSync(path)) continue;\n\t\ttry {\n\t\t\treturn parsePrismaSchema(readFileSync(path, \"utf-8\"));\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\n\n/** Case-insensitive model lookup (plural route names like `users` also match). */\nexport function getEntityModel(\n\tentityName: string,\n\tschema?: PrismaSchema | null,\n): PrismaModel | null {\n\tconst s = schema ?? loadPrismaSchema();\n\tif (!s) return null;\n\tconst key = entityName.toLowerCase().replace(/s$/, \"\");\n\tfor (const [modelKey, model] of s.models) {\n\t\tif (modelKey === key || modelKey === entityName.toLowerCase()) return model;\n\t}\n\treturn null;\n}\n\nconst FIELD_TYPE_ALIASES: Record<string, string> = {\n\tstring: \"String\",\n\tint: \"Int\",\n\tinteger: \"Int\",\n\tfloat: \"Float\",\n\tnumber: \"Float\",\n\tdecimal: \"Decimal\",\n\tbigint: \"BigInt\",\n\tboolean: \"Boolean\",\n\tbool: \"Boolean\",\n\tdate: \"DateTime\",\n\tdatetime: \"DateTime\",\n\tjson: \"Json\",\n\tbytes: \"Bytes\",\n};\n\n/**\n * Universal fallback: `--fields title:string,body:string,published:boolean?`\n * Types: string, int, float, number, decimal, boolean, date, json (+ `[]`\n * for lists, `?` for optional).\n */\nexport function parseFieldsFlag(value: string): FieldDef[] {\n\tconst fields: FieldDef[] = [];\n\tfor (const part of value.split(\",\")) {\n\t\tconst trimmed = part.trim();\n\t\tif (!trimmed) continue;\n\t\tconst m = /^([A-Za-z_]\\w*)\\s*:\\s*([A-Za-z_]\\w*)(\\[\\])?(\\?)?$/.exec(trimmed);\n\t\tif (!m) continue;\n\t\tconst [, name = \"\", rawType = \"\", list, optional] = m;\n\t\tconst type = FIELD_TYPE_ALIASES[rawType.toLowerCase()] ?? rawType;\n\t\tfields.push({\n\t\t\tname,\n\t\t\ttype,\n\t\t\toptional: Boolean(optional),\n\t\t\tlist: Boolean(list),\n\t\t\tisId: false,\n\t\t\tunique: false,\n\t\t\thasDefault: false,\n\t\t\tisEnum: !SCALARS.has(type),\n\t\t});\n\t}\n\treturn fields;\n}\n\n/** Create inputs exclude auto-generated columns (@id w/ default, @updatedAt). */\nexport function isAutoGenerated(field: FieldDef): boolean {\n\treturn field.isId || field.hasDefault;\n}\n\nfunction zodScalar(field: FieldDef, schema?: PrismaSchema | null): string {\n\tconst inner = (() => {\n\t\tswitch (field.type) {\n\t\t\tcase \"String\":\n\t\t\t\treturn \"z.string()\";\n\t\t\tcase \"Int\":\n\t\t\t\treturn \"z.number().int()\";\n\t\t\tcase \"Float\":\n\t\t\tcase \"BigInt\":\n\t\t\t\treturn \"z.number()\";\n\t\t\tcase \"Decimal\":\n\t\t\t\treturn \"z.union([z.number(), z.string()])\";\n\t\t\tcase \"Boolean\":\n\t\t\t\treturn \"z.boolean()\";\n\t\t\tcase \"DateTime\":\n\t\t\t\treturn \"z.string()\";\n\t\t\tcase \"Json\":\n\t\t\tcase \"Bytes\":\n\t\t\t\treturn \"z.any()\";\n\t\t\tdefault: {\n\t\t\t\tconst enumValues = schema?.enums.get(field.type.toLowerCase());\n\t\t\t\tif (enumValues && enumValues.length > 0) {\n\t\t\t\t\treturn `z.enum([${enumValues.map((v) => `\"${v}\"`).join(\", \")}])`;\n\t\t\t\t}\n\t\t\t\treturn \"z.string()\";\n\t\t\t}\n\t\t}\n\t})();\n\treturn inner;\n}\n\nfunction zodFor(field: FieldDef, schema?: PrismaSchema | null): string {\n\tlet out = field.list ? `z.array(${zodScalar(field, schema)})` : zodScalar(field, schema);\n\tif (field.optional) out += \".optional()\";\n\treturn out;\n}\n\n/** Zod object body lines for the create schema (update = .partial()). */\nexport function zodLinesForFields(\n\tfields: FieldDef[],\n\tschema?: PrismaSchema | null,\n): string[] {\n\tconst used = new Set<string>();\n\tconst lines: string[] = [];\n\tfor (const field of fields) {\n\t\tif (isAutoGenerated(field) || used.has(field.name)) continue;\n\t\tused.add(field.name);\n\t\tlines.push(`${field.name}: ${zodFor(field, schema)},`);\n\t}\n\treturn lines;\n}\n\nfunction fakerFor(field: FieldDef, schema?: PrismaSchema | null): string {\n\tconst enumValues = field.isEnum\n\t\t? schema?.enums.get(field.type.toLowerCase())\n\t\t: undefined;\n\tconst scalar = (() => {\n\t\tif (enumValues && enumValues.length > 0) {\n\t\t\treturn `faker.helpers.arrayElement([${enumValues.map((v) => `\"${v}\"`).join(\", \")}])`;\n\t\t}\n\t\tswitch (field.type) {\n\t\t\tcase \"String\":\n\t\t\t\tif (/mail/i.test(field.name)) return \"faker.internet.email()\";\n\t\t\t\tif (/^name$|username|full_?name|first_?name|last_?name/i.test(field.name))\n\t\t\t\t\treturn \"faker.person.fullName()\";\n\t\t\t\tif (/url|href|link/i.test(field.name)) return \"faker.internet.url()\";\n\t\t\t\tif (/slug/i.test(field.name)) return \"faker.helpers.slug()\";\n\t\t\t\treturn \"faker.lorem.words()\";\n\t\t\tcase \"Int\":\n\t\t\t\treturn \"faker.number.int({ max: 10000 })\";\n\t\t\tcase \"Float\":\n\t\t\tcase \"Decimal\":\n\t\t\tcase \"BigInt\":\n\t\t\t\treturn \"faker.number.float()\";\n\t\t\tcase \"Boolean\":\n\t\t\t\treturn \"faker.datatype.boolean()\";\n\t\t\tcase \"DateTime\":\n\t\t\t\treturn \"faker.date.recent().toISOString()\";\n\t\t\tcase \"Json\":\n\t\t\tcase \"Bytes\":\n\t\t\t\treturn \"faker.lorem.sentence()\";\n\t\t\tdefault:\n\t\t\t\treturn \"faker.lorem.words()\";\n\t\t}\n\t})();\n\treturn field.list ? `Array.from({ length: 3 }, () => ${scalar})` : scalar;\n}\n\n/** Faker assignment lines for factory `build()` bodies. */\nexport function fakerLinesForFields(\n\tfields: FieldDef[],\n\tschema?: PrismaSchema | null,\n): string[] {\n\tconst used = new Set<string>();\n\tconst lines: string[] = [];\n\tfor (const field of fields) {\n\t\tif (isAutoGenerated(field) || used.has(field.name)) continue;\n\t\tused.add(field.name);\n\t\tlines.push(`${field.name}: ${fakerFor(field, schema)},`);\n\t}\n\treturn lines;\n}\n\nfunction tsTypeFor(field: FieldDef, schema?: PrismaSchema | null): string {\n\tconst base = (() => {\n\t\tif (field.isEnum) {\n\t\t\tconst values = schema?.enums.get(field.type.toLowerCase());\n\t\t\tif (values && values.length > 0) return values.map((v) => `\"${v}\"`).join(\" | \");\n\t\t\treturn \"string\";\n\t\t}\n\t\tswitch (field.type) {\n\t\t\tcase \"Int\":\n\t\t\tcase \"Float\":\n\t\t\tcase \"Decimal\":\n\t\t\tcase \"BigInt\":\n\t\t\t\treturn \"number\";\n\t\t\tcase \"Boolean\":\n\t\t\t\treturn \"boolean\";\n\t\t\tcase \"Json\":\n\t\t\tcase \"Bytes\":\n\t\t\t\treturn \"unknown\";\n\t\t\tdefault:\n\t\t\t\treturn \"string\";\n\t\t}\n\t})();\n\treturn field.list ? `${base}[]` : base;\n}\n\n/** TypeScript member lines for an inline model type (non-Prisma factories). */\nexport function tsLinesForFields(\n\tfields: FieldDef[],\n\tschema?: PrismaSchema | null,\n): string[] {\n\tconst used = new Set<string>();\n\tconst lines: string[] = [];\n\tfor (const field of fields) {\n\t\tif (used.has(field.name)) continue;\n\t\tused.add(field.name);\n\t\tconst optional = field.optional ? \"?\" : \"\";\n\t\tlines.push(`${field.name}${optional}: ${tsTypeFor(field, schema)};`);\n\t}\n\treturn lines;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport type ORM = \"prisma\" | \"drizzle\" | \"typeorm\";\n\n/**\n * Detect the project ORM from config files first (definitive), then\n * package.json dependencies. Returns null when nothing matches.\n */\nexport function detectORMOrNull(): ORM | null {\n\t// Config / schema files\n\tif (existsSync(\"prisma/schema.prisma\") || existsSync(\"prisma/schema.ts\")) {\n\t\treturn \"prisma\";\n\t}\n\tif (existsSync(\"drizzle.config.ts\") || existsSync(\"drizzle.config.js\")) {\n\t\treturn \"drizzle\";\n\t}\n\tif (\n\t\texistsSync(\"ormconfig.json\") ||\n\t\texistsSync(\"ormconfig.ts\") ||\n\t\texistsSync(\"ormconfig.js\")\n\t) {\n\t\treturn \"typeorm\";\n\t}\n\n\t// Dependencies\n\tif (existsSync(\"package.json\")) {\n\t\ttry {\n\t\t\tconst pkg = JSON.parse(readFileSync(\"package.json\", \"utf-8\"));\n\t\t\tconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\t\t\tif (deps[\"@prisma/client\"] || deps[\"prisma\"]) return \"prisma\";\n\t\t\tif (deps[\"drizzle-orm\"] || deps[\"drizzle-kit\"]) return \"drizzle\";\n\t\t\tif (deps[\"typeorm\"]) return \"typeorm\";\n\t\t} catch {\n\t\t\t// ignore parse errors\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/** Detect ORM with `prisma` as fallback (for generators). */\nexport function detectORM(): ORM {\n\treturn detectORMOrNull() ?? \"prisma\";\n}\n\n/** Candidate entry files, probed in order (union of dev/debug/scaffold). */\nexport const ENTRY_CANDIDATES = [\n\t\"server.ts\",\n\t\"src/index.ts\",\n\t\"src/main.ts\",\n\t\"src/app.ts\",\n\t\"src/server.ts\",\n\t\"index.ts\",\n] as const;\n\n/**\n * Find the app entry file (relative path) or null when none exists.\n * Prefers a candidate that actually hosts the app (listen/new App/export).\n */\nexport function findEntryFile(cwd: string = process.cwd()): string | null {\n\tconst existing: string[] = [];\n\tfor (const candidate of ENTRY_CANDIDATES) {\n\t\tif (existsSync(join(cwd, candidate))) existing.push(candidate);\n\t}\n\tif (existing.length === 0) return null;\n\tfor (const candidate of existing) {\n\t\ttry {\n\t\t\tconst src = readFileSync(join(cwd, candidate), \"utf-8\");\n\t\t\tif (/app\\.listen\\s*\\(|new\\s+App\\s*\\(|export\\s+default\\s+app/.test(src)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t} catch {\n\t\t\t// unreadable candidate — keep looking\n\t\t}\n\t}\n\treturn existing[0] ?? null;\n}\n\n/** Index just past a balanced `)` starting at openIndex (points at `(`). */\nfunction findBalancedClose(src: string, openIndex: number): number {\n\tlet depth = 0;\n\tfor (let i = openIndex; i < src.length; i++) {\n\t\tconst ch = src[i];\n\t\tif (ch === \"(\") depth++;\n\t\telse if (ch === \")\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return i;\n\t\t}\n\t}\n\treturn -1;\n}\n\n/**\n * End of a `const app = new App(...)` declaration (options object supported),\n * or null when there is no app declaration.\n */\nexport function findAppDeclEnd(src: string): number | null {\n\tconst m = src.match(/(?:export\\s+)?const\\s+app\\s*=\\s*new\\s+App\\s*\\(/);\n\tif (m?.index === undefined) return null;\n\tconst open = m.index + m[0].length - 1;\n\tconst close = findBalancedClose(src, open);\n\tif (close === -1) return null;\n\tlet end = close + 1;\n\tif (src[end] === \";\") end++;\n\treturn end;\n}\n\n/**\n * Find where to insert registration lines before app.listen / route\n * handlers / exports, with fallback chain. Returns insertion index and\n * the matched text starting at that index.\n */\nexport function findInsertionIndex(src: string): {\n\tindex: number;\n\tbefore: string;\n} {\n\t// Pattern 1: app.listen(\n\tconst listenMatch = src.match(/(app\\.listen\\s*\\()/);\n\tif (listenMatch?.index !== undefined && listenMatch[1]) {\n\t\treturn { index: listenMatch.index, before: listenMatch[1] };\n\t}\n\t// Pattern 2: app.get( or app.post( etc (route handlers)\n\tconst routeMatch = src.match(/\\n(app\\.(get|post|put|delete|patch|all|use)\\s*\\()/);\n\tif (routeMatch?.index !== undefined && routeMatch[1]) {\n\t\treturn { index: routeMatch.index + 1, before: routeMatch[1] };\n\t}\n\t// Pattern 3: export default app\n\tconst exportDefaultMatch = src.match(/\\n(export\\s+default\\s+app)/);\n\tif (exportDefaultMatch?.index !== undefined && exportDefaultMatch[1]) {\n\t\treturn { index: exportDefaultMatch.index + 1, before: exportDefaultMatch[1] };\n\t}\n\t// Pattern 4: export const app = new App(...) — insert after the\n\t// balanced declaration (options object supported)\n\tconst exportConstMatch = src.match(/export\\s+const\\s+app\\s*=\\s*new\\s+App\\s*\\(/);\n\tif (exportConstMatch?.index !== undefined) {\n\t\tconst open = exportConstMatch.index + exportConstMatch[0].length - 1;\n\t\tconst close = findBalancedClose(src, open);\n\t\tif (close !== -1) {\n\t\t\tlet end = close + 1;\n\t\t\tif (src[end] === \";\") end++;\n\t\t\treturn { index: end, before: \"\" };\n\t\t}\n\t}\n\t// Fallback: append at end\n\treturn { index: src.length, before: \"\" };\n}\n\n/** Add an import line after the last existing import (no duplicates). */\nexport function ensureImport(src: string, imp: string): string {\n\tif (src.includes(imp)) return src;\n\tconst lines = src.split(\"\\n\");\n\tlet lastImportIndex = -1;\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tif (lines[i]?.startsWith(\"import \")) {\n\t\t\tlastImportIndex = i;\n\t\t}\n\t}\n\tif (lastImportIndex !== -1) {\n\t\tlines.splice(lastImportIndex + 1, 0, imp);\n\t} else {\n\t\tlines.unshift(imp);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Collect controllers imported from @/modules/*.\n * excludeFromScan: skip controllers already passed to registerController.\n */\nexport function collectImportedControllers(\n\tsrc: string,\n\texcludeFromScan: boolean,\n): string[] {\n\tconst imports = src.match(\n\t\t/import\\s*\\{\\s*(\\w+Controller)\\s*\\}\\s*from\\s*[\"']@\\/modules\\/\\w+[\"']/g,\n\t);\n\tconst controllers: string[] = [];\n\tif (imports) {\n\t\tfor (const imp of imports) {\n\t\t\tconst match = imp.match(/\\{\\s*(\\w+Controller)\\s*\\}/);\n\t\t\tif (match?.[1]) {\n\t\t\t\tif (excludeFromScan) {\n\t\t\t\t\tconst rcSingleMatch = src.match(\n\t\t\t\t\t\tnew RegExp(`app\\\\.registerController\\\\((${match[1]})\\\\)`),\n\t\t\t\t\t);\n\t\t\t\t\tconst rcArrayMatch = src.match(\n\t\t\t\t\t\tnew RegExp(`app\\\\.registerController\\\\(\\\\[([^\\\\]]*?${match[1]}[^\\\\]]*?)\\\\]\\\\)`),\n\t\t\t\t\t);\n\t\t\t\t\tif (rcSingleMatch || rcArrayMatch) continue;\n\t\t\t\t}\n\t\t\t\tcontrollers.push(match[1]);\n\t\t\t}\n\t\t}\n\t}\n\treturn controllers;\n}\n\n/**\n * Format files with Biome when it is installed locally.\n * Skips silently when node_modules/.bin/biome is absent (avoids `bunx`\n * resolving to an unrelated npm package).\n */\nexport function formatWithBiome(paths: string[]): boolean {\n\tif (paths.length === 0) return false;\n\tconst bin = join(process.cwd(), \"node_modules\", \".bin\", \"biome\");\n\tif (!existsSync(bin) && !existsSync(`${bin}.cmd`)) return false;\n\tconst proc = Bun.spawnSync(\n\t\t[\"bunx\", \"biome\", \"format\", \"--write\", ...paths],\n\t\t{ stdio: [\"ignore\", \"ignore\", \"ignore\"] },\n\t);\n\treturn proc.exitCode === 0;\n}\n","import { detectORM, type ORM } from \"../project.js\";\nimport { toCamelCase } from \"../utils.js\";\n\nexport { detectORM };\nexport type { ORM };\n\nexport interface RepositoryOptions {\n\t/** Generate the BaseRepository-based variant (Prisma only). */\n\tbase?: boolean;\n}\n\nfunction generatePrismaRepository(entityName: string, pascalName: string): string {\n\tconst delegate = toCamelCase(entityName);\n\treturn `import { prisma } from \"@/lib/prisma\";\nimport type { ${pascalName}, Prisma } from \"@prisma/client\";\n\nexport class ${pascalName}Repository {\n  async findAll(): Promise<${pascalName}[]> {\n    return prisma.${delegate}.findMany();\n  }\n\n  async findById(id: string | number): Promise<${pascalName} | null> {\n    return prisma.${delegate}.findUnique({ where: { id: id as any } });\n  }\n\n  async create(data: Prisma.${pascalName}CreateInput): Promise<${pascalName}> {\n    return prisma.${delegate}.create({ data });\n  }\n\n  async update(id: string | number, data: Prisma.${pascalName}UpdateInput): Promise<${pascalName}> {\n    return prisma.${delegate}.update({ where: { id: id as any }, data });\n  }\n\n  async delete(id: string | number): Promise<${pascalName}> {\n    return prisma.${delegate}.delete({ where: { id: id as any } });\n  }\n\n  async count(): Promise<number> {\n    return prisma.${delegate}.count();\n  }\n}\n`;\n}\n\nfunction generatePrismaBaseRepository(\n\tentityName: string,\n\tpascalName: string,\n): string {\n\treturn `import { BaseRepository } from \"@buntok/prisma\";\nimport { prisma } from \"@/lib/prisma\";\nimport type { ${pascalName}, Prisma } from \"@prisma/client\";\n\nexport class ${pascalName}Repository extends BaseRepository<\n  ${pascalName},\n  Prisma.${pascalName}CreateInput,\n  Prisma.${pascalName}UpdateInput\n> {\n  constructor() {\n    super(prisma, \"${entityName}\");\n  }\n}\n`;\n}\n\nfunction generateDrizzleRepository(entityName: string, pascalName: string): string {\n\treturn `import { count, eq } from \"drizzle-orm\";\nimport { db } from \"@/lib/db\";\nimport { ${entityName} } from \"@/lib/db/schema\";\n\nexport class ${pascalName}Repository {\n  async findAll() {\n    return db.select().from(${entityName});\n  }\n\n  async findById(id: number) {\n    const results = await db.select().from(${entityName}).where(eq(${entityName}.id, id));\n    return results[0] ?? null;\n  }\n\n  async create(data: typeof ${entityName}.$inferInsert) {\n    const results = await db.insert(${entityName}).values(data).returning();\n    return results[0];\n  }\n\n  async update(id: number, data: typeof ${entityName}.$inferUpdate) {\n    const results = await db.update(${entityName}).set(data).where(eq(${entityName}.id, id)).returning();\n    return results[0];\n  }\n\n  async delete(id: number) {\n    await db.delete(${entityName}).where(eq(${entityName}.id, id));\n    return true;\n  }\n\n  async count(): Promise<number> {\n    const results = await db.select({ value: count() }).from(${entityName});\n    return results[0]?.value ?? 0;\n  }\n}\n`;\n}\n\nfunction generateTypeORMRepository(entityName: string, pascalName: string): string {\n\treturn `import { AppDataSource } from \"@/lib/data-source\";\nimport { ${pascalName} } from \"@/lib/entities/${pascalName}\";\n\nexport class ${pascalName}Repository {\n  private repo = AppDataSource.getRepository(${pascalName});\n\n  async findAll() {\n    return this.repo.find();\n  }\n\n  async findById(id: number) {\n    return this.repo.findOneBy({ id });\n  }\n\n  async create(data: Partial<${pascalName}>) {\n    return this.repo.save(this.repo.create(data));\n  }\n\n  async update(id: number, data: Partial<${pascalName}>) {\n    await this.repo.update(id, data);\n    return this.repo.findOneBy({ id });\n  }\n\n  async delete(id: number) {\n    await this.repo.delete(id);\n    return true;\n  }\n\n  async count(): Promise<number> {\n    return this.repo.count();\n  }\n}\n`;\n}\n\n/**\n * Generate repository file content based on ORM.\n * Default is plain (explicit CRUD methods); `options.base` opts into the\n * BaseRepository variant (Prisma only — Drizzle/TypeORM stay plain).\n */\nexport function generateRepository(\n\tentityName: string,\n\tpascalName: string,\n\torm?: ORM,\n\toptions?: RepositoryOptions,\n): string {\n\tconst detectedOrm = orm ?? detectORM();\n\n\tswitch (detectedOrm) {\n\t\tcase \"drizzle\":\n\t\t\treturn generateDrizzleRepository(entityName, pascalName);\n\t\tcase \"typeorm\":\n\t\t\treturn generateTypeORMRepository(entityName, pascalName);\n\t\tcase \"prisma\":\n\t\tdefault:\n\t\t\treturn options?.base\n\t\t\t\t? generatePrismaBaseRepository(entityName, pascalName)\n\t\t\t\t: generatePrismaRepository(entityName, pascalName);\n\t}\n}\n","import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { toPascalCase } from \"../utils.js\";\n\ninterface SchemaOptions {\n\t/** Zod object body lines (from the Prisma model or `--fields`). */\n\tlines?: string[] | null;\n}\n\nfunction generateSchema(\n\tname: string,\n\tpascalName: string,\n\toptions?: SchemaOptions,\n): string {\n\tconst body =\n\t\toptions?.lines && options.lines.length > 0\n\t\t\t? options.lines.map((l) => `  ${l}`).join(\"\\n\")\n\t\t\t: `  name: z.string().min(1).max(100),\\n  // TODO: Add more fields`;\n\treturn `import { z } from \"@buntok/core/middlewares/validator\";\n\nexport const Create${pascalName}Schema = z.object({\n${body}\n});\n\nexport const Update${pascalName}Schema = Create${pascalName}Schema.partial();\n\nexport type Create${pascalName}Input = z.infer<typeof Create${pascalName}Schema>;\nexport type Update${pascalName}Input = z.infer<typeof Update${pascalName}Schema>;\n`;\n}\n\nexport async function generateSchemaFile(\n\tname: string,\n\tmoduleDir: string,\n\tforce = false,\n\toptions?: SchemaOptions,\n): Promise<string | null> {\n\tconst pascalName = toPascalCase(name);\n\tconst filePath = join(moduleDir, `${name}.schema.ts`);\n\n\tif (existsSync(filePath) && !force) {\n\t\treturn null;\n\t}\n\n\tawait fs.writeFile(filePath, generateSchema(name, pascalName, options));\n\treturn filePath;\n}\n","import type { ORM } from \"./repository.js\";\nimport { toCamelCase } from \"../utils.js\";\n\nexport interface ServiceOptions {\n\t/** Generate the BaseService-based variant. */\n\tbase?: boolean;\n}\n\nfunction getPrismaType(pascalName: string): string {\n\treturn `import type { ${pascalName} } from \"@prisma/client\";`;\n}\n\nfunction getDrizzleType(_entityName: string): string {\n\treturn `import type { InferSelectModel } from \"drizzle-orm\";\nimport { ${_entityName} } from \"@/lib/db/schema\";\n\ntype ${_entityName.charAt(0).toUpperCase() + _entityName.slice(1)} = InferSelectModel<typeof ${_entityName}>;`;\n}\n\nfunction getTypeORMType(pascalName: string): string {\n\treturn `import type { ${pascalName} } from \"@/lib/entities/${pascalName}\";`;\n}\n\nfunction resolveTypeRef(\n\tentityName: string,\n\tpascalName: string,\n\tdetectedOrm: ORM,\n): { typeImport: string; typeRef: string } {\n\tswitch (detectedOrm) {\n\t\tcase \"drizzle\":\n\t\t\treturn { typeImport: getDrizzleType(entityName), typeRef: pascalName };\n\t\tcase \"typeorm\":\n\t\t\treturn { typeImport: getTypeORMType(pascalName), typeRef: pascalName };\n\t\tcase \"prisma\":\n\t\tdefault:\n\t\t\treturn { typeImport: getPrismaType(pascalName), typeRef: pascalName };\n\t}\n}\n\nfunction generatePlainService(\n\tentityName: string,\n\tpascalName: string,\n\ttypeImport: string,\n\ttypeRef: string,\n): string {\n\tconst repoProp = `${toCamelCase(entityName)}Repository`;\n\treturn `import { Dependencies, NotFoundError } from \"@buntok/core\";\nimport { ${pascalName}Repository } from \"./${entityName}.repository\";\n${typeImport}\n\n@Dependencies(${pascalName}Repository)\nexport class ${pascalName}Service {\n  constructor(private readonly ${repoProp}: ${pascalName}Repository) {}\n\n  async getAll(): Promise<${typeRef}[]> {\n    return this.${repoProp}.findAll();\n  }\n\n  async getById(id: string | number): Promise<${typeRef}> {\n    const item = await this.${repoProp}.findById(id);\n    if (!item) throw new NotFoundError(\\`Data dengan id \\${id} tidak ditemukan\\`);\n    return item;\n  }\n\n  async create(data: any): Promise<${typeRef}> {\n    return this.${repoProp}.create(data);\n  }\n\n  async update(id: string | number, data: any): Promise<${typeRef}> {\n    await this.getById(id);\n    return this.${repoProp}.update(id, data);\n  }\n\n  async delete(id: string | number): Promise<${typeRef} | boolean> {\n    await this.getById(id);\n    return this.${repoProp}.delete(id);\n  }\n\n  async count(): Promise<number> {\n    return this.${repoProp}.count();\n  }\n}\n`;\n}\n\nfunction generateBaseService(\n\tentityName: string,\n\tpascalName: string,\n\ttypeImport: string,\n\ttypeRef: string,\n): string {\n\tconst repoProp = `${toCamelCase(entityName)}Repository`;\n\treturn `import { Dependencies, BaseService } from \"@buntok/core\";\nimport { ${pascalName}Repository } from \"./${entityName}.repository\";\n${typeImport}\n\n@Dependencies(${pascalName}Repository)\nexport class ${pascalName}Service extends BaseService<${typeRef}> {\n  constructor(private readonly ${repoProp}: ${pascalName}Repository) {\n    super(${repoProp});\n  }\n}\n`;\n}\n\nexport function generateService(\n\tentityName: string,\n\tpascalName: string,\n\twithRepo: boolean = true,\n\torm?: ORM,\n\toptions?: ServiceOptions,\n): string {\n\tif (withRepo) {\n\t\tconst detectedOrm = orm ?? \"prisma\";\n\t\tconst { typeImport, typeRef } = resolveTypeRef(\n\t\t\tentityName,\n\t\t\tpascalName,\n\t\t\tdetectedOrm,\n\t\t);\n\n\t\treturn options?.base\n\t\t\t? generateBaseService(entityName, pascalName, typeImport, typeRef)\n\t\t\t: generatePlainService(entityName, pascalName, typeImport, typeRef);\n\t}\n\n\treturn `export class ${pascalName}Service {\n  async getAll(): Promise<any[]> {\n    return [];\n  }\n\n  async getById(id: string): Promise<any> {\n    return { id };\n  }\n\n  async create(data: any): Promise<any> {\n    return data;\n  }\n\n  async update(id: string, data: any): Promise<any> {\n    return { id, ...data };\n  }\n\n  async delete(id: string): Promise<boolean> {\n    return true;\n  }\n}\n`;\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Static route scanner: parses `@Controller` / `@Get` / `@Post` / ... string\n * literals from source files — no app import, no runtime needed.\n */\n\nexport interface ScannedRoute {\n\tfile: string;\n\tcontroller: string | null;\n\tmethod: string;\n\tpath: string;\n\tline: number;\n}\n\nconst SKIP_DIRS = new Set([\n\t\"node_modules\",\n\t\"dist\",\n\t\".buntok\",\n\t\".git\",\n\t\"build\",\n\t\"coverage\",\n]);\n\nfunction walk(dir: string, out: string[]): void {\n\tlet entries: string[];\n\ttry {\n\t\tentries = readdirSync(dir);\n\t} catch {\n\t\treturn;\n\t}\n\tfor (const entry of entries) {\n\t\tif (entry.startsWith(\".\") && entry !== \".\") continue;\n\t\tconst full = join(dir, entry);\n\t\tif (SKIP_DIRS.has(entry)) continue;\n\t\ttry {\n\t\t\tif (statSync(full).isDirectory()) walk(full, out);\n\t\t\telse if (entry.endsWith(\".ts\") && !entry.endsWith(\".d.ts\")) out.push(full);\n\t\t} catch {\n\t\t\t// unreadable entries are skipped\n\t\t}\n\t}\n}\n\nfunction normalizePath(...segments: string[]): string {\n\tlet path = segments\n\t\t.filter((s) => s !== \"\")\n\t\t.join(\"\")\n\t\t.replace(/\\/{2,}/g, \"/\");\n\tif (!path.startsWith(\"/\")) path = `/${path}`;\n\tif (path.length > 1 && path.endsWith(\"/\")) path = path.slice(0, -1);\n\treturn path;\n}\n\nfunction joinRoutePath(prefix: string, methodPath: string): string {\n\tconst left = prefix.startsWith(\"/\") ? prefix : `/${prefix}`;\n\tconst right = methodPath.startsWith(\"/\") ? methodPath : `/${methodPath}`;\n\treturn normalizePath(`${left}${right}`);\n}\n\nconst HTTP_METHODS = [\n\t\"Get\",\n\t\"Post\",\n\t\"Put\",\n\t\"Patch\",\n\t\"Delete\",\n\t\"All\",\n\t\"Options\",\n\t\"Head\",\n] as const;\n\n/** Scan one file's content for controller-prefixed HTTP routes. */\nexport function scanRoutesInFile(file: string, content: string): ScannedRoute[] {\n\tconst routes: ScannedRoute[] = [];\n\tconst controllerMatch = content.match(\n\t\t/@Controller\\s*\\(\\s*[\"'`]([^\"'`]*)[\"'`]\\s*\\)/,\n\t);\n\tconst controllerPath = controllerMatch?.[1] ?? null;\n\tconst controllerName =\n\t\tcontent.match(/export\\s+(?:default\\s+)?class\\s+(\\w+)/)?.[1] ?? null;\n\tconst controllerLine = controllerMatch\n\t\t? content.slice(0, controllerMatch.index ?? 0).split(\"\\n\").length\n\t\t: 1;\n\n\tfor (const method of HTTP_METHODS) {\n\t\tconst re = new RegExp(`@${method}\\\\s*\\\\(\\\\s*[\"'\\`]([^\"\\`]*)[\"'\\`]\\\\s*\\\\)`, \"g\");\n\t\tlet m: RegExpExecArray | null;\n\t\twhile ((m = re.exec(content)) !== null) {\n\t\t\t// Skip decorator references inside comments\n\t\t\tconst before = content.slice(0, m.index);\n\t\t\tconst lastLineStart = before.lastIndexOf(\"\\n\") + 1;\n\t\t\tif (before.slice(lastLineStart).trimStart().startsWith(\"//\")) continue;\n\t\t\troutes.push({\n\t\t\t\tfile,\n\t\t\t\tcontroller: controllerName,\n\t\t\t\tmethod: method === \"All\" ? \"ALL\" : method.toUpperCase(),\n\t\t\t\tpath: joinRoutePath(controllerPath ?? \"\", m[1] ?? \"\"),\n\t\t\t\tline: before.split(\"\\n\").length,\n\t\t\t});\n\t\t}\n\t}\n\n\t// BaseController subclasses inherit the five pre-decorated CRUD routes.\n\tif (controllerPath !== null && /extends\\s+BaseController\\b/.test(content)) {\n\t\tconst inherited: [string, string][] = [\n\t\t\t[\"GET\", \"/\"],\n\t\t\t[\"GET\", \"/:id\"],\n\t\t\t[\"POST\", \"/\"],\n\t\t\t[\"PUT\", \"/:id\"],\n\t\t\t[\"DELETE\", \"/:id\"],\n\t\t];\n\t\tconst ownKeys = new Set(routes.map((r) => `${r.method} ${r.path}`));\n\t\tfor (const [method, path] of inherited) {\n\t\t\tconst fullPath = joinRoutePath(controllerPath, path);\n\t\t\tconst key = `${method} ${fullPath}`;\n\t\t\t// Own decorators override inherited methods (base route shadowed)\n\t\t\tif (ownKeys.has(key)) continue;\n\t\t\troutes.push({\n\t\t\t\tfile,\n\t\t\t\tcontroller: controllerName,\n\t\t\t\tmethod,\n\t\t\t\tpath: fullPath,\n\t\t\t\tline: controllerLine,\n\t\t\t});\n\t\t}\n\t}\n\treturn routes;\n}\n\n/** Scan all TypeScript files under src for decorated routes. */\nexport function scanRoutes(cwd: string = process.cwd()): ScannedRoute[] {\n\tconst srcDir = join(cwd, \"src\");\n\tif (!existsSync(srcDir)) return [];\n\tconst files: string[] = [];\n\twalk(srcDir, files);\n\tconst routes: ScannedRoute[] = [];\n\tfor (const file of files) {\n\t\ttry {\n\t\t\troutes.push(...scanRoutesInFile(file, readFileSync(file, \"utf-8\")));\n\t\t} catch {\n\t\t\t// unreadable file\n\t\t}\n\t}\n\treturn routes;\n}\n\nexport interface RouteConflict {\n\tkey: string;\n\troutes: ScannedRoute[];\n}\n\n/** Group routes sharing the same METHOD + normalized path. */\nexport function findDuplicateRoutes(routes: ScannedRoute[]): RouteConflict[] {\n\tconst byKey = new Map<string, ScannedRoute[]>();\n\tfor (const route of routes) {\n\t\tconst key = `${route.method} ${route.path}`;\n\t\tconst group = byKey.get(key);\n\t\tif (group) group.push(route);\n\t\telse byKey.set(key, [route]);\n\t}\n\tconst conflicts: RouteConflict[] = [];\n\tfor (const [key, group] of byKey) {\n\t\tif (group.length > 1) conflicts.push({ key, routes: group });\n\t}\n\treturn conflicts;\n}\n\n/** Print conflicts; returns true when duplicates were found. */\nexport function warnDuplicateRoutes(\n\troutes: ScannedRoute[],\n\tcwd: string = process.cwd(),\n): boolean {\n\tconst conflicts = findDuplicateRoutes(routes);\n\tif (conflicts.length === 0) return false;\n\tfor (const conflict of conflicts) {\n\t\tconsole.log(`\\n\\x1b[33m⚠ Duplicate route: ${conflict.key}\\x1b[0m`);\n\t\tfor (const r of conflict.routes) {\n\t\t\tconst rel = r.file.startsWith(cwd) ? r.file.slice(cwd.length + 1) : r.file;\n\t\t\tconsole.log(`    ${rel}:${r.line} (${r.controller ?? \"anonymous\"})`);\n\t\t}\n\t}\n\treturn true;\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { detectORMOrNull, type ORM } from \"../project.js\";\nimport { dbSeedCommand } from \"./db-seed.js\";\n\ntype DbCommand = \"migrate\" | \"seed\" | \"reset\" | \"generate\" | \"studio\" | \"status\";\n\nfunction runCommand(cmd: string, dryRun = false): void {\n\tif (dryRun) {\n\t\tconsole.log(`\\x1b[90m[dry-run] Would execute: ${cmd}\\x1b[0m`);\n\t\treturn;\n\t}\n\tconsole.log(`\\x1b[90m$ ${cmd}\\x1b[0m`);\n\ttry {\n\t\texecSync(cmd, { stdio: \"inherit\", cwd: process.cwd() });\n\t} catch {\n\t\t// Command already printed its error\n\t\tprocess.exitCode = 1;\n\t}\n}\n\nasync function confirm(message: string): Promise<boolean> {\n\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\treturn new Promise((resolve) => {\n\t\trl.question(`\\x1b[33m${message} (y/N): \\x1b[0m`, (answer) => {\n\t\t\trl.close();\n\t\t\tresolve(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n\t\t});\n\t});\n}\n\nfunction prismaCommand(subcommand: string, args: string[], dryRun = false): void {\n\tconst cmd = `npx prisma ${subcommand} ${args.join(\" \")}`.trim();\n\trunCommand(cmd, dryRun);\n}\n\nfunction drizzleCommand(subcommand: string, args: string[], dryRun = false): void {\n\tconst commands: Record<string, string> = {\n\t\tmigrate: \"drizzle-kit generate\",\n\t\tseed: \"drizzle-kit seed\",\n\t\treset: \"drizzle-kit drop\",\n\t\tstatus: \"drizzle-kit check\",\n\t\tgenerate: \"drizzle-kit generate\",\n\t\tstudio: \"drizzle-kit studio\",\n\t};\n\tconst cmd = `${commands[subcommand] ?? subcommand} ${args.join(\" \")}`.trim();\n\trunCommand(cmd, dryRun);\n}\n\nfunction typeormCommand(subcommand: string, args: string[], dryRun = false): void {\n\tconst commands: Record<string, string> = {\n\t\tmigrate: \"typeorm migration:run\",\n\t\tseed: \"typeorm seed\",\n\t\treset: \"typeorm migration:revert\",\n\t\tgenerate: \"typeorm migration:generate\",\n\t\tstatus: \"typeorm migration:show\",\n\t\tstudio: \"echo 'TypeORM does not have a built-in studio command'\",\n\t};\n\tconst cmd = `${commands[subcommand] ?? subcommand} ${args.join(\" \")}`.trim();\n\trunCommand(cmd, dryRun);\n}\n\nfunction printUsage(): void {\n\tconsole.log(`\n\\x1b[36mUsage:\\x1b[0m\n  buntok db <command> [args] [flags]\n\n\\x1b[36mCommands:\\x1b[0m\n  migrate [name]      Run pending migrations\n  seed                Seed database\n  reset               Reset database (drop & recreate)\n  generate            Generate migration from schema changes\n  studio              Open database GUI\n  status              Show migration status\n\n\\x1b[36mFlags:\\x1b[0m\n  --dry-run           Preview command without executing\n\n\\x1b[36mSupported ORMs:\\x1b[0m\n  Prisma, Drizzle, TypeORM (auto-detected)\n\n\\x1b[36mExamples:\\x1b[0m\n  buntok db migrate                    # Run pending migrations\n  buntok db migrate add user_table     # Create new migration\n  buntok db seed                       # Seed database\n  buntok db studio                     # Open Prisma Studio / etc\n  buntok db reset --dry-run            # Preview reset command\n`);\n}\n\nconst DESTRUCTIVE_COMMANDS: DbCommand[] = [\"reset\"];\n\n/**\n * A project-level seed configuration takes precedence (e.g. Prisma's\n * `prisma.seed` key in package.json). Otherwise, if the local seeders\n * directory exists, `buntok db seed` runs them via the built-in runner.\n */\nfunction hasOrmSeedConfig(orm: ORM): boolean {\n\tif (orm !== \"prisma\" || !existsSync(\"package.json\")) return false;\n\ttry {\n\t\tconst pkg = JSON.parse(readFileSync(\"package.json\", \"utf-8\")) as {\n\t\t\tprisma?: { seed?: unknown };\n\t\t};\n\t\treturn Boolean(pkg.prisma?.seed);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function dbCommand(args: string[]): Promise<void> {\n\tconst subcommand = args[0] as DbCommand | undefined;\n\n\tif (!subcommand) {\n\t\tprintUsage();\n\t\treturn;\n\t}\n\n\tconst validCommands: DbCommand[] = [\"migrate\", \"seed\", \"reset\", \"generate\", \"studio\", \"status\"];\n\tif (!validCommands.includes(subcommand)) {\n\t\tconsole.error(`\\x1b[31mUnknown command: ${subcommand}\\x1b[0m`);\n\t\tprintUsage();\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst orm = detectORMOrNull();\n\tif (!orm) {\n\t\tconsole.error(\"\\x1b[31mCould not detect ORM.\\x1b[0m\");\n\t\tconsole.error(\"Supported: Prisma, Drizzle, TypeORM\");\n\t\tconsole.error(\"Make sure you have one installed in package.json.\");\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst dryRun = args.includes(\"--dry-run\");\n\tconst subArgs = args.slice(1).filter((a) => a !== \"--dry-run\");\n\n\tconsole.log(`\\x1b[36mDetected ORM: ${orm}\\x1b[0m`);\n\n\t// Local seeders fallback: `buntok db seed` runs src/db/seeders directly\n\t// when the ORM has no seed configuration of its own.\n\tif (subcommand === \"seed\" && !hasOrmSeedConfig(orm)) {\n\t\tconst localSeeders = join(\"src\", \"db\", \"seeders\");\n\t\tif (existsSync(localSeeders)) {\n\t\t\tif (dryRun) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`\\x1b[90m[dry-run] Would run local seeders from ${localSeeders} (orm: ${orm})\\x1b[0m`,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait dbSeedCommand(orm);\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Confirmation for destructive commands\n\tif (DESTRUCTIVE_COMMANDS.includes(subcommand) && !dryRun) {\n\t\tconst confirmed = await confirm(\n\t\t\t`\\x1b[31mWARNING: This will ${subcommand} the database. Continue?\\x1b[0m`,\n\t\t);\n\t\tif (!confirmed) {\n\t\t\tconsole.log(\"\\x1b[90mAborted.\\x1b[0m\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\tswitch (orm) {\n\t\tcase \"prisma\":\n\t\t\tprismaCommand(subcommand, subArgs, dryRun);\n\t\t\tbreak;\n\t\tcase \"drizzle\":\n\t\t\tdrizzleCommand(subcommand, subArgs, dryRun);\n\t\t\tbreak;\n\t\tcase \"typeorm\":\n\t\t\ttypeormCommand(subcommand, subArgs, dryRun);\n\t\t\tbreak;\n\t}\n}\n","import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { detectORMOrNull, type ORM } from \"../project.js\";\n\nexport async function dbSeedCommand(orm?: ORM) {\n\tconst detectedOrm = orm ?? detectORMOrNull() ?? \"prisma\";\n\tconsole.log(\"\\x1b[36mRunning Database Seeders...\\x1b[0m\\n\");\n\n\tconst seederDir = resolve(process.cwd(), \"src/db/seeders\");\n\n\tif (!existsSync(seederDir)) {\n\t\tconsole.warn(\n\t\t\t`\\x1b[33mWarning: No seeders directory found at ${seederDir}\\x1b[0m`,\n\t\t);\n\t\treturn;\n\t}\n\n\tconst files = await fs.readdir(seederDir);\n\tconst seederFiles = files.filter(\n\t\t(f) => f.endsWith(\".ts\") && !f.endsWith(\".d.ts\") && !f.startsWith(\".\"),\n\t);\n\n\tif (seederFiles.length === 0) {\n\t\tconsole.log(\"\\x1b[90mNo seeders to run.\\x1b[0m\");\n\t\treturn;\n\t}\n\n\t// TypeORM needs an initialized DataSource; Prisma/Drizzle connect lazily\n\tconst preamble =\n\t\tdetectedOrm === \"typeorm\"\n\t\t\t? `import { AppDataSource } from \"@/lib/data-source\";\\nawait AppDataSource.initialize();\\n`\n\t\t\t: \"\";\n\tconst epilogue =\n\t\tdetectedOrm === \"typeorm\" ? `\\n  await AppDataSource.destroy();` : \"\";\n\n\t// Create a temporary runner script to execute all seeders in the user's app context\n\tconst runnerContent = `${seederFiles.map((file, i) => `import * as seeder${i} from \"./${file.replace(\".ts\", \"\")}\";`).join(\"\\n\")}\n${preamble}\nasync function runSeeders() {\n  console.log(\"🌱 Starting database seeding...\");\n  \n  try {\n    ${seederFiles\n\t\t\t.map(\n\t\t\t\t(_file, i) => `\n    for (const key of Object.keys(seeder${i})) {\n      if (typeof (seeder${i} as any)[key] === 'function') {\n        await (seeder${i} as any)[key]();\n      }\n    }`,\n\t\t\t)\n\t\t\t.join(\"\\n    \")}\n    \n    console.log(\"✅ All seeders executed successfully!\");${epilogue}\n    process.exit(0);\n  } catch (error) {\n    console.error(\"❌ Seeding failed:\", error);\n    process.exit(1);\n  }\n}\n\nrunSeeders();\n`;\n\n\tconst runnerPath = join(seederDir, \".runner.ts\");\n\tawait fs.writeFile(runnerPath, runnerContent);\n\n\ttry {\n\t\tconst proc = Bun.spawnSync([\"bun\", \"run\", runnerPath], {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: [\"inherit\", \"inherit\", \"inherit\"],\n\t\t});\n\n\t\tif (proc.exitCode !== 0) {\n\t\t\tconsole.error(\"\\x1b[31mSeeding process failed.\\x1b[0m\");\n\t\t}\n\t} finally {\n\t\t// Cleanup temporary runner\n\t\tif (existsSync(runnerPath)) {\n\t\t\tawait fs.unlink(runnerPath);\n\t\t}\n\t}\n}\n","import { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { findEntryFile } from \"../project.js\";\n\nfunction getMethodColor(method: string): string {\n\tswitch (method) {\n\t\tcase \"GET\": return \"\\x1b[32m\";    // green\n\t\tcase \"POST\": return \"\\x1b[33m\";   // yellow\n\t\tcase \"PUT\": return \"\\x1b[34m\";    // blue\n\t\tcase \"PATCH\": return \"\\x1b[35m\";  // magenta\n\t\tcase \"DELETE\": return \"\\x1b[31m\"; // red\n\t\tcase \"OPTIONS\": return \"\\x1b[36m\"; // cyan\n\t\tcase \"HEAD\": return \"\\x1b[37m\";   // white\n\t\tdefault: return \"\\x1b[37m\";      // white\n\t}\n}\n\nfunction printRouteTable(routes: any[]): void {\n\tif (routes.length === 0) {\n\t\tconsole.log(\"\\x1b[33mNo routes found.\\x1b[0m\");\n\t\treturn;\n\t}\n\n\t// Calculate column widths\n\tconst methodWidth = Math.max(6, ...routes.map((r: any) => r.method.length));\n\tconst pathWidth = Math.max(4, ...routes.map((r: any) => r.path.length));\n\tconst mwWidth = Math.max(11, ...routes.map((r: any) => {\n\t\tconst mw = (r.middlewares || []).join(\", \");\n\t\treturn mw.length > 40 ? 40 : mw.length;\n\t}));\n\tconst handlerWidth = Math.max(7, ...routes.map((r: any) => (r.handler || \"anonymous\").length));\n\n\t// Print header\n\tconst header = [\n\t\t\"Method\".padEnd(methodWidth),\n\t\t\"Path\".padEnd(pathWidth),\n\t\t\"Middlewares\".padEnd(mwWidth),\n\t\t\"Handler\".padEnd(handlerWidth),\n\t].join(\" │ \");\n\n\tconst separator = [\n\t\t\"─\".repeat(methodWidth),\n\t\t\"─\".repeat(pathWidth),\n\t\t\"─\".repeat(mwWidth),\n\t\t\"─\".repeat(handlerWidth),\n\t].join(\"─┼─\");\n\n\tconsole.log(`\\x1b[1m${header}\\x1b[0m`);\n\tconsole.log(separator);\n\n\t// Print rows\n\tfor (const route of routes) {\n\t\tconst methodColor = getMethodColor(route.method);\n\t\tconst mwStr = (route.middlewares || []).length > 0 ? route.middlewares.join(\", \") : \"—\";\n\t\tconst truncatedMw = mwStr.length > 40 ? mwStr.slice(0, 37) + \"...\" : mwStr;\n\n\t\tconst row = [\n\t\t\t`${methodColor}${route.method.padEnd(methodWidth)}\\x1b[0m`,\n\t\t\troute.path.padEnd(pathWidth),\n\t\t\ttruncatedMw.padEnd(mwWidth),\n\t\t\t(route.handler || \"anonymous\").padEnd(handlerWidth),\n\t\t].join(\" │ \");\n\n\t\tconsole.log(row);\n\t}\n\n\t// Print summary\n\tconsole.log(`\\n\\x1b[36m${routes.length} routes registered\\x1b[0m`);\n}\n\nfunction printSourceSummary(routes: any[]): void {\n\tconst bySource: Record<string, any[]> = {};\n\tfor (const route of routes) {\n\t\tconst key = route.controller || route.group || route.source || \"direct\";\n\t\tif (!bySource[key]) bySource[key] = [];\n\t\tbySource[key].push(route);\n\t}\n\n\tconst sources = Object.keys(bySource);\n\tif (sources.length <= 1) return;\n\n\tconsole.log(`\\n\\x1b[36mBy source:\\x1b[0m`);\n\tfor (const source of sources) {\n\t\tconst count = bySource[source]?.length ?? 0;\n\t\tconsole.log(`  ${source}: ${count} routes`);\n\t}\n}\n\nexport async function debugRoutesCommand(flags: string[]): Promise<void> {\n\tconst isJson = flags.includes(\"--json\");\n\tconst targetDir = process.cwd();\n\n\t// Find the user's app entry point (shared candidate list + content probe)\n\tconst entry = findEntryFile(targetDir);\n\n\tif (!entry) {\n\t\tconsole.error(\"\\x1b[31mError: Could not find app entry point (server.ts, src/index.ts, src/main.ts, src/app.ts, or src/server.ts)\\x1b[0m\");\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\tconst entryFile = resolve(targetDir, entry);\n\n\ttry {\n\t\t// Import the user's app to trigger route registration\n\t\tconst fileUrl = pathToFileURL(entryFile).href;\n\t\tconst mod = await import(fileUrl);\n\n\t\t// Find the app instance — check default export and named exports\n\t\tlet app: any = null;\n\t\tif (mod.default && mod.default.routeDebugInfo) {\n\t\t\tapp = mod.default;\n\t\t} else {\n\t\t\t// Search all exports for an app-like object\n\t\t\tfor (const key of Object.keys(mod)) {\n\t\t\t\tif (mod[key] && mod[key].routeDebugInfo) {\n\t\t\t\t\tapp = mod[key];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!app) {\n\t\t\tconsole.error(\"\\x1b[31mError: Could not find App instance with routeDebugInfo. Make sure your entry point exports a Buntok App instance.\\x1b[0m\");\n\t\t\tprocess.exitCode = 1;\n\t\t\treturn;\n\t\t}\n\n\t\tconst routes = app.routeDebugInfo || [];\n\n\t\tif (isJson) {\n\t\t\tconsole.log(JSON.stringify(routes, null, 2));\n\t\t} else {\n\t\t\tprintRouteTable(routes);\n\t\t\tprintSourceSummary(routes);\n\t\t}\n\t} catch (err: any) {\n\t\tconsole.error(`\\x1b[31mError importing app: ${err.message}\\x1b[0m`);\n\t\tif (err.stack) {\n\t\t\tconsole.error(`\\x1b[90m${err.stack}\\x1b[0m`);\n\t\t}\n\t\tprocess.exitCode = 1;\n\t}\n}\n","import { resolve } from \"node:path\";\nimport { buildChildEnv, loadEnvFiles, watchEnvFiles, type LoadedEnv } from \"../env.js\";\nimport { findEntryFile } from \"../project.js\";\n\nexport async function devCommand(flags: string[]): Promise<void> {\n\tconst isExpose = flags.includes(\"--expose\");\n\tconst port = flags.find(f => f.startsWith(\"--port=\"))?.split(\"=\")[1] || \"1212\";\n\n\tconst targetDir = process.cwd();\n\n\t// Find the user's entry point (shared candidate list + content probe)\n\tconst entry = findEntryFile(targetDir);\n\n\tif (!entry) {\n\t\tconsole.error(\"\\x1b[31mError: Could not find app entry point (server.ts, src/index.ts, src/main.ts, src/app.ts, or src/server.ts)\\x1b[0m\");\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\tconst entryFile = resolve(targetDir, entry);\n\n\t// Build dev command\n\tconst args = [\"--watch\", entryFile];\n\n\t// Resolve the tunnel before spawning so a missing localtunnel never leaves\n\t// an orphan server process behind.\n\tlet tunnel: { url: string; close: () => Promise<unknown> } | undefined;\n\tif (isExpose) {\n\t\tconsole.log(\"\\x1b[36mStarting development server with tunnel...\\x1b[0m\\n\");\n\t\ttry {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: optional dynamic import\n\t\t\tconst lt = await import(\"localtunnel\" as string);\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: optional dynamic import\n\t\t\ttunnel = await (lt as any).default({\n\t\t\t\tport: Number.parseInt(port),\n\t\t\t\tsubdomain: `buntok-${Date.now()}`,\n\t\t\t});\n\t\t} catch (err: any) {\n\t\t\tif (err.message?.includes(\"Cannot find module\") || err.code === \"ERR_MODULE_NOT_FOUND\") {\n\t\t\t\tconsole.error(\"\\x1b[31mError: localtunnel is required for --expose flag\\x1b[0m\");\n\t\t\t\tconsole.error(\"Install it with: \\x1b[36mbun add -d localtunnel\\x1b[0m\");\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t// Environment for the child: parent values minus stale .env keys, overlaid\n\t// with the freshly parsed .env files. Bun lets the environment win over\n\t// .env files, so the merge has to be explicit whenever .env changes.\n\tlet envKeys = new Set<string>();\n\tconst nextEnv = (fresh: LoadedEnv): Record<string, string> => {\n\t\tconst env = buildChildEnv(process.env, envKeys, fresh, {\n\t\t\tNODE_ENV: \"development\",\n\t\t\tPORT: port,\n\t\t});\n\t\tenvKeys = new Set(fresh.keys);\n\t\treturn env;\n\t};\n\n\tconst spawnServer = (env: Record<string, string>) =>\n\t\tBun.spawn([\"bun\", \"run\", ...args], {\n\t\t\tstdio: [\"inherit\", \"inherit\", \"inherit\"],\n\t\t\tenv,\n\t\t\tcwd: targetDir,\n\t\t});\n\n\tlet proc = spawnServer(nextEnv(loadEnvFiles(targetDir)));\n\n\t// Restart when any .env file changes — Bun's own --watch ignores .env.\n\tlet restartRequested = false;\n\tconst stopEnvWatch = watchEnvFiles(targetDir, (file) => {\n\t\tif (restartRequested) return;\n\t\trestartRequested = true;\n\t\tconsole.log(`\\x1b[33m  🔁 ${file} changed — restarting dev server...\\x1b[0m`);\n\t\tproc.kill();\n\t});\n\n\tconst runServer = async (): Promise<void> => {\n\t\tfor (;;) {\n\t\t\tawait proc.exited;\n\t\t\tif (!restartRequested) return;\n\t\t\trestartRequested = false;\n\t\t\tconst fresh = loadEnvFiles(targetDir);\n\t\t\tconsole.log(`\\x1b[32m  ✅ Dev server restarted\\x1b[0m`);\n\t\t\tproc = spawnServer(nextEnv(fresh));\n\t\t}\n\t};\n\n\t// Kill the child whenever this process goes away — SIGTERM to the parent\n\t// alone would otherwise leave an orphaned `bun --watch` behind.\n\tconst shutdown = async () => {\n\t\tstopEnvWatch();\n\t\tproc.kill();\n\t\tif (tunnel) await tunnel.close();\n\t\tprocess.exit(0);\n\t};\n\tprocess.on(\"SIGINT\", () => {\n\t\tvoid shutdown();\n\t});\n\tprocess.on(\"SIGTERM\", () => {\n\t\tvoid shutdown();\n\t});\n\tprocess.on(\"exit\", () => {\n\t\tstopEnvWatch();\n\t\tproc.kill();\n\t});\n\n\tif (tunnel) {\n\t\tconsole.log(`\\x1b[32m  Server running at http://localhost:${port}\\x1b[0m`);\n\t\tconsole.log(`\\x1b[36m  Tunnel: ${tunnel.url} → http://localhost:${port}\\x1b[0m`);\n\t\tconsole.log(`\\n  Press Ctrl+C to stop\\n`);\n\n\t\tawait runServer();\n\t\tawait tunnel.close();\n\t} else {\n\t\tconsole.log(`\\x1b[36mStarting development server...\\x1b[0m\\n`);\n\t\tconsole.log(`\\x1b[32m  Server running at http://localhost:${port}\\x1b[0m`);\n\t\tconsole.log(`\\n  Press Ctrl+C to stop\\n`);\n\n\t\tawait runServer();\n\t\tstopEnvWatch();\n\t}\n}\n","import { existsSync, readFileSync, statSync, watch, type FSWatcher } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/** Files loaded by Bun, in ascending precedence order (development mode). */\nconst ENV_FILES = [\".env\", \".env.development\", \".env.local\"] as const;\n\n/** Parse a single .env-style file (simple dotenv format, zero-dep). */\nexport function parseEnvFile(path: string): Record<string, string> {\n\tif (!existsSync(path)) return {};\n\tconst values: Record<string, string> = {};\n\tfor (const rawLine of readFileSync(path, \"utf8\").split(\"\\n\")) {\n\t\tconst line = rawLine.trim();\n\t\tif (!line || line.startsWith(\"#\")) continue;\n\t\tconst withoutExport = line.startsWith(\"export \") ? line.slice(7).trim() : line;\n\t\tconst eq = withoutExport.indexOf(\"=\");\n\t\tif (eq <= 0) continue;\n\t\tconst key = withoutExport.slice(0, eq).trim();\n\t\tif (!key) continue;\n\t\tlet value = withoutExport.slice(eq + 1).trim();\n\t\tif (\n\t\t\tvalue.length >= 2 &&\n\t\t\t((value.startsWith('\"') && value.endsWith('\"')) ||\n\t\t\t\t(value.startsWith(\"'\") && value.endsWith(\"'\")))\n\t\t) {\n\t\t\tvalue = value.slice(1, -1);\n\t\t}\n\t\tvalues[key] = value;\n\t}\n\treturn values;\n}\n\nexport interface LoadedEnv {\n\tvalues: Record<string, string>;\n\tkeys: string[];\n}\n\n/** Load every supported .env file in Bun's precedence order. */\nexport function loadEnvFiles(dir: string): LoadedEnv {\n\tconst values: Record<string, string> = {};\n\tfor (const name of ENV_FILES) {\n\t\tObject.assign(values, parseEnvFile(join(dir, name)));\n\t}\n\treturn { values, keys: Object.keys(values) };\n}\n\n/**\n * Build the child environment for the dev server: strip keys that came from\n * the previous .env generation (so deletions propagate), then overlay the\n * freshly parsed values. Shell/process values always win over files in Bun,\n * which is why the merge must be explicit on restart.\n */\nexport function buildChildEnv(\n\tparentEnv: Record<string, string | undefined>,\n\toldKeys: ReadonlySet<string>,\n\tfresh: LoadedEnv,\n\toverrides: Record<string, string>,\n): Record<string, string> {\n\tconst out: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(parentEnv)) {\n\t\tif (value !== undefined) out[key] = value;\n\t}\n\tfor (const key of oldKeys) delete out[key];\n\tObject.assign(out, fresh.values, overrides);\n\treturn out;\n}\n\nfunction envFileSignature(dir: string): string {\n\treturn ENV_FILES.map((name) => {\n\t\ttry {\n\t\t\treturn statSync(join(dir, name)).mtimeMs;\n\t\t} catch {\n\t\t\treturn 0;\n\t\t}\n\t}).join(\",\");\n}\n\n/**\n * Watch a directory for .env file changes (created, modified, renamed, or\n * deleted) and invoke `onChange` (debounced). Returns a stop function.\n *\n * The directory itself is watched instead of each file so editors that save\n * via atomic rename keep triggering events. If the event has no filename\n * (some platforms), an mtime signature of the .env files is used instead.\n */\nexport function watchEnvFiles(dir: string, onChange: (file: string) => void): () => void {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet signature = envFileSignature(dir);\n\n\tconst schedule = (file: string) => {\n\t\tif (timer) clearTimeout(timer);\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = undefined;\n\t\t\tsignature = envFileSignature(dir);\n\t\t\tonChange(file);\n\t\t}, 150);\n\t};\n\n\tlet watcher: FSWatcher;\n\ttry {\n\t\twatcher = watch(dir, (_event, filename) => {\n\t\t\tconst name = filename ? filename.toString() : \"\";\n\t\t\tif (name && !/^\\.env(\\..+)?$/.test(name)) return;\n\t\t\tif (!name) {\n\t\t\t\tconst next = envFileSignature(dir);\n\t\t\t\tif (next === signature) return;\n\t\t\t\tsignature = next;\n\t\t\t\tschedule(\".env\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tschedule(name);\n\t\t});\n\t} catch {\n\t\t// Directory unreadable / no permission — env watching stays disabled.\n\t\treturn () => {};\n\t}\n\n\treturn () => {\n\t\tif (timer) clearTimeout(timer);\n\t\twatcher.close();\n\t};\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\n\nconst __dirname = import.meta.dir;\n\nfunction askQuestion(question: string, defaultValue = true): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst rl = createInterface({\n\t\t\tinput: process.stdin,\n\t\t\toutput: process.stdout,\n\t\t});\n\n\t\trl.question(question, (answer) => {\n\t\t\trl.close();\n\t\t\tconst normalized = answer.trim().toLowerCase();\n\t\t\tif (normalized === \"\") return resolve(defaultValue);\n\t\t\tresolve(normalized === \"y\" || normalized === \"yes\");\n\t\t});\n\t});\n}\n\nconst REQUIRED_SCRIPTS: Record<string, string> = {\n\tdev: \"bun --watch server.ts\",\n\tbuild: \"bunx buntok build\",\n\tstart: \"bun .buntok/server.js\",\n\tcheck: \"bunx @biomejs/biome check --write .\",\n\tformat: \"bunx @biomejs/biome format --write .\",\n\tlint: \"bunx @biomejs/biome lint .\",\n};\n\nconst BIOME_CONFIG = {\n\tvcs: {\n\t\tenabled: true,\n\t\tclientKind: \"git\",\n\t\tuseIgnoreFile: true,\n\t},\n\tfiles: {\n\t\tignoreUnknown: true,\n\t\tincludes: [\"**\", \"!**/node_modules\", \"!**/dist\", \"!**/.buntok\", \"!**/coverage\"],\n\t},\n\tformatter: {\n\t\tenabled: true,\n\t\tindentStyle: \"tab\",\n\t\tindentWidth: 2,\n\t\tlineWidth: 100,\n\t\tlineEnding: \"lf\",\n\t},\n\tlinter: {\n\t\tenabled: true,\n\t\trules: {\n\t\t\tpreset: \"recommended\",\n\t\t\tcorrectness: {\n\t\t\t\tnoUnusedImports: {\n\t\t\t\t\tlevel: \"warn\",\n\t\t\t\t\tfix: \"safe\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tsuspicious: {\n\t\t\t\tnoExplicitAny: \"off\",\n\t\t\t},\n\t\t},\n\t},\n\tjavascript: {\n\t\tformatter: {\n\t\t\tquoteStyle: \"double\",\n\t\t\ttrailingCommas: \"all\",\n\t\t},\n\t},\n};\n\n\nconst TSCONFIG_TEMPLATE = {\n\tcompilerOptions: {\n\t\t// Environment setup & latest features\n\t\tlib: [\"ESNext\"],\n\t\ttarget: \"ESNext\",\n\t\tmodule: \"Preserve\",\n\t\tmoduleDetection: \"force\",\n\t\tjsx: \"react-jsx\",\n\t\tallowJs: true,\n\t\ttypes: [\"bun\", \"node\"],\n\n\t\t// Bundler mode\n\t\tmoduleResolution: \"bundler\",\n\t\tallowImportingTsExtensions: true,\n\t\tverbatimModuleSyntax: true,\n\t\tnoEmit: true,\n\n\t\t// Strictness Options for TS 7+\n\t\tstrict: true,\n\t\tnoUncheckedIndexedAccess: true,\n\t\texactOptionalPropertyTypes: true,\n\t\tnoImplicitOverride: true,\n\t\tnoFallthroughCasesInSwitch: true,\n\t\tisolatedModules: true,\n\t\tskipLibCheck: true,\n\n\t\t// Path alias\n\t\tpaths: {\n\t\t\t\"@/*\": [\"./src/*\"],\n\t\t},\n\t},\n\tinclude: [\"src/**/*\"],\n\texclude: [\"node_modules\", \".buntok\"],\n};\n\nconst VSCODE_SETTINGS = {\n\t\"editor.formatOnSave\": true,\n\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t\"editor.codeActionsOnSave\": {\n\t\t\"source.fixAll.biome\": \"explicit\",\n\t\t\"source.organizeImports.biome\": \"explicit\",\n\t},\n\t\"[javascript]\": {\n\t\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t},\n\t\"[typescript]\": {\n\t\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t},\n\t\"[typescriptreact]\": {\n\t\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t},\n\t\"[json]\": {\n\t\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t},\n\t\"[jsonc]\": {\n\t\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t},\n\t\"[html]\": {\n\t\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t},\n\t\"[css]\": {\n\t\t\"editor.defaultFormatter\": \"biomejs.biome\",\n\t},\n};\n\nconst INDEX_TEMPLATE = `import { App } from \"@buntok/core\";\nimport \"./env\";\n\nexport const app = new App();\n\napp.get(\"/\", (ctx) => {\n  return ctx.json({ message: \"Hello from Buntok!\" });\n});\n`;\n\nconst ENV_TS_TEMPLATE = `import { App } from \"@buntok/core\";\nimport { z } from \"@buntok/core/middlewares/validator\";\n\nexport const env = App.validateEnv({\n\tPORT: z.coerce.number().default(1212),\n\tAUTH_STORE: z.enum([\"header\", \"cookie\"]).default(\"header\"),\n\tAUTH_COOKIE: z.string().default(\"session\"),\n\tNODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n});\n`;\n\nfunction findSkillMdSource(): string | null {\n\t// 1. Relative path (works when running from @buntok/core package)\n\tconst relativePath = join(\n\t\t__dirname,\n\t\t\"..\",\n\t\t\"..\",\n\t\t\"scripts\",\n\t\t\"buntok-skill\",\n\t\t\"SKILL.md\",\n\t);\n\tif (existsSync(relativePath)) return relativePath;\n\n\t// 2. Resolve from @buntok/core package (works when running from buntok CLI)\n\ttry {\n\t\t// biome-ignore lint: dynamic import for package resolution\n\t\tconst pkgJson = require.resolve(\"@buntok/core/package.json\");\n\t\tconst pkgDir = dirname(pkgJson);\n\t\tconst skillPath = join(pkgDir, \"scripts\", \"buntok-skill\", \"SKILL.md\");\n\t\tif (existsSync(skillPath)) return skillPath;\n\t} catch {\n\t\t// package not found\n\t}\n\n\treturn null;\n}\n\nfunction copySkillMd(projectRoot: string): boolean {\n\tconst sourceSkill = findSkillMdSource();\n\n\tif (!sourceSkill) {\n\t\tconsole.warn(\n\t\t\t\"\\x1b[33m⚠ SKILL.md not found in @buntok/core, skipping.\\x1b[0m\",\n\t\t);\n\t\treturn false;\n\t}\n\n\tconst skillDir = join(projectRoot, \".agents\", \"skills\", \"buntok-skill\");\n\tconst destSkill = join(skillDir, \"SKILL.md\");\n\n\tif (!existsSync(skillDir)) {\n\t\tmkdirSync(skillDir, { recursive: true });\n\t}\n\n\twriteFileSync(destSkill, readFileSync(sourceSkill, \"utf-8\"), \"utf-8\");\n\tconsole.log(`\\x1b[32m✓ Created\\x1b[0m .agents/skills/buntok-skill/SKILL.md`);\n\treturn true;\n}\n\nfunction updatePackageJson(projectRoot: string): boolean {\n\tconst pkgPath = join(projectRoot, \"package.json\");\n\n\tlet pkg: { name?: string; scripts?: Record<string, string>; devDependencies?: Record<string, string> };\n\tif (existsSync(pkgPath)) {\n\t\tpkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n\t} else {\n\t\tconst folderName = projectRoot.split(\"/\").pop() || \"my-app\";\n\t\tpkg = { name: folderName, scripts: {}, devDependencies: {} };\n\t}\n\n\tif (!pkg.scripts) pkg.scripts = {};\n\n\tlet added = 0;\n\tfor (const [key, value] of Object.entries(REQUIRED_SCRIPTS)) {\n\t\tif (!pkg.scripts[key]) {\n\t\t\tpkg.scripts[key] = value;\n\t\t\tadded++;\n\t\t}\n\t}\n\n\tif (added === 0) {\n\t\tconsole.log(\"\\x1b[90m• package.json: all scripts already present\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\twriteFileSync(pkgPath, JSON.stringify(pkg, null, 2) + \"\\n\", \"utf-8\");\n\tconsole.log(`\\x1b[32m✓ Updated\\x1b[0m package.json (added ${added} scripts)`);\n\treturn true;\n}\n\nfunction stripJsonComments(text: string): string {\n\t// Remove single-line comments (// ...) but not inside strings\n\treturn text.replace(/(?<![\"':].*)\\/\\/.*$/gm, \"\");\n}\n\nfunction setupTsconfig(projectRoot: string): boolean {\n\tconst tsconfigPath = join(projectRoot, \"tsconfig.json\");\n\n\tif (existsSync(tsconfigPath)) {\n\t\t// Merge paths into existing tsconfig\n\t\tconst raw = readFileSync(tsconfigPath, \"utf-8\");\n\t\tconst existing = JSON.parse(stripJsonComments(raw));\n\t\tif (!existing.compilerOptions) existing.compilerOptions = {};\n\t\tif (!existing.compilerOptions.paths) {\n\t\t\texisting.compilerOptions.paths = { \"@/*\": [\"./src/*\"] };\n\t\t\twriteFileSync(tsconfigPath, JSON.stringify(existing, null, 2) + \"\\n\", \"utf-8\");\n\t\t\tconsole.log(\"\\x1b[32m✓ Updated\\x1b[0m tsconfig.json (added path alias)\");\n\t\t\treturn true;\n\t\t}\n\t\tif (!existing.compilerOptions.paths[\"@/*\"]) {\n\t\t\texisting.compilerOptions.paths[\"@/*\"] = [\"./src/*\"];\n\t\t\twriteFileSync(tsconfigPath, JSON.stringify(existing, null, 2) + \"\\n\", \"utf-8\");\n\t\t\tconsole.log(\"\\x1b[32m✓ Updated\\x1b[0m tsconfig.json (added path alias)\");\n\t\t\treturn true;\n\t\t}\n\t\tconsole.log(\"\\x1b[90m• tsconfig.json: path alias already present\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\t// Create new tsconfig\n\twriteFileSync(tsconfigPath, JSON.stringify(TSCONFIG_TEMPLATE, null, 2) + \"\\n\", \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m tsconfig.json\");\n\treturn true;\n}\n\nfunction setupBiome(projectRoot: string): boolean {\n\tconst biomePath = join(projectRoot, \"biome.json\");\n\n\tif (existsSync(biomePath)) {\n\t\tconsole.log(\"\\x1b[90m• biome.json: already exists, skipping\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\t// Check if @biomejs/biome is installed\n\tconst pkgPath = join(projectRoot, \"package.json\");\n\tlet needsInstall = false;\n\tif (existsSync(pkgPath)) {\n\t\tconst pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n\t\tconst allDeps = {\n\t\t\t...pkg.dependencies,\n\t\t\t...pkg.devDependencies,\n\t\t};\n\t\tneedsInstall = !allDeps[\"@biomejs/biome\"];\n\t}\n\n\tif (needsInstall) {\n\t\tconsole.log(\"\\x1b[90m• Installing @biomejs/biome...\\x1b[0m\");\n\t\ttry {\n\t\t\texecSync(\"bun add -d @biomejs/biome\", {\n\t\t\t\tcwd: projectRoot,\n\t\t\t\tstdio: \"ignore\",\n\t\t\t});\n\t\t\tconsole.log(\"\\x1b[32m✓ Installed\\x1b[0m @biomejs/biome\");\n\t\t} catch {\n\t\t\tconsole.warn(\n\t\t\t\t\"\\x1b[33m⚠ Failed to install @biomejs/biome, please install manually\\x1b[0m\",\n\t\t\t);\n\t\t}\n\t}\n\n\twriteFileSync(biomePath, JSON.stringify(BIOME_CONFIG, null, 2) + \"\\n\", \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m biome.json\");\n\treturn true;\n}\n\nfunction createIndexFile(projectRoot: string): boolean {\n\tconst srcDir = join(projectRoot, \"src\");\n\tconst indexPath = join(srcDir, \"index.ts\");\n\n\tif (existsSync(indexPath)) {\n\t\tconsole.log(\"\\x1b[90m• src/index.ts: already exists, skipping\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\tif (!existsSync(srcDir)) {\n\t\tmkdirSync(srcDir, { recursive: true });\n\t}\n\n\twriteFileSync(indexPath, INDEX_TEMPLATE, \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m src/index.ts\");\n\treturn true;\n}\n\nfunction createEnvTsFile(projectRoot: string): boolean {\n\tconst srcDir = join(projectRoot, \"src\");\n\tconst envTsPath = join(srcDir, \"env.ts\");\n\n\tif (existsSync(envTsPath)) {\n\t\tconsole.log(\"\\x1b[90m• src/env.ts: already exists, skipping\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\tif (!existsSync(srcDir)) {\n\t\tmkdirSync(srcDir, { recursive: true });\n\t}\n\n\twriteFileSync(envTsPath, ENV_TS_TEMPLATE, \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m src/env.ts\");\n\treturn true;\n}\n\nfunction setupVscode(projectRoot: string): boolean {\n\tconst vscodeDir = join(projectRoot, \".vscode\");\n\tconst settingsPath = join(vscodeDir, \"settings.json\");\n\n\tif (existsSync(settingsPath)) {\n\t\tconsole.log(\"\\x1b[90m• .vscode/settings.json: already exists, skipping\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\tif (!existsSync(vscodeDir)) {\n\t\tmkdirSync(vscodeDir, { recursive: true });\n\t}\n\n\twriteFileSync(settingsPath, JSON.stringify(VSCODE_SETTINGS, null, 2) + \"\\n\", \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m .vscode/settings.json\");\n\treturn true;\n}\n\nconst ENV_CONTENT = `# Buntok Configuration\nPORT=1212\nAUTH_STORE=header\nAUTH_COOKIE=session\n`;\n\nconst ENV_EXAMPLE_CONTENT = `# Buntok Configuration\n#\n# PORT: port is using for the app\n# AUTH_STORE: Where to store/read JWT tokens\n#   - \"header\" (default): Read from Authorization: Bearer <token> header\n#   - \"cookie\": Read from HttpOnly cookie (set AUTH_COOKIE for cookie name)\n#\n# AUTH_COOKIE: Cookie name for JWT storage (only used when AUTH_STORE=cookie)\n#\nPORT=1212\nAUTH_STORE=header\nAUTH_COOKIE=session\n`;\n\nconst VERCEL_JSON_TEMPLATE = {\n\t$schema: \"https://openapi.vercel.sh/vercel.json\",\n\tframework: \"bun\",\n\tbunVersion: \"1.4.x\",\n};\n\nconst SERVER_TS_TEMPLATE = `import { app } from \"./src/index\";\nimport { env } from \"./src/env\";\n\napp.listen(env.PORT);\n`;\n\nconst GITIGNORE_CONTENT = `# Dependencies\nnode_modules/\n\n# Build output\n.buntok/\n\n# Environment\n.env\n.env.local\n.env.*.local\n\n# IDE\n.vscode/\n.idea/\n*.swp\n*.swo\n*~\npublic/swagger.json\n\n# OS\n.DS_Store\nThumbs.db\n\n# Buntok\n.buntok/\n\n# Logs\n*.log\nnpm-debug.log*\n\n# Coverage\ncoverage/\n`;\n\nconst DOCKERFILE_TEMPLATE = `# Builder\nFROM oven/bun:1-alpine AS builder\nWORKDIR /app\n\nCOPY package.json bun.lock* ./\nRUN bun install --frozen-lockfile --production\n\nCOPY src/ src/\nCOPY server.ts ./\nCOPY tsconfig.json ./\nCOPY package.json ./\n\nRUN bunx buntok build\n\n# Production\nFROM oven/bun:1-alpine\nWORKDIR /app\n\nCOPY --from=builder /app/.buntok .buntok\nCOPY --from=builder /app/node_modules node_modules\nCOPY --from=builder /app/package.json ./\n\nEXPOSE 1212\n\nENV NODE_ENV=production\nENV PORT=1212\n\nCMD [\"bun\", \".buntok/server.js\"]\n`;\n\nconst DOCKERIGNORE_CONTENT = `node_modules\ndist\n.buntok\n*.log\n.env\n.env.*\ncoverage\n`;\n\nfunction createEnvFiles(projectRoot: string): boolean {\n\tconst envPath = join(projectRoot, \".env\");\n\tconst envExamplePath = join(projectRoot, \".env.example\");\n\tlet created = false;\n\n\tif (!existsSync(envPath)) {\n\t\twriteFileSync(envPath, ENV_CONTENT, \"utf-8\");\n\t\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m .env\");\n\t\tcreated = true;\n\t} else {\n\t\tconsole.log(\"\\x1b[90m• .env: already exists, skipping\\x1b[0m\");\n\t}\n\n\tif (!existsSync(envExamplePath)) {\n\t\twriteFileSync(envExamplePath, ENV_EXAMPLE_CONTENT, \"utf-8\");\n\t\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m .env.example\");\n\t\tcreated = true;\n\t} else {\n\t\tconsole.log(\"\\x1b[90m• .env.example: already exists, skipping\\x1b[0m\");\n\t}\n\n\treturn created;\n}\n\nfunction createGitignore(projectRoot: string): boolean {\n\tconst gitignorePath = join(projectRoot, \".gitignore\");\n\n\tif (existsSync(gitignorePath)) {\n\t\tconsole.log(\"\\x1b[90m• .gitignore: already exists, skipping\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\twriteFileSync(gitignorePath, GITIGNORE_CONTENT, \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m .gitignore\");\n\treturn true;\n}\n\nfunction createVercelJson(projectRoot: string): boolean {\n\tconst vercelPath = join(projectRoot, \"vercel.json\");\n\n\tif (existsSync(vercelPath)) {\n\t\tconsole.log(\"\\x1b[90m• vercel.json: already exists, skipping\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\twriteFileSync(vercelPath, JSON.stringify(VERCEL_JSON_TEMPLATE, null, 2) + \"\\n\", \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m vercel.json\");\n\n\t// Create empty public/ directory (Vercel requires it for static files)\n\tconst publicDir = join(projectRoot, \"public\");\n\tif (!existsSync(publicDir)) {\n\t\tmkdirSync(publicDir, { recursive: true });\n\t\twriteFileSync(join(publicDir, \".gitkeep\"), \"\");\n\t}\n\n\treturn true;\n}\n\nfunction createServerTsFile(projectRoot: string): boolean {\n\tconst serverPath = join(projectRoot, \"server.ts\");\n\n\tif (existsSync(serverPath)) {\n\t\tconsole.log(\"\\x1b[90m• server.ts: already exists, skipping\\x1b[0m\");\n\t\treturn false;\n\t}\n\n\twriteFileSync(serverPath, SERVER_TS_TEMPLATE, \"utf-8\");\n\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m server.ts\");\n\treturn true;\n}\n\nfunction updateDevScript(projectRoot: string): boolean {\n\tconst pkgPath = join(projectRoot, \"package.json\");\n\tif (!existsSync(pkgPath)) return false;\n\n\tconst pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n\tif (!pkg.scripts) return false;\n\n\tif (pkg.scripts.dev === \"bun --watch src/index.ts\") {\n\t\tpkg.scripts.dev = \"bun --watch server.ts\";\n\t\twriteFileSync(pkgPath, JSON.stringify(pkg, null, 2) + \"\\n\", \"utf-8\");\n\t\tconsole.log(\"\\x1b[32m✓ Updated\\x1b[0m package.json (dev → server.ts)\");\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nfunction createDockerfile(projectRoot: string): boolean {\n\tconst dockerfilePath = join(projectRoot, \"Dockerfile\");\n\tconst dockerignorePath = join(projectRoot, \".dockerignore\");\n\n\tlet created = false;\n\n\tif (!existsSync(dockerfilePath)) {\n\t\twriteFileSync(dockerfilePath, DOCKERFILE_TEMPLATE, \"utf-8\");\n\t\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m Dockerfile\");\n\t\tcreated = true;\n\t} else {\n\t\tconsole.log(\"\\x1b[90m• Dockerfile: already exists, skipping\\x1b[0m\");\n\t}\n\n\tif (!existsSync(dockerignorePath)) {\n\t\twriteFileSync(dockerignorePath, DOCKERIGNORE_CONTENT, \"utf-8\");\n\t\tconsole.log(\"\\x1b[32m✓ Created\\x1b[0m .dockerignore\");\n\t\tcreated = true;\n\t} else {\n\t\tconsole.log(\"\\x1b[90m• .dockerignore: already exists, skipping\\x1b[0m\");\n\t}\n\n\treturn created;\n}\n\nexport async function initCommand() {\n\tconst projectRoot = process.cwd();\n\n\tcopySkillMd(projectRoot);\n\tupdatePackageJson(projectRoot);\n\tsetupTsconfig(projectRoot);\n\tsetupBiome(projectRoot);\n\tsetupVscode(projectRoot);\n\tcreateEnvTsFile(projectRoot);\n\tcreateIndexFile(projectRoot);\n\tcreateEnvFiles(projectRoot);\n\tcreateGitignore(projectRoot);\n\tupdateDevScript(projectRoot);\n\n\tconst vercelPath = join(projectRoot, \"vercel.json\");\n\tif (!existsSync(vercelPath)) {\n\t\tconsole.log(\"\");\n\t\tconst useVercel = await askQuestion(\n\t\t\t\"\\x1b[36mDo you want to deploy to Vercel? (y/N): \\x1b[0m\",\n\t\t\tfalse,\n\t\t);\n\t\tif (useVercel) {\n\t\t\tcreateVercelJson(projectRoot);\n\t\t}\n\t} else {\n\t\tconsole.log(\"\\x1b[90m• vercel.json: already exists, skipping\\x1b[0m\");\n\t}\n\n\tcreateServerTsFile(projectRoot);\n\n\tconst dockerfilePath = join(projectRoot, \"Dockerfile\");\n\tif (!existsSync(dockerfilePath)) {\n\t\tconsole.log(\"\");\n\t\tconst useDocker = await askQuestion(\n\t\t\t\"\\x1b[36mDo you want to add Docker support? (Y/n): \\x1b[0m\",\n\t\t\ttrue,\n\t\t);\n\t\tif (useDocker) {\n\t\t\tcreateDockerfile(projectRoot);\n\t\t}\n\t} else {\n\t\tconsole.log(\"\\x1b[90m• Dockerfile: already exists, skipping\\x1b[0m\");\n\t}\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { generateOpenApiDocument } from \"../../helpers/openapi\";\n\nexport async function makeDocsCommand() {\n\tconsole.log(\"\\x1b[36mGenerating OpenAPI documentation...\\x1b[0m\");\n\n\t// Prevent the user's app from starting its HTTP server during import\n\tprocess.env.BUNTOK_DOCS_BUILD = \"1\";\n\n\tconst entryPath = resolve(process.cwd(), \"src/index.ts\");\n\n\ttry {\n\t\tconsole.log(`\\x1b[90mLoading app from ${entryPath}...\\x1b[0m`);\n\n\t\tconst userApp = await import(entryPath);\n\t\tconst appInstance = userApp.app || userApp.default;\n\n\t\tif (!appInstance?.openApiDocs) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Could not find an exported 'app' instance in src/index.ts. Make sure you export your app: `export const app = new App();`\",\n\t\t\t);\n\t\t}\n\n\t\tconst docsConfig = appInstance._apiDocsConfig;\n\n\t\tconst document = generateOpenApiDocument({\n\t\t\topenApiDocs: appInstance.openApiDocs,\n\t\t\ttitle: docsConfig?.title,\n\t\t\tversion: docsConfig?.version,\n\t\t\tdescription: docsConfig?.description,\n\t\t});\n\n\t\tif (!document) {\n\t\t\tconsole.warn(\n\t\t\t\t\"\\x1b[33m  ⚠ No routes with OpenAPI metadata found. Add zValidator() or zResponse() to your routes.\\x1b[0m\",\n\t\t\t);\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\t// Output directory: public/docs/\n\t\tconst docsDir = resolve(process.cwd(), \"public/docs\");\n\t\tmkdirSync(docsDir, { recursive: true });\n\n\t\tconst swaggerPath = resolve(docsDir, \"swagger.json\");\n\t\twriteFileSync(swaggerPath, JSON.stringify(document, null, 2));\n\t\tconsole.log(\n\t\t\t`\\x1b[32m✔ swagger.json generated at public/docs/swagger.json\\x1b[0m`,\n\t\t);\n\n\t\tprocess.exit(0);\n\t} catch (error) {\n\t\tconsole.error(\"\\x1b[31mFailed to generate docs:\\x1b[0m\");\n\t\tconsole.error(error);\n\t\tprocess.exit(1);\n\t}\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport {\n\tfakerLinesForFields,\n\tgetEntityModel,\n\tloadPrismaSchema,\n\tparseFieldsFlag,\n\ttsLinesForFields,\n\ttype FieldDef,\n\ttype PrismaSchema,\n} from \"../generators/model.js\";\nimport { detectORMOrNull, formatWithBiome } from \"../project.js\";\nimport { toPascalCase, toSnakeCase } from \"../utils.js\";\n\ninterface FactoryShape {\n\ttypeImport: string;\n\ttypeDecl: string;\n\tbody: string;\n}\n\nfunction generateFactoryTemplate(\n\tentityName: string,\n\torm: string | null,\n\tfields: FieldDef[] | null,\n\tschema: PrismaSchema | null,\n): FactoryShape {\n\tconst interfaceName = toPascalCase(entityName);\n\tconst fakerLines = fields ? fakerLinesForFields(fields, schema) : [];\n\tconst body =\n\t\tfakerLines.length > 0\n\t\t\t? fakerLines.map((l) => `  ${l}`).join(\"\\n\")\n\t\t\t: `  // TODO: Define your factory fields here\n  // Example:\n  // id: faker.number.int({ max: 10000 }),\n  // name: faker.person.fullName(),\n  // email: faker.internet.email(),`;\n\n\t// Prisma projects get the generated model type; other ORMs get an inline\n\t// type derived from the schema fields when available.\n\tif (orm === \"prisma\" || (!orm && !fields)) {\n\t\tconst typeImport = `import type { ${interfaceName} } from \"@prisma/client\";`;\n\t\treturn {\n\t\t\ttypeImport,\n\t\t\ttypeDecl: \"\",\n\t\t\tbody,\n\t\t};\n\t}\n\n\tconst tsLines = fields ? tsLinesForFields(fields, schema) : [];\n\tconst typeDecl =\n\t\ttsLines.length > 0\n\t\t\t? `type ${interfaceName} = {\\n${tsLines.map((l) => `  ${l}`).join(\"\\n\")}\\n};`\n\t\t\t: `type ${interfaceName} = Record<string, unknown>;`;\n\treturn {\n\t\ttypeImport: \"\",\n\t\ttypeDecl,\n\t\tbody,\n\t};\n}\n\nexport async function makeFactoryCommand(\n\tentityName: string,\n\tflags: string[],\n): Promise<void> {\n\tconst targetDir = process.cwd();\n\tconst isDryRun = flags.includes(\"--dry-run\");\n\tconst force = flags.includes(\"--force\");\n\tconst fieldsFlagValue = (() => {\n\t\tconst i = flags.indexOf(\"--fields\");\n\t\treturn i !== -1 ? flags[i + 1] : undefined;\n\t})();\n\n\t// Resolve paths\n\tconst factoryDir = resolve(targetDir, \"src\", \"factories\");\n\n\t// Ensure factories directory exists\n\tif (!existsSync(factoryDir)) {\n\t\tif (!isDryRun) {\n\t\t\tmkdirSync(factoryDir, { recursive: true });\n\t\t}\n\t\tconsole.log(`Created directory: src/factories/`);\n\t}\n\n\t// Model awareness: Prisma schema first, `--fields` overrides\n\tconst schema = fieldsFlagValue ? null : loadPrismaSchema();\n\tconst model = schema ? getEntityModel(entityName, schema) : null;\n\tconst fields: FieldDef[] | null = fieldsFlagValue\n\t\t? parseFieldsFlag(fieldsFlagValue)\n\t\t: (model?.fields ?? null);\n\tconst orm = detectORMOrNull();\n\tconst shape = generateFactoryTemplate(entityName, orm, fields, schema);\n\n\tconst className = toPascalCase(entityName) + \"Factory\";\n\tconst importLines = [\n\t\t`import { Factory } from \"@buntok/core\";`,\n\t\t`import { faker } from \"@faker-js/faker\";`,\n\t\tshape.typeImport,\n\t].filter((l) => l.length > 0);\n\tconst content = `${importLines.join(\"\\n\")}\n\nexport const ${className} = Factory.define<${toPascalCase(entityName)}>(() => ({\n${shape.body}\n}));\n${shape.typeDecl ? `\\n${shape.typeDecl}\\n` : \"\"}`;\n\n\tconst fileName = `${toSnakeCase(entityName)}.factory.ts`;\n\tconst filePath = join(factoryDir, fileName);\n\n\tif (isDryRun) {\n\t\tconsole.log(`\\n\\x1b[36m[DRY RUN] Would create:\\x1b[0m`);\n\t\tconsole.log(`  ${filePath}`);\n\t\tconsole.log(`\\x1b[36mContent:\\x1b[0m`);\n\t\tconsole.log(content);\n\t\treturn;\n\t}\n\n\t// Check if file already exists\n\tif (existsSync(filePath) && !force) {\n\t\tconsole.error(\n\t\t\t`\\x1b[31mError: Factory file already exists: ${filePath} (use --force to overwrite)\\x1b[0m`,\n\t\t);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\t// Write factory file\n\twriteFileSync(filePath, content, \"utf-8\");\n\tif (formatWithBiome([filePath])) {\n\t\tconsole.log(\n\t\t\t\"\\x1b[90m✨ Auto-formatted generated factory file with Biome\\x1b[0m\",\n\t\t);\n\t}\n\tconsole.log(`Created: src/factories/${fileName}`);\n\n\t// Print usage hint\n\tconsole.log(`\\n\\x1b[36mUsage:\\x1b[0m`);\n\tconsole.log(\n\t\t`  import { ${className} } from \"@/factories/${fileName.replace(\".ts\", \"\")}\";`,\n\t);\n\tconsole.log(``);\n\tconsole.log(`  const user = await ${className}.create();`);\n\tconsole.log(`  const users = await ${className}.createMany(10);`);\n\tconsole.log(`  const admin = await ${className}.create({ role: \"admin\" });`);\n}\n","import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { formatWithBiome } from \"../project.js\";\nimport { toPascalCase } from \"../utils.js\";\n\nfunction generateMiddleware(_name: string, pascalName: string): string {\n\treturn `import type { Context, Middleware } from \"@buntok/core\";\n\nexport const ${pascalName}Middleware: Middleware = async (ctx: Context, next: () => Promise<Response> | Response) => {\n  const start = performance.now();\n\n  const response = await next();\n\n  const end = performance.now();\n  const url = new URL(ctx.request.url);\n  console.log(\\`[\\${ctx.request.method}] \\${url.pathname} - \\${Math.round(end - start)}ms\\`);\n\n  return response;\n}\n`;\n}\n\nexport async function makeMiddlewareCommand(name: string, flags: string[] = []) {\n\tconst pascalName = toPascalCase(name);\n\tconst dryRun = flags.includes(\"--dry-run\");\n\tconst force = flags.includes(\"--force\");\n\tconsole.log(`\\n\\x1b[36mCreating ${pascalName} Middleware${dryRun ? \" (dry-run)\" : \"\"}...\\x1b[0m\\n`);\n\n\tconst middlewaresDir = \"src/middlewares\";\n\n\tif (!existsSync(middlewaresDir)) {\n\t\tif (dryRun) {\n\t\t\tconsole.log(`\\x1b[90mWould create directory: ${middlewaresDir}\\x1b[0m`);\n\t\t} else {\n\t\t\tawait fs.mkdir(middlewaresDir, { recursive: true });\n\t\t}\n\t}\n\n\tconst filePath = join(middlewaresDir, `${name}.middleware.ts`);\n\n\tif (existsSync(filePath) && !force) {\n\t\tconsole.error(\n\t\t\t`\\x1b[31mError: Middleware file already exists at ${filePath} (use --force to overwrite)\\x1b[0m`,\n\t\t);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst content = generateMiddleware(name, pascalName);\n\n\tif (dryRun) {\n\t\tconsole.log(`\\x1b[90mWould create file: ${filePath}\\x1b[0m`);\n\t\tconsole.log(`\\n\\x1b[36m--- Generated content ---\\x1b[0m\\n`);\n\t\tconsole.log(content);\n\t\treturn;\n\t}\n\n\tawait fs.writeFile(filePath, content);\n\n\tif (formatWithBiome([filePath])) {\n\t\tconsole.log(\"\\x1b[90m✨ Auto-formatted generated file with Biome\\x1b[0m\");\n\t}\n\n\tconsole.log(`\\x1b[32m✓ Generated middleware:\\x1b[0m ${filePath}`);\n\n\tconsole.log(`\n\\x1b[36mUsage:\\x1b[0m\n  Import and apply it globally in src/index.ts:\n     \\x1b[32mapp.use(${pascalName}Middleware);\\x1b[0m\n\n  Or apply it to a specific controller:\n     \\x1b[32m@Use(${pascalName}Middleware)\\x1b[0m\n     \\x1b[32mexport class MyController { ... }\\x1b[0m\n`);\n}\n","import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { detectORM, type ORM } from \"../generators/repository.js\";\nimport { formatWithBiome } from \"../project.js\";\nimport { toCamelCase, toPascalCase, toSnakeCase } from \"../utils.js\";\nimport { makeFactoryCommand } from \"./make-factory.js\";\n\nfunction generatePrismaSeeder(name: string, pascalName: string, useFactory: boolean): string {\n\tconst delegate = toCamelCase(name);\n\tconst factoryFile = toSnakeCase(name);\n\tif (useFactory) {\n\t\treturn `import { prisma } from \"@/lib/prisma\";\nimport { ${pascalName}Factory } from \"@/factories/${factoryFile}.factory\";\n\nexport async function seed${pascalName}() {\n  console.log(\"Seeding ${pascalName}...\");\n\n  const items = ${pascalName}Factory.buildMany(100);\n  await prisma.${delegate}.createMany({ data: items });\n\n  console.log(\"✓ ${pascalName} seeded successfully (100 records)\");\n}\n`;\n\t}\n\treturn `import { prisma } from \"@/lib/prisma\";\n\nexport async function seed${pascalName}() {\n  console.log(\"Seeding ${pascalName}...\");\n\n  // TODO: Insert your dummy data here\n  // await prisma.${delegate}.createMany({\n  //   data: [\n  //     { name: \"Dummy 1\" },\n  //     { name: \"Dummy 2\" },\n  //   ],\n  // });\n\n  console.log(\"✓ ${pascalName} seeded successfully\");\n}\n`;\n}\n\nfunction generateDrizzleSeeder(name: string, pascalName: string, useFactory: boolean): string {\n\tif (useFactory) {\n\t\treturn `import { db } from \"@/lib/db\";\nimport { ${name} } from \"@/lib/db/schema\";\nimport { ${pascalName}Factory } from \"@/factories/${toSnakeCase(name)}.factory\";\n\nexport async function seed${pascalName}() {\n  console.log(\"Seeding ${pascalName}...\");\n\n  const items = ${pascalName}Factory.buildMany(100);\n  await db.insert(${name}).values(items);\n\n  console.log(\"✓ ${pascalName} seeded successfully (100 records)\");\n}\n`;\n\t}\n\treturn `import { db } from \"@/lib/db\";\nimport { ${name} } from \"@/lib/db/schema\";\n\nexport async function seed${pascalName}() {\n  console.log(\"Seeding ${pascalName}...\");\n\n  // TODO: Insert your dummy data here\n  // await db.insert(${name}).values([\n  //   { name: \"Dummy 1\" },\n  //   { name: \"Dummy 2\" },\n  // ]);\n\n  console.log(\"✓ ${pascalName} seeded successfully\");\n}\n`;\n}\n\nfunction generateTypeORMSeeder(name: string, pascalName: string, useFactory: boolean): string {\n\tif (useFactory) {\n\t\treturn `import { AppDataSource } from \"@/lib/data-source\";\nimport { ${pascalName} } from \"@/lib/entities/${pascalName}\";\nimport { ${pascalName}Factory } from \"@/factories/${toSnakeCase(name)}.factory\";\n\nexport async function seed${pascalName}() {\n  console.log(\"Seeding ${pascalName}...\");\n\n  const repo = AppDataSource.getRepository(${pascalName});\n  const items = ${pascalName}Factory.buildMany(100);\n  await repo.save(items.map(item => repo.create(item)));\n\n  console.log(\"✓ ${pascalName} seeded successfully (100 records)\");\n}\n`;\n\t}\n\treturn `import { AppDataSource } from \"@/lib/data-source\";\nimport { ${pascalName} } from \"@/lib/entities/${pascalName}\";\n\nexport async function seed${pascalName}() {\n  console.log(\"Seeding ${pascalName}...\");\n\n  const repo = AppDataSource.getRepository(${pascalName});\n\n  // TODO: Insert your dummy data here\n  // await repo.save(repo.create({ name: \"Dummy 1\" }));\n  // await repo.save(repo.create({ name: \"Dummy 2\" }));\n\n  console.log(\"✓ ${pascalName} seeded successfully\");\n}\n`;\n}\n\nfunction generateSeeder(name: string, pascalName: string, orm: ORM, useFactory: boolean): string {\n\tswitch (orm) {\n\t\tcase \"drizzle\":\n\t\t\treturn generateDrizzleSeeder(name, pascalName, useFactory);\n\t\tcase \"typeorm\":\n\t\t\treturn generateTypeORMSeeder(name, pascalName, useFactory);\n\t\tcase \"prisma\":\n\t\tdefault:\n\t\t\treturn generatePrismaSeeder(name, pascalName, useFactory);\n\t}\n}\n\nexport async function makeSeederCommand(name: string, flags: string[] = []) {\n\tconst pascalName = toPascalCase(name);\n\tconst orm = detectORM();\n\tconst useFactory = flags.includes(\"--factory\");\n\tconst dryRun = flags.includes(\"--dry-run\");\n\tconst force = flags.includes(\"--force\");\n\tconsole.log(`\\n\\x1b[36mScaffolding Seeder for ${pascalName} (orm: ${orm}${useFactory ? \", using factory\" : \"\"}${dryRun ? \", dry-run\" : \"\"})...\\x1b[0m\\n`);\n\n\tconst seederDir = \"src/db/seeders\";\n\n\tif (!existsSync(seederDir)) {\n\t\tif (dryRun) {\n\t\t\tconsole.log(`\\x1b[90mWould create directory: ${seederDir}\\x1b[0m`);\n\t\t} else {\n\t\t\tawait fs.mkdir(seederDir, { recursive: true });\n\t\t}\n\t}\n\n\tconst filePath = join(seederDir, `${name}.seeder.ts`);\n\n\tif (existsSync(filePath) && !force) {\n\t\tconsole.error(\n\t\t\t`\\x1b[31mError: Seeder file already exists at ${filePath} (use --force to overwrite)\\x1b[0m`,\n\t\t);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst content = generateSeeder(name, pascalName, orm, useFactory);\n\n\tif (dryRun) {\n\t\tconsole.log(`\\x1b[90mWould create file: ${filePath}\\x1b[0m`);\n\t\tconsole.log(`\\n\\x1b[36m--- Generated content ---\\x1b[0m\\n`);\n\t\tconsole.log(content);\n\t\treturn;\n\t}\n\n\tawait fs.writeFile(filePath, content);\n\n\tif (formatWithBiome([filePath])) {\n\t\tconsole.log(\n\t\t\t\"\\x1b[90m✨ Auto-formatted generated seeder file with Biome\\x1b[0m\",\n\t\t);\n\t}\n\n\tconsole.log(`\\x1b[32m✓ Generated seeder:\\x1b[0m ${filePath}`);\n\n\tif (useFactory) {\n\t\t// Generate the factory on demand instead of just warning about it\n\t\tconst factoryPath = `src/factories/${toSnakeCase(name)}.factory.ts`;\n\t\tif (!existsSync(factoryPath)) {\n\t\t\tconsole.log(\n\t\t\t\t`\\n\\x1b[90mFactory not found at ${factoryPath} — generating it...\\x1b[0m`,\n\t\t\t);\n\t\t\tawait makeFactoryCommand(name, []);\n\t\t}\n\t}\n}\n","import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { formatWithBiome } from \"../project.js\";\nimport { toPascalCase } from \"../utils.js\";\n\ninterface TestShape {\n\t/** Service constructor takes the repository as a dependency. */\n\tinjectsRepo: boolean;\n\thasRepoFile: boolean;\n}\n\nfunction generateTest(\n\tname: string,\n\tpascalName: string,\n\tshape: TestShape,\n): string {\n\tconst repoImport = shape.hasRepoFile\n\t\t? `import { ${pascalName}Repository } from \"@/modules/${name}/${name}.repository\";\\n`\n\t\t: \"\";\n\tconst repoCast = shape.hasRepoFile\n\t\t? `mockRepo as unknown as ${pascalName}Repository`\n\t\t: `mockRepo as any`;\n\n\tif (!shape.injectsRepo) {\n\t\treturn `import { describe, it, expect, beforeEach } from \"bun:test\";\nimport { ${pascalName}Service } from \"@/modules/${name}/${name}.service\";\n\ndescribe(\"${pascalName}Service\", () => {\n  let service: ${pascalName}Service;\n\n  beforeEach(() => {\n    service = new ${pascalName}Service();\n  });\n\n  it(\"should be defined\", () => {\n    expect(service).toBeDefined();\n  });\n\n  it(\"should return an array of items\", async () => {\n    const result = await service.getAll();\n    expect(result).toBeInstanceOf(Array);\n  });\n\n  it(\"should return a single item by id\", async () => {\n    const result = await service.getById(1);\n    expect(result).toHaveProperty(\"id\", 1);\n  });\n\n  // TODO: Add more business logic tests here\n});\n`;\n\t}\n\n\treturn `import { describe, it, expect, beforeEach, mock } from \"bun:test\";\nimport { ${pascalName}Service } from \"@/modules/${name}/${name}.service\";\n${repoImport}\ndescribe(\"${pascalName}Service\", () => {\n  let service: ${pascalName}Service;\n  let mockRepo: any;\n\n  beforeEach(() => {\n    // 1. Mock the repository layer\n    mockRepo = {\n      findAll: mock(() => Promise.resolve([])),\n      findById: mock((id: number) => Promise.resolve({ id, name: \"Test ${pascalName}\" })),\n      create: mock((data: any) => Promise.resolve({ id: 1, ...data })),\n      update: mock((id: number, data: any) => Promise.resolve({ id, ...data })),\n      delete: mock((id: number) => Promise.resolve({ id })),\n      count: mock(() => Promise.resolve(0)),\n    };\n\n    // 2. Inject mock repo into the service\n    service = new ${pascalName}Service(${repoCast});\n  });\n\n  it(\"should be defined\", () => {\n    expect(service).toBeDefined();\n  });\n\n  it(\"should return an array of items\", async () => {\n    const result = await service.getAll();\n    expect(result).toBeInstanceOf(Array);\n    expect(mockRepo.findAll).toHaveBeenCalledTimes(1);\n  });\n\n  it(\"should return a single item by id\", async () => {\n    const result = await service.getById(1);\n    expect(result).toHaveProperty(\"id\", 1);\n    expect(result).toHaveProperty(\"name\", \"Test ${pascalName}\");\n    expect(mockRepo.findById).toHaveBeenCalledWith(1);\n  });\n\n  // TODO: Add more business logic tests here\n});\n`;\n}\n\nexport async function makeTestCommand(name: string, flags: string[] = []) {\n\tconst pascalName = toPascalCase(name);\n\tconst dryRun = flags.includes(\"--dry-run\");\n\tconst force = flags.includes(\"--force\");\n\tconsole.log(`\\n\\x1b[36mScaffolding Unit Test for ${pascalName}${dryRun ? \" (dry-run)\" : \"\"}...\\x1b[0m\\n`);\n\n\t// Stack awareness: the test must match what actually exists on disk\n\tconst servicePath = join(\"src\", \"modules\", name, `${name}.service.ts`);\n\tconst repoPath = join(\"src\", \"modules\", name, `${name}.repository.ts`);\n\tconst hasService = existsSync(servicePath);\n\tconst hasRepo = existsSync(repoPath);\n\n\tif (!hasService) {\n\t\tconsole.error(\n\t\t\t`\\x1b[31mError: No service found at ${servicePath} — the unit test would import a file that does not exist.\\x1b[0m`,\n\t\t);\n\t\tconsole.error(\n\t\t\t`  Generate it first: \\x1b[36mbuntok create ${name} --service\\x1b[0m`,\n\t\t);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst serviceSource = await fs.readFile(servicePath, \"utf-8\");\n\tconst shape: TestShape = {\n\t\tinjectsRepo: /constructor\\s*\\(/.test(serviceSource),\n\t\thasRepoFile: hasRepo,\n\t};\n\n\tconst testsDir = \"tests\";\n\n\tif (!existsSync(testsDir)) {\n\t\tif (dryRun) {\n\t\t\tconsole.log(`\\x1b[90mWould create directory: ${testsDir}\\x1b[0m`);\n\t\t} else {\n\t\t\tawait fs.mkdir(testsDir, { recursive: true });\n\t\t}\n\t}\n\n\tconst filePath = join(testsDir, `${name}.spec.ts`);\n\n\tif (existsSync(filePath) && !force) {\n\t\tconsole.error(\n\t\t\t`\\x1b[31mError: Test file already exists at ${filePath} (use --force to overwrite)\\x1b[0m`,\n\t\t);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst content = generateTest(name, pascalName, shape);\n\n\tif (dryRun) {\n\t\tconsole.log(`\\x1b[90mWould create file: ${filePath}\\x1b[0m`);\n\t\tconsole.log(`\\n\\x1b[36m--- Generated content ---\\x1b[0m\\n`);\n\t\tconsole.log(content);\n\t\treturn;\n\t}\n\n\tawait fs.writeFile(filePath, content);\n\n\tif (formatWithBiome([filePath])) {\n\t\tconsole.log(\n\t\t\t\"\\x1b[90m✨ Auto-formatted generated test file with Biome\\x1b[0m\",\n\t\t);\n\t}\n\n\tconsole.log(`\\x1b[32m✓ Generated test suite:\\x1b[0m ${filePath}`);\n\n\tconsole.log(`\n\\x1b[36mNext steps:\\x1b[0m\n  Run your test suite instantly using Bun's native test runner:\n     \\x1b[33mbun test\\x1b[0m\n     \\x1b[33mbun test --watch\\x1b[0m  (For TDD / Live Reload)\n`);\n}\n","import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { formatWithBiome } from \"../project.js\";\nimport { resolveNames, toPascalCase } from \"../utils.js\";\n\nfunction generateE2ETest(name: string, pascalName: string): string {\n\tconst route = resolveNames(name).route;\n\treturn `import { describe, it, expect } from \"bun:test\";\nimport { app } from \"@/index\";\n\ndescribe(\"${pascalName} API (E2E)\", () => {\n  it(\"should return a list of items (GET /${route})\", async () => {\n    const response = await app.request(\"/${route}\", {\n      method: \"GET\",\n    });\n\n    expect(response.status).toBe(200);\n\n    // const body = await response.json();\n    // expect(Array.isArray(body)).toBe(true);\n  });\n\n  it(\"should create a new item (POST /${route})\", async () => {\n    const response = await app.request(\"/${route}\", {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application/json\",\n      },\n      body: JSON.stringify({\n        // TODO: add payload here\n      }),\n    });\n\n    // expect(response.status).toBe(201);\n  });\n\n  it(\"should handle not found items (GET /${route}/999999)\", async () => {\n    const response = await app.request(\"/${route}/999999\", {\n      method: \"GET\",\n    });\n\n    // expect(response.status).toBe(404);\n  });\n});\n`;\n}\n\nexport async function makeTestE2ECommand(name: string, flags: string[] = []) {\n\tconst pascalName = toPascalCase(name);\n\tconst dryRun = flags.includes(\"--dry-run\");\n\tconst force = flags.includes(\"--force\");\n\tconsole.log(\n\t\t`\\n\\x1b[36mScaffolding E2E Test for ${pascalName} API${dryRun ? \" (dry-run)\" : \"\"}...\\x1b[0m\\n`,\n\t);\n\n\tconst testsDir = \"tests/e2e\";\n\n\tif (!existsSync(testsDir)) {\n\t\tif (dryRun) {\n\t\t\tconsole.log(`\\x1b[90mWould create directory: ${testsDir}\\x1b[0m`);\n\t\t} else {\n\t\t\tawait fs.mkdir(testsDir, { recursive: true });\n\t\t}\n\t}\n\n\tconst filePath = join(testsDir, `${name}.e2e.spec.ts`);\n\n\tif (existsSync(filePath) && !force) {\n\t\tconsole.error(\n\t\t\t`\\x1b[31mError: E2E Test file already exists at ${filePath} (use --force to overwrite)\\x1b[0m`,\n\t\t);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst content = generateE2ETest(name, pascalName);\n\n\tif (dryRun) {\n\t\tconsole.log(`\\x1b[90mWould create file: ${filePath}\\x1b[0m`);\n\t\tconsole.log(`\\n\\x1b[36m--- Generated content ---\\x1b[0m\\n`);\n\t\tconsole.log(content);\n\t\treturn;\n\t}\n\n\tawait fs.writeFile(filePath, content);\n\n\tif (formatWithBiome([filePath])) {\n\t\tconsole.log(\n\t\t\t\"\\x1b[90m✨ Auto-formatted generated E2E test file with Biome\\x1b[0m\",\n\t\t);\n\t}\n\n\tconsole.log(`\\x1b[32m✓ Generated E2E test suite:\\x1b[0m ${filePath}`);\n\n\tconsole.log(`\n\\x1b[36mNext steps:\\x1b[0m\n  Run all E2E tests:\n     \\x1b[33mbun test tests/e2e\\x1b[0m\n`);\n}\n","#!/usr/bin/env bun\n\nimport { buildCommand } from \"./commands/build.js\";\nimport { checkCommand } from \"./commands/check.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { dbCommand } from \"./commands/db.js\";\nimport { debugRoutesCommand } from \"./commands/debug-routes.js\";\nimport { devCommand } from \"./commands/dev.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { makeDocsCommand } from \"./commands/make-docs.js\";\nimport { makeFactoryCommand } from \"./commands/make-factory.js\";\nimport { makeMiddlewareCommand } from \"./commands/make-middleware.js\";\nimport { makeSeederCommand } from \"./commands/make-seeder.js\";\nimport { makeTestCommand } from \"./commands/make-test.js\";\nimport { makeTestE2ECommand } from \"./commands/make-test-e2e.js\";\nimport { VERSION } from \"../core-exports.js\";\n\nfunction printBanner() {\n\tconsole.log(`\n\\x1b[36m  Buntok CLI v${VERSION}\\x1b[0m\n`);\n}\n\nfunction printUsage() {\n\tconsole.log(`\n\\x1b[36mUsage:\\x1b[0m\n  buntok <command> [arguments] [options]\n\n\\x1b[36mCommands:\\x1b[0m\n  init                   Setup project: copy SKILL.md + configure package.json + generate env.ts\n  dev                    Start development server with hot reload\n  build                  Build project for production (output → .buntok/)\n  check                  Run TypeScript type check\n  create <entity>        Generate all files for entity (repo, service, controller, schema)\n  db <command>           Database operations (migrate, seed, reset, generate, studio, status)\n  debug:routes           Show all registered routes with middleware chains\n  make:docs              Generate OpenAPI documentation automatically\n  make:factory <entity>  Generate data factory for entity\n  make:test <entity>     Generate unit test for entity\n  make:test:e2e <entity> Generate E2E test for entity\n  make:seeder <entity>   Generate database seeder for entity\n  make:middleware <name>  Generate middleware file\n\n\\x1b[36mOptions (for create):\\x1b[0m\n  --repo                 Generate only repository\n  --service              Generate only service\n  --controller           Generate only controller\n  --schema               Generate only schema\n  --prisma               Use Prisma ORM (default: auto-detect)\n  --drizzle              Use Drizzle ORM\n  --typeorm              Use TypeORM\n  --dry-run              Preview files without writing\n  --force                Overwrite files that already exist\n  --base                 Generate code extending BaseRepository/BaseService/BaseController (default: plain code)\n  --fields \"a:string,b:int?\"  Field list for the schema when there is no Prisma model\n\n\\x1b[36mOptions (for check command):\\x1b[0m\n  --json                 Output results as JSON\n  --plain                Plain text output without colors\n\n\\x1b[36mOptions (for make:* commands):\\x1b[0m\n  --dry-run              Preview generated content without writing\n  --force                Overwrite file that already exists\n  --factory              (make:seeder) Use factory pattern data\n\n\\x1b[36mAliases:\\x1b[0m\n  g, gen, generate       Shortcut for create\n\n\\x1b[36mExamples:\\x1b[0m\n  buntok init                             # Initialize project setup\n  buntok dev                              # Start development server\n  buntok dev --expose                     # Start with public tunnel URL\n  buntok dev --expose --port=3000         # Start with tunnel on port 3000\n  buntok build                            # Build project for production\n  buntok check                            # Run TypeScript type check\n  buntok create user                      # Generate all files for user entity\n  buntok g user --repo --service          # Generate repository and service only\n  buntok g user --drizzle                 # Generate with Drizzle ORM\n  buntok g user --dry-run                 # Preview what would be generated\n  buntok db migrate                       # Run pending migrations\n  buntok db seed                          # Seed database\n  buntok debug:routes                     # Show all registered routes\n  buntok debug:routes --json              # Output routes as JSON\n  buntok make:factory user                # Generate user data factory\n  buntok make:docs                        # Generate OpenAPI documentation\n  buntok make:test user                   # Generate unit test for user\n  buntok make:test:e2e user               # Generate E2E test for user API\n  buntok make:seeder user                 # Generate user seeder\n  buntok make:middleware auth             # Generate auth middleware\n`);\n}\n\nexport async function main() {\n\tconst args = process.argv.slice(2);\n\tconst command = args[0];\n\tconst arg1 = args[1];\n\n\tif (!command) {\n\t\tprintBanner();\n\t\tprintUsage();\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tswitch (command) {\n\t\tcase \"init\":\n\t\t\tawait initCommand();\n\t\t\tbreak;\n\t\tcase \"build\":\n\t\t\tawait buildCommand();\n\t\t\tbreak;\n\t\tcase \"check\":\n\t\t\tawait checkCommand(args.slice(1));\n\t\t\tbreak;\n\t\tcase \"dev\":\n\t\t\tawait devCommand(args.slice(1));\n\t\t\tbreak;\n\t\tcase \"g\":\n\t\tcase \"gen\":\n\t\tcase \"generate\":\n\t\tcase \"create\":\n\t\t\tif (!arg1) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"\\x1b[31mError: entity name is required for create command\\x1b[0m\",\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait createCommand(arg1, args.slice(2));\n\t\t\tbreak;\n\t\tcase \"db\":\n\t\t\tawait dbCommand(args.slice(1));\n\t\t\tbreak;\n\t\tcase \"debug:routes\":\n\t\t\tawait debugRoutesCommand(args.slice(1));\n\t\t\tbreak;\n\t\tcase \"make:docs\":\n\t\t\tawait makeDocsCommand();\n\t\t\tbreak;\n\t\tcase \"make:factory\":\n\t\t\tif (!arg1) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"\\x1b[31mError: entity name is required for make:factory command\\x1b[0m\",\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait makeFactoryCommand(arg1, args.slice(2));\n\t\t\tbreak;\n\t\tcase \"make:test\":\n\t\t\tif (!arg1) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"\\x1b[31mError: entity name is required for make:test command\\x1b[0m\",\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait makeTestCommand(arg1, args.slice(2));\n\t\t\tbreak;\n\t\tcase \"make:test:e2e\":\n\t\t\tif (!arg1) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"\\x1b[31mError: entity name is required for make:test:e2e command\\x1b[0m\",\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait makeTestE2ECommand(arg1, args.slice(2));\n\t\t\tbreak;\n\t\tcase \"make:seeder\":\n\t\t\tif (!arg1) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"\\x1b[31mError: entity name is required for make:seeder command\\x1b[0m\",\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait makeSeederCommand(arg1, args.slice(2));\n\t\t\tbreak;\n\t\tcase \"make:middleware\":\n\t\t\tif (!arg1) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"\\x1b[31mError: middleware name is required for make:middleware command\\x1b[0m\",\n\t\t\t\t);\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait makeMiddlewareCommand(arg1, args.slice(2));\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\tconst commands = [\n\t\t\t\t\"init\",\n\t\t\t\t\"dev\",\n\t\t\t\t\"build\",\n\t\t\t\t\"check\",\n\t\t\t\t\"create\",\n\t\t\t\t\"g\",\n\t\t\t\t\"db\",\n\t\t\t\t\"debug:routes\",\n\t\t\t\t\"make:docs\",\n\t\t\t\t\"make:factory\",\n\t\t\t\t\"make:test\",\n\t\t\t\t\"make:test:e2e\",\n\t\t\t\t\"make:seeder\",\n\t\t\t\t\"make:middleware\",\n\t\t\t];\n\t\t\t// Simple fuzzy match: prefix or contains\n\t\t\tconst closest = commands.find(\n\t\t\t\t(c) =>\n\t\t\t\t\tc.startsWith(command) ||\n\t\t\t\t\tcommand.startsWith(c) ||\n\t\t\t\t\tc.includes(command) ||\n\t\t\t\t\tcommand.includes(c),\n\t\t\t);\n\t\t\tconst hint = closest ? `\\n  Did you mean: buntok ${closest}?` : \"\";\n\t\t\tconsole.error(`\\x1b[31mUnknown command: ${command}\\x1b[0m${hint}`);\n\t\t\tprintUsage();\n\t\t\tprocess.exitCode = 1;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nmain();\n"]}