create-nexst-monorepo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/dist/index.js +1727 -0
  2. package/package.json +37 -0
  3. package/template/.agents/plugins/marketplace.json +21 -0
  4. package/template/.claude/settings.json +6 -0
  5. package/template/.claude/skills/frontend-design/LICENSE.txt +177 -0
  6. package/template/.claude/skills/frontend-design/SKILL.md +154 -0
  7. package/template/.claude/skills/theme-factory/SKILL.md +95 -0
  8. package/template/.claude/skills/theme-factory/references/schema.md +104 -0
  9. package/template/.claude/skills/theme-factory/scripts/theme.mjs +261 -0
  10. package/template/.dockerignore +43 -0
  11. package/template/.editorconfig +10 -0
  12. package/template/.github/workflows/ci.yaml +289 -0
  13. package/template/.github/workflows/publish-app.yaml +66 -0
  14. package/template/.github/workflows/publish.yaml +148 -0
  15. package/template/.github/workflows/snyk.yaml +34 -0
  16. package/template/.vscode/settings.json +8 -0
  17. package/template/AGENTS.md +42 -0
  18. package/template/Dockerfile.base +9 -0
  19. package/template/README.md +54 -0
  20. package/template/_gitignore +10 -0
  21. package/template/apps/api/.env.example +32 -0
  22. package/template/apps/api/AGENTS.md +44 -0
  23. package/template/apps/api/Dockerfile +69 -0
  24. package/template/apps/api/_gitignore +8 -0
  25. package/template/apps/api/knip.config.ts +22 -0
  26. package/template/apps/api/kustomize/base/application.properties +16 -0
  27. package/template/apps/api/kustomize/base/deployment.yaml +94 -0
  28. package/template/apps/api/kustomize/base/kustomization.yaml +17 -0
  29. package/template/apps/api/kustomize/base/service.yaml +10 -0
  30. package/template/apps/api/kustomize/overlays/prod/kustomization.yaml +17 -0
  31. package/template/apps/api/kustomize/overlays/staging/application.properties +1 -0
  32. package/template/apps/api/kustomize/overlays/staging/kustomization.yaml +21 -0
  33. package/template/apps/api/kustomize/secret.keys +14 -0
  34. package/template/apps/api/oxfmt.config.ts +8 -0
  35. package/template/apps/api/oxlint.config.ts +107 -0
  36. package/template/apps/api/package.json +79 -0
  37. package/template/apps/api/prisma/migrations/20260927000000_init/migration.sql +113 -0
  38. package/template/apps/api/prisma/migrations/migration_lock.toml +3 -0
  39. package/template/apps/api/prisma/schema.prisma +113 -0
  40. package/template/apps/api/prisma.config.ts +7 -0
  41. package/template/apps/api/scripts/auth.cli.ts +19 -0
  42. package/template/apps/api/scripts/seal-secret.sh +171 -0
  43. package/template/apps/api/sonar-project.properties +9 -0
  44. package/template/apps/api/src/app-info/app-info.dto.ts +10 -0
  45. package/template/apps/api/src/app-info/app-info.module.ts +7 -0
  46. package/template/apps/api/src/app-info/app-info.resolver.spec.ts +14 -0
  47. package/template/apps/api/src/app-info/app-info.resolver.ts +21 -0
  48. package/template/apps/api/src/app.module.spec.ts +93 -0
  49. package/template/apps/api/src/app.module.ts +77 -0
  50. package/template/apps/api/src/auth/auth.guard.spec.ts +90 -0
  51. package/template/apps/api/src/auth/auth.guard.ts +97 -0
  52. package/template/apps/api/src/auth/auth.ts +129 -0
  53. package/template/apps/api/src/auth/decorator/allow-anonymous.decorator.ts +17 -0
  54. package/template/apps/api/src/auth/decorator/is-email-verified.decorator.spec.ts +41 -0
  55. package/template/apps/api/src/auth/decorator/is-email-verified.decorator.ts +20 -0
  56. package/template/apps/api/src/auth/decorator/roles.decorator.ts +27 -0
  57. package/template/apps/api/src/auth/testing/make-session.ts +31 -0
  58. package/template/apps/api/src/auth/types/auth.types.ts +27 -0
  59. package/template/apps/api/src/bootstrap/register-graphql-enums.ts +12 -0
  60. package/template/apps/api/src/bootstrap/security.ts +24 -0
  61. package/template/apps/api/src/bootstrap/swagger.ts +28 -0
  62. package/template/apps/api/src/config/app.config.spec.ts +22 -0
  63. package/template/apps/api/src/config/app.config.ts +122 -0
  64. package/template/apps/api/src/config/graphql-depth-limit.ts +103 -0
  65. package/template/apps/api/src/config/graphql.config.ts +77 -0
  66. package/template/apps/api/src/config/resources/app.yaml +29 -0
  67. package/template/apps/api/src/errors/app-parse-uuid.pipe.ts +27 -0
  68. package/template/apps/api/src/errors/app.exception.ts +47 -0
  69. package/template/apps/api/src/errors/error-code.enum.ts +54 -0
  70. package/template/apps/api/src/errors/http-status-fallback-code.util.ts +27 -0
  71. package/template/apps/api/src/errors/validation-exception.factory.ts +43 -0
  72. package/template/apps/api/src/health/health.controller.spec.ts +82 -0
  73. package/template/apps/api/src/health/health.controller.ts +57 -0
  74. package/template/apps/api/src/health/health.module.ts +12 -0
  75. package/template/apps/api/src/logging/context-logger.ts +18 -0
  76. package/template/apps/api/src/logging/logger.config.ts +23 -0
  77. package/template/apps/api/src/logging/logging.module.ts +22 -0
  78. package/template/apps/api/src/mail/mail.module.ts +12 -0
  79. package/template/apps/api/src/mail/mail.service.spec.ts +47 -0
  80. package/template/apps/api/src/mail/mail.service.ts +123 -0
  81. package/template/apps/api/src/main.ts +41 -0
  82. package/template/apps/api/src/prisma/prisma.module.ts +12 -0
  83. package/template/apps/api/src/prisma/prisma.service.spec.ts +136 -0
  84. package/template/apps/api/src/prisma/prisma.service.ts +138 -0
  85. package/template/apps/api/src/queue/dto/enqueue-example.input.ts +11 -0
  86. package/template/apps/api/src/queue/example-queue.resolver.ts +14 -0
  87. package/template/apps/api/src/queue/example-queue.service.spec.ts +21 -0
  88. package/template/apps/api/src/queue/example-queue.service.ts +32 -0
  89. package/template/apps/api/src/queue/queue.module.ts +27 -0
  90. package/template/apps/api/src/r2/r2.module.ts +12 -0
  91. package/template/apps/api/src/r2/r2.service.spec.ts +117 -0
  92. package/template/apps/api/src/r2/r2.service.ts +131 -0
  93. package/template/apps/api/src/user/dto/user.dto.ts +26 -0
  94. package/template/apps/api/src/user/user.module.ts +10 -0
  95. package/template/apps/api/src/user/user.resolver.spec.ts +18 -0
  96. package/template/apps/api/src/user/user.resolver.ts +24 -0
  97. package/template/apps/api/src/utils/catch-everything-exception.filter.spec.ts +292 -0
  98. package/template/apps/api/src/utils/catch-everything-exception.filter.ts +70 -0
  99. package/template/apps/api/src/utils/error-handler.util.spec.ts +20 -0
  100. package/template/apps/api/src/utils/error-handler.util.ts +12 -0
  101. package/template/apps/api/src/utils/escape-like-pattern.util.spec.ts +29 -0
  102. package/template/apps/api/src/utils/escape-like-pattern.util.ts +11 -0
  103. package/template/apps/api/src/utils/pagination.input.ts +20 -0
  104. package/template/apps/api/src/utils/prisma-exception.filter.spec.ts +186 -0
  105. package/template/apps/api/src/utils/prisma-exception.filter.ts +45 -0
  106. package/template/apps/api/src/utils/prisma-graphql-exception.filter.spec.ts +216 -0
  107. package/template/apps/api/src/utils/prisma-graphql-exception.filter.ts +43 -0
  108. package/template/apps/api/tests/app.e2e-spec.ts +35 -0
  109. package/template/apps/api/tests/auth.e2e-spec.ts +38 -0
  110. package/template/apps/api/tests/helpers/api.ts +27 -0
  111. package/template/apps/api/tsconfig.json +11 -0
  112. package/template/apps/api/vitest.config.e2e.ts +16 -0
  113. package/template/apps/api/vitest.config.ts +40 -0
  114. package/template/apps/web/.env.example +7 -0
  115. package/template/apps/web/.storybook/decorators.tsx +38 -0
  116. package/template/apps/web/.storybook/main.ts +17 -0
  117. package/template/apps/web/.storybook/preview.ts +38 -0
  118. package/template/apps/web/.storybook/vitest.setup.ts +5 -0
  119. package/template/apps/web/AGENTS.md +29 -0
  120. package/template/apps/web/Dockerfile +49 -0
  121. package/template/apps/web/_gitignore +16 -0
  122. package/template/apps/web/knip.config.ts +15 -0
  123. package/template/apps/web/kustomize/base/application.properties +5 -0
  124. package/template/apps/web/kustomize/base/deployment.yaml +60 -0
  125. package/template/apps/web/kustomize/base/kustomization.yaml +17 -0
  126. package/template/apps/web/kustomize/base/service.yaml +10 -0
  127. package/template/apps/web/kustomize/overlays/prod/kustomization.yaml +12 -0
  128. package/template/apps/web/kustomize/overlays/staging/application.properties +2 -0
  129. package/template/apps/web/kustomize/overlays/staging/kustomization.yaml +18 -0
  130. package/template/apps/web/messages/de.json +124 -0
  131. package/template/apps/web/messages/en.json +124 -0
  132. package/template/apps/web/next-env.d.ts +7 -0
  133. package/template/apps/web/next.config.ts +39 -0
  134. package/template/apps/web/oxfmt.config.ts +9 -0
  135. package/template/apps/web/oxlint.config.ts +36 -0
  136. package/template/apps/web/package.json +80 -0
  137. package/template/apps/web/playwright.config.ts +34 -0
  138. package/template/apps/web/postcss.config.mjs +7 -0
  139. package/template/apps/web/sonar-project.properties +9 -0
  140. package/template/apps/web/src/app/[locale]/(auth)/recovery/page.tsx +22 -0
  141. package/template/apps/web/src/app/[locale]/(auth)/reset-password/page.tsx +29 -0
  142. package/template/apps/web/src/app/[locale]/(auth)/sign-in/page.tsx +24 -0
  143. package/template/apps/web/src/app/[locale]/(auth)/sign-up/page.tsx +24 -0
  144. package/template/apps/web/src/app/[locale]/(auth)/verify/page.tsx +24 -0
  145. package/template/apps/web/src/app/[locale]/dashboard/page.tsx +34 -0
  146. package/template/apps/web/src/app/[locale]/layout.tsx +60 -0
  147. package/template/apps/web/src/app/[locale]/page.tsx +23 -0
  148. package/template/apps/web/src/app/api/health/route.ts +3 -0
  149. package/template/apps/web/src/app/global-error.tsx +19 -0
  150. package/template/apps/web/src/app/globals.css +98 -0
  151. package/template/apps/web/src/app/icon.svg +1 -0
  152. package/template/apps/web/src/app/robots.ts +15 -0
  153. package/template/apps/web/src/app/sitemap.ts +24 -0
  154. package/template/apps/web/src/components/alert/alert.stories.tsx +25 -0
  155. package/template/apps/web/src/components/alert/alert.tsx +50 -0
  156. package/template/apps/web/src/components/avatar/avatar.stories.tsx +116 -0
  157. package/template/apps/web/src/components/avatar/avatar.tsx +88 -0
  158. package/template/apps/web/src/components/button/button-variants.ts +28 -0
  159. package/template/apps/web/src/components/button/button.stories.tsx +33 -0
  160. package/template/apps/web/src/components/button/button.tsx +32 -0
  161. package/template/apps/web/src/components/checkbox/checkbox.stories.tsx +312 -0
  162. package/template/apps/web/src/components/checkbox/checkbox.tsx +38 -0
  163. package/template/apps/web/src/components/dialog/danger-panel.stories.tsx +41 -0
  164. package/template/apps/web/src/components/dialog/danger-panel.tsx +32 -0
  165. package/template/apps/web/src/components/dialog/dialog.stories.tsx +239 -0
  166. package/template/apps/web/src/components/dialog/dialog.tsx +136 -0
  167. package/template/apps/web/src/components/dialog-buttons.stories.tsx +55 -0
  168. package/template/apps/web/src/components/dialog-buttons.tsx +48 -0
  169. package/template/apps/web/src/components/drawer/drawer.stories.tsx +251 -0
  170. package/template/apps/web/src/components/drawer/drawer.tsx +120 -0
  171. package/template/apps/web/src/components/dropdown-menu/dropdown-menu.stories.tsx +329 -0
  172. package/template/apps/web/src/components/dropdown-menu/dropdown-menu.tsx +263 -0
  173. package/template/apps/web/src/components/empty-state.stories.tsx +49 -0
  174. package/template/apps/web/src/components/empty-state.tsx +33 -0
  175. package/template/apps/web/src/components/field-group.stories.tsx +47 -0
  176. package/template/apps/web/src/components/field-group.tsx +20 -0
  177. package/template/apps/web/src/components/field-label.stories.tsx +34 -0
  178. package/template/apps/web/src/components/field-label.tsx +28 -0
  179. package/template/apps/web/src/components/icons.tsx +25 -0
  180. package/template/apps/web/src/components/input/input-otp.stories.tsx +86 -0
  181. package/template/apps/web/src/components/input/input-otp.tsx +184 -0
  182. package/template/apps/web/src/components/input/input.stories.tsx +35 -0
  183. package/template/apps/web/src/components/input/input.tsx +180 -0
  184. package/template/apps/web/src/components/popover/popover.stories.tsx +479 -0
  185. package/template/apps/web/src/components/popover/popover.tsx +45 -0
  186. package/template/apps/web/src/components/responsive-dialog/responsive-dialog.stories.tsx +307 -0
  187. package/template/apps/web/src/components/responsive-dialog/responsive-dialog.tsx +96 -0
  188. package/template/apps/web/src/components/searchbar/searchbar.stories.tsx +59 -0
  189. package/template/apps/web/src/components/searchbar/searchbar.tsx +64 -0
  190. package/template/apps/web/src/components/select/select.stories.tsx +293 -0
  191. package/template/apps/web/src/components/select/select.tsx +445 -0
  192. package/template/apps/web/src/components/skeleton/skeleton.stories.tsx +76 -0
  193. package/template/apps/web/src/components/skeleton/skeleton.tsx +13 -0
  194. package/template/apps/web/src/components/spinner/spinner.tsx +18 -0
  195. package/template/apps/web/src/components/switch/switch.stories.tsx +71 -0
  196. package/template/apps/web/src/components/switch/switch.tsx +35 -0
  197. package/template/apps/web/src/components/tabs/tabs.stories.tsx +209 -0
  198. package/template/apps/web/src/components/tabs/tabs.tsx +69 -0
  199. package/template/apps/web/src/components/tabs/url-tabs.stories.tsx +68 -0
  200. package/template/apps/web/src/components/tabs/url-tabs.tsx +42 -0
  201. package/template/apps/web/src/components/textarea/textarea.stories.tsx +144 -0
  202. package/template/apps/web/src/components/textarea/textarea.tsx +115 -0
  203. package/template/apps/web/src/components/toast/toaster.tsx +38 -0
  204. package/template/apps/web/src/components/tooltip/tooltip.stories.tsx +237 -0
  205. package/template/apps/web/src/components/tooltip/tooltip.tsx +49 -0
  206. package/template/apps/web/src/config/csp.ts +59 -0
  207. package/template/apps/web/src/config/routes.ts +14 -0
  208. package/template/apps/web/src/config/site.ts +5 -0
  209. package/template/apps/web/src/env.ts +15 -0
  210. package/template/apps/web/src/features/auth/auth-card.tsx +20 -0
  211. package/template/apps/web/src/features/auth/auth-divider.tsx +14 -0
  212. package/template/apps/web/src/features/auth/google-auth-button.tsx +49 -0
  213. package/template/apps/web/src/features/auth/google-one-tap.tsx +23 -0
  214. package/template/apps/web/src/features/auth/lib/auth-error.test.ts +22 -0
  215. package/template/apps/web/src/features/auth/lib/auth-error.ts +16 -0
  216. package/template/apps/web/src/features/auth/lib/return-to.test.ts +41 -0
  217. package/template/apps/web/src/features/auth/lib/return-to.ts +19 -0
  218. package/template/apps/web/src/features/auth/lib/validator.test.ts +45 -0
  219. package/template/apps/web/src/features/auth/lib/validator.ts +49 -0
  220. package/template/apps/web/src/features/auth/passkey-settings.tsx +106 -0
  221. package/template/apps/web/src/features/auth/recovery-form.tsx +61 -0
  222. package/template/apps/web/src/features/auth/resend-verification-button.tsx +36 -0
  223. package/template/apps/web/src/features/auth/reset-password-form.tsx +62 -0
  224. package/template/apps/web/src/features/auth/sign-in-form.stories.tsx +22 -0
  225. package/template/apps/web/src/features/auth/sign-in-form.tsx +116 -0
  226. package/template/apps/web/src/features/auth/sign-out-button.tsx +26 -0
  227. package/template/apps/web/src/features/auth/sign-up-form.tsx +107 -0
  228. package/template/apps/web/src/features/shared/provider.tsx +16 -0
  229. package/template/apps/web/src/features/shared/site-header.tsx +48 -0
  230. package/template/apps/web/src/features/shared/theme-toggle.tsx +24 -0
  231. package/template/apps/web/src/i18n/navigation.ts +5 -0
  232. package/template/apps/web/src/i18n/request.ts +21 -0
  233. package/template/apps/web/src/i18n/routing.ts +6 -0
  234. package/template/apps/web/src/lib/auth-client.ts +19 -0
  235. package/template/apps/web/src/lib/auth-server.ts +46 -0
  236. package/template/apps/web/src/lib/auth.ts +8 -0
  237. package/template/apps/web/src/lib/codegen.ts +30 -0
  238. package/template/apps/web/src/lib/graphql-client.ts +29 -0
  239. package/template/apps/web/src/lib/graphql-server.ts +28 -0
  240. package/template/apps/web/src/lib/graphql-utils.test.ts +32 -0
  241. package/template/apps/web/src/lib/graphql-utils.ts +76 -0
  242. package/template/apps/web/src/lib/hooks/use-media-query.ts +21 -0
  243. package/template/apps/web/src/lib/metadata.ts +17 -0
  244. package/template/apps/web/src/lib/network-error.test.ts +30 -0
  245. package/template/apps/web/src/lib/network-error.ts +17 -0
  246. package/template/apps/web/src/lib/proxy-utils.ts +42 -0
  247. package/template/apps/web/src/lib/query-client.ts +29 -0
  248. package/template/apps/web/src/lib/utils.ts +5 -0
  249. package/template/apps/web/src/proxy.ts +57 -0
  250. package/template/apps/web/test-results/.last-run.json +4 -0
  251. package/template/apps/web/tests/auth.spec.ts +17 -0
  252. package/template/apps/web/tests/csp-theme-script.spec.ts +37 -0
  253. package/template/apps/web/tests/home.spec.ts +25 -0
  254. package/template/apps/web/tsconfig.build.json +4 -0
  255. package/template/apps/web/tsconfig.json +28 -0
  256. package/template/apps/web/vitest.config.ts +40 -0
  257. package/template/apps/web/vitest.shims.d.ts +1 -0
  258. package/template/apps/worker/.env.example +4 -0
  259. package/template/apps/worker/AGENTS.md +11 -0
  260. package/template/apps/worker/Dockerfile +35 -0
  261. package/template/apps/worker/knip.config.ts +3 -0
  262. package/template/apps/worker/kustomize/base/application.properties +4 -0
  263. package/template/apps/worker/kustomize/base/deployment.yaml +62 -0
  264. package/template/apps/worker/kustomize/base/kustomization.yaml +16 -0
  265. package/template/apps/worker/kustomize/overlays/prod/kustomization.yaml +12 -0
  266. package/template/apps/worker/kustomize/overlays/staging/application.properties +1 -0
  267. package/template/apps/worker/kustomize/overlays/staging/kustomization.yaml +18 -0
  268. package/template/apps/worker/oxfmt.config.ts +8 -0
  269. package/template/apps/worker/oxlint.config.ts +15 -0
  270. package/template/apps/worker/package.json +33 -0
  271. package/template/apps/worker/sonar-project.properties +8 -0
  272. package/template/apps/worker/src/env.ts +13 -0
  273. package/template/apps/worker/src/lib/graceful-shutdown.ts +27 -0
  274. package/template/apps/worker/src/lib/logger.ts +20 -0
  275. package/template/apps/worker/src/main.ts +17 -0
  276. package/template/apps/worker/src/processors/example-processor.ts +15 -0
  277. package/template/apps/worker/src/worker/redis.ts +19 -0
  278. package/template/apps/worker/src/worker/worker.ts +37 -0
  279. package/template/apps/worker/tests/example-processor.test.ts +13 -0
  280. package/template/apps/worker/tests/graceful-shutdown.test.ts +34 -0
  281. package/template/apps/worker/tsconfig.json +4 -0
  282. package/template/apps/worker/vitest.config.ts +13 -0
  283. package/template/bun.lock +3053 -0
  284. package/template/bunfig.toml +2 -0
  285. package/template/compose.yaml +53 -0
  286. package/template/docker-bake.hcl +86 -0
  287. package/template/package.json +47 -0
  288. package/template/packages/lint/knip.ts +40 -0
  289. package/template/packages/lint/oxfmt.ts +8 -0
  290. package/template/packages/lint/oxlint.ts +136 -0
  291. package/template/packages/lint/package.json +13 -0
  292. package/template/packages/queues/oxfmt.config.ts +8 -0
  293. package/template/packages/queues/oxlint.config.ts +7 -0
  294. package/template/packages/queues/package.json +15 -0
  295. package/template/packages/queues/src/example-job.ts +11 -0
  296. package/template/packages/queues/src/index.ts +3 -0
  297. package/template/packages/queues/src/queue-names.ts +2 -0
  298. package/template/packages/queues/src/redis-connection.ts +27 -0
  299. package/template/packages/queues/tsconfig.json +4 -0
  300. package/template/packages/tsconfig/base.json +23 -0
  301. package/template/packages/tsconfig/node.json +11 -0
  302. package/template/packages/tsconfig/package.json +4 -0
  303. package/template/turbo.json +50 -0
