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 +134 -0
- package/{bin.js → bin.cjs} +100 -71
- package/package.json +2 -2
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.
|
package/{bin.js → bin.cjs}
RENAMED
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
58720
|
+
const nodeAccess = /* @__PURE__ */ effectify2(NFS__namespace.access, /* @__PURE__ */ handleErrnoException("FileSystem", "access"), /* @__PURE__ */ handleBadArgument("access"));
|
|
58692
58721
|
return (path6, options3) => {
|
|
58693
|
-
let mode =
|
|
58722
|
+
let mode = NFS__namespace.constants.F_OK;
|
|
58694
58723
|
if (options3?.readable) {
|
|
58695
|
-
mode |=
|
|
58724
|
+
mode |= NFS__namespace.constants.R_OK;
|
|
58696
58725
|
}
|
|
58697
58726
|
if (options3?.writable) {
|
|
58698
|
-
mode |=
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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" ?
|
|
58739
|
-
return nodeMkdtemp(prefix ?
|
|
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(
|
|
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(
|
|
58760
|
-
const nodeClose = effectify2(
|
|
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(
|
|
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(
|
|
58769
|
-
const nodeTruncate = /* @__PURE__ */ effectify2(
|
|
58770
|
-
const nodeSync = /* @__PURE__ */ effectify2(
|
|
58771
|
-
const nodeWriteFactory = (method) => effectify2(
|
|
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(() =>
|
|
58876
|
-
return (options3) => pipe(zip5(makeDirectory2(options3), randomHexString2(6)), map16(([directory5, random4]) =>
|
|
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(
|
|
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: () =>
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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: () =>
|
|
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: () =>
|
|
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
|
-
...
|
|
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 =
|
|
59532
|
+
const rl = readline__namespace.createInterface({
|
|
59504
59533
|
input: stdin3,
|
|
59505
59534
|
escapeCodeTimeout: 50
|
|
59506
59535
|
});
|
|
59507
|
-
|
|
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
|
|
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) =>
|
|
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) =>
|
|
67136
|
-
return file6.split(
|
|
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 =
|
|
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
|
-
|
|
67258
|
+
path4__namespace.join(root, section.path)
|
|
67230
67259
|
);
|
|
67231
67260
|
for (const lesson of rawLessons) {
|
|
67232
|
-
const lessonPath =
|
|
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) =>
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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.
|
|
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.
|
|
6
|
+
"bin": "bin.cjs",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/mattpocock/ai-hero-cli"
|