epicshop 6.80.2 → 6.82.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
@@ -28,6 +28,13 @@ function formatHelp(helpText) {
28
28
  .replace(/--[\w-]+/g, (match) => chalk.yellow(match))
29
29
  .replace(/-\w(?=\s|,)/g, (match) => chalk.yellow(match));
30
30
  }
31
+ function resolveWorkshopContextCwd(explicitWorkshopDir) {
32
+ const fromFlag = explicitWorkshopDir?.trim() ? explicitWorkshopDir.trim() : undefined;
33
+ if (fromFlag)
34
+ return fromFlag;
35
+ const fromEnv = process.env.EPICSHOP_CONTEXT_CWD;
36
+ return fromEnv?.trim() ? fromEnv.trim() : undefined;
37
+ }
31
38
  // Set up yargs CLI
32
39
  const cli = yargs(args)
33
40
  .scriptName('epicshop')
@@ -767,6 +774,11 @@ const cli = yargs(args)
767
774
  type: 'boolean',
768
775
  description: 'Output saved playgrounds as JSON (saved list)',
769
776
  default: false,
777
+ })
778
+ .option('workshop-dir', {
779
+ alias: 'w',
780
+ type: 'string',
781
+ description: 'Path to a workshop directory to use as context (instead of the current working directory)',
770
782
  })
771
783
  .option('silent', {
772
784
  alias: 's',
@@ -784,9 +796,9 @@ const cli = yargs(args)
784
796
  .example('$0 playground saved 2026.01.18_11.12.00_01.01.problem', 'Set playground from a saved copy');
785
797
  }, async (argv) => {
786
798
  const { findWorkshopRoot } = await import("./commands/workshops.js");
787
- const workshopRoot = await findWorkshopRoot();
799
+ const workshopRoot = await findWorkshopRoot(resolveWorkshopContextCwd(argv.workshopDir));
788
800
  if (!workshopRoot) {
789
- console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
801
+ console.error(chalk.red('❌ Workshop not found. Please cd into a workshop directory or pass --workshop-dir.'));
790
802
  process.exit(1);
791
803
  }
792
804
  const originalCwd = process.cwd();
@@ -903,6 +915,11 @@ const cli = yargs(args)
903
915
  type: 'boolean',
904
916
  description: 'Output as JSON',
905
917
  default: false,
918
+ })
919
+ .option('workshop-dir', {
920
+ alias: 'w',
921
+ type: 'string',
922
+ description: 'Path to a workshop directory to use as context (instead of the current working directory)',
906
923
  })
907
924
  .option('silent', {
908
925
  alias: 's',
@@ -917,9 +934,9 @@ const cli = yargs(args)
917
934
  .example('$0 progress update 01-01-problem --incomplete', 'Mark lesson as incomplete');
918
935
  }, async (argv) => {
919
936
  const { findWorkshopRoot } = await import("./commands/workshops.js");
920
- const workshopRoot = await findWorkshopRoot();
937
+ const workshopRoot = await findWorkshopRoot(resolveWorkshopContextCwd(argv.workshopDir));
921
938
  if (!workshopRoot) {
922
- console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
939
+ console.error(chalk.red('❌ Workshop not found. Please cd into a workshop directory or pass --workshop-dir.'));
923
940
  process.exit(1);
924
941
  }
925
942
  const originalCwd = process.cwd();
@@ -970,14 +987,19 @@ const cli = yargs(args)
970
987
  type: 'boolean',
971
988
  description: 'Run without output logs',
972
989
  default: false,
990
+ })
991
+ .option('workshop-dir', {
992
+ alias: 'w',
993
+ type: 'string',
994
+ description: 'Path to a workshop directory to use as context (instead of the current working directory)',
973
995
  })
974
996
  .example('$0 diff', 'Select apps to diff (defaults to playground vs solution)')
975
997
  .example('$0 diff 01.02.problem 01.02.solution', 'Show diff between two apps');
976
998
  }, async (argv) => {
977
999
  const { findWorkshopRoot } = await import("./commands/workshops.js");
978
- const workshopRoot = await findWorkshopRoot();
1000
+ const workshopRoot = await findWorkshopRoot(resolveWorkshopContextCwd(argv.workshopDir));
979
1001
  if (!workshopRoot) {
980
- console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
1002
+ console.error(chalk.red('❌ Workshop not found. Please cd into a workshop directory or pass --workshop-dir.'));
981
1003
  process.exit(1);
982
1004
  }
983
1005
  const originalCwd = process.cwd();
@@ -1027,6 +1049,11 @@ const cli = yargs(args)
1027
1049
  type: 'boolean',
1028
1050
  description: 'Run without output logs',
1029
1051
  default: false,
1052
+ })
1053
+ .option('workshop-dir', {
1054
+ alias: 'w',
1055
+ type: 'string',
1056
+ description: 'Path to a workshop directory to use as context (instead of the current working directory)',
1030
1057
  })
1031
1058
  .example('$0 exercises', 'List all exercises with progress')
1032
1059
  .example('$0 exercises 1', 'Show details for exercise 1')
@@ -1034,9 +1061,9 @@ const cli = yargs(args)
1034
1061
  .example('$0 exercises --json', 'Output exercises as JSON');
