@insforge/cli 0.1.82 → 0.1.84

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.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { readFileSync as readFileSync12 } from "fs";
5
- import { join as join14, dirname as dirname2 } from "path";
4
+ import { readFileSync as readFileSync13 } from "fs";
5
+ import { join as join15, dirname as dirname2 } from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { Command } from "commander";
8
- import * as clack18 from "@clack/prompts";
8
+ import * as clack19 from "@clack/prompts";
9
9
 
10
10
  // src/lib/prompts.ts
11
11
  import * as readline from "readline";
@@ -1215,6 +1215,17 @@ function trackPayments(subcommand, config, properties) {
1215
1215
  ...properties
1216
1216
  });
1217
1217
  }
1218
+ function trackPosthog(subcommand, config, properties) {
1219
+ captureEvent(config.project_id, "cli_posthog_invoked", {
1220
+ subcommand,
1221
+ project_id: config.project_id,
1222
+ project_name: config.project_name,
1223
+ org_id: config.org_id,
1224
+ region: config.region,
1225
+ oss_mode: config.project_id === FAKE_PROJECT_ID,
1226
+ ...properties
1227
+ });
1228
+ }
1218
1229
  function trackConfig(subcommand, config, properties) {
1219
1230
  const distinctId = config?.project_id ?? FAKE_PROJECT_ID;
1220
1231
  captureEvent(distinctId, "cli_config_invoked", {
@@ -1707,15 +1718,91 @@ import { exec as exec3 } from "child_process";
1707
1718
  import { promisify as promisify4 } from "util";
1708
1719
  import * as fs5 from "fs/promises";
1709
1720
  import * as path5 from "path";
1710
- import * as clack13 from "@clack/prompts";
1721
+ import * as clack14 from "@clack/prompts";
1711
1722
  import pc2 from "picocolors";
1712
1723
 
1713
1724
  // src/lib/skills.ts
1714
1725
  import { exec } from "child_process";
1715
- import { existsSync as existsSync3, readFileSync as readFileSync2, appendFileSync } from "fs";
1716
- import { join as join2 } from "path";
1726
+ import { existsSync as existsSync4, readFileSync as readFileSync3, appendFileSync } from "fs";
1727
+ import { join as join3 } from "path";
1717
1728
  import { promisify } from "util";
1729
+ import * as clack10 from "@clack/prompts";
1730
+
1731
+ // src/lib/agents-md.ts
1732
+ import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
1733
+ import { join as join2 } from "path";
1718
1734
  import * as clack9 from "@clack/prompts";
1735
+ var AGENTS_MD_START = "<!-- INSFORGE:START -->";
1736
+ var AGENTS_MD_END = "<!-- INSFORGE:END -->";
1737
+ function buildInsforgeBlock(config) {
1738
+ const lines = [
1739
+ AGENTS_MD_START,
1740
+ "## InsForge backend",
1741
+ "",
1742
+ "This project uses [InsForge](https://insforge.dev): an all-in-one, open-source Postgres-based backend (BaaS) that gives this app a database, authentication, file storage, edge functions, realtime, an AI model gateway, and payments through one platform.",
1743
+ ""
1744
+ ];
1745
+ if (config?.project_name || config?.oss_host) {
1746
+ const name = config.project_name ? `**${config.project_name}**` : "This project";
1747
+ const host = config.oss_host ? ` (API base \`${config.oss_host}\`)` : "";
1748
+ lines.push(`- **Project:** ${name}${host}`);
1749
+ }
1750
+ lines.push(
1751
+ "- **Skills:** these InsForge skills are installed for supported coding agents. Reach for them before implementing any InsForge feature instead of guessing the API:",
1752
+ " - `insforge`: app code with the `@insforge/sdk` client (database CRUD, auth, storage, edge functions, realtime, AI, email, and Stripe payments).",
1753
+ " - `insforge-cli`: backend and infrastructure via the `insforge` CLI (projects, SQL, migrations, RLS policies, storage buckets, functions, secrets, payment setup, schedules, deploys).",
1754
+ " - `insforge-debug`: diagnosing failures (SDK/HTTP errors, RLS denials, auth and OAuth issues) and running security or performance audits.",
1755
+ " - `insforge-integrations`: wiring external auth providers (Clerk, Auth0, WorkOS, Better Auth, etc.) for JWT-based RLS, or the OKX x402 payment facilitator.",
1756
+ " - `find-skills`: discovering additional skills on demand.",
1757
+ "- **Credentials:** app code reads keys from `.env.local`; the CLI reads `.insforge/project.json`. Never hardcode or commit keys.",
1758
+ "",
1759
+ "Key patterns:",
1760
+ "",
1761
+ "- Database inserts take an array: `insert([{ ... }])`.",
1762
+ "- Reference users with `auth.users(id)`; use `auth.uid()` in RLS policies.",
1763
+ "- For storage uploads, persist both the returned `url` and `key`.",
1764
+ AGENTS_MD_END
1765
+ );
1766
+ return lines.join("\n");
1767
+ }
1768
+ function mergeAgentsMd(existing, config) {
1769
+ const block = buildInsforgeBlock(config);
1770
+ if (existing === null || existing.trim() === "") {
1771
+ return `# AGENTS.md
1772
+
1773
+ ${block}
1774
+ `;
1775
+ }
1776
+ const startIdx = existing.indexOf(AGENTS_MD_START);
1777
+ if (startIdx !== -1) {
1778
+ const endMarkerIdx = existing.indexOf(AGENTS_MD_END, startIdx + AGENTS_MD_START.length);
1779
+ let before = existing.slice(0, startIdx);
1780
+ if (before.length > 0 && !before.endsWith("\n")) before += "\n";
1781
+ const after = endMarkerIdx === -1 ? "\n" : existing.slice(endMarkerIdx + AGENTS_MD_END.length);
1782
+ return `${before}${block}${after}`;
1783
+ }
1784
+ return `${existing.replace(/\s+$/, "")}
1785
+
1786
+ ${block}
1787
+ `;
1788
+ }
1789
+ function writeLocalAgentsMd(json, opts) {
1790
+ const cwd = opts?.cwd ?? process.cwd();
1791
+ const config = opts?.config !== void 0 ? opts.config : getProjectConfig();
1792
+ const path6 = join2(cwd, "AGENTS.md");
1793
+ const existed = existsSync3(path6);
1794
+ const existing = existed ? readFileSync2(path6, "utf-8") : null;
1795
+ const next = mergeAgentsMd(existing, config);
1796
+ if (existing === next) return;
1797
+ writeFileSync3(path6, next);
1798
+ if (!json) {
1799
+ clack9.log.success(
1800
+ existed ? "Updated AGENTS.md with InsForge guidance." : "Created AGENTS.md with InsForge guidance."
1801
+ );
1802
+ }
1803
+ }
1804
+
1805
+ // src/lib/skills.ts
1719
1806
  var execAsync = promisify(exec);
1720
1807
  var SKILL_INSTALL_TIMEOUT_MS = 6e4;
1721
1808
  function describeExecError(err) {
@@ -1755,8 +1842,8 @@ var GITIGNORE_ENTRIES = [
1755
1842
  ".windsurf"
1756
1843
  ];
1757
1844
  function updateGitignore() {
1758
- const gitignorePath = join2(process.cwd(), ".gitignore");
1759
- const existing = existsSync3(gitignorePath) ? readFileSync2(gitignorePath, "utf-8") : "";
1845
+ const gitignorePath = join3(process.cwd(), ".gitignore");
1846
+ const existing = existsSync4(gitignorePath) ? readFileSync3(gitignorePath, "utf-8") : "";
1760
1847
  const lines = new Set(existing.split("\n").map((l) => l.trim()));
1761
1848
  const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.has(entry));
1762
1849
  if (!missing.length) return;
@@ -1772,44 +1859,44 @@ var PROVIDER_SKILLS = {
1772
1859
  };
1773
1860
  async function installSkills(json, authProvider) {
1774
1861
  try {
1775
- if (!json) clack9.log.info("Installing InsForge agent skills (global)...");
1862
+ if (!json) clack10.log.info("Installing InsForge agent skills (global)...");
1776
1863
  await execAsync(`npx skills add insforge/agent-skills -g -y ${AGENT_FLAGS}`, {
1777
1864
  cwd: process.cwd(),
1778
1865
  timeout: SKILL_INSTALL_TIMEOUT_MS
1779
1866
  });
1780
- if (!json) clack9.log.success("InsForge agent skills installed.");
1867
+ if (!json) clack10.log.success("InsForge agent skills installed.");
1781
1868
  } catch (err) {
1782
1869
  if (!json) {
1783
- clack9.log.warn(`Could not install agent skills: ${describeExecError(err)}`);
1784
- clack9.log.info("Run `npx skills add insforge/agent-skills` once resolved to see the full output.");
1870
+ clack10.log.warn(`Could not install agent skills: ${describeExecError(err)}`);
1871
+ clack10.log.info("Run `npx skills add insforge/agent-skills` once resolved to see the full output.");
1785
1872
  }
1786
1873
  }
1787
1874
  try {
1788
- if (!json) clack9.log.info("Installing find-skills (global)...");
1875
+ if (!json) clack10.log.info("Installing find-skills (global)...");
1789
1876
  await execAsync("npx skills add https://github.com/vercel-labs/skills --skill find-skills -g -y", {
1790
1877
  cwd: process.cwd(),
1791
1878
  timeout: SKILL_INSTALL_TIMEOUT_MS
1792
1879
  });
1793
- if (!json) clack9.log.success("find-skills installed.");
1880
+ if (!json) clack10.log.success("find-skills installed.");
1794
1881
  } catch (err) {
1795
1882
  if (!json) {
1796
- clack9.log.warn(`Could not install find-skills: ${describeExecError(err)}`);
1797
- clack9.log.info("Run `npx skills add https://github.com/vercel-labs/skills --skill find-skills` once resolved.");
1883
+ clack10.log.warn(`Could not install find-skills: ${describeExecError(err)}`);
1884
+ clack10.log.info("Run `npx skills add https://github.com/vercel-labs/skills --skill find-skills` once resolved.");
1798
1885
  }
1799
1886
  }
1800
1887
  const providerEntry = authProvider ? PROVIDER_SKILLS[authProvider] : void 0;
1801
1888
  if (providerEntry) {
1802
1889
  try {
1803
- if (!json) clack9.log.info(`Installing ${providerEntry.label} (global)...`);
1890
+ if (!json) clack10.log.info(`Installing ${providerEntry.label} (global)...`);
1804
1891
  await execAsync(`npx skills add ${providerEntry.repo} -g -y ${AGENT_FLAGS}`, {
1805
1892
  cwd: process.cwd(),
1806
1893
  timeout: SKILL_INSTALL_TIMEOUT_MS
1807
1894
  });
1808
- if (!json) clack9.log.success(`${providerEntry.label} installed.`);
1895
+ if (!json) clack10.log.success(`${providerEntry.label} installed.`);
1809
1896
  } catch (err) {
1810
1897
  if (!json) {
1811
- clack9.log.warn(`Could not install ${providerEntry.label}: ${describeExecError(err)}`);
1812
- clack9.log.info(`Run \`npx skills add ${providerEntry.repo}\` once resolved to see the full output.`);
1898
+ clack10.log.warn(`Could not install ${providerEntry.label}: ${describeExecError(err)}`);
1899
+ clack10.log.info(`Run \`npx skills add ${providerEntry.repo}\` once resolved to see the full output.`);
1813
1900
  }
1814
1901
  }
1815
1902
  }
@@ -1817,6 +1904,10 @@ async function installSkills(json, authProvider) {
1817
1904
  updateGitignore();
1818
1905
  } catch {
1819
1906
  }
1907
+ try {
1908
+ writeLocalAgentsMd(json);
1909
+ } catch {
1910
+ }
1820
1911
  }
1821
1912
  async function reportCliUsage(toolName, success, maxRetries = 1, explicitConfig) {
1822
1913
  let config = explicitConfig;
@@ -1866,7 +1957,7 @@ import { tmpdir } from "os";
1866
1957
  import { execFile } from "child_process";
1867
1958
  import { promisify as promisify2 } from "util";
1868
1959
  import { randomBytes as randomBytes2 } from "crypto";
1869
- import * as clack10 from "@clack/prompts";
1960
+ import * as clack11 from "@clack/prompts";
1870
1961
 
1871
1962
  // src/lib/api/oss.ts
1872
1963
  function requireProjectConfig() {
@@ -2107,7 +2198,7 @@ async function applyAuthProvider(provider, cwd, projectConfig, json) {
2107
2198
  if (!VALID_AUTH_PROVIDERS.includes(provider)) {
2108
2199
  throw new Error(`Unknown auth provider: ${provider}`);
2109
2200
  }
2110
- const fetchSpinner = !json ? clack10.spinner() : null;
2201
+ const fetchSpinner = !json ? clack11.spinner() : null;
2111
2202
  fetchSpinner?.start(`Fetching ${provider} scaffold from templates repo...`);
2112
2203
  const { dir: providerDir, cleanup } = await fetchProviderTree(provider);
2113
2204
  fetchSpinner?.stop(`${provider} scaffold ready`);
@@ -2206,15 +2297,15 @@ async function applyAuthProvider(provider, cwd, projectConfig, json) {
2206
2297
  result.envKeysRefreshed = Array.from(/* @__PURE__ */ new Set([...result.envKeysRefreshed, ...refreshed]));
2207
2298
  }
2208
2299
  if (!jwtSecret && !json) {
2209
- clack10.log.warn("Could not auto-fill JWT_SECRET \u2014 run `npx @insforge/cli secrets get JWT_SECRET` and paste it into .env.local.");
2300
+ clack11.log.warn("Could not auto-fill JWT_SECRET \u2014 run `npx @insforge/cli secrets get JWT_SECRET` and paste it into .env.local.");
2210
2301
  }
2211
2302
  if (result.envKeysSkipped.length > 0 && !json) {
2212
- clack10.log.warn(
2303
+ clack11.log.warn(
2213
2304
  `Kept your existing values for: ${result.envKeysSkipped.join(", ")}. If any of these need the auth-provider's defaults, see .env.example for reference.`
2214
2305
  );
2215
2306
  }
2216
2307
  if (result.envKeysRefreshed.length > 0 && !json) {
2217
- clack10.log.info(
2308
+ clack11.log.info(
2218
2309
  `Refreshed stale platform defaults: ${result.envKeysRefreshed.join(", ")}. Your value matched the manifest's default, so we replaced it with the live one.`
2219
2310
  );
2220
2311
  }
@@ -2230,7 +2321,7 @@ import { tmpdir as tmpdir2 } from "os";
2230
2321
  import { promisify as promisify3 } from "util";
2231
2322
  import * as fs4 from "fs/promises";
2232
2323
  import * as path4 from "path";
2233
- import * as clack12 from "@clack/prompts";
2324
+ import * as clack13 from "@clack/prompts";
2234
2325
 
2235
2326
  // src/lib/env.ts
2236
2327
  import * as fs2 from "fs/promises";
@@ -2265,7 +2356,7 @@ import * as path3 from "path";
2265
2356
  import * as fs3 from "fs/promises";
2266
2357
  import { createReadStream } from "fs";
2267
2358
  import { createHash as createHash2 } from "crypto";
2268
- import * as clack11 from "@clack/prompts";
2359
+ import * as clack12 from "@clack/prompts";
2269
2360
  import archiver from "archiver";
2270
2361
  var POLL_INTERVAL_MS3 = 5e3;
2271
2362
  var POLL_TIMEOUT_MS3 = 3e5;
@@ -2565,7 +2656,7 @@ function registerDeploymentsDeployCommand(deploymentsCmd2) {
2565
2656
  `"${dirName}" is an excluded directory and cannot be used as a deploy source. Please specify your project root or output directory instead.`
2566
2657
  );
2567
2658
  }
2568
- const spinner11 = !json ? clack11.spinner() : null;
2659
+ const spinner11 = !json ? clack12.spinner() : null;
2569
2660
  const startBody = {};
2570
2661
  if (opts.env) {
2571
2662
  try {
@@ -2598,9 +2689,9 @@ function registerDeploymentsDeployCommand(deploymentsCmd2) {
2598
2689
  outputJson(result.deployment);
2599
2690
  } else {
2600
2691
  if (result.liveUrl) {
2601
- clack11.log.success(`Live at: ${result.liveUrl}`);
2692
+ clack12.log.success(`Live at: ${result.liveUrl}`);
2602
2693
  }
2603
- clack11.log.info(`Deployment ID: ${result.deploymentId}`);
2694
+ clack12.log.info(`Deployment ID: ${result.deploymentId}`);
2604
2695
  }
2605
2696
  } else {
2606
2697
  spinner11?.stop("Deployment is still building");
@@ -2611,9 +2702,9 @@ function registerDeploymentsDeployCommand(deploymentsCmd2) {
2611
2702
  timedOut: true
2612
2703
  });
2613
2704
  } else {
2614
- clack11.log.info(`Deployment ID: ${result.deploymentId}`);
2615
- clack11.log.warn("Deployment did not finish within 5 minutes.");
2616
- clack11.log.info(`Check status with: npx @insforge/cli deployments status ${result.deploymentId}`);
2705
+ clack12.log.info(`Deployment ID: ${result.deploymentId}`);
2706
+ clack12.log.warn("Deployment did not finish within 5 minutes.");
2707
+ clack12.log.info(`Check status with: npx @insforge/cli deployments status ${result.deploymentId}`);
2617
2708
  }
2618
2709
  }
2619
2710
  await reportCliUsage("cli.deployments.deploy", true);
@@ -2753,7 +2844,7 @@ Browse available templates: https://insforge.dev/templates`
2753
2844
  await requireAuth(apiUrl, false);
2754
2845
  if (!json) {
2755
2846
  await animateBanner();
2756
- clack12.intro("Let's build something great");
2847
+ clack13.intro("Let's build something great");
2757
2848
  }
2758
2849
  let orgId = opts.orgId;
2759
2850
  if (!orgId) {
@@ -2763,7 +2854,7 @@ Browse available templates: https://insforge.dev/templates`
2763
2854
  }
2764
2855
  if (orgs.length === 1) {
2765
2856
  orgId = orgs[0].id;
2766
- if (!json) clack12.log.info(`Using organization: ${orgs[0].name}`);
2857
+ if (!json) clack13.log.info(`Using organization: ${orgs[0].name}`);
2767
2858
  } else {
2768
2859
  if (json) {
2769
2860
  throw new CLIError("Multiple organizations found. Specify --org-id.");
@@ -2879,7 +2970,7 @@ Browse available templates: https://insforge.dev/templates`
2879
2970
  process.chdir(projectDir);
2880
2971
  }
2881
2972
  let projectLinked = false;
2882
- const s = !json ? clack12.spinner() : null;
2973
+ const s = !json ? clack13.spinner() : null;
2883
2974
  try {
2884
2975
  s?.start("Creating project...");
2885
2976
  const project = await createProject(orgId, projectName, opts.region, apiUrl);
@@ -2906,10 +2997,7 @@ Browse available templates: https://insforge.dev/templates`
2906
2997
  json
2907
2998
  );
2908
2999
  if (downloaded) {
2909
- void reportMarketplaceDownload(
2910
- opts.marketplace,
2911
- apiUrl ?? "https://api.insforge.dev"
2912
- );
3000
+ void reportMarketplaceDownload(opts.marketplace);
2913
3001
  }
2914
3002
  } else if (githubTemplates.includes(template)) {
2915
3003
  await downloadGitHubTemplate(template, projectConfig, json);
@@ -2919,7 +3007,7 @@ Browse available templates: https://insforge.dev/templates`
2919
3007
  try {
2920
3008
  const anonKey = await getAnonKey();
2921
3009
  if (!anonKey) {
2922
- if (!json) clack12.log.warn("Could not retrieve anon key. You can add it to .env.local manually.");
3010
+ if (!json) clack13.log.warn("Could not retrieve anon key. You can add it to .env.local manually.");
2923
3011
  } else {
2924
3012
  const envPath = path4.join(process.cwd(), ".env.local");
2925
3013
  const envContent = [
@@ -2930,16 +3018,16 @@ Browse available templates: https://insforge.dev/templates`
2930
3018
  ].join("\n");
2931
3019
  await fs4.writeFile(envPath, envContent, { flag: "wx" });
2932
3020
  if (!json) {
2933
- clack12.log.success("Created .env.local with your InsForge credentials");
3021
+ clack13.log.success("Created .env.local with your InsForge credentials");
2934
3022
  }
2935
3023
  }
2936
3024
  } catch (err) {
2937
3025
  const error = err;
2938
3026
  if (!json) {
2939
3027
  if (error.code === "EEXIST") {
2940
- clack12.log.warn(".env.local already exists; skipping InsForge key seeding.");
3028
+ clack13.log.warn(".env.local already exists; skipping InsForge key seeding.");
2941
3029
  } else {
2942
- clack12.log.warn(`Failed to create .env.local: ${error.message}`);
3030
+ clack13.log.warn(`Failed to create .env.local: ${error.message}`);
2943
3031
  }
2944
3032
  }
2945
3033
  }
@@ -2948,12 +3036,12 @@ Browse available templates: https://insforge.dev/templates`
2948
3036
  try {
2949
3037
  const result = await applyAuthProvider(opts.auth, process.cwd(), projectConfig, json);
2950
3038
  if (!json) {
2951
- clack12.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3039
+ clack13.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
2952
3040
  }
2953
3041
  } catch (err) {
2954
3042
  const msg = `Failed to apply --auth ${opts.auth}: ${err.message}`;
2955
3043
  if (json) console.error(JSON.stringify({ warning: msg }));
2956
- else clack12.log.warn(msg);
3044
+ else clack13.log.warn(msg);
2957
3045
  }
2958
3046
  }
2959
3047
  await installSkills(json, opts.auth);
@@ -2961,7 +3049,7 @@ Browse available templates: https://insforge.dev/templates`
2961
3049
  await reportCliUsage("cli.create", true, 6);
2962
3050
  const templateDownloaded = hasTemplate ? await fs4.stat(path4.join(process.cwd(), "package.json")).catch(() => null) : null;
2963
3051
  if (templateDownloaded) {
2964
- const installSpinner = !json ? clack12.spinner() : null;
3052
+ const installSpinner = !json ? clack13.spinner() : null;
2965
3053
  installSpinner?.start("Installing dependencies...");
2966
3054
  try {
2967
3055
  await execAsync2("npm install", { cwd: process.cwd(), maxBuffer: 10 * 1024 * 1024 });
@@ -2969,8 +3057,8 @@ Browse available templates: https://insforge.dev/templates`
2969
3057
  } catch (err) {
2970
3058
  installSpinner?.stop("Failed to install dependencies");
2971
3059
  if (!json) {
2972
- clack12.log.warn(`npm install failed: ${err.message}`);
2973
- clack12.log.info("Run `npm install` manually to install dependencies.");
3060
+ clack13.log.warn(`npm install failed: ${err.message}`);
3061
+ clack13.log.info("Run `npm install` manually to install dependencies.");
2974
3062
  }
2975
3063
  }
2976
3064
  }
@@ -2986,7 +3074,7 @@ Browse available templates: https://insforge.dev/templates`
2986
3074
  if (envVars.length > 0) {
2987
3075
  startBody.envVars = envVars;
2988
3076
  }
2989
- const deploySpinner = clack12.spinner();
3077
+ const deploySpinner = clack13.spinner();
2990
3078
  const result = await deployProject({
2991
3079
  sourceDir: process.cwd(),
2992
3080
  startBody,
@@ -2997,12 +3085,12 @@ Browse available templates: https://insforge.dev/templates`
2997
3085
  liveUrl = result.liveUrl;
2998
3086
  } else {
2999
3087
  deploySpinner.stop("Deployment is still building");
3000
- clack12.log.info(`Deployment ID: ${result.deploymentId}`);
3001
- clack12.log.warn("Deployment did not finish within 2 minutes.");
3002
- clack12.log.info(`Check status with: npx @insforge/cli deployments status ${result.deploymentId}`);
3088
+ clack13.log.info(`Deployment ID: ${result.deploymentId}`);
3089
+ clack13.log.warn("Deployment did not finish within 2 minutes.");
3090
+ clack13.log.info(`Check status with: npx @insforge/cli deployments status ${result.deploymentId}`);
3003
3091
  }
3004
3092
  } catch (err) {
3005
- clack12.log.warn(`Deploy failed: ${err.message}`);
3093
+ clack13.log.warn(`Deploy failed: ${err.message}`);
3006
3094
  }
3007
3095
  }
3008
3096
  }
@@ -3019,33 +3107,33 @@ Browse available templates: https://insforge.dev/templates`
3019
3107
  }
3020
3108
  });
3021
3109
  } else {
3022
- clack12.log.step(`Dashboard: ${dashboardUrl}`);
3110
+ clack13.log.step(`Dashboard: ${dashboardUrl}`);
3023
3111
  if (liveUrl) {
3024
- clack12.log.success(`Live site: ${liveUrl}`);
3112
+ clack13.log.success(`Live site: ${liveUrl}`);
3025
3113
  }
3026
3114
  if (templateDownloaded) {
3027
3115
  const steps = [
3028
3116
  `cd ${dirName}`,
3029
3117
  "npm run dev"
3030
3118
  ];
3031
- clack12.note(steps.join("\n"), "Next steps");
3032
- clack12.note("Open your coding agent (Claude Code, Codex, Cursor, etc.) to add new features.", "Keep building");
3119
+ clack13.note(steps.join("\n"), "Next steps");
3120
+ clack13.note("Open your coding agent (Claude Code, Codex, Cursor, etc.) to add new features.", "Keep building");
3033
3121
  } else if (hasTemplate && !templateDownloaded) {
3034
- clack12.log.warn("Template download failed. You can retry or set up manually.");
3122
+ clack13.log.warn("Template download failed. You can retry or set up manually.");
3035
3123
  } else {
3036
3124
  const prompts = [
3037
3125
  "Build a todo app with Google OAuth sign-in",
3038
3126
  "Build an Instagram clone where users can upload photos, like, and comment",
3039
3127
  "Build an AI chatbot with conversation history"
3040
3128
  ];
3041
- clack12.note(
3129
+ clack13.note(
3042
3130
  `Open your coding agent (Claude Code, Codex, Cursor, etc.) and try:
3043
3131
 
3044
3132
  ${prompts.map((p3) => `\u2022 "${p3}"`).join("\n")}`,
3045
3133
  "Start building"
3046
3134
  );
3047
3135
  }
3048
- clack12.outro("Done!");
3136
+ clack13.outro("Done!");
3049
3137
  }
3050
3138
  } catch (err) {
3051
3139
  if (!projectLinked && hasTemplate && projectDir !== originalCwd) {
@@ -3064,7 +3152,7 @@ ${prompts.map((p3) => `\u2022 "${p3}"`).join("\n")}`,
3064
3152
  });
3065
3153
  }
3066
3154
  async function downloadTemplate(framework, projectConfig, projectName, json, _apiUrl) {
3067
- const s = !json ? clack12.spinner() : null;
3155
+ const s = !json ? clack13.spinner() : null;
3068
3156
  s?.start("Downloading template...");
3069
3157
  try {
3070
3158
  const anonKey = await getAnonKey();
@@ -3095,13 +3183,13 @@ async function downloadTemplate(framework, projectConfig, projectName, json, _ap
3095
3183
  } catch (err) {
3096
3184
  s?.stop("Template download failed");
3097
3185
  if (!json) {
3098
- clack12.log.warn(`Failed to download template: ${err.message}`);
3099
- clack12.log.info("You can manually set up the template later.");
3186
+ clack13.log.warn(`Failed to download template: ${err.message}`);
3187
+ clack13.log.info("You can manually set up the template later.");
3100
3188
  }
3101
3189
  }
3102
3190
  }
3103
3191
  async function downloadGitHubTemplate(templateName, projectConfig, json) {
3104
- const s = !json ? clack12.spinner() : null;
3192
+ const s = !json ? clack13.spinner() : null;
3105
3193
  s?.start(`Downloading ${templateName} template...`);
3106
3194
  const tempDir = path4.join(tmpdir2(), `insforge-template-${Date.now()}`);
3107
3195
  try {
@@ -3150,7 +3238,7 @@ async function downloadGitHubTemplate(templateName, projectConfig, json) {
3150
3238
  await fs4.writeFile(envLocalPath, envFinal, { flag: "wx" });
3151
3239
  } catch (e) {
3152
3240
  if (e.code === "EEXIST") {
3153
- if (!json) clack12.log.warn(".env.local already exists; skipping env seeding.");
3241
+ if (!json) clack13.log.warn(".env.local already exists; skipping env seeding.");
3154
3242
  } else {
3155
3243
  throw e;
3156
3244
  }
@@ -3160,7 +3248,7 @@ async function downloadGitHubTemplate(templateName, projectConfig, json) {
3160
3248
  const migrationPath = path4.join(cwd, "migrations", "db_init.sql");
3161
3249
  const migrationExists = await fs4.stat(migrationPath).catch(() => null);
3162
3250
  if (migrationExists) {
3163
- const dbSpinner = !json ? clack12.spinner() : null;
3251
+ const dbSpinner = !json ? clack13.spinner() : null;
3164
3252
  dbSpinner?.start("Running database migrations...");
3165
3253
  try {
3166
3254
  const sql = await fs4.readFile(migrationPath, "utf-8");
@@ -3169,8 +3257,8 @@ async function downloadGitHubTemplate(templateName, projectConfig, json) {
3169
3257
  } catch (err) {
3170
3258
  dbSpinner?.stop("Database migration failed");
3171
3259
  if (!json) {
3172
- clack12.log.warn(`Migration failed: ${err.message}`);
3173
- clack12.log.info('You can run the migration manually: npx @insforge/cli db query --unrestricted "$(cat migrations/db_init.sql)"');
3260
+ clack13.log.warn(`Migration failed: ${err.message}`);
3261
+ clack13.log.info('You can run the migration manually: npx @insforge/cli db query --unrestricted "$(cat migrations/db_init.sql)"');
3174
3262
  } else {
3175
3263
  throw err;
3176
3264
  }
@@ -3183,8 +3271,8 @@ async function downloadGitHubTemplate(templateName, projectConfig, json) {
3183
3271
  if (json) {
3184
3272
  console.error(JSON.stringify({ warning: msg }));
3185
3273
  } else {
3186
- clack12.log.warn(msg);
3187
- clack12.log.info("You can manually clone from: https://github.com/InsForge/insforge-templates");
3274
+ clack13.log.warn(msg);
3275
+ clack13.log.info("You can manually clone from: https://github.com/InsForge/insforge-templates");
3188
3276
  }
3189
3277
  return false;
3190
3278
  } finally {
@@ -3192,12 +3280,14 @@ async function downloadGitHubTemplate(templateName, projectConfig, json) {
3192
3280
  });
3193
3281
  }
3194
3282
  }
3195
- async function reportMarketplaceDownload(slug, apiUrl) {
3283
+ var MARKETPLACE_REPORT_URL = process.env.INSFORGE_MARKETPLACE_REPORT_URL ?? "https://p8n7m7ci.us-east.insforge.app/functions/report-download";
3284
+ async function reportMarketplaceDownload(slug) {
3196
3285
  try {
3197
- const res = await fetch(`${apiUrl}/templates/v1/${encodeURIComponent(slug)}/downloads`, {
3286
+ const res = await fetch(MARKETPLACE_REPORT_URL, {
3198
3287
  method: "POST",
3199
3288
  headers: { "Content-Type": "application/json" },
3200
- body: "{}"
3289
+ body: JSON.stringify({ slug }),
3290
+ signal: AbortSignal.timeout(5e3)
3201
3291
  });
3202
3292
  if (!res.ok) {
3203
3293
  return;
@@ -3209,15 +3299,15 @@ async function reportMarketplaceDownload(slug, apiUrl) {
3209
3299
  // src/commands/projects/link.ts
3210
3300
  var execAsync3 = promisify4(exec3);
3211
3301
  async function runNpmInstall(startMessage = "Installing dependencies...") {
3212
- const spinner11 = clack13.spinner();
3302
+ const spinner11 = clack14.spinner();
3213
3303
  spinner11.start(startMessage);
3214
3304
  try {
3215
3305
  await execAsync3("npm install", { cwd: process.cwd(), maxBuffer: 10 * 1024 * 1024 });
3216
3306
  spinner11.stop("Dependencies installed");
3217
3307
  } catch (err) {
3218
3308
  spinner11.stop("Failed to install dependencies");
3219
- clack13.log.warn(`npm install failed: ${err.message}`);
3220
- clack13.log.info("Run `npm install` manually to install dependencies.");
3309
+ clack14.log.warn(`npm install failed: ${err.message}`);
3310
+ clack14.log.info("Run `npm install` manually to install dependencies.");
3221
3311
  }
3222
3312
  }
3223
3313
  async function runNpmSetupIfPresent() {
@@ -3229,15 +3319,15 @@ async function runNpmSetupIfPresent() {
3229
3319
  } catch {
3230
3320
  }
3231
3321
  if (!hasSetup) return;
3232
- const spinner11 = clack13.spinner();
3322
+ const spinner11 = clack14.spinner();
3233
3323
  spinner11.start("Running setup (schema + migrations)...");
3234
3324
  try {
3235
3325
  await execAsync3("npm run setup", { cwd: process.cwd(), maxBuffer: 20 * 1024 * 1024 });
3236
3326
  spinner11.stop("Setup complete");
3237
3327
  } catch (err) {
3238
3328
  spinner11.stop("Setup failed");
3239
- clack13.log.warn(`npm run setup failed: ${err.message.split("\n")[0]}`);
3240
- clack13.log.info("Inspect the error, fix DATABASE_URL or network access, then run `npm run setup` manually.");
3329
+ clack14.log.warn(`npm run setup failed: ${err.message.split("\n")[0]}`);
3330
+ clack14.log.info("Inspect the error, fix DATABASE_URL or network access, then run `npm run setup` manually.");
3241
3331
  }
3242
3332
  }
3243
3333
  function registerProjectLinkCommand(program2) {
@@ -3260,7 +3350,7 @@ function registerProjectLinkCommand(program2) {
3260
3350
  if (json) {
3261
3351
  outputJson({ success: true, skills_only: true });
3262
3352
  } else {
3263
- clack13.note(
3353
+ clack14.note(
3264
3354
  `Open your coding agent (Claude Code, Codex, Cursor, etc.) and ask it to build something. It will walk you through provisioning an InsForge project when needed. If you're not signed in yet, your browser will open for sign-in at that point.`,
3265
3355
  "What's next"
3266
3356
  );
@@ -3338,11 +3428,11 @@ function registerProjectLinkCommand(program2) {
3338
3428
  if (opts.auth) {
3339
3429
  try {
3340
3430
  const result = await applyAuthProvider(opts.auth, process.cwd(), projectConfig2, json);
3341
- if (!json) clack13.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3431
+ if (!json) clack14.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3342
3432
  } catch (err) {
3343
3433
  const msg = `Failed to apply --auth ${opts.auth}: ${err.message}`;
3344
3434
  if (json) console.error(JSON.stringify({ warning: msg }));
3345
- else clack13.log.warn(msg);
3435
+ else clack14.log.warn(msg);
3346
3436
  }
3347
3437
  }
3348
3438
  if (templateDownloaded && !json) {
@@ -3368,9 +3458,9 @@ function registerProjectLinkCommand(program2) {
3368
3458
  `${pc2.bold("1.")} ${runCommand}`,
3369
3459
  `${pc2.bold("2.")} Open ${pc2.cyan("Claude Code")} or ${pc2.cyan("Cursor")} and prompt your agent to add more features`
3370
3460
  ];
3371
- clack13.note(steps.join("\n"), "What's next");
3461
+ clack14.note(steps.join("\n"), "What's next");
3372
3462
  } else {
3373
- clack13.log.warn("Template download failed. You can retry or set up manually.");
3463
+ clack14.log.warn("Template download failed. You can retry or set up manually.");
3374
3464
  }
3375
3465
  }
3376
3466
  return;
@@ -3385,7 +3475,7 @@ function registerProjectLinkCommand(program2) {
3385
3475
  try {
3386
3476
  const result = await applyAuthProvider(opts.auth, process.cwd(), projectConfig2, json);
3387
3477
  if (!json) {
3388
- clack13.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3478
+ clack14.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3389
3479
  }
3390
3480
  if (result.packageJsonPatched && !json) {
3391
3481
  await runNpmInstall("Installing new dependencies...");
@@ -3394,7 +3484,7 @@ function registerProjectLinkCommand(program2) {
3394
3484
  } catch (err) {
3395
3485
  const msg = `Failed to apply --auth ${opts.auth}: ${err.message}`;
3396
3486
  if (json) console.error(JSON.stringify({ warning: msg }));
3397
- else clack13.log.warn(msg);
3487
+ else clack14.log.warn(msg);
3398
3488
  }
3399
3489
  }
3400
3490
  trackCommand("link", "oss-org", { direct: true });
@@ -3424,7 +3514,7 @@ function registerProjectLinkCommand(program2) {
3424
3514
  }
3425
3515
  if (orgs.length === 1) {
3426
3516
  orgId = orgs[0].id;
3427
- if (!json) clack13.log.info(`Using organization: ${orgs[0].name}`);
3517
+ if (!json) clack14.log.info(`Using organization: ${orgs[0].name}`);
3428
3518
  } else {
3429
3519
  if (json) {
3430
3520
  throw new CLIError("Multiple organizations found. Specify --org-id.");
@@ -3535,11 +3625,11 @@ function registerProjectLinkCommand(program2) {
3535
3625
  if (opts.auth) {
3536
3626
  try {
3537
3627
  const result = await applyAuthProvider(opts.auth, process.cwd(), projectConfig, json);
3538
- if (!json) clack13.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3628
+ if (!json) clack14.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3539
3629
  } catch (err) {
3540
3630
  const msg = `Failed to apply --auth ${opts.auth}: ${err.message}`;
3541
3631
  if (json) console.error(JSON.stringify({ warning: msg }));
3542
- else clack13.log.warn(msg);
3632
+ else clack14.log.warn(msg);
3543
3633
  }
3544
3634
  }
3545
3635
  if (templateDownloaded && !json) {
@@ -3552,16 +3642,16 @@ function registerProjectLinkCommand(program2) {
3552
3642
  await reportCliUsage("cli.link", true, 6, projectConfig);
3553
3643
  if (!json) {
3554
3644
  const dashboardUrl = `${getFrontendUrl()}/dashboard/project/${project.id}`;
3555
- clack13.log.step(`Dashboard: ${pc2.underline(dashboardUrl)}`);
3645
+ clack14.log.step(`Dashboard: ${pc2.underline(dashboardUrl)}`);
3556
3646
  if (templateDownloaded) {
3557
3647
  const runCommand = `${pc2.cyan("cd")} ${pc2.green(dirName)} ${pc2.dim("&&")} ${pc2.cyan("npm run dev")}`;
3558
3648
  const steps = [
3559
3649
  `${pc2.bold("1.")} ${runCommand}`,
3560
3650
  `${pc2.bold("2.")} Open ${pc2.cyan("Claude Code")} or ${pc2.cyan("Cursor")} and prompt your agent to add more features`
3561
3651
  ];
3562
- clack13.note(steps.join("\n"), "What's next");
3652
+ clack14.note(steps.join("\n"), "What's next");
3563
3653
  } else {
3564
- clack13.log.warn("Template download failed. You can retry or set up manually.");
3654
+ clack14.log.warn("Template download failed. You can retry or set up manually.");
3565
3655
  }
3566
3656
  }
3567
3657
  } else {
@@ -3569,7 +3659,7 @@ function registerProjectLinkCommand(program2) {
3569
3659
  try {
3570
3660
  const result = await applyAuthProvider(opts.auth, process.cwd(), projectConfig, json);
3571
3661
  if (!json) {
3572
- clack13.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3662
+ clack14.log.success(`Wired in ${opts.auth}: ${result.written.length} new, ${result.overwritten.length} replaced`);
3573
3663
  }
3574
3664
  if (result.packageJsonPatched && !json) {
3575
3665
  await runNpmInstall("Installing new dependencies...");
@@ -3578,20 +3668,20 @@ function registerProjectLinkCommand(program2) {
3578
3668
  } catch (err) {
3579
3669
  const msg = `Failed to apply --auth ${opts.auth}: ${err.message}`;
3580
3670
  if (json) console.error(JSON.stringify({ warning: msg }));
3581
- else clack13.log.warn(msg);
3671
+ else clack14.log.warn(msg);
3582
3672
  }
3583
3673
  }
3584
3674
  await installSkills(json, opts.auth);
3585
3675
  await reportCliUsage("cli.link", true, 6, projectConfig);
3586
3676
  if (!json) {
3587
3677
  const dashboardUrl = `${getFrontendUrl()}/dashboard/project/${project.id}`;
3588
- clack13.log.step(`Dashboard: ${dashboardUrl}`);
3678
+ clack14.log.step(`Dashboard: ${dashboardUrl}`);
3589
3679
  const prompts = [
3590
3680
  "Build a todo app with Google OAuth sign-in",
3591
3681
  "Build an Instagram clone where users can upload photos, like, and comment",
3592
3682
  "Build an AI chatbot with conversation history and deploy it to a live URL"
3593
3683
  ];
3594
- clack13.note(
3684
+ clack14.note(
3595
3685
  `Open your coding agent (Claude Code, Codex, Cursor, etc.) and try:
3596
3686
 
3597
3687
  ${prompts.map((p3) => `\u2022 "${p3}"`).join("\n")}`,
@@ -3831,7 +3921,7 @@ function registerDbRpcCommand(dbCmd2) {
3831
3921
  }
3832
3922
 
3833
3923
  // src/commands/db/export.ts
3834
- import { writeFileSync as writeFileSync3 } from "fs";
3924
+ import { writeFileSync as writeFileSync4 } from "fs";
3835
3925
  function registerDbExportCommand(dbCmd2) {
3836
3926
  dbCmd2.command("export").description("Export database schema and/or data").option("--format <format>", "Export format: sql or json", "sql").option("--tables <tables>", "Comma-separated list of tables to export (default: all)").option("--no-data", "Exclude table data (schema only)").option("--include-functions", "Include database functions").option("--include-sequences", "Include sequences").option("--include-views", "Include views").option("--row-limit <n>", "Maximum rows per table").option("-o, --output <file>", "Output file path (default: stdout)").action(async (opts, cmd) => {
3837
3927
  const { json } = getRootOpts(cmd);
@@ -3871,7 +3961,7 @@ function registerDbExportCommand(dbCmd2) {
3871
3961
  return;
3872
3962
  }
3873
3963
  if (opts.output) {
3874
- writeFileSync3(opts.output, content);
3964
+ writeFileSync4(opts.output, content);
3875
3965
  const tableCount = meta?.tables?.length;
3876
3966
  const suffix = tableCount ? ` (${tableCount} tables, format: ${meta?.format ?? opts.format})` : "";
3877
3967
  outputSuccess(`Exported to ${opts.output}${suffix}`);
@@ -3885,7 +3975,7 @@ function registerDbExportCommand(dbCmd2) {
3885
3975
  }
3886
3976
 
3887
3977
  // src/commands/db/import.ts
3888
- import { readFileSync as readFileSync3 } from "fs";
3978
+ import { readFileSync as readFileSync4 } from "fs";
3889
3979
  import { basename as basename5 } from "path";
3890
3980
  function registerDbImportCommand(dbCmd2) {
3891
3981
  dbCmd2.command("import <file>").description("Import database from a local SQL file").option("--truncate", "Truncate existing tables before import").action(async (file, opts, cmd) => {
@@ -3894,7 +3984,7 @@ function registerDbImportCommand(dbCmd2) {
3894
3984
  await requireAuth();
3895
3985
  const config = getProjectConfig();
3896
3986
  if (!config) throw new ProjectNotLinkedError();
3897
- const fileContent = readFileSync3(file);
3987
+ const fileContent = readFileSync4(file);
3898
3988
  const fileName = basename5(file);
3899
3989
  const formData = new FormData();
3900
3990
  formData.append("file", new Blob([fileContent]), fileName);
@@ -3925,12 +4015,12 @@ function registerDbImportCommand(dbCmd2) {
3925
4015
  }
3926
4016
 
3927
4017
  // src/commands/db/migrations.ts
3928
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
3929
- import { join as join9 } from "path";
4018
+ import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
4019
+ import { join as join10 } from "path";
3930
4020
 
3931
4021
  // src/lib/migrations.ts
3932
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync } from "fs";
3933
- import { join as join8 } from "path";
4022
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
4023
+ import { join as join9 } from "path";
3934
4024
  var MIGRATION_VERSION_REGEX = /^\d{1,64}$/u;
3935
4025
  var MIGRATION_FILENAME_REGEX = /^(\d{1,64})_([a-z0-9-]+)\.sql$/u;
3936
4026
  function assertValidMigrationVersion(version) {
@@ -3994,18 +4084,18 @@ function incrementMigrationVersion(version) {
3994
4084
  return formatMigrationVersion(new Date(nextTimestamp));
3995
4085
  }
3996
4086
  function getMigrationsDir(cwd = process.cwd()) {
3997
- return join8(cwd, "migrations");
4087
+ return join9(cwd, "migrations");
3998
4088
  }
3999
4089
  function ensureMigrationsDir(cwd = process.cwd()) {
4000
4090
  const migrationsDir = getMigrationsDir(cwd);
4001
- if (!existsSync4(migrationsDir)) {
4091
+ if (!existsSync5(migrationsDir)) {
4002
4092
  mkdirSync2(migrationsDir, { recursive: true });
4003
4093
  }
4004
4094
  return migrationsDir;
4005
4095
  }
4006
4096
  function listLocalMigrationFilenames(cwd = process.cwd()) {
4007
4097
  const migrationsDir = getMigrationsDir(cwd);
4008
- if (!existsSync4(migrationsDir)) {
4098
+ if (!existsSync5(migrationsDir)) {
4009
4099
  return [];
4010
4100
  }
4011
4101
  return readdirSync(migrationsDir).sort((left, right) => left.localeCompare(right));
@@ -4193,12 +4283,12 @@ function registerDbMigrationsCommand(dbCmd2) {
4193
4283
  migration.version,
4194
4284
  migration.name
4195
4285
  );
4196
- const filePath = join9(migrationsDir, filename);
4197
- if (existingLocalVersions.has(migration.version) || existsSync5(filePath)) {
4286
+ const filePath = join10(migrationsDir, filename);
4287
+ if (existingLocalVersions.has(migration.version) || existsSync6(filePath)) {
4198
4288
  skippedFiles.push(filename);
4199
4289
  continue;
4200
4290
  }
4201
- writeFileSync4(filePath, formatMigrationSql(migration.statements));
4291
+ writeFileSync5(filePath, formatMigrationSql(migration.statements));
4202
4292
  createdFiles.push(filename);
4203
4293
  existingLocalVersions.add(migration.version);
4204
4294
  }
@@ -4236,9 +4326,9 @@ function registerDbMigrationsCommand(dbCmd2) {
4236
4326
  );
4237
4327
  const filename = buildMigrationFilename(nextVersion, migrationName);
4238
4328
  const migrationsDir = ensureMigrationsDir();
4239
- const filePath = join9(migrationsDir, filename);
4329
+ const filePath = join10(migrationsDir, filename);
4240
4330
  try {
4241
- writeFileSync4(filePath, "", { flag: "wx" });
4331
+ writeFileSync5(filePath, "", { flag: "wx" });
4242
4332
  } catch (error) {
4243
4333
  if (error.code === "EEXIST") {
4244
4334
  throw new CLIError(`Migration file already exists: ${filename}`);
@@ -4294,11 +4384,11 @@ function registerDbMigrationsCommand(dbCmd2) {
4294
4384
  `Migration ${targetMigration.filename} is not the next pending local migration. Apply ${earlierPendingMigration.filename} first, or fix/delete it locally if it is invalid or no longer needed.`
4295
4385
  );
4296
4386
  }
4297
- const filePath = join9(getMigrationsDir(), targetMigration.filename);
4298
- if (!existsSync5(filePath)) {
4387
+ const filePath = join10(getMigrationsDir(), targetMigration.filename);
4388
+ if (!existsSync6(filePath)) {
4299
4389
  throw new CLIError(`Local migration file not found: ${targetMigration.filename}`);
4300
4390
  }
4301
- const sql = readFileSync4(filePath, "utf-8");
4391
+ const sql = readFileSync5(filePath, "utf-8");
4302
4392
  if (!sql.trim()) {
4303
4393
  throw new CLIError(`Migration file is empty: ${targetMigration.filename}`);
4304
4394
  }
@@ -4360,11 +4450,11 @@ function registerDbMigrationsCommand(dbCmd2) {
4360
4450
  }
4361
4451
  }
4362
4452
  for (const migration of migrationsToApply) {
4363
- const filePath = join9(getMigrationsDir(), migration.filename);
4364
- if (!existsSync5(filePath)) {
4453
+ const filePath = join10(getMigrationsDir(), migration.filename);
4454
+ if (!existsSync6(filePath)) {
4365
4455
  throw new CLIError(`Local migration file not found: ${migration.filename}`);
4366
4456
  }
4367
- const sql = readFileSync4(filePath, "utf-8");
4457
+ const sql = readFileSync5(filePath, "utf-8");
4368
4458
  if (!sql.trim()) {
4369
4459
  throw new CLIError(`Migration file is empty: ${migration.filename}`);
4370
4460
  }
@@ -4593,12 +4683,12 @@ function registerFunctionsCommands(functionsCmd2) {
4593
4683
  }
4594
4684
 
4595
4685
  // src/commands/functions/deploy.ts
4596
- import { readFileSync as readFileSync5, existsSync as existsSync6 } from "fs";
4686
+ import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
4597
4687
  function resolveDeployFilePath(opts) {
4598
4688
  if (!opts.file) {
4599
4689
  throw new CLIError("Missing required option: --file <path>");
4600
4690
  }
4601
- if (!existsSync6(opts.file)) {
4691
+ if (!existsSync7(opts.file)) {
4602
4692
  throw new CLIError(`Source file not found: ${opts.file}`);
4603
4693
  }
4604
4694
  return opts.file;
@@ -4609,7 +4699,7 @@ function registerFunctionsDeployCommand(functionsCmd2) {
4609
4699
  try {
4610
4700
  await requireAuth();
4611
4701
  const filePath = resolveDeployFilePath(opts);
4612
- const code = readFileSync5(filePath, "utf-8");
4702
+ const code = readFileSync6(filePath, "utf-8");
4613
4703
  const name = opts.name ?? slug;
4614
4704
  const description = opts.description ?? "";
4615
4705
  let exists = false;
@@ -4730,7 +4820,7 @@ function registerFunctionsCodeCommand(functionsCmd2) {
4730
4820
  }
4731
4821
 
4732
4822
  // src/commands/functions/delete.ts
4733
- import * as clack14 from "@clack/prompts";
4823
+ import * as clack15 from "@clack/prompts";
4734
4824
  function registerFunctionsDeleteCommand(functionsCmd2) {
4735
4825
  functionsCmd2.command("delete <slug>").description("Delete an edge function").action(async (slug, _opts, cmd) => {
4736
4826
  const { json, yes } = getRootOpts(cmd);
@@ -4741,7 +4831,7 @@ function registerFunctionsDeleteCommand(functionsCmd2) {
4741
4831
  message: `Delete function "${slug}"? This cannot be undone.`
4742
4832
  });
4743
4833
  if (isCancel2(confirmed) || !confirmed) {
4744
- clack14.log.info("Cancelled.");
4834
+ clack15.log.info("Cancelled.");
4745
4835
  return;
4746
4836
  }
4747
4837
  }
@@ -4796,7 +4886,7 @@ function registerStorageBucketsCommand(storageCmd2) {
4796
4886
  }
4797
4887
 
4798
4888
  // src/commands/storage/upload.ts
4799
- import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
4889
+ import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
4800
4890
  import { basename as basename6 } from "path";
4801
4891
  function registerStorageUploadCommand(storageCmd2) {
4802
4892
  storageCmd2.command("upload <file>").description("Upload a file to a storage bucket").requiredOption("--bucket <name>", "Target bucket name").option("--key <objectKey>", "Object key (defaults to filename)").action(async (file, opts, cmd) => {
@@ -4805,10 +4895,10 @@ function registerStorageUploadCommand(storageCmd2) {
4805
4895
  await requireAuth();
4806
4896
  const config = getProjectConfig();
4807
4897
  if (!config) throw new ProjectNotLinkedError();
4808
- if (!existsSync7(file)) {
4898
+ if (!existsSync8(file)) {
4809
4899
  throw new CLIError(`File not found: ${file}`);
4810
4900
  }
4811
- const fileContent = readFileSync6(file);
4901
+ const fileContent = readFileSync7(file);
4812
4902
  const objectKey = opts.key ?? basename6(file);
4813
4903
  const bucketName = opts.bucket;
4814
4904
  const formData = new FormData();
@@ -4839,8 +4929,8 @@ function registerStorageUploadCommand(storageCmd2) {
4839
4929
  }
4840
4930
 
4841
4931
  // src/commands/storage/download.ts
4842
- import { writeFileSync as writeFileSync5 } from "fs";
4843
- import { join as join10, basename as basename7 } from "path";
4932
+ import { writeFileSync as writeFileSync6 } from "fs";
4933
+ import { join as join11, basename as basename7 } from "path";
4844
4934
  function registerStorageDownloadCommand(storageCmd2) {
4845
4935
  storageCmd2.command("download <objectKey>").description("Download a file from a storage bucket").requiredOption("--bucket <name>", "Source bucket name").option("--output <path>", "Output file path (defaults to current directory)").action(async (objectKey, opts, cmd) => {
4846
4936
  const { json } = getRootOpts(cmd);
@@ -4860,8 +4950,8 @@ function registerStorageDownloadCommand(storageCmd2) {
4860
4950
  throw new CLIError(err.error ?? `Download failed: ${res.status}`);
4861
4951
  }
4862
4952
  const buffer = Buffer.from(await res.arrayBuffer());
4863
- const outputPath = opts.output ?? join10(process.cwd(), basename7(objectKey));
4864
- writeFileSync5(outputPath, buffer);
4953
+ const outputPath = opts.output ?? join11(process.cwd(), basename7(objectKey));
4954
+ writeFileSync6(outputPath, buffer);
4865
4955
  if (json) {
4866
4956
  outputJson({ success: true, path: outputPath, size: buffer.length });
4867
4957
  } else {
@@ -5991,16 +6081,16 @@ function registerComputeEventsCommand(computeCmd2) {
5991
6081
  }
5992
6082
 
5993
6083
  // src/commands/compute/deploy.ts
5994
- import { existsSync as existsSync9 } from "fs";
5995
- import { join as join12, resolve as resolve4 } from "path";
6084
+ import { existsSync as existsSync10 } from "fs";
6085
+ import { join as join13, resolve as resolve4 } from "path";
5996
6086
 
5997
6087
  // src/lib/env-file.ts
5998
- import { readFileSync as readFileSync7 } from "fs";
6088
+ import { readFileSync as readFileSync8 } from "fs";
5999
6089
  var ENV_KEY_REGEX2 = /^[A-Z_][A-Z0-9_]*$/;
6000
6090
  function parseEnvFile(path6) {
6001
6091
  let raw;
6002
6092
  try {
6003
- raw = readFileSync7(path6, "utf-8");
6093
+ raw = readFileSync8(path6, "utf-8");
6004
6094
  } catch (err) {
6005
6095
  const msg = err instanceof Error ? err.message : String(err);
6006
6096
  throw new CLIError(`Could not read --env-file at ${path6}: ${msg}`);
@@ -6036,8 +6126,8 @@ function parseEnvFile(path6) {
6036
6126
 
6037
6127
  // src/lib/flyctl.ts
6038
6128
  import { spawn, spawnSync } from "child_process";
6039
- import { existsSync as existsSync8, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3 } from "fs";
6040
- import { join as join11 } from "path";
6129
+ import { existsSync as existsSync9, writeFileSync as writeFileSync7, unlinkSync as unlinkSync3 } from "fs";
6130
+ import { join as join12 } from "path";
6041
6131
  function ensureFlyctlAvailable() {
6042
6132
  const r = spawnSync("flyctl", ["version"], {
6043
6133
  encoding: "utf8",
@@ -6050,8 +6140,8 @@ function ensureFlyctlAvailable() {
6050
6140
  }
6051
6141
  }
6052
6142
  function ensureFlyTomlStub(opts) {
6053
- const path6 = join11(opts.dir, "fly.toml");
6054
- if (existsSync8(path6)) {
6143
+ const path6 = join12(opts.dir, "fly.toml");
6144
+ if (existsSync9(path6)) {
6055
6145
  return () => {
6056
6146
  };
6057
6147
  }
@@ -6068,7 +6158,7 @@ primary_region = "${opts.region}"
6068
6158
  auto_start_machines = true
6069
6159
  min_machines_running = 0
6070
6160
  `;
6071
- writeFileSync6(path6, stub, "utf8");
6161
+ writeFileSync7(path6, stub, "utf8");
6072
6162
  return () => {
6073
6163
  try {
6074
6164
  unlinkSync3(path6);
@@ -6238,8 +6328,8 @@ function registerComputeDeployCommand(computeCmd2) {
6238
6328
  return;
6239
6329
  }
6240
6330
  const absDir = resolve4(dir);
6241
- const dockerfilePath = join12(absDir, "Dockerfile");
6242
- if (!existsSync9(dockerfilePath)) {
6331
+ const dockerfilePath = join13(absDir, "Dockerfile");
6332
+ if (!existsSync10(dockerfilePath)) {
6243
6333
  throw new CLIError(
6244
6334
  `No Dockerfile at ${dockerfilePath}.
6245
6335
  Either:
@@ -6474,7 +6564,7 @@ function formatSize2(gb) {
6474
6564
 
6475
6565
  // src/commands/diagnose/index.ts
6476
6566
  import * as os from "os";
6477
- import * as clack15 from "@clack/prompts";
6567
+ import * as clack16 from "@clack/prompts";
6478
6568
 
6479
6569
  // src/commands/diagnose/metrics.ts
6480
6570
  var METRIC_LABELS = {
@@ -7015,10 +7105,10 @@ function registerDiagnoseCommands(diagnoseCmd2) {
7015
7105
  if (question.length === 0 || question.length > 2e3) {
7016
7106
  throw new CLIError("Question must be between 1 and 2000 characters.");
7017
7107
  }
7018
- const s = !json ? clack15.spinner() : null;
7108
+ const s = !json ? clack16.spinner() : null;
7019
7109
  s?.start("Collecting diagnostic data...");
7020
7110
  const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
7021
- const cliVersion = "0.1.82";
7111
+ const cliVersion = "0.1.84";
7022
7112
  s?.stop("Data collected");
7023
7113
  if (!json) {
7024
7114
  console.log(`
@@ -7151,9 +7241,9 @@ function registerDiagnoseCommands(diagnoseCmd2) {
7151
7241
  void 0,
7152
7242
  apiUrl
7153
7243
  );
7154
- clack15.log.success("Thanks for your feedback!");
7244
+ clack16.log.success("Thanks for your feedback!");
7155
7245
  } catch {
7156
- clack15.log.warn("Failed to submit rating.");
7246
+ clack16.log.warn("Failed to submit rating.");
7157
7247
  }
7158
7248
  }
7159
7249
  }
@@ -8382,7 +8472,7 @@ function registerPaymentsCommands(paymentsCmd2) {
8382
8472
  }
8383
8473
 
8384
8474
  // src/commands/posthog/setup.ts
8385
- import * as clack16 from "@clack/prompts";
8475
+ import * as clack17 from "@clack/prompts";
8386
8476
  import pc3 from "picocolors";
8387
8477
 
8388
8478
  // src/lib/api/posthog.ts
@@ -8567,6 +8657,8 @@ function registerPosthogSetupCommand(program2) {
8567
8657
  }
8568
8658
  } catch (err) {
8569
8659
  handleError(err, json);
8660
+ } finally {
8661
+ await shutdownAnalytics();
8570
8662
  }
8571
8663
  });
8572
8664
  }
@@ -8579,13 +8671,14 @@ async function runSetup(opts) {
8579
8671
  if (!token) {
8580
8672
  throw new AuthError("Not logged in. Run `insforge login` first.");
8581
8673
  }
8674
+ trackPosthog("setup", proj);
8582
8675
  if (!opts.json) {
8583
- clack16.intro("PostHog setup");
8676
+ clack17.intro("PostHog setup");
8584
8677
  outputSuccess(`Linked to InsForge project: ${proj.project_name} (${proj.project_id})`);
8585
8678
  }
8586
8679
  const dashboardConnection = await ensureDashboardConnection(proj.project_id, token, opts);
8587
8680
  if (!opts.json) {
8588
- clack16.note(
8681
+ clack17.note(
8589
8682
  `Run this in your terminal to wire PostHog into your app code:
8590
8683
 
8591
8684
  ${WIZARD_COMMAND}
@@ -8623,13 +8716,13 @@ async function runConnectFlow(projectId, token, authorizeUrl, opts) {
8623
8716
  `);
8624
8717
  process.stderr.write("Your browser should open automatically. If not, copy the URL above.\n");
8625
8718
  } else {
8626
- clack16.log.info("PostHog is not yet connected to your InsForge dashboard.");
8719
+ clack17.log.info("PostHog is not yet connected to your InsForge dashboard.");
8627
8720
  if (opts.skipBrowser) {
8628
- clack16.log.info(`Open this URL to authorize PostHog:
8721
+ clack17.log.info(`Open this URL to authorize PostHog:
8629
8722
  ${pc3.cyan(pc3.underline(authorizeUrl))}`);
8630
8723
  } else {
8631
- clack16.log.info("Opening browser to authorize PostHog...");
8632
- clack16.log.info(`If browser doesn't open, visit:
8724
+ clack17.log.info("Opening browser to authorize PostHog...");
8725
+ clack17.log.info(`If browser doesn't open, visit:
8633
8726
  ${pc3.cyan(pc3.underline(authorizeUrl))}`);
8634
8727
  }
8635
8728
  }
@@ -8640,11 +8733,11 @@ ${pc3.cyan(pc3.underline(authorizeUrl))}`);
8640
8733
  } catch {
8641
8734
  }
8642
8735
  }
8643
- const spinner11 = !opts.json && isInteractive ? clack16.spinner() : null;
8736
+ const spinner11 = !opts.json && isInteractive ? clack17.spinner() : null;
8644
8737
  if (spinner11) {
8645
8738
  spinner11.start("Waiting for InsForge dashboard connection... (timeout: 15 minutes)");
8646
8739
  } else if (!opts.json) {
8647
- clack16.log.info("Waiting for InsForge dashboard connection (up to 15 minutes)...");
8740
+ clack17.log.info("Waiting for InsForge dashboard connection (up to 15 minutes)...");
8648
8741
  }
8649
8742
  try {
8650
8743
  await pollPosthogConnection(
@@ -8668,20 +8761,20 @@ ${pc3.cyan(pc3.underline(authorizeUrl))}`);
8668
8761
  if (spinner11) {
8669
8762
  spinner11.stop("InsForge dashboard connection received.");
8670
8763
  } else if (!opts.json) {
8671
- clack16.log.success("InsForge dashboard connection received.");
8764
+ clack17.log.success("InsForge dashboard connection received.");
8672
8765
  }
8673
8766
  } catch (err) {
8674
8767
  if (spinner11) {
8675
8768
  spinner11.stop("InsForge dashboard connection wait failed.");
8676
8769
  } else if (!opts.json) {
8677
- clack16.log.error("InsForge dashboard connection wait failed.");
8770
+ clack17.log.error("InsForge dashboard connection wait failed.");
8678
8771
  }
8679
8772
  throw err;
8680
8773
  }
8681
8774
  }
8682
8775
 
8683
8776
  // src/commands/config/export.ts
8684
- import { writeFileSync as writeFileSync7, existsSync as existsSync10 } from "fs";
8777
+ import { writeFileSync as writeFileSync8, existsSync as existsSync11 } from "fs";
8685
8778
  import { resolve as resolve5 } from "path";
8686
8779
  import * as p from "@clack/prompts";
8687
8780
  import pc4 from "picocolors";
@@ -9167,7 +9260,7 @@ function registerConfigExportCommand(cfg) {
9167
9260
  projectConfig = getProjectConfig();
9168
9261
  await requireAuth();
9169
9262
  const target = resolve5(process.cwd(), opts.out);
9170
- if (existsSync10(target) && !opts.force) {
9263
+ if (existsSync11(target) && !opts.force) {
9171
9264
  if (json) {
9172
9265
  throw new CLIError(
9173
9266
  `${opts.out} exists. Re-run with --force to overwrite.`,
@@ -9194,7 +9287,7 @@ function registerConfigExportCommand(cfg) {
9194
9287
  const raw = await res.json();
9195
9288
  const { config, skipped } = configFromMetadata(raw);
9196
9289
  const toml = stringifyConfigToml(config);
9197
- writeFileSync7(target, toml, "utf8");
9290
+ writeFileSync8(target, toml, "utf8");
9198
9291
  if (json) {
9199
9292
  console.log(JSON.stringify({ written: target, config, skipped }, null, 2));
9200
9293
  } else {
@@ -9230,7 +9323,7 @@ function registerConfigExportCommand(cfg) {
9230
9323
  }
9231
9324
 
9232
9325
  // src/commands/config/plan.ts
9233
- import { readFileSync as readFileSync8 } from "fs";
9326
+ import { readFileSync as readFileSync9 } from "fs";
9234
9327
  import { resolve as resolve6 } from "path";
9235
9328
  import pc5 from "picocolors";
9236
9329
 
@@ -9538,7 +9631,7 @@ function registerConfigPlanCommand(cfg) {
9538
9631
  projectConfig = getProjectConfig();
9539
9632
  await requireAuth();
9540
9633
  const tomlPath = resolve6(process.cwd(), opts.file);
9541
- const tomlSource = readFileSync8(tomlPath, "utf8");
9634
+ const tomlSource = readFileSync9(tomlPath, "utf8");
9542
9635
  const file = parseConfigToml(tomlSource);
9543
9636
  const res = await ossFetch("/api/metadata");
9544
9637
  const raw = await res.json();
@@ -9582,7 +9675,7 @@ function registerConfigPlanCommand(cfg) {
9582
9675
  }
9583
9676
 
9584
9677
  // src/commands/config/apply.ts
9585
- import { readFileSync as readFileSync9 } from "fs";
9678
+ import { readFileSync as readFileSync10 } from "fs";
9586
9679
  import { resolve as resolve7 } from "path";
9587
9680
  import * as p2 from "@clack/prompts";
9588
9681
  import pc6 from "picocolors";
@@ -9594,7 +9687,7 @@ function registerConfigApplyCommand(cfg) {
9594
9687
  projectConfig = getProjectConfig();
9595
9688
  await requireAuth();
9596
9689
  const tomlPath = resolve7(process.cwd(), opts.file);
9597
- const tomlSource = readFileSync9(tomlPath, "utf8");
9690
+ const tomlSource = readFileSync10(tomlPath, "utf8");
9598
9691
  const file = parseConfigToml(tomlSource);
9599
9692
  const res = await ossFetch("/api/metadata");
9600
9693
  const raw = await res.json();
@@ -9783,9 +9876,9 @@ function registerConfigCommand(program2) {
9783
9876
  }
9784
9877
 
9785
9878
  // src/commands/ai/setup.ts
9786
- import { appendFileSync as appendFileSync2, existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
9787
- import { isAbsolute, join as join13, relative as relative3, resolve as resolve8 } from "path";
9788
- import * as clack17 from "@clack/prompts";
9879
+ import { appendFileSync as appendFileSync2, existsSync as existsSync13, readFileSync as readFileSync12 } from "fs";
9880
+ import { isAbsolute, join as join14, relative as relative3, resolve as resolve8 } from "path";
9881
+ import * as clack18 from "@clack/prompts";
9789
9882
  import pc7 from "picocolors";
9790
9883
 
9791
9884
  // src/lib/api/ai.ts
@@ -9806,7 +9899,7 @@ async function getOpenRouterApiKey() {
9806
9899
  }
9807
9900
 
9808
9901
  // src/lib/env-writer.ts
9809
- import { existsSync as existsSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
9902
+ import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
9810
9903
  var KEY_LINE_RE = (key) => (
9811
9904
  // Match `KEY=...` at the start of a line (allowing leading whitespace).
9812
9905
  // Captures the value side; we only need the value portion to compare.
@@ -9821,8 +9914,8 @@ function stripQuotes(v) {
9821
9914
  return hash >= 0 ? t.slice(0, hash).trimEnd() : t;
9822
9915
  }
9823
9916
  function upsertEnvFile(path6, entries) {
9824
- const exists = existsSync11(path6);
9825
- let content = exists ? readFileSync10(path6, "utf-8") : "";
9917
+ const exists = existsSync12(path6);
9918
+ let content = exists ? readFileSync11(path6, "utf-8") : "";
9826
9919
  const result = { added: [], skipped: [], mismatched: [] };
9827
9920
  const additions = [];
9828
9921
  for (const [key, value] of Object.entries(entries)) {
@@ -9845,7 +9938,7 @@ function upsertEnvFile(path6, entries) {
9845
9938
  content += "\n";
9846
9939
  }
9847
9940
  content += additions.join("\n") + "\n";
9848
- writeFileSync8(path6, content);
9941
+ writeFileSync9(path6, content);
9849
9942
  } else if (!exists) {
9850
9943
  }
9851
9944
  return result;
@@ -9878,10 +9971,10 @@ async function runAiSetup(opts) {
9878
9971
  throw new ProjectNotLinkedError();
9879
9972
  }
9880
9973
  if (!opts.json) {
9881
- clack17.intro("AI setup");
9974
+ clack18.intro("AI setup");
9882
9975
  outputSuccess(`Linked to InsForge project: ${project.project_name} (${project.project_id})`);
9883
9976
  }
9884
- const spinner11 = !opts.json && isInteractive ? clack17.spinner() : null;
9977
+ const spinner11 = !opts.json && isInteractive ? clack18.spinner() : null;
9885
9978
  spinner11?.start("Fetching OpenRouter key...");
9886
9979
  let key;
9887
9980
  try {
@@ -9914,7 +10007,7 @@ async function runAiSetup(opts) {
9914
10007
  outputInfo(pc7.dim(`${envLabel}: ${update.skipped.join(", ")} already set (matching) - left as-is.`));
9915
10008
  }
9916
10009
  for (const m of update.mismatched) {
9917
- clack17.log.warn(
10010
+ clack18.log.warn(
9918
10011
  `${envLabel} already has ${m.key}; left existing value untouched. Remove it or pass --env-file to write elsewhere.`
9919
10012
  );
9920
10013
  }
@@ -9922,7 +10015,7 @@ async function runAiSetup(opts) {
9922
10015
  outputInfo(pc7.dim("Added .env*.local to .gitignore."));
9923
10016
  }
9924
10017
  if (!isLocalEnvFile(envFile)) {
9925
- clack17.log.warn(
10018
+ clack18.log.warn(
9926
10019
  `${envLabel} may be committed unless it is listed in .gitignore. Keep ${OPENROUTER_ENV_KEY} server-only.`
9927
10020
  );
9928
10021
  }
@@ -9930,7 +10023,7 @@ async function runAiSetup(opts) {
9930
10023
  outputInfo("Use this key only from server-side code as process.env.OPENROUTER_API_KEY.");
9931
10024
  outputInfo("For deployment, add OPENROUTER_API_KEY to your hosting provider environment.");
9932
10025
  outputInfo(`Do not rename it to ${pc7.bold("NEXT_PUBLIC_")}, ${pc7.bold("VITE_")}, or ${pc7.bold("PUBLIC_")}.`);
9933
- clack17.outro("Done.");
10026
+ clack18.outro("Done.");
9934
10027
  }
9935
10028
  return {
9936
10029
  envFile: envLabel,
@@ -9960,8 +10053,8 @@ function ensureLocalEnvIgnored(cwd, envFile) {
9960
10053
  if (!relEnvPath || relEnvPath.startsWith("..") || isAbsolute(relEnvPath)) {
9961
10054
  return false;
9962
10055
  }
9963
- const gitignorePath = join13(cwd, ".gitignore");
9964
- const existing = existsSync12(gitignorePath) ? readFileSync11(gitignorePath, "utf-8") : "";
10056
+ const gitignorePath = join14(cwd, ".gitignore");
10057
+ const existing = existsSync13(gitignorePath) ? readFileSync12(gitignorePath, "utf-8") : "";
9965
10058
  const lines = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
9966
10059
  const envBasename = envFile.replace(/\\/g, "/").split("/").pop() ?? envFile;
9967
10060
  if (lines.has(".env*") || lines.has(".env.*") || lines.has(".env*.local") || lines.has(".env.local") && envBasename === ".env.local") {
@@ -9982,7 +10075,7 @@ function registerAiCommands(aiCmd2) {
9982
10075
 
9983
10076
  // src/index.ts
9984
10077
  var __dirname = dirname2(fileURLToPath(import.meta.url));
9985
- var pkg = JSON.parse(readFileSync12(join14(__dirname, "../package.json"), "utf-8"));
10078
+ var pkg = JSON.parse(readFileSync13(join15(__dirname, "../package.json"), "utf-8"));
9986
10079
  var INSFORGE_LOGO = `
9987
10080
  \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
9988
10081
  \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
@@ -10093,7 +10186,7 @@ async function showInteractiveMenu() {
10093
10186
  } catch {
10094
10187
  }
10095
10188
  console.log(INSFORGE_LOGO);
10096
- clack18.intro(`InsForge CLI v${pkg.version}`);
10189
+ clack19.intro(`InsForge CLI v${pkg.version}`);
10097
10190
  const options = [];
10098
10191
  if (!isLoggedIn) {
10099
10192
  options.push({ value: "login", label: "Log in to InsForge" });
@@ -10114,7 +10207,7 @@ async function showInteractiveMenu() {
10114
10207
  options
10115
10208
  });
10116
10209
  if (isCancel2(action)) {
10117
- clack18.cancel("Bye!");
10210
+ clack19.cancel("Bye!");
10118
10211
  process.exit(0);
10119
10212
  }
10120
10213
  switch (action) {