@icyouo/evt-cli 0.1.0 → 0.1.2
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 +76 -7
- package/README.zh-CN.md +66 -7
- package/data/scanner.example.json +2 -5
- package/package.json +7 -3
- package/scripts/build-package.js +173 -0
- package/scripts/check-api-audit.js +260 -0
- package/scripts/check-api-coverage.js +41 -0
- package/scripts/local-ci.js +38 -0
- package/scripts/sync-api-coverage.js +227 -0
- package/skills/evt-api-scanner/SKILL.md +147 -0
- package/skills/evt-api-scanner/scripts/discover.js +160 -0
- package/skills/evt-api-scanner/scripts/scan.js +231 -0
- package/skills/evt-flow-generator/SKILL.md +139 -0
- package/skills/evt-profile-generator/SKILL.md +122 -0
- package/src/config/serviceScanner.js +60 -10
- package/src/index.js +45 -1
- package/src/util/args.js +3 -0
- package/test/apiAudit.test.js +137 -0
- package/test/duration.test.js +11 -0
- package/test/flow.test.js +215 -0
- package/test/liveTester.test.js +54 -0
- package/test/requestBuilder.test.js +214 -0
- package/test/serviceScanner.test.js +196 -0
- package/test/template.test.js +18 -0
- package/test/yaml.test.js +20 -0
package/README.md
CHANGED
|
@@ -9,7 +9,8 @@ evt-cli is a general-purpose HTTP CLI for running YAML-defined APIs and workflow
|
|
|
9
9
|
- Runtime endpoints come only from `apis/*.yaml`.
|
|
10
10
|
- Flows come only from `flows/*.yaml`.
|
|
11
11
|
- Environments, base URLs, headers, and test fixtures come only from `profiles/*.json`.
|
|
12
|
-
-
|
|
12
|
+
- Endpoint definitions are persisted as YAML. Scanner JSON is only an internal machine-readable handoff.
|
|
13
|
+
- Bundled skills are preferred for project data bootstrap. The built-in regex scanner remains as an endpoint-only fallback for users without an agent or skill workflow.
|
|
13
14
|
- The default data directory is bundled with the CLI package. You can also point to your own project data directory with `--config-root` or `EVT_CLI_ROOT`.
|
|
14
15
|
|
|
15
16
|
## Quick Start
|
|
@@ -77,12 +78,33 @@ evt-cli ships with `data/**/*.example.*` for validation and reference. Real proj
|
|
|
77
78
|
|
|
78
79
|
For compatibility with existing projects, evt also reads `apis/`, `flows/`, `profiles/`, and `scanner.config.json` directly under `--config-root` when those paths exist.
|
|
79
80
|
|
|
81
|
+
## Bootstrap Project Data With Skills
|
|
82
|
+
|
|
83
|
+
evt-cli ships generic example data and bundled skills. A skill-aware agent can
|
|
84
|
+
turn an empty project data directory into runnable project data:
|
|
85
|
+
|
|
86
|
+
1. Use `evt-profile-generator` to create `data/profiles/<env>.json` from source
|
|
87
|
+
config, docs, endpoint schemas, and user-provided test credentials.
|
|
88
|
+
2. Use `evt-api-scanner` to discover API source paths, write
|
|
89
|
+
`data/scanner.json`, and generate `data/apis/*.yaml`.
|
|
90
|
+
3. Use `evt-flow-generator` to create `data/flows/login.yaml`, smoke flows, and
|
|
91
|
+
feature flows from the generated endpoints and product workflow.
|
|
92
|
+
4. Run `evt validate --config-root ./cli`.
|
|
93
|
+
5. Run flows with `--dry-run` first, then against a safe test environment.
|
|
94
|
+
|
|
95
|
+
Profile and flow generation are AI-first tasks because base URLs, headers,
|
|
96
|
+
login state, test accounts, token response paths, and feature sequences are
|
|
97
|
+
project-specific. evt-cli keeps code fallback only for endpoint scanning.
|
|
98
|
+
|
|
80
99
|
## Local Check And Package
|
|
81
100
|
|
|
82
101
|
```bash
|
|
83
102
|
npm run ci:local
|
|
84
103
|
```
|
|
85
104
|
|
|
105
|
+
The npm package includes source code, scripts, tests, data examples, and skills
|
|
106
|
+
so users can run local checks and build the standalone local binary package.
|
|
107
|
+
|
|
86
108
|
This runs:
|
|
87
109
|
|
|
88
110
|
- `npm test`
|
|
@@ -100,6 +122,7 @@ The local package directory contains only:
|
|
|
100
122
|
|
|
101
123
|
- `evt`
|
|
102
124
|
- `data/`
|
|
125
|
+
- `skills/`
|
|
103
126
|
- `README.md`
|
|
104
127
|
- `README.zh-CN.md`
|
|
105
128
|
|
|
@@ -146,7 +169,47 @@ Each endpoint should include:
|
|
|
146
169
|
- `response`
|
|
147
170
|
- `dangerous: true` when the endpoint is destructive or sensitive
|
|
148
171
|
|
|
149
|
-
## Scan And Coverage
|
|
172
|
+
## Skills, Scan, Sync, And Coverage
|
|
173
|
+
|
|
174
|
+
evt-cli includes these bundled skills:
|
|
175
|
+
|
|
176
|
+
- `skills/evt-profile-generator/SKILL.md`
|
|
177
|
+
- `skills/evt-api-scanner/SKILL.md`
|
|
178
|
+
- `skills/evt-flow-generator/SKILL.md`
|
|
179
|
+
|
|
180
|
+
Agents can use these skills to create profile JSON, discover source
|
|
181
|
+
directories, write scanner config, generate YAML endpoint definitions, create
|
|
182
|
+
flow YAML, and audit coverage.
|
|
183
|
+
|
|
184
|
+
Endpoint definitions are written to YAML under `data/apis/*.yaml`. The scanner
|
|
185
|
+
may use JSON internally, but JSON is not the endpoint definition format.
|
|
186
|
+
|
|
187
|
+
Discover API source paths and write `data/scanner.json`:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
evt api discover --config-root ./cli
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Generate or update YAML endpoint definitions:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
evt api sync --config-root ./cli
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Audit YAML quality after sync:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
evt api audit --config-root ./cli --strict
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Check YAML coverage:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
evt api coverage --config-root ./cli
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The built-in regex scanner is still available as a fallback. It is less complete
|
|
212
|
+
than the skill-guided workflow, but it works without an agent.
|
|
150
213
|
|
|
151
214
|
Scan source code for candidate endpoints:
|
|
152
215
|
|
|
@@ -166,7 +229,8 @@ Generate missing YAML skeletons:
|
|
|
166
229
|
npm run sync:api -- --config-root /path/to/project/cli
|
|
167
230
|
```
|
|
168
231
|
|
|
169
|
-
The scanner supports `kotlin`, `swift`, `js`, and `dart`. It also supports
|
|
232
|
+
The scanner supports `kotlin`, `swift`, `js`, and `dart`. It also supports the
|
|
233
|
+
bundled skill scanner and external command scanners:
|
|
170
234
|
|
|
171
235
|
```json
|
|
172
236
|
{
|
|
@@ -179,15 +243,16 @@ The scanner supports `kotlin`, `swift`, `js`, and `dart`. It also supports exter
|
|
|
179
243
|
},
|
|
180
244
|
{
|
|
181
245
|
"language": "skill",
|
|
182
|
-
"name": "
|
|
183
|
-
"
|
|
184
|
-
"args": ["tools/scan-endpoints.js"]
|
|
246
|
+
"name": "evt-api-scanner",
|
|
247
|
+
"skill": "evt-api-scanner"
|
|
185
248
|
}
|
|
186
249
|
]
|
|
187
250
|
}
|
|
188
251
|
```
|
|
189
252
|
|
|
190
|
-
An external scanner can output a JSON array or `{ "endpoints": [] }
|
|
253
|
+
An external scanner can output a JSON array or `{ "endpoints": [] }` as an
|
|
254
|
+
internal scan result. `evt api sync` converts that scan result into YAML. Each
|
|
255
|
+
intermediate endpoint should include at least:
|
|
191
256
|
|
|
192
257
|
```json
|
|
193
258
|
{
|
|
@@ -206,6 +271,10 @@ This JSON is used only for scanning, coverage, and sync. Runtime execution still
|
|
|
206
271
|
```bash
|
|
207
272
|
evt profile list
|
|
208
273
|
evt api list
|
|
274
|
+
evt api discover --config-root ./cli
|
|
275
|
+
evt api sync --config-root ./cli
|
|
276
|
+
evt api audit --config-root ./cli --strict
|
|
277
|
+
evt api coverage --config-root ./cli
|
|
209
278
|
evt api call todo.list --dry-run
|
|
210
279
|
evt flow run login --profile local
|
|
211
280
|
evt cache show
|
package/README.zh-CN.md
CHANGED
|
@@ -9,7 +9,8 @@ evt-cli 是一个通用 HTTP CLI,用 YAML 定义接口、用 YAML 定义 flow
|
|
|
9
9
|
- 运行时端点只来自 `apis/*.yaml`。
|
|
10
10
|
- flow 只来自 `flows/*.yaml`。
|
|
11
11
|
- 环境、base URL、headers、测试 fixtures 只来自 `profiles/*.json`。
|
|
12
|
-
-
|
|
12
|
+
- endpoint 定义持久化格式始终是 YAML。scanner JSON 只作为内部机器中间结果。
|
|
13
|
+
- 内置 skills 优先用于项目 data 初始化。现有正则 scanner 只保留给没有 agent 或 skill workflow 的用户做 endpoint 扫描兜底。
|
|
13
14
|
- 默认数据目录是当前 CLI 包内目录;也可以通过 `--config-root` 或 `EVT_CLI_ROOT` 指向项目自己的数据目录。
|
|
14
15
|
|
|
15
16
|
## 快速开始
|
|
@@ -77,12 +78,26 @@ evt-cli 自带 `data/**/*.example.*`,用于开箱验证和复制参考。真
|
|
|
77
78
|
|
|
78
79
|
为了兼容已有项目,`--config-root` 下直接存在 `apis/`、`flows/`、`profiles/`、`scanner.config.json` 时也会被读取。
|
|
79
80
|
|
|
81
|
+
## 用 Skills 初始化项目 Data
|
|
82
|
+
|
|
83
|
+
evt-cli 自带通用 example data 和内置 skills。支持 skill 的 agent 可以把一个空的项目 data 目录生成成可运行的项目 data:
|
|
84
|
+
|
|
85
|
+
1. 使用 `evt-profile-generator` 根据源码配置、文档、endpoint schema 和用户提供的测试账号生成 `data/profiles/<env>.json`。
|
|
86
|
+
2. 使用 `evt-api-scanner` 发现 API 源码路径,写入 `data/scanner.json`,并生成 `data/apis/*.yaml`。
|
|
87
|
+
3. 使用 `evt-flow-generator` 根据生成的 endpoint 和产品流程生成 `data/flows/login.yaml`、smoke flow 和 feature flow。
|
|
88
|
+
4. 执行 `evt validate --config-root ./cli`。
|
|
89
|
+
5. 先用 `--dry-run` 跑 flow,再在安全测试环境里跑真实请求。
|
|
90
|
+
|
|
91
|
+
profile 和 flow 生成是 AI-first 任务,因为 base URL、headers、登录态、测试账号、token 返回路径和 feature 调用顺序都依赖具体项目语义。evt-cli 只保留 endpoint 扫描的代码兜底。
|
|
92
|
+
|
|
80
93
|
## 本地校验和打包
|
|
81
94
|
|
|
82
95
|
```bash
|
|
83
96
|
npm run ci:local
|
|
84
97
|
```
|
|
85
98
|
|
|
99
|
+
npm 包会包含源码、脚本、测试、示例数据和 skills,用户可以自行运行本地校验并构建独立本地二进制包。
|
|
100
|
+
|
|
86
101
|
执行内容:
|
|
87
102
|
|
|
88
103
|
- `npm test`
|
|
@@ -100,6 +115,7 @@ npm run ci:local
|
|
|
100
115
|
|
|
101
116
|
- `evt`
|
|
102
117
|
- `data/`
|
|
118
|
+
- `skills/`
|
|
103
119
|
- `README.md`
|
|
104
120
|
- `README.zh-CN.md`
|
|
105
121
|
|
|
@@ -146,7 +162,46 @@ endpoints:
|
|
|
146
162
|
- `response`
|
|
147
163
|
- 必要时标记 `dangerous: true`
|
|
148
164
|
|
|
149
|
-
##
|
|
165
|
+
## Skills、扫描、同步和覆盖率
|
|
166
|
+
|
|
167
|
+
evt-cli 内置这些 skills:
|
|
168
|
+
|
|
169
|
+
- `skills/evt-profile-generator/SKILL.md`
|
|
170
|
+
- `skills/evt-api-scanner/SKILL.md`
|
|
171
|
+
- `skills/evt-flow-generator/SKILL.md`
|
|
172
|
+
|
|
173
|
+
agent 可以使用这些 skills 生成 profile JSON、发现源码目录、写入 scanner 配置、
|
|
174
|
+
生成 YAML endpoint 定义、生成 flow YAML,并做覆盖率审计。
|
|
175
|
+
|
|
176
|
+
endpoint 定义会写到 `data/apis/*.yaml`。scanner 可以在内部使用 JSON,但 JSON
|
|
177
|
+
不是 endpoint 的最终定义格式。
|
|
178
|
+
|
|
179
|
+
发现 API 源码路径并写入 `data/scanner.json`:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
evt api discover --config-root ./cli
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
生成或更新 YAML endpoint 定义:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
evt api sync --config-root ./cli
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
检查 YAML 质量门禁:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
evt api audit --config-root ./cli --strict
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
检查 YAML 覆盖率:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
evt api coverage --config-root ./cli
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
内置正则 scanner 仍然保留为兜底方案。它不如 skill workflow 完整,但不依赖
|
|
204
|
+
agent,也能让没有 agent 的用户勉强使用。
|
|
150
205
|
|
|
151
206
|
扫描源码候选 endpoint:
|
|
152
207
|
|
|
@@ -166,7 +221,7 @@ npm run coverage:api -- --config-root /path/to/project/cli
|
|
|
166
221
|
npm run sync:api -- --config-root /path/to/project/cli
|
|
167
222
|
```
|
|
168
223
|
|
|
169
|
-
扫描器支持 `kotlin`、`swift`、`js`、`dart
|
|
224
|
+
扫描器支持 `kotlin`、`swift`、`js`、`dart`,也支持内置 skill scanner 和外部命令 scanner:
|
|
170
225
|
|
|
171
226
|
```json
|
|
172
227
|
{
|
|
@@ -179,15 +234,15 @@ npm run sync:api -- --config-root /path/to/project/cli
|
|
|
179
234
|
},
|
|
180
235
|
{
|
|
181
236
|
"language": "skill",
|
|
182
|
-
"name": "
|
|
183
|
-
"
|
|
184
|
-
"args": ["tools/scan-endpoints.js"]
|
|
237
|
+
"name": "evt-api-scanner",
|
|
238
|
+
"skill": "evt-api-scanner"
|
|
185
239
|
}
|
|
186
240
|
]
|
|
187
241
|
}
|
|
188
242
|
```
|
|
189
243
|
|
|
190
|
-
外部 scanner
|
|
244
|
+
外部 scanner 可以输出 JSON 数组,或 `{ "endpoints": [] }` 作为内部扫描结果。
|
|
245
|
+
`evt api sync` 会把这个扫描结果转换成 YAML。每个中间 endpoint 至少包含:
|
|
191
246
|
|
|
192
247
|
```json
|
|
193
248
|
{
|
|
@@ -206,6 +261,10 @@ npm run sync:api -- --config-root /path/to/project/cli
|
|
|
206
261
|
```bash
|
|
207
262
|
evt profile list
|
|
208
263
|
evt api list
|
|
264
|
+
evt api discover --config-root ./cli
|
|
265
|
+
evt api sync --config-root ./cli
|
|
266
|
+
evt api audit --config-root ./cli --strict
|
|
267
|
+
evt api coverage --config-root ./cli
|
|
209
268
|
evt api call todo.list --dry-run
|
|
210
269
|
evt flow run login --profile local
|
|
211
270
|
evt cache show
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icyouo/evt-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Run YAML-defined HTTP APIs and interactive workflows from your terminal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -17,17 +17,21 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"bin/",
|
|
19
19
|
"src/",
|
|
20
|
+
"scripts/",
|
|
21
|
+
"test/",
|
|
20
22
|
"data/",
|
|
23
|
+
"skills/",
|
|
21
24
|
"README.md",
|
|
22
25
|
"README.zh-CN.md"
|
|
23
26
|
],
|
|
24
27
|
"scripts": {
|
|
25
28
|
"ci:local": "node scripts/local-ci.js",
|
|
26
29
|
"test": "node --test",
|
|
27
|
-
"check": "node --check bin/evt.js && node --check src/index.js && node --check src/api/liveTester.js && node --check scripts/sync-api-coverage.js && node --check scripts/check-api-coverage.js && node --check scripts/local-ci.js && node --check scripts/build-package.js",
|
|
30
|
+
"check": "node --check bin/evt.js && node --check src/index.js && node --check src/api/liveTester.js && node --check scripts/sync-api-coverage.js && node --check scripts/check-api-coverage.js && node --check scripts/check-api-audit.js && node --check scripts/local-ci.js && node --check scripts/build-package.js && node --check skills/evt-api-scanner/scripts/discover.js && node --check skills/evt-api-scanner/scripts/scan.js",
|
|
28
31
|
"package:local": "node scripts/build-package.js",
|
|
29
32
|
"sync:api": "node scripts/sync-api-coverage.js",
|
|
30
|
-
"coverage:api": "node scripts/check-api-coverage.js"
|
|
33
|
+
"coverage:api": "node scripts/check-api-coverage.js",
|
|
34
|
+
"audit:api": "node scripts/check-api-audit.js"
|
|
31
35
|
},
|
|
32
36
|
"engines": {
|
|
33
37
|
"node": ">=20"
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { spawnSync } = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
const cliRoot = path.resolve(__dirname, "..");
|
|
8
|
+
const packageJson = require(path.join(cliRoot, "package.json"));
|
|
9
|
+
const distDir = path.join(cliRoot, "dist");
|
|
10
|
+
const packageName = "evt-cli";
|
|
11
|
+
const packageDir = path.join(distDir, packageName);
|
|
12
|
+
const entryId = "bin/evt.js";
|
|
13
|
+
|
|
14
|
+
function toPosix(file) {
|
|
15
|
+
return file.split(path.sep).join("/");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function normalizeModuleId(file) {
|
|
19
|
+
return path.posix.normalize(toPosix(path.relative(cliRoot, file)));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function resolveLocalModule(fromId, request) {
|
|
23
|
+
const base = path.posix.dirname(fromId);
|
|
24
|
+
const target = path.posix.normalize(path.posix.join(base, request));
|
|
25
|
+
const candidates = [
|
|
26
|
+
target,
|
|
27
|
+
`${target}.js`,
|
|
28
|
+
path.posix.join(target, "index.js")
|
|
29
|
+
];
|
|
30
|
+
for (const candidate of candidates) {
|
|
31
|
+
const absolute = path.join(cliRoot, ...candidate.split("/"));
|
|
32
|
+
if (fs.existsSync(absolute) && fs.statSync(absolute).isFile()) {
|
|
33
|
+
return normalizeModuleId(absolute);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Unable to resolve ${request} from ${fromId}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function findLocalRequires(source) {
|
|
40
|
+
const requires = [];
|
|
41
|
+
const pattern = /require\(\s*["']([^"']+)["']\s*\)/g;
|
|
42
|
+
let match;
|
|
43
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
44
|
+
if (match[1].startsWith(".")) {
|
|
45
|
+
requires.push(match[1]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return requires;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function collectModules(entry) {
|
|
52
|
+
const modules = new Map();
|
|
53
|
+
const queue = [entry];
|
|
54
|
+
|
|
55
|
+
while (queue.length > 0) {
|
|
56
|
+
const id = queue.shift();
|
|
57
|
+
if (modules.has(id)) continue;
|
|
58
|
+
|
|
59
|
+
const absolute = path.join(cliRoot, ...id.split("/"));
|
|
60
|
+
let source = fs.readFileSync(absolute, "utf8");
|
|
61
|
+
if (source.startsWith("#!")) {
|
|
62
|
+
source = source.replace(/^#!.*\n/, "");
|
|
63
|
+
}
|
|
64
|
+
modules.set(id, source);
|
|
65
|
+
|
|
66
|
+
for (const request of findLocalRequires(source)) {
|
|
67
|
+
const resolved = resolveLocalModule(id, request);
|
|
68
|
+
if (!modules.has(resolved)) {
|
|
69
|
+
queue.push(resolved);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return modules;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function renderExecutable(modules) {
|
|
78
|
+
const moduleEntries = Array.from(modules.entries())
|
|
79
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
80
|
+
.map(([id, source]) => `modules[${JSON.stringify(id)}] = function(require, module, exports, __filename, __dirname) {\n${source}\n};`)
|
|
81
|
+
.join("\n\n");
|
|
82
|
+
|
|
83
|
+
return `#!/usr/bin/env node
|
|
84
|
+
const __nodeRequire = require;
|
|
85
|
+
const path = __nodeRequire("node:path");
|
|
86
|
+
const runtimeRoot = path.dirname(process.argv[1] ? path.resolve(process.argv[1]) : __filename);
|
|
87
|
+
const modules = Object.create(null);
|
|
88
|
+
const moduleCache = Object.create(null);
|
|
89
|
+
|
|
90
|
+
${moduleEntries}
|
|
91
|
+
|
|
92
|
+
function resolveModule(fromId, request) {
|
|
93
|
+
if (!request.startsWith(".")) return request;
|
|
94
|
+
const base = path.posix.dirname(fromId);
|
|
95
|
+
const target = path.posix.normalize(path.posix.join(base, request));
|
|
96
|
+
const candidates = [target, target + ".js", path.posix.join(target, "index.js")];
|
|
97
|
+
for (const candidate of candidates) {
|
|
98
|
+
if (Object.prototype.hasOwnProperty.call(modules, candidate)) return candidate;
|
|
99
|
+
}
|
|
100
|
+
throw new Error("Unable to resolve " + request + " from " + fromId);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function loadModule(id) {
|
|
104
|
+
if (!Object.prototype.hasOwnProperty.call(modules, id)) {
|
|
105
|
+
return __nodeRequire(id);
|
|
106
|
+
}
|
|
107
|
+
if (moduleCache[id]) return moduleCache[id].exports;
|
|
108
|
+
const filename = path.join(runtimeRoot, ...id.split("/"));
|
|
109
|
+
const dirname = path.dirname(filename);
|
|
110
|
+
const module = { exports: {} };
|
|
111
|
+
moduleCache[id] = module;
|
|
112
|
+
const localRequire = (request) => loadModule(resolveModule(id, request));
|
|
113
|
+
modules[id](localRequire, module, module.exports, filename, dirname);
|
|
114
|
+
return module.exports;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
loadModule(${JSON.stringify(entryId)});
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function copyDir(sourceDir, targetDir) {
|
|
122
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
123
|
+
for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
124
|
+
if (entry.name === ".DS_Store") continue;
|
|
125
|
+
const source = path.join(sourceDir, entry.name);
|
|
126
|
+
const target = path.join(targetDir, entry.name);
|
|
127
|
+
if (entry.isDirectory()) {
|
|
128
|
+
copyDir(source, target);
|
|
129
|
+
} else if (entry.isFile()) {
|
|
130
|
+
fs.copyFileSync(source, target);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function run(command, args) {
|
|
136
|
+
const result = spawnSync(command, args, {
|
|
137
|
+
cwd: distDir,
|
|
138
|
+
stdio: "inherit",
|
|
139
|
+
shell: false
|
|
140
|
+
});
|
|
141
|
+
if (result.status !== 0) {
|
|
142
|
+
process.exit(result.status || 1);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function cleanDist() {
|
|
147
|
+
fs.rmSync(distDir, { recursive: true, force: true });
|
|
148
|
+
fs.mkdirSync(packageDir, { recursive: true });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function main() {
|
|
152
|
+
cleanDist();
|
|
153
|
+
|
|
154
|
+
const executablePath = path.join(packageDir, "evt");
|
|
155
|
+
fs.writeFileSync(executablePath, renderExecutable(collectModules(entryId)));
|
|
156
|
+
fs.chmodSync(executablePath, 0o755);
|
|
157
|
+
|
|
158
|
+
copyDir(path.join(cliRoot, "data"), path.join(packageDir, "data"));
|
|
159
|
+
copyDir(path.join(cliRoot, "skills"), path.join(packageDir, "skills"));
|
|
160
|
+
fs.copyFileSync(path.join(cliRoot, "README.md"), path.join(packageDir, "README.md"));
|
|
161
|
+
fs.copyFileSync(path.join(cliRoot, "README.zh-CN.md"), path.join(packageDir, "README.zh-CN.md"));
|
|
162
|
+
|
|
163
|
+
const artifactName = `${packageName}-${packageJson.version}-${process.platform}-${process.arch}.tar.gz`;
|
|
164
|
+
run("tar", ["-czf", artifactName, packageName]);
|
|
165
|
+
|
|
166
|
+
console.log("\nLocal package artifacts:");
|
|
167
|
+
console.log(`- dist/${packageName}/`);
|
|
168
|
+
console.log(`- dist/${artifactName}`);
|
|
169
|
+
console.log("\nPackage contents are limited to evt, data examples, skills, README.md, and README.zh-CN.md.");
|
|
170
|
+
console.log("No npm publish or remote upload was performed.");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
main();
|