@pixel-point/toolcraft 0.0.11 → 0.0.13

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/README.md CHANGED
@@ -19,7 +19,7 @@ tools for client work.
19
19
  npx @pixel-point/toolcraft create
20
20
  ```
21
21
 
22
- The create command uses the current directory when no target directory is passed, prompts for missing project values in an interactive terminal, generates the app, runs `pnpm install`, then prints the command to start the dev server.
22
+ The create command uses the current directory when no target directory is passed, prompts for missing project values in an interactive terminal, generates the app, runs dependency installation with the package manager that launched the CLI, then prints the command to start the dev server.
23
23
 
24
24
  After dependencies are installed, Toolcraft installs the required workflow skills
25
25
  in a batch through the `skills` CLI. The skill installer uses the same agent,
@@ -30,7 +30,7 @@ Example:
30
30
  ```bash
31
31
  npx @pixel-point/toolcraft create my-ascii-tool
32
32
  cd my-ascii-tool
33
- pnpm dev
33
+ npm run dev
34
34
  ```
35
35
 
36
36
  Then open the generated folder in Codex, Claude Code, Cursor, or another AI
@@ -46,6 +46,8 @@ Scripted usage:
46
46
  npx @pixel-point/toolcraft create my-toolcraft-app --name my-toolcraft-app --yes --force
47
47
  ```
48
48
 
49
+ Toolcraft detects `npm` and `pnpm` from the package manager user agent. For example, `npx @pixel-point/toolcraft create` generates npm-flavored setup commands, while `pnpm dlx @pixel-point/toolcraft create` generates pnpm-flavored setup commands.
50
+
49
51
  Install Toolcraft skills to specific agents or locations:
50
52
 
51
53
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixel-point/toolcraft",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@clack/prompts": "^1.6.0",
27
+ "cross-spawn": "^7.0.6",
27
28
  "skills": "^1.5.12"
28
29
  }
29
30
  }
package/src/cli.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import { spawn } from "node:child_process";
2
1
  import { createRequire } from "node:module";
3
2
  import fs from "node:fs/promises";
4
3
  import path from "node:path";
@@ -16,8 +15,14 @@ import {
16
15
  text,
17
16
  } from "@clack/prompts";
18
17
 
18
+ import { runCommand } from "./command-runner.mjs";
19
19
  import { pathExists } from "./copy-recursive.mjs";
20
+ import { installGeneratedAppDependencies } from "./dependency-install.mjs";
20
21
  import { generateToolcraft } from "./generate.mjs";
22
+ import {
23
+ createRunScriptCommand,
24
+ detectPackageManager,
25
+ } from "./package-manager.mjs";
21
26
  import { sanitizePackageName } from "./package-json.mjs";
22
27
 
23
28
  const DEFAULT_PROJECT_NAME = "my-toolcraft-app";
@@ -355,31 +360,6 @@ export async function resolveCreateOptions(parsedOptions, context = {}) {
355
360
  };
356
361
  }
357
362
 
358
- function runCommand(command, args, options = {}, context = {}) {
359
- if (context.runCommand) {
360
- return context.runCommand(command, args, options);
361
- }
362
-
363
- return new Promise((resolve, reject) => {
364
- const child = spawn(command, args, {
365
- cwd: options.cwd,
366
- env: options.env,
367
- shell: process.platform === "win32",
368
- stdio: options.stdio ?? "inherit",
369
- });
370
-
371
- child.on("error", reject);
372
- child.on("exit", (exitCode) => {
373
- if (exitCode === 0) {
374
- resolve();
375
- return;
376
- }
377
-
378
- reject(new Error(`${command} ${args.join(" ")} failed with exit code ${exitCode}.`));
379
- });
380
- });
381
- }
382
-
383
363
  function getSkillsCliPath(context = {}) {
384
364
  if (context.skillsCliPath) {
385
365
  return context.skillsCliPath;
@@ -439,6 +419,7 @@ async function installToolcraftSkills(parsedOptions, targetDir, context = {}) {
439
419
  ...process.env,
440
420
  ...(context.env ?? {}),
441
421
  },
422
+ shell: false,
442
423
  stdio: "inherit",
443
424
  },
444
425
  context,
@@ -458,7 +439,7 @@ function writeFinalSummary(stdout, result, createOptions) {
458
439
  : result.relativeTargetDir;
459
440
  writeLine(stdout, ` cd ${displayTargetDir}`);
460
441
  }
461
- writeLine(stdout, " pnpm dev");
442
+ writeLine(stdout, ` ${createRunScriptCommand(createOptions.packageManager, "dev")}`);
462
443
  }
