spfn 0.3.0-beta.6 → 0.3.0-beta.7

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 (3) hide show
  1. package/README.md +6 -0
  2. package/dist/index.js +463 -280
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -948,7 +948,7 @@ import { dirname as dirname2, join as join10 } from "path";
948
948
  import { fileURLToPath as fileURLToPath2 } from "url";
949
949
  function getCliVersion() {
950
950
  if (true) {
951
- return "0.3.0-beta.6";
951
+ return "0.3.0-beta.7";
952
952
  }
953
953
  return fromPackageJson ?? (fromPackageJson = readPackageVersion());
954
954
  }
@@ -1190,6 +1190,7 @@ function envLocalTemplate(mode) {
1190
1190
  # Full scaffold: auth session encryption (Next.js server only; never NEXT_PUBLIC_*)
1191
1191
  SPFN_AUTH_SESSION_SECRET=${randomSecret("base64url")}
1192
1192
  SPFN_AUTH_SESSION_TTL=7d
1193
+ ${CSRF_ENV_LINES}
1193
1194
  NEXT_PUBLIC_SPFN_APP_URL=http://localhost:3790
1194
1195
  `;
1195
1196
  }
@@ -1386,7 +1387,7 @@ function updateTsconfig(cwd) {
1386
1387
  logger.warn('Could not update tsconfig.json (you can add "src/server" to exclude manually)');
1387
1388
  }
1388
1389
  }
1389
- var writeFileSync8, ENV_LOCAL_TEMPLATE, FULL_ENV_LOCAL_EXAMPLE, ENV_SERVER_TEMPLATE, FULL_ENV_SERVER_EXAMPLE;
1390
+ var writeFileSync8, ENV_LOCAL_TEMPLATE, CSRF_ENV_LINES, FULL_ENV_LOCAL_EXAMPLE, ENV_SERVER_TEMPLATE, FULL_ENV_SERVER_EXAMPLE;
1390
1391
  var init_config_files = __esm({
1391
1392
  "src/commands/init/steps/config-files.ts"() {
1392
1393
  "use strict";
@@ -1404,10 +1405,13 @@ NEXT_PUBLIC_SPFN_API_URL=http://localhost:8790
1404
1405
  # Next.js app URL (used by the SPFN server for CORS/redirects)
1405
1406
  SPFN_APP_URL=http://localhost:3790
1406
1407
  `;
1408
+ CSRF_ENV_LINES = `# CSRF for cookie-session mutations: off | warn | enforce (unset = warn)
1409
+ SPFN_AUTH_CSRF=enforce`;
1407
1410
  FULL_ENV_LOCAL_EXAMPLE = `
1408
1411
  # Full scaffold: auth session encryption (Next.js server only; never NEXT_PUBLIC_*)
1409
1412
  SPFN_AUTH_SESSION_SECRET=replace-with-a-random-secret-at-least-32-characters
1410
1413
  SPFN_AUTH_SESSION_TTL=7d
1414
+ ${CSRF_ENV_LINES}
1411
1415
  NEXT_PUBLIC_SPFN_APP_URL=http://localhost:3790
1412
1416
  `;
1413
1417
  ENV_SERVER_TEMPLATE = `# SPFN backend environment
@@ -1981,16 +1985,182 @@ init_init();
1981
1985
 
1982
1986
  // src/commands/dev.ts
1983
1987
  init_logger();
1984
- init_package_manager();
1985
1988
  import { Command as Command4 } from "commander";
1986
- import { existsSync as existsSync15, readFileSync as readFileSync8, writeFileSync as writeFileSync10, mkdirSync, unlinkSync, rmSync, watch } from "fs";
1987
- import { join as join16, relative, sep as sep2 } from "path";
1989
+ import { existsSync as existsSync16, readFileSync as readFileSync9, writeFileSync as writeFileSync11, mkdirSync, unlinkSync, rmSync, watch } from "fs";
1990
+ import { join as join17, relative, sep as sep2 } from "path";
1988
1991
  import { execa as execa6 } from "execa";
1989
1992
  import chokidar from "chokidar";
1990
1993
 
1994
+ // src/lib/agent-instructions.ts
1995
+ import { existsSync as existsSync15, readFileSync as readFileSync8, writeFileSync as writeFileSync10 } from "fs";
1996
+ import { join as join15 } from "path";
1997
+
1998
+ // src/lib/agent-instructions-template.ts
1999
+ init_version();
2000
+ var BEGIN_MARKER = "<!-- spfn:agent-instructions:begin \u2014 generated by spfn dev; edits inside are overwritten -->";
2001
+ var END_MARKER = "<!-- spfn:agent-instructions:end -->";
2002
+ function renderAgentInstructions(version = getCliVersion()) {
2003
+ return `${BEGIN_MARKER}
2004
+ ## SPFN conventions for coding agents
2005
+
2006
+ This is not the stack you know. An SPFN app looks like Next.js plus Drizzle, but
2007
+ its idioms are not the ecosystem defaults, and code written from general priors
2008
+ is wrong here. Read the docs below before writing server, data or auth code.
2009
+
2010
+ **Data access.** Every query goes through a repository extending
2011
+ \`BaseRepository\` \u2014 \`this.db\` writes, \`this.readDb\` reads. Handlers and
2012
+ services never import drizzle query builders directly.
2013
+
2014
+ \`\`\`typescript
2015
+ import { BaseRepository } from '@spfn/core/db';
2016
+ import { orders } from '../entities/order.entity';
2017
+
2018
+ export class OrderRepository extends BaseRepository
2019
+ {
2020
+ async findByCustomer(customerId: bigint)
2021
+ {
2022
+ return this._findMany(orders, { where: { customerId } });
2023
+ }
2024
+ }
2025
+ \`\`\`
2026
+
2027
+ The scaffold's \`src/server/repositories/\` shows the shape.
2028
+
2029
+ **Transactions.** Wrap the route in \`Transactional()\`, or call
2030
+ \`runInTransaction\` in a service or script. Never accept or pass a \`tx\`
2031
+ parameter: repositories pick the transaction up from the async context. Side
2032
+ effects that must not fire on a rollback go in \`onAfterCommit(...)\`.
2033
+
2034
+ **Auth.** Read the principal with \`getAuth(c)\` from \`@spfn/auth/server\`.
2035
+ Authorization is declared route middleware \u2014
2036
+ \`.use([authenticate, requirePermissions('order:write')])\` \u2014 never an ad-hoc
2037
+ check inside the handler body.
2038
+
2039
+ **Frontend data.** A page's initial data is awaited in a Server Component
2040
+ through the isomorphic \`api.\` client; cookies forward automatically. Fetching
2041
+ initial data from a \`'use client'\` component in \`useEffect\` is the
2042
+ anti-pattern. Mutations go through server actions, or the same \`api.\` client
2043
+ from a Client Component.
2044
+
2045
+ **Generated files.** Route maps under \`src/generated/\` come from
2046
+ \`pnpm codegen\` \u2014 never hand-edit them. Migrations come from
2047
+ \`spfn db generate\` off the entities; never hand-write migration SQL.
2048
+
2049
+ **Read before writing.** \`node_modules/@spfn/core/README.md\`,
2050
+ \`node_modules/@spfn/core/src/db/README.md\`, \`node_modules/@spfn/auth/README.md\`.
2051
+ Online: \`https://superfunction.xyz/docs/packages/core/<module>\` for cache,
2052
+ codegen, config, db, env, errors, event, job, logger, middleware, nextjs, route,
2053
+ security and server; \`https://superfunction.xyz/docs/guides/<guide>\` for
2054
+ authentication, custom-generators, deployment, file-upload, monitoring and
2055
+ websockets. Do not guess other paths \u2014 they 404.
2056
+
2057
+ <!-- spfn CLI v${version} -->
2058
+ ${END_MARKER}`;
2059
+ }
2060
+
2061
+ // src/lib/agent-instructions.ts
2062
+ var AGENTS_FILE = "AGENTS.md";
2063
+ var CLAUDE_FILE = "CLAUDE.md";
2064
+ function syncAgentInstructions(projectRoot, options = {}) {
2065
+ if (isOptedOut(options)) {
2066
+ return { action: "skipped" };
2067
+ }
2068
+ const agentsPath = join15(projectRoot, AGENTS_FILE);
2069
+ const block = renderAgentInstructions();
2070
+ if (!existsSync15(agentsPath)) {
2071
+ writeFileSync10(agentsPath, `${block}
2072
+ `, "utf8");
2073
+ ensureClaudeReference(projectRoot);
2074
+ return { action: "created" };
2075
+ }
2076
+ const content = withoutByteOrderMark(readFileSync8(agentsPath, "utf8"));
2077
+ const lines = content.split("\n");
2078
+ const location = locateBlock(lines);
2079
+ if (location.kind === "malformed") {
2080
+ return {
2081
+ action: "skipped",
2082
+ warning: `${AGENTS_FILE} has a malformed spfn block \u2014 expected exactly one "${BEGIN_MARKER}" line followed by one "${END_MARKER}" line. Fix or delete the markers; nothing was written.`
2083
+ };
2084
+ }
2085
+ ensureClaudeReference(projectRoot);
2086
+ if (location.kind === "absent") {
2087
+ const eol = content.includes("\r\n") ? "\r\n" : "\n";
2088
+ const existing = content.replace(/(\r?\n)+$/, "");
2089
+ const separator = existing.length > 0 ? `${eol}${eol}` : "";
2090
+ writeFileSync10(agentsPath, `${existing}${separator}${block.split("\n").join(eol)}${eol}`, "utf8");
2091
+ return { action: "appended" };
2092
+ }
2093
+ const carriageReturn = lines[location.begin].endsWith("\r") ? "\r" : "";
2094
+ const blockLines = block.split("\n").map((line) => line + carriageReturn);
2095
+ const currentLines = lines.slice(location.begin, location.end + 1);
2096
+ if (currentLines.length === blockLines.length && currentLines.every((line, index) => line === blockLines[index])) {
2097
+ return { action: "unchanged" };
2098
+ }
2099
+ lines.splice(location.begin, location.end - location.begin + 1, ...blockLines);
2100
+ writeFileSync10(agentsPath, lines.join("\n"), "utf8");
2101
+ return { action: "replaced" };
2102
+ }
2103
+ function isOptedOut(options) {
2104
+ const fromEnv = (process.env.SPFN_AGENT_FILES ?? "").toLowerCase();
2105
+ return options.agentFiles === false || fromEnv === "0" || fromEnv === "false";
2106
+ }
2107
+ function locateBlock(lines) {
2108
+ const fenced = fencedLines(lines);
2109
+ const begins = lineIndicesOf(lines, BEGIN_MARKER, fenced);
2110
+ const ends = lineIndicesOf(lines, END_MARKER, fenced);
2111
+ if (begins.length === 0 && ends.length === 0) {
2112
+ return { kind: "absent" };
2113
+ }
2114
+ if (begins.length !== 1 || ends.length !== 1 || ends[0] < begins[0]) {
2115
+ return { kind: "malformed" };
2116
+ }
2117
+ return { kind: "found", begin: begins[0], end: ends[0] };
2118
+ }
2119
+ function lineIndicesOf(lines, marker, fenced) {
2120
+ const found = [];
2121
+ lines.forEach((line, index) => {
2122
+ if (!fenced[index] && withoutCarriageReturn(line) === marker) {
2123
+ found.push(index);
2124
+ }
2125
+ });
2126
+ return found;
2127
+ }
2128
+ var FENCE_LINE = /^\s*(`{3,}|~{3,})(.*)$/;
2129
+ function fencedLines(lines) {
2130
+ let open = null;
2131
+ return lines.map((rawLine) => {
2132
+ const fence = FENCE_LINE.exec(withoutCarriageReturn(rawLine));
2133
+ if (open === null) {
2134
+ open = fence ? { character: fence[1][0], length: fence[1].length } : null;
2135
+ return false;
2136
+ }
2137
+ if (fence && fence[1][0] === open.character && fence[1].length >= open.length && fence[2].trim() === "") {
2138
+ open = null;
2139
+ }
2140
+ return true;
2141
+ });
2142
+ }
2143
+ function withoutCarriageReturn(line) {
2144
+ return line.endsWith("\r") ? line.slice(0, -1) : line;
2145
+ }
2146
+ function withoutByteOrderMark(content) {
2147
+ return content.startsWith("\uFEFF") ? content.slice(1) : content;
2148
+ }
2149
+ function ensureClaudeReference(projectRoot) {
2150
+ const claudePath = join15(projectRoot, CLAUDE_FILE);
2151
+ if (existsSync15(claudePath)) {
2152
+ return;
2153
+ }
2154
+ writeFileSync10(claudePath, `@${AGENTS_FILE}
2155
+ `, "utf8");
2156
+ }
2157
+
2158
+ // src/commands/dev.ts
2159
+ init_package_manager();
2160
+
1991
2161
  // src/utils/secret-store/index.ts
1992
2162
  init_env_file();
1993
- import { join as join15 } from "path";
2163
+ import { join as join16 } from "path";
1994
2164
 
1995
2165
  // src/utils/secret-store/macos.ts
1996
2166
  import { execa as execa4 } from "execa";
@@ -2177,7 +2347,7 @@ function keychainRef(key) {
2177
2347
  return `${KEYCHAIN_REF_PREFIX}${keychainName(key)}`;
2178
2348
  }
2179
2349
  async function resolveKeychainEnv(cwd) {
2180
- const parsed = parseEnvFile(join15(cwd, ".env.server"));
2350
+ const parsed = parseEnvFile(join16(cwd, ".env.server"));
2181
2351
  const refs = Object.entries(parsed).filter(([, value]) => value.startsWith(KEYCHAIN_REF_PREFIX));
2182
2352
  if (refs.length === 0) {
2183
2353
  return { env: {}, missing: [] };
@@ -2205,33 +2375,45 @@ import { loadAppConfig, resolvePorts, resolveHost } from "@spfn/core/app-config"
2205
2375
  function ignoreDotfilesUnder(root) {
2206
2376
  return (watchedPath) => relative(root, watchedPath).split(sep2).some((segment) => segment.startsWith(".") && segment !== "." && segment !== "..");
2207
2377
  }
2378
+ function writeAgentInstructions(cwd, agentFiles) {
2379
+ try {
2380
+ const { action, warning } = syncAgentInstructions(cwd, { agentFiles });
2381
+ if (warning) {
2382
+ logger.warn(`[SPFN] ${warning}`);
2383
+ } else if (action !== "unchanged" && action !== "skipped") {
2384
+ logger.info(`[SPFN] Agent instructions ${action} in AGENTS.md`);
2385
+ }
2386
+ } catch (error) {
2387
+ logger.warn(`[SPFN] Could not write the agent instruction files (AGENTS.md, CLAUDE.md): ${error instanceof Error ? error.message : String(error)}`);
2388
+ }
2389
+ }
2208
2390
  function waitForReadyFile(filePath, timeoutMs = 3e4) {
2209
2391
  return new Promise((resolve4, reject) => {
2210
- if (existsSync15(filePath)) {
2392
+ if (existsSync16(filePath)) {
2211
2393
  unlinkSync(filePath);
2212
2394
  }
2213
2395
  const timer = setTimeout(() => {
2214
2396
  watcher.close();
2215
2397
  reject(new Error(`Server did not become ready within ${timeoutMs / 1e3}s`));
2216
2398
  }, timeoutMs);
2217
- const dir = join16(filePath, "..");
2399
+ const dir = join17(filePath, "..");
2218
2400
  const fileName = filePath.split("/").pop();
2219
2401
  const watcher = watch(dir, (_event, name) => {
2220
- if (name === fileName && existsSync15(filePath)) {
2402
+ if (name === fileName && existsSync16(filePath)) {
2221
2403
  watcher.close();
2222
2404
  clearTimeout(timer);
2223
- resolve4(readFileSync8(filePath, "utf-8").trim());
2405
+ resolve4(readFileSync9(filePath, "utf-8").trim());
2224
2406
  }
2225
2407
  });
2226
2408
  });
2227
2409
  }
2228
- var devCommand = new Command4("dev").description("Start SPFN development server (detects and runs Next.js + Hono)").option("-p, --port <port>", "Server port").option("-H, --host <host>", "Server host").option("--server-only", "Run only Hono server (skip Next.js)").option("--watch", "Enable hot reload (watch mode)").option("--allow-pending-migrations", "Start even when migrations are pending (they are listed as a warning)").action(async (options) => {
2410
+ var devCommand = new Command4("dev").description("Start SPFN development server (detects and runs Next.js + Hono)").option("-p, --port <port>", "Server port").option("-H, --host <host>", "Server host").option("--server-only", "Run only Hono server (skip Next.js)").option("--watch", "Enable hot reload (watch mode)").option("--allow-pending-migrations", "Start even when migrations are pending (they are listed as a warning)").option("--no-agent-files", "Do not write the SPFN instruction block into AGENTS.md (same as SPFN_AGENT_FILES=0)").action(async (options) => {
2229
2411
  process.setMaxListeners(20);
2230
2412
  if (!process.env.NODE_ENV) {
2231
2413
  process.env.NODE_ENV = "development";
2232
2414
  }
2233
2415
  const cwd = process.cwd();
2234
- const serverDir = join16(cwd, "src", "server");
2416
+ const serverDir = join17(cwd, "src", "server");
2235
2417
  if (options.port) {
2236
2418
  process.env.SPFN_PORT = String(options.port);
2237
2419
  }
@@ -2241,11 +2423,12 @@ var devCommand = new Command4("dev").description("Start SPFN development server
2241
2423
  const appConfig = await loadAppConfig(cwd);
2242
2424
  const { next: nextPort, server: serverPort } = resolvePorts(appConfig);
2243
2425
  const serverHost = resolveHost(appConfig);
2244
- if (!existsSync15(serverDir)) {
2426
+ if (!existsSync16(serverDir)) {
2245
2427
  logger.error("src/server directory not found.");
2246
2428
  logger.info('Run "spfn init" first to initialize SPFN in your project.');
2247
2429
  process.exit(1);
2248
2430
  }
2431
+ writeAgentInstructions(cwd, options.agentFiles !== false);
2249
2432
  const { env: keychainEnv, missing: keychainMissing } = await resolveKeychainEnv(cwd);
2250
2433
  const injectedCount = Object.keys(keychainEnv).length;
2251
2434
  if (injectedCount > 0) {
@@ -2267,28 +2450,28 @@ var devCommand = new Command4("dev").description("Start SPFN development server
2267
2450
  if (migrationCheck.allowPending) {
2268
2451
  serverEnv.SPFN_ALLOW_PENDING_MIGRATIONS = "true";
2269
2452
  }
2270
- const packageJsonPath = join16(cwd, "package.json");
2453
+ const packageJsonPath = join17(cwd, "package.json");
2271
2454
  let hasNext = false;
2272
- if (existsSync15(packageJsonPath)) {
2273
- const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
2455
+ if (existsSync16(packageJsonPath)) {
2456
+ const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
2274
2457
  hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
2275
2458
  }
2276
- const tempDir = join16(cwd, ".spfn");
2277
- const serverEntry = join16(tempDir, "server.mjs");
2278
- const watcherEntry = join16(tempDir, "watcher.mjs");
2459
+ const tempDir = join17(cwd, ".spfn");
2460
+ const serverEntry = join17(tempDir, "server.mjs");
2461
+ const watcherEntry = join17(tempDir, "watcher.mjs");
2279
2462
  mkdirSync(tempDir, { recursive: true });
2280
- const serverBuildDir = join16(tempDir, "server");
2281
- if (existsSync15(serverBuildDir)) {
2463
+ const serverBuildDir = join17(tempDir, "server");
2464
+ if (existsSync16(serverBuildDir)) {
2282
2465
  rmSync(serverBuildDir, { recursive: true, force: true });
2283
2466
  logger.info("[SPFN] Cleaned stale build cache (.spfn/server)");
2284
2467
  }
2285
- const readySignal = join16(tempDir, "server-ready");
2286
- if (existsSync15(readySignal)) {
2468
+ const readySignal = join17(tempDir, "server-ready");
2469
+ if (existsSync16(readySignal)) {
2287
2470
  unlinkSync(readySignal);
2288
2471
  }
2289
2472
  const configParts = ["debug: true"];
2290
- const readyFile = join16(tempDir, "server-ready");
2291
- writeFileSync10(serverEntry, `
2473
+ const readyFile = join17(tempDir, "server-ready");
2474
+ writeFileSync11(serverEntry, `
2292
2475
  import { writeFileSync } from 'fs';
2293
2476
 
2294
2477
  // Load environment variables FIRST (before any imports that depend on them)
@@ -2304,7 +2487,7 @@ const instance = await startServer({
2304
2487
  // Signal ready with actual port
2305
2488
  writeFileSync(${JSON.stringify(readyFile)}, String(instance.config.port));
2306
2489
  `);
2307
- writeFileSync10(watcherEntry, `
2490
+ writeFileSync11(watcherEntry, `
2308
2491
  // Load environment variables
2309
2492
  // const { loadEnvFiles } = await import('@spfn/core/server');
2310
2493
  // loadEnvFiles();
@@ -2575,8 +2758,8 @@ catch (error)
2575
2758
  init_logger();
2576
2759
  init_package_manager();
2577
2760
  import { Command as Command5 } from "commander";
2578
- import { existsSync as existsSync16, writeFileSync as writeFileSync11, mkdirSync as mkdirSync2, readdirSync } from "fs";
2579
- import { join as join17 } from "path";
2761
+ import { existsSync as existsSync17, writeFileSync as writeFileSync12, mkdirSync as mkdirSync2, readdirSync } from "fs";
2762
+ import { join as join18 } from "path";
2580
2763
  import { execa as execa7 } from "execa";
2581
2764
  import ora5 from "ora";
2582
2765
  import chalk7 from "chalk";
@@ -2603,16 +2786,16 @@ async function buildProject(options) {
2603
2786
  }
2604
2787
  const cwd = process.cwd();
2605
2788
  const pm = detectPackageManager(cwd);
2606
- const packageJsonPath = join17(cwd, "package.json");
2789
+ const packageJsonPath = join18(cwd, "package.json");
2607
2790
  let hasNext = false;
2608
- if (existsSync16(packageJsonPath)) {
2791
+ if (existsSync17(packageJsonPath)) {
2609
2792
  const packageJson = JSON.parse(await import("fs").then(
2610
2793
  (fs5) => fs5.promises.readFile(packageJsonPath, "utf-8")
2611
2794
  ));
2612
2795
  hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
2613
2796
  }
2614
- const serverDir = join17(cwd, "src", "server");
2615
- const hasServer = existsSync16(serverDir);
2797
+ const serverDir = join18(cwd, "src", "server");
2798
+ const hasServer = existsSync17(serverDir);
2616
2799
  console.log(chalk7.blue.bold("\n\u{1F3D7}\uFE0F Building SPFN project for production...\n"));
2617
2800
  if (hasServer) {
2618
2801
  const spinner = ora5("Generating API client...").start();
@@ -2654,10 +2837,10 @@ async function buildProject(options) {
2654
2837
  if (hasServer && !options.nextOnly) {
2655
2838
  const spinner = ora5("Building SPFN server...").start();
2656
2839
  try {
2657
- const outputDir = join17(cwd, ".spfn", "server");
2840
+ const outputDir = join18(cwd, ".spfn", "server");
2658
2841
  mkdirSync2(outputDir, { recursive: true });
2659
- const serverDir2 = join17(cwd, "src", "server");
2660
- if (!existsSync16(serverDir2)) {
2842
+ const serverDir2 = join18(cwd, "src", "server");
2843
+ if (!existsSync17(serverDir2)) {
2661
2844
  spinner.fail("SPFN server build failed");
2662
2845
  logger.error("src/server/ directory not found");
2663
2846
  logger.error('Please run "spfn init" to initialize the project.');
@@ -2691,12 +2874,12 @@ async function buildProject(options) {
2691
2874
  onSuccess: async () => {
2692
2875
  }
2693
2876
  });
2694
- const prodServerPath = join17(cwd, ".spfn", "prod-server.mjs");
2877
+ const prodServerPath = join18(cwd, ".spfn", "prod-server.mjs");
2695
2878
  const prodServerContent = renderProdServerEntry();
2696
- writeFileSync11(prodServerPath, prodServerContent);
2879
+ writeFileSync12(prodServerPath, prodServerContent);
2697
2880
  spinner.succeed(`SPFN server build completed \u2192 .spfn/server`);
2698
- const routesDir = join17(cwd, ".spfn", "server", "routes");
2699
- if (existsSync16(routesDir)) {
2881
+ const routesDir = join18(cwd, ".spfn", "server", "routes");
2882
+ if (existsSync17(routesDir)) {
2700
2883
  console.log();
2701
2884
  console.log(chalk7.bold("Route (api)"));
2702
2885
  try {
@@ -2752,8 +2935,8 @@ var buildCommand = new Command5("build").description("Build SPFN project for pro
2752
2935
  init_logger();
2753
2936
  init_package_manager();
2754
2937
  import { Command as Command6 } from "commander";
2755
- import { existsSync as existsSync17, readFileSync as readFileSync9 } from "fs";
2756
- import { join as join18 } from "path";
2938
+ import { existsSync as existsSync18, readFileSync as readFileSync10 } from "fs";
2939
+ import { join as join19 } from "path";
2757
2940
  import { execa as execa8 } from "execa";
2758
2941
  import chalk8 from "chalk";
2759
2942
  import { loadAppConfig as loadAppConfig2, resolvePorts as resolvePorts2 } from "@spfn/core/app-config";
@@ -2762,16 +2945,16 @@ var startCommand = new Command6("start").description("Start SPFN production serv
2762
2945
  process.env.NODE_ENV = "production";
2763
2946
  }
2764
2947
  const cwd = process.cwd();
2765
- const packageJsonPath = join18(cwd, "package.json");
2948
+ const packageJsonPath = join19(cwd, "package.json");
2766
2949
  let hasNext = false;
2767
- if (existsSync17(packageJsonPath)) {
2768
- const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
2950
+ if (existsSync18(packageJsonPath)) {
2951
+ const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
2769
2952
  hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
2770
2953
  }
2771
- const builtServerDir = join18(cwd, ".spfn", "server");
2772
- const hasBuiltServer = existsSync17(builtServerDir);
2773
- const nextBuildDir = join18(cwd, ".next");
2774
- const hasNextBuild = existsSync17(nextBuildDir);
2954
+ const builtServerDir = join19(cwd, ".spfn", "server");
2955
+ const hasBuiltServer = existsSync18(builtServerDir);
2956
+ const nextBuildDir = join19(cwd, ".next");
2957
+ const hasNextBuild = existsSync18(nextBuildDir);
2775
2958
  if (!options.nextOnly && !hasBuiltServer) {
2776
2959
  logger.error('.spfn/server directory not found. Please run "spfn build" first.');
2777
2960
  process.exit(1);
@@ -2781,8 +2964,8 @@ var startCommand = new Command6("start").description("Start SPFN production serv
2781
2964
  process.exit(1);
2782
2965
  }
2783
2966
  const pm = detectPackageManager(cwd);
2784
- const serverEntry = join18(cwd, ".spfn", "prod-server.mjs");
2785
- if (!existsSync17(serverEntry)) {
2967
+ const serverEntry = join19(cwd, ".spfn", "prod-server.mjs");
2968
+ if (!existsSync18(serverEntry)) {
2786
2969
  logger.error('.spfn/prod-server.mjs not found. Please run "spfn build" first.');
2787
2970
  process.exit(1);
2788
2971
  }
@@ -2864,8 +3047,8 @@ var startCommand = new Command6("start").description("Start SPFN production serv
2864
3047
  init_logger();
2865
3048
  init_package_manager();
2866
3049
  import { Command as Command7 } from "commander";
2867
- import { existsSync as existsSync18, mkdirSync as mkdirSync3, writeFileSync as writeFileSync12 } from "fs";
2868
- import { join as join19 } from "path";
3050
+ import { existsSync as existsSync19, mkdirSync as mkdirSync3, writeFileSync as writeFileSync13 } from "fs";
3051
+ import { join as join20 } from "path";
2869
3052
  import { pathToFileURL } from "url";
2870
3053
  import { execa as execa9 } from "execa";
2871
3054
  var CONFIG_FILE_PATHS = [
@@ -2875,7 +3058,7 @@ var CONFIG_FILE_PATHS = [
2875
3058
  "src/server/server.config.js"
2876
3059
  ];
2877
3060
  function findServerConfig(cwd) {
2878
- return CONFIG_FILE_PATHS.map((path5) => join19(cwd, path5)).find(existsSync18);
3061
+ return CONFIG_FILE_PATHS.map((path5) => join20(cwd, path5)).find(existsSync19);
2879
3062
  }
2880
3063
  var provisionCommand = new Command7("provision").description("Run deploy-time provisioning (seed/RBAC lifecycle hooks) \u2014 once per deploy, not per cold start").action(async () => {
2881
3064
  if (!process.env.NODE_ENV) {
@@ -2896,10 +3079,10 @@ var provisionCommand = new Command7("provision").description("Run deploy-time pr
2896
3079
  if (keychainMissing.length > 0) {
2897
3080
  logger.warn(`[SPFN] Could not resolve keychain secret(s): ${keychainMissing.join(", ")} \u2014 run \`spfn secret set <KEY>\``);
2898
3081
  }
2899
- const tempDir = join19(cwd, ".spfn");
2900
- const runnerEntry = join19(tempDir, "provision.mjs");
3082
+ const tempDir = join20(cwd, ".spfn");
3083
+ const runnerEntry = join20(tempDir, "provision.mjs");
2901
3084
  mkdirSync3(tempDir, { recursive: true });
2902
- writeFileSync12(runnerEntry, `
3085
+ writeFileSync13(runnerEntry, `
2903
3086
  if (!process.env.NODE_ENV)
2904
3087
  {
2905
3088
  process.env.NODE_ENV = 'production';
@@ -2942,13 +3125,13 @@ process.exit(0);
2942
3125
  // src/commands/codegen.ts
2943
3126
  init_logger();
2944
3127
  import { Command as Command8 } from "commander";
2945
- import { existsSync as existsSync19, writeFileSync as writeFileSync13 } from "fs";
2946
- import { join as join20 } from "path";
3128
+ import { existsSync as existsSync20, writeFileSync as writeFileSync14 } from "fs";
3129
+ import { join as join21 } from "path";
2947
3130
  import chalk9 from "chalk";
2948
3131
  async function initCodegen(options) {
2949
3132
  const cwd = process.cwd();
2950
- const rcPath = join20(cwd, ".spfnrc.ts");
2951
- if (existsSync19(rcPath)) {
3133
+ const rcPath = join21(cwd, ".spfnrc.ts");
3134
+ if (existsSync20(rcPath)) {
2952
3135
  logger.warn(".spfnrc.ts already exists");
2953
3136
  logger.info("Edit manually to add custom generators");
2954
3137
  process.exit(0);
@@ -2973,7 +3156,7 @@ export default defineConfig({
2973
3156
  ],
2974
3157
  });
2975
3158
  `;
2976
- writeFileSync13(rcPath, content);
3159
+ writeFileSync14(rcPath, content);
2977
3160
  console.log("\n" + chalk9.green.bold("\u2713 Created .spfnrc.ts\n"));
2978
3161
  console.log(chalk9.gray("Configured the @spfn/core:route-map generator."));
2979
3162
  if (options.withExample) {
@@ -3041,18 +3224,18 @@ codegenCommand.command("run").description("Run code generators once (no watch mo
3041
3224
  // src/commands/contract.ts
3042
3225
  init_logger();
3043
3226
  import { Command as Command9 } from "commander";
3044
- import { join as join21 } from "path";
3227
+ import { join as join22 } from "path";
3045
3228
  import chalk10 from "chalk";
3046
3229
  async function resolveContractsDir(cwd, override) {
3047
3230
  if (override) {
3048
- return join21(cwd, override);
3231
+ return join22(cwd, override);
3049
3232
  }
3050
3233
  const { loadCodegenConfig } = await import("@spfn/core/codegen");
3051
3234
  const config = loadCodegenConfig(cwd);
3052
3235
  const generator = config.generators?.find(
3053
3236
  (entry) => "name" in entry && entry.name === "@spfn/core:contract"
3054
3237
  );
3055
- return join21(cwd, generator?.outputDir ?? "./contracts");
3238
+ return join22(cwd, generator?.outputDir ?? "./contracts");
3056
3239
  }
3057
3240
  async function regenerate(cwd) {
3058
3241
  const { loadCodegenConfig, createGeneratorsFromConfig, CodegenOrchestrator } = await import("@spfn/core/codegen");
@@ -3320,7 +3503,7 @@ import { Command as Command11 } from "commander";
3320
3503
  import chalk13 from "chalk";
3321
3504
 
3322
3505
  // src/commands/db/utils/drizzle.ts
3323
- import { existsSync as existsSync20, writeFileSync as writeFileSync14, unlinkSync as unlinkSync2 } from "fs";
3506
+ import { existsSync as existsSync21, writeFileSync as writeFileSync15, unlinkSync as unlinkSync2 } from "fs";
3324
3507
  import { spawn } from "child_process";
3325
3508
  import { pathToFileURL as pathToFileURL2 } from "url";
3326
3509
  import chalk12 from "chalk";
@@ -3387,7 +3570,7 @@ function validateDatabasePrerequisites() {
3387
3570
  }
3388
3571
  }
3389
3572
  async function runDrizzleCommand(command) {
3390
- const hasUserConfig = existsSync20("./drizzle.config.ts");
3573
+ const hasUserConfig = existsSync21("./drizzle.config.ts");
3391
3574
  const tempConfigPath = `./drizzle.config.${process.pid}.${Date.now()}.temp.ts`;
3392
3575
  const configPath = hasUserConfig ? "./drizzle.config.ts" : tempConfigPath;
3393
3576
  if (!hasUserConfig) {
@@ -3406,7 +3589,7 @@ async function runDrizzleCommand(command) {
3406
3589
  expandGlobs: true,
3407
3590
  autoDetectSchemas: true
3408
3591
  });
3409
- writeFileSync14(tempConfigPath, configContent);
3592
+ writeFileSync15(tempConfigPath, configContent);
3410
3593
  console.log(chalk12.dim("Using auto-generated Drizzle config\n"));
3411
3594
  }
3412
3595
  const args = command.split(" ");
@@ -3419,7 +3602,7 @@ async function runDrizzleCommand(command) {
3419
3602
  env: shouldRelaxDbTls(env2.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
3420
3603
  });
3421
3604
  const cleanup = () => {
3422
- if (!hasUserConfig && existsSync20(tempConfigPath)) {
3605
+ if (!hasUserConfig && existsSync21(tempConfigPath)) {
3423
3606
  unlinkSync2(tempConfigPath);
3424
3607
  }
3425
3608
  };
@@ -3739,8 +3922,8 @@ async function applyFunctionMigrations(plans) {
3739
3922
 
3740
3923
  // src/commands/db/migrate.ts
3741
3924
  import chalk21 from "chalk";
3742
- import { join as join22 } from "path";
3743
- import { existsSync as existsSync22 } from "fs";
3925
+ import { join as join23 } from "path";
3926
+ import { existsSync as existsSync23 } from "fs";
3744
3927
 
3745
3928
  // src/commands/db/backup.ts
3746
3929
  import { promises as fs3 } from "fs";
@@ -3833,7 +4016,7 @@ function formatTimestamp() {
3833
4016
 
3834
4017
  // src/commands/db/utils/backup-files.ts
3835
4018
  import { promises as fs2 } from "fs";
3836
- import { existsSync as existsSync21 } from "fs";
4019
+ import { existsSync as existsSync22 } from "fs";
3837
4020
  import path2 from "path";
3838
4021
  import chalk19 from "chalk";
3839
4022
 
@@ -3933,7 +4116,7 @@ async function ensureBackupInGitignore() {
3933
4116
  const gitignorePath = path2.join(process.cwd(), ".gitignore");
3934
4117
  try {
3935
4118
  let content = "";
3936
- let exists = existsSync21(gitignorePath);
4119
+ let exists = existsSync22(gitignorePath);
3937
4120
  if (exists) {
3938
4121
  content = await fs2.readFile(gitignorePath, "utf-8");
3939
4122
  }
@@ -3955,7 +4138,7 @@ async function ensureBackupDir() {
3955
4138
  try {
3956
4139
  await fs2.mkdir(backupDir, { recursive: true });
3957
4140
  const gitignorePath = path2.join(backupDir, ".gitignore");
3958
- const gitignoreExists = existsSync21(gitignorePath);
4141
+ const gitignoreExists = existsSync22(gitignorePath);
3959
4142
  if (!gitignoreExists) {
3960
4143
  await fs2.writeFile(gitignorePath, "# Ignore all backup files\n*.sql\n*.dump\n*.meta.json\n");
3961
4144
  }
@@ -4149,8 +4332,8 @@ async function dbMigrate(options = {}) {
4149
4332
  await executeFunctionMigrations2(loadFunctionMigrationPlans2(functions));
4150
4333
  console.log(chalk21.green("\u2705 Function migrations applied\n"));
4151
4334
  }
4152
- const projectMigrationsDir = join22(process.cwd(), "src/server/drizzle");
4153
- if (existsSync22(projectMigrationsDir)) {
4335
+ const projectMigrationsDir = join23(process.cwd(), "src/server/drizzle");
4336
+ if (existsSync23(projectMigrationsDir)) {
4154
4337
  const projConn = postgres.default(env5.DATABASE_URL, { max: 1 });
4155
4338
  const projDb = drizzle({ client: projConn });
4156
4339
  try {
@@ -4256,7 +4439,7 @@ function printReport(report2) {
4256
4439
 
4257
4440
  // src/commands/db/studio.ts
4258
4441
  import chalk23 from "chalk";
4259
- import { existsSync as existsSync23, writeFileSync as writeFileSync15, unlinkSync as unlinkSync3 } from "fs";
4442
+ import { existsSync as existsSync24, writeFileSync as writeFileSync16, unlinkSync as unlinkSync3 } from "fs";
4260
4443
  import { spawn as spawn3 } from "child_process";
4261
4444
  import { env as env6 } from "@spfn/core/config";
4262
4445
  async function dbStudio(requestedPort) {
@@ -4274,7 +4457,7 @@ async function dbStudio(requestedPort) {
4274
4457
  console.error(chalk23.red(error instanceof Error ? error.message : "Failed to find available port"));
4275
4458
  process.exit(1);
4276
4459
  }
4277
- const hasUserConfig = existsSync23("./drizzle.config.ts");
4460
+ const hasUserConfig = existsSync24("./drizzle.config.ts");
4278
4461
  const tempConfigPath = `./drizzle.config.${process.pid}.${Date.now()}.temp.ts`;
4279
4462
  try {
4280
4463
  const configPath = hasUserConfig ? "./drizzle.config.ts" : tempConfigPath;
@@ -4291,7 +4474,7 @@ async function dbStudio(requestedPort) {
4291
4474
  expandGlobs: true
4292
4475
  // Expand glob patterns for Studio compatibility
4293
4476
  });
4294
- writeFileSync15(tempConfigPath, configContent);
4477
+ writeFileSync16(tempConfigPath, configContent);
4295
4478
  console.log(chalk23.dim("Using auto-generated Drizzle config\n"));
4296
4479
  }
4297
4480
  const studioProcess = spawn3("drizzle-kit", ["studio", `--port=${port}`, `--config=${configPath}`], {
@@ -4300,7 +4483,7 @@ async function dbStudio(requestedPort) {
4300
4483
  env: shouldRelaxDbTls(env6.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
4301
4484
  });
4302
4485
  const cleanup = () => {
4303
- if (!hasUserConfig && existsSync23(tempConfigPath)) {
4486
+ if (!hasUserConfig && existsSync24(tempConfigPath)) {
4304
4487
  unlinkSync3(tempConfigPath);
4305
4488
  }
4306
4489
  };
@@ -4330,7 +4513,7 @@ async function dbStudio(requestedPort) {
4330
4513
  process.exit(0);
4331
4514
  });
4332
4515
  } catch (error) {
4333
- if (!hasUserConfig && existsSync23(tempConfigPath)) {
4516
+ if (!hasUserConfig && existsSync24(tempConfigPath)) {
4334
4517
  unlinkSync3(tempConfigPath);
4335
4518
  }
4336
4519
  console.error(chalk23.red("\u274C Failed to start Drizzle Studio"));
@@ -4717,8 +4900,8 @@ async function dbBackupClean(options) {
4717
4900
  }
4718
4901
 
4719
4902
  // src/commands/db/reindex.ts
4720
- import { existsSync as existsSync24, readFileSync as readFileSync10, writeFileSync as writeFileSync16, renameSync, copyFileSync } from "fs";
4721
- import { join as join23 } from "path";
4903
+ import { existsSync as existsSync25, readFileSync as readFileSync11, writeFileSync as writeFileSync17, renameSync, copyFileSync } from "fs";
4904
+ import { join as join24 } from "path";
4722
4905
  import chalk29 from "chalk";
4723
4906
  import { loadEnv as loadEnv9 } from "@spfn/core/server";
4724
4907
  function isTimestampPrefix(tag) {
@@ -4740,13 +4923,13 @@ async function dbReindex(options = {}) {
4740
4923
  const { getDrizzleConfig } = await import("@spfn/core/db");
4741
4924
  const config = getDrizzleConfig({ disablePackageDiscovery: true });
4742
4925
  const outDir = config.out;
4743
- const journalPath = join23(outDir, "meta", "_journal.json");
4744
- if (!existsSync24(journalPath)) {
4926
+ const journalPath = join24(outDir, "meta", "_journal.json");
4927
+ if (!existsSync25(journalPath)) {
4745
4928
  console.error(chalk29.red("\u274C No _journal.json found at:"), journalPath);
4746
4929
  console.log(chalk29.yellow("\u{1F4A1} Run `spfn db generate` first to create migrations"));
4747
4930
  process.exit(1);
4748
4931
  }
4749
- const journal = JSON.parse(readFileSync10(journalPath, "utf-8"));
4932
+ const journal = JSON.parse(readFileSync11(journalPath, "utf-8"));
4750
4933
  if (journal.entries.length === 0) {
4751
4934
  console.log(chalk29.yellow("No migration entries found \u2014 nothing to reindex."));
4752
4935
  return;
@@ -4762,14 +4945,14 @@ async function dbReindex(options = {}) {
4762
4945
  const { prefix: oldPrefix, suffix } = parseTag(entry.tag);
4763
4946
  const newPrefix = String(entry.when);
4764
4947
  const newTag = suffix ? `${newPrefix}_${suffix}` : newPrefix;
4765
- const oldSql = join23(outDir, `${entry.tag}.sql`);
4766
- const newSql = join23(outDir, `${newTag}.sql`);
4767
- if (existsSync24(oldSql)) {
4948
+ const oldSql = join24(outDir, `${entry.tag}.sql`);
4949
+ const newSql = join24(outDir, `${newTag}.sql`);
4950
+ if (existsSync25(oldSql)) {
4768
4951
  renames.push({ type: "sql", from: oldSql, to: newSql });
4769
4952
  }
4770
- const oldSnapshot = join23(outDir, "meta", `${oldPrefix}_snapshot.json`);
4771
- const newSnapshot = join23(outDir, "meta", `${newPrefix}_snapshot.json`);
4772
- if (existsSync24(oldSnapshot)) {
4953
+ const oldSnapshot = join24(outDir, "meta", `${oldPrefix}_snapshot.json`);
4954
+ const newSnapshot = join24(outDir, "meta", `${newPrefix}_snapshot.json`);
4955
+ if (existsSync25(oldSnapshot)) {
4773
4956
  renames.push({ type: "snapshot", from: oldSnapshot, to: newSnapshot });
4774
4957
  }
4775
4958
  tagUpdates.push({ idx: entry.idx, oldTag: entry.tag, newTag });
@@ -4812,7 +4995,7 @@ async function dbReindex(options = {}) {
4812
4995
  entry.tag = update.newTag;
4813
4996
  }
4814
4997
  }
4815
- writeFileSync16(journalPath, JSON.stringify(journal, null, 2) + "\n");
4998
+ writeFileSync17(journalPath, JSON.stringify(journal, null, 2) + "\n");
4816
4999
  console.log(chalk29.green(`
4817
5000
  \u2705 Reindex complete \u2014 ${tagUpdates.length} migration(s) converted to timestamp prefix.`));
4818
5001
  }
@@ -4835,21 +5018,21 @@ dbCommand.command("reindex").description("Convert migration files from sequentia
4835
5018
  // src/commands/add.ts
4836
5019
  init_package_manager();
4837
5020
  import { Command as Command12 } from "commander";
4838
- import { existsSync as existsSync26, readFileSync as readFileSync12 } from "fs";
4839
- import { join as join25 } from "path";
5021
+ import { existsSync as existsSync27, readFileSync as readFileSync13 } from "fs";
5022
+ import { join as join26 } from "path";
4840
5023
  import { execa as execa10 } from "execa";
4841
5024
  import chalk31 from "chalk";
4842
5025
  import ora11 from "ora";
4843
5026
 
4844
5027
  // src/commands/add-vercel.ts
4845
5028
  init_templates();
4846
- import { copyFileSync as copyFileSync2, existsSync as existsSync25, mkdirSync as mkdirSync4, readFileSync as readFileSync11 } from "fs";
4847
- import { dirname as dirname4, join as join24 } from "path";
5029
+ import { copyFileSync as copyFileSync2, existsSync as existsSync26, mkdirSync as mkdirSync4, readFileSync as readFileSync12 } from "fs";
5030
+ import { dirname as dirname4, join as join25 } from "path";
4848
5031
  import chalk30 from "chalk";
4849
5032
  var FILES = [
4850
5033
  {
4851
5034
  template: "route.ts",
4852
- target: join24("src", "app", "api", "backend", "[[...route]]", "route.ts"),
5035
+ target: join25("src", "app", "api", "backend", "[[...route]]", "route.ts"),
4853
5036
  description: "hono/vercel adapter (mounts the SPFN app under /api/backend)"
4854
5037
  },
4855
5038
  {
@@ -4864,7 +5047,7 @@ var FILES = [
4864
5047
  }
4865
5048
  ];
4866
5049
  function registryEnvValue(templatesDir) {
4867
- const scopeLines = readFileSync11(join24(templatesDir, "npmrc"), "utf8").trim();
5050
+ const scopeLines = readFileSync12(join25(templatesDir, "npmrc"), "utf8").trim();
4868
5051
  const registryUrl = scopeLines.split("\n")[0].split("=")[1];
4869
5052
  const authKey = `${registryUrl.replace(/^https?:/, "").replace(/\/*$/, "/")}:_authToken`;
4870
5053
  return [
@@ -4877,15 +5060,15 @@ function registryEnvValue(templatesDir) {
4877
5060
  async function addVercel() {
4878
5061
  console.log(chalk30.blue("\n\u{1F4E6} Setting up the Vercel serverless target...\n"));
4879
5062
  const cwd = process.cwd();
4880
- const templatesDir = join24(findTemplatesPath(), "vercel");
5063
+ const templatesDir = join25(findTemplatesPath(), "vercel");
4881
5064
  for (const file of FILES) {
4882
- const targetPath = join24(cwd, file.target);
4883
- if (existsSync25(targetPath)) {
5065
+ const targetPath = join25(cwd, file.target);
5066
+ if (existsSync26(targetPath)) {
4884
5067
  console.log(chalk30.yellow(`\u23ED\uFE0F ${file.target} already exists \u2014 skipped (not overwritten)`));
4885
5068
  continue;
4886
5069
  }
4887
5070
  mkdirSync4(dirname4(targetPath), { recursive: true });
4888
- copyFileSync2(join24(templatesDir, file.template), targetPath);
5071
+ copyFileSync2(join25(templatesDir, file.template), targetPath);
4889
5072
  console.log(chalk30.green(`\u2705 ${file.target}`) + chalk30.gray(` \u2014 ${file.description}`));
4890
5073
  }
4891
5074
  console.log(chalk30.green("\n\u2705 Vercel target ready!\n"));
@@ -4930,9 +5113,9 @@ async function addPackage(packageName) {
4930
5113
  console.log(chalk31.blue(`
4931
5114
  \u{1F4E6} Setting up ${packageName}...
4932
5115
  `));
4933
- const pkgPath = join25(process.cwd(), "node_modules", ...packageName.split("/"));
4934
- const pkgJsonPath = join25(pkgPath, "package.json");
4935
- if (!existsSync26(pkgJsonPath)) {
5116
+ const pkgPath = join26(process.cwd(), "node_modules", ...packageName.split("/"));
5117
+ const pkgJsonPath = join26(pkgPath, "package.json");
5118
+ if (!existsSync27(pkgJsonPath)) {
4936
5119
  const pm = detectPackageManager(process.cwd());
4937
5120
  const installSpinner = ora11("Installing package...").start();
4938
5121
  try {
@@ -4946,11 +5129,11 @@ async function addPackage(packageName) {
4946
5129
  } else {
4947
5130
  console.log(chalk31.gray("\u2713 Package already installed (using local version)\n"));
4948
5131
  }
4949
- if (!existsSync26(pkgJsonPath)) {
5132
+ if (!existsSync27(pkgJsonPath)) {
4950
5133
  console.error(chalk31.red(`\u274C Package ${packageName} not found after installation`));
4951
5134
  process.exit(1);
4952
5135
  }
4953
- const pkgJson = JSON.parse(readFileSync12(pkgJsonPath, "utf-8"));
5136
+ const pkgJson = JSON.parse(readFileSync13(pkgJsonPath, "utf-8"));
4954
5137
  if (pkgJson.spfn?.migrations) {
4955
5138
  console.log(chalk31.blue(`
4956
5139
  \u{1F5C4}\uFE0F Setting up database for ${packageName}...
@@ -4996,7 +5179,7 @@ var addCommand = new Command12("add").description("Add a capability to this proj
4996
5179
  // src/commands/env.ts
4997
5180
  import { Command as Command13 } from "commander";
4998
5181
  import chalk32 from "chalk";
4999
- import { existsSync as existsSync27, readFileSync as readFileSync13, writeFileSync as writeFileSync17 } from "fs";
5182
+ import { existsSync as existsSync28, readFileSync as readFileSync14, writeFileSync as writeFileSync18 } from "fs";
5000
5183
  import { resolve as resolve2 } from "path";
5001
5184
  import { parse as parse2 } from "dotenv";
5002
5185
 
@@ -5287,11 +5470,11 @@ async function initEnvFiles(options) {
5287
5470
  }
5288
5471
  function writeEnvTemplate(cwd, file, vars, force) {
5289
5472
  const filePath = resolve2(cwd, file);
5290
- if (existsSync27(filePath) && !force) {
5473
+ if (existsSync28(filePath) && !force) {
5291
5474
  console.log(chalk32.yellow(` \u23ED\uFE0F ${file} already exists (use --force to overwrite)`));
5292
5475
  return;
5293
5476
  }
5294
- writeFileSync17(filePath, generateEnvFileContent(vars), "utf-8");
5477
+ writeFileSync18(filePath, generateEnvFileContent(vars), "utf-8");
5295
5478
  console.log(chalk32.green(` \u2705 ${file} (${vars.length} variables)`));
5296
5479
  }
5297
5480
  function generateEnvFileContent(vars) {
@@ -5336,10 +5519,10 @@ async function checkEnvFiles(options) {
5336
5519
  const warnings = [];
5337
5520
  for (const file of filesToCheck) {
5338
5521
  const filePath = resolve2(cwd, file);
5339
- if (!existsSync27(filePath)) {
5522
+ if (!existsSync28(filePath)) {
5340
5523
  continue;
5341
5524
  }
5342
- const content = readFileSync13(filePath, "utf-8");
5525
+ const content = readFileSync14(filePath, "utf-8");
5343
5526
  const parsed = parse2(content);
5344
5527
  for (const [key, value] of Object.entries(parsed)) {
5345
5528
  loadedEnv[key] = { value: value || "", file };
@@ -6046,12 +6229,12 @@ import chalk34 from "chalk";
6046
6229
 
6047
6230
  // src/utils/ops/auth-crypto.ts
6048
6231
  import { createRequire } from "module";
6049
- import { join as join26 } from "path";
6232
+ import { join as join27 } from "path";
6050
6233
  import { pathToFileURL as pathToFileURL3 } from "url";
6051
6234
  var CRYPTO_ENTRY_SINCE = "0.3.0-beta.2";
6052
6235
  var CRYPTO_ENTRY = "@spfn/auth/crypto";
6053
6236
  async function importFromApp(specifier) {
6054
- const requireFromApp = createRequire(join26(process.cwd(), "noop.js"));
6237
+ const requireFromApp = createRequire(join27(process.cwd(), "noop.js"));
6055
6238
  return await import(pathToFileURL3(requireFromApp.resolve(specifier)).href);
6056
6239
  }
6057
6240
  async function loadAuthCrypto() {
@@ -6468,12 +6651,12 @@ function resolveEnv(env9) {
6468
6651
 
6469
6652
  // src/commands/secret/store-value.ts
6470
6653
  init_logger();
6471
- import { join as join28 } from "path";
6654
+ import { join as join29 } from "path";
6472
6655
  init_env_file();
6473
6656
 
6474
6657
  // src/utils/sops.ts
6475
6658
  import { execa as execa11 } from "execa";
6476
- import { existsSync as existsSync28, mkdirSync as mkdirSync5, writeFileSync as writeFileSync18 } from "fs";
6659
+ import { existsSync as existsSync29, mkdirSync as mkdirSync5, writeFileSync as writeFileSync19 } from "fs";
6477
6660
  import { dirname as dirname5 } from "path";
6478
6661
  async function ensureSopsInstalled() {
6479
6662
  try {
@@ -6483,14 +6666,14 @@ async function ensureSopsInstalled() {
6483
6666
  }
6484
6667
  }
6485
6668
  async function sopsDecrypt(absFile) {
6486
- if (!existsSync28(absFile)) {
6669
+ if (!existsSync29(absFile)) {
6487
6670
  return {};
6488
6671
  }
6489
6672
  const { stdout } = await execa11("sops", ["--decrypt", "--output-type", "json", absFile]);
6490
6673
  return JSON.parse(stdout);
6491
6674
  }
6492
6675
  async function sopsSetValue(absFile, relFile, key, value) {
6493
- if (existsSync28(absFile)) {
6676
+ if (existsSync29(absFile)) {
6494
6677
  await execa11("sops", ["set", absFile, `["${key}"]`, JSON.stringify(value)]);
6495
6678
  return;
6496
6679
  }
@@ -6509,27 +6692,27 @@ async function sopsSetValue(absFile, relFile, key, value) {
6509
6692
  ],
6510
6693
  { input: JSON.stringify({ [key]: value }) }
6511
6694
  );
6512
- writeFileSync18(absFile, stdout);
6695
+ writeFileSync19(absFile, stdout);
6513
6696
  }
6514
6697
  async function sopsUpdateKeys(absFile) {
6515
6698
  await execa11("sops", ["updatekeys", "-y", absFile]);
6516
6699
  }
6517
6700
 
6518
6701
  // src/utils/secret-config.ts
6519
- import { existsSync as existsSync29, readdirSync as readdirSync2 } from "fs";
6520
- import { join as join27 } from "path";
6702
+ import { existsSync as existsSync30, readdirSync as readdirSync2 } from "fs";
6703
+ import { join as join28 } from "path";
6521
6704
  var SECRETS_DIR = "secrets";
6522
6705
  function getSopsFile(cwd, env9) {
6523
6706
  const relFile = `${SECRETS_DIR}/${env9}.enc.json`;
6524
- return { absFile: join27(cwd, relFile), relFile };
6707
+ return { absFile: join28(cwd, relFile), relFile };
6525
6708
  }
6526
6709
  function findUp(cwd, filename, maxDepth = 6) {
6527
6710
  let dir = cwd;
6528
6711
  for (let depth = 0; depth < maxDepth; depth++) {
6529
- if (existsSync29(join27(dir, filename))) {
6712
+ if (existsSync30(join28(dir, filename))) {
6530
6713
  return dir;
6531
6714
  }
6532
- const parent = join27(dir, "..");
6715
+ const parent = join28(dir, "..");
6533
6716
  if (parent === dir) {
6534
6717
  break;
6535
6718
  }
@@ -6539,17 +6722,17 @@ function findUp(cwd, filename, maxDepth = 6) {
6539
6722
  }
6540
6723
  function findSopsConfig(cwd) {
6541
6724
  const dir = findUp(cwd, ".sops.yaml");
6542
- return dir ? join27(dir, ".sops.yaml") : null;
6725
+ return dir ? join28(dir, ".sops.yaml") : null;
6543
6726
  }
6544
6727
  function hasSopsConfig(cwd) {
6545
6728
  return findSopsConfig(cwd) !== null;
6546
6729
  }
6547
6730
  function listSopsFiles(cwd) {
6548
- const dir = join27(cwd, SECRETS_DIR);
6549
- if (!existsSync29(dir)) {
6731
+ const dir = join28(cwd, SECRETS_DIR);
6732
+ if (!existsSync30(dir)) {
6550
6733
  return [];
6551
6734
  }
6552
- return readdirSync2(dir).filter((name) => name.endsWith(".enc.json")).map((name) => join27(dir, name));
6735
+ return readdirSync2(dir).filter((name) => name.endsWith(".enc.json")).map((name) => join28(dir, name));
6553
6736
  }
6554
6737
 
6555
6738
  // src/commands/secret/store-value.ts
@@ -6578,7 +6761,7 @@ async function storeSecret(cwd, env9, key, value) {
6578
6761
  );
6579
6762
  }
6580
6763
  await store.set(keychainName(key), value);
6581
- const serverEnvPath = join28(cwd, ".env.server");
6764
+ const serverEnvPath = join29(cwd, ".env.server");
6582
6765
  const result = upsertEnvVar(serverEnvPath, key, keychainRef(key));
6583
6766
  restrictEnvFilePerms(serverEnvPath);
6584
6767
  ensureGitignored(cwd, [{ pattern: ".env.server", comment: "spfn server env (secrets)" }]);
@@ -6816,12 +6999,12 @@ function requireEntry(schema, key) {
6816
6999
  // src/commands/secret/keygen.ts
6817
7000
  init_logger();
6818
7001
  import { execa as execa12 } from "execa";
6819
- import { existsSync as existsSync30, mkdirSync as mkdirSync6 } from "fs";
7002
+ import { existsSync as existsSync31, mkdirSync as mkdirSync6 } from "fs";
6820
7003
  import { homedir } from "os";
6821
- import { dirname as dirname6, join as join29 } from "path";
7004
+ import { dirname as dirname6, join as join30 } from "path";
6822
7005
  import chalk41 from "chalk";
6823
7006
  function ageKeyFile() {
6824
- return process.env.SOPS_AGE_KEY_FILE ?? join29(homedir(), ".config", "sops", "age", "keys.txt");
7007
+ return process.env.SOPS_AGE_KEY_FILE ?? join30(homedir(), ".config", "sops", "age", "keys.txt");
6825
7008
  }
6826
7009
  async function ensureAgeInstalled() {
6827
7010
  try {
@@ -6841,7 +7024,7 @@ async function secretKeygen() {
6841
7024
  process.exit(1);
6842
7025
  }
6843
7026
  const keyFile = ageKeyFile();
6844
- if (existsSync30(keyFile)) {
7027
+ if (existsSync31(keyFile)) {
6845
7028
  const { stdout } = await execa12("age-keygen", ["-y", keyFile]);
6846
7029
  logger.warn(`age key file already exists: ${keyFile}`);
6847
7030
  printPublicKeys(publicKeys(stdout));
@@ -6868,8 +7051,8 @@ function printPublicKeys(keys) {
6868
7051
 
6869
7052
  // src/commands/secret/recipients.ts
6870
7053
  init_logger();
6871
- import { existsSync as existsSync31, readFileSync as readFileSync14, writeFileSync as writeFileSync19 } from "fs";
6872
- import { join as join30 } from "path";
7054
+ import { existsSync as existsSync32, readFileSync as readFileSync15, writeFileSync as writeFileSync20 } from "fs";
7055
+ import { join as join31 } from "path";
6873
7056
  import { parse as parse3, stringify } from "yaml";
6874
7057
  import chalk42 from "chalk";
6875
7058
  var SOPS_CONFIG = ".sops.yaml";
@@ -6877,7 +7060,7 @@ var DEFAULT_PATH_REGEX = "secrets/.*\\.enc\\.json$";
6877
7060
  var AGE_RECIPIENT = /^age1[0-9a-z]+$/;
6878
7061
  async function secretRecipients(action, key, _options) {
6879
7062
  const cwd = process.cwd();
6880
- const configPath = join30(cwd, SOPS_CONFIG);
7063
+ const configPath = join31(cwd, SOPS_CONFIG);
6881
7064
  if (action === "list") {
6882
7065
  listRecipients(configPath);
6883
7066
  return;
@@ -6904,12 +7087,12 @@ async function secretRecipients(action, key, _options) {
6904
7087
  logger.warn("Removing a recipient does not revoke values they already decrypted \u2014 rotate those values.");
6905
7088
  }
6906
7089
  rule.age = [...recipients].join(",");
6907
- writeFileSync19(configPath, stringify(config));
7090
+ writeFileSync20(configPath, stringify(config));
6908
7091
  logger.success(`${action === "add" ? "Added" : "Removed"} recipient; updated ${SOPS_CONFIG}.`);
6909
7092
  await reencrypt(cwd);
6910
7093
  }
6911
7094
  function listRecipients(configPath) {
6912
- if (!existsSync31(configPath)) {
7095
+ if (!existsSync32(configPath)) {
6913
7096
  logger.info(`No ${SOPS_CONFIG} found.`);
6914
7097
  return;
6915
7098
  }
@@ -6927,10 +7110,10 @@ function listRecipients(configPath) {
6927
7110
  console.log();
6928
7111
  }
6929
7112
  function loadConfig(configPath) {
6930
- if (!existsSync31(configPath)) {
7113
+ if (!existsSync32(configPath)) {
6931
7114
  return { creation_rules: [] };
6932
7115
  }
6933
- return parse3(readFileSync14(configPath, "utf-8")) ?? { creation_rules: [] };
7116
+ return parse3(readFileSync15(configPath, "utf-8")) ?? { creation_rules: [] };
6934
7117
  }
6935
7118
  function ensureRule(config) {
6936
7119
  if (!config.creation_rules) {
@@ -6962,7 +7145,7 @@ async function reencrypt(cwd) {
6962
7145
 
6963
7146
  // src/commands/secret/check.ts
6964
7147
  init_logger();
6965
- import { join as join31 } from "path";
7148
+ import { join as join32 } from "path";
6966
7149
  import chalk43 from "chalk";
6967
7150
  init_env_file();
6968
7151
  var COMMITTED_FILES = [".env", ".env.example"];
@@ -6981,14 +7164,14 @@ async function secretCheck(options) {
6981
7164
  const issues = [];
6982
7165
  const warnings = [];
6983
7166
  for (const file of COMMITTED_FILES) {
6984
- const parsed = parseEnvFile(join31(cwd, file));
7167
+ const parsed = parseEnvFile(join32(cwd, file));
6985
7168
  for (const [key, value] of Object.entries(parsed)) {
6986
7169
  if (secretKeys.has(key) && value.length > 0 && !PLACEHOLDER.test(value)) {
6987
7170
  issues.push(`${chalk43.cyan(key)} has a real value in committed ${chalk43.yellow(file)} \u2014 move it to the keychain/SOPS.`);
6988
7171
  }
6989
7172
  }
6990
7173
  }
6991
- const serverEnv = parseEnvFile(join31(cwd, ".env.server"));
7174
+ const serverEnv = parseEnvFile(join32(cwd, ".env.server"));
6992
7175
  for (const key of secretKeys) {
6993
7176
  const value = serverEnv[key];
6994
7177
  if (value && !value.startsWith(KEYCHAIN_REF_PREFIX)) {
@@ -7074,20 +7257,20 @@ async function deleteCloudToken(provider) {
7074
7257
 
7075
7258
  // src/utils/cloud/config.ts
7076
7259
  init_env_file();
7077
- import { existsSync as existsSync32, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync20 } from "fs";
7078
- import { dirname as dirname7, join as join32 } from "path";
7079
- var CONFIG_REL_PATH = join32(".spfn", "cloud.json");
7260
+ import { existsSync as existsSync33, mkdirSync as mkdirSync7, readFileSync as readFileSync16, writeFileSync as writeFileSync21 } from "fs";
7261
+ import { dirname as dirname7, join as join33 } from "path";
7262
+ var CONFIG_REL_PATH = join33(".spfn", "cloud.json");
7080
7263
  function cloudConfigPath(cwd) {
7081
- return join32(cwd, CONFIG_REL_PATH);
7264
+ return join33(cwd, CONFIG_REL_PATH);
7082
7265
  }
7083
7266
  function readCloudConfig(cwd) {
7084
7267
  const path5 = cloudConfigPath(cwd);
7085
- if (!existsSync32(path5)) {
7268
+ if (!existsSync33(path5)) {
7086
7269
  return {};
7087
7270
  }
7088
7271
  let parsed;
7089
7272
  try {
7090
- parsed = JSON.parse(readFileSync15(path5, "utf-8"));
7273
+ parsed = JSON.parse(readFileSync16(path5, "utf-8"));
7091
7274
  } catch {
7092
7275
  throw new Error(`${path5} is not valid JSON \u2014 delete it and run \`spfn cloud link\` again.`);
7093
7276
  }
@@ -7099,7 +7282,7 @@ function readCloudConfig(cwd) {
7099
7282
  function writeCloudConfig(cwd, config) {
7100
7283
  const path5 = cloudConfigPath(cwd);
7101
7284
  mkdirSync7(dirname7(path5), { recursive: true });
7102
- writeFileSync20(path5, JSON.stringify(config, null, 4) + "\n", "utf-8");
7285
+ writeFileSync21(path5, JSON.stringify(config, null, 4) + "\n", "utf-8");
7103
7286
  ensureGitignored(cwd, [{ pattern: ".spfn/cloud.json", comment: "spfn cloud link state (per-user accounts)" }]);
7104
7287
  }
7105
7288
  function requireLinked(config, provider) {
@@ -7740,8 +7923,8 @@ function printMigrationPrompt(nearLimit) {
7740
7923
 
7741
7924
  // src/commands/cloud/keepalive.ts
7742
7925
  init_logger();
7743
- import { existsSync as existsSync33, mkdirSync as mkdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync21 } from "fs";
7744
- import { dirname as dirname8, join as join33 } from "path";
7926
+ import { existsSync as existsSync34, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync22 } from "fs";
7927
+ import { dirname as dirname8, join as join34 } from "path";
7745
7928
  import chalk49 from "chalk";
7746
7929
  var DEFAULT_HEALTH_PATH = "/api/backend/_core/health?detailed=true";
7747
7930
  var DEFAULT_SCHEDULE = "0 3 * * *";
@@ -7767,12 +7950,12 @@ async function cloudKeepalive(options) {
7767
7950
  logger.info("The DB ping needs detailed health checks: keep `healthCheck: { detailed: true }` in your server config.");
7768
7951
  }
7769
7952
  function setupVercelCron(cwd, healthPath) {
7770
- const vercelJsonPath = join33(cwd, "vercel.json");
7953
+ const vercelJsonPath = join34(cwd, "vercel.json");
7771
7954
  let vercelJson = {};
7772
- if (existsSync33(vercelJsonPath)) {
7955
+ if (existsSync34(vercelJsonPath)) {
7773
7956
  let parsed;
7774
7957
  try {
7775
- parsed = JSON.parse(readFileSync16(vercelJsonPath, "utf-8"));
7958
+ parsed = JSON.parse(readFileSync17(vercelJsonPath, "utf-8"));
7776
7959
  } catch {
7777
7960
  logger.error("vercel.json is not valid JSON (comments and trailing commas are not allowed) \u2014 fix it and re-run.");
7778
7961
  process.exit(1);
@@ -7793,7 +7976,7 @@ function setupVercelCron(cwd, healthPath) {
7793
7976
  logger.info(`Point the existing cron at ${chalk49.cyan(healthPath)} yourself, or use \`--github-actions --url <deployed-url>\`.`);
7794
7977
  process.exit(1);
7795
7978
  }
7796
- writeFileSync21(vercelJsonPath, JSON.stringify(vercelJson, null, 4) + "\n", "utf-8");
7979
+ writeFileSync22(vercelJsonPath, JSON.stringify(vercelJson, null, 4) + "\n", "utf-8");
7797
7980
  logger.success(`vercel.json: daily cron added (${DEFAULT_SCHEDULE} UTC \u2192 ${healthPath}). Deploy to activate.`);
7798
7981
  warnIfBackendRouteMissing(cwd);
7799
7982
  }
@@ -7813,8 +7996,8 @@ function setupGithubActions(cwd, healthPath, url) {
7813
7996
  logger.error("`--github-actions` needs `--url <deployed-url>` \u2014 the workflow runs outside your app and must know where it lives.");
7814
7997
  process.exit(1);
7815
7998
  }
7816
- const workflowPath = join33(cwd, ".github", "workflows", "spfn-keepalive.yml");
7817
- if (existsSync33(workflowPath)) {
7999
+ const workflowPath = join34(cwd, ".github", "workflows", "spfn-keepalive.yml");
8000
+ if (existsSync34(workflowPath)) {
7818
8001
  logger.success(`${workflowPath} already exists \u2014 nothing to do.`);
7819
8002
  return;
7820
8003
  }
@@ -7824,7 +8007,7 @@ function setupGithubActions(cwd, healthPath, url) {
7824
8007
  process.exit(1);
7825
8008
  }
7826
8009
  mkdirSync8(dirname8(workflowPath), { recursive: true });
7827
- writeFileSync21(workflowPath, githubWorkflow(new URL(healthPath, base).toString()), "utf-8");
8010
+ writeFileSync22(workflowPath, githubWorkflow(new URL(healthPath, base).toString()), "utf-8");
7828
8011
  logger.success(".github/workflows/spfn-keepalive.yml: daily keep-alive workflow added. Commit and push to activate.");
7829
8012
  }
7830
8013
  function normalizeDeployUrl(url) {
@@ -7861,8 +8044,8 @@ jobs:
7861
8044
  `;
7862
8045
  }
7863
8046
  function warnIfBackendRouteMissing(cwd) {
7864
- const routePath = join33(cwd, "src", "app", "api", "backend", "[[...route]]", "route.ts");
7865
- if (!existsSync33(routePath)) {
8047
+ const routePath = join34(cwd, "src", "app", "api", "backend", "[[...route]]", "route.ts");
8048
+ if (!existsSync34(routePath)) {
7866
8049
  logger.warn("src/app/api/backend/[[...route]]/route.ts not found \u2014 the cron path answers only after `spfn add vercel`.");
7867
8050
  }
7868
8051
  }
@@ -7870,7 +8053,7 @@ function warnIfBackendRouteMissing(cwd) {
7870
8053
  // src/commands/cloud/env.ts
7871
8054
  init_logger();
7872
8055
  init_env_file();
7873
- import { join as join34 } from "path";
8056
+ import { join as join35 } from "path";
7874
8057
  import prompts13 from "prompts";
7875
8058
  import chalk50 from "chalk";
7876
8059
  async function cloudEnvPull(options) {
@@ -7891,7 +8074,7 @@ async function cloudEnvPull(options) {
7891
8074
  logger.info("Values were written to files/keychain only \u2014 none were displayed.");
7892
8075
  }
7893
8076
  function writePublicValues(cwd, projectRef2, keys) {
7894
- const envLocalPath = join34(cwd, ".env.local");
8077
+ const envLocalPath = join35(cwd, ".env.local");
7895
8078
  ensureGitignored(cwd, [{ pattern: ".env.local", comment: "local env (per-machine values)" }]);
7896
8079
  upsertEnvVar(envLocalPath, "NEXT_PUBLIC_SUPABASE_URL", `https://${projectRef2}.supabase.co`);
7897
8080
  logger.success("NEXT_PUBLIC_SUPABASE_URL \u2192 .env.local");
@@ -7985,8 +8168,8 @@ async function cloudEnvPush(keys) {
7985
8168
  }
7986
8169
  }
7987
8170
  async function resolveLocalValues(cwd, keys) {
7988
- const publicEnv = { ...parseEnvFile(join34(cwd, ".env")), ...parseEnvFile(join34(cwd, ".env.local")) };
7989
- const serverEnv = parseEnvFile(join34(cwd, ".env.server"));
8171
+ const publicEnv = { ...parseEnvFile(join35(cwd, ".env")), ...parseEnvFile(join35(cwd, ".env.local")) };
8172
+ const serverEnv = parseEnvFile(join35(cwd, ".env.server"));
7990
8173
  const keychain = await resolveKeychainEnv(cwd);
7991
8174
  const vars = [];
7992
8175
  const missing = [];
@@ -8142,8 +8325,8 @@ async function resolveKitAdapters(request2) {
8142
8325
  // src/kit/operations/install.ts
8143
8326
  import { createHash as createHash2 } from "crypto";
8144
8327
  import { hostname as hostname2, tmpdir } from "os";
8145
- import { mkdtempSync, existsSync as existsSync45 } from "fs";
8146
- import { join as join44 } from "path";
8328
+ import { mkdtempSync, existsSync as existsSync46 } from "fs";
8329
+ import { join as join45 } from "path";
8147
8330
 
8148
8331
  // src/kit/events.ts
8149
8332
  import chalk51 from "chalk";
@@ -8220,8 +8403,8 @@ function nextLine(event) {
8220
8403
  }
8221
8404
 
8222
8405
  // src/kit/journal.ts
8223
- import { mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as readFileSync17, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync23, existsSync as existsSync35, statSync } from "fs";
8224
- import { dirname as dirname9, join as join36 } from "path";
8406
+ import { mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as readFileSync18, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync24, existsSync as existsSync36, statSync } from "fs";
8407
+ import { dirname as dirname9, join as join37 } from "path";
8225
8408
 
8226
8409
  // src/kit/digest.ts
8227
8410
  import { createHash } from "crypto";
@@ -8262,8 +8445,8 @@ function digestOfJson(value) {
8262
8445
  }
8263
8446
 
8264
8447
  // src/kit/paths.ts
8265
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync22, existsSync as existsSync34 } from "fs";
8266
- import { join as join35 } from "path";
8448
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync23, existsSync as existsSync35 } from "fs";
8449
+ import { join as join36 } from "path";
8267
8450
  var KIT_STATE_DIR = ".spfn";
8268
8451
  var OPERATIONS_IGNORE = [
8269
8452
  "# Written by `spfn kit`. One machine's run is not part of the project.",
@@ -8271,27 +8454,27 @@ var OPERATIONS_IGNORE = [
8271
8454
  ""
8272
8455
  ].join("\n");
8273
8456
  function kitPaths(root) {
8274
- const stateDir = join35(root, KIT_STATE_DIR);
8275
- const operationsDir = join35(stateDir, "operations");
8276
- const lockDir = join35(operationsDir, "operation.lock");
8457
+ const stateDir = join36(root, KIT_STATE_DIR);
8458
+ const operationsDir = join36(stateDir, "operations");
8459
+ const lockDir = join36(operationsDir, "operation.lock");
8277
8460
  return {
8278
8461
  root,
8279
8462
  stateDir,
8280
- licenseFile: join35(stateDir, "license.json"),
8281
- lockFile: join35(stateDir, "kit-lock.json"),
8463
+ licenseFile: join36(stateDir, "license.json"),
8464
+ lockFile: join36(stateDir, "kit-lock.json"),
8282
8465
  operationsDir,
8283
- activeJournal: join35(operationsDir, "active.json"),
8284
- historyDir: join35(operationsDir, "history"),
8466
+ activeJournal: join36(operationsDir, "active.json"),
8467
+ historyDir: join36(operationsDir, "history"),
8285
8468
  lockDir,
8286
- lockOwnerFile: join35(lockDir, "owner.json")
8469
+ lockOwnerFile: join36(lockDir, "owner.json")
8287
8470
  };
8288
8471
  }
8289
8472
  function ensureOperationsDir(root) {
8290
8473
  const paths = kitPaths(root);
8291
- const ignoreFile = join35(paths.stateDir, ".gitignore");
8474
+ const ignoreFile = join36(paths.stateDir, ".gitignore");
8292
8475
  mkdirSync9(paths.stateDir, { recursive: true });
8293
- if (!existsSync34(ignoreFile)) {
8294
- writeFileSync22(ignoreFile, OPERATIONS_IGNORE, "utf8");
8476
+ if (!existsSync35(ignoreFile)) {
8477
+ writeFileSync23(ignoreFile, OPERATIONS_IGNORE, "utf8");
8295
8478
  }
8296
8479
  mkdirSync9(paths.operationsDir, { recursive: true });
8297
8480
  return paths.operationsDir;
@@ -8578,14 +8761,14 @@ var JournalStore = class {
8578
8761
  return readJournalFile(this.paths.activeJournal);
8579
8762
  }
8580
8763
  readHistory(operationId) {
8581
- return readJournalFile(join36(this.paths.historyDir, `${operationId}.json`));
8764
+ return readJournalFile(join37(this.paths.historyDir, `${operationId}.json`));
8582
8765
  }
8583
8766
  /** Every journal this project still has, newest update first. */
8584
8767
  listHistory() {
8585
- if (!existsSync35(this.paths.historyDir)) {
8768
+ if (!existsSync36(this.paths.historyDir)) {
8586
8769
  return [];
8587
8770
  }
8588
- return readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) => readJournalFile(join36(this.paths.historyDir, name))).filter((journal) => journal !== null).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
8771
+ return readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) => readJournalFile(join37(this.paths.historyDir, name))).filter((journal) => journal !== null).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
8589
8772
  }
8590
8773
  create(init) {
8591
8774
  const timestamp = this.now();
@@ -8644,15 +8827,15 @@ var JournalStore = class {
8644
8827
  }
8645
8828
  /** Move a finished operation into history and clear the active slot. */
8646
8829
  archive(journal) {
8647
- writeJsonAtomically(join36(this.paths.historyDir, `${journal.operationId}.json`), journal);
8830
+ writeJsonAtomically(join37(this.paths.historyDir, `${journal.operationId}.json`), journal);
8648
8831
  rmSync2(this.paths.activeJournal, { force: true });
8649
8832
  this.pruneHistory();
8650
8833
  }
8651
8834
  pruneHistory() {
8652
- if (!existsSync35(this.paths.historyDir)) {
8835
+ if (!existsSync36(this.paths.historyDir)) {
8653
8836
  return;
8654
8837
  }
8655
- const files = readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) => join36(this.paths.historyDir, name)).sort((left, right) => statSync(right).mtimeMs - statSync(left).mtimeMs);
8838
+ const files = readdirSync3(this.paths.historyDir).filter((name) => name.endsWith(".json")).map((name) => join37(this.paths.historyDir, name)).sort((left, right) => statSync(right).mtimeMs - statSync(left).mtimeMs);
8656
8839
  for (const file of files.slice(this.historyLimit)) {
8657
8840
  rmSync2(file, { force: true });
8658
8841
  }
@@ -8674,11 +8857,11 @@ function upsertCheckpoint(checkpoints, entry) {
8674
8857
  return next;
8675
8858
  }
8676
8859
  function readJournalFile(file) {
8677
- if (!existsSync35(file)) {
8860
+ if (!existsSync36(file)) {
8678
8861
  return null;
8679
8862
  }
8680
8863
  try {
8681
- const parsed = JSON.parse(readFileSync17(file, "utf8"));
8864
+ const parsed = JSON.parse(readFileSync18(file, "utf8"));
8682
8865
  return validateOperationJournal(parsed).valid ? parsed : null;
8683
8866
  } catch {
8684
8867
  return null;
@@ -8687,13 +8870,13 @@ function readJournalFile(file) {
8687
8870
  function writeJsonAtomically(file, value) {
8688
8871
  mkdirSync10(dirname9(file), { recursive: true });
8689
8872
  const temporary = `${file}.tmp`;
8690
- writeFileSync23(temporary, `${JSON.stringify(value, null, 4)}
8873
+ writeFileSync24(temporary, `${JSON.stringify(value, null, 4)}
8691
8874
  `, { encoding: "utf8", mode: 384 });
8692
8875
  renameSync2(temporary, file);
8693
8876
  }
8694
8877
 
8695
8878
  // src/kit/lock.ts
8696
- import { mkdirSync as mkdirSync11, readFileSync as readFileSync18, rmSync as rmSync3, writeFileSync as writeFileSync24, existsSync as existsSync36 } from "fs";
8879
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync19, rmSync as rmSync3, writeFileSync as writeFileSync25, existsSync as existsSync37 } from "fs";
8697
8880
  import { hostname } from "os";
8698
8881
  function defaultIsProcessAlive(pid) {
8699
8882
  try {
@@ -8729,11 +8912,11 @@ function acquireOperationLock(options) {
8729
8912
  }
8730
8913
  function readLockOwner(root) {
8731
8914
  const paths = kitPaths(root);
8732
- if (!existsSync36(paths.lockOwnerFile)) {
8915
+ if (!existsSync37(paths.lockOwnerFile)) {
8733
8916
  return null;
8734
8917
  }
8735
8918
  try {
8736
- const parsed = JSON.parse(readFileSync18(paths.lockOwnerFile, "utf8"));
8919
+ const parsed = JSON.parse(readFileSync19(paths.lockOwnerFile, "utf8"));
8737
8920
  return typeof parsed?.pid === "number" && typeof parsed?.operationId === "string" ? parsed : null;
8738
8921
  } catch {
8739
8922
  return null;
@@ -8802,7 +8985,7 @@ function tryCreateLockDir(paths) {
8802
8985
  }
8803
8986
  }
8804
8987
  function writeOwner(paths, owner) {
8805
- writeFileSync24(paths.lockOwnerFile, `${JSON.stringify(owner, null, 4)}
8988
+ writeFileSync25(paths.lockOwnerFile, `${JSON.stringify(owner, null, 4)}
8806
8989
  `, "utf8");
8807
8990
  }
8808
8991
  function handle(paths, owner, reclaimed) {
@@ -8816,18 +8999,18 @@ function handle(paths, owner, reclaimed) {
8816
8999
  }
8817
9000
 
8818
9001
  // src/kit/operation-context.ts
8819
- import { mkdirSync as mkdirSync12, readFileSync as readFileSync19, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync25, existsSync as existsSync37 } from "fs";
8820
- import { dirname as dirname10, join as join37 } from "path";
9002
+ import { mkdirSync as mkdirSync12, readFileSync as readFileSync20, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync26, existsSync as existsSync38 } from "fs";
9003
+ import { dirname as dirname10, join as join38 } from "path";
8821
9004
  function contextFile(root) {
8822
- return join37(kitPaths(root).operationsDir, "context.json");
9005
+ return join38(kitPaths(root).operationsDir, "context.json");
8823
9006
  }
8824
9007
  function readOperationContext(root) {
8825
9008
  const file = contextFile(root);
8826
- if (!existsSync37(file)) {
9009
+ if (!existsSync38(file)) {
8827
9010
  return null;
8828
9011
  }
8829
9012
  try {
8830
- const parsed = JSON.parse(readFileSync19(file, "utf8"));
9013
+ const parsed = JSON.parse(readFileSync20(file, "utf8"));
8831
9014
  return parsed?.schemaVersion === 1 && typeof parsed.operationId === "string" ? parsed : null;
8832
9015
  } catch {
8833
9016
  return null;
@@ -8837,7 +9020,7 @@ function writeOperationContext(root, context) {
8837
9020
  const file = contextFile(root);
8838
9021
  mkdirSync12(dirname10(file), { recursive: true });
8839
9022
  const temporary = `${file}.tmp`;
8840
- writeFileSync25(temporary, `${JSON.stringify(context, null, 4)}
9023
+ writeFileSync26(temporary, `${JSON.stringify(context, null, 4)}
8841
9024
  `, "utf8");
8842
9025
  renameSync3(temporary, file);
8843
9026
  }
@@ -9472,8 +9655,8 @@ var KeychainKitCredentialStore = class {
9472
9655
  };
9473
9656
 
9474
9657
  // src/kit/tooling.ts
9475
- import { cpSync, mkdirSync as mkdirSync13, readdirSync as readdirSync4, readFileSync as readFileSync20, rmSync as rmSync5, statSync as statSync2, existsSync as existsSync38 } from "fs";
9476
- import { join as join38, relative as relative2, sep as sep3 } from "path";
9658
+ import { cpSync, mkdirSync as mkdirSync13, readdirSync as readdirSync4, readFileSync as readFileSync21, rmSync as rmSync5, statSync as statSync2, existsSync as existsSync39 } from "fs";
9659
+ import { join as join39, relative as relative2, sep as sep3 } from "path";
9477
9660
 
9478
9661
  // src/kit/manifest.ts
9479
9662
  var DEFAULT_AGENT_PACK_ROOT = ".spfn/agent-pack";
@@ -9784,7 +9967,7 @@ function snapshotTree(root, ignore = ["node_modules", ".git"]) {
9784
9967
  if (ignore.includes(entry.name)) {
9785
9968
  continue;
9786
9969
  }
9787
- const absolute = join38(directory, entry.name);
9970
+ const absolute = join39(directory, entry.name);
9788
9971
  if (entry.isDirectory()) {
9789
9972
  walk(absolute);
9790
9973
  continue;
@@ -9794,11 +9977,11 @@ function snapshotTree(root, ignore = ["node_modules", ".git"]) {
9794
9977
  }
9795
9978
  files.set(
9796
9979
  relative2(root, absolute).split(sep3).join("/"),
9797
- sha256Digest(readFileSync20(absolute))
9980
+ sha256Digest(readFileSync21(absolute))
9798
9981
  );
9799
9982
  }
9800
9983
  };
9801
- if (existsSync38(root) && statSync2(root).isDirectory()) {
9984
+ if (existsSync39(root) && statSync2(root).isDirectory()) {
9802
9985
  walk(root);
9803
9986
  }
9804
9987
  return { files };
@@ -9855,22 +10038,22 @@ function assertWritesWithinAllowlist(diff, allowlist, context) {
9855
10038
  }
9856
10039
 
9857
10040
  // src/kit/agent-pack.ts
9858
- import { existsSync as existsSync39, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync26 } from "fs";
9859
- import { dirname as dirname11, join as join39 } from "path";
10041
+ import { existsSync as existsSync40, mkdirSync as mkdirSync14, readFileSync as readFileSync22, writeFileSync as writeFileSync27 } from "fs";
10042
+ import { dirname as dirname11, join as join40 } from "path";
9860
10043
  var AGENT_PACK_RECORD_PATH = ".spfn/agent-pack.json";
9861
10044
  function writeAgentPackRecord(projectDir2, record) {
9862
- const file = join39(projectDir2, AGENT_PACK_RECORD_PATH);
10045
+ const file = join40(projectDir2, AGENT_PACK_RECORD_PATH);
9863
10046
  mkdirSync14(dirname11(file), { recursive: true });
9864
- writeFileSync26(file, `${JSON.stringify(record, null, 4)}
10047
+ writeFileSync27(file, `${JSON.stringify(record, null, 4)}
9865
10048
  `, "utf8");
9866
10049
  }
9867
10050
  function readAgentPackRecord(projectDir2) {
9868
- const file = join39(projectDir2, AGENT_PACK_RECORD_PATH);
9869
- if (!existsSync39(file)) {
10051
+ const file = join40(projectDir2, AGENT_PACK_RECORD_PATH);
10052
+ if (!existsSync40(file)) {
9870
10053
  return null;
9871
10054
  }
9872
10055
  try {
9873
- const parsed = JSON.parse(readFileSync21(file, "utf8"));
10056
+ const parsed = JSON.parse(readFileSync22(file, "utf8"));
9874
10057
  return parsed.schemaVersion === 1 && typeof parsed.files === "object" && parsed.files !== null ? parsed : null;
9875
10058
  } catch {
9876
10059
  return null;
@@ -9878,7 +10061,7 @@ function readAgentPackRecord(projectDir2) {
9878
10061
  }
9879
10062
 
9880
10063
  // src/kit/installed-state.ts
9881
- import { mkdirSync as mkdirSync15, readFileSync as readFileSync22, renameSync as renameSync4, writeFileSync as writeFileSync27, existsSync as existsSync40 } from "fs";
10064
+ import { mkdirSync as mkdirSync15, readFileSync as readFileSync23, renameSync as renameSync4, writeFileSync as writeFileSync28, existsSync as existsSync41 } from "fs";
9882
10065
  import { dirname as dirname12 } from "path";
9883
10066
  function readLicenseFile(file) {
9884
10067
  const parsed = readJson(file);
@@ -9921,7 +10104,7 @@ function requireInstalledLock(file) {
9921
10104
  const lock = readInstalledLock(file);
9922
10105
  if (lock === null) {
9923
10106
  throw new KitError("KIT_LOCK_INVALID", "This project has no readable .spfn/kit-lock.json.", {
9924
- evidence: { file, exists: existsSync40(file) },
10107
+ evidence: { file, exists: existsSync41(file) },
9925
10108
  next: { command: "spfn kit recover --json", requiresHumanApproval: false }
9926
10109
  });
9927
10110
  }
@@ -9956,11 +10139,11 @@ function lockFromManifest(manifest, context) {
9956
10139
  };
9957
10140
  }
9958
10141
  function readJson(file) {
9959
- if (!existsSync40(file)) {
10142
+ if (!existsSync41(file)) {
9960
10143
  return null;
9961
10144
  }
9962
10145
  try {
9963
- return JSON.parse(readFileSync22(file, "utf8"));
10146
+ return JSON.parse(readFileSync23(file, "utf8"));
9964
10147
  } catch {
9965
10148
  return null;
9966
10149
  }
@@ -9968,17 +10151,17 @@ function readJson(file) {
9968
10151
  function writeJsonAtomically2(file, value) {
9969
10152
  mkdirSync15(dirname12(file), { recursive: true });
9970
10153
  const temporary = `${file}.tmp`;
9971
- writeFileSync27(temporary, `${JSON.stringify(value, null, 4)}
10154
+ writeFileSync28(temporary, `${JSON.stringify(value, null, 4)}
9972
10155
  `, "utf8");
9973
10156
  renameSync4(temporary, file);
9974
10157
  }
9975
10158
 
9976
10159
  // src/kit/drift.ts
9977
- import { readFileSync as readFileSync23, existsSync as existsSync41 } from "fs";
9978
- import { join as join40 } from "path";
10160
+ import { readFileSync as readFileSync24, existsSync as existsSync42 } from "fs";
10161
+ import { join as join41 } from "path";
9979
10162
  function fileDigest(root, relativePath) {
9980
- const file = join40(root, relativePath);
9981
- return existsSync41(file) ? sha256Digest(readFileSync23(file)) : null;
10163
+ const file = join41(root, relativePath);
10164
+ return existsSync42(file) ? sha256Digest(readFileSync24(file)) : null;
9982
10165
  }
9983
10166
  function agentPackTargets(root, lock) {
9984
10167
  if (lock.agentPack.root === void 0) {
@@ -10009,12 +10192,12 @@ function managedDigests(root, lock) {
10009
10192
  }
10010
10193
 
10011
10194
  // src/kit/operations/shared.ts
10012
- import { mkdirSync as mkdirSync17, readdirSync as readdirSync5, readFileSync as readFileSync26, writeFileSync as writeFileSync30, existsSync as existsSync44 } from "fs";
10013
- import { dirname as dirname14, join as join43 } from "path";
10195
+ import { mkdirSync as mkdirSync17, readdirSync as readdirSync5, readFileSync as readFileSync27, writeFileSync as writeFileSync31, existsSync as existsSync45 } from "fs";
10196
+ import { dirname as dirname14, join as join44 } from "path";
10014
10197
 
10015
10198
  // src/kit/expand.ts
10016
- import { mkdirSync as mkdirSync16, existsSync as existsSync42, readFileSync as readFileSync24, writeFileSync as writeFileSync28 } from "fs";
10017
- import { dirname as dirname13, join as join41 } from "path";
10199
+ import { mkdirSync as mkdirSync16, existsSync as existsSync43, readFileSync as readFileSync25, writeFileSync as writeFileSync29 } from "fs";
10200
+ import { dirname as dirname13, join as join42 } from "path";
10018
10201
 
10019
10202
  // src/kit/tar.ts
10020
10203
  var BLOCK = 512;
@@ -10116,26 +10299,26 @@ function expandArchive(bytes, request2) {
10116
10299
  let matched = 0;
10117
10300
  for (const entry of entries) {
10118
10301
  const relative3 = request2.root === void 0 || request2.root.length === 0 ? entry.path : `${request2.root.replace(/\/+$/, "")}/${entry.path}`;
10119
- const destination = join41(request2.targetDir, relative3);
10302
+ const destination = join42(request2.targetDir, relative3);
10120
10303
  if (entry.kind === "directory") {
10121
10304
  mkdirSync16(destination, { recursive: true });
10122
10305
  continue;
10123
10306
  }
10124
10307
  const digest = sha256Digest(entry.bytes);
10125
10308
  files[relative3] = digest;
10126
- if (existsSync42(destination) && request2.existing !== "replace") {
10309
+ if (existsSync43(destination) && request2.existing !== "replace") {
10127
10310
  assertSameBytes(destination, relative3, digest);
10128
10311
  matched += 1;
10129
10312
  continue;
10130
10313
  }
10131
10314
  mkdirSync16(dirname13(destination), { recursive: true });
10132
- writeFileSync28(destination, entry.bytes, { mode: entry.mode === 0 ? 420 : entry.mode });
10315
+ writeFileSync29(destination, entry.bytes, { mode: entry.mode === 0 ? 420 : entry.mode });
10133
10316
  written += 1;
10134
10317
  }
10135
10318
  return { files, written, matched };
10136
10319
  }
10137
10320
  function assertSameBytes(destination, relative3, expected) {
10138
- const actual = sha256Digest(readFileSync24(destination));
10321
+ const actual = sha256Digest(readFileSync25(destination));
10139
10322
  if (actual === expected) {
10140
10323
  return;
10141
10324
  }
@@ -10243,15 +10426,15 @@ function registryNpmrc(scopes, registryUrl) {
10243
10426
  }
10244
10427
 
10245
10428
  // src/kit/package-graph.ts
10246
- import { existsSync as existsSync43, readFileSync as readFileSync25, writeFileSync as writeFileSync29 } from "fs";
10247
- import { join as join42 } from "path";
10429
+ import { existsSync as existsSync44, readFileSync as readFileSync26, writeFileSync as writeFileSync30 } from "fs";
10430
+ import { join as join43 } from "path";
10248
10431
  var DEPENDENCY_BLOCKS = ["dependencies", "devDependencies", "optionalDependencies"];
10249
10432
  function applyManifestVersions(projectDir2, manifest) {
10250
- const file = join42(projectDir2, "package.json");
10251
- if (!existsSync43(file)) {
10433
+ const file = join43(projectDir2, "package.json");
10434
+ if (!existsSync44(file)) {
10252
10435
  return [];
10253
10436
  }
10254
- const raw = readFileSync25(file, "utf8");
10437
+ const raw = readFileSync26(file, "utf8");
10255
10438
  const document = JSON.parse(raw);
10256
10439
  const wanted = new Map(manifest.packages.map((entry) => [entry.name, entry.version]));
10257
10440
  const changes = [];
@@ -10270,7 +10453,7 @@ function applyManifestVersions(projectDir2, manifest) {
10270
10453
  }
10271
10454
  }
10272
10455
  if (changes.length > 0) {
10273
- writeFileSync29(file, `${JSON.stringify(document, null, indentationOf(raw))}${trailingNewline(raw)}`);
10456
+ writeFileSync30(file, `${JSON.stringify(document, null, indentationOf(raw))}${trailingNewline(raw)}`);
10274
10457
  }
10275
10458
  return changes;
10276
10459
  }
@@ -10298,12 +10481,12 @@ function installedGraphMismatches(projectDir2, manifest, skip = () => false) {
10298
10481
  return mismatches;
10299
10482
  }
10300
10483
  function installedVersion(projectDir2, name) {
10301
- const file = join42(projectDir2, "node_modules", ...name.split("/"), "package.json");
10302
- if (!existsSync43(file)) {
10484
+ const file = join43(projectDir2, "node_modules", ...name.split("/"), "package.json");
10485
+ if (!existsSync44(file)) {
10303
10486
  return null;
10304
10487
  }
10305
10488
  try {
10306
- const version = JSON.parse(readFileSync25(file, "utf8")).version;
10489
+ const version = JSON.parse(readFileSync26(file, "utf8")).version;
10307
10490
  return typeof version === "string" ? version : null;
10308
10491
  } catch {
10309
10492
  return null;
@@ -10390,7 +10573,7 @@ function latestActiveRelease(catalog) {
10390
10573
  return active[0];
10391
10574
  }
10392
10575
  function assertEmptyTarget(targetDir) {
10393
- if (!existsSync44(targetDir)) {
10576
+ if (!existsSync45(targetDir)) {
10394
10577
  return;
10395
10578
  }
10396
10579
  const entries = readdirSync5(targetDir).filter((name) => name !== ".DS_Store");
@@ -10421,13 +10604,13 @@ async function materializeTargets(adapters, projectDir2, targets, options = {})
10421
10604
  continue;
10422
10605
  }
10423
10606
  written[target.path] = digest;
10424
- writeManagedFile(join43(projectDir2, target.path), target.path, bytes, digest, options.existing);
10607
+ writeManagedFile(join44(projectDir2, target.path), target.path, bytes, digest, options.existing);
10425
10608
  }
10426
10609
  return written;
10427
10610
  }
10428
10611
  function writeManagedFile(file, path5, bytes, digest, existing = "verify") {
10429
- if (existsSync44(file) && existing !== "replace") {
10430
- const actual = sha256Digest(readFileSync26(file));
10612
+ if (existsSync45(file) && existing !== "replace") {
10613
+ const actual = sha256Digest(readFileSync27(file));
10431
10614
  if (actual === digest) {
10432
10615
  return;
10433
10616
  }
@@ -10437,7 +10620,7 @@ function writeManagedFile(file, path5, bytes, digest, existing = "verify") {
10437
10620
  });
10438
10621
  }
10439
10622
  mkdirSync17(dirname14(file), { recursive: true });
10440
- writeFileSync30(file, bytes);
10623
+ writeFileSync31(file, bytes);
10441
10624
  }
10442
10625
  async function installFrozenGraph(adapters, options) {
10443
10626
  const maxAttempts = options.allowSessionRetry === false ? 1 : 2;
@@ -10499,7 +10682,7 @@ function scopesOf(manifest) {
10499
10682
  return scopes.length === 0 ? ["@superfunction"] : [...new Set(scopes)];
10500
10683
  }
10501
10684
  function writeRegistryNpmrc(projectDir2, manifest, registryUrl) {
10502
- writeFileSync30(join43(projectDir2, ".npmrc"), registryNpmrc(scopesOf(manifest), registryUrl), "utf8");
10685
+ writeFileSync31(join44(projectDir2, ".npmrc"), registryNpmrc(scopesOf(manifest), registryUrl), "utf8");
10503
10686
  }
10504
10687
  function assertGraphInstalled(options) {
10505
10688
  if (options.expect === void 0) {
@@ -10747,10 +10930,10 @@ function installSteps(options) {
10747
10930
  return { kind: "done", evidence: { attempts: evidence.attempts, tooling: tooling.specifier } };
10748
10931
  },
10749
10932
  async verify() {
10750
- if (!existsSync45(join44(projectDir2, "node_modules"))) {
10933
+ if (!existsSync46(join45(projectDir2, "node_modules"))) {
10751
10934
  return { ok: false, reason: "dependencies-missing" };
10752
10935
  }
10753
- if (!existsSync45(paths.lockFile)) {
10936
+ if (!existsSync46(paths.lockFile)) {
10754
10937
  writeLock(options, projectDir2, adapters.clock.now());
10755
10938
  }
10756
10939
  return { ok: true };
@@ -10849,7 +11032,7 @@ async function verifyToolingPlan(options, projectDir2, operationId) {
10849
11032
  });
10850
11033
  const isolated = await runIsolated(
10851
11034
  projectDir2,
10852
- join44(mkdtempSync(join44(tmpdir(), "spfn-kit-")), operationId),
11035
+ join45(mkdtempSync(join45(tmpdir(), "spfn-kit-")), operationId),
10853
11036
  (workingCopy) => discovered.tooling.planInstall({
10854
11037
  projectDir: workingCopy,
10855
11038
  release: options.manifest.version
@@ -11157,8 +11340,8 @@ async function startRecovery(sink, adapters, activationId) {
11157
11340
  }
11158
11341
 
11159
11342
  // src/kit/customer-source.ts
11160
- import { existsSync as existsSync46, mkdirSync as mkdirSync18, readFileSync as readFileSync27, writeFileSync as writeFileSync31 } from "fs";
11161
- import { dirname as dirname15, join as join45 } from "path";
11343
+ import { existsSync as existsSync47, mkdirSync as mkdirSync18, readFileSync as readFileSync28, writeFileSync as writeFileSync32 } from "fs";
11344
+ import { dirname as dirname15, join as join46 } from "path";
11162
11345
  var IGNORED_DIRECTORIES = ["node_modules", ".git", ".next", ".turbo", ".vercel", "dist", "coverage"];
11163
11346
  var KIT_OWNED_FILES = ["pnpm-lock.yaml", "package.json", ".npmrc", "tsconfig.tsbuildinfo"];
11164
11347
  function declaredPaths(declaration) {
@@ -11203,21 +11386,21 @@ function compareCustomerSource(before, after) {
11203
11386
  return paths.filter((path5) => before[path5] !== after[path5]).map((path5) => ({ path: path5, before: before[path5] ?? null, after: after[path5] ?? null }));
11204
11387
  }
11205
11388
  function customerBaselinePath(projectDir2, operationId) {
11206
- return join45(projectDir2, ".spfn", "operations", `${operationId}.customer-source.json`);
11389
+ return join46(projectDir2, ".spfn", "operations", `${operationId}.customer-source.json`);
11207
11390
  }
11208
11391
  function writeCustomerBaseline(projectDir2, baseline) {
11209
11392
  const path5 = customerBaselinePath(projectDir2, baseline.operationId);
11210
11393
  mkdirSync18(dirname15(path5), { recursive: true });
11211
- writeFileSync31(path5, `${JSON.stringify(baseline, null, 4)}
11394
+ writeFileSync32(path5, `${JSON.stringify(baseline, null, 4)}
11212
11395
  `);
11213
11396
  }
11214
11397
  function readCustomerBaseline(projectDir2, operationId) {
11215
11398
  const path5 = customerBaselinePath(projectDir2, operationId);
11216
- if (!existsSync46(path5)) {
11399
+ if (!existsSync47(path5)) {
11217
11400
  return null;
11218
11401
  }
11219
11402
  try {
11220
- const parsed = JSON.parse(readFileSync27(path5, "utf8"));
11403
+ const parsed = JSON.parse(readFileSync28(path5, "utf8"));
11221
11404
  return parsed?.schemaVersion === 1 && typeof parsed.files === "object" ? parsed : null;
11222
11405
  } catch {
11223
11406
  return null;
@@ -11619,8 +11802,8 @@ function planResult(sink, plan, digest) {
11619
11802
  }
11620
11803
 
11621
11804
  // src/kit/operations/inspect.ts
11622
- import { existsSync as existsSync47 } from "fs";
11623
- import { join as join46 } from "path";
11805
+ import { existsSync as existsSync48 } from "fs";
11806
+ import { join as join47 } from "path";
11624
11807
  async function runStatus(request2, adapters) {
11625
11808
  const paths = kitPaths(request2.projectDir);
11626
11809
  const lock = readInstalledLock(paths.lockFile);
@@ -11733,7 +11916,7 @@ async function runCheck(request2, adapters) {
11733
11916
  fixCommand: `spfn kit resume ${journal.operationId} --json`
11734
11917
  });
11735
11918
  }
11736
- if (!existsSync47(join46(request2.projectDir, "node_modules"))) {
11919
+ if (!existsSync48(join47(request2.projectDir, "node_modules"))) {
11737
11920
  diagnostics.push({
11738
11921
  code: "KIT_GATE_FAILED",
11739
11922
  severity: "warning",
@@ -12145,8 +12328,8 @@ function parseKeys(raw) {
12145
12328
  }
12146
12329
 
12147
12330
  // src/kit/scaffold.ts
12148
- import { mkdirSync as mkdirSync19, existsSync as existsSync48, readFileSync as readFileSync28, writeFileSync as writeFileSync32 } from "fs";
12149
- import { dirname as dirname16, join as join47 } from "path";
12331
+ import { mkdirSync as mkdirSync19, existsSync as existsSync49, readFileSync as readFileSync29, writeFileSync as writeFileSync33 } from "fs";
12332
+ import { dirname as dirname16, join as join48 } from "path";
12150
12333
 
12151
12334
  // src/kit/http/registry.ts
12152
12335
  import { createHash as createHash3 } from "crypto";
@@ -12492,20 +12675,20 @@ var ArtifactScaffoldPort = class {
12492
12675
  }
12493
12676
  };
12494
12677
  function seedProjectName(targetDir, name) {
12495
- const file = join47(targetDir, "package.json");
12496
- if (!existsSync48(file)) {
12678
+ const file = join48(targetDir, "package.json");
12679
+ if (!existsSync49(file)) {
12497
12680
  return;
12498
12681
  }
12499
12682
  let parsed;
12500
12683
  try {
12501
- parsed = JSON.parse(readFileSync28(file, "utf8"));
12684
+ parsed = JSON.parse(readFileSync29(file, "utf8"));
12502
12685
  } catch {
12503
12686
  throw new KitError("KIT_MANIFEST_INVALID", "The release scaffold's package.json is not readable JSON.", {
12504
12687
  evidence: { path: "package.json" }
12505
12688
  });
12506
12689
  }
12507
12690
  parsed.name = packageNameOf(name);
12508
- writeFileSync32(file, `${JSON.stringify(parsed, null, 4)}
12691
+ writeFileSync33(file, `${JSON.stringify(parsed, null, 4)}
12509
12692
  `, "utf8");
12510
12693
  }
12511
12694
  function packageNameOf(name) {
@@ -12513,9 +12696,9 @@ function packageNameOf(name) {
12513
12696
  return cleaned.length === 0 ? "kit-project" : cleaned;
12514
12697
  }
12515
12698
  function writeScaffoldRecord(targetDir, record) {
12516
- const file = join47(targetDir, SCAFFOLD_RECORD_PATH);
12699
+ const file = join48(targetDir, SCAFFOLD_RECORD_PATH);
12517
12700
  mkdirSync19(dirname16(file), { recursive: true });
12518
- writeFileSync32(file, `${JSON.stringify(record, null, 4)}
12701
+ writeFileSync33(file, `${JSON.stringify(record, null, 4)}
12519
12702
  `, "utf8");
12520
12703
  }
12521
12704
 
@@ -12895,7 +13078,7 @@ function requireCatalogUrl(projectDir2) {
12895
13078
 
12896
13079
  // src/kit/local/index.ts
12897
13080
  import { createRequire as createRequire2 } from "module";
12898
- import { join as join51 } from "path";
13081
+ import { join as join52 } from "path";
12899
13082
  import { pathToFileURL as pathToFileURL4 } from "url";
12900
13083
 
12901
13084
  // src/kit/local/process.ts
@@ -13044,8 +13227,8 @@ ${result.stdout}`;
13044
13227
  }
13045
13228
 
13046
13229
  // src/kit/local/database.ts
13047
- import { existsSync as existsSync49 } from "fs";
13048
- import { dirname as dirname17, join as join48 } from "path";
13230
+ import { existsSync as existsSync50 } from "fs";
13231
+ import { dirname as dirname17, join as join49 } from "path";
13049
13232
  import { fileURLToPath as fileURLToPath3 } from "url";
13050
13233
  var DEFAULT_DATABASE_TIMEOUT_MS = 9e5;
13051
13234
  var SpfnDatabasePort = class {
@@ -13130,8 +13313,8 @@ function spfnCommand() {
13130
13313
  function resolveSpfnBin(from = fileURLToPath3(import.meta.url)) {
13131
13314
  let directory = dirname17(from);
13132
13315
  for (let depth = 0; depth < 8; depth += 1) {
13133
- const candidate = join48(directory, "bin", "spfn.js");
13134
- if (existsSync49(candidate)) {
13316
+ const candidate = join49(directory, "bin", "spfn.js");
13317
+ if (existsSync50(candidate)) {
13135
13318
  return candidate;
13136
13319
  }
13137
13320
  const parent = dirname17(directory);
@@ -13144,8 +13327,8 @@ function resolveSpfnBin(from = fileURLToPath3(import.meta.url)) {
13144
13327
  }
13145
13328
 
13146
13329
  // src/kit/local/gates.ts
13147
- import { existsSync as existsSync50, readFileSync as readFileSync29 } from "fs";
13148
- import { join as join49 } from "path";
13330
+ import { existsSync as existsSync51, readFileSync as readFileSync30 } from "fs";
13331
+ import { join as join50 } from "path";
13149
13332
  var DEFAULT_GATE_TIMEOUT_MS = 9e5;
13150
13333
  var GATE_PLANS = {
13151
13334
  "kit-check": { scripts: [], fallback: spfnFallback(["kit", "check", "--json"]) },
@@ -13196,12 +13379,12 @@ var CommandGatePort = class {
13196
13379
  }
13197
13380
  };
13198
13381
  function projectScripts(cwd) {
13199
- const file = join49(cwd, "package.json");
13200
- if (!existsSync50(file)) {
13382
+ const file = join50(cwd, "package.json");
13383
+ if (!existsSync51(file)) {
13201
13384
  return {};
13202
13385
  }
13203
13386
  try {
13204
- const parsed = JSON.parse(readFileSync29(file, "utf8"));
13387
+ const parsed = JSON.parse(readFileSync30(file, "utf8"));
13205
13388
  return parsed.scripts ?? {};
13206
13389
  } catch {
13207
13390
  return {};
@@ -13213,8 +13396,8 @@ function spfnFallback(args) {
13213
13396
  }
13214
13397
 
13215
13398
  // src/kit/local/git.ts
13216
- import { existsSync as existsSync51 } from "fs";
13217
- import { join as join50 } from "path";
13399
+ import { existsSync as existsSync52 } from "fs";
13400
+ import { join as join51 } from "path";
13218
13401
  var FALLBACK_AUTHOR_NAME = "spfn kit";
13219
13402
  var FALLBACK_AUTHOR_EMAIL = "kit@superfunction.xyz";
13220
13403
  var DEFAULT_GIT_TIMEOUT_MS = 12e4;
@@ -13225,7 +13408,7 @@ var SystemGitPort = class {
13225
13408
  }
13226
13409
  /** Start a repository, or leave the one that is already there alone. */
13227
13410
  async init(request2) {
13228
- if (existsSync51(join50(request2.cwd, ".git"))) {
13411
+ if (existsSync52(join51(request2.cwd, ".git"))) {
13229
13412
  return;
13230
13413
  }
13231
13414
  const result = await this.git(request2.cwd, ["init"]);
@@ -13342,7 +13525,7 @@ function createKitLocalPorts(options = {}) {
13342
13525
  }
13343
13526
  function createProjectModuleLoader() {
13344
13527
  return async (specifier, projectDir2) => {
13345
- const resolve4 = createRequire2(join51(projectDir2, "package.json"));
13528
+ const resolve4 = createRequire2(join52(projectDir2, "package.json"));
13346
13529
  return import(pathToFileURL4(resolve4.resolve(specifier)).href);
13347
13530
  };
13348
13531
  }