@lessonkit/cli 1.0.2 → 1.2.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/README.md +2 -0
- package/dist/bin.js +57 -21
- package/dist/index.js +57 -21
- package/package.json +4 -4
- package/template/vite-react/package.json +6 -6
- package/template/vite-react/vitest.config.ts +1 -1
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ lessonkit package --target scorm12 # LMS artifact
|
|
|
32
32
|
|
|
33
33
|
Every project includes a root `lessonkit.json` manifest (`schemaVersion: 1`).
|
|
34
34
|
|
|
35
|
+
Subprocess timeout defaults to **30 minutes** (`LESSONKIT_CMD_TIMEOUT_MS`; set `0` to disable).
|
|
36
|
+
|
|
35
37
|
## Docs
|
|
36
38
|
|
|
37
39
|
[CLI reference](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) · [Packaging guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html) · [Template source](https://github.com/eddiethedean/lessonkit/tree/main/templates/vite-react)
|
package/dist/bin.js
CHANGED
|
@@ -54,7 +54,19 @@ ${details}`;
|
|
|
54
54
|
|
|
55
55
|
// src/lib/exec.ts
|
|
56
56
|
import { spawn } from "child_process";
|
|
57
|
+
var DEFAULT_CMD_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
58
|
+
function resolveCommandTimeoutMs(explicit) {
|
|
59
|
+
if (explicit !== void 0) {
|
|
60
|
+
return explicit > 0 ? explicit : void 0;
|
|
61
|
+
}
|
|
62
|
+
const raw = process.env.LESSONKIT_CMD_TIMEOUT_MS;
|
|
63
|
+
if (raw === void 0 || raw === "") return DEFAULT_CMD_TIMEOUT_MS;
|
|
64
|
+
const parsed = Number(raw);
|
|
65
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
|
|
66
|
+
return parsed;
|
|
67
|
+
}
|
|
57
68
|
async function runCommand(command, args, opts) {
|
|
69
|
+
const timeoutMs = resolveCommandTimeoutMs(opts.timeoutMs);
|
|
58
70
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
59
71
|
const child = spawn(command, args, {
|
|
60
72
|
cwd: opts.cwd,
|
|
@@ -62,25 +74,48 @@ async function runCommand(command, args, opts) {
|
|
|
62
74
|
stdio: "inherit",
|
|
63
75
|
shell: false
|
|
64
76
|
});
|
|
77
|
+
let timedOut = false;
|
|
78
|
+
const timer = timeoutMs !== void 0 ? setTimeout(() => {
|
|
79
|
+
timedOut = true;
|
|
80
|
+
child.kill("SIGTERM");
|
|
81
|
+
setTimeout(() => child.kill("SIGKILL"), 5e3).unref?.();
|
|
82
|
+
}, timeoutMs) : void 0;
|
|
83
|
+
const settle = (fn) => {
|
|
84
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
85
|
+
fn();
|
|
86
|
+
};
|
|
65
87
|
child.on("error", (err) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
settle(() => {
|
|
89
|
+
rejectPromise(
|
|
90
|
+
new CliError(`Failed to run ${command}: ${err.message}`, {
|
|
91
|
+
code: "RUNTIME",
|
|
92
|
+
exitCode: EXIT_RUNTIME
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
});
|
|
72
96
|
});
|
|
73
97
|
child.on("close", (code) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
settle(() => {
|
|
99
|
+
if (timedOut) {
|
|
100
|
+
rejectPromise(
|
|
101
|
+
new CliError(`${command} timed out after ${timeoutMs}ms.`, {
|
|
102
|
+
code: "RUNTIME",
|
|
103
|
+
exitCode: EXIT_RUNTIME
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (code === 0) {
|
|
109
|
+
resolvePromise();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
rejectPromise(
|
|
113
|
+
new CliError(`${command} exited with code ${code ?? "unknown"}.`, {
|
|
114
|
+
code: "RUNTIME",
|
|
115
|
+
exitCode: EXIT_RUNTIME
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
});
|
|
84
119
|
});
|
|
85
120
|
});
|
|
86
121
|
}
|
|
@@ -126,6 +161,7 @@ async function copyTemplate(src, dest) {
|
|
|
126
161
|
await copyTemplate(srcPath, destPath);
|
|
127
162
|
} else if (entry.isFile()) {
|
|
128
163
|
await cp(srcPath, destPath);
|
|
164
|
+
} else {
|
|
129
165
|
}
|
|
130
166
|
}
|
|
131
167
|
}
|
|
@@ -164,8 +200,8 @@ async function runInit(opts, logger) {
|
|
|
164
200
|
exitCode: EXIT_INVALID_PROJECT
|
|
165
201
|
});
|
|
166
202
|
}
|
|
167
|
-
const slug = slugifyId(rawName
|
|
168
|
-
const projectName = rawName
|
|
203
|
+
const slug = slugifyId(rawName);
|
|
204
|
+
const projectName = rawName;
|
|
169
205
|
const projectDir = opts.here ? cwd : resolve(cwd, slug);
|
|
170
206
|
if (!opts.here && existsSync(projectDir)) {
|
|
171
207
|
throw new CliError(
|
|
@@ -598,10 +634,10 @@ function createProgram(baseLogger = console) {
|
|
|
598
634
|
out: opts.out,
|
|
599
635
|
json: opts.json
|
|
600
636
|
});
|
|
601
|
-
if (!opts.json && result.ok) {
|
|
602
|
-
if (result.
|
|
637
|
+
if (!opts.json && result.ok && result.command === "package") {
|
|
638
|
+
if (result.target === "react-vite") {
|
|
603
639
|
logger.log(`Built react-vite \u2192 ${result.distDir}`);
|
|
604
|
-
} else
|
|
640
|
+
} else {
|
|
605
641
|
const dest = result.outputPath ?? result.outputDir;
|
|
606
642
|
logger.log(
|
|
607
643
|
`Packaged ${result.target}${dest ? ` \u2192 ${dest}` : ""} (${result.fileCount} files)`
|
package/dist/index.js
CHANGED
|
@@ -52,7 +52,19 @@ ${details}`;
|
|
|
52
52
|
|
|
53
53
|
// src/lib/exec.ts
|
|
54
54
|
import { spawn } from "child_process";
|
|
55
|
+
var DEFAULT_CMD_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
56
|
+
function resolveCommandTimeoutMs(explicit) {
|
|
57
|
+
if (explicit !== void 0) {
|
|
58
|
+
return explicit > 0 ? explicit : void 0;
|
|
59
|
+
}
|
|
60
|
+
const raw = process.env.LESSONKIT_CMD_TIMEOUT_MS;
|
|
61
|
+
if (raw === void 0 || raw === "") return DEFAULT_CMD_TIMEOUT_MS;
|
|
62
|
+
const parsed = Number(raw);
|
|
63
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return void 0;
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
55
66
|
async function runCommand(command, args, opts) {
|
|
67
|
+
const timeoutMs = resolveCommandTimeoutMs(opts.timeoutMs);
|
|
56
68
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
57
69
|
const child = spawn(command, args, {
|
|
58
70
|
cwd: opts.cwd,
|
|
@@ -60,25 +72,48 @@ async function runCommand(command, args, opts) {
|
|
|
60
72
|
stdio: "inherit",
|
|
61
73
|
shell: false
|
|
62
74
|
});
|
|
75
|
+
let timedOut = false;
|
|
76
|
+
const timer = timeoutMs !== void 0 ? setTimeout(() => {
|
|
77
|
+
timedOut = true;
|
|
78
|
+
child.kill("SIGTERM");
|
|
79
|
+
setTimeout(() => child.kill("SIGKILL"), 5e3).unref?.();
|
|
80
|
+
}, timeoutMs) : void 0;
|
|
81
|
+
const settle = (fn) => {
|
|
82
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
83
|
+
fn();
|
|
84
|
+
};
|
|
63
85
|
child.on("error", (err) => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
settle(() => {
|
|
87
|
+
rejectPromise(
|
|
88
|
+
new CliError(`Failed to run ${command}: ${err.message}`, {
|
|
89
|
+
code: "RUNTIME",
|
|
90
|
+
exitCode: EXIT_RUNTIME
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
});
|
|
70
94
|
});
|
|
71
95
|
child.on("close", (code) => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
settle(() => {
|
|
97
|
+
if (timedOut) {
|
|
98
|
+
rejectPromise(
|
|
99
|
+
new CliError(`${command} timed out after ${timeoutMs}ms.`, {
|
|
100
|
+
code: "RUNTIME",
|
|
101
|
+
exitCode: EXIT_RUNTIME
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (code === 0) {
|
|
107
|
+
resolvePromise();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
rejectPromise(
|
|
111
|
+
new CliError(`${command} exited with code ${code ?? "unknown"}.`, {
|
|
112
|
+
code: "RUNTIME",
|
|
113
|
+
exitCode: EXIT_RUNTIME
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
});
|
|
82
117
|
});
|
|
83
118
|
});
|
|
84
119
|
}
|
|
@@ -124,6 +159,7 @@ async function copyTemplate(src, dest) {
|
|
|
124
159
|
await copyTemplate(srcPath, destPath);
|
|
125
160
|
} else if (entry.isFile()) {
|
|
126
161
|
await cp(srcPath, destPath);
|
|
162
|
+
} else {
|
|
127
163
|
}
|
|
128
164
|
}
|
|
129
165
|
}
|
|
@@ -162,8 +198,8 @@ async function runInit(opts, logger) {
|
|
|
162
198
|
exitCode: EXIT_INVALID_PROJECT
|
|
163
199
|
});
|
|
164
200
|
}
|
|
165
|
-
const slug = slugifyId(rawName
|
|
166
|
-
const projectName = rawName
|
|
201
|
+
const slug = slugifyId(rawName);
|
|
202
|
+
const projectName = rawName;
|
|
167
203
|
const projectDir = opts.here ? cwd : resolve(cwd, slug);
|
|
168
204
|
if (!opts.here && existsSync(projectDir)) {
|
|
169
205
|
throw new CliError(
|
|
@@ -596,10 +632,10 @@ function createProgram(baseLogger = console) {
|
|
|
596
632
|
out: opts.out,
|
|
597
633
|
json: opts.json
|
|
598
634
|
});
|
|
599
|
-
if (!opts.json && result.ok) {
|
|
600
|
-
if (result.
|
|
635
|
+
if (!opts.json && result.ok && result.command === "package") {
|
|
636
|
+
if (result.target === "react-vite") {
|
|
601
637
|
logger.log(`Built react-vite \u2192 ${result.distDir}`);
|
|
602
|
-
} else
|
|
638
|
+
} else {
|
|
603
639
|
const dest = result.outputPath ?? result.outputDir;
|
|
604
640
|
logger.log(
|
|
605
641
|
`Packaged ${result.target}${dest ? ` \u2192 ${dest}` : ""} (${result.fileCount} files)`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lessonkit/cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "LessonKit CLI — init, dev, build, and package learning experiences.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"url": "git+https://github.com/eddiethedean/lessonkit.git",
|
|
10
10
|
"directory": "packages/cli"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://
|
|
12
|
+
"homepage": "https://lessonkit.readthedocs.io/en/latest/reference/cli.html",
|
|
13
13
|
"bugs": {
|
|
14
14
|
"url": "https://github.com/eddiethedean/lessonkit/issues"
|
|
15
15
|
},
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"lint": "echo \"(no lint configured yet)\""
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@lessonkit/core": "1.0
|
|
46
|
-
"@lessonkit/lxpack": "1.0
|
|
45
|
+
"@lessonkit/core": "1.2.0",
|
|
46
|
+
"@lessonkit/lxpack": "1.2.0",
|
|
47
47
|
"commander": "^14.0.1"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"test:coverage": "vitest run --coverage --passWithNoTests=false"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@lessonkit/core": "^1.0
|
|
17
|
-
"@lessonkit/react": "^1.0
|
|
18
|
-
"@lessonkit/themes": "^1.0
|
|
19
|
-
"@lessonkit/xapi": "^1.0
|
|
16
|
+
"@lessonkit/core": "^1.2.0",
|
|
17
|
+
"@lessonkit/react": "^1.2.0",
|
|
18
|
+
"@lessonkit/themes": "^1.2.0",
|
|
19
|
+
"@lessonkit/xapi": "^1.2.0",
|
|
20
20
|
"react": "^18.3.1",
|
|
21
21
|
"react-dom": "^18.3.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@lessonkit/cli": "^1.0
|
|
25
|
-
"@lessonkit/lxpack": "^1.0
|
|
24
|
+
"@lessonkit/cli": "^1.2.0",
|
|
25
|
+
"@lessonkit/lxpack": "^1.2.0",
|
|
26
26
|
"@testing-library/react": "^16.3.0",
|
|
27
27
|
"@types/react": "^18.3.23",
|
|
28
28
|
"@types/react-dom": "^18.3.7",
|
|
@@ -8,7 +8,7 @@ export default defineConfig({
|
|
|
8
8
|
provider: "v8",
|
|
9
9
|
include: ["src/**/*.{ts,tsx}"],
|
|
10
10
|
exclude: ["dist/**", "node_modules/**", "**/*.d.ts", "**/*.d.cts"],
|
|
11
|
-
thresholds: { lines:
|
|
11
|
+
thresholds: { statements: 85, branches: 85, functions: 85, lines: 85 },
|
|
12
12
|
},
|
|
13
13
|
},
|
|
14
14
|
});
|