463
444
 
464
445
  export async function runCreateCommand(parsedOptions, context = {}) {
@@ -470,6 +451,7 @@ export async function runCreateCommand(parsedOptions, context = {}) {
470
451
  intro("Create Toolcraft app");
471
452
  }
472
453
 
454
+ const packageManager = detectPackageManager(context.env ?? process.env);
473
455
  const createOptions = await resolveCreateOptions(parsedOptions, context);
474
456
 
475
457
  const result = await runWithSpinner(context, "Creating Toolcraft app...", "Created app", () =>
@@ -477,26 +459,19 @@ export async function runCreateCommand(parsedOptions, context = {}) {
477
459
  cwd,
478
460
  force: createOptions.force,
479
461
  name: createOptions.name,
462
+ packageManager,
480
463
  targetDir: createOptions.targetDir,
481
464
  }),
482
465
  );
483
466
 
484
467
  if (createOptions.install) {
485
- writeLine(stdout, "");
486
- writeLine(stdout, "Installing dependencies with pnpm...");
487
- await runCommand(
488
- "pnpm",
489
- ["install"],
490
- {
491
- cwd: result.targetDir,
492
- env: {
493
- ...process.env,
494
- ...(context.env ?? {}),
495
- },
496
- stdio: "inherit",
497
- },
468
+ await installGeneratedAppDependencies({
498
469
  context,
499
- );
470
+ packageManager,
471
+ result,
472
+ skillsRequested: createOptions.skills,
473
+ stdout,
474
+ });
500
475
  }
501
476
 
