epicshop 6.68.0 → 6.69.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/dist/cli.js CHANGED
@@ -1,12 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import '@epic-web/workshop-utils/init-env';
3
- import { PACKAGE_MANAGERS, getPackageManager, isPackageManagerConfigured, setPackageManager, } from '@epic-web/workshop-utils/workshops.server';
4
3
  import chalk from 'chalk';
5
4
  import { matchSorter } from 'match-sorter';
6
5
  import yargs from 'yargs';
7
6
  import { hideBin } from 'yargs/helpers';
8
- import { assertCanPrompt, hasTty, isCiEnvironment, } from "./utils/cli-runtime.js";
9
- import { detectRuntimePackageManager } from "./utils/package-manager.js";
7
+ import { assertCanPrompt } from "./utils/cli-runtime.js";
10
8
  import { initCliSentry } from "./utils/sentry-cli.js";
11
9
  // Check for --help on start command before yargs parses
12
10
  // (yargs exits before command handler when help is requested)
@@ -30,43 +28,6 @@ function formatHelp(helpText) {
30
28
  .replace(/--[\w-]+/g, (match) => chalk.yellow(match))
31
29
  .replace(/-\w(?=\s|,)/g, (match) => chalk.yellow(match));
32
30
  }
33
- async function maybePromptToUpdatePackageManager(parsedArgs) {
34
- if (parsedArgs.includes('--help') || parsedArgs.includes('-h'))
35
- return;
36
- if (parsedArgs.includes('--silent') || parsedArgs.includes('-s'))
37
- return;
38
- if (parsedArgs[0] === 'config')
39
- return;
40
- if (isCiEnvironment() || !hasTty())
41
- return;
42
- const runtimeManager = detectRuntimePackageManager();
43
- if (!runtimeManager)
44
- return;
45
- const isConfigured = await isPackageManagerConfigured();
46
- if (!isConfigured)
47
- return;
48
- const configuredManager = await getPackageManager();
49
- if (configuredManager === runtimeManager)
50
- return;
51
- const { confirm } = await import('@inquirer/prompts');
52
- const shouldUpdate = await confirm({
53
- message: `You ran epicshop with ${runtimeManager}, but your default package manager is ${configuredManager}. Update the default?`,
54
- default: true,
55
- });
56
- if (shouldUpdate) {
57
- await setPackageManager(runtimeManager);
58
- console.log(chalk.green(`✅ Default package manager updated to ${runtimeManager}.`));
59
- }
60
- }
61
- try {
62
- await maybePromptToUpdatePackageManager(args);
63
- }
64
- catch (error) {
65
- if (error.message === 'USER_QUIT') {
66
- process.exit(0);
67
- }
68
- // Silently ignore other errors during package manager prompt to avoid disrupting CLI startup
69
- }
70
31
  // Set up yargs CLI
71
32
  const cli = yargs(args)
72
33
  .scriptName('epicshop')
@@ -323,11 +284,6 @@ const cli = yargs(args)
323
284
  .option('repos-dir', {
324
285
  type: 'string',
325
286
  description: 'Set the default directory for workshop repos',
326
- })
327
- .option('package-manager', {
328
- type: 'string',
329
- choices: PACKAGE_MANAGERS,
330
- description: 'Set the default package manager',
331
287
  })