1035
1062
  }, async (argv) => {
1036
1063
  const { findWorkshopRoot } = await import("./commands/workshops.js");
1037
- const workshopRoot = await findWorkshopRoot();
1064
+ const workshopRoot = await findWorkshopRoot(resolveWorkshopContextCwd(argv.workshopDir));
1038
1065
  if (!workshopRoot) {
1039
- console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
1066
+ console.error(chalk.red('❌ Workshop not found. Please cd into a workshop directory or pass --workshop-dir.'));
1040
1067
  process.exit(1);
1041
1068
  }
1042
1069
  const originalCwd = process.cwd();
@@ -1087,7 +1114,7 @@ try {
1087
1114
  if (args.length === 0) {
1088
1115
  // Check if we're inside a workshop first
1089
1116
  const { findWorkshopRoot } = await import("./commands/workshops.js");
1090
- const workshopRoot = await findWorkshopRoot();
1117
+ const workshopRoot = await findWorkshopRoot(resolveWorkshopContextCwd());
1091
1118
  // Get workshop title if we're inside one
1092
1119
  let workshopTitle = null;
1093
1120
  if (workshopRoot) {
@@ -1495,7 +1522,7 @@ try {
1495
1522
  }
1496
1523
  case 'exercises': {
1497
1524
  const { findWorkshopRoot } = await import("./commands/workshops.js");
1498
- const wsRoot = await findWorkshopRoot();
1525
+ const wsRoot = await findWorkshopRoot(resolveWorkshopContextCwd());
1499
1526
  if (!wsRoot) {
1500
1527
  console.error(chalk.red('❌ Not inside a workshop directory'));
1501
1528
  process.exit(1);
@@ -1515,7 +1542,7 @@ try {
1515
1542
  }
1516
1543
  case 'playground': {
1517
1544
  const { findWorkshopRoot } = await import("./commands/workshops.js");
1518
- const wsRoot = await findWorkshopRoot();
1545
+ const wsRoot = await findWorkshopRoot(resolveWorkshopContextCwd());
1519
1546
  if (!wsRoot) {
1520
1547
  console.error(chalk.red('❌ Not inside a workshop directory'));
1521
1548
  process.exit(1);
@@ -1535,7 +1562,7 @@ try {
1535
1562
  }
1536
1563
  case 'progress': {
1537
1564
  const { findWorkshopRoot } = await import("./commands/workshops.js");
1538
- const wsRoot = await findWorkshopRoot();
1565
+ const wsRoot = await findWorkshopRoot(resolveWorkshopContextCwd());
1539
1566
  if (!wsRoot) {
1540
1567
  console.error(chalk.red('❌ Not inside a workshop directory'));
1541
1568
  process.exit(1);
@@ -1555,7 +1582,7 @@ try {
1555
1582
  }
1556
1583
  case 'diff': {
1557
1584
  const { findWorkshopRoot } = await import("./commands/workshops.js");
1558
- const wsRoot = await findWorkshopRoot();
1585
+ const wsRoot = await findWorkshopRoot(resolveWorkshopContextCwd());
1559
1586
  if (!wsRoot) {
1560
1587
  console.error(chalk.red('❌ Not inside a workshop directory'));
1561
1588
  process.exit(1);
@@ -4,7 +4,7 @@ import '@epic-web/workshop-utils/init-env';
4
4
  * looking for a package.json with an epicshop field.
5
5
  * Returns the workshop root path if found, null otherwise.
6
6
  */
7
- export declare function findWorkshopRoot(): Promise<string | null>;
7
+ export declare function findWorkshopRoot(startDir?: string): Promise<string | null>;
8
8
  /**
9
9
  * Check if the current working directory is inside a workshop
10
10
  * (has epicshop config in package.json in current dir or any parent)
@@ -38,8 +38,21 @@ const EPIC_SITES = [
38
38
  * looking for a package.json with an epicshop field.
39
39
  * Returns the workshop root path if found, null otherwise.
40
40
  */
41
- export async function findWorkshopRoot() {
42
- let currentDir = process.cwd();
41
+ export async function findWorkshopRoot(startDir) {
42
+ let currentDir = startDir
43
+ ? path.resolve(resolvePathWithTilde(startDir))
44
+ : process.cwd();
45
+ // If the user gave us a file path (or something that isn't a directory),
46
+ // treat the containing folder as the start point.
47
+ try {
48
+ const stat = await fs.promises.stat(currentDir);
49
+ if (!stat.isDirectory()) {
50
+ currentDir = path.dirname(currentDir);
51
+ }
52
+ }
53
+ catch {
54
+ // If the path doesn't exist, we still attempt to walk upward from it.
55
+ }
43
56
  const root = path.parse(currentDir).root;
44
57
  while (currentDir !== root) {
45
58
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epicshop",
3
- "version": "6.80.2",
3
+ "version": "6.82.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.80.2",
102
+ "@epic-web/workshop-utils": "6.82.0",
103
103
  "@inquirer/prompts": "^8.2.0",
104
104
  "@sentry/node": "^10.38.0",
105
105
  "chalk": "^5.6.2",
@@ -108,13 +108,13 @@
108
108
  "get-port": "^7.1.0",
109
109
  "match-sorter": "^8.2.0",
110
110
  "open": "^11.0.0",
111
- "openid-client": "^6.8.1",
112
- "ora": "^9.1.0",
111
+ "openid-client": "^6.8.2",
112
+ "ora": "^9.3.0",
113
113
  "yargs": "^18.0.0"
114
114
  },
115
115
  "devDependencies": {
116
- "@epic-web/config": "^1.21.3",
117
- "@types/node": "^25.1.0",
116
+ "@epic-web/config": "^1.22.0",
117
+ "@types/node": "^25.2.3",
118
118
  "@types/yargs": "^17.0.35",
119
119
  "vitest": "^4.0.18",
120
120
  "zshy": "^0.7.0"