502
477
  if (createOptions.skills) {
@@ -508,12 +483,12 @@ export async function runCreateCommand(parsedOptions, context = {}) {
508
483
  if (usingClack) {
509
484
  const nextSteps = [
510
485
  ...(result.targetDir === cwd ? [] : [`cd ${result.relativeTargetDir}`]),
511
- "pnpm dev",
486
+ createRunScriptCommand(packageManager, "dev"),
512
487
  ].join("\n");
513
488
  note(nextSteps, "Next steps");
514
489
  outro(`Created ${result.packageName}`);
515
490
  } else {
516
- writeFinalSummary(stdout, result, { ...createOptions, cwd });
491
+ writeFinalSummary(stdout, result, { ...createOptions, cwd, packageManager });
517
492
  }
518
493
 
519
494
  return result;
@@ -548,7 +523,7 @@ Options:
548
523
  --copy Copy skills instead of using the skills CLI default link behavior.
549
524
  --all Install Toolcraft skills to all supported agents without skills prompts.
550
525
  --no-skills Skip Toolcraft skills installation.
551
- --no-install Skip automatic pnpm install. Intended for local CLI tests and automation.
526
+ --no-install Skip automatic dependency installation. Intended for local CLI tests and automation.
552
527
  --help, -h Show this help message.`;
553
528
  }
554
529
 
package/src/cli.test.mjs CHANGED
@@ -206,7 +206,7 @@ describe("runToolcraftCli", () => {
206
206
  assert.ok(await fs.stat(path.join(tempRoot, "src/app/app-schema.ts")));
207
207
  assert.match(stdout.text, new RegExp(`Created ${path.basename(tempRoot).toLowerCase()}`));
208
208
  assert.doesNotMatch(stdout.text, /cd /);
209
- assert.match(stdout.text, /pnpm dev/);
209
+ assert.match(stdout.text, /npm run dev/);
210
210
  assert.equal(stderr.text, "");
211
211
  });
212
212
 
@@ -239,12 +239,12 @@ describe("runToolcraftCli", () => {
239
239
  assert.ok(await fs.stat(path.join(tempRoot, "generated-app/src/app/app-schema.ts")));
240
240
  assert.match(stdout.text, /Created generated-app/);
241
241
  assert.match(stdout.text, /cd generated-app/);
242
- assert.match(stdout.text, /pnpm dev/);
242
+ assert.match(stdout.text, /npm run dev/);
243
243
  assert.doesNotMatch(stdout.text, /pnpm verify:final/);
244
244
  assert.equal(stderr.text, "");
245
245
  });
246
246
 
247
- it("runs pnpm install and Toolcraft skills install by default after creating the app", async () => {
247
+ it("runs npm install and Toolcraft skills install when launched through npx", async () => {
248
248
  const tempRoot = await createTempRoot();
249
249
  const stdout = createWritableCapture();
250
250
  const installs = [];
@@ -253,33 +253,170 @@ describe("runToolcraftCli", () => {
253
253
 
254
254
  await runToolcraftCli(["create", "install-app", "--name", "Install App", "--yes", "--force"], {
255
255
  cwd: tempRoot,
256
- env: {},
256
+ env: {
257
+ npm_config_user_agent: "npm/10.9.4 node/v24.4.1 darwin arm64",
258
+ },
257
259
  stdout,
258
260
  skillsCliPath,
259
261
  throwOnError: true,
260
262
  toolcraftSkillsSourceDir: skillsSourceDir,
261
263
  async runCommand(command, args, options) {
262
- installs.push({ args, command, cwd: options.cwd });
264
+ installs.push({ args, command, cwd: options.cwd, shell: options.shell });
263
265
  },
264
266
  });
265
267
 
266
268
  assert.deepEqual(installs, [
267
269
  {
268
270
  args: ["install"],
269
- command: "pnpm",
271
+ command: "npm",
270
272
  cwd: path.join(tempRoot, "install-app"),
273
+ shell: false,
271
274
  },
272
275
  {
273
276
  args: [skillsCliPath, "add", skillsSourceDir, "--skill", "*", "--yes"],
274
277
  command: process.execPath,
275
278
  cwd: path.join(tempRoot, "install-app"),
279
+ shell: false,
276
280
  },
277
281
  ]);
278
- assert.match(stdout.text, /Installing dependencies with pnpm/);
282
+ assert.match(stdout.text, /Installing dependencies with npm/);
279
283
  assert.match(stdout.text, /Installing Toolcraft skills/);
284
+ assert.match(stdout.text, /npm run dev/);
285
+
286
+ const packageJson = JSON.parse(
287
+ await fs.readFile(path.join(tempRoot, "install-app/package.json"), "utf8"),
288
+ );
289
+ assert.equal(
290
+ packageJson.scripts["verify:final"],
291
+ "npm run ai:check && npm run test && npm run build && npm run test:browser",
292
+ );
293
+
294
+ const playwrightConfigSource = await fs.readFile(
295
+ path.join(tempRoot, "install-app/playwright.config.ts"),
296
+ "utf8",
297
+ );
298
+ assert.match(playwrightConfigSource, /npm exec -- vite dev/);
299
+ });
300
+
301
+ it("runs pnpm install when launched through pnpm", async () => {
302
+ const tempRoot = await createTempRoot();
303
+ const stdout = createWritableCapture();
304
+ const installs = [];
305
+
306
+ await runToolcraftCli(
307
+ ["create", "pnpm-app", "--name", "Pnpm App", "--yes", "--force", "--no-skills"],
308
+ {
309
+ cwd: tempRoot,
310
+ env: {
311
+ npm_config_user_agent: "pnpm/10.0.0 npm/? node/v24.4.1 darwin arm64",
312
+ },
313
+ stdout,
314
+ throwOnError: true,
315
+ async runCommand(command, args, options) {
316
+ installs.push({ args, command, cwd: options.cwd, shell: options.shell });
317
+ },
318
+ },
319
+ );
320
+
321
+ assert.deepEqual(installs, [
322
+ {
323
+ args: ["install"],
324
+ command: "pnpm",
325
+ cwd: path.join(tempRoot, "pnpm-app"),
326
+ shell: false,
327
+ },
328
+ ]);
329
+ assert.match(stdout.text, /Installing dependencies with pnpm/);
280
330
  assert.match(stdout.text, /pnpm dev/);
281
331
  });
282
332
 
333
+ it("reports recovery steps when dependency installation command is missing", async () => {
334
+ const tempRoot = await createTempRoot();
335
+ const stdout = createWritableCapture();
336
+ const stderr = createWritableCapture();
337
+ const commands = [];
338
+ let exitCode;
339
+
340
+ const result = await runToolcraftCli(
341
+ ["create", "missing-npm-app", "--name", "Missing Npm App", "--yes", "--force"],
342
+ {
343
+ cwd: tempRoot,
344
+ env: {
345
+ npm_config_user_agent: "npm/10.9.4 node/v24.4.1 darwin arm64",
346
+ },
347
+ stderr,
348
+ stdout,
349
+ setExitCode(value) {
350
+ exitCode = value;
351
+ },
352
+ async runCommand(command, args, options) {
353
+ commands.push({ args, command, cwd: options.cwd });
354
+ const error = new Error("spawn npm ENOENT");
355
+ error.code = "ENOENT";
356
+ throw error;
357
+ },
358
+ },
359
+ );
360
+
361
+ assert.equal(result.ok, false);
362
+ assert.equal(exitCode, 1);
363
+ assert.deepEqual(commands, [
364
+ {
365
+ args: ["install"],
366
+ command: "npm",
367
+ cwd: path.join(tempRoot, "missing-npm-app"),
368
+ },
369
+ ]);
370
+ assert.ok(await fs.stat(path.join(tempRoot, "missing-npm-app/src/app/app-schema.ts")));
371
+ assert.match(stderr.text, /Toolcraft app created at .*missing-npm-app, but setup did not finish/);
372
+ assert.match(stderr.text, /npm was not found in PATH/);
373
+ assert.match(stderr.text, /cd .*missing-npm-app/);
374
+ assert.match(stderr.text, /npm install/);
375
+ assert.match(stderr.text, /Toolcraft skills were not installed/);
376
+ assert.match(stderr.text, /npm run dev/);
377
+ assert.doesNotMatch(stdout.text, /Installing Toolcraft skills/);
378
+ });
379
+
380
+ it("does not mention skipped skills when dependency installation fails with --no-skills", async () => {
381
+ const tempRoot = await createTempRoot();
382
+ const stdout = createWritableCapture();
383
+ const stderr = createWritableCapture();
384
+ let exitCode;
385
+
386
+ const result = await runToolcraftCli(
387
+ [
388
+ "create",
389
+ "missing-npm-no-skills-app",
390
+ "--name",
391
+ "Missing Npm No Skills App",
392
+ "--yes",
393
+ "--force",
394
+ "--no-skills",
395
+ ],
396
+ {
397
+ cwd: tempRoot,
398
+ env: {
399
+ npm_config_user_agent: "npm/10.9.4 node/v24.4.1 darwin arm64",
400
+ },
401
+ stderr,
402
+ stdout,
403
+ setExitCode(value) {
404
+ exitCode = value;
405
+ },
406
+ async runCommand() {
407
+ const error = new Error("spawn npm ENOENT");
408
+ error.code = "ENOENT";
409
+ throw error;
410
+ },
411
+ },
412
+ );
413
+
414
+ assert.equal(result.ok, false);
415
+ assert.equal(exitCode, 1);
416
+ assert.match(stderr.text, /npm was not found in PATH/);
417
+ assert.doesNotMatch(stderr.text, /Toolcraft skills were not installed/);
418
+ });
419
+
283
420
  it("forwards skills add compatible options", async () => {
284
421
  const tempRoot = await createTempRoot();
285
422
  const skillsCommands = [];
@@ -308,7 +445,7 @@ describe("runToolcraftCli", () => {
308
445
  throwOnError: true,
309
446
  toolcraftSkillsSourceDir: skillsSourceDir,
310
447
  async runCommand(command, args, options) {
311
- skillsCommands.push({ args, command, cwd: options.cwd });
448
+ skillsCommands.push({ args, command, cwd: options.cwd, shell: options.shell });
312
449
  },
313
450
  },
314
451
  );
@@ -331,6 +468,7 @@ describe("runToolcraftCli", () => {
331
468
  ],
332
469
  command: process.execPath,
333
470
  cwd: path.join(tempRoot, "skills-options-app"),
471
+ shell: false,
334
472
  },
335
473
  ]);
336
474
  });
@@ -0,0 +1,71 @@
1
+ import spawn from "cross-spawn";
2
+
3
+ export class CommandRunError extends Error {
4
+ constructor(command, args, options, details = {}) {
5
+ super(details.message);
6
+ this.name = "CommandRunError";
7
+ this.args = args;
8
+ this.code = details.code;
9
+ this.command = command;
10
+ this.cwd = options.cwd;
11
+ this.exitCode = details.exitCode;
12
+ this.signal = details.signal;
13
+ }
14
+ }
15
+
16
+ export function getErrorCode(error) {
17
+ return error && typeof error === "object" ? error.code : undefined;
18
+ }
19
+
20
+ export function runCommand(command, args, options = {}, context = {}) {
21
+ if (context.runCommand) {
22
+ return context.runCommand(command, args, options);
23
+ }
24
+
25
+ return new Promise((resolve, reject) => {
26
+ let settled = false;
27
+ const settle = (callback) => {
28
+ if (settled) {
29
+ return;
30
+ }
31
+
32
+ settled = true;
33
+ callback();
34
+ };
35
+
36
+ const child = spawn(command, args, {
37
+ cwd: options.cwd,
38
+ env: options.env,
39
+ shell: options.shell ?? false,
40
+ stdio: options.stdio ?? "inherit",
41
+ });
42
+
43
+ child.on("error", (error) => {
44
+ settle(() =>
45
+ reject(
46
+ new CommandRunError(command, args, options, {
47
+ code: error.code,
48
+ message:
49
+ error.code === "ENOENT" ? `Command not found: ${command}` : error.message,
50
+ }),
51
+ ),
52
+ );
53
+ });
54
+ child.on("close", (exitCode, signal) => {
55
+ settle(() => {
56
+ if (exitCode === 0) {
57
+ resolve();
58
+ return;
59
+ }
60
+
61
+ reject(
62
+ new CommandRunError(command, args, options, {
63
+ exitCode,
64
+ message: `${command} ${args.join(" ")} failed with exit code ${exitCode}.`,
65
+ signal,
66
+ }),
67
+ );
68
+ });
69
+ });
70
+ });
71
+ }
@@ -0,0 +1,87 @@
1
+ import { getErrorCode, runCommand } from "./command-runner.mjs";
2
+ import {
3
+ createInstallCommand,
4
+ createInstallHelp,
5
+ createRunScriptCommand,
6
+ normalizePackageManager,
7
+ } from "./package-manager.mjs";
8
+
9
+ function writeLine(stream, message = "") {
10
+ stream.write(`${message}\n`);
11
+ }
12
+
13
+ export function createDependencyInstallError(
14
+ error,
15
+ result,
16
+ packageManager,
17
+ { skillsRequested = true } = {},
18
+ ) {
19
+ const normalizedPackageManager = normalizePackageManager(packageManager);
20
+ const installCommand = `${normalizedPackageManager} install`;
21
+ const devCommand = createRunScriptCommand(normalizedPackageManager, "dev");
22
+ const commandMissing = getErrorCode(error) === "ENOENT";
23
+ const lines = [`Toolcraft app created at ${result.targetDir}, but setup did not finish.`, ""];
24
+
25
+ if (commandMissing) {
26
+ lines.push(
27
+ `Dependency installation failed because ${normalizedPackageManager} was not found in PATH.`,
28
+ "",
29
+ `Install ${normalizedPackageManager}:`,
30
+ "",
31
+ ...createInstallHelp(normalizedPackageManager),
32
+ );
33
+ } else {
34
+ lines.push(
35
+ "Dependency installation failed while running:",
36
+ "",
37
+ ` ${installCommand}`,
38
+ "",
39
+ `Original error: ${error instanceof Error ? error.message : String(error)}`,
40
+ );
41
+ }
42
+
43
+ lines.push("", "Then finish setup:", "", ` cd ${result.targetDir}`, ` ${installCommand}`);
44
+
45
+ if (skillsRequested) {
46
+ lines.push("", "Toolcraft skills were not installed because dependency installation failed.");
47
+ }
48
+
49
+ lines.push("", "After setup, start the app with:", "", ` ${devCommand}`);
50
+
51
+ return new Error(lines.join("\n"));
52
+ }
53
+
54
+ export async function installGeneratedAppDependencies({
55
+ context = {},
56
+ packageManager,
57
+ result,
58
+ skillsRequested = true,
59
+ stdout,
60
+ }) {
61
+ const normalizedPackageManager = normalizePackageManager(packageManager);
62
+ const installCommand = createInstallCommand(normalizedPackageManager);
63
+
64
+ writeLine(stdout, "");
65
+ writeLine(stdout, `Installing dependencies with ${normalizedPackageManager}...`);
66
+
67
+ try {
68
+ await runCommand(
69
+ installCommand.command,
70
+ installCommand.args,
71
+ {
72
+ cwd: result.targetDir,
73
+ env: {
74
+ ...process.env,
75
+ ...(context.env ?? {}),
76
+ },
77
+ shell: false,
78
+ stdio: "inherit",
79
+ },
80
+ context,
81
+ );
82
+ } catch (error) {
83
+ throw createDependencyInstallError(error, result, normalizedPackageManager, {
84
+ skillsRequested,
85
+ });
86
+ }
87
+ }
package/src/generate.mjs CHANGED
@@ -11,6 +11,11 @@ import {
11
11
  pathExists,
12
12
  removeDirectory,
13
13
  } from "./copy-recursive.mjs";
14
+ import {
15
+ DEFAULT_PACKAGE_MANAGER,
16
+ normalizePackageManager,
17
+ replaceGeneratedCommandReferences,
18
+ } from "./package-manager.mjs";
14
19
  import {
15
20
  createGeneratedPackageJson,
16
21
  createGeneratedTsConfig,
@@ -50,8 +55,29 @@ function createRelativePath(fromDir, toDir) {
50
55
  return relativePath === "" ? "." : relativePath;
51
56
  }
52
57
 
53
- function rewriteGeneratedAppText(source) {
54
- return rewriteGeneratedText(source)
58
+ function shouldReplacePackageManagerCommands(filePath, targetDir) {
59
+ const relativePath = path.relative(targetDir, filePath).split(path.sep).join("/");
60
+
61
+ return (
62
+ relativePath === "AGENTS.md" ||
63
+ relativePath === "playwright.config.ts" ||
64
+ relativePath === "scripts/check-toolcraft-docs.mjs" ||
65
+ /^docs\/toolcraft\/.+\.md$/.test(relativePath)
66
+ );
67
+ }
68
+
69
+ function rewriteGeneratedAppText(
70
+ source,
71
+ filePath,
72
+ { packageManager = DEFAULT_PACKAGE_MANAGER, targetDir } = {},
73
+ ) {
74
+ const rewrittenSource = rewriteGeneratedText(source);
75
+ const commandSource =
76
+ targetDir && shouldReplacePackageManagerCommands(filePath, targetDir)
77
+ ? replaceGeneratedCommandReferences(rewrittenSource, packageManager)
78
+ : rewrittenSource;
79
+
80
+ return commandSource
55
81
  .replaceAll("starterAcceptance", "appAcceptance")
56
82
  .replaceAll("starter-acceptance", "app-acceptance")
57
83
  .replaceAll("starterProductReadiness", "appProductReadiness")
@@ -218,6 +244,7 @@ export function getDefaultSourcePaths(repoRoot = REPO_ROOT) {
218
244
  export async function generateToolcraft(options = {}) {
219
245
  const cwd = options.cwd ?? process.cwd();
220
246
  const targetDir = path.resolve(cwd, options.targetDir ?? ".");
247
+ const packageManager = normalizePackageManager(options.packageManager ?? DEFAULT_PACKAGE_MANAGER);
221
248
  const sourcePaths = options.sourcePaths ?? getDefaultSourcePaths(options.repoRoot ?? REPO_ROOT);
222
249
 
223
250
  await assertDirectory(sourcePaths.starterDir, "Starter app");
@@ -226,6 +253,7 @@ export async function generateToolcraft(options = {}) {
226
253
  const starterPackageJson = await readJson(path.join(sourcePaths.starterDir, "package.json"));
227
254
  const packageJson = createGeneratedPackageJson({
228
255
  name: options.name ?? path.basename(targetDir),
256
+ packageManager,
229
257
  starterPackageJson,
230
258
  });
231
259
  const projectTitle = normalizeProjectTitle(packageJson.name);
@@ -243,8 +271,8 @@ export async function generateToolcraft(options = {}) {
243
271
  await copyDirectory(sourcePaths.toolcraftSrc, path.join(toolcraftRoot, "runtime"));
244
272
  await removeToolcraftTestFiles(toolcraftRoot);
245
273
 
246
- const changedFiles = await rewriteTextFiles(targetDir, (source) =>
247
- rewriteGeneratedAppText(source),
274
+ const changedFiles = await rewriteTextFiles(targetDir, (source, filePath) =>
275
+ rewriteGeneratedAppText(source, filePath, { packageManager, targetDir }),
248
276
  );
249
277
  await writeGeneratedProjectTitle(targetDir, projectTitle);
250
278
  await writeToolcraftIntegrityManifest(toolcraftRoot);