332
288
  .option('silent', {
333
289
  alias: 's',
@@ -343,7 +299,6 @@ const cli = yargs(args)
343
299
  const result = await config({
344
300
  subcommand: argv.subcommand === 'reset' ? 'reset' : undefined,
345
301
  reposDir: argv.reposDir,
346
- packageManager: argv.packageManager,
347
302
  silent: argv.silent,
348
303
  });
349
304
  if (!result.success) {
@@ -7,4 +7,12 @@ export type SetupResult = {
7
7
  message?: string;
8
8
  error?: Error;
9
9
  };
10
+ /**
11
+ * Install workshop dependencies in the current directory.
12
+ * Must be run from within a workshop directory (containing package.json).
13
+ *
14
+ * Automatically detects and uses the package manager based on how epicshop was
15
+ * invoked (e.g., pnpm dlx epicshop setup uses pnpm, bunx epicshop setup uses bun).
16
+ * This is handled by pkgmgr, which detects the runtime package manager.
17
+ */
10
18
  export declare function setup(options?: SetupOptions): Promise<SetupResult>;
@@ -1,11 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { getErrorMessage } from '@epic-web/workshop-utils/utils';
4
- import { getPackageManager, isPackageManagerConfigured, } from '@epic-web/workshop-utils/workshops.server';
5
4
  import chalk from 'chalk';
6
- import { execa } from 'execa';
7
- import { resolveCliCommand, runCommand, } from "../utils/command-runner.js";
8
- import { formatPackageManagerCommand, getPackageManagerInstallArgs, getPackageManagerRunArgs, } from "../utils/package-manager.js";
5
+ import { runCommand, } from "../utils/command-runner.js";
9
6
  function isPackageJson(value) {
10
7
  if (!value || typeof value !== 'object')
11
8
  return false;
@@ -18,27 +15,6 @@ function isPackageJson(value) {
18
15
  return false;
19
16
  return Object.values(scriptsValue).every((script) => typeof script === 'string');
20
17
  }
21
- async function getPackageManagerVersion(packageManager) {
22
- try {
23
- const result = await execa(resolveCliCommand(packageManager), ['--version'], {
24
- stdio: 'pipe',
25
- });
26
- return { success: true, version: result.stdout.trim() };
27
- }
28
- catch (error) {
29
- const message = getErrorMessage(error, 'Failed to check package manager');
30
- const err = error instanceof Error ? error : new Error(message);
31
- return { success: false, error: err };
32
- }
33
- }
34
- function isNpmVersionSupported(version) {
35
- const [majorString, minorString] = version.split('.');
36
- const major = Number(majorString);
37
- const minor = Number(minorString);
38
- if (!Number.isFinite(major) || !Number.isFinite(minor))
39
- return false;
40
- return major > 8 || (major === 8 && minor >= 16);
41
- }
42
18
  function formatCommandResultError(result, fallbackMessage) {
43
19
  return {
44
20
  success: false,
@@ -46,6 +22,14 @@ function formatCommandResultError(result, fallbackMessage) {
46
22
  error: result.error,
47
23
  };
48
24
  }
25
+ /**
26
+ * Install workshop dependencies in the current directory.
27
+ * Must be run from within a workshop directory (containing package.json).
28
+ *
29
+ * Automatically detects and uses the package manager based on how epicshop was
30
+ * invoked (e.g., pnpm dlx epicshop setup uses pnpm, bunx epicshop setup uses bun).
31
+ * This is handled by pkgmgr, which detects the runtime package manager.
32
+ */
49
33
  export async function setup(options = {}) {
50
34
  const { silent = false } = options;
51
35
  const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
@@ -74,39 +58,12 @@ export async function setup(options = {}) {
74
58
  }
75
59
  return { success: false, message, error: error };
76
60
  }
77
- const packageManager = await getPackageManager();
78
- const isConfigured = await isPackageManagerConfigured();
79
- const managerLabel = isConfigured
80
- ? packageManager
81
- : `${packageManager} (default)`;
82
- const versionResult = await getPackageManagerVersion(packageManager);
83
- if (!versionResult.success || !versionResult.version) {
84
- const message = `Failed to run ${packageManager} --version. Please ensure ${packageManager} is installed.`;
85
- if (!silent) {
86
- console.error(chalk.red(`❌ ${message}`));
87
- }
88
- return {
89
- success: false,
90
- message,
91
- error: versionResult.error ?? new Error(message),
92
- };
93
- }
94
- if (packageManager === 'npm' &&
95
- !isNpmVersionSupported(versionResult.version)) {
96
- const message = `npm version is ${versionResult.version} which is out of date. Please install npm@8.16.0 or greater.`;
97
- if (!silent) {
98
- console.error(chalk.red(`❌ ${message}`));
99
- }
100
- return { success: false, message, error: new Error(message) };
101
- }
102
- const installArgs = getPackageManagerInstallArgs(packageManager);
103
- const installCommand = formatPackageManagerCommand(packageManager, installArgs);
104
61
  if (!silent) {
105
- console.log(chalk.cyan(`📦 Installing dependencies using ${chalk.bold(managerLabel)}...`));
106
- console.log(chalk.gray(` To change this, run: npx epicshop config --package-manager <npm|pnpm|yarn|bun>`));
107
- console.log(chalk.gray(` Running: ${installCommand}`));
62
+ console.log(chalk.cyan(`📦 Installing dependencies using ${chalk.bold('pkgmgr')}...`));
63
+ console.log(chalk.gray(` pkgmgr automatically detects your package manager (npm, pnpm, yarn, or bun)`));
64
+ console.log(chalk.gray(` Running: pkgmgr install`));
108
65
  }
109
- const installResult = await runCommand(packageManager, installArgs, {
66
+ const installResult = await runCommand('pkgmgr', ['install'], {
110
67
  cwd,
111
68
  silent,
112
69
  });
@@ -115,12 +72,10 @@ export async function setup(options = {}) {
115
72
  }
116
73
  const hasCustomSetup = Boolean(scripts?.['setup:custom']);
117
74
  if (hasCustomSetup) {
118
- const customArgs = getPackageManagerRunArgs(packageManager, 'setup:custom');
119
- const customCommand = formatPackageManagerCommand(packageManager, customArgs);
120
75
  if (!silent) {
121
- console.log(chalk.cyan(`🔧 Running ${customCommand}...`));
76
+ console.log(chalk.cyan(`🔧 Running npm run setup:custom...`));
122
77
  }
123
- const customResult = await runCommand(packageManager, customArgs, {
78
+ const customResult = await runCommand('npm', ['run', 'setup:custom'], {
124
79
  cwd,
125
80
  silent,
126
81
  });
@@ -1,5 +1,4 @@
1
1
  import '@epic-web/workshop-utils/init-env';
2
- import { type PackageManager } from '@epic-web/workshop-utils/workshops.server';
3
2
  /**
4
3
  * Find the workshop root directory by walking up from the current directory
5
4
  * looking for a package.json with an epicshop field.
@@ -28,7 +27,6 @@ export type StartOptions = {
28
27
  };
29
28
  export type ConfigOptions = {
30
29
  reposDir?: string;
31
- packageManager?: PackageManager;
32
30
  silent?: boolean;
33
31
  subcommand?: 'reset' | 'delete';
34
32
  };
@@ -6,13 +6,11 @@ import { cachified, githubCache } from '@epic-web/workshop-utils/cache.server';
6
6
  import { parseEpicshopConfig } from '@epic-web/workshop-utils/config.server';
7
7
  import { getAuthInfo } from '@epic-web/workshop-utils/db.server';
8
8
  import { userHasAccessToWorkshop } from '@epic-web/workshop-utils/epic-api.server';
9
- import { PACKAGE_MANAGERS, clearPackageManager, getPackageManager, isPackageManagerConfigured, setPackageManager, } from '@epic-web/workshop-utils/workshops.server';
10
9
  import chalk from 'chalk';
11
10
  import { matchSorter, rankings } from 'match-sorter';
12
11
  import ora from 'ora';
13
12
  import { assertCanPrompt, isCiEnvironment } from "../utils/cli-runtime.js";
14
13
  import { runCommand, runCommandInteractive } from "../utils/command-runner.js";
15
- import { formatPackageManagerCommand, getPackageManagerRunArgs, } from "../utils/package-manager.js";
16
14
  import { setup } from "./setup.js";
17
15
  const GITHUB_ORG = 'epicweb-dev';
18
16
  const TUTORIAL_REPO = 'epicshop-tutorial';
@@ -789,8 +787,7 @@ export async function list({ silent = false, } = {}) {
789
787
  });
790
788
  },
791
789
  });
792
- const packageManager = await getPackageManager();
793
- const startCommand = formatPackageManagerCommand(packageManager, getPackageManagerRunArgs(packageManager, 'start'));
790
+ const startCommand = 'npm run start';
794
791
  // Show actions for selected workshop
795
792
  const actionChoices = [
796
793
  {
@@ -1081,10 +1078,8 @@ export async function startWorkshop(options = {}) {
1081
1078
  console.log(chalk.cyan(`🚀 Starting ${chalk.bold(workshopToStart.title)}...`));
1082
1079
  console.log(chalk.gray(` Path: ${workshopToStart.path}\n`));
1083
1080
  }
1084
- const packageManager = await getPackageManager();
1085
- const startArgs = getPackageManagerRunArgs(packageManager, 'start');
1086
1081
  // Run start script in the workshop directory
1087
- const startResult = await runCommandInteractive(packageManager, startArgs, {
1082
+ const startResult = await runCommandInteractive('npm', ['run', 'start'], {
1088
1083
  cwd: workshopToStart.path,
1089
1084
  });
1090
1085
  if (!startResult.success) {
@@ -1292,13 +1287,6 @@ export async function config(options = {}) {
1292
1287
  if (!silent)
1293
1288
  console.log(chalk.green(`✅ ${message}`));
1294
1289
  }
1295
- if (options.packageManager) {
1296
- await setPackageManager(options.packageManager);
1297
- const message = `Package manager set to: ${options.packageManager}`;
1298
- messages.push(message);
1299
- if (!silent)
1300
- console.log(chalk.green(`✅ ${message}`));
1301
- }
1302
1290
  // If either option was set, return now
1303
1291
  if (messages.length > 0) {
1304
1292
  return { success: true, message: messages.join('; ') };
@@ -1313,16 +1301,13 @@ export async function config(options = {}) {
1313
1301
  reason: 'select a configuration option',
1314
1302
  hints: [
1315
1303
  'Set repos dir directly: npx epicshop config --repos-dir <path>',
1316
- 'Set package manager directly: npx epicshop config --package-manager <npm|pnpm|yarn|bun>',
1317
1304
  'Delete config non-interactively: npx epicshop config reset --silent',
1318
1305
  ],
1319
1306
  });
1320
- const { search, confirm, select } = await import('@inquirer/prompts');
1307
+ const { search, confirm } = await import('@inquirer/prompts');
1321
1308
  const reposDir = await getReposDirectory();
1322
1309
  const isConfigured = await isReposDirectoryConfigured();
1323
1310
  const defaultDir = getDefaultReposDir();
1324
- const packageManager = await getPackageManager();
1325
- const isPackageManagerSet = await isPackageManagerConfigured();
1326
1311
  // Build config options
1327
1312
  const configOptions = [
1328
1313
  {
@@ -1330,13 +1315,6 @@ export async function config(options = {}) {
1330
1315
  value: 'repos-dir',
1331
1316
  description: isConfigured ? reposDir : `${reposDir} (default)`,
1332
1317
  },
1333
- {
1334
- name: `Package manager`,
1335
- value: 'package-manager',
1336
- description: isPackageManagerSet
1337
- ? packageManager
1338
- : `${packageManager} (default)`,
1339
- },
1340
1318
  {
1341
1319
  name: `Reset config file`,
1342
1320
  value: 'reset',
@@ -1455,87 +1433,6 @@ export async function config(options = {}) {
1455
1433
  return { success: true, message: 'Cancelled' };
1456
1434
  }
1457
1435
  }
1458
- if (selectedConfig === 'package-manager') {
1459
- console.log();
1460
- console.log(chalk.bold(' Current value:'));
1461
- if (isPackageManagerSet) {
1462
- console.log(chalk.white(` ${packageManager}`));
1463
- }
1464
- else {
1465
- console.log(chalk.gray(` ${packageManager} (default, not explicitly set)`));
1466
- }
1467
- console.log();
1468
- const actionChoices = [
1469
- {
1470
- name: 'Edit',
1471
- value: 'edit',
1472
- description: 'Change the default package manager',
1473
- },
1474
- ...(isPackageManagerSet
1475
- ? [
1476
- {
1477
- name: 'Remove',
1478
- value: 'remove',
1479
- description: 'Reset to default (npm)',
1480
- },
1481
- ]
1482
- : []),
1483
- {
1484
- name: 'Cancel',
1485
- value: 'cancel',
1486
- description: 'Go back without changes',
1487
- },
1488
- ];
1489
- const action = await search({
1490
- message: 'What would you like to do?',
1491
- source: async (input) => {
1492
- if (!input)
1493
- return actionChoices;
1494
- return matchSorter(actionChoices, input, {
1495
- keys: ['name', 'value', 'description'],
1496
- });
1497
- },
1498
- });
1499
- if (action === 'edit') {
1500
- const selectedManager = await select({
1501
- message: 'Select a package manager:',
1502
- choices: PACKAGE_MANAGERS.map((manager) => ({
1503
- name: manager,
1504
- value: manager,
1505
- })),
1506
- });
1507
- await setPackageManager(selectedManager);
1508
- console.log();
1509
- console.log(chalk.green(`✅ Package manager set to: ${chalk.bold(selectedManager)}`));
1510
- return {
1511
- success: true,
1512
- message: `Package manager set to: ${selectedManager}`,
1513
- };
1514
- }
1515
- else if (action === 'remove') {
1516
- const shouldRemove = await confirm({
1517
- message: 'Reset package manager to default (npm)?',
1518
- default: false,
1519
- });
1520
- if (shouldRemove) {
1521
- await clearPackageManager();
1522
- console.log();
1523
- console.log(chalk.green(`✅ Package manager reset to default (npm).`));
1524
- return {
1525
- success: true,
1526
- message: 'Package manager reset to default (npm).',
1527
- };
1528
- }
1529
- else {
1530
- console.log(chalk.gray('\nNo changes made.'));
1531
- return { success: true, message: 'Cancelled' };
1532
- }
1533
- }
1534
- else {
1535
- console.log(chalk.gray('\nNo changes made.'));
1536
- return { success: true, message: 'Cancelled' };
1537
- }
1538
- }
1539
1436
  return { success: true, message: 'Config viewed' };
1540
1437
  }
1541
1438
  catch (error) {
@@ -1822,8 +1719,7 @@ async function promptAndSetupAccessibleWorkshops() {
1822
1719
  const { workshopExists } = await import('@epic-web/workshop-utils/workshops.server');
1823
1720
  console.log(chalk.bold.cyan('\n📚 Workshop Setup\n'));
1824
1721
  console.log(chalk.cyan('🐨 Next, you can select any workshops you’d like me to set up for you.'));
1825
- const packageManager = await getPackageManager();
1826
- console.log(chalk.gray(` This will clone each workshop repo into your workshops directory and run setup using ${packageManager}.\n` +
1722
+ console.log(chalk.gray(` This will clone each workshop repo into your workshops directory and run setup.\n` +
1827
1723
  ' (If something fails, we’ll keep going and you can retry later with `npx epicshop add`.)\n'));
1828
1724
  assertCanPrompt({
1829
1725
  reason: 'select workshops to set up',
@@ -2132,10 +2028,8 @@ async function ensureTutorialAndStart() {
2132
2028
  }
2133
2029
  await promptToStartTutorial(workshopTitle);
2134
2030
  console.log(chalk.cyan(`\n🚀 Starting ${chalk.bold(workshopTitle)}...\n`));
2135
- const packageManager = await getPackageManager();
2136
- const startArgs = getPackageManagerRunArgs(packageManager, 'start');
2137
2031
  // Start the workshop
2138
- const startResult = await runCommandInteractive(packageManager, startArgs, {
2032
+ const startResult = await runCommandInteractive('npm', ['run', 'start'], {
2139
2033
  cwd: workshopPath,
2140
2034
  });
2141
2035
  if (!startResult.success) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epicshop",
3
- "version": "6.68.0",
3
+ "version": "6.69.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -99,7 +99,7 @@
99
99
  "build:watch": "nx watch --projects=epicshop -- nx run \\$NX_PROJECT_NAME:build"
100
100
  },
101
101
  "dependencies": {
102
- "@epic-web/workshop-utils": "6.68.0",
102
+ "@epic-web/workshop-utils": "6.69.0",
103
103
  "@inquirer/prompts": "^8.2.0",
104
104
  "@sentry/node": "^10.35.0",
105
105
  "chalk": "^5.6.2",
@@ -1,5 +0,0 @@
1
- import { type PackageManager } from '@epic-web/workshop-utils/workshops.server';
2
- export declare function detectRuntimePackageManager(): PackageManager | null;
3
- export declare function getPackageManagerInstallArgs(_packageManager: PackageManager): string[];
4
- export declare function getPackageManagerRunArgs(_packageManager: PackageManager, script: string): string[];
5
- export declare function formatPackageManagerCommand(packageManager: PackageManager, args: string[]): string;
@@ -1,27 +0,0 @@
1
- function detectPackageManager(value) {
2
- if (!value)
3
- return null;
4
- if (value.includes('pnpm'))
5
- return 'pnpm';
6
- if (value.includes('yarn'))
7
- return 'yarn';
8
- if (value.includes('bun'))
9
- return 'bun';
10
- if (value.includes('npm'))
11
- return 'npm';
12
- return null;
13
- }
14
- export function detectRuntimePackageManager() {
15
- const userAgent = (process.env.npm_config_user_agent ?? '').toLowerCase();
16
- const execPath = (process.env.npm_execpath ?? '').toLowerCase();
17
- return detectPackageManager(userAgent) ?? detectPackageManager(execPath);
18
- }
19
- export function getPackageManagerInstallArgs(_packageManager) {
20
- return ['install'];
21
- }
22
- export function getPackageManagerRunArgs(_packageManager, script) {
23
- return ['run', script];
24
- }
25
- export function formatPackageManagerCommand(packageManager, args) {
26
- return `${packageManager} ${args.join(' ')}`.trim();
27
- }