ai-hero-cli 0.0.6 → 0.0.8

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 ADDED
@@ -0,0 +1,134 @@
1
+ # AI Hero CLI
2
+
3
+ A command-line interface tool designed to help students navigate and run AI Hero exercises efficiently.
4
+
5
+ ## Overview
6
+
7
+ The AI Hero CLI is a specialized tool that makes it easy to:
8
+
9
+ - Browse and select exercises from the AI Hero course
10
+ - Run exercises with proper environment setup
11
+ - Navigate between exercises seamlessly
12
+ - Get exercise instructions and context
13
+
14
+ ## Installation
15
+
16
+ This CLI is typically pre-installed in AI Hero exercise repositories. If you need to install it manually:
17
+
18
+ ```bash
19
+ pnpm add -D ai-hero-cli
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Basic Commands
25
+
26
+ #### Run an Exercise
27
+
28
+ ```bash
29
+ # Run a specific exercise by lesson number
30
+ ai-hero exercise 1
31
+
32
+ # Run a specific exercise with subfolder
33
+ ai-hero exercise 1 --subfolder 2
34
+
35
+ # Browse and select an exercise interactively
36
+ ai-hero exercise
37
+ ```
38
+
39
+ #### Command Options
40
+
41
+ - `--root`: Directory to look for lessons (default: current directory)
42
+ - `--env-file`: Path to environment file (default: `.env` in current directory)
43
+ - `--cwd`: Working directory to run the command in (default: current directory)
44
+
45
+ ### Interactive Features
46
+
47
+ When running an exercise, the CLI provides an interactive interface with several shortcuts:
48
+
49
+ - **Enter**: Choose a new exercise to run
50
+ - **n**: Go to the next exercise
51
+ - **p**: Go to the previous exercise
52
+ - **q**: Quit the current exercise
53
+ - **h**: Show all available shortcuts
54
+
55
+ ### Exercise Navigation
56
+
57
+ The CLI automatically detects the structure of your AI Hero exercises and provides seamless navigation:
58
+
59
+ 1. **Exercise Selection**: Use the interactive menu to browse and search through available exercises
60
+ 2. **Subfolder Support**: If an exercise has multiple subfolders, you'll be prompted to select one
61
+ 3. **Progressive Navigation**: Easily move to the next or previous exercise in the course
62
+ 4. **Context Preservation**: The CLI remembers your position and provides relevant navigation options
63
+
64
+ ### Exercise Execution
65
+
66
+ When you run an exercise:
67
+
68
+ 1. The CLI clears the terminal and displays the exercise information
69
+ 2. Shows the exercise instructions (if available in `readme.md`)
70
+ 3. Runs the exercise using `pnpm tsx` with your environment variables
71
+ 4. Provides interactive controls while the exercise is running
72
+ 5. Offers options when the exercise completes or encounters an error
73
+
74
+ ### Post-Exercise Options
75
+
76
+ After an exercise completes, you can:
77
+
78
+ - **Run Again**: Retry the current exercise
79
+ - **Next Exercise**: Automatically move to the next exercise in the sequence
80
+ - **Previous Exercise**: Go back to the previous exercise
81
+ - **Choose Exercise**: Browse and select a different exercise
82
+ - **Finish**: Exit the CLI
83
+
84
+ ## Internal Commands
85
+
86
+ The CLI also includes internal commands for maintenance:
87
+
88
+ ```bash
89
+ # Upgrade AI SDK packages
90
+ ai-hero internal upgrade
91
+
92
+ # Upgrade with verbose output
93
+ ai-hero internal upgrade --verbose
94
+ ```
95
+
96
+ ## File Structure Expectations
97
+
98
+ The CLI expects your AI Hero exercises to follow this structure:
99
+
100
+ ```
101
+ exercises/
102
+ ├── 1-section-name/
103
+ │ ├── 1-exercise-name/
104
+ │ │ ├── main.ts
105
+ │ │ └── readme.md
106
+ │ └── 2-another-exercise/
107
+ │ ├── main.ts
108
+ │ └── readme.md
109
+ ```
110
+
111
+ - Each exercise should have a `main.ts` file as the entry point
112
+ - Optional `readme.md` files provide exercise instructions
113
+ - Exercise and section names should start with a number followed by a hyphen
114
+
115
+ ## Environment Setup
116
+
117
+ The CLI automatically loads environment variables from:
118
+
119
+ - `.env` file in the current directory (default)
120
+ - Custom env file specified with `--env-file` option
121
+
122
+ Make sure your `.env` file contains any necessary API keys or configuration for the exercises.
123
+
124
+ ## Troubleshooting
125
+
126
+ ### Getting Help
127
+
128
+ - Use `h` during exercise execution to see available shortcuts
129
+ - Check the exercise's `readme.md` file for specific instructions
130
+ - Ensure all dependencies are installed with `pnpm install`
131
+
132
+ ---
133
+
134
+ **Note**: This CLI is specifically designed for AI Hero exercises and is not intended for general use outside of the AI Hero course context.
@@ -1,13 +1,42 @@
1
1
  #!/usr/bin/env node
2
- import * as ChildProcess from 'child_process';
3
- import * as Crypto from 'crypto';
4
- import * as NFS from 'fs';
5
- import * as OS from 'os';
6
- import * as path4 from 'path';
7
- import * as NodeUrl from 'url';
8
- import * as readline from 'readline';
9
- import * as readline2 from 'readline/promises';
10
- import { styleText } from 'util';
2
+ 'use strict';
3
+
4
+ var ChildProcess = require('child_process');
5
+ var Crypto = require('crypto');
6
+ var NFS = require('fs');
7
+ var OS = require('os');
8
+ var path4 = require('path');
9
+ var NodeUrl = require('url');
10
+ var readline = require('readline');
11
+ var readline2 = require('readline/promises');
12
+ var util = require('util');
13
+
14
+ function _interopNamespace(e) {
15
+ if (e && e.__esModule) return e;
16
+ var n = Object.create(null);
17
+ if (e) {
18
+ Object.keys(e).forEach(function (k) {
19
+ if (k !== 'default') {
20
+ var d = Object.getOwnPropertyDescriptor(e, k);
21
+ Object.defineProperty(n, k, d.get ? d : {
22
+ enumerable: true,
23
+ get: function () { return e[k]; }
24
+ });
25
+ }
26
+ });
27
+ }
28
+ n.default = e;
29
+ return Object.freeze(n);
30
+ }
31
+
32
+ var ChildProcess__namespace = /*#__PURE__*/_interopNamespace(ChildProcess);
33
+ var Crypto__namespace = /*#__PURE__*/_interopNamespace(Crypto);
34
+ var NFS__namespace = /*#__PURE__*/_interopNamespace(NFS);
35
+ var OS__namespace = /*#__PURE__*/_interopNamespace(OS);
36
+ var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
37
+ var NodeUrl__namespace = /*#__PURE__*/_interopNamespace(NodeUrl);
38
+ var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
39
+ var readline2__namespace = /*#__PURE__*/_interopNamespace(readline2);
11
40
 
12
41
  var __create = Object.create;
13
42
  var __defProp = Object.defineProperty;
@@ -58561,7 +58590,7 @@ var runCommand = (fileSystem) => (command2) => {
58561
58590
  switch (command2._tag) {
58562
58591
  case "StandardCommand": {
58563
58592
  const spawn2 = flatMap9(make24(), (exitCode3) => async2((resume2) => {
58564
- const handle = ChildProcess.spawn(command2.command, command2.args, {
58593
+ const handle = ChildProcess__namespace.spawn(command2.command, command2.args, {
58565
58594
  stdio: [inputToStdioOption(command2.stdin), outputToStdioOption(command2.stdout), outputToStdioOption(command2.stderr)],
58566
58595
  cwd: getOrElse(command2.cwd, constUndefined),
58567
58596
  shell: command2.shell,
@@ -58585,7 +58614,7 @@ var runCommand = (fileSystem) => (command2) => {
58585
58614
  });
58586
58615
  }));
58587
58616
  const killProcessGroup = process.platform === "win32" ? (handle, _) => async2((resume2) => {
58588
- ChildProcess.exec(`taskkill /pid ${handle.pid} /T /F`, (error4) => {
58617
+ ChildProcess__namespace.exec(`taskkill /pid ${handle.pid} /T /F`, (error4) => {
58589
58618
  if (error4) {
58590
58619
  resume2(fail8(toPlatformError("kill", toError(error4), command2)));
58591
58620
  } else {
@@ -58688,20 +58717,20 @@ var handleBadArgument = (method) => (cause3) => new BadArgument({
58688
58717
  cause: cause3
58689
58718
  });
58690
58719
  var access2 = /* @__PURE__ */ (() => {
58691
- const nodeAccess = /* @__PURE__ */ effectify2(NFS.access, /* @__PURE__ */ handleErrnoException("FileSystem", "access"), /* @__PURE__ */ handleBadArgument("access"));
58720
+ const nodeAccess = /* @__PURE__ */ effectify2(NFS__namespace.access, /* @__PURE__ */ handleErrnoException("FileSystem", "access"), /* @__PURE__ */ handleBadArgument("access"));
58692
58721
  return (path6, options3) => {
58693
- let mode = NFS.constants.F_OK;
58722
+ let mode = NFS__namespace.constants.F_OK;
58694
58723
  if (options3?.readable) {
58695
- mode |= NFS.constants.R_OK;
58724
+ mode |= NFS__namespace.constants.R_OK;
58696
58725
  }
58697
58726
  if (options3?.writable) {
58698
- mode |= NFS.constants.W_OK;
58727
+ mode |= NFS__namespace.constants.W_OK;
58699
58728
  }
58700
58729
  return nodeAccess(path6, mode);
58701
58730
  };
58702
58731
  })();
58703
58732
  var copy3 = /* @__PURE__ */ (() => {
58704
- const nodeCp = /* @__PURE__ */ effectify2(NFS.cp, /* @__PURE__ */ handleErrnoException("FileSystem", "copy"), /* @__PURE__ */ handleBadArgument("copy"));
58733
+ const nodeCp = /* @__PURE__ */ effectify2(NFS__namespace.cp, /* @__PURE__ */ handleErrnoException("FileSystem", "copy"), /* @__PURE__ */ handleBadArgument("copy"));
58705
58734
  return (fromPath, toPath, options3) => nodeCp(fromPath, toPath, {
58706
58735
  force: options3?.overwrite ?? false,
58707
58736
  preserveTimestamps: options3?.preserveTimestamps ?? false,
@@ -58709,39 +58738,39 @@ var copy3 = /* @__PURE__ */ (() => {
58709
58738
  });
58710
58739
  })();
58711
58740
  var copyFile2 = /* @__PURE__ */ (() => {
58712
- const nodeCopyFile = /* @__PURE__ */ effectify2(NFS.copyFile, /* @__PURE__ */ handleErrnoException("FileSystem", "copyFile"), /* @__PURE__ */ handleBadArgument("copyFile"));
58741
+ const nodeCopyFile = /* @__PURE__ */ effectify2(NFS__namespace.copyFile, /* @__PURE__ */ handleErrnoException("FileSystem", "copyFile"), /* @__PURE__ */ handleBadArgument("copyFile"));
58713
58742
  return (fromPath, toPath) => nodeCopyFile(fromPath, toPath);
58714
58743
  })();
58715
58744
  var chmod2 = /* @__PURE__ */ (() => {
58716
- const nodeChmod = /* @__PURE__ */ effectify2(NFS.chmod, /* @__PURE__ */ handleErrnoException("FileSystem", "chmod"), /* @__PURE__ */ handleBadArgument("chmod"));
58745
+ const nodeChmod = /* @__PURE__ */ effectify2(NFS__namespace.chmod, /* @__PURE__ */ handleErrnoException("FileSystem", "chmod"), /* @__PURE__ */ handleBadArgument("chmod"));
58717
58746
  return (path6, mode) => nodeChmod(path6, mode);
58718
58747
  })();
58719
58748
  var chown2 = /* @__PURE__ */ (() => {
58720
- const nodeChown = /* @__PURE__ */ effectify2(NFS.chown, /* @__PURE__ */ handleErrnoException("FileSystem", "chown"), /* @__PURE__ */ handleBadArgument("chown"));
58749
+ const nodeChown = /* @__PURE__ */ effectify2(NFS__namespace.chown, /* @__PURE__ */ handleErrnoException("FileSystem", "chown"), /* @__PURE__ */ handleBadArgument("chown"));
58721
58750
  return (path6, uid, gid) => nodeChown(path6, uid, gid);
58722
58751
  })();
58723
58752
  var link2 = /* @__PURE__ */ (() => {
58724
- const nodeLink = /* @__PURE__ */ effectify2(NFS.link, /* @__PURE__ */ handleErrnoException("FileSystem", "link"), /* @__PURE__ */ handleBadArgument("link"));
58753
+ const nodeLink = /* @__PURE__ */ effectify2(NFS__namespace.link, /* @__PURE__ */ handleErrnoException("FileSystem", "link"), /* @__PURE__ */ handleBadArgument("link"));
58725
58754
  return (existingPath, newPath) => nodeLink(existingPath, newPath);
58726
58755
  })();
58727
58756
  var makeDirectory = /* @__PURE__ */ (() => {
58728
- const nodeMkdir = /* @__PURE__ */ effectify2(NFS.mkdir, /* @__PURE__ */ handleErrnoException("FileSystem", "makeDirectory"), /* @__PURE__ */ handleBadArgument("makeDirectory"));
58757
+ const nodeMkdir = /* @__PURE__ */ effectify2(NFS__namespace.mkdir, /* @__PURE__ */ handleErrnoException("FileSystem", "makeDirectory"), /* @__PURE__ */ handleBadArgument("makeDirectory"));
58729
58758
  return (path6, options3) => nodeMkdir(path6, {
58730
58759
  recursive: options3?.recursive ?? false,
58731
58760
  mode: options3?.mode
58732
58761
  });
58733
58762
  })();
58734
58763
  var makeTempDirectoryFactory = (method) => {
58735
- const nodeMkdtemp = effectify2(NFS.mkdtemp, handleErrnoException("FileSystem", method), handleBadArgument(method));
58764
+ const nodeMkdtemp = effectify2(NFS__namespace.mkdtemp, handleErrnoException("FileSystem", method), handleBadArgument(method));
58736
58765
  return (options3) => suspend4(() => {
58737
58766
  const prefix = options3?.prefix ?? "";
58738
- const directory5 = typeof options3?.directory === "string" ? path4.join(options3.directory, ".") : OS.tmpdir();
58739
- return nodeMkdtemp(prefix ? path4.join(directory5, prefix) : directory5 + "/");
58767
+ const directory5 = typeof options3?.directory === "string" ? path4__namespace.join(options3.directory, ".") : OS__namespace.tmpdir();
58768
+ return nodeMkdtemp(prefix ? path4__namespace.join(directory5, prefix) : directory5 + "/");
58740
58769
  });
58741
58770
  };
58742
58771
  var makeTempDirectory = /* @__PURE__ */ makeTempDirectoryFactory("makeTempDirectory");
58743
58772
  var removeFactory = (method) => {
58744
- const nodeRm = effectify2(NFS.rm, handleErrnoException("FileSystem", method), handleBadArgument(method));
58773
+ const nodeRm = effectify2(NFS__namespace.rm, handleErrnoException("FileSystem", method), handleBadArgument(method));
58745
58774
  return (path6, options3) => nodeRm(path6, {
58746
58775
  recursive: options3?.recursive ?? false,
58747
58776
  force: options3?.force ?? false
@@ -58756,19 +58785,19 @@ var makeTempDirectoryScoped = /* @__PURE__ */ (() => {
58756
58785
  })));
58757
58786
  })();
58758
58787
  var openFactory = (method) => {
58759
- const nodeOpen = effectify2(NFS.open, handleErrnoException("FileSystem", method), handleBadArgument(method));
58760
- const nodeClose = effectify2(NFS.close, handleErrnoException("FileSystem", method), handleBadArgument(method));
58788
+ const nodeOpen = effectify2(NFS__namespace.open, handleErrnoException("FileSystem", method), handleBadArgument(method));
58789
+ const nodeClose = effectify2(NFS__namespace.close, handleErrnoException("FileSystem", method), handleBadArgument(method));
58761
58790
  return (path6, options3) => pipe(acquireRelease2(nodeOpen(path6, options3?.flag ?? "r", options3?.mode), (fd) => orDie2(nodeClose(fd))), map16((fd) => makeFile(FileDescriptor(fd), options3?.flag?.startsWith("a") ?? false)));
58762
58791
  };
58763
58792
  var open2 = /* @__PURE__ */ openFactory("open");
58764
58793
  var makeFile = /* @__PURE__ */ (() => {
58765
- const nodeReadFactory = (method) => effectify2(NFS.read, handleErrnoException("FileSystem", method), handleBadArgument(method));
58794
+ const nodeReadFactory = (method) => effectify2(NFS__namespace.read, handleErrnoException("FileSystem", method), handleBadArgument(method));
58766
58795
  const nodeRead = /* @__PURE__ */ nodeReadFactory("read");
58767
58796
  const nodeReadAlloc = /* @__PURE__ */ nodeReadFactory("readAlloc");
58768
- const nodeStat = /* @__PURE__ */ effectify2(NFS.fstat, /* @__PURE__ */ handleErrnoException("FileSystem", "stat"), /* @__PURE__ */ handleBadArgument("stat"));
58769
- const nodeTruncate = /* @__PURE__ */ effectify2(NFS.ftruncate, /* @__PURE__ */ handleErrnoException("FileSystem", "truncate"), /* @__PURE__ */ handleBadArgument("truncate"));
58770
- const nodeSync = /* @__PURE__ */ effectify2(NFS.fsync, /* @__PURE__ */ handleErrnoException("FileSystem", "sync"), /* @__PURE__ */ handleBadArgument("sync"));
58771
- const nodeWriteFactory = (method) => effectify2(NFS.write, handleErrnoException("FileSystem", method), handleBadArgument(method));
58797
+ const nodeStat = /* @__PURE__ */ effectify2(NFS__namespace.fstat, /* @__PURE__ */ handleErrnoException("FileSystem", "stat"), /* @__PURE__ */ handleBadArgument("stat"));
58798
+ const nodeTruncate = /* @__PURE__ */ effectify2(NFS__namespace.ftruncate, /* @__PURE__ */ handleErrnoException("FileSystem", "truncate"), /* @__PURE__ */ handleBadArgument("truncate"));
58799
+ const nodeSync = /* @__PURE__ */ effectify2(NFS__namespace.fsync, /* @__PURE__ */ handleErrnoException("FileSystem", "sync"), /* @__PURE__ */ handleBadArgument("sync"));
58800
+ const nodeWriteFactory = (method) => effectify2(NFS__namespace.write, handleErrnoException("FileSystem", method), handleBadArgument(method));
58772
58801
  const nodeWrite = /* @__PURE__ */ nodeWriteFactory("write");
58773
58802
  const nodeWriteAll = /* @__PURE__ */ nodeWriteFactory("writeAll");
58774
58803
  class FileImpl {
@@ -58872,8 +58901,8 @@ var makeFile = /* @__PURE__ */ (() => {
58872
58901
  var makeTempFileFactory = (method) => {
58873
58902
  const makeDirectory2 = makeTempDirectoryFactory(method);
58874
58903
  const open3 = openFactory(method);
58875
- const randomHexString2 = (bytes) => sync4(() => Crypto.randomBytes(bytes).toString("hex"));
58876
- return (options3) => pipe(zip5(makeDirectory2(options3), randomHexString2(6)), map16(([directory5, random4]) => path4.join(directory5, random4)), tap3((path6) => scoped2(open3(path6, {
58904
+ const randomHexString2 = (bytes) => sync4(() => Crypto__namespace.randomBytes(bytes).toString("hex"));
58905
+ return (options3) => pipe(zip5(makeDirectory2(options3), randomHexString2(6)), map16(([directory5, random4]) => path4__namespace.join(directory5, random4)), tap3((path6) => scoped2(open3(path6, {
58877
58906
  flag: "w+"
58878
58907
  }))));
58879
58908
  };
@@ -58881,17 +58910,17 @@ var makeTempFile = /* @__PURE__ */ makeTempFileFactory("makeTempFile");
58881
58910
  var makeTempFileScoped = /* @__PURE__ */ (() => {
58882
58911
  const makeFile2 = /* @__PURE__ */ makeTempFileFactory("makeTempFileScoped");
58883
58912
  const removeDirectory = /* @__PURE__ */ removeFactory("makeTempFileScoped");
58884
- return (options3) => acquireRelease2(makeFile2(options3), (file6) => orDie2(removeDirectory(path4.dirname(file6), {
58913
+ return (options3) => acquireRelease2(makeFile2(options3), (file6) => orDie2(removeDirectory(path4__namespace.dirname(file6), {
58885
58914
  recursive: true
58886
58915
  })));
58887
58916
  })();
58888
58917
  var readDirectory = (path6, options3) => tryPromise2({
58889
- try: () => NFS.promises.readdir(path6, options3),
58918
+ try: () => NFS__namespace.promises.readdir(path6, options3),
58890
58919
  catch: (err) => handleErrnoException("FileSystem", "readDirectory")(err, [path6])
58891
58920
  });
58892
58921
  var readFile2 = (path6) => async2((resume2, signal) => {
58893
58922
  try {
58894
- NFS.readFile(path6, {
58923
+ NFS__namespace.readFile(path6, {
58895
58924
  signal
58896
58925
  }, (err, data) => {
58897
58926
  if (err) {
@@ -58905,15 +58934,15 @@ var readFile2 = (path6) => async2((resume2, signal) => {
58905
58934
  }
58906
58935
  });
58907
58936
  var readLink = /* @__PURE__ */ (() => {
58908
- const nodeReadLink = /* @__PURE__ */ effectify2(NFS.readlink, /* @__PURE__ */ handleErrnoException("FileSystem", "readLink"), /* @__PURE__ */ handleBadArgument("readLink"));
58937
+ const nodeReadLink = /* @__PURE__ */ effectify2(NFS__namespace.readlink, /* @__PURE__ */ handleErrnoException("FileSystem", "readLink"), /* @__PURE__ */ handleBadArgument("readLink"));
58909
58938
  return (path6) => nodeReadLink(path6);
58910
58939
  })();
58911
58940
  var realPath = /* @__PURE__ */ (() => {
58912
- const nodeRealPath = /* @__PURE__ */ effectify2(NFS.realpath, /* @__PURE__ */ handleErrnoException("FileSystem", "realPath"), /* @__PURE__ */ handleBadArgument("realPath"));
58941
+ const nodeRealPath = /* @__PURE__ */ effectify2(NFS__namespace.realpath, /* @__PURE__ */ handleErrnoException("FileSystem", "realPath"), /* @__PURE__ */ handleBadArgument("realPath"));
58913
58942
  return (path6) => nodeRealPath(path6);
58914
58943
  })();
58915
58944
  var rename3 = /* @__PURE__ */ (() => {
58916
- const nodeRename = /* @__PURE__ */ effectify2(NFS.rename, /* @__PURE__ */ handleErrnoException("FileSystem", "rename"), /* @__PURE__ */ handleBadArgument("rename"));
58945
+ const nodeRename = /* @__PURE__ */ effectify2(NFS__namespace.rename, /* @__PURE__ */ handleErrnoException("FileSystem", "rename"), /* @__PURE__ */ handleBadArgument("rename"));
58917
58946
  return (oldPath, newPath) => nodeRename(oldPath, newPath);
58918
58947
  })();
58919
58948
  var makeFileInfo = (stat3) => ({
@@ -58933,23 +58962,23 @@ var makeFileInfo = (stat3) => ({
58933
58962
  blocks: fromNullable(stat3.blocks)
58934
58963
  });
58935
58964
  var stat2 = /* @__PURE__ */ (() => {
58936
- const nodeStat = /* @__PURE__ */ effectify2(NFS.stat, /* @__PURE__ */ handleErrnoException("FileSystem", "stat"), /* @__PURE__ */ handleBadArgument("stat"));
58965
+ const nodeStat = /* @__PURE__ */ effectify2(NFS__namespace.stat, /* @__PURE__ */ handleErrnoException("FileSystem", "stat"), /* @__PURE__ */ handleBadArgument("stat"));
58937
58966
  return (path6) => map16(nodeStat(path6), makeFileInfo);
58938
58967
  })();
58939
58968
  var symlink2 = /* @__PURE__ */ (() => {
58940
- const nodeSymlink = /* @__PURE__ */ effectify2(NFS.symlink, /* @__PURE__ */ handleErrnoException("FileSystem", "symlink"), /* @__PURE__ */ handleBadArgument("symlink"));
58969
+ const nodeSymlink = /* @__PURE__ */ effectify2(NFS__namespace.symlink, /* @__PURE__ */ handleErrnoException("FileSystem", "symlink"), /* @__PURE__ */ handleBadArgument("symlink"));
58941
58970
  return (target, path6) => nodeSymlink(target, path6);
58942
58971
  })();
58943
58972
  var truncate2 = /* @__PURE__ */ (() => {
58944
- const nodeTruncate = /* @__PURE__ */ effectify2(NFS.truncate, /* @__PURE__ */ handleErrnoException("FileSystem", "truncate"), /* @__PURE__ */ handleBadArgument("truncate"));
58973
+ const nodeTruncate = /* @__PURE__ */ effectify2(NFS__namespace.truncate, /* @__PURE__ */ handleErrnoException("FileSystem", "truncate"), /* @__PURE__ */ handleBadArgument("truncate"));
58945
58974
  return (path6, length3) => nodeTruncate(path6, length3 !== void 0 ? Number(length3) : void 0);
58946
58975
  })();
58947
58976
  var utimes2 = /* @__PURE__ */ (() => {
58948
- const nodeUtimes = /* @__PURE__ */ effectify2(NFS.utimes, /* @__PURE__ */ handleErrnoException("FileSystem", "utime"), /* @__PURE__ */ handleBadArgument("utime"));
58977
+ const nodeUtimes = /* @__PURE__ */ effectify2(NFS__namespace.utimes, /* @__PURE__ */ handleErrnoException("FileSystem", "utime"), /* @__PURE__ */ handleBadArgument("utime"));
58949
58978
  return (path6, atime, mtime) => nodeUtimes(path6, atime, mtime);
58950
58979
  })();
58951
58980
  var watchNode = (path6, options3) => asyncScoped2((emit) => acquireRelease2(sync4(() => {
58952
- const watcher = NFS.watch(path6, {
58981
+ const watcher = NFS__namespace.watch(path6, {
58953
58982
  recursive: options3?.recursive
58954
58983
  }, (event, path7) => {
58955
58984
  if (!path7) return;
@@ -58990,7 +59019,7 @@ var watchNode = (path6, options3) => asyncScoped2((emit) => acquireRelease2(sync
58990
59019
  var watch2 = (backend, path6, options3) => stat2(path6).pipe(map16((stat3) => backend.pipe(flatMap((_) => _.register(path6, stat3, options3)), getOrElse(() => watchNode(path6, options3)))), unwrap3);
58991
59020
  var writeFile2 = (path6, data, options3) => async2((resume2, signal) => {
58992
59021
  try {
58993
- NFS.writeFile(path6, data, {
59022
+ NFS__namespace.writeFile(path6, data, {
58994
59023
  signal,
58995
59024
  flag: options3?.flag,
58996
59025
  mode: options3?.mode
@@ -59046,7 +59075,7 @@ var Path2 = /* @__PURE__ */ GenericTag("@effect/platform/Path");
59046
59075
  var TypeId22 = TypeId21;
59047
59076
  var Path3 = Path2;
59048
59077
  var fromFileUrl2 = (url2) => try_2({
59049
- try: () => NodeUrl.fileURLToPath(url2),
59078
+ try: () => NodeUrl__namespace.fileURLToPath(url2),
59050
59079
  catch: (error4) => new BadArgument({
59051
59080
  module: "Path",
59052
59081
  method: "fromFileUrl",
@@ -59055,7 +59084,7 @@ var fromFileUrl2 = (url2) => try_2({
59055
59084
  })
59056
59085
  });
59057
59086
  var toFileUrl2 = (path6) => try_2({
59058
- try: () => NodeUrl.pathToFileURL(path6),
59087
+ try: () => NodeUrl__namespace.pathToFileURL(path6),
59059
59088
  catch: (error4) => new BadArgument({
59060
59089
  module: "Path",
59061
59090
  method: "toFileUrl",
@@ -59065,7 +59094,7 @@ var toFileUrl2 = (path6) => try_2({
59065
59094
  });
59066
59095
  var layer6 = /* @__PURE__ */ succeed9(Path3, /* @__PURE__ */ Path3.of({
59067
59096
  [TypeId22]: TypeId22,
59068
- ...path4,
59097
+ ...path4__namespace,
59069
59098
  fromFileUrl: fromFileUrl2,
59070
59099
  toFileUrl: toFileUrl2
59071
59100
  }));
@@ -59500,11 +59529,11 @@ var make58 = /* @__PURE__ */ fnUntraced2(function* (shouldQuit = defaultShouldQu
59500
59529
  const stdout3 = process.stdout;
59501
59530
  const rlRef = yield* make45({
59502
59531
  acquire: acquireRelease2(sync4(() => {
59503
- const rl = readline.createInterface({
59532
+ const rl = readline__namespace.createInterface({
59504
59533
  input: stdin3,
59505
59534
  escapeCodeTimeout: 50
59506
59535
  });
59507
- readline.emitKeypressEvents(stdin3, rl);
59536
+ readline__namespace.emitKeypressEvents(stdin3, rl);
59508
59537
  if (stdin3.isTTY) {
59509
59538
  stdin3.setRawMode(true);
59510
59539
  }
@@ -67116,7 +67145,7 @@ var Lesson = class {
67116
67145
  this.root = opts.root;
67117
67146
  }
67118
67147
  absolutePath() {
67119
- return path4.resolve(this.root, this.sectionName, this.path);
67148
+ return path4__namespace.resolve(this.root, this.sectionName, this.path);
67120
67149
  }
67121
67150
  allFiles() {
67122
67151
  const absolutePath = this.absolutePath();
@@ -67125,15 +67154,15 @@ var Lesson = class {
67125
67154
  const files = yield* fs.readDirectory(absolutePath, {
67126
67155
  recursive: true
67127
67156
  });
67128
- return files.map((file6) => path4.join(absolutePath, file6));
67157
+ return files.map((file6) => path4__namespace.join(absolutePath, file6));
67129
67158
  });
67130
67159
  }
67131
67160
  subfolders() {
67132
67161
  const absolutePath = this.absolutePath();
67133
67162
  return this.allFiles().pipe(
67134
67163
  Effect_exports.map(
67135
- (files) => files.map((file6) => path4.relative(absolutePath, file6)).filter((file6) => {
67136
- return file6.split(path4.sep).length === 1;
67164
+ (files) => files.map((file6) => path4__namespace.relative(absolutePath, file6)).filter((file6) => {
67165
+ return file6.split(path4__namespace.sep).length === 1;
67137
67166
  })
67138
67167
  )
67139
67168
  );
@@ -67207,7 +67236,7 @@ var LessonParserService = class extends Effect_exports.Service()(
67207
67236
  const sections = yield* Effect_exports.all(
67208
67237
  rawSections.map((section) => {
67209
67238
  return Effect_exports.gen(function* () {
67210
- const sectionPath = path4.join(root, section);
67239
+ const sectionPath = path4__namespace.join(root, section);
67211
67240
  const stat3 = yield* fs.stat(sectionPath);
67212
67241
  if (stat3.type !== "Directory") {
67213
67242
  return filterMeOut;
@@ -67226,10 +67255,10 @@ var LessonParserService = class extends Effect_exports.Service()(
67226
67255
  yield* Effect_exports.forEach(sections, (section) => {
67227
67256
  return Effect_exports.gen(function* () {
67228
67257
  const rawLessons = yield* fs.readDirectory(
67229
- path4.join(root, section.path)
67258
+ path4__namespace.join(root, section.path)
67230
67259
  );
67231
67260
  for (const lesson of rawLessons) {
67232
- const lessonPath = path4.join(
67261
+ const lessonPath = path4__namespace.join(
67233
67262
  root,
67234
67263
  section.path,
67235
67264
  lesson
@@ -67304,7 +67333,7 @@ var runLesson = Effect_exports.fn("runLesson")(function* (opts) {
67304
67333
  const previousLesson = lessons[foundLessonIndex - 1];
67305
67334
  const nextLesson = lessons[foundLessonIndex + 1];
67306
67335
  const subfolders = yield* foundLesson.subfolders().pipe(
67307
- Effect_exports.map((files) => files.map((p3) => path4.basename(p3)))
67336
+ Effect_exports.map((files) => files.map((p3) => path4__namespace.basename(p3)))
67308
67337
  );
67309
67338
  if (subfolders.length === 0) {
67310
67339
  return yield* new LessonEntrypointNotFoundError({
@@ -67372,7 +67401,7 @@ var runLesson = Effect_exports.fn("runLesson")(function* (opts) {
67372
67401
  const mainFile = yield* foundLesson.allFiles().pipe(
67373
67402
  Effect_exports.map(
67374
67403
  (files) => files.find(
67375
- (file6) => file6.includes(path4.join(subfolder, "main.ts"))
67404
+ (file6) => file6.includes(path4__namespace.join(subfolder, "main.ts"))
67376
67405
  )
67377
67406
  )
67378
67407
  );
@@ -67385,30 +67414,30 @@ var runLesson = Effect_exports.fn("runLesson")(function* (opts) {
67385
67414
  const readmeFile = yield* foundLesson.allFiles().pipe(
67386
67415
  Effect_exports.map(
67387
67416
  (files) => files.find(
67388
- (file6) => file6.includes(path4.join(subfolder, "readme.md"))
67417
+ (file6) => file6.includes(path4__namespace.join(subfolder, "readme.md"))
67389
67418
  )
67390
67419
  )
67391
67420
  );
67392
67421
  yield* Console_exports.clear;
67393
67422
  yield* Console_exports.log(
67394
- styleText(
67423
+ util.styleText(
67395
67424
  "bold",
67396
67425
  `Running ${foundLesson.num} ${subfolder}...`
67397
67426
  )
67398
67427
  );
67399
67428
  yield* Console_exports.log(
67400
- styleText(
67429
+ util.styleText(
67401
67430
  "dim",
67402
67431
  " Press n + enter to go to the next exercise"
67403
67432
  )
67404
67433
  );
67405
67434
  yield* Console_exports.log(
67406
- styleText("dim", " Press h + enter for more shortcuts\n")
67435
+ util.styleText("dim", " Press h + enter for more shortcuts\n")
67407
67436
  );
67408
67437
  if (readmeFile) {
67409
67438
  yield* Console_exports.log(
67410
- `${styleText([], "Instructions:")}
67411
- ${styleText(
67439
+ `${util.styleText([], "Instructions:")}
67440
+ ${util.styleText(
67412
67441
  "dim",
67413
67442
  readmeFile
67414
67443
  )}
@@ -67431,7 +67460,7 @@ var runLesson = Effect_exports.fn("runLesson")(function* (opts) {
67431
67460
  Effect_exports.map((code2) => code2 === 0 ? "exit" : "failed")
67432
67461
  ),
67433
67462
  Effect_exports.gen(function* () {
67434
- const rl = readline2.createInterface({
67463
+ const rl = readline2__namespace.createInterface({
67435
67464
  input: process.stdin
67436
67465
  });
67437
67466
  yield* Effect_exports.addFinalizer(() => {
@@ -67442,10 +67471,10 @@ var runLesson = Effect_exports.fn("runLesson")(function* (opts) {
67442
67471
  () => rl.question("")
67443
67472
  );
67444
67473
  if (line4 === "h") {
67445
- yield* Console_exports.log(styleText("bold", "Shortcuts:"));
67474
+ yield* Console_exports.log(util.styleText("bold", "Shortcuts:"));
67446
67475
  for (const [key, value5] of Object.entries(shortcuts)) {
67447
67476
  yield* Console_exports.log(
67448
- ` ${key} ${styleText("dim", `- ${value5}`)}`
67477
+ ` ${key} ${util.styleText("dim", `- ${value5}`)}`
67449
67478
  );
67450
67479
  }
67451
67480
  } else if (line4 === "q") {
@@ -67596,13 +67625,13 @@ var exercise = Command_exports2.make(
67596
67625
  Options_exports.withDescription(
67597
67626
  "The directory to look for lessons"
67598
67627
  ),
67599
- Options_exports.withDefault(process.cwd())
67628
+ Options_exports.withDefault(path4__namespace.join(process.cwd(), "exercises"))
67600
67629
  ),
67601
67630
  envFilePath: Options_exports.text("env-file").pipe(
67602
67631
  Options_exports.withDescription(
67603
67632
  "The path to the environment file to use"
67604
67633
  ),
67605
- Options_exports.withDefault(path4.join(process.cwd(), ".env"))
67634
+ Options_exports.withDefault(path4__namespace.join(process.cwd(), ".env"))
67606
67635
  ),
67607
67636
  cwd: Options_exports.text("cwd").pipe(
67608
67637
  Options_exports.withDescription(
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "ai-hero-cli",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "description": "The CLI used to run exercises for the AI Hero course",
6
- "bin": "bin.js",
6
+ "bin": "bin.cjs",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "https://github.com/mattpocock/ai-hero-cli"