@posthog/wizard 2.50.0 → 2.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/dist/{add-mcp-server-to-clients-Bd8XRxzi.js → add-mcp-server-to-clients-C1f2al7N.js} +5 -5
  2. package/dist/{add-mcp-server-to-clients-Bd8XRxzi.js.map → add-mcp-server-to-clients-C1f2al7N.js.map} +1 -1
  3. package/dist/{agent-interface-C_aRBziP.js → agent-interface-BL2wCV3b.js} +30 -69
  4. package/dist/agent-interface-BL2wCV3b.js.map +1 -0
  5. package/dist/agent-prompt-loader-CEWWA98d.js +275 -0
  6. package/dist/agent-prompt-loader-CEWWA98d.js.map +1 -0
  7. package/dist/{agent-runner-NzzrOB02.js → agent-runner-DSKXFDXa.js} +100 -318
  8. package/dist/agent-runner-DSKXFDXa.js.map +1 -0
  9. package/dist/{analytics-CArgq7XO.js → analytics-Ddf3zJgF.js} +2 -2
  10. package/dist/{analytics-CArgq7XO.js.map → analytics-Ddf3zJgF.js.map} +1 -1
  11. package/dist/analytics-GD_xM1XO.js +2 -0
  12. package/dist/{api-CX1g-14-.js → api-BdanR3Zp.js} +3 -3
  13. package/dist/{api-CX1g-14-.js.map → api-BdanR3Zp.js.map} +1 -1
  14. package/dist/bin.js +84 -86
  15. package/dist/bin.js.map +1 -1
  16. package/dist/bounded-fs-d0dw1Qv5.js +242 -0
  17. package/dist/bounded-fs-d0dw1Qv5.js.map +1 -0
  18. package/dist/{ci-install-BYThh_Gl.js → ci-install-DnVNVs0f.js} +4 -4
  19. package/dist/{ci-install-BYThh_Gl.js.map → ci-install-DnVNVs0f.js.map} +1 -1
  20. package/dist/commandments-BagyrYRW.js +2 -0
  21. package/dist/{commandments-DSNrOeOC.js → commandments-DiMtIz1o.js} +1 -1
  22. package/dist/{commandments-DSNrOeOC.js.map → commandments-DiMtIz1o.js.map} +1 -1
  23. package/dist/{debug-CdScMjI7.js → debug-By1_VtgZ.js} +1 -1
  24. package/dist/{debug-dX5JKcxf.js → debug-DaXKSXEy.js} +8 -27
  25. package/dist/debug-DaXKSXEy.js.map +1 -0
  26. package/dist/{defaults-CtWMmC8s.js → defaults-DAE9_QMn.js} +1 -1
  27. package/dist/{defaults-CtWMmC8s.js.map → defaults-DAE9_QMn.js.map} +1 -1
  28. package/dist/{env-api-key-C3LzH8Lr.js → env-api-key-DDVkPQmo.js} +1 -1
  29. package/dist/{env-api-key-C3LzH8Lr.js.map → env-api-key-DDVkPQmo.js.map} +1 -1
  30. package/dist/{environment-D-xSv8Xv.js → environment-DJQOs7MR.js} +4 -4
  31. package/dist/environment-DJQOs7MR.js.map +1 -0
  32. package/dist/{file-watcher-Z28w46F3.js → file-watcher-LZe_W3hM.js} +2 -2
  33. package/dist/{file-watcher-Z28w46F3.js.map → file-watcher-LZe_W3hM.js.map} +1 -1
  34. package/dist/{headless-ui-T-cv04Ne.js → headless-ui-wIeUgvJ8.js} +2 -2
  35. package/dist/{headless-ui-T-cv04Ne.js.map → headless-ui-wIeUgvJ8.js.map} +1 -1
  36. package/dist/{interactive-uhGISvkt.js → interactive-j4DoJDnk.js} +2 -2
  37. package/dist/{interactive-uhGISvkt.js.map → interactive-j4DoJDnk.js.map} +1 -1
  38. package/dist/{mcp-B9NosVx4.js → mcp-Butt7ktW.js} +2 -2
  39. package/dist/{mcp-B9NosVx4.js.map → mcp-Butt7ktW.js.map} +1 -1
  40. package/dist/{mcp-prompt-streaming-ByofAot4.js → mcp-prompt-streaming-D25BQfRa.js} +3 -3
  41. package/dist/{mcp-prompt-streaming-ByofAot4.js.map → mcp-prompt-streaming-D25BQfRa.js.map} +1 -1
  42. package/dist/{non-interactive-dGAp1rES.js → non-interactive-Cpof2JsA.js} +2 -2
  43. package/dist/{non-interactive-dGAp1rES.js.map → non-interactive-Cpof2JsA.js.map} +1 -1
  44. package/dist/{orchestrator-tools-9D5vTenD.js → orchestrator-tools-CsJizPpV.js} +3 -3
  45. package/dist/{orchestrator-tools-9D5vTenD.js.map → orchestrator-tools-CsJizPpV.js.map} +1 -1
  46. package/dist/{package-json-DCuoye-H.js → package-json-CDs1ZVKu.js} +1 -1
  47. package/dist/{package-json-DCuoye-H.js.map → package-json-CDs1ZVKu.js.map} +1 -1
  48. package/dist/{package-manager-D3M_H5Pk.js → package-manager-DnzNEjci.js} +2 -2
  49. package/dist/{package-manager-D3M_H5Pk.js.map → package-manager-DnzNEjci.js.map} +1 -1
  50. package/dist/{pi--w-M8eD-.js → pi-DE2cAVfO.js} +89 -138
  51. package/dist/pi-DE2cAVfO.js.map +1 -0
  52. package/dist/{playground-GURThvy5.js → playground-C3sLBq6A.js} +7 -7
  53. package/dist/{playground-GURThvy5.js.map → playground-C3sLBq6A.js.map} +1 -1
  54. package/dist/{posthog-integration-Dk1hbtRQ.js → posthog-integration-_GSKRotZ.js} +45 -38
  55. package/dist/posthog-integration-_GSKRotZ.js.map +1 -0
  56. package/dist/{posthog-DZZbziJ1.js → posthog-mgz-FQlS.js} +1 -1
  57. package/dist/{posthog-DZZbziJ1.js.map → posthog-mgz-FQlS.js.map} +1 -1
  58. package/dist/{provisioning-CJQwMFVo.js → provisioning-BndgugFk.js} +3 -3
  59. package/dist/{provisioning-CJQwMFVo.js.map → provisioning-BndgugFk.js.map} +1 -1
  60. package/dist/{queue-tools-DW-pUVKK.js → queue-tools-DZjAjiqk.js} +97 -10
  61. package/dist/queue-tools-DZjAjiqk.js.map +1 -0
  62. package/dist/{registry-CYNjgbAh.js → registry-BMjfECF2.js} +272 -429
  63. package/dist/registry-BMjfECF2.js.map +1 -0
  64. package/dist/{security-D9TV_nIO.js → security-D5hjYVFi.js} +4 -4
  65. package/dist/{security-D9TV_nIO.js.map → security-D5hjYVFi.js.map} +1 -1
  66. package/dist/{setup-utils-D5RLhAEe.js → setup-utils-ZKEk71yV.js} +14 -17
  67. package/dist/setup-utils-ZKEk71yV.js.map +1 -0
  68. package/dist/smoke-test.sh +1 -1
  69. package/dist/{start-tui-Dvk-0lGv.js → start-tui-B2Tb427o.js} +19 -19
  70. package/dist/{start-tui-Dvk-0lGv.js.map → start-tui-B2Tb427o.js.map} +1 -1
  71. package/dist/{steps-CcRX3kDT.js → steps-ClMZ6MZd.js} +7 -7
  72. package/dist/{steps-CcRX3kDT.js.map → steps-ClMZ6MZd.js.map} +1 -1
  73. package/dist/{store-DkQLlZF9.js → store-Db77bfRv.js} +5 -5
  74. package/dist/{store-DkQLlZF9.js.map → store-Db77bfRv.js.map} +1 -1
  75. package/dist/{subagent-Dxh0Pwgv.js → subagent--VXEEc8S.js} +2 -2
  76. package/dist/{subagent-Dxh0Pwgv.js.map → subagent--VXEEc8S.js.map} +1 -1
  77. package/dist/{task-C-r2xQvb.js → task-CBQfx_f5.js} +30 -45
  78. package/dist/task-CBQfx_f5.js.map +1 -0
  79. package/dist/{task-stream-_e6Mf24V.js → task-stream-DCrqCmFa.js} +5 -5
  80. package/dist/{task-stream-_e6Mf24V.js.map → task-stream-DCrqCmFa.js.map} +1 -1
  81. package/dist/{tasks-BqpaakPz.js → tasks-BJuz1XQ1.js} +2 -2
  82. package/dist/{tasks-BqpaakPz.js.map → tasks-BJuz1XQ1.js.map} +1 -1
  83. package/dist/{telemetry-CeQm0f0H.js → telemetry-tdU6F90U.js} +3 -3
  84. package/dist/{telemetry-CeQm0f0H.js.map → telemetry-tdU6F90U.js.map} +1 -1
  85. package/dist/{terminal-2gT6ezna.js → terminal-ClWui_UN.js} +13 -13
  86. package/dist/{terminal-2gT6ezna.js.map → terminal-ClWui_UN.js.map} +1 -1
  87. package/dist/{tools-C5Lsz2zR.js → tools-DwpaEyEv.js} +10 -8
  88. package/dist/tools-DwpaEyEv.js.map +1 -0
  89. package/dist/{wizard-abort-D_Xcbesm.js → wizard-abort-B1iPXM3K.js} +4 -4
  90. package/dist/{wizard-abort-D_Xcbesm.js.map → wizard-abort-B1iPXM3K.js.map} +1 -1
  91. package/dist/{wizard-abort-CaKAS9_Z.js → wizard-abort-cX4Kytai.js} +1 -1
  92. package/dist/{wizard-session-tp4Zdbwl.js → wizard-session-BAZql11N.js} +1 -1
  93. package/dist/{wizard-session-tp4Zdbwl.js.map → wizard-session-BAZql11N.js.map} +1 -1
  94. package/dist/{wizard-session-DWHe83uk.js → wizard-session-C5lZPPEc.js} +1 -1
  95. package/dist/{yara-hooks-CGzlyuQA.js → yara-hooks-CEs3jx7j.js} +139 -56
  96. package/dist/yara-hooks-CEs3jx7j.js.map +1 -0
  97. package/dist/yara-hooks-gz4AceFG.js +2 -0
  98. package/package.json +2 -2
  99. package/dist/agent-interface-C_aRBziP.js.map +0 -1
  100. package/dist/agent-runner-NzzrOB02.js.map +0 -1
  101. package/dist/analytics-C7QE7PWl.js +0 -2
  102. package/dist/commandments-qTW7pwaT.js +0 -2
  103. package/dist/debug-dX5JKcxf.js.map +0 -1
  104. package/dist/environment-D-xSv8Xv.js.map +0 -1
  105. package/dist/file-utils-BpTQ4NFR.js +0 -140
  106. package/dist/file-utils-BpTQ4NFR.js.map +0 -1
  107. package/dist/pi--w-M8eD-.js.map +0 -1
  108. package/dist/posthog-integration-Dk1hbtRQ.js.map +0 -1
  109. package/dist/queue-tools-DW-pUVKK.js.map +0 -1
  110. package/dist/registry-CYNjgbAh.js.map +0 -1
  111. package/dist/setup-utils-D5RLhAEe.js.map +0 -1
  112. package/dist/task-C-r2xQvb.js.map +0 -1
  113. package/dist/tools-C5Lsz2zR.js.map +0 -1
  114. package/dist/yara-hooks-CGzlyuQA.js.map +0 -1
  115. package/dist/yara-hooks-CQaKM0f4.js +0 -2