package/dist/index.js ADDED
@@ -0,0 +1,1727 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ if (mod && typeof mod === "object" || typeof mod === "function") {
23
+ for (let key of __getOwnPropNames(mod))
24
+ if (!__hasOwnProp.call(to, key))
25
+ __defProp(to, key, {
26
+ get: __accessProp.bind(mod, key),
27
+ enumerable: true
28
+ });
29
+ }
30
+ if (canCache)
31
+ cache.set(mod, to);
32
+ return to;
33
+ };
34
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
35
+
36
+ // ../node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
37
+ var require_src = __commonJS(function(exports, module) {
38
+ var ESC = "\x1B";
39
+ var CSI = `${ESC}[`;
40
+ var beep = "\x07";
41
+ var cursor = {
42
+ to(x, y) {
43
+ if (!y)
44
+ return `${CSI}${x + 1}G`;
45
+ return `${CSI}${y + 1};${x + 1}H`;
46
+ },
47
+ move(x, y) {
48
+ let ret = "";
49
+ if (x < 0)
50
+ ret += `${CSI}${-x}D`;
51
+ else if (x > 0)
52
+ ret += `${CSI}${x}C`;
53
+ if (y < 0)
54
+ ret += `${CSI}${-y}A`;
55
+ else if (y > 0)
56
+ ret += `${CSI}${y}B`;
57
+ return ret;
58
+ },
59
+ up: (count = 1) => `${CSI}${count}A`,
60
+ down: (count = 1) => `${CSI}${count}B`,
61
+ forward: (count = 1) => `${CSI}${count}C`,
62
+ backward: (count = 1) => `${CSI}${count}D`,
63
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
64
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
65
+ left: `${CSI}G`,
66
+ hide: `${CSI}?25l`,
67
+ show: `${CSI}?25h`,
68
+ save: `${ESC}7`,
69
+ restore: `${ESC}8`
70
+ };
71
+ var scroll = {
72
+ up: (count = 1) => `${CSI}S`.repeat(count),
73
+ down: (count = 1) => `${CSI}T`.repeat(count)
74
+ };
75
+ var erase = {
76
+ screen: `${CSI}2J`,
77
+ up: (count = 1) => `${CSI}1J`.repeat(count),
78
+ down: (count = 1) => `${CSI}J`.repeat(count),
79
+ line: `${CSI}2K`,
80
+ lineEnd: `${CSI}K`,
81
+ lineStart: `${CSI}1K`,
82
+ lines(count) {
83
+ let clear = "";
84
+ for (let i = 0;i < count; i++)
85
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
86
+ if (count)
87
+ clear += cursor.left;
88
+ return clear;
89
+ }
90
+ };
91
+ module.exports = { cursor, scroll, erase, beep };
92
+ });
93
+
94
+ // src/index.ts
95
+ import { spawnSync } from "node:child_process";
96
+ import { existsSync as existsSync2 } from "node:fs";
97
+ import path2 from "node:path";
98
+ import { fileURLToPath } from "node:url";
99
+ import { parseArgs } from "node:util";
100
+
101
+ // ../node_modules/.bun/@clack+core@1.5.1/node_modules/@clack/core/dist/index.mjs
102
+ import { styleText } from "node:util";
103
+ import { stdout, stdin } from "node:process";
104
+ import * as l from "node:readline";
105
+ import l__default from "node:readline";
106
+
107
+ // ../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
108
+ var getCodePointsLength = (() => {
109
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
110
+ return (input) => {
111
+ let surrogatePairsNr = 0;
112
+ SURROGATE_PAIR_RE.lastIndex = 0;
113
+ while (SURROGATE_PAIR_RE.test(input)) {
114
+ surrogatePairsNr += 1;
115
+ }
116
+ return input.length - surrogatePairsNr;
117
+ };
118
+ })();
119
+ var isFullWidth = (x) => {
120
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
121
+ };
122
+ var isWideNotCJKTNotEmoji = (x) => {
123
+ return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
124
+ };
125
+
126
+ // ../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
127
+ var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
128
+ var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
129
+ var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
130
+ var TAB_RE = /\t{1,1000}/y;
131
+ var EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/yu;
132
+ var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
133
+ var MODIFIER_RE = /\p{M}+/gu;
134
+ var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
135
+ var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
136
+ const LIMIT = truncationOptions.limit ?? Infinity;
137
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
138
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
139
+ const ANSI_WIDTH = 0;
140
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
141
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
142
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
143
+ const FULL_WIDTH_WIDTH = 2;
144
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
145
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
146
+ const PARSE_BLOCKS = [
147
+ [LATIN_RE, REGULAR_WIDTH],
148
+ [ANSI_RE, ANSI_WIDTH],
149
+ [CONTROL_RE, CONTROL_WIDTH],
150
+ [TAB_RE, TAB_WIDTH],
151
+ [EMOJI_RE, EMOJI_WIDTH],
152
+ [CJKT_WIDE_RE, WIDE_WIDTH]
153
+ ];
154
+ let indexPrev = 0;
155
+ let index = 0;
156
+ let length = input.length;
157
+ let lengthExtra = 0;
158
+ let truncationEnabled = false;
159
+ let truncationIndex = length;
160
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
161
+ let unmatchedStart = 0;
162
+ let unmatchedEnd = 0;
163
+ let width = 0;
164
+ let widthExtra = 0;
165
+ outer:
166
+ while (true) {
167
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
168
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
169
+ lengthExtra = 0;
170
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
171
+ const codePoint = char.codePointAt(0) || 0;
172
+ if (isFullWidth(codePoint)) {
173
+ widthExtra = FULL_WIDTH_WIDTH;
174
+ } else if (isWideNotCJKTNotEmoji(codePoint)) {
175
+ widthExtra = WIDE_WIDTH;
176
+ } else {
177
+ widthExtra = REGULAR_WIDTH;
178
+ }
179
+ if (width + widthExtra > truncationLimit) {
180
+ truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
181
+ }
182
+ if (width + widthExtra > LIMIT) {
183
+ truncationEnabled = true;
184
+ break outer;
185
+ }
186
+ lengthExtra += char.length;
187
+ width += widthExtra;
188
+ }
189
+ unmatchedStart = unmatchedEnd = 0;
190
+ }
191
+ if (index >= length) {
192
+ break outer;
193
+ }
194
+ for (let i = 0, l = PARSE_BLOCKS.length;i < l; i++) {
195
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
196
+ BLOCK_RE.lastIndex = index;
197
+ if (BLOCK_RE.test(input)) {
198
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
199
+ widthExtra = lengthExtra * BLOCK_WIDTH;
200
+ if (width + widthExtra > truncationLimit) {
201
+ truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
202
+ }
203
+ if (width + widthExtra > LIMIT) {
204
+ truncationEnabled = true;
205
+ break outer;
206
+ }
207
+ width += widthExtra;
208
+ unmatchedStart = indexPrev;
209
+ unmatchedEnd = index;
210
+ index = indexPrev = BLOCK_RE.lastIndex;
211
+ continue outer;
212
+ }
213
+ }
214
+ index += 1;
215
+ }
216
+ return {
217
+ width: truncationEnabled ? truncationLimit : width,
218
+ index: truncationEnabled ? truncationIndex : length,
219
+ truncated: truncationEnabled,
220
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
221
+ };
222
+ };
223
+ var dist_default = getStringTruncatedWidth;
224
+
225
+ // ../node_modules/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
226
+ var NO_TRUNCATION2 = {
227
+ limit: Infinity,
228
+ ellipsis: "",
229
+ ellipsisWidth: 0
230
+ };
231
+ var fastStringWidth = (input, options = {}) => {
232
+ return dist_default(input, NO_TRUNCATION2, options).width;
233
+ };
234
+ var dist_default2 = fastStringWidth;
235
+
236
+ // ../node_modules/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
237
+ var ESC = "\x1B";
238
+ var CSI = "›";
239
+ var END_CODE = 39;
240
+ var ANSI_ESCAPE_BELL = "\x07";
241
+ var ANSI_CSI = "[";
242
+ var ANSI_OSC = "]";
243
+ var ANSI_SGR_TERMINATOR = "m";
244
+ var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
245
+ var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
246
+ var getClosingCode = (openingCode) => {
247
+ if (openingCode >= 30 && openingCode <= 37)
248
+ return 39;
249
+ if (openingCode >= 90 && openingCode <= 97)
250
+ return 39;
251
+ if (openingCode >= 40 && openingCode <= 47)
252
+ return 49;
253
+ if (openingCode >= 100 && openingCode <= 107)
254
+ return 49;
255
+ if (openingCode === 1 || openingCode === 2)
256
+ return 22;
257
+ if (openingCode === 3)
258
+ return 23;
259
+ if (openingCode === 4)
260
+ return 24;
261
+ if (openingCode === 7)
262
+ return 27;
263
+ if (openingCode === 8)
264
+ return 28;
265
+ if (openingCode === 9)
266
+ return 29;
267
+ if (openingCode === 0)
268
+ return 0;
269
+ return;
270
+ };
271
+ var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
272
+ var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
273
+ var wrapWord = (rows, word, columns) => {
274
+ const characters = word[Symbol.iterator]();
275
+ let isInsideEscape = false;
276
+ let isInsideLinkEscape = false;
277
+ let lastRow = rows.at(-1);
278
+ let visible = lastRow === undefined ? 0 : dist_default2(lastRow);
279
+ let currentCharacter = characters.next();
280
+ let nextCharacter = characters.next();
281
+ let rawCharacterIndex = 0;
282
+ while (!currentCharacter.done) {
283
+ const character = currentCharacter.value;
284
+ const characterLength = dist_default2(character);
285
+ if (visible + characterLength <= columns) {
286
+ rows[rows.length - 1] += character;
287
+ } else {
288
+ rows.push(character);
289
+ visible = 0;
290
+ }
291
+ if (character === ESC || character === CSI) {
292
+ isInsideEscape = true;
293
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
294
+ }
295
+ if (isInsideEscape) {
296
+ if (isInsideLinkEscape) {
297
+ if (character === ANSI_ESCAPE_BELL) {
298
+ isInsideEscape = false;
299
+ isInsideLinkEscape = false;
300
+ }
301
+ } else if (character === ANSI_SGR_TERMINATOR) {
302
+ isInsideEscape = false;
303
+ }
304
+ } else {
305
+ visible += characterLength;
306
+ if (visible === columns && !nextCharacter.done) {
307
+ rows.push("");
308
+ visible = 0;
309
+ }
310
+ }
311
+ currentCharacter = nextCharacter;
312
+ nextCharacter = characters.next();
313
+ rawCharacterIndex += character.length;
314
+ }
315
+ lastRow = rows.at(-1);
316
+ if (!visible && lastRow !== undefined && lastRow.length && rows.length > 1) {
317
+ rows[rows.length - 2] += rows.pop();
318
+ }
319
+ };
320
+ var stringVisibleTrimSpacesRight = (string) => {
321
+ const words = string.split(" ");
322
+ let last = words.length;
323
+ while (last) {
324
+ if (dist_default2(words[last - 1])) {
325
+ break;
326
+ }
327
+ last--;
328
+ }
329
+ if (last === words.length) {
330
+ return string;
331
+ }
332
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
333
+ };
334
+ var exec = (string, columns, options = {}) => {
335
+ if (options.trim !== false && string.trim() === "") {
336
+ return "";
337
+ }
338
+ let returnValue = "";
339
+ let escapeCode;
340
+ let escapeUrl;
341
+ const words = string.split(" ");
342
+ let rows = [""];
343
+ let rowLength = 0;
344
+ for (let index = 0;index < words.length; index++) {
345
+ const word = words[index];
346
+ if (options.trim !== false) {
347
+ const row = rows.at(-1) ?? "";
348
+ const trimmed = row.trimStart();
349
+ if (row.length !== trimmed.length) {
350
+ rows[rows.length - 1] = trimmed;
351
+ rowLength = dist_default2(trimmed);
352
+ }
353
+ }
354
+ if (index !== 0) {
355
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
356
+ rows.push("");
357
+ rowLength = 0;
358
+ }
359
+ if (rowLength || options.trim === false) {
360
+ rows[rows.length - 1] += " ";
361
+ rowLength++;
362
+ }
363
+ }
364
+ const wordLength = dist_default2(word);
365
+ if (options.hard && wordLength > columns) {
366
+ const remainingColumns = columns - rowLength;
367
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
368
+ const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
369
+ if (breaksStartingNextLine < breaksStartingThisLine) {
370
+ rows.push("");
371
+ }
372
+ wrapWord(rows, word, columns);
373
+ rowLength = dist_default2(rows.at(-1) ?? "");
374
+ continue;
375
+ }
376
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
377
+ if (options.wordWrap === false && rowLength < columns) {
378
+ wrapWord(rows, word, columns);
379
+ rowLength = dist_default2(rows.at(-1) ?? "");
380
+ continue;
381
+ }
382
+ rows.push("");
383
+ rowLength = 0;
384
+ }
385
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
386
+ wrapWord(rows, word, columns);
387
+ rowLength = dist_default2(rows.at(-1) ?? "");
388
+ continue;
389
+ }
390
+ rows[rows.length - 1] += word;
391
+ rowLength += wordLength;
392
+ }
393
+ if (options.trim !== false) {
394
+ rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
395
+ }
396
+ const preString = rows.join(`
397
+ `);
398
+ let inSurrogate = false;
399
+ for (let i = 0;i < preString.length; i++) {
400
+ const character = preString[i];
401
+ returnValue += character;
402
+ if (!inSurrogate) {
403
+ inSurrogate = character >= "\uD800" && character <= "\uDBFF";
404
+ if (inSurrogate) {
405
+ continue;
406
+ }
407
+ } else {
408
+ inSurrogate = false;
409
+ }
410
+ if (character === ESC || character === CSI) {
411
+ GROUP_REGEX.lastIndex = i + 1;
412
+ const groupsResult = GROUP_REGEX.exec(preString);
413
+ const groups = groupsResult?.groups;
414
+ if (groups?.code !== undefined) {
415
+ const code = Number.parseFloat(groups.code);
416
+ escapeCode = code === END_CODE ? undefined : code;
417
+ } else if (groups?.uri !== undefined) {
418
+ escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
419
+ }
420
+ }
421
+ if (preString[i + 1] === `
422
+ `) {
423
+ if (escapeUrl) {
424
+ returnValue += wrapAnsiHyperlink("");
425
+ }
426
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : undefined;
427
+ if (escapeCode && closingCode) {
428
+ returnValue += wrapAnsiCode(closingCode);
429
+ }
430
+ } else if (character === `
431
+ `) {
432
+ if (escapeCode && getClosingCode(escapeCode)) {
433
+ returnValue += wrapAnsiCode(escapeCode);
434
+ }
435
+ if (escapeUrl) {
436
+ returnValue += wrapAnsiHyperlink(escapeUrl);
437
+ }
438
+ }
439
+ }
440
+ return returnValue;
441
+ };
442
+ var CRLF_OR_LF = /\r?\n/;
443
+ function wrapAnsi(string, columns, options) {
444
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join(`
445
+ `);
446
+ }
447
+
448
+ // ../node_modules/.bun/@clack+core@1.5.1/node_modules/@clack/core/dist/index.mjs
449
+ var import_sisteransi = __toESM(require_src(), 1);
450
+ import { ReadStream } from "node:tty";
451
+ function findCursor(s, o, l) {
452
+ if (!l.some((r) => !r.disabled))
453
+ return s;
454
+ const t = s + o, n = Math.max(l.length - 1, 0), e = t < 0 ? n : t > n ? 0 : t;
455
+ return l[e]?.disabled ? findCursor(e, o < 0 ? -1 : 1, l) : e;
456
+ }
457
+ var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
458
+ var t = [
459
+ "January",
460
+ "February",
461
+ "March",
462
+ "April",
463
+ "May",
464
+ "June",
465
+ "July",
466
+ "August",
467
+ "September",
468
+ "October",
469
+ "November",
470
+ "December"
471
+ ];
472
+ var settings = {
473
+ actions: new Set(a$1),
474
+ aliases: /* @__PURE__ */ new Map([
475
+ ["k", "up"],
476
+ ["j", "down"],
477
+ ["h", "left"],
478
+ ["l", "right"],
479
+ ["\x03", "cancel"],
480
+ ["escape", "cancel"]
481
+ ]),
482
+ messages: {
483
+ cancel: "Canceled",
484
+ error: "Something went wrong"
485
+ },
486
+ withGuide: true,
487
+ accessible: undefined,
488
+ date: {
489
+ monthNames: [...t],
490
+ messages: {
491
+ required: "Please enter a valid date",
492
+ invalidMonth: "There are only 12 months in a year",
493
+ invalidDay: (n, e) => `There are only ${n} days in ${e}`,
494
+ afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
495
+ beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
496
+ }
497
+ }
498
+ };
499
+ function isAccessible(n) {
500
+ if (n !== undefined)
501
+ return n;
502
+ if (settings.accessible !== undefined)
503
+ return settings.accessible;
504
+ const e = process.env.ACCESSIBLE;
505
+ return e !== undefined && e !== "" && e !== "0" && e !== "false";
506
+ }
507
+ function isActionKey(n, e) {
508
+ if (typeof n == "string")
509
+ return settings.aliases.get(n) === e;
510
+ for (const s of n)
511
+ if (s !== undefined && isActionKey(s, e))
512
+ return true;
513
+ return false;
514
+ }
515
+ function diffLines(i, s) {
516
+ if (i === s)
517
+ return;
518
+ const e = i.split(`
519
+ `), t = s.split(`
520
+ `), r = Math.max(e.length, t.length), f = [];
521
+ for (let n = 0;n < r; n++)
522
+ e[n] !== t[n] && f.push(n);
523
+ return {
524
+ lines: f,
525
+ numLinesBefore: e.length,
526
+ numLinesAfter: t.length,
527
+ numLines: r
528
+ };
529
+ }
530
+ var R = globalThis.process.platform.startsWith("win");
531
+ var CANCEL_SYMBOL = Symbol("clack:cancel");
532
+ function isCancel(e) {
533
+ return e === CANCEL_SYMBOL;
534
+ }
535
+ function setRawMode(e, r) {
536
+ const o = e;
537
+ o.isTTY && o.setRawMode(r);
538
+ }
539
+ function block({
540
+ input: e = stdin,
541
+ output: r = stdout,
542
+ overwrite: o = true,
543
+ hideCursor: n = true
544
+ } = {}) {
545
+ const s = l.createInterface({
546
+ input: e,
547
+ output: r,
548
+ prompt: "",
549
+ tabSize: 1
550
+ });
551
+ l.emitKeypressEvents(e, s), e instanceof ReadStream && e.isTTY && e.setRawMode(true);
552
+ const t = (f, { name: a, sequence: w }) => {
553
+ const c = String(f);
554
+ if (isActionKey([c, a, w], "cancel")) {
555
+ n && r.write(import_sisteransi.cursor.show), process.exit(0);
556
+ return;
557
+ }
558
+ if (!o)
559
+ return;
560
+ const i = a === "return" ? 0 : -1, m = a === "return" ? -1 : 0;
561
+ l.moveCursor(r, i, m, () => {
562
+ l.clearLine(r, 1, () => {
563
+ e.once("keypress", t);
564
+ });
565
+ });
566
+ };
567
+ return n && r.write(import_sisteransi.cursor.hide), e.once("keypress", t), () => {
568
+ e.off("keypress", t), n && r.write(import_sisteransi.cursor.show), e instanceof ReadStream && e.isTTY && !R && e.setRawMode(false), s.terminal = false, s.close();
569
+ };
570
+ }
571
+ var getColumns = (e) => ("columns" in e) && typeof e.columns == "number" ? e.columns : 80;
572
+ var getRows = (e) => ("rows" in e) && typeof e.rows == "number" ? e.rows : 20;
573
+ function wrapTextWithPrefix(e, r, o, n = o, s = o, t) {
574
+ const f = getColumns(e ?? stdout);
575
+ return wrapAnsi(r, f - o.length, {
576
+ hard: true,
577
+ trim: false
578
+ }).split(`
579
+ `).map((c, i, m) => {
580
+ const d = t ? t(c, i) : c;
581
+ return i === 0 ? `${n}${d}` : i === m.length - 1 ? `${s}${d}` : `${o}${d}`;
582
+ }).join(`
583
+ `);
584
+ }
585
+ function runValidation(e, a) {
586
+ if ("~standard" in e) {
587
+ const n = e["~standard"].validate(a);
588
+ return n instanceof Promise ? n.then((r) => r.issues?.at(0)?.message) : n.issues?.at(0)?.message;
589
+ }
590
+ return e(a);
591
+ }
592
+
593
+ class y {
594
+ input;
595
+ output;
596
+ _abortSignal;
597
+ rl;
598
+ opts;
599
+ _render;
600
+ _track = false;
601
+ _prevFrame = "";
602
+ _subscribers = /* @__PURE__ */ new Map;
603
+ _cursor = 0;
604
+ state = "initial";
605
+ error = "";
606
+ value;
607
+ userInput = "";
608
+ get accessible() {
609
+ return isAccessible(this.opts.accessible);
610
+ }
611
+ constructor(t, e = true) {
612
+ const { input: i = stdin, output: s = stdout, render: r, signal: n, ...o } = t;
613
+ this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = r.bind(this), this._track = e, this._abortSignal = n, this.input = i, this.output = s;
614
+ }
615
+ unsubscribe() {
616
+ this._subscribers.clear();
617
+ }
618
+ setSubscriber(t, e) {
619
+ const i = this._subscribers.get(t) ?? [];
620
+ i.push(e), this._subscribers.set(t, i);
621
+ }
622
+ on(t, e) {
623
+ this.setSubscriber(t, { cb: e });
624
+ }
625
+ once(t, e) {
626
+ this.setSubscriber(t, { cb: e, once: true });
627
+ }
628
+ emit(t, ...e) {
629
+ const i = this._subscribers.get(t) ?? [], s = [];
630
+ for (const r of i)
631
+ r.cb(...e), r.once && s.push(() => i.splice(i.indexOf(r), 1));
632
+ for (const r of s)
633
+ r();
634
+ }
635
+ prompt() {
636
+ return new Promise((t) => {
637
+ if (this._abortSignal) {
638
+ if (this._abortSignal.aborted)
639
+ return this.state = "cancel", this.close(), t(CANCEL_SYMBOL);
640
+ this._abortSignal.addEventListener("abort", () => {
641
+ this.state = "cancel", this.close();
642
+ }, { once: true });
643
+ }
644
+ this.rl = l__default.createInterface({
645
+ input: this.input,
646
+ tabSize: 2,
647
+ prompt: "",
648
+ escapeCodeTimeout: 50,
649
+ terminal: true
650
+ }), this.rl.prompt(), this.opts.initialUserInput !== undefined && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
651
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(this.value);
652
+ }), this.once("cancel", () => {
653
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(CANCEL_SYMBOL);
654
+ });
655
+ });
656
+ }
657
+ _isActionKey(t, e) {
658
+ return t === "\t";
659
+ }
660
+ _shouldSubmit(t, e) {
661
+ return true;
662
+ }
663
+ _setValue(t) {
664
+ this.value = t, this.emit("value", this.value);
665
+ }
666
+ _setUserInput(t, e) {
667
+ this.userInput = t ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
668
+ }
669
+ _clearUserInput() {
670
+ this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
671
+ }
672
+ async onKeypress(t, e) {
673
+ if (this.state !== "validating") {
674
+ if (this._track && e.name !== "return" && (e.name && this._isActionKey(t, e) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e?.name && (!this._track && settings.aliases.has(e.name) && this.emit("cursor", settings.aliases.get(e.name)), settings.actions.has(e.name) && this.emit("cursor", e.name)), t && (t.toLowerCase() === "y" || t.toLowerCase() === "n") && this.emit("confirm", t.toLowerCase() === "y"), this.emit("key", t, e), e?.name === "return" && this._shouldSubmit(t, e)) {
675
+ if (this.opts.validate) {
676
+ const i = runValidation(this.opts.validate, this.value);
677
+ let s;
678
+ i instanceof Promise ? (this.state = "validating", this.render(), s = await i) : s = i, s && (this.error = s instanceof Error ? s.message : s, this.state = "error", this.rl?.write(this.userInput));
679
+ }
680
+ this.state !== "error" && (this.state = "submit");
681
+ }
682
+ isActionKey([t, e?.name, e?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
683
+ }
684
+ }
685
+ close() {
686
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
687
+ `), setRawMode(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
688
+ }
689
+ restoreCursor() {
690
+ const t = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
691
+ `).length - 1;
692
+ this.output.write(import_sisteransi.cursor.move(-999, t * -1));
693
+ }
694
+ render() {
695
+ const t = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
696
+ hard: true,
697
+ trim: false
698
+ });
699
+ if (t !== this._prevFrame) {
700
+ if (this.state === "initial")
701
+ this.output.write(import_sisteransi.cursor.hide);
702
+ else {
703
+ const e = diffLines(this._prevFrame, t), i = getRows(this.output);
704
+ if (this.restoreCursor(), e) {
705
+ const s = Math.max(0, e.numLinesAfter - i), r = Math.max(0, e.numLinesBefore - i);
706
+ let n = e.lines.find((o) => o >= s);
707
+ if (n === undefined) {
708
+ this._prevFrame = t;
709
+ return;
710
+ }
711
+ if (e.lines.length === 1) {
712
+ this.output.write(import_sisteransi.cursor.move(0, n - r)), this.output.write(import_sisteransi.erase.lines(1));
713
+ const o = t.split(`
714
+ `);
715
+ this.output.write(o[n]), this._prevFrame = t, this.output.write(import_sisteransi.cursor.move(0, o.length - n - 1));
716
+ return;
717
+ } else if (e.lines.length > 1) {
718
+ if (s < r)
719
+ n = s;
720
+ else {
721
+ const h = n - r;
722
+ h > 0 && this.output.write(import_sisteransi.cursor.move(0, h));
723
+ }
724
+ this.output.write(import_sisteransi.erase.down());
725
+ const f = t.split(`
726
+ `).slice(n);
727
+ this.output.write(f.join(`
728
+ `)), this._prevFrame = t;
729
+ return;
730
+ }
731
+ }
732
+ this.output.write(import_sisteransi.erase.down());
733
+ }
734
+ this.output.write(t), this.state === "initial" && (this.state = "active"), this._prevFrame = t;
735
+ }
736
+ }
737
+ }
738
+ class a extends y {
739
+ options;
740
+ cursor = 0;
741
+ get _value() {
742
+ return this.options[this.cursor]?.value;
743
+ }
744
+ get _enabledOptions() {
745
+ return this.options.filter((e) => e.disabled !== true);
746
+ }
747
+ toggleAll() {
748
+ const e = this._enabledOptions, i = this.value !== undefined && this.value.length === e.length;
749
+ this.value = i ? [] : e.map((t) => t.value);
750
+ }
751
+ toggleInvert() {
752
+ const e = this.value;
753
+ if (!e)
754
+ return;
755
+ const i = this._enabledOptions.filter((t) => !e.includes(t.value));
756
+ this.value = i.map((t) => t.value);
757
+ }
758
+ toggleValue() {
759
+ this.value === undefined && (this.value = []);
760
+ const e = this.value.includes(this._value);
761
+ this.value = e ? this.value.filter((i) => i !== this._value) : [...this.value, this._value];
762
+ }
763
+ constructor(e) {
764
+ super(e, false), this.options = e.options, this.value = [...e.initialValues ?? []];
765
+ const i = Math.max(this.options.findIndex(({ value: t }) => t === e.cursorAt), 0);
766
+ this.cursor = this.options[i]?.disabled ? findCursor(i, 1, this.options) : i, this.on("key", (t, l) => {
767
+ l.name === "a" && this.toggleAll(), l.name === "i" && this.toggleInvert();
768
+ }), this.on("cursor", (t) => {
769
+ switch (t) {
770
+ case "left":
771
+ case "up":
772
+ this.cursor = findCursor(this.cursor, -1, this.options);
773
+ break;
774
+ case "down":
775
+ case "right":
776
+ this.cursor = findCursor(this.cursor, 1, this.options);
777
+ break;
778
+ case "space":
779
+ this.toggleValue();
780
+ break;
781
+ }
782
+ });
783
+ }
784
+ }
785
+ class n extends y {
786
+ get userInputWithCursor() {
787
+ if (this.state === "submit")
788
+ return this.userInput;
789
+ const t = this.userInput;
790
+ if (this.cursor >= t.length)
791
+ return `${this.userInput}█`;
792
+ const r = t.slice(0, this.cursor), s = t.slice(this.cursor, this.cursor + 1), e = t.slice(this.cursor + 1);
793
+ return `${r}${styleText("inverse", s)}${e}`;
794
+ }
795
+ get cursor() {
796
+ return this._cursor;
797
+ }
798
+ constructor(t) {
799
+ super({
800
+ ...t,
801
+ initialUserInput: t.initialUserInput ?? t.initialValue
802
+ }), this.on("userInput", (r) => {
803
+ this._setValue(r);
804
+ }), this.on("finalize", () => {
805
+ this.value || (this.value = t.defaultValue), this.value === undefined && (this.value = "");
806
+ });
807
+ }
808
+ }
809
+
810
+ // ../node_modules/.bun/@clack+prompts@1.8.1/node_modules/@clack/prompts/dist/index.mjs
811
+ import { styleText as styleText2, stripVTControlCharacters } from "node:util";
812
+ import process$1 from "node:process";
813
+ var import_sisteransi2 = __toESM(require_src(), 1);
814
+ function isUnicodeSupported() {
815
+ if (process$1.platform !== "win32") {
816
+ return process$1.env.TERM !== "linux";
817
+ }
818
+ return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
819
+ }
820
+ var unicode = isUnicodeSupported();
821
+ var isCI = () => process.env.CI === "true";
822
+ var unicodeOr = (o, e) => unicode ? o : e;
823
+ var S_STEP_ACTIVE = unicodeOr("◆", "*");
824
+ var S_STEP_CANCEL = unicodeOr("■", "x");
825
+ var S_STEP_ERROR = unicodeOr("▲", "x");
826
+ var S_STEP_SUBMIT = unicodeOr("◇", "o");
827
+ var S_BAR_START = unicodeOr("┌", "T");
828
+ var S_BAR = unicodeOr("│", "|");
829
+ var S_BAR_END = unicodeOr("└", "—");
830
+ var S_BAR_START_RIGHT = unicodeOr("┐", "T");
831
+ var S_BAR_END_RIGHT = unicodeOr("┘", "—");
832
+ var S_RADIO_ACTIVE = unicodeOr("●", ">");
833
+ var S_RADIO_INACTIVE = unicodeOr("○", " ");
834
+ var S_CHECKBOX_ACTIVE = unicodeOr("◻", "[•]");
835
+ var S_CHECKBOX_SELECTED = unicodeOr("◼", "[+]");
836
+ var S_CHECKBOX_INACTIVE = unicodeOr("◻", "[ ]");
837
+ var S_PASSWORD_MASK = unicodeOr("▪", "•");
838
+ var S_BAR_H = unicodeOr("─", "-");
839
+ var S_CORNER_TOP_RIGHT = unicodeOr("╮", "+");
840
+ var S_CONNECT_LEFT = unicodeOr("├", "+");
841
+ var S_CORNER_BOTTOM_RIGHT = unicodeOr("╯", "+");
842
+ var S_CORNER_BOTTOM_LEFT = unicodeOr("╰", "+");
843
+ var S_CORNER_TOP_LEFT = unicodeOr("╭", "+");
844
+ var S_INFO = unicodeOr("●", "•");
845
+ var S_SUCCESS = unicodeOr("◆", "*");
846
+ var S_WARN = unicodeOr("▲", "!");
847
+ var S_ERROR = unicodeOr("■", "x");
848
+ var symbol = (o) => {
849
+ switch (o) {
850
+ case "initial":
851
+ case "active":
852
+ return styleText2("cyan", S_STEP_ACTIVE);
853
+ case "cancel":
854
+ return styleText2("red", S_STEP_CANCEL);
855
+ case "error":
856
+ return styleText2("yellow", S_STEP_ERROR);
857
+ case "submit":
858
+ return styleText2("green", S_STEP_SUBMIT);
859
+ case "validating":
860
+ return styleText2("dim", S_STEP_ACTIVE);
861
+ }
862
+ };
863
+ var symbolBar = (o) => {
864
+ switch (o) {
865
+ case "initial":
866
+ case "active":
867
+ return styleText2("cyan", S_BAR);
868
+ case "cancel":
869
+ return styleText2("red", S_BAR);
870
+ case "error":
871
+ return styleText2("yellow", S_BAR);
872
+ case "submit":
873
+ return styleText2("green", S_BAR);
874
+ }
875
+ };
876
+ function formatInstructionFooter(o, e) {
877
+ const r = [`${e ? `${styleText2("cyan", S_BAR)} ` : ""}${o.join(" • ")}`];
878
+ return e && r.push(styleText2("cyan", S_BAR_END)), r;
879
+ }
880
+ var I = (l, e, w, p, b, C = false) => {
881
+ let r = e, O = 0;
882
+ if (C)
883
+ for (let i = p - 1;i >= w; i--) {
884
+ const m = l[i];
885
+ if (m && (r -= m.length), O++, r <= b)
886
+ break;
887
+ }
888
+ else
889
+ for (let i = w;i < p; i++) {
890
+ const m = l[i];
891
+ if (m && (r -= m.length), O++, r <= b)
892
+ break;
893
+ }
894
+ return { lineCount: r, removals: O };
895
+ };
896
+ var limitOptions = ({
897
+ cursor: l,
898
+ options: e,
899
+ style: w,
900
+ output: p = process.stdout,
901
+ maxItems: b = Number.POSITIVE_INFINITY,
902
+ columnPadding: C = 0,
903
+ rowPadding: r = 4
904
+ }) => {
905
+ const i = getColumns(p) - C, m = getRows(p), M = styleText2("dim", "..."), v = Math.max(m - r, 0), a = Math.max(Math.min(b, v), 5);
906
+ let f = 0;
907
+ l >= a - 3 && (f = Math.max(Math.min(l - a + 3, e.length - a), 0));
908
+ let d = a < e.length && f > 0, c = a < e.length && f + a < e.length;
909
+ const W = Math.min(f + a, e.length), s = [];
910
+ let g = 0;
911
+ d && g++, c && g++;
912
+ const T = f + (d ? 1 : 0), y = W - (c ? 1 : 0);
913
+ for (let t = T;t < y; t++) {
914
+ const n = e[t], o = n ? w(n, t === l) : "", h = wrapAnsi(o, i, {
915
+ hard: true,
916
+ trim: false
917
+ }).split(`
918
+ `);
919
+ s.push(h), g += h.length;
920
+ }
921
+ if (g > v) {
922
+ let t = 0, n = 0, o = g;
923
+ const h = l - T;
924
+ let u = v;
925
+ const L = () => I(s, o, 0, h, u), E = () => I(s, o, h + 1, s.length, u, true);
926
+ d ? ({ lineCount: o, removals: t } = L(), o > u && (c || (u -= 1), { lineCount: o, removals: n } = E())) : (c || (u -= 1), { lineCount: o, removals: n } = E(), o > u && (u -= 1, { lineCount: o, removals: t } = L())), t > 0 && (d = true, s.splice(0, t)), n > 0 && (c = true, s.splice(s.length - n, n));
927
+ }
928
+ const x = [];
929
+ d && x.push(M);
930
+ for (const t of s)
931
+ for (const n of t)
932
+ x.push(n);
933
+ return c && x.push(M), x;
934
+ };
935
+ var MULTISELECT_INSTRUCTIONS = [
936
+ `${styleText2("dim", "↑/↓")} to navigate`,
937
+ `${styleText2("dim", "Space:")} select`,
938
+ `${styleText2("dim", "Enter:")} confirm`
939
+ ];
940
+ var m = (i, u) => i.split(`
941
+ `).map((d) => u(d)).join(`
942
+ `);
943
+ var multiselect = (i) => {
944
+ const u = (t, a) => {
945
+ const r = t.label ?? String(t.value);
946
+ return a === "disabled" ? `${styleText2("gray", S_CHECKBOX_INACTIVE)} ${m(r, (o) => styleText2(["strikethrough", "gray"], o))}${t.hint ? ` ${styleText2("dim", `(${t.hint ?? "disabled"})`)}` : ""}` : a === "active" ? `${styleText2("cyan", S_CHECKBOX_ACTIVE)} ${r}${t.hint ? ` ${styleText2("dim", `(${t.hint})`)}` : ""}` : a === "selected" ? `${styleText2("green", S_CHECKBOX_SELECTED)} ${m(r, (o) => styleText2("dim", o))}${t.hint ? ` ${styleText2("dim", `(${t.hint})`)}` : ""}` : a === "cancelled" ? `${m(r, (o) => styleText2(["strikethrough", "dim"], o))}` : a === "active-selected" ? `${styleText2("green", S_CHECKBOX_SELECTED)} ${r}${t.hint ? ` ${styleText2("dim", `(${t.hint})`)}` : ""}` : a === "submitted" ? `${m(r, (o) => styleText2("dim", o))}` : `${styleText2("dim", S_CHECKBOX_INACTIVE)} ${m(r, (o) => styleText2("dim", o))}`;
947
+ }, d = i.required ?? true, x = i.showInstructions ?? true;
948
+ return new a({
949
+ options: i.options,
950
+ signal: i.signal,
951
+ input: i.input,
952
+ output: i.output,
953
+ initialValues: i.initialValues,
954
+ required: d,
955
+ cursorAt: i.cursorAt,
956
+ validate(t) {
957
+ if (d && (t === undefined || t.length === 0))
958
+ return `Please select at least one option.
959
+ ${styleText2("reset", styleText2("dim", `Press ${styleText2(["gray", "bgWhite", "inverse"], " space ")} to select, ${styleText2("gray", styleText2("bgWhite", styleText2("inverse", " enter ")))} to submit`))}`;
960
+ },
961
+ render() {
962
+ const t = i.withGuide ?? settings.withGuide, a = wrapTextWithPrefix(i.output, i.message, t ? `${symbolBar(this.state)} ` : "", `${symbol(this.state)} `), r = `${t ? `${styleText2("gray", S_BAR)}
963
+ ` : ""}${a}
964
+ `, o = this.value ?? [], g = (n, l) => {
965
+ if (n.disabled)
966
+ return u(n, "disabled");
967
+ const s = o.includes(n.value);
968
+ return l && s ? u(n, "active-selected") : s ? u(n, "selected") : u(n, l ? "active" : "inactive");
969
+ };
970
+ switch (this.state) {
971
+ case "submit": {
972
+ const n = this.options.filter(({ value: s }) => o.includes(s)).map((s) => u(s, "submitted")).join(styleText2("dim", ", ")) || styleText2("dim", "none"), l = wrapTextWithPrefix(i.output, n, t ? `${styleText2("gray", S_BAR)} ` : "");
973
+ return `${r}${l}`;
974
+ }
975
+ case "cancel": {
976
+ const n = this.options.filter(({ value: s }) => o.includes(s)).map((s) => u(s, "cancelled")).join(styleText2("dim", ", "));
977
+ if (n.trim() === "")
978
+ return `${r}${styleText2("gray", S_BAR)}`;
979
+ const l = wrapTextWithPrefix(i.output, n, t ? `${styleText2("gray", S_BAR)} ` : "");
980
+ return `${r}${l}${t ? `
981
+ ${styleText2("gray", S_BAR)}` : ""}`;
982
+ }
983
+ case "error": {
984
+ const n = t ? `${styleText2("yellow", S_BAR)} ` : "", l = this.error.split(`
985
+ `).map(($, v) => v === 0 ? `${t ? `${styleText2("yellow", S_BAR_END)} ` : ""}${styleText2("yellow", $)}` : ` ${$}`).join(`
986
+ `), s = r.split(`
987
+ `).length, h = l.split(`
988
+ `).length + 1;
989
+ return `${r}${n}${limitOptions({
990
+ output: i.output,
991
+ options: this.options,
992
+ cursor: this.cursor,
993
+ maxItems: i.maxItems,
994
+ columnPadding: n.length,
995
+ rowPadding: s + h,
996
+ style: g
997
+ }).join(`
998
+ ${n}`)}
999
+ ${l}
1000
+ `;
1001
+ }
1002
+ default: {
1003
+ const n = t ? `${styleText2("cyan", S_BAR)} ` : "", l = r.split(`
1004
+ `).length, s = x ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, t) : t ? [styleText2("cyan", S_BAR_END)] : [], h = s.join(`
1005
+ `), $ = s.length + 1;
1006
+ return `${r}${n}${limitOptions({
1007
+ output: i.output,
1008
+ options: this.options,
1009
+ cursor: this.cursor,
1010
+ maxItems: i.maxItems,
1011
+ columnPadding: n.length,
1012
+ rowPadding: l + $,
1013
+ style: g
1014
+ }).join(`
1015
+ ${n}`)}
1016
+ ${h}
1017
+ `;
1018
+ }
1019
+ }
1020
+ }
1021
+ }).prompt();
1022
+ };
1023
+ var log = {
1024
+ message: (s = [], {
1025
+ symbol: e = styleText2("gray", S_BAR),
1026
+ secondarySymbol: r = styleText2("gray", S_BAR),
1027
+ output: m = process.stdout,
1028
+ spacing: l = 1,
1029
+ withGuide: c
1030
+ } = {}) => {
1031
+ const t = [], o = c ?? settings.withGuide, f = o ? r : "", O = o ? `${e} ` : "", u = o ? `${r} ` : "";
1032
+ for (let i = 0;i < l; i++)
1033
+ t.push(f);
1034
+ const g = Array.isArray(s) ? s : s.split(`
1035
+ `);
1036
+ if (g.length > 0) {
1037
+ const [i, ...y] = g;
1038
+ i.length > 0 ? t.push(`${O}${i}`) : t.push(o ? e : "");
1039
+ for (const p of y)
1040
+ p.length > 0 ? t.push(`${u}${p}`) : t.push(o ? r : "");
1041
+ }
1042
+ m.write(`${t.join(`
1043
+ `)}
1044
+ `);
1045
+ },
1046
+ info: (s, e) => {
1047
+ log.message(s, { ...e, symbol: styleText2("blue", S_INFO) });
1048
+ },
1049
+ success: (s, e) => {
1050
+ log.message(s, { ...e, symbol: styleText2("green", S_SUCCESS) });
1051
+ },
1052
+ step: (s, e) => {
1053
+ log.message(s, { ...e, symbol: styleText2("green", S_STEP_SUBMIT) });
1054
+ },
1055
+ warn: (s, e) => {
1056
+ log.message(s, { ...e, symbol: styleText2("yellow", S_WARN) });
1057
+ },
1058
+ warning: (s, e) => {
1059
+ log.warn(s, e);
1060
+ },
1061
+ error: (s, e) => {
1062
+ log.message(s, { ...e, symbol: styleText2("red", S_ERROR) });
1063
+ }
1064
+ };
1065
+ var cancel = (o = "", t) => {
1066
+ const i = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
1067
+ i.write(`${e}${styleText2("red", o)}
1068
+
1069
+ `);
1070
+ };
1071
+ var intro = (o = "", t) => {
1072
+ const i = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
1073
+ i.write(`${e}${o}
1074
+ `);
1075
+ };
1076
+ var outro = (o = "", t) => {
1077
+ const i = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
1078
+ ${styleText2("gray", S_BAR_END)} ` : "";
1079
+ i.write(`${e}${o}
1080
+
1081
+ `);
1082
+ };
1083
+ var W$1 = (o) => o;
1084
+ var C = (o, e, s) => {
1085
+ const a = {
1086
+ hard: true,
1087
+ trim: false
1088
+ }, i = wrapAnsi(o, e, a).split(`
1089
+ `), c = i.reduce((n, t) => Math.max(dist_default2(t), n), 0), u = i.map(s).reduce((n, t) => Math.max(dist_default2(t), n), 0), g = e - (u - c);
1090
+ return wrapAnsi(o, g, a);
1091
+ };
1092
+ var note = (o = "", e = "", s) => {
1093
+ const a = s?.output ?? process$1.stdout, i = s?.withGuide ?? settings.withGuide, c = s?.format ?? W$1, g = ["", ...C(o, getColumns(a) - 6, c).split(`
1094
+ `).map(c), ""], n = dist_default2(e), t = Math.max(g.reduce((m, F) => {
1095
+ const O = dist_default2(F);
1096
+ return O > m ? O : m;
1097
+ }, 0), n) + 2, h = g.map((m) => `${styleText2("gray", S_BAR)} ${m}${" ".repeat(t - dist_default2(m))}${styleText2("gray", S_BAR)}`).join(`
1098
+ `), T = i ? `${styleText2("gray", S_BAR)}
1099
+ ` : "", l$1 = i ? S_CONNECT_LEFT : S_CORNER_BOTTOM_LEFT;
1100
+ a.write(`${T}${styleText2("green", S_STEP_SUBMIT)} ${styleText2("reset", e)} ${styleText2("gray", S_BAR_H.repeat(Math.max(t - n - 1, 1)) + S_CORNER_TOP_RIGHT)}
1101
+ ${h}
1102
+ ${styleText2("gray", l$1 + S_BAR_H.repeat(t + 2) + S_CORNER_BOTTOM_RIGHT)}
1103
+ `);
1104
+ };
1105
+ var W = (l) => styleText2("magenta", l);
1106
+ var spinner = ({
1107
+ indicator: l = "dots",
1108
+ onCancel: h,
1109
+ output: n = process.stdout,
1110
+ cancelMessage: G,
1111
+ errorMessage: O,
1112
+ frames: E = unicode ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"],
1113
+ delay: F = unicode ? 80 : 120,
1114
+ signal: m,
1115
+ ...I
1116
+ } = {}) => {
1117
+ const u = isCI();
1118
+ let M, T, d = false, S = false, s = "", p, w = performance.now();
1119
+ const x = getColumns(n), k = I?.styleFrame ?? W, g = (e) => {
1120
+ const r = e > 1 ? O ?? settings.messages.error : G ?? settings.messages.cancel;
1121
+ S = e === 1, d && (a(r, e), S && typeof h == "function" && h());
1122
+ }, f = () => g(2), i = () => g(1), A = () => {
1123
+ process.on("uncaughtExceptionMonitor", f), process.on("unhandledRejection", f), process.on("SIGINT", i), process.on("SIGTERM", i), process.on("exit", g), m && m.addEventListener("abort", i);
1124
+ }, H = () => {
1125
+ process.removeListener("uncaughtExceptionMonitor", f), process.removeListener("unhandledRejection", f), process.removeListener("SIGINT", i), process.removeListener("SIGTERM", i), process.removeListener("exit", g), m && m.removeEventListener("abort", i);
1126
+ }, y = () => {
1127
+ if (p === undefined)
1128
+ return;
1129
+ u && n.write(`
1130
+ `);
1131
+ const r = wrapAnsi(p, x, {
1132
+ hard: true,
1133
+ trim: false
1134
+ }).split(`
1135
+ `);
1136
+ r.length > 1 && n.write(import_sisteransi2.cursor.up(r.length - 1)), n.write(import_sisteransi2.cursor.to(0)), n.write(import_sisteransi2.erase.down());
1137
+ }, C = (e) => e.replace(/\.+$/, ""), _ = (e) => {
1138
+ const r = (performance.now() - e) / 1000, t = Math.floor(r / 60), o = Math.floor(r % 60);
1139
+ return t > 0 ? `[${t}m ${o}s]` : `[${o}s]`;
1140
+ }, N = I.withGuide ?? settings.withGuide, P = (e = "") => {
1141
+ d = true, M = block({ output: n }), s = C(e), w = performance.now(), N && n.write(`${styleText2("gray", S_BAR)}
1142
+ `);
1143
+ let r = 0, t = 0;
1144
+ A(), T = setInterval(() => {
1145
+ if (u && s === p)
1146
+ return;
1147
+ y(), p = s;
1148
+ const o = k(E[r]);
1149
+ let v;
1150
+ if (u)
1151
+ v = `${o} ${s}...`;
1152
+ else if (l === "timer")
1153
+ v = `${o} ${s} ${_(w)}`;
1154
+ else {
1155
+ const B = ".".repeat(Math.floor(t)).slice(0, 3);
1156
+ v = `${o} ${s}${B}`;
1157
+ }
1158
+ const j = wrapAnsi(v, x, {
1159
+ hard: true,
1160
+ trim: false
1161
+ });
1162
+ n.write(j), r = r + 1 < E.length ? r + 1 : 0, t = t < 4 ? t + 0.125 : 0;
1163
+ }, F);
1164
+ }, a = (e = "", r = 0, t = false) => {
1165
+ if (!d)
1166
+ return;
1167
+ d = false, clearInterval(T), y();
1168
+ const o = r === 0 ? styleText2("green", S_STEP_SUBMIT) : r === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
1169
+ s = e ?? s, t || (l === "timer" ? n.write(`${o} ${s} ${_(w)}
1170
+ `) : n.write(`${o} ${s}
1171
+ `)), H(), M();
1172
+ };
1173
+ return {
1174
+ start: P,
1175
+ stop: (e = "") => a(e, 0),
1176
+ message: (e = "") => {
1177
+ s = C(e ?? s);
1178
+ },
1179
+ cancel: (e = "") => a(e, 1),
1180
+ error: (e = "") => a(e, 2),
1181
+ clear: () => a("", 0, true),
1182
+ get isCancelled() {
1183
+ return S;
1184
+ }
1185
+ };
1186
+ };
1187
+ var u2 = {
1188
+ light: unicodeOr("─", "-"),
1189
+ heavy: unicodeOr("━", "="),
1190
+ block: unicodeOr("█", "#")
1191
+ };
1192
+ var SELECT_INSTRUCTIONS = [
1193
+ `${styleText2("dim", "↑/↓")} to navigate`,
1194
+ `${styleText2("dim", "Enter:")} confirm`
1195
+ ];
1196
+ var i = `${styleText2("gray", S_BAR)} `;
1197
+ var text = (t) => new n({
1198
+ validate: t.validate,
1199
+ placeholder: t.placeholder,
1200
+ defaultValue: t.defaultValue,
1201
+ initialValue: t.initialValue,
1202
+ output: t.output,
1203
+ signal: t.signal,
1204
+ input: t.input,
1205
+ render() {
1206
+ const r = t?.withGuide ?? settings.withGuide, l = `${`${r ? `${styleText2("gray", S_BAR)}
1207
+ ` : ""}${symbol(this.state)} `}${t.message}
1208
+ `, d = t.placeholder && t.placeholder.length > 0 ? styleText2("inverse", t.placeholder[0]) + styleText2("dim", t.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o = this.userInput ? this.userInputWithCursor : d, s = this.value ?? "";
1209
+ switch (this.state) {
1210
+ case "validating": {
1211
+ const n = r ? `${styleText2("cyan", S_BAR)} ` : "", i = r ? styleText2("cyan", S_BAR_END) : "", c = styleText2("dim", o), $ = styleText2("dim", "Validating...");
1212
+ return `${l}${n}${c}
1213
+ ${i} ${$}
1214
+ `;
1215
+ }
1216
+ case "error": {
1217
+ const n = this.error ? ` ${styleText2("yellow", this.error)}` : "", i = r ? `${styleText2("yellow", S_BAR)} ` : "", c = r ? styleText2("yellow", S_BAR_END) : "";
1218
+ return `${l.trim()}
1219
+ ${i}${o}
1220
+ ${c}${n}
1221
+ `;
1222
+ }
1223
+ case "submit": {
1224
+ const n = s ? `${r ? " " : ""}${styleText2("dim", s)}` : "", i = r ? styleText2("gray", S_BAR) : "";
1225
+ return `${l}${i}${n}`;
1226
+ }
1227
+ case "cancel": {
1228
+ const n = s ? ` ${styleText2(["strikethrough", "dim"], s)}` : "", i = r ? styleText2("gray", S_BAR) : "";
1229
+ return `${l}${i}${n}${s.trim() ? `
1230
+ ${i}` : ""}`;
1231
+ }
1232
+ default: {
1233
+ const n = r ? `${styleText2("cyan", S_BAR)} ` : "", i = r ? styleText2("cyan", S_BAR_END) : "";
1234
+ return `${l}${n}${o}
1235
+ ${i}
1236
+ `;
1237
+ }
1238
+ }
1239
+ }
1240
+ }).prompt();
1241
+
1242
+ // src/features.ts
1243
+ var FEATURE_NAMES = ["auth", "r2", "ui", "worker"];
1244
+ var WEB_MESSAGES = ["apps/web/messages/en.json", "apps/web/messages/de.json"];
1245
+ var FEATURES = {
1246
+ auth: {
1247
+ description: "Better Auth (email + password, passkeys, Google, verification & reset mails) in API and web",
1248
+ jsonKeys: Object.fromEntries(WEB_MESSAGES.map((file) => [
1249
+ file,
1250
+ [
1251
+ "Auth",
1252
+ "Dashboard",
1253
+ "Header.dashboard",
1254
+ "Header.signIn",
1255
+ "Header.signOut",
1256
+ "Home.cta",
1257
+ "ApiErrors.EMAIL_NOT_VERIFIED",
1258
+ "ApiErrors.INSUFFICIENT_ROLE"
1259
+ ]
1260
+ ])),
1261
+ label: "Auth",
1262
+ packages: {
1263
+ "apps/api/package.json": {
1264
+ dependencies: ["@better-auth/passkey", "@thallesp/nestjs-better-auth", "better-auth", "nodemailer", "resend"],
1265
+ devDependencies: ["@types/nodemailer"],
1266
+ scripts: ["auth:generate"]
1267
+ },
1268
+ "apps/web/package.json": {
1269
+ dependencies: ["@better-auth/passkey", "better-auth", "@hookform/resolvers", "react-hook-form"]
1270
+ }
1271
+ },
1272
+ paths: [
1273
+ "apps/api/scripts/auth.cli.ts",
1274
+ "apps/api/src/auth",
1275
+ "apps/api/src/bootstrap/register-graphql-enums.ts",
1276
+ "apps/api/src/mail",
1277
+ "apps/api/src/user",
1278
+ "apps/api/tests/auth.e2e-spec.ts",
1279
+ "apps/web/src/app/[locale]/(auth)",
1280
+ "apps/web/src/app/[locale]/dashboard",
1281
+ "apps/web/src/components/icons.tsx",
1282
+ "apps/web/src/config/routes.ts",
1283
+ "apps/web/src/features/auth",
1284
+ "apps/web/src/lib/auth-client.ts",
1285
+ "apps/web/src/lib/auth-server.ts",
1286
+ "apps/web/src/lib/auth.ts",
1287
+ "apps/web/tests/auth.spec.ts"
1288
+ ]
1289
+ },
1290
+ r2: {
1291
+ description: "Cloudflare R2 object storage service (uploads, presigned URLs)",
1292
+ label: "Cloudflare R2",
1293
+ packages: {
1294
+ "apps/api/package.json": {
1295
+ dependencies: ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"],
1296
+ devDependencies: ["aws-sdk-client-mock"]
1297
+ }
1298
+ },
1299
+ paths: ["apps/api/src/r2"]
1300
+ },
1301
+ ui: {
1302
+ description: "Extra UI components (dialog, drawer, select, switch, tabs, tooltip, …) with stories",
1303
+ jsonKeys: Object.fromEntries(WEB_MESSAGES.map((file) => [
1304
+ file,
1305
+ [
1306
+ "Common.cancel",
1307
+ "Common.a11y.clearSearch",
1308
+ "Common.a11y.close",
1309
+ "Common.a11y.scrollDown",
1310
+ "Common.a11y.scrollUp"
1311
+ ]
1312
+ ])),
1313
+ label: "UI components",
1314
+ packages: {
1315
+ "apps/web/package.json": {
1316
+ dependencies: [
1317
+ "@radix-ui/react-checkbox",
1318
+ "@radix-ui/react-dialog",
1319
+ "@radix-ui/react-dropdown-menu",
1320
+ "@radix-ui/react-popover",
1321
+ "@radix-ui/react-select",
1322
+ "@radix-ui/react-tabs",
1323
+ "@radix-ui/react-tooltip",
1324
+ "vaul"
1325
+ ]
1326
+ }
1327
+ },
1328
+ paths: [
1329
+ ...[
1330
+ "avatar",
1331
+ "checkbox",
1332
+ "dialog",
1333
+ "dialog-buttons.stories.tsx",
1334
+ "dialog-buttons.tsx",
1335
+ "drawer",
1336
+ "dropdown-menu",
1337
+ "empty-state.stories.tsx",
1338
+ "empty-state.tsx",
1339
+ "field-group.stories.tsx",
1340
+ "field-group.tsx",
1341
+ "field-label.stories.tsx",
1342
+ "field-label.tsx",
1343
+ "input/input-otp.stories.tsx",
1344
+ "input/input-otp.tsx",
1345
+ "popover",
1346
+ "responsive-dialog",
1347
+ "searchbar",
1348
+ "select",
1349
+ "skeleton",
1350
+ "switch",
1351
+ "tabs",
1352
+ "textarea",
1353
+ "tooltip"
1354
+ ].map((component) => `apps/web/src/components/${component}`),
1355
+ "apps/web/src/lib/hooks"
1356
+ ]
1357
+ },
1358
+ worker: {
1359
+ description: "BullMQ worker app + Redis, with shared queue contracts",
1360
+ label: "Worker",
1361
+ packages: {
1362
+ "apps/api/package.json": {
1363
+ dependencies: ["@nexst/queues", "@nestjs/bullmq", "bullmq", "ioredis"]
1364
+ }
1365
+ },
1366
+ paths: ["apps/worker", "packages/queues", "apps/api/src/queue"]
1367
+ }
1368
+ };
1369
+
1370
+ // src/generate.ts
1371
+ import { randomBytes } from "node:crypto";
1372
+ import { existsSync } from "node:fs";
1373
+ import { cp, mkdir, readdir, readFile, rename, rm, writeFile } from "node:fs/promises";
1374
+ import path from "node:path";
1375
+
1376
+ // src/markers.ts
1377
+ var COMMENT_OPEN = String.raw`(?:\/\/|#|--|\{\/\*|<!--)`;
1378
+ var COMMENT_CLOSE = String.raw`(?:\*\/\}|-->)?`;
1379
+ var CONDITION = String.raw`([!\w\s&|]+?)`;
1380
+ var BLOCK_IF = new RegExp(String.raw`^\s*${COMMENT_OPEN}\s*@if\s+${CONDITION}\s*${COMMENT_CLOSE}\s*$`);
1381
+ var BLOCK_END = new RegExp(String.raw`^\s*${COMMENT_OPEN}\s*@endif\s*${COMMENT_CLOSE}\s*$`);
1382
+ var LINE_IF = new RegExp(String.raw`^(.*\S)\s+${COMMENT_OPEN}\s*@if\s+${CONDITION}\s*${COMMENT_CLOSE}\s*$`);
1383
+ var LEADING_COMMENT = /^(\s*)(?:\/\/|#|--) ?/;
1384
+ function evaluate(condition, features) {
1385
+ return condition.split("||").some((any) => any.split("&&").every((term) => {
1386
+ const name = term.trim();
1387
+ const negated = name.startsWith("!");
1388
+ const key = negated ? name.slice(1).trim() : name;
1389
+ if (!(key in features)) {
1390
+ throw new Error(`Unknown feature "${key}" in marker condition "${condition}"`);
1391
+ }
1392
+ return negated ? !features[key] : features[key];
1393
+ }));
1394
+ }
1395
+ function hasMarkers(text) {
1396
+ return text.includes("@if ");
1397
+ }
1398
+ function applyMarkers(text, features, allFeatures, file = "<text>") {
1399
+ const lines = text.split(`
1400
+ `);
1401
+ const out = [];
1402
+ const stack = [];
1403
+ let removedJustNow = false;
1404
+ const keeping = () => stack.every((block) => block.keep);
1405
+ const uncommenting = () => stack.some((block) => block.uncomment);
1406
+ const dropImportContinuation = () => {
1407
+ while (out.length > 0) {
1408
+ const last = out.pop();
1409
+ if (/^\s*(?:import|export)\b/.test(last))
1410
+ return;
1411
+ }
1412
+ };
1413
+ for (const [index, line] of lines.entries()) {
1414
+ const blockIf = BLOCK_IF.exec(line);
1415
+ if (blockIf) {
1416
+ const condition = blockIf[1];
1417
+ stack.push({
1418
+ keep: evaluate(condition, features),
1419
+ uncomment: !evaluate(condition, allFeatures)
1420
+ });
1421
+ continue;
1422
+ }
1423
+ if (BLOCK_END.test(line)) {
1424
+ const block = stack.pop();
1425
+ if (!block)
1426
+ throw new Error(`${file}:${index + 1}: @endif without @if`);
1427
+ if (!block.keep)
1428
+ removedJustNow = true;
1429
+ continue;
1430
+ }
1431
+ if (!keeping())
1432
+ continue;
1433
+ let current = line;
1434
+ const lineIf = LINE_IF.exec(line);
1435
+ if (lineIf) {
1436
+ const [, code, condition] = lineIf;
1437
+ if (!evaluate(condition, features)) {
1438
+ if (/^\s*\}\s*from\s/.test(code))
1439
+ dropImportContinuation();
1440
+ removedJustNow = true;
1441
+ continue;
1442
+ }
1443
+ current = evaluate(condition, allFeatures) ? code : code.replace(LEADING_COMMENT, "$1");
1444
+ } else if (uncommenting()) {
1445
+ current = line.replace(LEADING_COMMENT, "$1");
1446
+ }
1447
+ if (removedJustNow && current.trim() === "" && out.at(-1)?.trim() === "") {
1448
+ removedJustNow = false;
1449
+ continue;
1450
+ }
1451
+ removedJustNow = false;
1452
+ out.push(current);
1453
+ }
1454
+ if (stack.length > 0)
1455
+ throw new Error(`${file}: ${stack.length} unclosed @if block(s)`);
1456
+ return out.join(`
1457
+ `);
1458
+ }
1459
+
1460
+ // src/generate.ts
1461
+ var SKIP = new Set([
1462
+ ".env",
1463
+ ".env.development",
1464
+ ".next",
1465
+ ".turbo",
1466
+ "coverage",
1467
+ "dist",
1468
+ "node_modules",
1469
+ "playwright-report",
1470
+ "storybook-static",
1471
+ "test-results"
1472
+ ]);
1473
+ var BINARY = /\.(?:png|jpe?g|gif|webp|ico|woff2?|ttf|pdf|zip)$/i;
1474
+ var NAME_PATTERN = /^[a-z][a-z0-9-]*[a-z0-9]$/;
1475
+ function toTitle(name) {
1476
+ return name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1477
+ }
1478
+ function replaceTokens(text, options) {
1479
+ const snake = options.name.replaceAll("-", "_");
1480
+ return text.replaceAll("create-nexst-monorepo", "\x00CLI\x00").replaceAll("nexst_", `${snake}_`).replaceAll("Nexst", toTitle(options.name)).replaceAll("nexst", options.name).replaceAll("your-org", options.owner).replaceAll("example.com", options.domain).replaceAll("\x00CLI\x00", "create-nexst-monorepo");
1481
+ }
1482
+ async function generate(options) {
1483
+ if (!NAME_PATTERN.test(options.name)) {
1484
+ throw new Error(`Invalid project name "${options.name}" (lowercase letters, digits, dashes)`);
1485
+ }
1486
+ if (existsSync(options.targetDir) && (await readdir(options.targetDir)).length > 0) {
1487
+ throw new Error(`${options.targetDir} already exists and is not empty`);
1488
+ }
1489
+ await mkdir(options.targetDir, { recursive: true });
1490
+ await cp(options.templateDir, options.targetDir, {
1491
+ filter: (source) => !SKIP.has(path.basename(source)) && !source.endsWith(".tsbuildinfo"),
1492
+ recursive: true
1493
+ });
1494
+ for (const file of await walk(options.targetDir)) {
1495
+ if (path.basename(file) === "_gitignore") {
1496
+ await rename(file, path.join(path.dirname(file), ".gitignore"));
1497
+ }
1498
+ }
1499
+ const disabled = FEATURE_NAMES.filter((feature) => !options.features[feature]);
1500
+ for (const feature of disabled) {
1501
+ await removeFeature(options.targetDir, feature);
1502
+ }
1503
+ const allOn = Object.fromEntries(FEATURE_NAMES.map((feature) => [feature, true]));
1504
+ for (const file of await walk(options.targetDir)) {
1505
+ if (BINARY.test(file) || path.basename(file) === "bun.lock") {
1506
+ if (path.basename(file) === "bun.lock") {
1507
+ await writeFile(file, replaceTokens(await readFile(file, "utf8"), options));
1508
+ }
1509
+ continue;
1510
+ }
1511
+ const original = await readFile(file, "utf8");
1512
+ const resolved = hasMarkers(original) ? applyMarkers(original, options.features, allOn, path.relative(options.targetDir, file)) : original;
1513
+ const replaced = replaceTokens(resolved, options);
1514
+ if (replaced !== original)
1515
+ await writeFile(file, replaced);
1516
+ }
1517
+ await writeEnvFiles(options);
1518
+ }
1519
+ async function removeFeature(root, feature) {
1520
+ const manifest = FEATURES[feature];
1521
+ for (const target of manifest.paths) {
1522
+ await rm(path.join(root, target), { force: true, recursive: true });
1523
+ }
1524
+ for (const [file, edits] of Object.entries(manifest.packages ?? {})) {
1525
+ const full = path.join(root, file);
1526
+ if (!existsSync(full))
1527
+ continue;
1528
+ const pkg = JSON.parse(await readFile(full, "utf8"));
1529
+ for (const [section, names] of Object.entries(edits)) {
1530
+ for (const name of names)
1531
+ delete pkg[section]?.[name];
1532
+ }
1533
+ await writeFile(full, `${JSON.stringify(pkg, null, 2)}
1534
+ `);
1535
+ }
1536
+ for (const [file, keys] of Object.entries(manifest.jsonKeys ?? {})) {
1537
+ const full = path.join(root, file);
1538
+ if (!existsSync(full))
1539
+ continue;
1540
+ const json = JSON.parse(await readFile(full, "utf8"));
1541
+ for (const key of keys)
1542
+ deleteKey(json, key.split("."));
1543
+ await writeFile(full, `${JSON.stringify(json, null, 2)}
1544
+ `);
1545
+ }
1546
+ }
1547
+ function deleteKey(object, [head, ...rest]) {
1548
+ if (rest.length === 0) {
1549
+ delete object[head];
1550
+ return;
1551
+ }
1552
+ const child = object[head];
1553
+ if (child && typeof child === "object")
1554
+ deleteKey(child, rest);
1555
+ }
1556
+ async function writeEnvFiles(options) {
1557
+ const targets = {
1558
+ "apps/api": ".env.development",
1559
+ "apps/web": ".env",
1560
+ "apps/worker": ".env"
1561
+ };
1562
+ for (const [dir, envFile] of Object.entries(targets)) {
1563
+ const example = path.join(options.targetDir, dir, ".env.example");
1564
+ if (!existsSync(example))
1565
+ continue;
1566
+ const content = (await readFile(example, "utf8")).replace(/^BETTER_AUTH_SECRET=.*$/m, `BETTER_AUTH_SECRET=${randomBytes(32).toString("base64")}`);
1567
+ await writeFile(path.join(options.targetDir, dir, envFile), content);
1568
+ }
1569
+ }
1570
+ async function walk(dir) {
1571
+ const entries = await readdir(dir, { withFileTypes: true });
1572
+ const files = await Promise.all(entries.map((entry) => {
1573
+ const full = path.join(dir, entry.name);
1574
+ return entry.isDirectory() ? walk(full) : Promise.resolve([full]);
1575
+ }));
1576
+ return files.flat();
1577
+ }
1578
+
1579
+ // src/index.ts
1580
+ var HELP = `
1581
+ Usage: create-nexst-monorepo [directory] [options]
1582
+
1583
+ Scaffolds a Next.js + NestJS monorepo (bun, turbo, oxlint, vitest, Playwright,
1584
+ Prisma, Docker, kustomize, GitHub Actions).
1585
+
1586
+ Options:
1587
+ --auth / --no-auth Better Auth: email + password, passkeys, Google (API and web)
1588
+ --r2 / --no-r2 Cloudflare R2 storage service
1589
+ --ui / --no-ui Extra UI components (dialog, drawer, select, switch, tabs, …)
1590
+ --worker / --no-worker BullMQ worker app + Redis
1591
+ --owner <name> GitHub owner for ghcr.io images (default: your-org)
1592
+ --domain <domain> Production domain (default: example.com)
1593
+ --no-install Skip bun install, formatting and prisma generate
1594
+ --no-git Skip git init and the initial commit
1595
+ -y, --yes Accept defaults for everything not given as a flag
1596
+ -h, --help Show this help
1597
+ `;
1598
+ function resolveTemplateDir() {
1599
+ const here = path2.dirname(fileURLToPath(import.meta.url));
1600
+ const candidates = [path2.resolve(here, "../template"), path2.resolve(here, "../../template")];
1601
+ const found = candidates.find((dir) => existsSync2(path2.join(dir, "turbo.json")));
1602
+ if (!found)
1603
+ throw new Error("Template directory not found next to the CLI");
1604
+ return found;
1605
+ }
1606
+ function run(command, args, cwd) {
1607
+ const result = spawnSync(command, args, { cwd, stdio: "inherit" });
1608
+ return result.status === 0;
1609
+ }
1610
+ function cancelled() {
1611
+ cancel("Cancelled.");
1612
+ process.exit(1);
1613
+ }
1614
+ async function main() {
1615
+ const { positionals, values } = parseArgs({
1616
+ allowNegative: true,
1617
+ allowPositionals: true,
1618
+ options: {
1619
+ auth: { type: "boolean" },
1620
+ domain: { type: "string" },
1621
+ git: { default: true, type: "boolean" },
1622
+ help: { short: "h", type: "boolean" },
1623
+ install: { default: true, type: "boolean" },
1624
+ owner: { type: "string" },
1625
+ r2: { type: "boolean" },
1626
+ ui: { type: "boolean" },
1627
+ worker: { type: "boolean" },
1628
+ yes: { short: "y", type: "boolean" }
1629
+ }
1630
+ });
1631
+ if (values.help) {
1632
+ console.log(HELP);
1633
+ return;
1634
+ }
1635
+ const interactive = !values.yes && process.stdin.isTTY;
1636
+ intro("create-nexst-monorepo");
1637
+ let directory = positionals[0];
1638
+ if (!directory) {
1639
+ if (!interactive)
1640
+ throw new Error("Pass a project directory, e.g. `create-nexst-monorepo my-app`");
1641
+ const answer = await text({
1642
+ message: "Project name",
1643
+ placeholder: "my-app",
1644
+ validate: (value) => value && NAME_PATTERN.test(value) ? undefined : "Lowercase letters, digits and dashes"
1645
+ });
1646
+ if (isCancel(answer))
1647
+ cancelled();
1648
+ directory = answer;
1649
+ }
1650
+ const targetDir = path2.resolve(directory);
1651
+ const name = path2.basename(targetDir);
1652
+ if (!NAME_PATTERN.test(name)) {
1653
+ throw new Error(`"${name}" is not a valid name (lowercase letters, digits, dashes)`);
1654
+ }
1655
+ const features = {};
1656
+ const unanswered = FEATURE_NAMES.filter((feature) => values[feature] === undefined);
1657
+ for (const feature of FEATURE_NAMES)
1658
+ features[feature] = values[feature] ?? true;
1659
+ if (interactive && unanswered.length > 0) {
1660
+ const picked = await multiselect({
1661
+ initialValues: [...unanswered],
1662
+ message: "Optional features (space to toggle)",
1663
+ options: unanswered.map((feature) => ({
1664
+ hint: FEATURES[feature].description,
1665
+ label: FEATURES[feature].label,
1666
+ value: feature
1667
+ })),
1668
+ required: false
1669
+ });
1670
+ if (isCancel(picked))
1671
+ cancelled();
1672
+ for (const feature of unanswered)
1673
+ features[feature] = picked.includes(feature);
1674
+ }
1675
+ let owner = values.owner;
1676
+ if (!owner && interactive) {
1677
+ const answer = await text({
1678
+ initialValue: "your-org",
1679
+ message: "GitHub owner (images go to ghcr.io/<owner>/)"
1680
+ });
1681
+ if (isCancel(answer))
1682
+ cancelled();
1683
+ owner = answer.toLowerCase();
1684
+ }
1685
+ let domain = values.domain;
1686
+ if (!domain && interactive) {
1687
+ const answer = await text({ initialValue: "example.com", message: "Production domain" });
1688
+ if (isCancel(answer))
1689
+ cancelled();
1690
+ domain = answer;
1691
+ }
1692
+ const spinner2 = spinner();
1693
+ spinner2.start(`Creating ${name}`);
1694
+ await generate({
1695
+ domain: domain ?? "example.com",
1696
+ features,
1697
+ name,
1698
+ owner: owner ?? "your-org",
1699
+ targetDir,
1700
+ templateDir: resolveTemplateDir()
1701
+ });
1702
+ spinner2.stop(`Created ${path2.relative(process.cwd(), targetDir) || "."}`);
1703
+ if (values.install) {
1704
+ log.step("Installing dependencies");
1705
+ const ok = run("bun", ["install"], targetDir) && run("bunx", ["--bun", "prisma", "generate"], path2.join(targetDir, "apps/api")) && run("bun", ["run", "fmt"], targetDir);
1706
+ if (!ok)
1707
+ log.warn("Setup did not finish; run `bun install` and `bun run fmt` yourself.");
1708
+ }
1709
+ if (values.git) {
1710
+ const ok = run("git", ["init", "-q", "-b", "main"], targetDir) && run("git", ["add", "-A"], targetDir) && run("git", ["commit", "-q", "-m", "chore: scaffold with create-nexst-monorepo"], targetDir);
1711
+ if (!ok)
1712
+ log.warn("Git setup skipped (git missing or no identity configured).");
1713
+ }
1714
+ const enabled = FEATURE_NAMES.filter((feature) => features[feature]).map((feature) => FEATURES[feature].label);
1715
+ note([
1716
+ `cd ${path2.relative(process.cwd(), targetDir) || "."}`,
1717
+ ...values.install ? [] : ["bun install"],
1718
+ "(cd apps/api && bunx --bun prisma migrate deploy)",
1719
+ "bun dev"
1720
+ ].join(`
1721
+ `), `Features: ${enabled.length > 0 ? enabled.join(", ") : "none"}`);
1722
+ outro("Done.");
1723
+ }
1724
+ main().catch((error) => {
1725
+ log.error(error instanceof Error ? error.message : String(error));
1726
+ process.exit(1);
1727
+ });