create-better-t-stack 3.37.0 → 3.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as __reExport, t as __exportAll } from "./chunk-BtN16TXe.mjs";
2
+ import { n as __reExport, t as __exportAll } from "./rolldown-runtime-yhw22V8Z.mjs";
3
3
  import { getAllJsonSchemas } from "@better-t-stack/types/json-schema";
4
4
  import { initTRPC } from "@trpc/server";
5
5
  import { Result, Result as Result$1, TaggedError } from "better-result";
@@ -336,7 +336,7 @@ const cliConsola = {
336
336
  /**
337
337
  * User cancelled the operation (e.g., Ctrl+C in prompts)
338
338
  */
339
- var UserCancelledError = class extends TaggedError("UserCancelledError")() {
339
+ var UserCancelledError = class extends TaggedError("UserCancelledError") {
340
340
  constructor(args) {
341
341
  super({ message: args?.message ?? "Operation cancelled" });
342
342
  }
@@ -344,11 +344,11 @@ var UserCancelledError = class extends TaggedError("UserCancelledError")() {
344
344
  /**
345
345
  * General CLI error for validation failures, invalid flags, etc.
346
346
  */
347
- var CLIError = class extends TaggedError("CLIError")() {};
347
+ var CLIError = class extends TaggedError("CLIError") {};
348
348
  /**
349
349
  * Validation error for config/flag validation failures
350
350
  */
351
- var ValidationError = class extends TaggedError("ValidationError")() {
351
+ var ValidationError = class extends TaggedError("ValidationError") {
352
352
  constructor(args) {
353
353
  super(args);
354
354
  }
@@ -356,7 +356,7 @@ var ValidationError = class extends TaggedError("ValidationError")() {
356
356
  /**
357
357
  * Compatibility error for incompatible option combinations
358
358
  */
359
- var CompatibilityError = class extends TaggedError("CompatibilityError")() {
359
+ var CompatibilityError = class extends TaggedError("CompatibilityError") {
360
360
  constructor(args) {
361
361
  super(args);
362
362
  }
@@ -364,7 +364,7 @@ var CompatibilityError = class extends TaggedError("CompatibilityError")() {
364
364
  /**
365
365
  * Directory conflict error when target directory exists and is not empty
366
366
  */
367
- var DirectoryConflictError = class extends TaggedError("DirectoryConflictError")() {
367
+ var DirectoryConflictError = class extends TaggedError("DirectoryConflictError") {
368
368
  constructor(args) {
369
369
  super({
370
370
  directory: args.directory,
@@ -375,7 +375,7 @@ var DirectoryConflictError = class extends TaggedError("DirectoryConflictError")
375
375
  /**
376
376
  * Project creation error for failures during scaffolding
377
377
  */
378
- var ProjectCreationError = class extends TaggedError("ProjectCreationError")() {
378
+ var ProjectCreationError = class extends TaggedError("ProjectCreationError") {
379
379
  constructor(args) {
380
380
  super(args);
381
381
  }
@@ -383,7 +383,7 @@ var ProjectCreationError = class extends TaggedError("ProjectCreationError")() {
383
383
  /**
384
384
  * Database setup error for failures during database configuration
385
385
  */
386
- var DatabaseSetupError = class extends TaggedError("DatabaseSetupError")() {
386
+ var DatabaseSetupError = class extends TaggedError("DatabaseSetupError") {
387
387
  constructor(args) {
388
388
  super(args);
389
389
  }
@@ -391,7 +391,7 @@ var DatabaseSetupError = class extends TaggedError("DatabaseSetupError")() {
391
391
  /**
392
392
  * Addon setup error for failures during addon configuration
393
393
  */
394
- var AddonSetupError = class extends TaggedError("AddonSetupError")() {
394
+ var AddonSetupError = class extends TaggedError("AddonSetupError") {
395
395
  constructor(args) {
396
396
  super(args);
397
397
  }
@@ -441,7 +441,7 @@ function getLatestCLIVersion() {
441
441
  //#region src/utils/project-history.ts
442
442
  const paths = envPaths("better-t-stack", { suffix: "" });
443
443
  const HISTORY_FILE = "history.json";
444
- var HistoryError = class extends TaggedError("HistoryError")() {};
444
+ var HistoryError = class extends TaggedError("HistoryError") {};
445
445
  function getHistoryDir() {
446
446
  return paths.data;
447
447
  }
@@ -1701,15 +1701,37 @@ const evlogWebFrontends = [
1701
1701
  "tanstack-start",
1702
1702
  "astro"
1703
1703
  ];
1704
+ const NODE_DEV_FS_DRAIN_EXPRESSION = "process.env.NODE_ENV === \"production\" ? undefined : createFsDrain()";
1705
+ const SVELTE_DEV_FS_DRAIN_EXPRESSION = "dev ? createFsDrain() : undefined";
1706
+ const ASTRO_DEV_FS_DRAIN_EXPRESSION = "import.meta.env.DEV ? createFsDrain() : undefined";
1704
1707
  function isEvlogBackend(backend) {
1705
1708
  return evlogBackends.includes(backend);
1706
1709
  }
1707
1710
  function getEvlogWebFrontend(frontends) {
1708
1711
  return frontends.find((frontend) => evlogWebFrontends.includes(frontend));
1709
1712
  }
1713
+ function shouldWireEvlogServerFsDrain(config) {
1714
+ return isEvlogBackend(config.backend) && config.runtime !== "workers" && config.serverDeploy !== "cloudflare";
1715
+ }
1716
+ function shouldWireEvlogWebFsDrain(config) {
1717
+ return getEvlogWebFrontend(config.frontend) !== void 0 && config.webDeploy !== "cloudflare";
1718
+ }
1719
+ function supportsEvlogLocalLogs(config) {
1720
+ return shouldWireEvlogServerFsDrain(config) || shouldWireEvlogWebFsDrain(config);
1721
+ }
1710
1722
  function shouldIdentifyWebAuth(config) {
1711
1723
  return config.auth === "better-auth" && config.backend === "self";
1712
1724
  }
1725
+ function getEvlogServerMiddlewareMarker(backend, fsDrain) {
1726
+ const options = fsDrain ? `{ drain: ${NODE_DEV_FS_DRAIN_EXPRESSION} }` : "";
1727
+ if (backend === "hono" || backend === "express") return `app.use(evlog(${options}));`;
1728
+ if (backend === "fastify") return `fastify.register(evlog${options ? `, ${options}` : ""});`;
1729
+ return `.use(evlog(${options}))`;
1730
+ }
1731
+ function findEvlogServerMiddlewareMarker(content, backend) {
1732
+ const fsDrainMarker = getEvlogServerMiddlewareMarker(backend, true);
1733
+ return content.includes(fsDrainMarker) ? fsDrainMarker : getEvlogServerMiddlewareMarker(backend, false);
1734
+ }
1713
1735
  function prependMissingImports(content, imports) {
1714
1736
  const missingImports = imports.filter((line) => !content.includes(line));
1715
1737
  if (missingImports.length === 0) return content;
@@ -1771,46 +1793,72 @@ function addEvlogBetterAuthServerSetup(content, backend, authExpression) {
1771
1793
  const identifySnippet = usesAuthFactory ? "" : `const identifyUser = createAuthMiddleware(${evlogAuthExpression}, ${authOptions});\n\n`;
1772
1794
  const identifyUserSetup = usesAuthFactory ? `\n\tconst identifyUser = createAuthMiddleware(${evlogAuthExpression}, ${authOptions});` : "";
1773
1795
  if (backend === "hono") {
1796
+ const evlogMarker = findEvlogServerMiddlewareMarker(nextContent, backend);
1774
1797
  nextContent = insertBeforeOnce(nextContent, "const app = new Hono", identifySnippet, "createAuthMiddleware(");
1775
- return insertAfterOnce(nextContent, "app.use(evlog());", `\napp.use("*", async (c, next) => {${identifyUserSetup}\n\tawait identifyUser(c.get("log"), c.req.raw.headers, c.req.path);\n\tawait next();\n});`, "identifyUser(c.get(\"log\")");
1798
+ return insertAfterOnce(nextContent, evlogMarker, `\napp.use("*", async (c, next) => {${identifyUserSetup}\n\tawait identifyUser(c.get("log"), c.req.raw.headers, c.req.path);\n\tawait next();\n});`, "identifyUser(c.get(\"log\")");
1776
1799
  }
1777
1800
  if (backend === "express") {
1801
+ const evlogMarker = findEvlogServerMiddlewareMarker(nextContent, backend);
1778
1802
  nextContent = addNamedImport(nextContent, "evlog/express", ["useLogger"]);
1779
1803
  nextContent = insertBeforeOnce(nextContent, "const app = express();", identifySnippet, "createAuthMiddleware(");
1780
- return insertAfterOnce(nextContent, "app.use(evlog());", `\napp.use(async (req, _res, next) => {${identifyUserSetup}\n\tawait identifyUser(useLogger(), req.headers, req.path);\n\tnext();\n});`, "identifyUser(useLogger()");
1804
+ return insertAfterOnce(nextContent, evlogMarker, `\napp.use(async (req, _res, next) => {${identifyUserSetup}\n\tawait identifyUser(useLogger(), req.headers, req.path);\n\tnext();\n});`, "identifyUser(useLogger()");
1781
1805
  }
1782
1806
  if (backend === "fastify") {
1807
+ const evlogMarker = findEvlogServerMiddlewareMarker(nextContent, backend);
1783
1808
  nextContent = addNamedImport(nextContent, "evlog/fastify", ["useLogger"]);
1784
1809
  nextContent = insertBeforeOnce(nextContent, "const fastify = Fastify", identifySnippet, "createAuthMiddleware(");
1785
- return insertAfterOnce(nextContent, "fastify.register(evlog);", `\nfastify.addHook("preHandler", async (request) => {${identifyUserSetup}\n\tawait identifyUser(useLogger(), request.headers, request.url);\n});`, "identifyUser(useLogger()");
1810
+ return insertAfterOnce(nextContent, evlogMarker, `\nfastify.addHook("preHandler", async (request) => {${identifyUserSetup}\n\tawait identifyUser(useLogger(), request.headers, request.url);\n});`, "identifyUser(useLogger()");
1786
1811
  }
1787
1812
  const elysiaMarker = nextContent.includes("const app = new Elysia") ? "const app = new Elysia" : "new Elysia";
1788
1813
  nextContent = insertBeforeOnce(nextContent, elysiaMarker, identifySnippet, "createAuthMiddleware(");
1789
- return insertAfterOnce(nextContent, ".use(evlog())", `\n\t.derive(async ({ request, log }) => {${identifyUserSetup.replace(/\n\t/g, "\n ")}\n\t\tawait identifyUser(log, request.headers, new URL(request.url).pathname);\n\t\treturn {};\n\t})`, "identifyUser(log");
1814
+ const evlogMarker = findEvlogServerMiddlewareMarker(nextContent, backend);
1815
+ return insertAfterOnce(nextContent, evlogMarker, `\n\t.derive(async ({ request, log }) => {${identifyUserSetup.replace(/\n\t/g, "\n ")}\n\t\tawait identifyUser(log, request.headers, new URL(request.url).pathname);\n\t\treturn {};\n\t})`, "identifyUser(log");
1790
1816
  }
1791
- function addEvlogServerSetup(content, backend, serviceName) {
1817
+ function addEvlogServerSetup(content, backend, serviceName, fsDrain) {
1792
1818
  const initSnippet = `initLogger({\n\tenv: { service: "${serviceName}" },\n});\n\n`;
1819
+ const evlogMarker = getEvlogServerMiddlewareMarker(backend, fsDrain);
1820
+ const legacyEvlogMarker = getEvlogServerMiddlewareMarker(backend, false);
1793
1821
  if (backend === "hono") {
1794
- let nextContent = prependMissingImports(content, ["import { initLogger } from \"evlog\";", "import { evlog, type EvlogVariables } from \"evlog/hono\";"]);
1822
+ let nextContent = prependMissingImports(content, [
1823
+ "import { initLogger } from \"evlog\";",
1824
+ "import { evlog, type EvlogVariables } from \"evlog/hono\";",
1825
+ ...fsDrain ? ["import { createFsDrain } from \"evlog/fs\";"] : []
1826
+ ]);
1795
1827
  nextContent = insertBeforeOnce(nextContent, "const app = new Hono", initSnippet, "initLogger({");
1796
1828
  nextContent = nextContent.replace("const app = new Hono();", "const app = new Hono<EvlogVariables>();");
1797
1829
  nextContent = nextContent.replace("import { logger } from \"hono/logger\";\n", "").replace(/\napp\.use\(logger\(\)\);/, "");
1798
- return insertAfterOnce(nextContent, "const app = new Hono<EvlogVariables>();", "\n\napp.use(evlog());", "app.use(evlog());");
1830
+ if (fsDrain) nextContent = nextContent.replace(legacyEvlogMarker, evlogMarker);
1831
+ return insertAfterOnce(nextContent, "const app = new Hono<EvlogVariables>();", `\n\n${evlogMarker}`, evlogMarker);
1799
1832
  }
1800
1833
  if (backend === "express") {
1801
- let nextContent = prependMissingImports(content, ["import { initLogger } from \"evlog\";", "import { evlog } from \"evlog/express\";"]);
1834
+ let nextContent = prependMissingImports(content, [
1835
+ "import { initLogger } from \"evlog\";",
1836
+ "import { evlog } from \"evlog/express\";",
1837
+ ...fsDrain ? ["import { createFsDrain } from \"evlog/fs\";"] : []
1838
+ ]);
1802
1839
  nextContent = insertBeforeOnce(nextContent, "const app = express();", initSnippet, "initLogger({");
1803
- return insertAfterOnce(nextContent, "const app = express();", "\n\napp.use(evlog());", "app.use(evlog());");
1840
+ if (fsDrain) nextContent = nextContent.replace(legacyEvlogMarker, evlogMarker);
1841
+ return insertAfterOnce(nextContent, "const app = express();", `\n\n${evlogMarker}`, evlogMarker);
1804
1842
  }
1805
1843
  if (backend === "fastify") {
1806
- let nextContent = prependMissingImports(content, ["import { initLogger } from \"evlog\";", "import { evlog } from \"evlog/fastify\";"]);
1844
+ let nextContent = prependMissingImports(content, [
1845
+ "import { initLogger } from \"evlog\";",
1846
+ "import { evlog } from \"evlog/fastify\";",
1847
+ ...fsDrain ? ["import { createFsDrain } from \"evlog/fs\";"] : []
1848
+ ]);
1807
1849
  nextContent = insertBeforeOnce(nextContent, "const fastify = Fastify", initSnippet, "initLogger({");
1808
- return insertBeforeOnce(nextContent, "fastify.register(fastifyCors", "fastify.register(evlog);\n", "fastify.register(evlog);");
1850
+ if (fsDrain) nextContent = nextContent.replace(legacyEvlogMarker, evlogMarker);
1851
+ return insertBeforeOnce(nextContent, "fastify.register(fastifyCors", `${evlogMarker}\n`, evlogMarker);
1809
1852
  }
1810
- let nextContent = prependMissingImports(content, ["import { initLogger } from \"evlog\";", "import { evlog } from \"evlog/elysia\";"]);
1853
+ let nextContent = prependMissingImports(content, [
1854
+ "import { initLogger } from \"evlog\";",
1855
+ "import { evlog } from \"evlog/elysia\";",
1856
+ ...fsDrain ? ["import { createFsDrain } from \"evlog/fs\";"] : []
1857
+ ]);
1811
1858
  const elysiaMarker = nextContent.includes("const app = new Elysia") ? "const app = new Elysia" : "new Elysia";
1812
1859
  nextContent = insertBeforeOnce(nextContent, elysiaMarker, initSnippet, "initLogger({");
1813
- for (const marker of ["new Elysia({ adapter: node() })", "new Elysia()"]) nextContent = insertAfterOnce(nextContent, marker, "\n .use(evlog())", ".use(evlog())");
1860
+ if (fsDrain) nextContent = nextContent.replace(legacyEvlogMarker, evlogMarker);
1861
+ for (const marker of ["new Elysia({ adapter: node() })", "new Elysia()"]) nextContent = insertAfterOnce(nextContent, marker, `\n\t${evlogMarker}`, evlogMarker);
1814
1862
  return nextContent;
1815
1863
  }
1816
1864
  function addNuxtEvlogSetup(content, serviceName) {
@@ -1827,14 +1875,20 @@ function addSvelteViteEvlogSetup(content, serviceName) {
1827
1875
  if (nextContent.includes("evlog({")) return nextContent;
1828
1876
  return nextContent.replace("plugins: [tailwindcss(), sveltekit()],", `plugins: [\n tailwindcss(),\n sveltekit(),\n evlog({ service: "${serviceName}" }),\n ],`);
1829
1877
  }
1830
- function addSvelteHooksEvlogSetup(content) {
1831
- let nextContent = prependMissingImports(content, ["import { createEvlogHooks } from \"evlog/sveltekit\";"]);
1878
+ function getSvelteEvlogHooksCall(fsDrain) {
1879
+ return fsDrain ? `createEvlogHooks({ drain: ${SVELTE_DEV_FS_DRAIN_EXPRESSION} })` : "createEvlogHooks()";
1880
+ }
1881
+ function addSvelteHooksEvlogSetup(content, fsDrain) {
1882
+ let nextContent = prependMissingImports(content, ["import { createEvlogHooks } from \"evlog/sveltekit\";", ...fsDrain ? ["import { createFsDrain } from \"evlog/fs\";"] : []]);
1883
+ if (fsDrain) nextContent = addNamedImport(nextContent, "$app/environment", ["dev"]);
1884
+ const hooksCall = getSvelteEvlogHooksCall(fsDrain);
1885
+ if (fsDrain) nextContent = nextContent.replaceAll("createEvlogHooks()", hooksCall);
1832
1886
  if (!nextContent.includes("export const handle") && !nextContent.includes("const authHandle")) {
1833
- if (!nextContent.includes("createEvlogHooks()")) nextContent = `${nextContent.trimEnd()}\n\nexport const { handle, handleError } = createEvlogHooks();\n`;
1887
+ if (!nextContent.includes("createEvlogHooks(")) nextContent = `${nextContent.trimEnd()}\n\nexport const { handle, handleError } = ${hooksCall};\n`;
1834
1888
  return nextContent;
1835
1889
  }
1836
1890
  nextContent = prependMissingImports(nextContent, ["import { sequence } from \"@sveltejs/kit/hooks\";"]);
1837
- if (!nextContent.includes("const { handle: evlogHandle, handleError }")) nextContent = nextContent.replace(/((?:import .+\n)+)/, `$1\nconst { handle: evlogHandle, handleError } = createEvlogHooks();\n\n`);
1891
+ if (!nextContent.includes("const { handle: evlogHandle, handleError }")) nextContent = nextContent.replace(/((?:import .+\n)+)/, `$1\nconst { handle: evlogHandle, handleError } = ${hooksCall};\n\n`);
1838
1892
  nextContent = nextContent.replace(/export const handle(:\s*Handle)?\s*=\s*async/, (_match, typeAnnotation) => `const authHandle${typeAnnotation ?? ""} = async`);
1839
1893
  if (!nextContent.includes("sequence(evlogHandle, authHandle)")) nextContent = `${nextContent.trimEnd()}\n\nexport const handle = sequence(evlogHandle as Handle, authHandle);\nexport { handleError };\n`;
1840
1894
  return nextContent;
@@ -1853,10 +1907,14 @@ function addTanstackStartRootEvlogSetup(content) {
1853
1907
  if (/server:\s*{/.test(nextContent)) return nextContent.replace(/server:\s*{\n/, `server: {\n middleware: [${middlewareEntry}],\n`);
1854
1908
  return nextContent.replace("head: () => ({", `server: {\n middleware: [${middlewareEntry}],\n },\n\n head: () => ({`);
1855
1909
  }
1856
- function addAstroMiddlewareEvlogSetup(content, serviceName) {
1857
- let nextContent = prependMissingImports(content, ["import { createRequestLogger, initLogger } from \"evlog\";"]);
1858
- const initSnippet = `initLogger({\n env: { service: "${serviceName}" },\n});\n\n`;
1910
+ function getInitLoggerSnippet(serviceName, fsDrain, indent) {
1911
+ return `initLogger({\n${indent}env: { service: "${serviceName}" },${fsDrain ? `\n${indent}drain: ${ASTRO_DEV_FS_DRAIN_EXPRESSION},` : ""}\n});\n\n`;
1912
+ }
1913
+ function addAstroMiddlewareEvlogSetup(content, serviceName, fsDrain) {
1914
+ let nextContent = prependMissingImports(content, ["import { createRequestLogger, initLogger } from \"evlog\";", ...fsDrain ? ["import { createFsDrain } from \"evlog/fs\";"] : []]);
1915
+ const initSnippet = getInitLoggerSnippet(serviceName, fsDrain, " ");
1859
1916
  nextContent = insertBeforeOnce(nextContent, "export const onRequest", initSnippet, "initLogger({");
1917
+ if (fsDrain && !nextContent.includes("drain:")) nextContent = nextContent.replace(/initLogger\(\{\n(\s+env: \{ service: "[^"]+" \},)/, `initLogger({\n$1\n drain: ${ASTRO_DEV_FS_DRAIN_EXPRESSION},`);
1860
1918
  if (nextContent.includes("createRequestLogger({")) return nextContent;
1861
1919
  const contextMarker = "export const onRequest = defineMiddleware(async (context, next) => {";
1862
1920
  if (nextContent.includes(contextMarker)) {
@@ -1931,7 +1989,8 @@ function addSvelteBetterAuthEvlogSetup(content, config) {
1931
1989
  const authExpression = getAuthExpression(config);
1932
1990
  const authOptions = "{ exclude: [\"/api/auth/**\"], maskEmail: true }";
1933
1991
  const authHandleSnippet = usesCreateAuthFactory(config) && config.webDeploy === "cloudflare" ? `const evlogAuthHandle: Handle = async ({ event, resolve }) => {\n\tif (building) {\n\t\treturn resolve(event);\n\t}\n\n\tconst authEnv = event.platform?.env ?? localEnv;\n\tconst identifyUser = createAuthMiddleware(createAuth(authEnv) as BetterAuthInstance, ${authOptions});\n\tawait identifyUser(event.locals.log, event.request.headers, event.url.pathname);\n\treturn resolve(event);\n};\n\n` : `const identifyUser = createAuthMiddleware(${authExpression} as BetterAuthInstance, ${authOptions});\n\nconst evlogAuthHandle: Handle = async ({ event, resolve }) => {\n\tawait identifyUser(event.locals.log, event.request.headers, event.url.pathname);\n\treturn resolve(event);\n};\n\n`;
1934
- nextContent = insertAfterOnce(nextContent, "const { handle: evlogHandle, handleError } = createEvlogHooks();\n\n", authHandleSnippet, "evlogAuthHandle");
1992
+ const evlogHandleDeclaration = nextContent.match(/const \{ handle: evlogHandle, handleError \} = createEvlogHooks\([\s\S]*?\);\n\n/)?.[0];
1993
+ if (evlogHandleDeclaration) nextContent = insertAfterOnce(nextContent, evlogHandleDeclaration, authHandleSnippet, "evlogAuthHandle");
1935
1994
  return nextContent.replace("sequence(evlogHandle as Handle, authHandle)", "sequence(evlogHandle as Handle, evlogAuthHandle, authHandle)").replace("sequence(evlogHandle, authHandle)", "sequence(evlogHandle as Handle, evlogAuthHandle, authHandle)");
1936
1995
  }
1937
1996
  function addAstroBetterAuthEvlogSetup(content, config) {
@@ -1950,19 +2009,29 @@ function addAstroBetterAuthEvlogSetup(content, config) {
1950
2009
  }
1951
2010
  return nextContent;
1952
2011
  }
1953
- function getNextEvlogFile(serviceName) {
2012
+ function getNextEvlogFile(serviceName, fsDrain) {
1954
2013
  return `import { createEvlog } from "evlog/next";
1955
2014
  import { createInstrumentation } from "evlog/next/instrumentation/create";
2015
+ ${fsDrain ? "import { createFsDrain } from \"evlog/fs\";\n" : ""}
1956
2016
 
1957
2017
  export const { withEvlog, useLogger, log, createError } = createEvlog({
1958
2018
  service: "${serviceName}",
1959
- });
2019
+ ${fsDrain ? ` drain: ${NODE_DEV_FS_DRAIN_EXPRESSION},\n` : ""}});
1960
2020
 
1961
2021
  export const { register, onRequestError } = createInstrumentation({
1962
2022
  service: "${serviceName}",
1963
2023
  });
1964
2024
  `;
1965
2025
  }
2026
+ function getNitroEvlogDrainFile() {
2027
+ return `import { createFsDrain } from "evlog/fs";
2028
+
2029
+ export default defineNitroPlugin((nitroApp) => {
2030
+ if (!import.meta.dev) return;
2031
+ nitroApp.hooks.hook("evlog:drain", createFsDrain());
2032
+ });
2033
+ `;
2034
+ }
1966
2035
  function getNextInstrumentationFile() {
1967
2036
  return `import { defineNodeInstrumentation } from "evlog/next/instrumentation";
1968
2037
 
@@ -2077,13 +2146,12 @@ export default defineConfig({
2077
2146
  });
2078
2147
  `;
2079
2148
  }
2080
- function getAstroMiddlewareFile(serviceName) {
2149
+ function getAstroMiddlewareFile(serviceName, fsDrain) {
2081
2150
  return `import { defineMiddleware } from "astro:middleware";
2082
2151
  import { createRequestLogger, initLogger } from "evlog";
2152
+ ${fsDrain ? "import { createFsDrain } from \"evlog/fs\";\n" : ""}
2083
2153
 
2084
- initLogger({
2085
- env: { service: "${serviceName}" },
2086
- });
2154
+ ${getInitLoggerSnippet(serviceName, fsDrain, " ").trimEnd()}
2087
2155
 
2088
2156
  export const onRequest = defineMiddleware(async ({ request, locals }, next) => {
2089
2157
  const url = new URL(request.url);
@@ -2120,8 +2188,9 @@ declare namespace App {
2120
2188
  }
2121
2189
  async function setupNextEvlog(config, serviceName) {
2122
2190
  const webDir = path.join(config.projectDir, "apps/web");
2191
+ const fsDrain = shouldWireEvlogWebFsDrain(config);
2123
2192
  const evlogPath = path.join(webDir, "src/lib/evlog.ts");
2124
- if (!await fs.pathExists(evlogPath)) await writeFileIfChanged(evlogPath, getNextEvlogFile(serviceName));
2193
+ if (!await fs.pathExists(evlogPath)) await writeFileIfChanged(evlogPath, getNextEvlogFile(serviceName, fsDrain));
2125
2194
  const identifyWebAuth = shouldIdentifyWebAuth(config);
2126
2195
  if (identifyWebAuth) {
2127
2196
  const evlogAuthPath = path.join(webDir, "src/lib/evlog-auth.ts");
@@ -2147,7 +2216,12 @@ async function setupNextEvlog(config, serviceName) {
2147
2216
  }
2148
2217
  async function setupNuxtEvlog(config, serviceName) {
2149
2218
  const webDir = path.join(config.projectDir, "apps/web");
2219
+ const fsDrain = shouldWireEvlogWebFsDrain(config);
2150
2220
  await updateFileIfExists(path.join(webDir, "nuxt.config.ts"), (content) => addNuxtEvlogSetup(content, serviceName));
2221
+ if (fsDrain) {
2222
+ const drainPath = path.join(webDir, "server/plugins/evlog-drain.ts");
2223
+ if (!await fs.pathExists(drainPath)) await writeFileIfChanged(drainPath, getNitroEvlogDrainFile());
2224
+ }
2151
2225
  if (shouldIdentifyWebAuth(config)) {
2152
2226
  const oldAuthPluginPath = path.join(webDir, "server/plugins/evlog-auth.ts");
2153
2227
  if (await fs.pathExists(oldAuthPluginPath)) {
@@ -2160,12 +2234,15 @@ async function setupNuxtEvlog(config, serviceName) {
2160
2234
  }
2161
2235
  async function setupSvelteEvlog(config, serviceName) {
2162
2236
  const webDir = path.join(config.projectDir, "apps/web");
2237
+ const fsDrain = shouldWireEvlogWebFsDrain(config);
2163
2238
  await updateFileIfExists(path.join(webDir, "vite.config.ts"), (content) => addSvelteViteEvlogSetup(content, serviceName));
2164
2239
  const hooksPath = path.join(webDir, "src/hooks.server.ts");
2165
- if (await fs.pathExists(hooksPath)) await updateFileIfExists(hooksPath, addSvelteHooksEvlogSetup);
2240
+ if (await fs.pathExists(hooksPath)) await updateFileIfExists(hooksPath, (content) => addSvelteHooksEvlogSetup(content, fsDrain));
2166
2241
  else await writeFileIfChanged(hooksPath, `import { createEvlogHooks } from "evlog/sveltekit";
2242
+ ${fsDrain ? "import { createFsDrain } from \"evlog/fs\";\n" : ""}
2243
+ ${fsDrain ? "import { dev } from \"$app/environment\";\n" : ""}
2167
2244
 
2168
- export const { handle, handleError } = createEvlogHooks();
2245
+ export const { handle, handleError } = ${getSvelteEvlogHooksCall(fsDrain)};
2169
2246
  `);
2170
2247
  await updateFileIfExists(path.join(webDir, "src/app.d.ts"), addSvelteLocalsType);
2171
2248
  if (shouldIdentifyWebAuth(config)) await updateFileIfExists(path.join(webDir, "src/hooks.server.ts"), (content) => addSvelteBetterAuthEvlogSetup(content, config));
@@ -2173,9 +2250,14 @@ export const { handle, handleError } = createEvlogHooks();
2173
2250
  }
2174
2251
  async function setupTanstackStartEvlog(config, serviceName) {
2175
2252
  const webDir = path.join(config.projectDir, "apps/web");
2253
+ const fsDrain = shouldWireEvlogWebFsDrain(config);
2176
2254
  const nitroConfigPath = path.join(webDir, "nitro.config.ts");
2177
2255
  if (!await fs.pathExists(nitroConfigPath)) await writeFileIfChanged(nitroConfigPath, getTanstackNitroConfigFile(serviceName));
2178
2256
  await updateFileIfExists(path.join(webDir, "src/routes/__root.tsx"), addTanstackStartRootEvlogSetup);
2257
+ if (fsDrain) {
2258
+ const drainPath = path.join(webDir, "server/plugins/evlog-drain.ts");
2259
+ if (!await fs.pathExists(drainPath)) await writeFileIfChanged(drainPath, getNitroEvlogDrainFile());
2260
+ }
2179
2261
  if (shouldIdentifyWebAuth(config)) {
2180
2262
  const authPluginPath = path.join(webDir, "server/plugins/evlog-auth.ts");
2181
2263
  if (!await fs.pathExists(authPluginPath)) await writeFileIfChanged(authPluginPath, getNitroEvlogAuthPluginFile(config));
@@ -2184,9 +2266,10 @@ async function setupTanstackStartEvlog(config, serviceName) {
2184
2266
  }
2185
2267
  async function setupAstroEvlog(config, serviceName) {
2186
2268
  const webDir = path.join(config.projectDir, "apps/web");
2269
+ const fsDrain = shouldWireEvlogWebFsDrain(config);
2187
2270
  const middlewarePath = path.join(webDir, "src/middleware.ts");
2188
- if (!await fs.pathExists(middlewarePath)) await writeFileIfChanged(middlewarePath, getAstroMiddlewareFile(serviceName));
2189
- else await updateFileIfExists(middlewarePath, (content) => addAstroMiddlewareEvlogSetup(content, serviceName));
2271
+ if (!await fs.pathExists(middlewarePath)) await writeFileIfChanged(middlewarePath, getAstroMiddlewareFile(serviceName, fsDrain));
2272
+ else await updateFileIfExists(middlewarePath, (content) => addAstroMiddlewareEvlogSetup(content, serviceName, fsDrain));
2190
2273
  const envPath = path.join(webDir, "src/env.d.ts");
2191
2274
  if (!await fs.pathExists(envPath)) await writeFileIfChanged(envPath, getAstroEnvFile());
2192
2275
  else await updateFileIfExists(envPath, addAstroLocalsType);
@@ -2209,7 +2292,7 @@ async function setupEvlog(config) {
2209
2292
  const serverIndexPath = path.join(config.projectDir, "apps/server/src/index.ts");
2210
2293
  if (await fs.pathExists(serverIndexPath)) {
2211
2294
  const content = await fs.readFile(serverIndexPath, "utf-8");
2212
- let nextContent = addEvlogServerSetup(content, config.backend, `${config.projectName}-server`);
2295
+ let nextContent = addEvlogServerSetup(content, config.backend, `${config.projectName}-server`, shouldWireEvlogServerFsDrain(config));
2213
2296
  if (config.auth === "better-auth") nextContent = addEvlogBetterAuthServerSetup(nextContent, config.backend, getAuthExpression(config));
2214
2297
  if (config.examples.includes("ai")) nextContent = addBackendAiEvlogSetup(nextContent, config.backend);
2215
2298
  if (nextContent !== content) await fs.writeFile(serverIndexPath, nextContent);
@@ -2431,6 +2514,10 @@ const TEMPLATES$2 = {
2431
2514
  label: "Tanstack Start SPA: Fumadocs MDX (not RSC)",
2432
2515
  hint: "SPA mode allows you to host the site statically, compatible with a CDN.",
2433
2516
  value: "tanstack-start-spa"
2517
+ },
2518
+ astro: {
2519
+ label: "Astro: Fumadocs MDX",
2520
+ value: "astro"
2434
2521
  }
2435
2522
  };
2436
2523
  const DEFAULT_TEMPLATE$2 = "next-mdx";
@@ -2444,7 +2531,7 @@ function getFumadocsLinter(addons) {
2444
2531
  if (addons.includes("vite-plus")) return "oxlint";
2445
2532
  }
2446
2533
  function getFumadocsAddonContext(currentAddons, persistedAddons) {
2447
- return Array.from(new Set([...persistedAddons ?? [], ...currentAddons]));
2534
+ return Array.from(/* @__PURE__ */ new Set([...persistedAddons ?? [], ...currentAddons]));
2448
2535
  }
2449
2536
  async function setupFumadocs(config) {
2450
2537
  if (shouldSkipExternalCommands()) return Result.ok(void 0);
@@ -2646,6 +2733,11 @@ const MCP_AGENTS = [
2646
2733
  label: "GitHub Copilot CLI",
2647
2734
  scope: "both"
2648
2735
  },
2736
+ {
2737
+ value: "grok-build",
2738
+ label: "Grok Build",
2739
+ scope: "both"
2740
+ },
2649
2741
  {
2650
2742
  value: "mcporter",
2651
2743
  label: "MCPorter",
@@ -2656,6 +2748,11 @@ const MCP_AGENTS = [
2656
2748
  label: "VS Code (GitHub Copilot)",
2657
2749
  scope: "both"
2658
2750
  },
2751
+ {
2752
+ value: "windsurf",
2753
+ label: "Windsurf",
2754
+ scope: "global"
2755
+ },
2659
2756
  {
2660
2757
  value: "zed",
2661
2758
  label: "Zed",
@@ -3029,10 +3126,42 @@ const SKILL_SOURCES = {
3029
3126
  "haydenbleasel/ultracite": { label: "Ultracite" },
3030
3127
  "https://www.evlog.dev": { label: "evlog" }
3031
3128
  };
3032
- const AVAILABLE_AGENTS = [
3129
+ const SKILLS_CLI_AGENT_OPTIONS = [
3033
3130
  {
3034
- value: "cursor",
3035
- label: "Cursor"
3131
+ value: "adal",
3132
+ label: "AdaL"
3133
+ },
3134
+ {
3135
+ value: "aider-desk",
3136
+ label: "AiderDesk"
3137
+ },
3138
+ {
3139
+ value: "amp",
3140
+ label: "Amp"
3141
+ },
3142
+ {
3143
+ value: "antigravity",
3144
+ label: "Antigravity"
3145
+ },
3146
+ {
3147
+ value: "antigravity-cli",
3148
+ label: "Antigravity CLI"
3149
+ },
3150
+ {
3151
+ value: "astrbot",
3152
+ label: "AstrBot"
3153
+ },
3154
+ {
3155
+ value: "augment",
3156
+ label: "Augment"
3157
+ },
3158
+ {
3159
+ value: "autohand-code",
3160
+ label: "Autohand Code CLI"
3161
+ },
3162
+ {
3163
+ value: "bob",
3164
+ label: "IBM Bob"
3036
3165
  },
3037
3166
  {
3038
3167
  value: "claude-code",
@@ -3043,100 +3172,306 @@ const AVAILABLE_AGENTS = [
3043
3172
  label: "Cline"
3044
3173
  },
3045
3174
  {
3046
- value: "github-copilot",
3047
- label: "GitHub Copilot"
3175
+ value: "codearts-agent",
3176
+ label: "CodeArts Agent"
3177
+ },
3178
+ {
3179
+ value: "codebuddy",
3180
+ label: "CodeBuddy"
3181
+ },
3182
+ {
3183
+ value: "codemaker",
3184
+ label: "Codemaker"
3185
+ },
3186
+ {
3187
+ value: "codestudio",
3188
+ label: "Code Studio"
3048
3189
  },
3049
3190
  {
3050
3191
  value: "codex",
3051
3192
  label: "Codex"
3052
3193
  },
3053
3194
  {
3054
- value: "opencode",
3055
- label: "OpenCode"
3195
+ value: "command-code",
3196
+ label: "Command Code"
3056
3197
  },
3057
3198
  {
3058
- value: "windsurf",
3059
- label: "Windsurf"
3199
+ value: "continue",
3200
+ label: "Continue"
3201
+ },
3202
+ {
3203
+ value: "cortex",
3204
+ label: "Cortex Code"
3205
+ },
3206
+ {
3207
+ value: "crush",
3208
+ label: "Crush"
3209
+ },
3210
+ {
3211
+ value: "cursor",
3212
+ label: "Cursor"
3213
+ },
3214
+ {
3215
+ value: "deepagents",
3216
+ label: "Deep Agents"
3217
+ },
3218
+ {
3219
+ value: "devin",
3220
+ label: "Devin for Terminal"
3221
+ },
3222
+ {
3223
+ value: "dexto",
3224
+ label: "Dexto"
3225
+ },
3226
+ {
3227
+ value: "droid",
3228
+ label: "Droid"
3229
+ },
3230
+ {
3231
+ value: "eve",
3232
+ label: "Eve"
3233
+ },
3234
+ {
3235
+ value: "firebender",
3236
+ label: "Firebender"
3237
+ },
3238
+ {
3239
+ value: "forgecode",
3240
+ label: "ForgeCode"
3241
+ },
3242
+ {
3243
+ value: "gemini-cli",
3244
+ label: "Gemini CLI"
3245
+ },
3246
+ {
3247
+ value: "github-copilot",
3248
+ label: "GitHub Copilot"
3060
3249
  },
3061
3250
  {
3062
3251
  value: "goose",
3063
3252
  label: "Goose"
3064
3253
  },
3065
3254
  {
3066
- value: "roo",
3067
- label: "Roo Code"
3255
+ value: "grok",
3256
+ label: "Grok Build"
3257
+ },
3258
+ {
3259
+ value: "hermes-agent",
3260
+ label: "Hermes Agent"
3261
+ },
3262
+ {
3263
+ value: "iflow-cli",
3264
+ label: "iFlow CLI"
3265
+ },
3266
+ {
3267
+ value: "inference-sh",
3268
+ label: "inference.sh"
3269
+ },
3270
+ {
3271
+ value: "jazz",
3272
+ label: "Jazz"
3273
+ },
3274
+ {
3275
+ value: "junie",
3276
+ label: "Junie"
3068
3277
  },
3069
3278
  {
3070
3279
  value: "kilo",
3071
3280
  label: "Kilo Code"
3072
3281
  },
3073
3282
  {
3074
- value: "gemini-cli",
3075
- label: "Gemini CLI"
3283
+ value: "kimchi",
3284
+ label: "Kimchi"
3076
3285
  },
3077
3286
  {
3078
- value: "antigravity",
3079
- label: "Antigravity"
3287
+ value: "kimi-code-cli",
3288
+ label: "Kimi Code CLI"
3080
3289
  },
3081
3290
  {
3082
- value: "openhands",
3083
- label: "OpenHands"
3291
+ value: "kiro-cli",
3292
+ label: "Kiro CLI"
3084
3293
  },
3085
3294
  {
3086
- value: "trae",
3087
- label: "Trae"
3295
+ value: "kode",
3296
+ label: "Kode"
3088
3297
  },
3089
3298
  {
3090
- value: "amp",
3091
- label: "Amp"
3299
+ value: "lingma",
3300
+ label: "Lingma"
3301
+ },
3302
+ {
3303
+ value: "loaf",
3304
+ label: "Loaf"
3305
+ },
3306
+ {
3307
+ value: "mcpjam",
3308
+ label: "MCPJam"
3309
+ },
3310
+ {
3311
+ value: "mistral-vibe",
3312
+ label: "Mistral Vibe"
3313
+ },
3314
+ {
3315
+ value: "moxby",
3316
+ label: "Moxby"
3317
+ },
3318
+ {
3319
+ value: "mux",
3320
+ label: "Mux"
3321
+ },
3322
+ {
3323
+ value: "neovate",
3324
+ label: "Neovate"
3325
+ },
3326
+ {
3327
+ value: "ona",
3328
+ label: "Ona"
3329
+ },
3330
+ {
3331
+ value: "openclaw",
3332
+ label: "OpenClaw"
3333
+ },
3334
+ {
3335
+ value: "opencode",
3336
+ label: "OpenCode"
3337
+ },
3338
+ {
3339
+ value: "openhands",
3340
+ label: "OpenHands"
3092
3341
  },
3093
3342
  {
3094
3343
  value: "pi",
3095
3344
  label: "Pi"
3096
3345
  },
3346
+ {
3347
+ value: "pochi",
3348
+ label: "Pochi"
3349
+ },
3350
+ {
3351
+ value: "promptscript",
3352
+ label: "PromptScript"
3353
+ },
3097
3354
  {
3098
3355
  value: "qoder",
3099
3356
  label: "Qoder"
3100
3357
  },
3358
+ {
3359
+ value: "qoder-cn",
3360
+ label: "Qoder CN"
3361
+ },
3101
3362
  {
3102
3363
  value: "qwen-code",
3103
3364
  label: "Qwen Code"
3104
3365
  },
3105
3366
  {
3106
- value: "kiro-cli",
3107
- label: "Kiro CLI"
3367
+ value: "reasonix",
3368
+ label: "Reasonix"
3108
3369
  },
3109
3370
  {
3110
- value: "droid",
3111
- label: "Droid"
3371
+ value: "replit",
3372
+ label: "Replit"
3112
3373
  },
3113
3374
  {
3114
- value: "command-code",
3115
- label: "Command Code"
3375
+ value: "roo",
3376
+ label: "Roo Code"
3116
3377
  },
3117
3378
  {
3118
- value: "clawdbot",
3119
- label: "Clawdbot"
3379
+ value: "rovodev",
3380
+ label: "Rovo Dev"
3120
3381
  },
3121
3382
  {
3122
- value: "zencoder",
3123
- label: "Zencoder"
3383
+ value: "tabnine-cli",
3384
+ label: "Tabnine CLI"
3124
3385
  },
3125
3386
  {
3126
- value: "neovate",
3127
- label: "Neovate"
3387
+ value: "terramind",
3388
+ label: "Terramind"
3128
3389
  },
3129
3390
  {
3130
- value: "mcpjam",
3131
- label: "MCPJam"
3391
+ value: "tinycloud",
3392
+ label: "Tinycloud"
3393
+ },
3394
+ {
3395
+ value: "trae",
3396
+ label: "Trae"
3397
+ },
3398
+ {
3399
+ value: "trae-cn",
3400
+ label: "Trae CN"
3401
+ },
3402
+ {
3403
+ value: "universal",
3404
+ label: "Universal"
3405
+ },
3406
+ {
3407
+ value: "warp",
3408
+ label: "Warp"
3409
+ },
3410
+ {
3411
+ value: "windsurf",
3412
+ label: "Windsurf"
3413
+ },
3414
+ {
3415
+ value: "zcode",
3416
+ label: "ZCode"
3417
+ },
3418
+ {
3419
+ value: "zed",
3420
+ label: "Zed"
3421
+ },
3422
+ {
3423
+ value: "zencoder",
3424
+ label: "Zencoder"
3425
+ },
3426
+ {
3427
+ value: "zenflow",
3428
+ label: "Zenflow"
3132
3429
  }
3133
3430
  ];
3134
- const DEFAULT_SCOPE = "project";
3135
- const DEFAULT_AGENTS$1 = [
3431
+ const UNIVERSAL_SKILLS_AGENTS = [
3432
+ "amp",
3433
+ "antigravity",
3434
+ "antigravity-cli",
3435
+ "cline",
3436
+ "codex",
3136
3437
  "cursor",
3137
- "claude-code",
3138
- "github-copilot"
3438
+ "deepagents",
3439
+ "dexto",
3440
+ "firebender",
3441
+ "gemini-cli",
3442
+ "github-copilot",
3443
+ "kimi-code-cli",
3444
+ "loaf",
3445
+ "opencode",
3446
+ "promptscript",
3447
+ "warp",
3448
+ "zed"
3449
+ ];
3450
+ const PROMPT_HIDDEN_AGENTS = /* @__PURE__ */ new Set([
3451
+ ...UNIVERSAL_SKILLS_AGENTS,
3452
+ "universal",
3453
+ "eve",
3454
+ "replit"
3455
+ ]);
3456
+ const SKILLS_AGENT_PROMPT_OPTIONS = [
3457
+ {
3458
+ value: "universal",
3459
+ label: "Universal (.agents/skills)",
3460
+ hint: "17 agents including Amp, Antigravity, Cline, Codex, Cursor, Gemini CLI, Copilot, OpenCode, Warp, and Zed"
3461
+ },
3462
+ ...SKILLS_CLI_AGENT_OPTIONS.filter(({ value }) => value === "claude-code"),
3463
+ ...SKILLS_CLI_AGENT_OPTIONS.filter(({ value }) => value !== "claude-code" && !PROMPT_HIDDEN_AGENTS.has(value))
3139
3464
  ];
3465
+ function expandSkillsAgentTargets(agents) {
3466
+ const expanded = agents.flatMap((agent) => {
3467
+ if (agent === "universal") return [...UNIVERSAL_SKILLS_AGENTS];
3468
+ if (agent === "clawdbot") return ["openclaw"];
3469
+ return [agent];
3470
+ });
3471
+ return Array.from(new Set(expanded));
3472
+ }
3473
+ const DEFAULT_SCOPE = "project";
3474
+ const DEFAULT_AGENTS$1 = ["universal", "claude-code"];
3140
3475
  function hasReactBasedFrontend(frontend) {
3141
3476
  return frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("tanstack-start") || frontend.includes("next");
3142
3477
  }
@@ -3238,7 +3573,11 @@ const CURATED_SKILLS_BY_SOURCE = {
3238
3573
  ],
3239
3574
  "msmps/opentui-skill": () => ["opentui"],
3240
3575
  "haydenbleasel/ultracite": () => ["ultracite"],
3241
- "https://www.evlog.dev": () => ["review-logging-patterns", "analyze-logs"]
3576
+ "https://www.evlog.dev": (config) => [
3577
+ "review-logging-patterns",
3578
+ "build-audit-logs",
3579
+ ...supportsEvlogLocalLogs(config) ? ["analyze-logs"] : []
3580
+ ]
3242
3581
  };
3243
3582
  function getCuratedSkillNamesForSourceKey(sourceKey, config) {
3244
3583
  return CURATED_SKILLS_BY_SOURCE[sourceKey](config);
@@ -3315,9 +3654,10 @@ async function setupSkills(config) {
3315
3654
  if (configuredAgents !== void 0) return [...configuredAgents];
3316
3655
  return navigableMultiselect({
3317
3656
  message: "Select agents to install skills to",
3318
- options: AVAILABLE_AGENTS,
3657
+ options: SKILLS_AGENT_PROMPT_OPTIONS,
3319
3658
  required: false,
3320
- initialValues: [...DEFAULT_AGENTS$1]
3659
+ initialValues: [...DEFAULT_AGENTS$1],
3660
+ maxItems: 10
3321
3661
  });
3322
3662
  }
3323
3663
  });
@@ -3337,6 +3677,7 @@ async function setupSkills(config) {
3337
3677
  installSpinner.start("Installing skills...");
3338
3678
  const runner = getPackageRunnerPrefix(packageManager);
3339
3679
  const globalFlags = scope === "global" ? ["-g"] : [];
3680
+ const agentTargets = expandSkillsAgentTargets(selectedAgents);
3340
3681
  for (const [source, skills] of Object.entries(skillsBySource)) if ((await Result.tryPromise({
3341
3682
  try: async () => {
3342
3683
  const args = [
@@ -3348,7 +3689,7 @@ async function setupSkills(config) {
3348
3689
  "--skill",
3349
3690
  ...skills,
3350
3691
  "--agent",
3351
- ...selectedAgents,
3692
+ ...agentTargets,
3352
3693
  "-y"
3353
3694
  ];
3354
3695
  await $({
@@ -3660,7 +4001,7 @@ const HOOKS = {
3660
4001
  claude: { label: "Claude Code" },
3661
4002
  copilot: { label: "GitHub Copilot" }
3662
4003
  };
3663
- const ULTRACITE_VERSION = "7.9.3";
4004
+ const ULTRACITE_VERSION = "7.9.4";
3664
4005
  const DEFAULT_LINTER = "biome";
3665
4006
  const DEFAULT_EDITORS = ["vscode"];
3666
4007
  const DEFAULT_AGENTS = ["universal"];
@@ -5387,9 +5728,7 @@ async function getProjectName(initialName) {
5387
5728
  */
5388
5729
  function isTelemetryEnabled() {
5389
5730
  const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
5390
- const BTS_TELEMETRY = "1";
5391
5731
  if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
5392
- if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
5393
5732
  return true;
5394
5733
  }
5395
5734
  //#endregion
@@ -5509,16 +5848,15 @@ async function handleDirectoryConflict(currentPathInput) {
5509
5848
  }
5510
5849
  }
5511
5850
  }
5851
+ function resolveProjectDirectoryPath(finalPathInput) {
5852
+ const finalResolvedPath = finalPathInput === "." ? process.cwd() : path.resolve(process.cwd(), finalPathInput);
5853
+ return {
5854
+ finalResolvedPath,
5855
+ finalBaseName: path.basename(finalResolvedPath)
5856
+ };
5857
+ }
5512
5858
  async function setupProjectDirectory(finalPathInput, shouldClearDirectory) {
5513
- let finalResolvedPath;
5514
- let finalBaseName;
5515
- if (finalPathInput === ".") {
5516
- finalResolvedPath = process.cwd();
5517
- finalBaseName = path.basename(finalResolvedPath);
5518
- } else {
5519
- finalResolvedPath = path.resolve(process.cwd(), finalPathInput);
5520
- finalBaseName = path.basename(finalResolvedPath);
5521
- }
5859
+ const { finalResolvedPath, finalBaseName } = resolveProjectDirectoryPath(finalPathInput);
5522
5860
  const pathSafetyResult = await validateSafeProjectDirectoryPath(finalPathInput);
5523
5861
  if (pathSafetyResult.isErr()) throw pathSafetyResult.error;
5524
5862
  if (shouldClearDirectory) {
@@ -5767,7 +6105,7 @@ function validateArrayOptions(options) {
5767
6105
  }
5768
6106
  //#endregion
5769
6107
  //#region src/validation.ts
5770
- const CORE_STACK_FLAGS = new Set([
6108
+ const coreStackFlags = /* @__PURE__ */ new Set([
5771
6109
  "database",
5772
6110
  "orm",
5773
6111
  "backend",
@@ -5785,7 +6123,7 @@ const CORE_STACK_FLAGS = new Set([
5785
6123
  function validateYesFlagCombination(options, providedFlags) {
5786
6124
  if (!options.yes) return Result.ok(void 0);
5787
6125
  if (options.template && options.template !== "none") return Result.ok(void 0);
5788
- const coreStackFlagsProvided = Array.from(providedFlags).filter((flag) => CORE_STACK_FLAGS.has(flag));
6126
+ const coreStackFlagsProvided = Array.from(providedFlags).filter((flag) => coreStackFlags.has(flag));
5789
6127
  if (coreStackFlagsProvided.length > 0) return Result.err(new ValidationError({ message: `Cannot combine --yes with core stack configuration flags: ${coreStackFlagsProvided.map((f) => `--${f}`).join(", ")}. The --yes flag uses default configuration. Remove these flags or use --yes without them.` }));
5790
6128
  return Result.ok(void 0);
5791
6129
  }
@@ -5824,6 +6162,9 @@ function validateConfigCompatibility(config, providedFlags, options) {
5824
6162
  if (options && providedFlags) return validateFullConfig(config, providedFlags, options);
5825
6163
  else return validateConfigForProgrammaticUse(config);
5826
6164
  }
6165
+ function validateResolvedConfigCompatibility(config) {
6166
+ return validateFullConfig(config, coreStackFlags, config);
6167
+ }
5827
6168
  //#endregion
5828
6169
  //#region src/utils/file-formatter.ts
5829
6170
  const formatOptions = {
@@ -6017,7 +6358,7 @@ async function initMongoDBAtlas(serverDir) {
6017
6358
  await $({
6018
6359
  cwd: serverDir,
6019
6360
  stdio: "inherit"
6020
- })`atlas deployments setup`;
6361
+ })`atlas setup`;
6021
6362
  cliLog.success("MongoDB Atlas deployment ready");
6022
6363
  },
6023
6364
  catch: (e) => new DatabaseSetupError({
@@ -6066,7 +6407,7 @@ ${pc.green("MongoDB Atlas Manual Setup Instructions:")}
6066
6407
  ${pc.blue("https://www.mongodb.com/docs/atlas/cli/stable/install-atlas-cli/")}
6067
6408
 
6068
6409
  2. Run the following command and follow the prompts:
6069
- ${pc.blue("atlas deployments setup")}
6410
+ ${pc.blue("atlas setup")}
6070
6411
 
6071
6412
  3. Get your connection string from the Atlas dashboard:
6072
6413
  Format: ${pc.dim("mongodb+srv://USERNAME:PASSWORD@CLUSTER.mongodb.net/DATABASE_NAME")}
@@ -6167,10 +6508,6 @@ const NEON_REGIONS = [
6167
6508
  label: "AWS Asia Pacific (Singapore)",
6168
6509
  value: "aws-ap-southeast-1"
6169
6510
  },
6170
- {
6171
- label: "AWS South America East 1 (São Paulo)",
6172
- value: "aws-sa-east-1"
6173
- },
6174
6511
  {
6175
6512
  label: "AWS Asia Pacific (Sydney)",
6176
6513
  value: "aws-ap-southeast-2"
@@ -6180,13 +6517,12 @@ const NEON_REGIONS = [
6180
6517
  value: "azure-eastus2"
6181
6518
  }
6182
6519
  ];
6183
- async function executeNeonCommand(packageManager, commandArgsString, spinnerText) {
6520
+ async function executeNeonCommand(commandArgs, spinnerText) {
6184
6521
  const s = createSpinner();
6185
- const args = getPackageExecutionArgs(packageManager, commandArgsString);
6186
6522
  if (spinnerText) s.start(spinnerText);
6187
6523
  return Result.tryPromise({
6188
6524
  try: async () => {
6189
- const result = await $`${args}`;
6525
+ const result = await $`${commandArgs}`;
6190
6526
  if (spinnerText) s.stop(pc.green(spinnerText.replace("...", "").replace("ing ", "ed ").trim()));
6191
6527
  return result;
6192
6528
  },
@@ -6200,8 +6536,22 @@ async function executeNeonCommand(packageManager, commandArgsString, spinnerText
6200
6536
  }
6201
6537
  });
6202
6538
  }
6539
+ function getNeonProjectCreateArgs(packageManager, projectName, regionId) {
6540
+ return [
6541
+ ...getPackageRunnerPrefix(packageManager),
6542
+ "neon@latest",
6543
+ "projects",
6544
+ "create",
6545
+ "--name",
6546
+ projectName,
6547
+ "--region-id",
6548
+ regionId,
6549
+ "--output",
6550
+ "json"
6551
+ ];
6552
+ }
6203
6553
  async function createNeonProject(projectName, regionId, packageManager) {
6204
- const execResult = await executeNeonCommand(packageManager, `neonctl@latest projects create --name ${projectName} --region-id ${regionId} --output json`, `Creating Neon project "${projectName}"...`);
6554
+ const execResult = await executeNeonCommand(getNeonProjectCreateArgs(packageManager, projectName, regionId), `Creating Neon project "${projectName}"...`);
6205
6555
  if (execResult.isErr()) return Result.err(execResult.error);
6206
6556
  const parseResult = Result.try({
6207
6557
  try: () => JSON.parse(execResult.value.stdout),
@@ -6245,7 +6595,7 @@ async function writeEnvFile$2(projectDir, backend, config) {
6245
6595
  }
6246
6596
  async function setupWithNeonDb(projectDir, packageManager, backend) {
6247
6597
  const s = createSpinner();
6248
- s.start("Creating Neon database using get-db...");
6598
+ s.start("Creating Neon database using neon-new...");
6249
6599
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
6250
6600
  const targetDir = path.join(projectDir, targetApp);
6251
6601
  const ensureDirResult = await Result.tryPromise({
@@ -6260,17 +6610,17 @@ async function setupWithNeonDb(projectDir, packageManager, backend) {
6260
6610
  s.stop(pc.red("Failed to create directory"));
6261
6611
  return ensureDirResult;
6262
6612
  }
6263
- const packageArgs = getPackageExecutionArgs(packageManager, `get-db@latest --yes --ref "sbA3tIe"`);
6613
+ const packageArgs = getPackageExecutionArgs(packageManager, `neon-new@latest --yes --ref "sbA3tIe"`);
6264
6614
  return Result.tryPromise({
6265
6615
  try: async () => {
6266
6616
  await $({ cwd: targetDir })`${packageArgs}`;
6267
6617
  s.stop(pc.green("Neon database created successfully!"));
6268
6618
  },
6269
6619
  catch: (e) => {
6270
- s.stop(pc.red("Failed to create database with get-db"));
6620
+ s.stop(pc.red("Failed to create database with neon-new"));
6271
6621
  return new DatabaseSetupError({
6272
6622
  provider: "neon",
6273
- message: `Failed to create database with get-db: ${e instanceof Error ? e.message : String(e)}`,
6623
+ message: `Failed to create database with neon-new: ${e instanceof Error ? e.message : String(e)}`,
6274
6624
  cause: e
6275
6625
  });
6276
6626
  }
@@ -6331,25 +6681,25 @@ async function setupNeonPostgres(config, cliInput) {
6331
6681
  return Result.ok(void 0);
6332
6682
  }
6333
6683
  let setupMethod = cliInput?.dbSetupOptions?.neon?.method ?? config.dbSetupOptions?.neon?.method;
6334
- if (!setupMethod) if (isSilent()) setupMethod = "neondb";
6684
+ if (!setupMethod) if (isSilent()) setupMethod = "neon-new";
6335
6685
  else {
6336
6686
  const promptedSetupMethod = await select({
6337
6687
  message: "Choose your Neon setup method:",
6338
6688
  options: [{
6339
- label: "Quick setup with get-db",
6340
- value: "neondb",
6689
+ label: "Quick setup with neon-new",
6690
+ value: "neon-new",
6341
6691
  hint: "fastest, no auth required"
6342
6692
  }, {
6343
- label: "Custom setup with neonctl",
6344
- value: "neonctl",
6693
+ label: "Custom setup with Neon CLI",
6694
+ value: "neon",
6345
6695
  hint: "More control - choose project name and region"
6346
6696
  }],
6347
- initialValue: "neondb"
6697
+ initialValue: "neon-new"
6348
6698
  });
6349
6699
  if (isCancel(promptedSetupMethod)) return userCancelled("Operation cancelled");
6350
6700
  setupMethod = promptedSetupMethod;
6351
6701
  }
6352
- if (setupMethod === "neondb") {
6702
+ if (setupMethod === "neon-new" || setupMethod === "neondb") {
6353
6703
  const neonDbResult = await setupWithNeonDb(projectDir, packageManager, backend);
6354
6704
  if (neonDbResult.isErr()) {
6355
6705
  cliLog.error(pc.red(neonDbResult.error.message));
@@ -7269,7 +7619,7 @@ async function getDockerStatus(database) {
7269
7619
  //#endregion
7270
7620
  //#region src/helpers/core/post-installation.ts
7271
7621
  function getDesktopStaticBuildNote(frontend) {
7272
- const staticBuildFrontends = new Map([
7622
+ const staticBuildFrontends = /* @__PURE__ */ new Map([
7273
7623
  ["tanstack-start", "TanStack Start"],
7274
7624
  ["next", "Next.js"],
7275
7625
  ["nuxt", "Nuxt"],
@@ -7739,24 +8089,35 @@ function createEmptyResult(timeScaffolded, elapsedTimeMs, error) {
7739
8089
  error
7740
8090
  };
7741
8091
  }
7742
- async function createProjectHandler(input, options = {}) {
8092
+ async function executeCreateProjectHandler(input, options) {
7743
8093
  const { silent = false } = options;
7744
8094
  return runWithContextAsync({ silent }, async () => {
7745
8095
  const startTime = Date.now();
7746
8096
  const timeScaffolded = (/* @__PURE__ */ new Date()).toISOString();
7747
- const result = await createProjectHandlerInternal(input, startTime, timeScaffolded);
7748
- if (result.isOk()) return result.value;
7749
- const error = result.error;
7750
- const elapsedTimeMs = Date.now() - startTime;
7751
- if (UserCancelledError.is(error)) {
7752
- if (isSilent()) return createEmptyResult(timeScaffolded, elapsedTimeMs, error.message);
7753
- return;
7754
- }
7755
- if (isSilent()) return createEmptyResult(timeScaffolded, elapsedTimeMs, error.message);
7756
- displayError(error);
7757
- process.exit(1);
8097
+ return {
8098
+ result: await createProjectHandlerInternal(input, startTime, timeScaffolded),
8099
+ startTime,
8100
+ timeScaffolded
8101
+ };
7758
8102
  });
7759
8103
  }
8104
+ async function createProjectHandlerResult(input, options = {}) {
8105
+ return (await executeCreateProjectHandler(input, options)).result;
8106
+ }
8107
+ async function createProjectHandler(input, options = {}) {
8108
+ const { silent = false } = options;
8109
+ const { result, startTime, timeScaffolded } = await executeCreateProjectHandler(input, options);
8110
+ if (result.isOk()) return result.value;
8111
+ const error = result.error;
8112
+ const elapsedTimeMs = Date.now() - startTime;
8113
+ if (UserCancelledError.is(error)) {
8114
+ if (silent) return createEmptyResult(timeScaffolded, elapsedTimeMs, error.message);
8115
+ return;
8116
+ }
8117
+ if (silent) return createEmptyResult(timeScaffolded, elapsedTimeMs, error.message);
8118
+ displayError(error);
8119
+ process.exit(1);
8120
+ }
7760
8121
  async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
7761
8122
  return Result.gen(async function* () {
7762
8123
  if (!isSilent() && input.renderTitle !== false) renderTitle();
@@ -7789,25 +8150,7 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
7789
8150
  shouldClearDirectory = conflictResult.shouldClearDirectory;
7790
8151
  yield* validateResolvedProjectPathInput(finalPathInput);
7791
8152
  yield* Result.await(validateSafeProjectDirectoryPath(finalPathInput));
7792
- let finalResolvedPath;
7793
- let finalBaseName;
7794
- if (input.dryRun) {
7795
- finalResolvedPath = finalPathInput === "." ? process.cwd() : path.resolve(process.cwd(), finalPathInput);
7796
- finalBaseName = path.basename(finalResolvedPath);
7797
- } else {
7798
- const setupResult = yield* Result.await(Result.tryPromise({
7799
- try: async () => setupProjectDirectory(finalPathInput, shouldClearDirectory),
7800
- catch: (e) => {
7801
- if (e instanceof UserCancelledError) return e;
7802
- return new CLIError({
7803
- message: e instanceof Error ? e.message : String(e),
7804
- cause: e
7805
- });
7806
- }
7807
- }));
7808
- finalResolvedPath = setupResult.finalResolvedPath;
7809
- finalBaseName = setupResult.finalBaseName;
7810
- }
8153
+ const { finalResolvedPath, finalBaseName } = resolveProjectDirectoryPath(finalPathInput);
7811
8154
  const originalInput = {
7812
8155
  ...input,
7813
8156
  projectDirectory: input.projectName
@@ -7846,10 +8189,10 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
7846
8189
  relativePath: finalPathInput
7847
8190
  };
7848
8191
  const validationResult = validateConfigCompatibility(config, providedFlags, cliInput);
7849
- if (validationResult.isErr()) return Result.err(new CLIError({
8192
+ if (validationResult.isErr()) yield* new CLIError({
7850
8193
  message: validationResult.error.message,
7851
8194
  cause: validationResult.error
7852
- }));
8195
+ });
7853
8196
  if (!isSilent()) log.info(pc.dim("Quick setup selected — using defaults and provided flags."));
7854
8197
  } else {
7855
8198
  const flagConfigResult = processAndValidateFlags(cliInput, providedFlags, finalBaseName);
@@ -7881,9 +8224,22 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
7881
8224
  dbSetupOptions: effectiveDbSetupOptions
7882
8225
  };
7883
8226
  if (!input.yolo) {
7884
- const addonsValidationResult = validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime);
7885
- if (addonsValidationResult.isErr()) return Result.err(new CLIError({ message: addonsValidationResult.error.message }));
8227
+ const resolvedConfigValidationResult = validateResolvedConfigCompatibility(config);
8228
+ if (resolvedConfigValidationResult.isErr()) yield* new CLIError({
8229
+ message: resolvedConfigValidationResult.error.message,
8230
+ cause: resolvedConfigValidationResult.error
8231
+ });
7886
8232
  }
8233
+ if (!input.dryRun) yield* Result.await(Result.tryPromise({
8234
+ try: async () => setupProjectDirectory(finalPathInput, shouldClearDirectory),
8235
+ catch: (e) => {
8236
+ if (e instanceof UserCancelledError) return e;
8237
+ return new CLIError({
8238
+ message: e instanceof Error ? e.message : String(e),
8239
+ cause: e
8240
+ });
8241
+ }
8242
+ }));
7887
8243
  if (!isSilent()) {
7888
8244
  log.info(pc.magenta(pc.bold("Stack ready")));
7889
8245
  log.message(displayConfig(config));
@@ -8100,7 +8456,7 @@ const router = t.router({
8100
8456
  }),
8101
8457
  createJson: t.procedure.meta({
8102
8458
  description: "Create a project from a raw JSON payload (agent-friendly)",
8103
- jsonInput: true
8459
+ jsonInput: "always"
8104
8460
  }).input(types_exports.CreateInputSchema).mutation(async ({ input }) => {
8105
8461
  const result = await createProjectHandler(input, { silent: true });
8106
8462
  if (!result) throw new UserCancelledError({ message: "Operation cancelled" });
@@ -8122,7 +8478,7 @@ const router = t.router({
8122
8478
  }),
8123
8479
  addJson: t.procedure.meta({
8124
8480
  description: "Add addons from a raw JSON payload (agent-friendly)",
8125
- jsonInput: true
8481
+ jsonInput: "always"
8126
8482
  }).input(types_exports.AddInputSchema).mutation(async ({ input }) => {
8127
8483
  const result = await addHandler(input, { silent: true });
8128
8484
  if (!result) throw new UserCancelledError({ message: "Operation cancelled" });
@@ -8194,15 +8550,15 @@ async function create(projectName, options) {
8194
8550
  };
8195
8551
  return Result.tryPromise({
8196
8552
  try: async () => {
8197
- const result = await createProjectHandler(input, { silent: true });
8198
- if (!result) throw new UserCancelledError({ message: "Operation cancelled" });
8199
- if (!result.success) throw new CLIError({ message: result.error || "Unknown error occurred" });
8200
- return result;
8553
+ const result = await createProjectHandlerResult(input, { silent: true });
8554
+ if (result.isErr()) throw result.error;
8555
+ return result.value;
8201
8556
  },
8202
8557
  catch: (e) => {
8203
- if (e instanceof UserCancelledError) return e;
8204
- if (e instanceof CLIError) return e;
8205
- if (e instanceof ProjectCreationError) return e;
8558
+ if (UserCancelledError.is(e)) return e;
8559
+ if (CLIError.is(e)) return e;
8560
+ if (DirectoryConflictError.is(e)) return e;
8561
+ if (ProjectCreationError.is(e)) return e;
8206
8562
  return new CLIError({
8207
8563
  message: e instanceof Error ? e.message : String(e),
8208
8564
  cause: e
@@ -8273,7 +8629,7 @@ async function createVirtual(options) {
8273
8629
  webDeploy: virtualOptions.webDeploy || "none",
8274
8630
  serverDeploy: virtualOptions.serverDeploy || "none"
8275
8631
  };
8276
- const validationResult = validateConfigCompatibility(config, new Set([
8632
+ const validationResult = validateConfigCompatibility(config, /* @__PURE__ */ new Set([
8277
8633
  "database",
8278
8634
  "orm",
8279
8635
  "backend",