@@ -1,8 +1,9 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { f as getUI } from "./debug-dX5JKcxf.js";
3
- import { a as createVersionBucket, c as detectAllPackageManagers, i as tryGetPackageJson } from "./setup-utils-D5RLhAEe.js";
4
- import { n as getInstalledPackageVersion, r as hasDeclaredDependency, t as getDeclaredVersion } from "./package-json-DCuoye-H.js";
5
- import { a as gradlePackageManager, c as getPackageManagerName$1, i as detectPythonPackageManagers, l as getPythonVersion, n as composerPackageManager, o as swiftPackageManager, r as detectNodePackageManagers, s as detectPackageManager$1, t as bundlerPackageManager, u as getPythonVersionBucket } from "./package-manager-D3M_H5Pk.js";
2
+ import { f as getUI } from "./debug-DaXKSXEy.js";
3
+ import { r as readProjectFile, t as boundedGlob } from "./bounded-fs-d0dw1Qv5.js";
4
+ import { a as createVersionBucket, c as detectAllPackageManagers, i as tryGetPackageJson } from "./setup-utils-ZKEk71yV.js";
5
+ import { n as getInstalledPackageVersion, r as hasDeclaredDependency, t as getDeclaredVersion } from "./package-json-CDs1ZVKu.js";
6
+ import { a as gradlePackageManager, c as getPackageManagerName$1, i as detectPythonPackageManagers, l as getPythonVersion, n as composerPackageManager, o as swiftPackageManager, r as detectNodePackageManagers, s as detectPackageManager$1, t as bundlerPackageManager, u as getPythonVersionBucket } from "./package-manager-DnzNEjci.js";
6
7
  import * as semver from "semver";
7
8
  import { major, minVersion } from "semver";
8
9
  import path from "path";
@@ -12,26 +13,20 @@ import fg from "fast-glob";
12
13
  import fs from "fs/promises";
13
14
  //#region src/frameworks/nextjs/utils.ts
14
15
  const getNextJsVersionBucket = createVersionBucket();
15
- const IGNORE_PATTERNS$9 = [
16
- "**/node_modules/**",
17
- "**/dist/**",
18
- "**/build/**",
19
- "**/public/**",
20
- "**/.next/**"
21
- ];
16
+ const IGNORE_PATTERNS$1 = ["**/public/**"];
22
17
  /**
23
18
  * Detect Next.js router type. Pure — returns null if ambiguous.
24
19
  */
