epicshop 6.50.1 → 6.50.3
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 +12 -0
- package/dist/cli.js +463 -67
- package/dist/commands/diff.d.ts +21 -0
- package/dist/commands/diff.js +139 -0
- package/dist/commands/exercises.d.ts +23 -0
- package/dist/commands/exercises.js +281 -0
- package/dist/commands/playground.d.ts +36 -0
- package/dist/commands/playground.js +268 -0
- package/dist/commands/progress.d.ts +22 -0
- package/dist/commands/progress.js +221 -0
- package/dist/commands/workshops.js +32 -10
- package/package.json +28 -3
package/README.md
CHANGED
|
@@ -47,6 +47,10 @@ epicshop start <workshop>
|
|
|
47
47
|
- `epicshop open`: open a workshop in your editor
|
|
48
48
|
- `epicshop update`: pull the latest workshop changes
|
|
49
49
|
- `epicshop warm`: warm caches for faster workshop startup
|
|
50
|
+
- `epicshop exercises`: list exercises with progress (context-aware)
|
|
51
|
+
- `epicshop playground`: view or set the current playground (context-aware)
|
|
52
|
+
- `epicshop progress`: view or update your progress (context-aware)
|
|
53
|
+
- `epicshop diff`: show diff between playground and solution (context-aware)
|
|
50
54
|
|
|
51
55
|
## Environment variables
|
|
52
56
|
|
|
@@ -62,6 +66,14 @@ This package also exports ESM entrypoints:
|
|
|
62
66
|
import { start } from 'epicshop/start'
|
|
63
67
|
import { update } from 'epicshop/update'
|
|
64
68
|
import { warm } from 'epicshop/warm'
|
|
69
|
+
import { show, set } from 'epicshop/playground'
|
|
70
|
+
import {
|
|
71
|
+
show as showProgress,
|
|
72
|
+
update as updateProgress,
|
|
73
|
+
} from 'epicshop/progress'
|
|
74
|
+
import { showProgressDiff, showDiffBetweenApps } from 'epicshop/diff'
|
|
75
|
+
import { list, showExercise } from 'epicshop/exercises'
|
|
76
|
+
import { status, login, logout } from 'epicshop/auth'
|
|
65
77
|
```
|
|
66
78
|
|
|
67
79
|
## Documentation
|
package/dist/cli.js
CHANGED
|
@@ -636,6 +636,309 @@ const cli = yargs(args)
|
|
|
636
636
|
if (!result.success) {
|
|
637
637
|
process.exit(1);
|
|
638
638
|
}
|
|
639
|
+
})
|
|
640
|
+
.command('playground [subcommand] [target]', 'Manage the playground environment (context-aware)', (yargs) => {
|
|
641
|
+
return yargs
|
|
642
|
+
.positional('subcommand', {
|
|
643
|
+
describe: 'Playground subcommand (show, set)',
|
|
644
|
+
type: 'string',
|
|
645
|
+
choices: ['show', 'set'],
|
|
646
|
+
})
|
|
647
|
+
.positional('target', {
|
|
648
|
+
describe: 'Target exercise step (e.g., 1.2.problem, 2.3.solution)',
|
|
649
|
+
type: 'string',
|
|
650
|
+
})
|
|
651
|
+
.option('exercise', {
|
|
652
|
+
alias: 'e',
|
|
653
|
+
type: 'number',
|
|
654
|
+
description: 'Exercise number',
|
|
655
|
+
})
|
|
656
|
+
.option('step', {
|
|
657
|
+
type: 'number',
|
|
658
|
+
description: 'Step number',
|
|
659
|
+
})
|
|
660
|
+
.option('type', {
|
|
661
|
+
alias: 't',
|
|
662
|
+
type: 'string',
|
|
663
|
+
choices: ['problem', 'solution'],
|
|
664
|
+
description: 'App type (problem or solution)',
|
|
665
|
+
})
|
|
666
|
+
.option('silent', {
|
|
667
|
+
alias: 's',
|
|
668
|
+
type: 'boolean',
|
|
669
|
+
description: 'Run without output logs',
|
|
670
|
+
default: false,
|
|
671
|
+
})
|
|
672
|
+
.example('$0 playground', 'Show current playground status')
|
|
673
|
+
.example('$0 playground show', 'Show current playground status')
|
|
674
|
+
.example('$0 playground set', 'Set playground (auto-detect next)')
|
|
675
|
+
.example('$0 playground set 1.2.problem', 'Set to specific step')
|
|
676
|
+
.example('$0 playground set --exercise 1 --step 2', 'Set with options');
|
|
677
|
+
}, async (argv) => {
|
|
678
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
679
|
+
const workshopRoot = await findWorkshopRoot();
|
|
680
|
+
if (!workshopRoot) {
|
|
681
|
+
console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
|
|
682
|
+
process.exit(1);
|
|
683
|
+
}
|
|
684
|
+
const originalCwd = process.cwd();
|
|
685
|
+
process.chdir(workshopRoot);
|
|
686
|
+
try {
|
|
687
|
+
const { show, set, selectAndSet, parseAppIdentifier } = await import("./commands/playground.js");
|
|
688
|
+
const subcommand = argv.subcommand || 'show';
|
|
689
|
+
if (subcommand === 'show') {
|
|
690
|
+
const result = await show({ silent: argv.silent });
|
|
691
|
+
if (!result.success)
|
|
692
|
+
process.exit(1);
|
|
693
|
+
}
|
|
694
|
+
else if (subcommand === 'set') {
|
|
695
|
+
// Parse target if provided (e.g., "1.2.problem")
|
|
696
|
+
let exerciseNumber = argv.exercise;
|
|
697
|
+
let stepNumber = argv.step;
|
|
698
|
+
let type = argv.type;
|
|
699
|
+
if (argv.target) {
|
|
700
|
+
const parsed = parseAppIdentifier(argv.target);
|
|
701
|
+
// Validate that the target was parseable - at least exercise number should be found
|
|
702
|
+
if (parsed.exerciseNumber === undefined) {
|
|
703
|
+
console.error(chalk.red(`❌ Invalid target format: "${argv.target}". Expected format like "1.2.problem" or "01.02.solution"`));
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
exerciseNumber = parsed.exerciseNumber ?? exerciseNumber;
|
|
707
|
+
stepNumber = parsed.stepNumber ?? stepNumber;
|
|
708
|
+
type = parsed.type ?? type;
|
|
709
|
+
}
|
|
710
|
+
// If no specific target, check if we should show interactive or auto
|
|
711
|
+
if (!exerciseNumber && !stepNumber && !type) {
|
|
712
|
+
// Auto-detect next step or show interactive
|
|
713
|
+
const result = await set({ silent: argv.silent });
|
|
714
|
+
if (!result.success) {
|
|
715
|
+
// If auto-detect fails, try interactive
|
|
716
|
+
const interactiveResult = await selectAndSet({
|
|
717
|
+
silent: argv.silent,
|
|
718
|
+
});
|
|
719
|
+
if (!interactiveResult.success)
|
|
720
|
+
process.exit(1);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
const result = await set({
|
|
725
|
+
exerciseNumber,
|
|
726
|
+
stepNumber,
|
|
727
|
+
type,
|
|
728
|
+
silent: argv.silent,
|
|
729
|
+
});
|
|
730
|
+
if (!result.success)
|
|
731
|
+
process.exit(1);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
console.error(chalk.red(`❌ Unknown subcommand: ${subcommand}`));
|
|
736
|
+
process.exit(1);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
finally {
|
|
740
|
+
process.chdir(originalCwd);
|
|
741
|
+
}
|
|
742
|
+
})
|
|
743
|
+
.command('progress [subcommand] [lesson-slug]', 'View and manage your progress (context-aware)', (yargs) => {
|
|
744
|
+
return yargs
|
|
745
|
+
.positional('subcommand', {
|
|
746
|
+
describe: 'Progress subcommand (show, update)',
|
|
747
|
+
type: 'string',
|
|
748
|
+
choices: ['show', 'update'],
|
|
749
|
+
})
|
|
750
|
+
.positional('lesson-slug', {
|
|
751
|
+
describe: 'Lesson slug to update (for update subcommand)',
|
|
752
|
+
type: 'string',
|
|
753
|
+
})
|
|
754
|
+
.option('complete', {
|
|
755
|
+
alias: 'c',
|
|
756
|
+
type: 'boolean',
|
|
757
|
+
description: 'Mark as complete (default: true)',
|
|
758
|
+
default: true,
|
|
759
|
+
})
|
|
760
|
+
.option('incomplete', {
|
|
761
|
+
alias: 'i',
|
|
762
|
+
type: 'boolean',
|
|
763
|
+
description: 'Mark as incomplete',
|
|
764
|
+
default: false,
|
|
765
|
+
})
|
|
766
|
+
.option('json', {
|
|
767
|
+
type: 'boolean',
|
|
768
|
+
description: 'Output as JSON',
|
|
769
|
+
default: false,
|
|
770
|
+
})
|
|
771
|
+
.option('silent', {
|
|
772
|
+
alias: 's',
|
|
773
|
+
type: 'boolean',
|
|
774
|
+
description: 'Run without output logs',
|
|
775
|
+
default: false,
|
|
776
|
+
})
|
|
777
|
+
.example('$0 progress', 'Show progress for current workshop')
|
|
778
|
+
.example('$0 progress show', 'Show progress for current workshop')
|
|
779
|
+
.example('$0 progress show --json', 'Output progress as JSON')
|
|
780
|
+
.example('$0 progress update 01-01-problem', 'Mark lesson as complete')
|
|
781
|
+
.example('$0 progress update 01-01-problem --incomplete', 'Mark lesson as incomplete');
|
|
782
|
+
}, async (argv) => {
|
|
783
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
784
|
+
const workshopRoot = await findWorkshopRoot();
|
|
785
|
+
if (!workshopRoot) {
|
|
786
|
+
console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
|
|
787
|
+
process.exit(1);
|
|
788
|
+
}
|
|
789
|
+
const originalCwd = process.cwd();
|
|
790
|
+
process.chdir(workshopRoot);
|
|
791
|
+
try {
|
|
792
|
+
const { show, update } = await import("./commands/progress.js");
|
|
793
|
+
const subcommand = argv.subcommand || 'show';
|
|
794
|
+
if (subcommand === 'show') {
|
|
795
|
+
const result = await show({
|
|
796
|
+
silent: argv.silent,
|
|
797
|
+
json: argv.json,
|
|
798
|
+
});
|
|
799
|
+
if (!result.success)
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
else if (subcommand === 'update') {
|
|
803
|
+
// --incomplete takes precedence, otherwise use --complete value
|
|
804
|
+
const complete = argv.incomplete ? false : argv.complete;
|
|
805
|
+
const result = await update({
|
|
806
|
+
lessonSlug: argv.lessonSlug,
|
|
807
|
+
complete,
|
|
808
|
+
silent: argv.silent,
|
|
809
|
+
});
|
|
810
|
+
if (!result.success)
|
|
811
|
+
process.exit(1);
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
console.error(chalk.red(`❌ Unknown subcommand: ${subcommand}`));
|
|
815
|
+
process.exit(1);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
finally {
|
|
819
|
+
process.chdir(originalCwd);
|
|
820
|
+
}
|
|
821
|
+
})
|
|
822
|
+
.command('diff [app1] [app2]', 'Show differences between apps or playground vs solution (context-aware)', (yargs) => {
|
|
823
|
+
return yargs
|
|
824
|
+
.positional('app1', {
|
|
825
|
+
describe: 'First app identifier (e.g., 01.02.problem). If omitted, shows playground vs solution.',
|
|
826
|
+
type: 'string',
|
|
827
|
+
})
|
|
828
|
+
.positional('app2', {
|
|
829
|
+
describe: 'Second app identifier (e.g., 01.02.solution)',
|
|
830
|
+
type: 'string',
|
|
831
|
+
})
|
|
832
|
+
.option('silent', {
|
|
833
|
+
alias: 's',
|
|
834
|
+
type: 'boolean',
|
|
835
|
+
description: 'Run without output logs',
|
|
836
|
+
default: false,
|
|
837
|
+
})
|
|
838
|
+
.example('$0 diff', 'Show diff between playground and solution')
|
|
839
|
+
.example('$0 diff 01.02.problem 01.02.solution', 'Show diff between two apps');
|
|
840
|
+
}, async (argv) => {
|
|
841
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
842
|
+
const workshopRoot = await findWorkshopRoot();
|
|
843
|
+
if (!workshopRoot) {
|
|
844
|
+
console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
|
|
845
|
+
process.exit(1);
|
|
846
|
+
}
|
|
847
|
+
const originalCwd = process.cwd();
|
|
848
|
+
process.chdir(workshopRoot);
|
|
849
|
+
try {
|
|
850
|
+
const { showProgressDiff, showDiffBetweenApps } = await import("./commands/diff.js");
|
|
851
|
+
if (argv.app1 && argv.app2) {
|
|
852
|
+
const result = await showDiffBetweenApps({
|
|
853
|
+
app1: argv.app1,
|
|
854
|
+
app2: argv.app2,
|
|
855
|
+
silent: argv.silent,
|
|
856
|
+
});
|
|
857
|
+
if (!result.success)
|
|
858
|
+
process.exit(1);
|
|
859
|
+
}
|
|
860
|
+
else if (argv.app1 && !argv.app2) {
|
|
861
|
+
console.error(chalk.red('❌ When providing app1, app2 is also required'));
|
|
862
|
+
process.exit(1);
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
const result = await showProgressDiff({ silent: argv.silent });
|
|
866
|
+
if (!result.success)
|
|
867
|
+
process.exit(1);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
finally {
|
|
871
|
+
process.chdir(originalCwd);
|
|
872
|
+
}
|
|
873
|
+
})
|
|
874
|
+
.command('exercises [exercise] [step]', 'List exercises or show exercise details (context-aware)', (yargs) => {
|
|
875
|
+
return yargs
|
|
876
|
+
.positional('exercise', {
|
|
877
|
+
describe: 'Exercise number to show details for (e.g., 1 or 01)',
|
|
878
|
+
type: 'string',
|
|
879
|
+
})
|
|
880
|
+
.positional('step', {
|
|
881
|
+
describe: 'Step number to show details for (e.g., 2 or 02)',
|
|
882
|
+
type: 'string',
|
|
883
|
+
})
|
|
884
|
+
.option('json', {
|
|
885
|
+
type: 'boolean',
|
|
886
|
+
description: 'Output as JSON',
|
|
887
|
+
default: false,
|
|
888
|
+
})
|
|
889
|
+
.option('silent', {
|
|
890
|
+
alias: 's',
|
|
891
|
+
type: 'boolean',
|
|
892
|
+
description: 'Run without output logs',
|
|
893
|
+
default: false,
|
|
894
|
+
})
|
|
895
|
+
.example('$0 exercises', 'List all exercises with progress')
|
|
896
|
+
.example('$0 exercises 1', 'Show details for exercise 1')
|
|
897
|
+
.example('$0 exercises 1 2', 'Show details for exercise 1 step 2')
|
|
898
|
+
.example('$0 exercises --json', 'Output exercises as JSON');
|
|
899
|
+
}, async (argv) => {
|
|
900
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
901
|
+
const workshopRoot = await findWorkshopRoot();
|
|
902
|
+
if (!workshopRoot) {
|
|
903
|
+
console.error(chalk.red('❌ Not inside a workshop directory. Please cd into a workshop first.'));
|
|
904
|
+
process.exit(1);
|
|
905
|
+
}
|
|
906
|
+
const originalCwd = process.cwd();
|
|
907
|
+
process.chdir(workshopRoot);
|
|
908
|
+
try {
|
|
909
|
+
const { list, showExercise } = await import("./commands/exercises.js");
|
|
910
|
+
if (argv.exercise) {
|
|
911
|
+
const exerciseNumber = parseInt(argv.exercise, 10);
|
|
912
|
+
if (isNaN(exerciseNumber)) {
|
|
913
|
+
console.error(chalk.red(`❌ Invalid exercise number: "${argv.exercise}". Expected a number.`));
|
|
914
|
+
process.exit(1);
|
|
915
|
+
}
|
|
916
|
+
const stepNumber = argv.step ? parseInt(argv.step, 10) : undefined;
|
|
917
|
+
if (stepNumber !== undefined && isNaN(stepNumber)) {
|
|
918
|
+
console.error(chalk.red(`❌ Invalid step number: "${argv.step}". Expected a number.`));
|
|
919
|
+
process.exit(1);
|
|
920
|
+
}
|
|
921
|
+
const result = await showExercise({
|
|
922
|
+
exerciseNumber,
|
|
923
|
+
stepNumber,
|
|
924
|
+
json: argv.json,
|
|
925
|
+
silent: argv.silent,
|
|
926
|
+
});
|
|
927
|
+
if (!result.success)
|
|
928
|
+
process.exit(1);
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
const result = await list({
|
|
932
|
+
json: argv.json,
|
|
933
|
+
silent: argv.silent,
|
|
934
|
+
});
|
|
935
|
+
if (!result.success)
|
|
936
|
+
process.exit(1);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
finally {
|
|
940
|
+
process.chdir(originalCwd);
|
|
941
|
+
}
|
|
639
942
|
})
|
|
640
943
|
.epilogue(`For more information, visit: ${chalk.cyan('https://github.com/epicweb-dev/epicshop')}`)
|
|
641
944
|
.strict()
|
|
@@ -674,73 +977,86 @@ try {
|
|
|
674
977
|
],
|
|
675
978
|
});
|
|
676
979
|
const { search } = await import('@inquirer/prompts');
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
{
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
980
|
+
// Build choices - workshop-specific commands only show when inside a workshop
|
|
981
|
+
const baseChoices = [];
|
|
982
|
+
// Always-available commands
|
|
983
|
+
baseChoices.push({
|
|
984
|
+
name: `${chalk.green('start')} - Start a workshop`,
|
|
985
|
+
value: 'start',
|
|
986
|
+
description: workshopTitle
|
|
987
|
+
? `Start ${workshopTitle}`
|
|
988
|
+
: 'Select a workshop to start',
|
|
989
|
+
}, {
|
|
990
|
+
name: `${chalk.green('open')} - Open a workshop in editor`,
|
|
991
|
+
value: 'open',
|
|
992
|
+
description: workshopTitle
|
|
993
|
+
? `Open ${workshopTitle}`
|
|
994
|
+
: 'Select a workshop to open',
|
|
995
|
+
});
|
|
996
|
+
// Workshop-specific commands (only when inside a workshop)
|
|
997
|
+
if (workshopTitle) {
|
|
998
|
+
baseChoices.push({
|
|
999
|
+
name: `${chalk.green('exercises')} - List exercises`,
|
|
1000
|
+
value: 'exercises',
|
|
1001
|
+
description: `View exercises and progress in ${workshopTitle}`,
|
|
1002
|
+
}, {
|
|
1003
|
+
name: `${chalk.green('playground')} - Manage playground`,
|
|
1004
|
+
value: 'playground',
|
|
1005
|
+
description: 'View or set the current playground',
|
|
1006
|
+
}, {
|
|
1007
|
+
name: `${chalk.green('progress')} - View/update progress`,
|
|
1008
|
+
value: 'progress',
|
|
1009
|
+
description: 'View or update your learning progress',
|
|
1010
|
+
}, {
|
|
1011
|
+
name: `${chalk.green('diff')} - Show differences`,
|
|
1012
|
+
value: 'diff',
|
|
1013
|
+
description: 'Show diff between playground and solution',
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
// More always-available commands
|
|
1017
|
+
baseChoices.push({
|
|
1018
|
+
name: `${chalk.green('list')} - List all workshops`,
|
|
1019
|
+
value: 'list',
|
|
1020
|
+
description: 'List all added workshops',
|
|
1021
|
+
}, {
|
|
1022
|
+
name: `${chalk.green('add')} - Add a workshop`,
|
|
1023
|
+
value: 'add',
|
|
1024
|
+
description: 'Clone a workshop from epicweb-dev GitHub org',
|
|
1025
|
+
}, {
|
|
1026
|
+
name: `${chalk.green('remove')} - Remove a workshop`,
|
|
1027
|
+
value: 'remove',
|
|
1028
|
+
description: workshopTitle
|
|
1029
|
+
? `Remove ${workshopTitle}`
|
|
1030
|
+
: 'Select a workshop to remove',
|
|
1031
|
+
}, {
|
|
1032
|
+
name: `${chalk.green('update')} - Update workshop`,
|
|
1033
|
+
value: 'update',
|
|
1034
|
+
description: workshopTitle
|
|
1035
|
+
? `Update ${workshopTitle}`
|
|
1036
|
+
: 'Select a workshop to update',
|
|
1037
|
+
}, {
|
|
1038
|
+
name: `${chalk.green('warm')} - Warm caches`,
|
|
1039
|
+
value: 'warm',
|
|
1040
|
+
description: workshopTitle
|
|
1041
|
+
? `Warm the cache for ${workshopTitle}`
|
|
1042
|
+
: 'Select a workshop to warm the cache for',
|
|
1043
|
+
}, {
|
|
1044
|
+
name: `${chalk.green('config')} - View/update configuration`,
|
|
1045
|
+
value: 'config',
|
|
1046
|
+
description: 'View or update workshop configuration',
|
|
1047
|
+
}, {
|
|
1048
|
+
name: `${chalk.green('init')} - First-time setup`,
|
|
1049
|
+
value: 'init',
|
|
1050
|
+
description: 'Initialize epicshop and start the tutorial',
|
|
1051
|
+
}, {
|
|
1052
|
+
name: `${chalk.green('auth')} - Manage authentication`,
|
|
1053
|
+
value: 'auth',
|
|
1054
|
+
description: 'Login/logout from EpicWeb.dev, EpicReact.dev, EpicAI.pro',
|
|
1055
|
+
}, {
|
|
1056
|
+
name: `${chalk.green('help')} - Show help`,
|
|
1057
|
+
value: 'help',
|
|
1058
|
+
description: 'Display CLI help information',
|
|
1059
|
+
});
|
|
744
1060
|
const subcommand = await search({
|
|
745
1061
|
message: workshopTitle
|
|
746
1062
|
? `What would you like to do? ${chalk.gray(`(in ${workshopTitle})`)}`
|
|
@@ -1006,6 +1322,86 @@ try {
|
|
|
1006
1322
|
process.exit(1);
|
|
1007
1323
|
break;
|
|
1008
1324
|
}
|
|
1325
|
+
case 'exercises': {
|
|
1326
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
1327
|
+
const wsRoot = await findWorkshopRoot();
|
|
1328
|
+
if (!wsRoot) {
|
|
1329
|
+
console.error(chalk.red('❌ Not inside a workshop directory'));
|
|
1330
|
+
process.exit(1);
|
|
1331
|
+
}
|
|
1332
|
+
const originalCwd = process.cwd();
|
|
1333
|
+
process.chdir(wsRoot);
|
|
1334
|
+
try {
|
|
1335
|
+
const { list: listExercises } = await import("./commands/exercises.js");
|
|
1336
|
+
const result = await listExercises({});
|
|
1337
|
+
if (!result.success)
|
|
1338
|
+
process.exit(1);
|
|
1339
|
+
}
|
|
1340
|
+
finally {
|
|
1341
|
+
process.chdir(originalCwd);
|
|
1342
|
+
}
|
|
1343
|
+
break;
|
|
1344
|
+
}
|
|
1345
|
+
case 'playground': {
|
|
1346
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
1347
|
+
const wsRoot = await findWorkshopRoot();
|
|
1348
|
+
if (!wsRoot) {
|
|
1349
|
+
console.error(chalk.red('❌ Not inside a workshop directory'));
|
|
1350
|
+
process.exit(1);
|
|
1351
|
+
}
|
|
1352
|
+
const originalCwd = process.cwd();
|
|
1353
|
+
process.chdir(wsRoot);
|
|
1354
|
+
try {
|
|
1355
|
+
const { show: showPlayground } = await import("./commands/playground.js");
|
|
1356
|
+
const result = await showPlayground({});
|
|
1357
|
+
if (!result.success)
|
|
1358
|
+
process.exit(1);
|
|
1359
|
+
}
|
|
1360
|
+
finally {
|
|
1361
|
+
process.chdir(originalCwd);
|
|
1362
|
+
}
|
|
1363
|
+
break;
|
|
1364
|
+
}
|
|
1365
|
+
case 'progress': {
|
|
1366
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
1367
|
+
const wsRoot = await findWorkshopRoot();
|
|
1368
|
+
if (!wsRoot) {
|
|
1369
|
+
console.error(chalk.red('❌ Not inside a workshop directory'));
|
|
1370
|
+
process.exit(1);
|
|
1371
|
+
}
|
|
1372
|
+
const originalCwd = process.cwd();
|
|
1373
|
+
process.chdir(wsRoot);
|
|
1374
|
+
try {
|
|
1375
|
+
const { show: showProgress } = await import("./commands/progress.js");
|
|
1376
|
+
const result = await showProgress({});
|
|
1377
|
+
if (!result.success)
|
|
1378
|
+
process.exit(1);
|
|
1379
|
+
}
|
|
1380
|
+
finally {
|
|
1381
|
+
process.chdir(originalCwd);
|
|
1382
|
+
}
|
|
1383
|
+
break;
|
|
1384
|
+
}
|
|
1385
|
+
case 'diff': {
|
|
1386
|
+
const { findWorkshopRoot } = await import("./commands/workshops.js");
|
|
1387
|
+
const wsRoot = await findWorkshopRoot();
|
|
1388
|
+
if (!wsRoot) {
|
|
1389
|
+
console.error(chalk.red('❌ Not inside a workshop directory'));
|
|
1390
|
+
process.exit(1);
|
|
1391
|
+
}
|
|
1392
|
+
const originalCwd = process.cwd();
|
|
1393
|
+
process.chdir(wsRoot);
|
|
1394
|
+
try {
|
|
1395
|
+
const { showProgressDiff } = await import("./commands/diff.js");
|
|
1396
|
+
const result = await showProgressDiff({});
|
|
1397
|
+
if (!result.success)
|
|
1398
|
+
process.exit(1);
|
|
1399
|
+
}
|
|
1400
|
+
finally {
|
|
1401
|
+
process.chdir(originalCwd);
|
|
1402
|
+
}
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1009
1405
|
case 'help': {
|
|
1010
1406
|
cli.showHelp((helpText) => {
|
|
1011
1407
|
console.log(formatHelp(helpText));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type DiffResult = {
|
|
2
|
+
success: boolean;
|
|
3
|
+
message?: string;
|
|
4
|
+
diff?: string;
|
|
5
|
+
error?: Error;
|
|
6
|
+
};
|
|
7
|
+
export type DiffOptions = {
|
|
8
|
+
app1?: string;
|
|
9
|
+
app2?: string;
|
|
10
|
+
silent?: boolean;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Show diff between the current playground and its solution
|
|
14
|
+
*/
|
|
15
|
+
export declare function showProgressDiff(options?: {
|
|
16
|
+
silent?: boolean;
|
|
17
|
+
}): Promise<DiffResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Show diff between two specific apps
|
|
20
|
+
*/
|
|
21
|
+
export declare function showDiffBetweenApps(options?: DiffOptions): Promise<DiffResult>;
|