25
20
  async function getNextJsRouter({ installDir }) {
26
- const hasPagesDir = (await fg("**/pages/_app.@(ts|tsx|js|jsx)", {
27
- dot: true,
21
+ const hasPagesDir = (await boundedGlob("**/pages/_app.@(ts|tsx|js|jsx)", {
28
22
  cwd: installDir,
29
- ignore: IGNORE_PATTERNS$9
23
+ extraIgnore: IGNORE_PATTERNS$1,
24
+ limit: 1
30
25
  })).length > 0;
31
- const hasAppDir = (await fg("**/app/**/layout.@(ts|tsx|js|jsx)", {
32
- dot: true,
26
+ const hasAppDir = (await boundedGlob("**/app/**/layout.@(ts|tsx|js|jsx)", {
33
27
  cwd: installDir,
34
- ignore: IGNORE_PATTERNS$9
28
+ extraIgnore: IGNORE_PATTERNS$1,
29
+ limit: 1
35
30
  })).length > 0;
36
31
  if (hasPagesDir && !hasAppDir) return "pages-router";
37
32
  if (hasAppDir && !hasPagesDir) return "app-router";
@@ -215,47 +210,42 @@ const VUE_AGENT_CONFIG = {
215
210
  };
216
211
  //#endregion
217
212
  //#region src/frameworks/react-router/utils.ts
218
- const IGNORE_PATTERNS$8 = [
219
- "**/node_modules/**",
220
- "**/dist/**",
221
- "**/build/**",
222
- "**/public/**",
223
- "**/.next/**"
224
- ];
213
+ const EXTRA_IGNORE$11 = ["**/public/**"];
225
214
  const getReactRouterVersionBucket = createVersionBucket();
215
+ /** Content probes read at most this many files, one in memory at a time. */
216
+ const SOURCE_PROBE_LIMIT$5 = 200;
217
+ /** Files that set up a React Router — never a blanket source sweep. */
218
+ const ROUTER_FILE_GLOBS = [
219
+ "**/routes/**/*.@(ts|tsx|js|jsx)",
220
+ "**/*[Rr]out*.@(ts|tsx|js|jsx)",
221
+ "**/@(main|app|App|index|root).@(ts|tsx|js|jsx)"
222
+ ];
226
223
  async function hasReactRouterConfig({ installDir }) {
227
- return (await fg("**/react-router.config.@(ts|js|tsx|jsx)", {
228
- dot: true,
224
+ return (await boundedGlob("**/react-router.config.@(ts|js|tsx|jsx)", {
229
225
  cwd: installDir,
230
- ignore: IGNORE_PATTERNS$8
226
+ extraIgnore: EXTRA_IGNORE$11,
227
+ limit: 1
231
228
  })).length > 0;
232
229
  }
233
230
  async function hasCreateBrowserRouter({ installDir }) {
234
- const sourceFiles = await fg("**/*.@(ts|tsx|js|jsx)", {
235
- dot: true,
231
+ const sourceFiles = await boundedGlob(ROUTER_FILE_GLOBS, {
236
232
  cwd: installDir,
237
- ignore: IGNORE_PATTERNS$8
233
+ extraIgnore: EXTRA_IGNORE$11,
234
+ limit: SOURCE_PROBE_LIMIT$5
238
235
  });
239
- for (const file of sourceFiles) try {
240
- const filePath = path$1.join(installDir, file);
241
- if (fs$1.readFileSync(filePath, "utf-8").includes("createBrowserRouter")) return true;
242
- } catch {
243
- continue;
244
- }
236
+ for (const file of sourceFiles) if (readProjectFile(path$1.join(installDir, file))?.includes("createBrowserRouter")) return true;
245
237
  return false;
246
238
  }
247
239
  async function hasDeclarativeRouter({ installDir }) {
248
- const sourceFiles = await fg("**/*.@(ts|tsx|js|jsx)", {
249
- dot: true,
240
+ const sourceFiles = await boundedGlob(ROUTER_FILE_GLOBS, {
250
241
  cwd: installDir,
251
- ignore: IGNORE_PATTERNS$8
242
+ extraIgnore: EXTRA_IGNORE$11,
243
+ limit: SOURCE_PROBE_LIMIT$5
252
244
  });
253
- for (const file of sourceFiles) try {
254
- const filePath = path$1.join(installDir, file);
255
- const content = fs$1.readFileSync(filePath, "utf-8");
245
+ for (const file of sourceFiles) {
246
+ const content = readProjectFile(path$1.join(installDir, file));
247
+ if (!content) continue;
256
248
  if (content.includes("<BrowserRouter") || content.includes("BrowserRouter") && (content.includes("from \"react-router-dom\"") || content.includes("from 'react-router-dom'"))) return true;
257
- } catch {
258
- continue;
259
249
  }
260
250
  return false;
261
251
  }
@@ -354,20 +344,25 @@ const REACT_ROUTER_AGENT_CONFIG = {
354
344
  };
355
345
  //#endregion
356
346
  //#region src/frameworks/tanstack-router/utils.ts
357
- const IGNORE_PATTERNS$7 = [
358
- "**/node_modules/**",
359
- "**/dist/**",
360
- "**/build/**",
347
+ const EXTRA_IGNORE$10 = [
361
348
  "**/public/**",
362
349
  "**/.vinxi/**",
363
350
  "**/.output/**"
364
351
  ];
365
352
  const getTanStackRouterVersionBucket = createVersionBucket();
353
+ /** Content probes read at most this many files, one in memory at a time. */
354
+ const SOURCE_PROBE_LIMIT$4 = 200;
355
+ /** Files that define TanStack routes — never a blanket source sweep. */
356
+ const ROUTE_FILE_GLOBS = [
357
+ "**/routes/**/*.@(ts|tsx|js|jsx)",
358
+ "**/*[Rr]oute*.@(ts|tsx|js|jsx)",
359
+ "**/@(main|router|app|App|index).@(ts|tsx|js|jsx)"
360
+ ];
366
361
  async function hasFileBasedRouting({ installDir }) {
367
- if ((await fg("**/routeTree.gen.@(ts|tsx|js|jsx)", {
368
- dot: true,
362
+ if ((await boundedGlob("**/routeTree.gen.@(ts|tsx|js|jsx)", {
369
363
  cwd: installDir,
370
- ignore: IGNORE_PATTERNS$7
364
+ extraIgnore: EXTRA_IGNORE$10,
365
+ limit: 1
371
366
  })).length > 0) return true;
372
367
  try {
373
368
  const packageJsonPath = path$1.join(installDir, "package.json");
@@ -375,34 +370,27 @@ async function hasFileBasedRouting({ installDir }) {
375
370
  const packageJson = JSON.parse(content);
376
371
  if (hasDeclaredDependency("@tanstack/router-plugin", packageJson) || hasDeclaredDependency("@tanstack/router-vite-plugin", packageJson)) return true;
377
372
  } catch {}
378
- const sourceFiles = await fg("**/*.@(ts|tsx|js|jsx)", {
379
- dot: true,
373
+ const sourceFiles = await boundedGlob(ROUTE_FILE_GLOBS, {
380
374
  cwd: installDir,
381
- ignore: IGNORE_PATTERNS$7
375
+ extraIgnore: EXTRA_IGNORE$10,
376
+ limit: SOURCE_PROBE_LIMIT$4
382
377
  });
383
- for (const file of sourceFiles) try {
384
- const filePath = path$1.join(installDir, file);
385
- if (fs$1.readFileSync(filePath, "utf-8").includes("createFileRoute")) return true;
386
- } catch {
387
- continue;
388
- }
378
+ for (const file of sourceFiles) if (readProjectFile(path$1.join(installDir, file))?.includes("createFileRoute")) return true;
389
379
  return false;
390
380
  }
391
381
  async function hasCodeBasedRouting({ installDir }) {
392
- const sourceFiles = await fg("**/*.@(ts|tsx|js|jsx)", {
393
- dot: true,
382
+ const sourceFiles = await boundedGlob(ROUTE_FILE_GLOBS, {
394
383
  cwd: installDir,
395
- ignore: IGNORE_PATTERNS$7
384
+ extraIgnore: EXTRA_IGNORE$10,
385
+ limit: SOURCE_PROBE_LIMIT$4
396
386
  });
397
387
  let hasCreateRoute = false;
398
388
  let hasCreateFileRoute = false;
399
- for (const file of sourceFiles) try {
400
- const filePath = path$1.join(installDir, file);
401
- const content = fs$1.readFileSync(filePath, "utf-8");
389
+ for (const file of sourceFiles) {
390
+ const content = readProjectFile(path$1.join(installDir, file));
391
+ if (!content) continue;
402
392
  if (content.includes("createRoute(")) hasCreateRoute = true;
403
393
  if (content.includes("createFileRoute")) hasCreateFileRoute = true;
404
- } catch {
405
- continue;
406
394
  }
407
395
  return hasCreateRoute && !hasCreateFileRoute;
408
396
  }
@@ -663,19 +651,15 @@ const ANGULAR_AGENT_CONFIG = {
663
651
  //#endregion
664
652
  //#region src/frameworks/astro/utils.ts
665
653
  const getAstroVersionBucket = createVersionBucket();
666
- const IGNORE_PATTERNS$6 = [
667
- "**/node_modules/**",
668
- "**/dist/**",
669
- "**/.astro/**"
670
- ];
654
+ const EXTRA_IGNORE$9 = ["**/.astro/**"];
671
655
  /**
672
656
  * Detect the Astro rendering mode. Pure — always resolves (Astro detection is reliable).
673
657
  */
674
658
  async function getAstroRenderingMode({ installDir }) {
675
- const configMatches = await fg("astro.config.@(mjs|ts|js)", {
676
- dot: true,
659
+ const configMatches = await boundedGlob("astro.config.@(mjs|ts|js)", {
677
660
  cwd: installDir,
678
- ignore: IGNORE_PATTERNS$6
661
+ extraIgnore: EXTRA_IGNORE$9,
662
+ limit: 1
679
663
  });
680
664
  let hasAdapter = false;
681
665
  let outputMode = null;
@@ -695,19 +679,19 @@ async function getAstroRenderingMode({ installDir }) {
695
679
  const outputMatch = (await fs.readFile(configPath, "utf-8")).match(/output:\s*['"](\w+)['"]/);
696
680
  if (outputMatch) outputMode = outputMatch[1];
697
681
  } catch {}
698
- const viewTransitionMatches = await fg("**/*.@(astro|ts|tsx|js|jsx)", {
699
- dot: true,
682
+ const viewTransitionMatches = await boundedGlob("**/*.@(astro|ts|tsx|js|jsx)", {
700
683
  cwd: installDir,
701
- ignore: IGNORE_PATTERNS$6
684
+ extraIgnore: EXTRA_IGNORE$9,
685
+ limit: 20
702
686
  });
703
- for (const file of viewTransitionMatches.slice(0, 20)) try {
704
- const filePath = path.join(installDir, file);
705
- const content = await fs.readFile(filePath, "utf-8");
687
+ for (const file of viewTransitionMatches) {
688
+ const content = readProjectFile(path.join(installDir, file));
689
+ if (!content) continue;
706
690
  if (content.includes("ClientRouter") || content.includes("ViewTransitions") || content.includes("astro:transitions")) {
707
691
  usesViewTransitions = true;
708
692
  break;
709
693
  }
710
- } catch {}
694
+ }
711
695
  if (usesViewTransitions) return "view-transitions";
712
696
  if (outputMode === "server" && hasAdapter) return "ssr";
713
697
  if (hasAdapter) return "hybrid";
@@ -811,15 +795,9 @@ const PYTHON_PACKAGE_INSTALLATION = "Use the detect_package_manager tool to dete
811
795
  const SPINNER_MESSAGE = "Writing your PostHog setup with events, error capture and more...";
812
796
  //#endregion
813
797
  //#region src/frameworks/django/utils.ts
814
- const IGNORE_PATTERNS$5 = [
815
- "**/node_modules/**",
816
- "**/dist/**",
817
- "**/build/**",
818
- "**/venv/**",
819
- "**/.venv/**",
798
+ const EXTRA_IGNORE$8 = [
820
799
  "**/env/**",
821
800
  "**/.env/**",
822
- "**/__pycache__/**",
823
801
  "**/migrations/**"
824
802
  ];
825
803
  /**
@@ -831,89 +809,72 @@ const getDjangoVersionBucket = createVersionBucket();
831
809
  */
832
810
  async function getDjangoVersion(options) {
833
811
  const { installDir } = options;
834
- const requirementsFiles = await fg([
812
+ const requirementsFiles = await boundedGlob([
835
813
  "**/requirements*.txt",
836
814
  "**/pyproject.toml",
837
815
  "**/setup.py",
838
816
  "**/Pipfile"
839
817
  ], {
840
818
  cwd: installDir,
841
- ignore: IGNORE_PATTERNS$5
819
+ extraIgnore: EXTRA_IGNORE$8
842
820
  });
843
- for (const reqFile of requirementsFiles) try {
844
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
821
+ for (const reqFile of requirementsFiles) {
822
+ const content = readProjectFile(path$1.join(installDir, reqFile));
823
+ if (!content) continue;
845
824
  const requirementsMatch = content.match(/[Dd]jango[=<>~!]+([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
846
825
  if (requirementsMatch) return requirementsMatch[1];
847
826
  const pyprojectMatch = content.match(/[Dd]jango["\s]*[=<>~!]+\s*["']?([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
848
827
  if (pyprojectMatch) return pyprojectMatch[1];
849
- } catch {
850
- continue;
851
828
  }
852
829
  }
853
830
  /**
854
831
  * Check if Django REST Framework is installed
855
832
  */
856
833
  async function hasDRF({ installDir }) {
857
- const requirementsFiles = await fg([
834
+ const requirementsFiles = await boundedGlob([
858
835
  "**/requirements*.txt",
859
836
  "**/pyproject.toml",
860
837
  "**/Pipfile"
861
838
  ], {
862
839
  cwd: installDir,
863
- ignore: IGNORE_PATTERNS$5
840
+ extraIgnore: EXTRA_IGNORE$8
864
841
  });
865
- for (const reqFile of requirementsFiles) try {
866
- if (fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8").includes("djangorestframework")) return true;
867
- } catch {
868
- continue;
869
- }
870
- const settingsFiles = await fg("**/settings.py", {
842
+ for (const reqFile of requirementsFiles) if (readProjectFile(path$1.join(installDir, reqFile))?.includes("djangorestframework")) return true;
843
+ const settingsFiles = await boundedGlob("**/settings.py", {
871
844
  cwd: installDir,
872
- ignore: IGNORE_PATTERNS$5
845
+ extraIgnore: EXTRA_IGNORE$8
873
846
  });
874
- for (const settingsFile of settingsFiles) try {
875
- if (fs$1.readFileSync(path$1.join(installDir, settingsFile), "utf-8").includes("rest_framework")) return true;
876
- } catch {
877
- continue;
878
- }
847
+ for (const settingsFile of settingsFiles) if (readProjectFile(path$1.join(installDir, settingsFile))?.includes("rest_framework")) return true;
879
848
  return false;
880
849
  }
881
850
  /**
882
851
  * Check if Wagtail is installed
883
852
  */
884
853
  async function hasWagtail({ installDir }) {
885
- const requirementsFiles = await fg([
854
+ const requirementsFiles = await boundedGlob([
886
855
  "**/requirements*.txt",
887
856
  "**/pyproject.toml",
888
857
  "**/Pipfile"
889
858
  ], {
890
859
  cwd: installDir,
891
- ignore: IGNORE_PATTERNS$5
860
+ extraIgnore: EXTRA_IGNORE$8
892
861
  });
893
- for (const reqFile of requirementsFiles) try {
894
- if (fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8").includes("wagtail")) return true;
895
- } catch {
896
- continue;
897
- }
862
+ for (const reqFile of requirementsFiles) if (readProjectFile(path$1.join(installDir, reqFile))?.includes("wagtail")) return true;
898
863
  return false;
899
864
  }
900
865
  /**
901
866
  * Check if Django Channels is installed
902
867
  */
903
868
  async function hasChannels({ installDir }) {
904
- const requirementsFiles = await fg([
869
+ const requirementsFiles = await boundedGlob([
905
870
  "**/requirements*.txt",
906
871
  "**/pyproject.toml",
907
872
  "**/Pipfile"
908
873
  ], {
909
874
  cwd: installDir,
910
- ignore: IGNORE_PATTERNS$5
875
+ extraIgnore: EXTRA_IGNORE$8
911
876
  });
912
- for (const reqFile of requirementsFiles) try {
913
- if (fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8").includes("channels")) return true;
914
- } catch {
915
- continue;
916
- }
877
+ for (const reqFile of requirementsFiles) if (readProjectFile(path$1.join(installDir, reqFile))?.includes("channels")) return true;
917
878
  return false;
918
879
  }
919
880
  /**
@@ -952,28 +913,26 @@ function getDjangoProjectTypeName(projectType) {
952
913
  */
953
914
  async function findDjangoSettingsFile(options) {
954
915
  const { installDir } = options;
955
- const settingsFiles = await fg("**/settings.py", {
916
+ const settingsFiles = await boundedGlob("**/settings.py", {
956
917
  cwd: installDir,
957
- ignore: IGNORE_PATTERNS$5
918
+ extraIgnore: EXTRA_IGNORE$8
958
919
  });
959
920
  if (settingsFiles.length === 0) {
960
- const splitSettingsFiles = await fg("**/settings/__init__.py", {
921
+ const splitSettingsFiles = await boundedGlob("**/settings/__init__.py", {
961
922
  cwd: installDir,
962
- ignore: IGNORE_PATTERNS$5
923
+ extraIgnore: EXTRA_IGNORE$8,
924
+ limit: 1
963
925
  });
964
926
  if (splitSettingsFiles.length > 0) return splitSettingsFiles[0];
965
927
  return;
966
928
  }
967
929
  if (settingsFiles.length === 1) return settingsFiles[0];
968
- for (const settingsFile of settingsFiles) try {
969
- if (fs$1.readFileSync(path$1.join(installDir, settingsFile), "utf-8").includes("ROOT_URLCONF")) return settingsFile;
970
- } catch {
971
- continue;
972
- }
930
+ for (const settingsFile of settingsFiles) if (readProjectFile(path$1.join(installDir, settingsFile))?.includes("ROOT_URLCONF")) return settingsFile;
973
931
  return settingsFiles[0];
974
932
  }
975
933
  //#endregion
976
934
  //#region src/frameworks/django/django-wizard-agent.ts
935
+ const EXTRA_IGNORE$7 = ["**/env/**", "**/.env/**"];
977
936
  const DJANGO_AGENT_CONFIG = {
978
937
  metadata: {
979
938
  name: "Django",
@@ -997,39 +956,27 @@ const DJANGO_AGENT_CONFIG = {
997
956
  getInstalledVersion: (options) => getDjangoVersion(options),
998
957
  detect: async (options) => {
999
958
  const { installDir } = options;
1000
- const managePyMatches = await fg("**/manage.py", {
959
+ const managePyMatches = await boundedGlob("**/manage.py", {
1001
960
  cwd: installDir,
1002
- ignore: [
1003
- "**/venv/**",
1004
- "**/.venv/**",
1005
- "**/env/**",
1006
- "**/.env/**"
1007
- ]
961
+ extraIgnore: EXTRA_IGNORE$7
1008
962
  });
1009
- if (managePyMatches.length > 0) for (const match of managePyMatches) try {
1010
- const content = fs$1.readFileSync(path$1.join(installDir, match), "utf-8");
963
+ if (managePyMatches.length > 0) for (const match of managePyMatches) {
964
+ const content = readProjectFile(path$1.join(installDir, match));
965
+ if (!content) continue;
1011
966
  if (content.includes("from django") || content.includes("import django") || content.includes("DJANGO_SETTINGS_MODULE") || /execute_from_command_line/.test(content)) return true;
1012
- } catch {
1013
- continue;
1014
967
  }
1015
- const requirementsFiles = await fg([
968
+ const requirementsFiles = await boundedGlob([
1016
969
  "**/requirements*.txt",
1017
970
  "**/pyproject.toml",
1018
971
  "**/setup.py"
1019
972
  ], {
1020
973
  cwd: installDir,
1021
- ignore: [
1022
- "**/venv/**",
1023
- "**/.venv/**",
1024
- "**/env/**",
1025
- "**/.env/**"
1026
- ]
974
+ extraIgnore: EXTRA_IGNORE$7
1027
975
  });
1028
- for (const reqFile of requirementsFiles) try {
1029
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
976
+ for (const reqFile of requirementsFiles) {
977
+ const content = readProjectFile(path$1.join(installDir, reqFile));
978
+ if (!content) continue;
1030
979
  if (/^django([>=~!<\s]|$)/im.test(content) || /["']django["']/i.test(content)) return true;
1031
- } catch {
1032
- continue;
1033
980
  }
1034
981
  return false;
1035
982
  },
@@ -1079,18 +1026,14 @@ const DJANGO_AGENT_CONFIG = {
1079
1026
  };
1080
1027
  //#endregion
1081
1028
  //#region src/frameworks/flask/utils.ts
1082
- const IGNORE_PATTERNS$4 = [
1083
- "**/node_modules/**",
1084
- "**/dist/**",
1085
- "**/build/**",
1086
- "**/venv/**",
1087
- "**/.venv/**",
1029
+ const EXTRA_IGNORE$6 = [
1088
1030
  "**/env/**",
1089
1031
  "**/.env/**",
1090
- "**/__pycache__/**",
1091
1032
  "**/migrations/**",
1092
1033
  "**/instance/**"
1093
1034
  ];
1035
+ /** Content probes read at most this many files, one in memory at a time. */
1036
+ const SOURCE_PROBE_LIMIT$3 = 200;
1094
1037
  /**
1095
1038
  * Get Flask version bucket for analytics
1096
1039
  */
@@ -1100,52 +1043,50 @@ const getFlaskVersionBucket = createVersionBucket();
1100
1043
  */
1101
1044
  async function getFlaskVersion(options) {
1102
1045
  const { installDir } = options;
1103
- const requirementsFiles = await fg([
1046
+ const requirementsFiles = await boundedGlob([
1104
1047
  "**/requirements*.txt",
1105
1048
  "**/pyproject.toml",
1106
1049
  "**/setup.py",
1107
1050
  "**/Pipfile"
1108
1051
  ], {
1109
1052
  cwd: installDir,
1110
- ignore: IGNORE_PATTERNS$4
1053
+ extraIgnore: EXTRA_IGNORE$6
1111
1054
  });
1112
- for (const reqFile of requirementsFiles) try {
1113
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
1055
+ for (const reqFile of requirementsFiles) {
1056
+ const content = readProjectFile(path$1.join(installDir, reqFile));
1057
+ if (!content) continue;
1114
1058
  const requirementsMatch = content.match(/[Ff]lask[=<>~!]+([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
1115
1059
  if (requirementsMatch) return requirementsMatch[1];
1116
1060
  const pyprojectMatch = content.match(/[Ff]lask["\s]*[=<>~!]+\s*["']?([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
1117
1061
  if (pyprojectMatch) return pyprojectMatch[1];
1118
- } catch {
1119
- continue;
1120
1062
  }
1121
1063
  }
1122
1064
  /**
1123
1065
  * Check if Flask-RESTful is installed
1124
1066
  */
1125
1067
  async function hasFlaskRESTful({ installDir }) {
1126
- const requirementsFiles = await fg([
1068
+ const requirementsFiles = await boundedGlob([
1127
1069
  "**/requirements*.txt",
1128
1070
  "**/pyproject.toml",
1129
1071
  "**/Pipfile"
1130
1072
  ], {
1131
1073
  cwd: installDir,
1132
- ignore: IGNORE_PATTERNS$4
1074
+ extraIgnore: EXTRA_IGNORE$6
1133
1075
  });
1134
- for (const reqFile of requirementsFiles) try {
1135
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
1076
+ for (const reqFile of requirementsFiles) {
1077
+ const content = readProjectFile(path$1.join(installDir, reqFile));
1078
+ if (!content) continue;
1136
1079
  if (content.includes("flask-restful") || content.includes("Flask-RESTful")) return true;
1137
- } catch {
1138
- continue;
1139
1080
  }
1140
- const pyFiles = await fg(["**/*.py"], {
1081
+ const pyFiles = await boundedGlob(["**/*.py"], {
1141
1082
  cwd: installDir,
1142
- ignore: IGNORE_PATTERNS$4
1083
+ extraIgnore: EXTRA_IGNORE$6,
1084
+ limit: SOURCE_PROBE_LIMIT$3
1143
1085
  });
1144
- for (const pyFile of pyFiles) try {
1145
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1086
+ for (const pyFile of pyFiles) {
1087
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1088
+ if (!content) continue;
1146
1089
  if (content.includes("from flask_restful import") || content.includes("import flask_restful")) return true;
1147
- } catch {
1148
- continue;
1149
1090
  }
1150
1091
  return false;
1151
1092
  }
@@ -1153,29 +1094,28 @@ async function hasFlaskRESTful({ installDir }) {
1153
1094
  * Check if Flask-RESTX is installed
1154
1095
  */
1155
1096
  async function hasFlaskRESTX({ installDir }) {
1156
- const requirementsFiles = await fg([
1097
+ const requirementsFiles = await boundedGlob([
1157
1098
  "**/requirements*.txt",
1158
1099
  "**/pyproject.toml",
1159
1100
  "**/Pipfile"
1160
1101
  ], {
1161
1102
  cwd: installDir,
1162
- ignore: IGNORE_PATTERNS$4
1103
+ extraIgnore: EXTRA_IGNORE$6
1163
1104
  });
1164
- for (const reqFile of requirementsFiles) try {
1165
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
1105
+ for (const reqFile of requirementsFiles) {
1106
+ const content = readProjectFile(path$1.join(installDir, reqFile));
1107
+ if (!content) continue;
1166
1108
  if (content.includes("flask-restx") || content.includes("Flask-RESTX")) return true;
1167
- } catch {
1168
- continue;
1169
1109
  }
1170
- const pyFiles = await fg(["**/*.py"], {
1110
+ const pyFiles = await boundedGlob(["**/*.py"], {
1171
1111
  cwd: installDir,
1172
- ignore: IGNORE_PATTERNS$4
1112
+ extraIgnore: EXTRA_IGNORE$6,
1113
+ limit: SOURCE_PROBE_LIMIT$3
1173
1114
  });
1174
- for (const pyFile of pyFiles) try {
1175
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1115
+ for (const pyFile of pyFiles) {
1116
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1117
+ if (!content) continue;
1176
1118
  if (content.includes("from flask_restx import") || content.includes("import flask_restx")) return true;
1177
- } catch {
1178
- continue;
1179
1119
  }
1180
1120
  return false;
1181
1121
  }
@@ -1183,28 +1123,28 @@ async function hasFlaskRESTX({ installDir }) {
1183
1123
  * Check if flask-smorest is installed
1184
1124
  */
1185
1125
  async function hasFlaskSmorest({ installDir }) {
1186
- const requirementsFiles = await fg([
1126
+ const requirementsFiles = await boundedGlob([
1187
1127
  "**/requirements*.txt",
1188
1128
  "**/pyproject.toml",
1189
1129
  "**/Pipfile"
1190
1130
  ], {
1191
1131
  cwd: installDir,
1192
- ignore: IGNORE_PATTERNS$4
1132
+ extraIgnore: EXTRA_IGNORE$6
1193
1133
  });
1194
- for (const reqFile of requirementsFiles) try {
1195
- if (fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8").includes("flask-smorest")) return true;
1196
- } catch {
1197
- continue;
1134
+ for (const reqFile of requirementsFiles) {
1135
+ const content = readProjectFile(path$1.join(installDir, reqFile));
1136
+ if (!content) continue;
1137
+ if (content.includes("flask-smorest")) return true;
1198
1138
  }
1199
- const pyFiles = await fg(["**/*.py"], {
1139
+ const pyFiles = await boundedGlob(["**/*.py"], {
1200
1140
  cwd: installDir,
1201
- ignore: IGNORE_PATTERNS$4
1141
+ extraIgnore: EXTRA_IGNORE$6,
1142
+ limit: SOURCE_PROBE_LIMIT$3
1202
1143
  });
1203
- for (const pyFile of pyFiles) try {
1204
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1144
+ for (const pyFile of pyFiles) {
1145
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1146
+ if (!content) continue;
1205
1147
  if (content.includes("from flask_smorest import") || content.includes("import flask_smorest")) return true;
1206
- } catch {
1207
- continue;
1208
1148
  }
1209
1149
  return false;
1210
1150
  }
@@ -1212,15 +1152,15 @@ async function hasFlaskSmorest({ installDir }) {
1212
1152
  * Check if app uses Flask Blueprints
1213
1153
  */
1214
1154
  async function hasBlueprints({ installDir }) {
1215
- const pyFiles = await fg(["**/*.py"], {
1155
+ const pyFiles = await boundedGlob(["**/*.py"], {
1216
1156
  cwd: installDir,
1217
- ignore: IGNORE_PATTERNS$4
1157
+ extraIgnore: EXTRA_IGNORE$6,
1158
+ limit: SOURCE_PROBE_LIMIT$3
1218
1159
  });
1219
- for (const pyFile of pyFiles) try {
1220
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1160
+ for (const pyFile of pyFiles) {
1161
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1162
+ if (!content) continue;
1221
1163
  if (content.includes("Blueprint(") || content.includes("register_blueprint(") || content.includes("from flask import Blueprint")) return true;
1222
- } catch {
1223
- continue;
1224
1164
  }
1225
1165
  return false;
1226
1166
  }
@@ -1265,7 +1205,7 @@ function getFlaskProjectTypeName(projectType) {
1265
1205
  */
1266
1206
  async function findFlaskAppFile(options) {
1267
1207
  const { installDir } = options;
1268
- const appFiles = await fg([
1208
+ const appFiles = await boundedGlob([
1269
1209
  "**/app.py",
1270
1210
  "**/wsgi.py",
1271
1211
  "**/application.py",
@@ -1274,28 +1214,28 @@ async function findFlaskAppFile(options) {
1274
1214
  "**/__init__.py"
1275
1215
  ], {
1276
1216
  cwd: installDir,
1277
- ignore: IGNORE_PATTERNS$4
1217
+ extraIgnore: EXTRA_IGNORE$6
1278
1218
  });
1279
- for (const appFile of appFiles) try {
1280
- const content = fs$1.readFileSync(path$1.join(installDir, appFile), "utf-8");
1219
+ for (const appFile of appFiles) {
1220
+ const content = readProjectFile(path$1.join(installDir, appFile));
1221
+ if (!content) continue;
1281
1222
  if (content.includes("Flask(__name__)") || content.includes("Flask(") || content.includes("def create_app(")) return appFile;
1282
- } catch {
1283
- continue;
1284
1223
  }
1285
- const allPyFiles = await fg(["**/*.py"], {
1224
+ const allPyFiles = await boundedGlob(["**/*.py"], {
1286
1225
  cwd: installDir,
1287
- ignore: IGNORE_PATTERNS$4
1226
+ extraIgnore: EXTRA_IGNORE$6,
1227
+ limit: SOURCE_PROBE_LIMIT$3
1288
1228
  });
1289
- for (const pyFile of allPyFiles) try {
1290
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1229
+ for (const pyFile of allPyFiles) {
1230
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1231
+ if (!content) continue;
1291
1232
  if (content.includes("Flask(__name__)") || content.includes("def create_app(")) return pyFile;
1292
- } catch {
1293
- continue;
1294
1233
  }
1295
1234
  if (appFiles.length > 0) return appFiles[0];
1296
1235
  }
1297
1236
  //#endregion
1298
1237
  //#region src/frameworks/flask/flask-wizard-agent.ts
1238
+ const EXTRA_IGNORE$5 = ["**/env/**", "**/.env/**"];
1299
1239
  const FLASK_AGENT_CONFIG = {
1300
1240
  metadata: {
1301
1241
  name: "Flask",
@@ -1319,46 +1259,33 @@ const FLASK_AGENT_CONFIG = {
1319
1259
  getInstalledVersion: (options) => getFlaskVersion(options),
1320
1260
  detect: async (options) => {
1321
1261
  const { installDir } = options;
1322
- const requirementsFiles = await fg([
1262
+ const requirementsFiles = await boundedGlob([
1323
1263
  "**/requirements*.txt",
1324
1264
  "**/pyproject.toml",
1325
1265
  "**/setup.py",
1326
1266
  "**/Pipfile"
1327
1267
  ], {
1328
1268
  cwd: installDir,
1329
- ignore: [
1330
- "**/venv/**",
1331
- "**/.venv/**",
1332
- "**/env/**",
1333
- "**/.env/**"
1334
- ]
1269
+ extraIgnore: EXTRA_IGNORE$5
1335
1270
  });
1336
- for (const reqFile of requirementsFiles) try {
1337
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
1271
+ for (const reqFile of requirementsFiles) {
1272
+ const content = readProjectFile(path$1.join(installDir, reqFile));
1273
+ if (!content) continue;
1338
1274
  if (/^flask([<>=~!]|$|\s)/im.test(content) || /["']flask["']/i.test(content)) return true;
1339
- } catch {
1340
- continue;
1341
1275
  }
1342
- const pyFiles = await fg([
1276
+ const pyFiles = await boundedGlob([
1343
1277
  "**/app.py",
1344
1278
  "**/wsgi.py",
1345
1279
  "**/application.py",
1346
1280
  "**/__init__.py"
1347
1281
  ], {
1348
1282
  cwd: installDir,
1349
- ignore: [
1350
- "**/venv/**",
1351
- "**/.venv/**",
1352
- "**/env/**",
1353
- "**/.env/**",
1354
- "**/__pycache__/**"
1355
- ]
1283
+ extraIgnore: EXTRA_IGNORE$5
1356
1284
  });
1357
- for (const pyFile of pyFiles) try {
1358
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1285
+ for (const pyFile of pyFiles) {
1286
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1287
+ if (!content) continue;
1359
1288
  if (content.includes("from flask import") || content.includes("import flask") || /Flask\s*\(/.test(content)) return true;
1360
- } catch {
1361
- continue;
1362
1289
  }
1363
1290
  return false;
1364
1291
  },
@@ -1409,17 +1336,13 @@ const FLASK_AGENT_CONFIG = {
1409
1336
  };
1410
1337
  //#endregion
1411
1338
  //#region src/frameworks/fastapi/utils.ts
1412
- const IGNORE_PATTERNS$3 = [
1413
- "**/node_modules/**",
1414
- "**/dist/**",
1415
- "**/build/**",
1416
- "**/venv/**",
1417
- "**/.venv/**",
1339
+ const EXTRA_IGNORE$4 = [
1418
1340
  "**/env/**",
1419
1341
  "**/.env/**",
1420
- "**/__pycache__/**",
1421
1342
  "**/migrations/**"
1422
1343
  ];
1344
+ /** Content probes read at most this many files, one in memory at a time. */
1345
+ const SOURCE_PROBE_LIMIT$2 = 200;
1423
1346
  /**
1424
1347
  * Get FastAPI version bucket for analytics
1425
1348
  */
@@ -1440,38 +1363,37 @@ function getFastAPIVersionBucket(version) {
1440
1363
  */
1441
1364
  async function getFastAPIVersion(options) {
1442
1365
  const { installDir } = options;
1443
- const requirementsFiles = await fg([
1366
+ const requirementsFiles = await boundedGlob([
1444
1367
  "**/requirements*.txt",
1445
1368
  "**/pyproject.toml",
1446
1369
  "**/setup.py",
1447
1370
  "**/Pipfile"
1448
1371
  ], {
1449
1372
  cwd: installDir,
1450
- ignore: IGNORE_PATTERNS$3
1373
+ extraIgnore: EXTRA_IGNORE$4
1451
1374
  });
1452
- for (const reqFile of requirementsFiles) try {
1453
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
1375
+ for (const reqFile of requirementsFiles) {
1376
+ const content = readProjectFile(path$1.join(installDir, reqFile));
1377
+ if (!content) continue;
1454
1378
  const requirementsMatch = content.match(/[Ff]ast[Aa][Pp][Ii][=<>~!]+([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
1455
1379
  if (requirementsMatch) return requirementsMatch[1];
1456
1380
  const pyprojectMatch = content.match(/[Ff]ast[Aa][Pp][Ii]["\s]*[=<>~!]+\s*["']?([0-9]+\.[0-9]+(?:\.[0-9]+)?)/);
1457
1381
  if (pyprojectMatch) return pyprojectMatch[1];
1458
- } catch {
1459
- continue;
1460
1382
  }
1461
1383
  }
1462
1384
  /**
1463
1385
  * Check if app uses FastAPI APIRouter
1464
1386
  */
1465
1387
  async function hasAPIRouter({ installDir }) {
1466
- const pyFiles = await fg(["**/*.py"], {
1388
+ const pyFiles = await boundedGlob(["**/*.py"], {
1467
1389
  cwd: installDir,
1468
- ignore: IGNORE_PATTERNS$3
1390
+ extraIgnore: EXTRA_IGNORE$4,
1391
+ limit: SOURCE_PROBE_LIMIT$2
1469
1392
  });
1470
- for (const pyFile of pyFiles) try {
1471
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1393
+ for (const pyFile of pyFiles) {
1394
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1395
+ if (!content) continue;
1472
1396
  if (content.includes("APIRouter(") || content.includes("include_router(") || content.includes("from fastapi import APIRouter")) return true;
1473
- } catch {
1474
- continue;
1475
1397
  }
1476
1398
  return false;
1477
1399
  }
@@ -1479,20 +1401,20 @@ async function hasAPIRouter({ installDir }) {
1479
1401
  * Check if app uses Jinja2 templates (fullstack pattern)
1480
1402
  */
1481
1403
  async function hasTemplates({ installDir }) {
1482
- const pyFiles = await fg(["**/*.py"], {
1404
+ const pyFiles = await boundedGlob(["**/*.py"], {
1483
1405
  cwd: installDir,
1484
- ignore: IGNORE_PATTERNS$3
1406
+ extraIgnore: EXTRA_IGNORE$4,
1407
+ limit: SOURCE_PROBE_LIMIT$2
1485
1408
  });
1486
- for (const pyFile of pyFiles) try {
1487
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1409
+ for (const pyFile of pyFiles) {
1410
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1411
+ if (!content) continue;
1488
1412
  if (content.includes("Jinja2Templates") || content.includes("from fastapi.templating import")) return true;
1489
- } catch {
1490
- continue;
1491
1413
  }
1492
- return (await fg(["**/templates"], {
1414
+ return (await boundedGlob(["**/templates/**"], {
1493
1415
  cwd: installDir,
1494
- ignore: IGNORE_PATTERNS$3,
1495
- onlyDirectories: true
1416
+ extraIgnore: EXTRA_IGNORE$4,
1417
+ limit: 1
1496
1418
  })).length > 0;
1497
1419
  }
1498
1420
  /**
@@ -1526,7 +1448,7 @@ function getFastAPIProjectTypeName(projectType) {
1526
1448
  */
1527
1449
  async function findFastAPIAppFile(options) {
1528
1450
  const { installDir } = options;
1529
- const appFiles = await fg([
1451
+ const appFiles = await boundedGlob([
1530
1452
  "**/main.py",
1531
1453
  "**/app.py",
1532
1454
  "**/application.py",
@@ -1534,27 +1456,24 @@ async function findFastAPIAppFile(options) {
1534
1456
  "**/__init__.py"
1535
1457
  ], {
1536
1458
  cwd: installDir,
1537
- ignore: IGNORE_PATTERNS$3
1459
+ extraIgnore: EXTRA_IGNORE$4
1538
1460
  });
1539
- for (const appFile of appFiles) try {
1540
- const content = fs$1.readFileSync(path$1.join(installDir, appFile), "utf-8");
1461
+ for (const appFile of appFiles) {
1462
+ const content = readProjectFile(path$1.join(installDir, appFile));
1463
+ if (!content) continue;
1541
1464
  if (content.includes("FastAPI(") || content.includes("from fastapi import FastAPI")) return appFile;
1542
- } catch {
1543
- continue;
1544
1465
  }
1545
- const allPyFiles = await fg(["**/*.py"], {
1466
+ const allPyFiles = await boundedGlob(["**/*.py"], {
1546
1467
  cwd: installDir,
1547
- ignore: IGNORE_PATTERNS$3
1468
+ extraIgnore: EXTRA_IGNORE$4,
1469
+ limit: SOURCE_PROBE_LIMIT$2
1548
1470
  });
1549
- for (const pyFile of allPyFiles) try {
1550
- if (fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8").includes("FastAPI(")) return pyFile;
1551
- } catch {
1552
- continue;
1553
- }
1471
+ for (const pyFile of allPyFiles) if (readProjectFile(path$1.join(installDir, pyFile))?.includes("FastAPI(")) return pyFile;
1554
1472
  if (appFiles.length > 0) return appFiles[0];
1555
1473
  }
1556
1474
  //#endregion
1557
1475
  //#region src/frameworks/fastapi/fastapi-wizard-agent.ts
1476
+ const EXTRA_IGNORE$3 = ["**/env/**", "**/.env/**"];
1558
1477
  /**
1559
1478
  * FastAPI framework configuration for the universal agent runner
1560
1479
  */
@@ -1580,46 +1499,33 @@ const FASTAPI_AGENT_CONFIG = {
1580
1499
  getInstalledVersion: getFastAPIVersion,
1581
1500
  detect: async (options) => {
1582
1501
  const { installDir } = options;
1583
- const requirementsFiles = await fg([
1502
+ const requirementsFiles = await boundedGlob([
1584
1503
  "**/requirements*.txt",
1585
1504
  "**/pyproject.toml",
1586
1505
  "**/setup.py",
1587
1506
  "**/Pipfile"
1588
1507
  ], {
1589
1508
  cwd: installDir,
1590
- ignore: [
1591
- "**/venv/**",
1592
- "**/.venv/**",
1593
- "**/env/**",
1594
- "**/.env/**"
1595
- ]
1509
+ extraIgnore: EXTRA_IGNORE$3
1596
1510
  });
1597
- for (const reqFile of requirementsFiles) try {
1598
- const content = fs$1.readFileSync(path$1.join(installDir, reqFile), "utf-8");
1511
+ for (const reqFile of requirementsFiles) {
1512
+ const content = readProjectFile(path$1.join(installDir, reqFile));
1513
+ if (!content) continue;
1599
1514
  if (/^fastapi([<>=~!]|$|\s)/im.test(content) || /["']fastapi["']/i.test(content)) return true;
1600
- } catch {
1601
- continue;
1602
1515
  }
1603
- const pyFiles = await fg([
1516
+ const pyFiles = await boundedGlob([
1604
1517
  "**/main.py",
1605
1518
  "**/app.py",
1606
1519
  "**/application.py",
1607
1520
  "**/__init__.py"
1608
1521
  ], {
1609
1522
  cwd: installDir,
1610
- ignore: [
1611
- "**/venv/**",
1612
- "**/.venv/**",
1613
- "**/env/**",
1614
- "**/.env/**",
1615
- "**/__pycache__/**"
1616
- ]
1523
+ extraIgnore: EXTRA_IGNORE$3
1617
1524
  });
1618
- for (const pyFile of pyFiles) try {
1619
- const content = fs$1.readFileSync(path$1.join(installDir, pyFile), "utf-8");
1525
+ for (const pyFile of pyFiles) {
1526
+ const content = readProjectFile(path$1.join(installDir, pyFile));
1527
+ if (!content) continue;
1620
1528
  if (content.includes("from fastapi import") || content.includes("import fastapi") || /FastAPI\s*\(/.test(content)) return true;
1621
- } catch {
1622
- continue;
1623
1529
  }
1624
1530
  return false;
1625
1531
  },
@@ -1672,18 +1578,15 @@ const FASTAPI_AGENT_CONFIG = {
1672
1578
  };
1673
1579
  //#endregion
1674
1580
  //#region src/frameworks/laravel/utils.ts
1675
- /**
1676
- * Ignore patterns for Laravel projects
1677
- */
1678
- const LARAVEL_IGNORE_PATTERNS = [
1679
- "**/node_modules/**",
1680
- "**/vendor/**",
1581
+ const EXTRA_IGNORE$2 = [
1681
1582
  "**/storage/**",
1682
1583
  "**/bootstrap/cache/**",
1683
1584
  "**/.phpunit.cache/**",
1684
1585
  "**/public/build/**",
1685
1586
  "**/public/hot/**"
1686
1587
  ];
1588
+ /** Content probes read at most this many files, one in memory at a time. */
1589
+ const SOURCE_PROBE_LIMIT$1 = 200;
1687
1590
  /**
1688
1591
  * Get Laravel version bucket for analytics
1689
1592
  */
@@ -1723,16 +1626,16 @@ function getComposerPackageVersion(packageName, options) {
1723
1626
  */
1724
1627
  async function hasLaravelCodePattern(pattern, options, filePatterns = ["**/*.php"]) {
1725
1628
  const { installDir } = options;
1726
- const phpFiles = await fg(filePatterns, {
1629
+ const phpFiles = await boundedGlob(filePatterns, {
1727
1630
  cwd: installDir,
1728
- ignore: LARAVEL_IGNORE_PATTERNS
1631
+ extraIgnore: EXTRA_IGNORE$2,
1632
+ limit: SOURCE_PROBE_LIMIT$1
1729
1633
  });
1730
1634
  const searchPattern = typeof pattern === "string" ? new RegExp(pattern) : pattern;
1731
- for (const phpFile of phpFiles) try {
1732
- const content = fs$1.readFileSync(path$1.join(installDir, phpFile), "utf-8");
1635
+ for (const phpFile of phpFiles) {
1636
+ const content = readProjectFile(path$1.join(installDir, phpFile));
1637
+ if (!content) continue;
1733
1638
  if (searchPattern.test(content)) return true;
1734
- } catch {
1735
- continue;
1736
1639
  }
1737
1640
  return false;
1738
1641
  }
@@ -1787,9 +1690,10 @@ async function findLaravelServiceProvider(options) {
1787
1690
  const { installDir } = options;
1788
1691
  const appServiceProvider = path$1.join(installDir, "app/Providers/AppServiceProvider.php");
1789
1692
  if (fs$1.existsSync(appServiceProvider)) return "app/Providers/AppServiceProvider.php";
1790
- return (await fg(["**/app/Providers/*ServiceProvider.php"], {
1693
+ return (await boundedGlob(["**/app/Providers/*ServiceProvider.php"], {
1791
1694
  cwd: installDir,
1792
- ignore: LARAVEL_IGNORE_PATTERNS
1695
+ extraIgnore: EXTRA_IGNORE$2,
1696
+ limit: 1
1793
1697
  }))[0];
1794
1698
  }
1795
1699
  /**
@@ -1855,9 +1759,9 @@ const LARAVEL_AGENT_CONFIG = {
1855
1759
  const composer = JSON.parse(content);
1856
1760
  if (composer.require?.["laravel/framework"] || composer["require-dev"]?.["laravel/framework"]) return true;
1857
1761
  } catch {}
1858
- return (await fg(["**/bootstrap/app.php", "**/app/Http/Kernel.php"], {
1762
+ return (await boundedGlob(["**/bootstrap/app.php", "**/app/Http/Kernel.php"], {
1859
1763
  cwd: installDir,
1860
- ignore: ["**/vendor/**"]
1764
+ limit: 1
1861
1765
  })).length > 0;
1862
1766
  },
1863
1767
  detectPackageManager: composerPackageManager
@@ -1957,6 +1861,9 @@ const SVELTEKIT_AGENT_CONFIG = {
1957
1861
  };
1958
1862
  //#endregion
1959
1863
  //#region src/frameworks/swift/utils.ts
1864
+ const EXTRA_IGNORE$1 = ["**/.build/**", "**/*.xcodeproj/**"];
1865
+ /** Content probes read at most this many files, one in memory at a time. */
1866
+ const SOURCE_PROBE_LIMIT = 200;
1960
1867
  function getSwiftProjectTypeName(projectType) {
1961
1868
  switch (projectType) {
1962
1869
  case "swiftui": return "SwiftUI";
@@ -1973,24 +1880,18 @@ async function detectSwiftProjectType(options) {
1973
1880
  onlyDirectories: true
1974
1881
  });
1975
1882
  if (hasPackageSwift && xcodeProjects.length === 0 && !hasXcodeGenSpec) return "spm";
1976
- const swiftFiles = await fg("**/*.swift", {
1883
+ const swiftFiles = await boundedGlob("**/*.swift", {
1977
1884
  cwd: installDir,
1978
- ignore: [
1979
- "**/.build/**",
1980
- "**/DerivedData/**",
1981
- "**/build/**",
1982
- "**/*.xcodeproj/**",
1983
- "**/Pods/**"
1984
- ]
1885
+ extraIgnore: EXTRA_IGNORE$1,
1886
+ limit: SOURCE_PROBE_LIMIT
1985
1887
  });
1986
1888
  let hasSwiftUI = false;
1987
1889
  let hasUIKit = false;
1988
- for (const file of swiftFiles) try {
1989
- const content = fs$1.readFileSync(path$1.join(installDir, file), "utf-8");
1890
+ for (const file of swiftFiles) {
1891
+ const content = readProjectFile(path$1.join(installDir, file));
1892
+ if (!content) continue;
1990
1893
  if (content.includes("import SwiftUI")) hasSwiftUI = true;
1991
1894
  if (content.includes("import UIKit")) hasUIKit = true;
1992
- } catch {
1993
- continue;
1994
1895
  }
1995
1896
  if (hasSwiftUI) return "swiftui";
1996
1897
  if (hasUIKit) return "uikit";
@@ -2020,15 +1921,10 @@ const SWIFT_AGENT_CONFIG = {
2020
1921
  });
2021
1922
  const hasXcodeGenSpec = fs$1.existsSync(path$1.join(installDir, "project.yml"));
2022
1923
  if (xcodeProjects.length > 0 || hasXcodeGenSpec) {
2023
- if ((await fg("**/*.swift", {
1924
+ if ((await boundedGlob("**/*.swift", {
2024
1925
  cwd: installDir,
2025
- ignore: [
2026
- "**/.build/**",
2027
- "**/DerivedData/**",
2028
- "**/build/**",
2029
- "**/*.xcodeproj/**",
2030
- "**/Pods/**"
2031
- ]
1926
+ extraIgnore: ["**/.build/**", "**/*.xcodeproj/**"],
1927
+ limit: 1
2032
1928
  })).length > 0) return true;
2033
1929
  }
2034
1930
  const packageSwiftPath = path$1.join(installDir, "Package.swift");
@@ -2088,26 +1984,15 @@ const KMP_AGENT_CONFIG = {
2088
1984
  detectPackageManager: gradlePackageManager,
2089
1985
  detect: async (options) => {
2090
1986
  const { installDir } = options;
2091
- const buildFiles = await fg(["**/build.gradle", "**/build.gradle.kts"], {
2092
- cwd: installDir,
2093
- ignore: [
2094
- "**/build/**",
2095
- "**/node_modules/**",
2096
- "**/.gradle/**"
2097
- ]
2098
- });
1987
+ const buildFiles = await boundedGlob(["**/build.gradle", "**/build.gradle.kts"], { cwd: installDir });
2099
1988
  for (const file of buildFiles) {
2100
- const content = fs$1.readFileSync(path$1.join(installDir, file), "utf-8");
1989
+ const content = readProjectFile(path$1.join(installDir, file));
1990
+ if (!content) continue;
2101
1991
  if (content.includes("kotlin(\"multiplatform\")") || content.includes("org.jetbrains.kotlin.multiplatform") || content.includes("kotlin-multiplatform")) return true;
2102
1992
  }
2103
- return (await fg("**/src/commonMain", {
1993
+ return (await boundedGlob("**/src/commonMain/**", {
2104
1994
  cwd: installDir,
2105
- onlyDirectories: true,
2106
- ignore: [
2107
- "**/build/**",
2108
- "**/node_modules/**",
2109
- "**/.gradle/**"
2110
- ]
1995
+ limit: 1
2111
1996
  })).length > 0;
2112
1997
  }
2113
1998
  },
@@ -2149,26 +2034,18 @@ const KMP_AGENT_CONFIG = {
2149
2034
  };
2150
2035
  //#endregion
2151
2036
  //#region src/frameworks/android/utils.ts
2152
- const IGNORE_PATTERNS$2 = [
2153
- "**/build/**",
2154
- "**/.gradle/**",
2155
- "**/node_modules/**"
2156
- ];
2157
2037
  /**
2158
2038
  * Extract minSdk from the app-level build.gradle(.kts).
2159
2039
  * Returns the value as a semver-like string (e.g. "24" from minSdk = 24).
2160
2040
  */
2161
2041
  async function getMinSdkVersion(options) {
2162
2042
  const { installDir } = options;
2163
- const buildFiles = await fg(["**/build.gradle", "**/build.gradle.kts"], {
2164
- cwd: installDir,
2165
- ignore: IGNORE_PATTERNS$2
2166
- });
2167
- for (const file of buildFiles) try {
2168
- const match = fs$1.readFileSync(path$1.join(installDir, file), "utf-8").match(/minSdk(?:Version)?\s*=?\s*(\d+)/);
2043
+ const buildFiles = await boundedGlob(["**/build.gradle", "**/build.gradle.kts"], { cwd: installDir });
2044
+ for (const file of buildFiles) {
2045
+ const content = readProjectFile(path$1.join(installDir, file));
2046
+ if (!content) continue;
2047
+ const match = content.match(/minSdk(?:Version)?\s*=?\s*(\d+)/);
2169
2048
  if (match) return match[1];
2170
- } catch {
2171
- continue;
2172
2049
  }
2173
2050
  }
2174
2051
  const getKotlinVersionBucket = createVersionBucket();
@@ -2222,21 +2099,13 @@ const ANDROID_AGENT_CONFIG = {
2222
2099
  if (content.includes("com.android.application") || content.includes("com.android.library") || content.includes("com.android.tools.build:gradle")) return true;
2223
2100
  }
2224
2101
  }
2225
- if ((await fg("**/AndroidManifest.xml", {
2102
+ if ((await boundedGlob("**/AndroidManifest.xml", {
2226
2103
  cwd: installDir,
2227
- ignore: [
2228
- "**/build/**",
2229
- "**/node_modules/**",
2230
- "**/.gradle/**"
2231
- ]
2104
+ limit: 1
2232
2105
  })).length > 0) {
2233
- if ((await fg("**/*.kt", {
2106
+ if ((await boundedGlob("**/*.kt", {
2234
2107
  cwd: installDir,
2235
- ignore: [
2236
- "**/build/**",
2237
- "**/node_modules/**",
2238
- "**/.gradle/**"
2239
- ]
2108
+ limit: 1
2240
2109
  })).length > 0) return true;
2241
2110
  }
2242
2111
  return false;
@@ -2277,7 +2146,7 @@ const ANDROID_AGENT_CONFIG = {
2277
2146
  };
2278
2147
  //#endregion
2279
2148
  //#region src/frameworks/rails/utils.ts
2280
- const IGNORE_PATTERNS$1 = [
2149
+ const IGNORE_PATTERNS = [
2281
2150
  "**/node_modules/**",
2282
2151
  "**/vendor/**",
2283
2152
  "**/vendor/bundle/**",
@@ -2371,7 +2240,7 @@ async function isRailsProject(options) {
2371
2240
  if (hasGem("rails", options)) return true;
2372
2241
  return (await fg(["config/routes.rb", "config/environment.rb"], {
2373
2242
  cwd: installDir,
2374
- ignore: IGNORE_PATTERNS$1
2243
+ ignore: IGNORE_PATTERNS
2375
2244
  })).length >= 2;
2376
2245
  }
2377
2246
  //#endregion
@@ -2568,13 +2437,7 @@ const PYTHON_AGENT_CONFIG = {
2568
2437
  };
2569
2438
  //#endregion
2570
2439
  //#region src/frameworks/ruby/utils.ts
2571
- const IGNORE_PATTERNS = [
2572
- "**/node_modules/**",
2573
- "**/vendor/**",
2574
- "**/vendor/bundle/**",
2575
- "**/tmp/**",
2576
- "**/log/**"
2577
- ];
2440
+ const EXTRA_IGNORE = ["**/tmp/**", "**/log/**"];
2578
2441
  /**
2579
2442
  * Get Ruby version bucket for analytics
2580
2443
  */
@@ -2628,17 +2491,19 @@ async function isRubyProject(options) {
2628
2491
  }
2629
2492
  const rubyVersionPath = path$1.join(installDir, ".ruby-version");
2630
2493
  if (fs$1.existsSync(rubyVersionPath)) return true;
2631
- if ((await fg("*.gemspec", {
2494
+ if ((await boundedGlob("*.gemspec", {
2632
2495
  cwd: installDir,
2633
- ignore: IGNORE_PATTERNS
2496
+ extraIgnore: EXTRA_IGNORE,
2497
+ limit: 1
2634
2498
  })).length > 0) return true;
2635
- return (await fg([
2499
+ return (await boundedGlob([
2636
2500
  "*.rb",
2637
2501
  "lib/**/*.rb",
2638
2502
  "bin/**/*.rb"
2639
2503
  ], {
2640
2504
  cwd: installDir,
2641
- ignore: IGNORE_PATTERNS
2505
+ extraIgnore: EXTRA_IGNORE,
2506
+ limit: 1
2642
2507
  })).length > 0;
2643
2508
  }
2644
2509
  //#endregion
@@ -2787,15 +2652,6 @@ const JAVASCRIPT_NODE_AGENT_CONFIG = {
2787
2652
  //#endregion
2788
2653
  //#region src/frameworks/javascript-web/utils.ts
2789
2654
  const INDEX_HTML_MAX_DEPTH = 6;
2790
- const INDEX_HTML_IGNORE_DIRS = new Set([
2791
- "node_modules",
2792
- ".git",
2793
- ".next",
2794
- "dist",
2795
- "build",
2796
- ".turbo",
2797
- ".cache"
2798
- ]);
2799
2655
  /**
2800
2656
  * Packages that indicate a specific framework integration exists.
2801
2657
  * If any of these are in package.json, we should NOT match as generic JavaScript.
@@ -2849,25 +2705,12 @@ function detectBundler(options) {
2849
2705
  * Heuristic: check if there is an index.html anywhere in the project,
2850
2706
  * ignoring common build and dependency directories.
2851
2707
  */
2852
- function hasIndexHtml(options) {
2853
- const root = options.installDir;
2854
- function search(dir, depth) {
2855
- if (depth > INDEX_HTML_MAX_DEPTH) return false;
2856
- const base = path$1.basename(dir);
2857
- if (INDEX_HTML_IGNORE_DIRS.has(base)) return false;
2858
- let entries;
2859
- try {
2860
- entries = fs$1.readdirSync(dir, { withFileTypes: true });
2861
- } catch {
2862
- return false;
2863
- }
2864
- for (const entry of entries) if (entry.isFile() && entry.name.toLowerCase() === "index.html") return true;
2865
- for (const entry of entries) if (entry.isDirectory()) {
2866
- if (search(path$1.join(dir, entry.name), depth + 1)) return true;
2867
- }
2868
- return false;
2869
- }
2870
- return search(root, 0);
2708
+ async function hasIndexHtml(options) {
2709
+ return (await boundedGlob("**/index.html", {
2710
+ cwd: options.installDir,
2711
+ deep: INDEX_HTML_MAX_DEPTH,
2712
+ limit: 1
2713
+ })).length > 0;
2871
2714
  }
2872
2715
  //#endregion
2873
2716
  //#region src/frameworks/javascript-web/javascript-web-wizard-agent.ts
@@ -2898,7 +2741,7 @@ const JAVASCRIPT_WEB_AGENT_CONFIG = {
2898
2741
  if (!packageJson) return false;
2899
2742
  for (const frameworkPkg of FRAMEWORK_PACKAGES) if (hasDeclaredDependency(frameworkPkg, packageJson)) return false;
2900
2743
  const { installDir } = options;
2901
- const hasIndexHtmlFlag = hasIndexHtml(options);
2744
+ const hasIndexHtmlFlag = await hasIndexHtml(options);
2902
2745
  const hasBundler = !!detectBundler(options);
2903
2746
  if ([
2904
2747
  "package-lock.json",
@@ -2987,4 +2830,4 @@ const FRAMEWORK_REGISTRY = {
2987
2830
  //#endregion
2988
2831
  export { SPINNER_MESSAGE as i, registry_exports as n, DEFAULT_PACKAGE_INSTALLATION as r, FRAMEWORK_REGISTRY as t };
2989
2832
 
2990
- //# sourceMappingURL=registry-CYNjgbAh.js.map
2833
+ //# sourceMappingURL=registry-BMjfECF2.js.map