@hagicode/hagiscript 0.1.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 +215 -0
- package/README_cn.md +215 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +37 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/node-runtime-commands.d.ts +2 -0
- package/dist/commands/node-runtime-commands.js +88 -0
- package/dist/commands/node-runtime-commands.js.map +1 -0
- package/dist/commands/npm-sync-commands.d.ts +2 -0
- package/dist/commands/npm-sync-commands.js +92 -0
- package/dist/commands/npm-sync-commands.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/node-download.d.ts +13 -0
- package/dist/runtime/node-download.js +78 -0
- package/dist/runtime/node-download.js.map +1 -0
- package/dist/runtime/node-extract.d.ts +6 -0
- package/dist/runtime/node-extract.js +155 -0
- package/dist/runtime/node-extract.js.map +1 -0
- package/dist/runtime/node-installer.d.ts +18 -0
- package/dist/runtime/node-installer.js +46 -0
- package/dist/runtime/node-installer.js.map +1 -0
- package/dist/runtime/node-platform.d.ts +14 -0
- package/dist/runtime/node-platform.js +41 -0
- package/dist/runtime/node-platform.js.map +1 -0
- package/dist/runtime/node-release.d.ts +28 -0
- package/dist/runtime/node-release.js +146 -0
- package/dist/runtime/node-release.js.map +1 -0
- package/dist/runtime/node-verify.d.ts +20 -0
- package/dist/runtime/node-verify.js +66 -0
- package/dist/runtime/node-verify.js.map +1 -0
- package/dist/runtime/npm-global.d.ts +20 -0
- package/dist/runtime/npm-global.js +53 -0
- package/dist/runtime/npm-global.js.map +1 -0
- package/dist/runtime/npm-sync.d.ts +94 -0
- package/dist/runtime/npm-sync.js +290 -0
- package/dist/runtime/npm-sync.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +9 -0
- package/dist/version.js.map +1 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Hagiscript
|
|
2
|
+
|
|
3
|
+
`@hagicode/hagiscript` is the scoped npm package foundation for future Hagiscript language tooling. This initial package intentionally keeps runtime behavior small: it exposes version metadata, a baseline runtime-info API, and an executable CLI placeholder that can be built, tested, packed, and published safely.
|
|
4
|
+
|
|
5
|
+
## Installation Assumptions
|
|
6
|
+
|
|
7
|
+
- Node.js 20 or newer is required.
|
|
8
|
+
- npm is the package manager for this standalone repository.
|
|
9
|
+
- The npm package name is `@hagicode/hagiscript`.
|
|
10
|
+
- GitHub Actions publishing uses `npm publish --provenance`. Local manual publishing should use plain `npm publish` unless you are inside a supported trusted publishing environment.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
Install the package from npm:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @hagicode/hagiscript
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The installed CLI command remains `hagiscript`.
|
|
21
|
+
|
|
22
|
+
Run the CLI locally during development:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run dev -- --help
|
|
26
|
+
npm run dev -- info
|
|
27
|
+
npm run dev -- install-node --target .tmp/node-runtime
|
|
28
|
+
npm run dev -- check-node --target .tmp/node-runtime
|
|
29
|
+
npm run dev -- npm-sync --runtime .tmp/node-runtime --manifest manifest.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
After building, run the compiled CLI:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm run build
|
|
36
|
+
node dist/cli.js --version
|
|
37
|
+
node dist/cli.js info
|
|
38
|
+
node dist/cli.js install-node --target .tmp/node-runtime
|
|
39
|
+
node dist/cli.js check-node --target .tmp/node-runtime
|
|
40
|
+
node dist/cli.js npm-sync --runtime .tmp/node-runtime --manifest manifest.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Managed Node.js Runtime Commands
|
|
44
|
+
|
|
45
|
+
`install-node` downloads an official Node.js archive from `https://nodejs.org/dist`, extracts it into the target directory, and verifies both `node` and `npm` before reporting success.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
hagiscript install-node --target /opt/hagiscript/node
|
|
49
|
+
hagiscript install-node --target /opt/hagiscript/node20 --version 20
|
|
50
|
+
hagiscript install-node --target /opt/hagiscript/lts --version lts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
When `--version` is omitted, Hagiscript installs the latest available Node.js 22 release. Supported selectors are `lts`, `latest`, `current`, a major version such as `22`, an exact version such as `22.12.0`, or an exact version with a `v` prefix such as `v22.12.0`.
|
|
54
|
+
|
|
55
|
+
The target path must be missing or empty. Hagiscript refuses to install into a non-empty target directory and does not delete existing user files. During installation, temporary staging files are created beside the target directory and cleaned up after success or failure.
|
|
56
|
+
|
|
57
|
+
Example success output:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
Installing Node.js 22 into /opt/hagiscript/node
|
|
61
|
+
Download progress: 100%
|
|
62
|
+
Node.js runtime installed successfully.
|
|
63
|
+
Target: /opt/hagiscript/node
|
|
64
|
+
Node.js: v22.12.0
|
|
65
|
+
npm: 10.9.0
|
|
66
|
+
node: /opt/hagiscript/node/bin/node
|
|
67
|
+
npm: /opt/hagiscript/node/bin/npm
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`check-node` validates an existing runtime directory and exits with code `0` only when both `node --version` and `npm --version` succeed.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
hagiscript check-node --target /opt/hagiscript/node
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Example valid output:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
Node.js runtime is valid.
|
|
80
|
+
Target: /opt/hagiscript/node
|
|
81
|
+
Node.js: v22.12.0
|
|
82
|
+
npm: 10.9.0
|
|
83
|
+
node: /opt/hagiscript/node/bin/node
|
|
84
|
+
npm: /opt/hagiscript/node/bin/npm
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Example invalid output exits non-zero and includes the failure reason:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
Node.js runtime is invalid.
|
|
91
|
+
Target: /opt/hagiscript/node
|
|
92
|
+
Reason: missing executable
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### npm Global Package Synchronization
|
|
96
|
+
|
|
97
|
+
`npm-sync` aligns npm global packages inside an explicit Node.js runtime with a JSON manifest. It always uses the `npm` executable resolved from `--runtime`; it does not use or mutate npm from the ambient shell `PATH`.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
hagiscript npm-sync --runtime /opt/hagiscript/node --manifest ./manifest.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Manifest schema:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"packages": {
|
|
108
|
+
"<npm-package-name>": {
|
|
109
|
+
"version": "<semver range>",
|
|
110
|
+
"target": "<optional npm install selector>"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The required `version` field accepts package.json-style semver ranges such as `^1.2.0`, `>=1.0.0 <2.0.0`, or `1.0.0 || 2.0.0`. The optional `target` field controls the selector used for `npm install -g`; when omitted, Hagiscript installs `<package>@<version>`.
|
|
117
|
+
|
|
118
|
+
Example manifest for openspec and skills tooling:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"packages": {
|
|
123
|
+
"@openspec/cli": {
|
|
124
|
+
"version": "^1.0.0"
|
|
125
|
+
},
|
|
126
|
+
"@hagicode/skills": {
|
|
127
|
+
"version": ">=0.5.0 <1.0.0",
|
|
128
|
+
"target": "0.5.4"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
During execution, Hagiscript validates the manifest and runtime before any npm install command runs, lists global packages with `/opt/hagiscript/node/bin/npm list -g --depth=0 --json`, plans no-op, install, upgrade, downgrade, or sync actions, and then runs `npm install -g <package>@<selector>` only for packages that need changes.
|
|
135
|
+
|
|
136
|
+
Example output:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
Manifest validated: ./manifest.json (2 packages)
|
|
140
|
+
Runtime validated: /opt/hagiscript/node
|
|
141
|
+
node: /opt/hagiscript/node/bin/node (v22.12.0)
|
|
142
|
+
npm: /opt/hagiscript/node/bin/npm (10.9.0)
|
|
143
|
+
Detected global packages: 4
|
|
144
|
+
Plan: @openspec/cli noop installed=1.0.2 required=^1.0.0 selector=@openspec/cli@^1.0.0
|
|
145
|
+
Skip: @openspec/cli already satisfies range
|
|
146
|
+
Plan: @hagicode/skills upgrade installed=0.4.0 required=>=0.5.0 <1.0.0 selector=@hagicode/skills@0.5.4
|
|
147
|
+
Install: @hagicode/skills using @hagicode/skills@0.5.4
|
|
148
|
+
Synced: @hagicode/skills (upgrade)
|
|
149
|
+
npm-sync complete.
|
|
150
|
+
Runtime: /opt/hagiscript/node
|
|
151
|
+
Manifest: ./manifest.json
|
|
152
|
+
Packages: 2
|
|
153
|
+
No-op: 1
|
|
154
|
+
Changed: 1
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Use the library API from ESM consumers:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { createRuntimeInfo, getPackageMetadata } from "@hagicode/hagiscript";
|
|
161
|
+
|
|
162
|
+
console.log(getPackageMetadata());
|
|
163
|
+
console.log(createRuntimeInfo());
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Development Commands
|
|
167
|
+
|
|
168
|
+
Run all commands from `repos/hagiscript/`:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npm install
|
|
172
|
+
npm run lint
|
|
173
|
+
npm run format:check
|
|
174
|
+
npm test
|
|
175
|
+
npm run build
|
|
176
|
+
npm run pack:check
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Additional commands:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm run clean
|
|
183
|
+
npm run format
|
|
184
|
+
npm run test:watch
|
|
185
|
+
npm run publish:prepare-dev-version
|
|
186
|
+
npm run publish:verify-release -- v0.1.0
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Build Outputs
|
|
190
|
+
|
|
191
|
+
`npm run build` compiles TypeScript with strict NodeNext settings into `dist/`. Expected entry points include:
|
|
192
|
+
|
|
193
|
+
- `dist/index.js`
|
|
194
|
+
- `dist/index.d.ts`
|
|
195
|
+
- `dist/index.js.map`
|
|
196
|
+
- `dist/cli.js`
|
|
197
|
+
- `dist/cli.d.ts`
|
|
198
|
+
- `dist/cli.js.map`
|
|
199
|
+
|
|
200
|
+
The package `exports` field points consumers to `dist/index.js` and `dist/index.d.ts`. The published package name is `@hagicode/hagiscript`, and the `bin.hagiscript` entry points to `dist/cli.js`.
|
|
201
|
+
|
|
202
|
+
## Package Verification
|
|
203
|
+
|
|
204
|
+
`npm run pack:check` runs a dry-run package inspection and fails if required runtime files are missing or source-only files are accidentally included. The published package should contain generated `dist` files and documentation, not raw tests, scripts, coverage, or temporary files.
|
|
205
|
+
|
|
206
|
+
## Release Automation
|
|
207
|
+
|
|
208
|
+
GitHub Actions provide three automation paths:
|
|
209
|
+
|
|
210
|
+
- `ci.yml` installs dependencies with `npm ci`, then runs lint, format check, tests, build, and package verification.
|
|
211
|
+
- `npm-publish.yml` publishes a unique prerelease version to the `dev` dist-tag from `main`.
|
|
212
|
+
- `npm-publish.yml` also publishes stable GitHub releases tagged as `vX.Y.Z` to the `latest` dist-tag after validating the tag against `package.json`.
|
|
213
|
+
- `release-drafter.yml` keeps a categorized release draft using `.github/release-drafter.yml`.
|
|
214
|
+
|
|
215
|
+
Before the first publish, make sure the npm organization `hagicode` exists and grant publish access for `@hagicode/hagiscript`. For GitHub Actions releases, configure npm trusted publishing. For local manual releases, run plain `npm publish`.
|
package/README_cn.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Hagiscript
|
|
2
|
+
|
|
3
|
+
`@hagicode/hagiscript` 是 Hagiscript 语言工具链的作用域 npm 包基础工程。本次初始化只提供最小运行能力:版本元数据、基础运行时信息 API,以及一个可构建、可测试、可打包、可发布的 CLI 占位入口。
|
|
4
|
+
|
|
5
|
+
## 安装假设
|
|
6
|
+
|
|
7
|
+
- 需要 Node.js 20 或更高版本。
|
|
8
|
+
- 该独立仓库使用 npm 作为包管理器。
|
|
9
|
+
- npm 包名为 `@hagicode/hagiscript`。
|
|
10
|
+
- GitHub Actions 发布使用 `npm publish --provenance`。本地手动发布时,应直接使用普通 `npm publish`,除非当前环境本身就是受支持的 trusted publishing 环境。
|
|
11
|
+
|
|
12
|
+
## 使用方式
|
|
13
|
+
|
|
14
|
+
先从 npm 安装该包:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @hagicode/hagiscript
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
安装后的 CLI 命令仍然是 `hagiscript`。
|
|
21
|
+
|
|
22
|
+
开发时运行 CLI:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run dev -- --help
|
|
26
|
+
npm run dev -- info
|
|
27
|
+
npm run dev -- install-node --target .tmp/node-runtime
|
|
28
|
+
npm run dev -- check-node --target .tmp/node-runtime
|
|
29
|
+
npm run dev -- npm-sync --runtime .tmp/node-runtime --manifest manifest.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
构建后运行编译产物:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm run build
|
|
36
|
+
node dist/cli.js --version
|
|
37
|
+
node dist/cli.js info
|
|
38
|
+
node dist/cli.js install-node --target .tmp/node-runtime
|
|
39
|
+
node dist/cli.js check-node --target .tmp/node-runtime
|
|
40
|
+
node dist/cli.js npm-sync --runtime .tmp/node-runtime --manifest manifest.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 托管 Node.js 运行时命令
|
|
44
|
+
|
|
45
|
+
`install-node` 会从 `https://nodejs.org/dist` 下载官方 Node.js 归档包,解压到目标目录,并在成功前验证 `node` 与 `npm` 都可执行。
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
hagiscript install-node --target /opt/hagiscript/node
|
|
49
|
+
hagiscript install-node --target /opt/hagiscript/node20 --version 20
|
|
50
|
+
hagiscript install-node --target /opt/hagiscript/lts --version lts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
省略 `--version` 时,Hagiscript 默认安装最新可用的 Node.js 22 版本。支持的选择器包括 `lts`、`latest`、`current`、类似 `22` 的主版本号、类似 `22.12.0` 的精确版本,以及类似 `v22.12.0` 的带 `v` 精确版本。
|
|
54
|
+
|
|
55
|
+
目标路径必须不存在或为空目录。Hagiscript 会拒绝安装到非空目标目录,也不会删除已有用户文件。安装期间,临时 staging 文件会创建在目标目录旁边,并在成功或失败后清理。
|
|
56
|
+
|
|
57
|
+
成功输出示例:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
Installing Node.js 22 into /opt/hagiscript/node
|
|
61
|
+
Download progress: 100%
|
|
62
|
+
Node.js runtime installed successfully.
|
|
63
|
+
Target: /opt/hagiscript/node
|
|
64
|
+
Node.js: v22.12.0
|
|
65
|
+
npm: 10.9.0
|
|
66
|
+
node: /opt/hagiscript/node/bin/node
|
|
67
|
+
npm: /opt/hagiscript/node/bin/npm
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`check-node` 会验证已有运行时目录;只有 `node --version` 和 `npm --version` 都成功时才以退出码 `0` 结束。
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
hagiscript check-node --target /opt/hagiscript/node
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
有效运行时输出示例:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
Node.js runtime is valid.
|
|
80
|
+
Target: /opt/hagiscript/node
|
|
81
|
+
Node.js: v22.12.0
|
|
82
|
+
npm: 10.9.0
|
|
83
|
+
node: /opt/hagiscript/node/bin/node
|
|
84
|
+
npm: /opt/hagiscript/node/bin/npm
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
无效运行时会以非零退出码结束,并输出失败原因:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
Node.js runtime is invalid.
|
|
91
|
+
Target: /opt/hagiscript/node
|
|
92
|
+
Reason: missing executable
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### npm 全局包同步
|
|
96
|
+
|
|
97
|
+
`npm-sync` 会根据 JSON manifest,把指定 Node.js 运行时中的 npm 全局包版本同步到约束范围内。它始终使用 `--runtime` 解析出的 `npm` 可执行文件,不会使用或修改当前 shell `PATH` 中的 npm。
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
hagiscript npm-sync --runtime /opt/hagiscript/node --manifest ./manifest.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Manifest 结构:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"packages": {
|
|
108
|
+
"<npm-package-name>": {
|
|
109
|
+
"version": "<semver range>",
|
|
110
|
+
"target": "<optional npm install selector>"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
必填的 `version` 字段使用 package.json 风格的 semver 范围,例如 `^1.2.0`、`>=1.0.0 <2.0.0` 或 `1.0.0 || 2.0.0`。可选的 `target` 字段用于指定实际执行 `npm install -g` 时使用的选择器;如果省略,Hagiscript 会安装 `<package>@<version>`。
|
|
117
|
+
|
|
118
|
+
openspec 和 skills 工具同步示例:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"packages": {
|
|
123
|
+
"@openspec/cli": {
|
|
124
|
+
"version": "^1.0.0"
|
|
125
|
+
},
|
|
126
|
+
"@hagicode/skills": {
|
|
127
|
+
"version": ">=0.5.0 <1.0.0",
|
|
128
|
+
"target": "0.5.4"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
执行时,Hagiscript 会先验证 manifest 和运行时,再执行任何 npm install 操作;它会用 `/opt/hagiscript/node/bin/npm list -g --depth=0 --json` 检测全局包,生成 no-op、install、upgrade、downgrade 或 sync 计划,然后只对需要变更的包执行 `npm install -g <package>@<selector>`。
|
|
135
|
+
|
|
136
|
+
输出示例:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
Manifest validated: ./manifest.json (2 packages)
|
|
140
|
+
Runtime validated: /opt/hagiscript/node
|
|
141
|
+
node: /opt/hagiscript/node/bin/node (v22.12.0)
|
|
142
|
+
npm: /opt/hagiscript/node/bin/npm (10.9.0)
|
|
143
|
+
Detected global packages: 4
|
|
144
|
+
Plan: @openspec/cli noop installed=1.0.2 required=^1.0.0 selector=@openspec/cli@^1.0.0
|
|
145
|
+
Skip: @openspec/cli already satisfies range
|
|
146
|
+
Plan: @hagicode/skills upgrade installed=0.4.0 required=>=0.5.0 <1.0.0 selector=@hagicode/skills@0.5.4
|
|
147
|
+
Install: @hagicode/skills using @hagicode/skills@0.5.4
|
|
148
|
+
Synced: @hagicode/skills (upgrade)
|
|
149
|
+
npm-sync complete.
|
|
150
|
+
Runtime: /opt/hagiscript/node
|
|
151
|
+
Manifest: ./manifest.json
|
|
152
|
+
Packages: 2
|
|
153
|
+
No-op: 1
|
|
154
|
+
Changed: 1
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
在 ESM 项目中使用库 API:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { createRuntimeInfo, getPackageMetadata } from "@hagicode/hagiscript";
|
|
161
|
+
|
|
162
|
+
console.log(getPackageMetadata());
|
|
163
|
+
console.log(createRuntimeInfo());
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 开发命令
|
|
167
|
+
|
|
168
|
+
所有命令都应在 `repos/hagiscript/` 下执行:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npm install
|
|
172
|
+
npm run lint
|
|
173
|
+
npm run format:check
|
|
174
|
+
npm test
|
|
175
|
+
npm run build
|
|
176
|
+
npm run pack:check
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
其他常用命令:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm run clean
|
|
183
|
+
npm run format
|
|
184
|
+
npm run test:watch
|
|
185
|
+
npm run publish:prepare-dev-version
|
|
186
|
+
npm run publish:verify-release -- v0.1.0
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 构建输出
|
|
190
|
+
|
|
191
|
+
`npm run build` 会使用严格的 NodeNext TypeScript 配置编译到 `dist/`。预期入口文件包括:
|
|
192
|
+
|
|
193
|
+
- `dist/index.js`
|
|
194
|
+
- `dist/index.d.ts`
|
|
195
|
+
- `dist/index.js.map`
|
|
196
|
+
- `dist/cli.js`
|
|
197
|
+
- `dist/cli.d.ts`
|
|
198
|
+
- `dist/cli.js.map`
|
|
199
|
+
|
|
200
|
+
`package.json` 的 `exports` 字段指向 `dist/index.js` 和 `dist/index.d.ts`。发布到 npm 后的包名是 `@hagicode/hagiscript`,`bin.hagiscript` 指向 `dist/cli.js`。
|
|
201
|
+
|
|
202
|
+
## 包内容校验
|
|
203
|
+
|
|
204
|
+
`npm run pack:check` 会执行 dry-run 打包检查。如果缺少必要运行文件,或错误包含源码测试、脚本、覆盖率、临时目录等只应存在于开发环境的文件,脚本会失败。
|
|
205
|
+
|
|
206
|
+
## 发布自动化
|
|
207
|
+
|
|
208
|
+
GitHub Actions 提供三类自动化流程:
|
|
209
|
+
|
|
210
|
+
- `ci.yml` 使用 `npm ci` 安装依赖,并执行 lint、格式检查、测试、构建和包内容校验。
|
|
211
|
+
- `npm-publish.yml` 在 `main` 分支发布唯一预发布版本到 `dev` dist-tag。
|
|
212
|
+
- `npm-publish.yml` 也会在非草稿、非 prerelease 的 GitHub Release 发布时,校验 `vX.Y.Z` 标签并发布到 `latest` dist-tag。
|
|
213
|
+
- `release-drafter.yml` 通过 `.github/release-drafter.yml` 维护分类清晰的发布草稿。
|
|
214
|
+
|
|
215
|
+
首次发布前,需要先确保 npm 组织 `hagicode` 已存在,并且 `@hagicode/hagiscript` 已授权当前发布主体。GitHub Actions 发布时再配置 trusted publishing;本地手动发布时直接执行普通 `npm publish` 即可。
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { createRuntimeInfo, packageVersion } from "./index.js";
|
|
4
|
+
import { registerNpmSyncCommand } from "./commands/npm-sync-commands.js";
|
|
5
|
+
import { registerNodeRuntimeCommands } from "./commands/node-runtime-commands.js";
|
|
6
|
+
export function createCli() {
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("hagiscript")
|
|
10
|
+
.description("Hagiscript language tooling CLI foundation.")
|
|
11
|
+
.version(packageVersion, "-v, --version", "print the hagiscript version");
|
|
12
|
+
program
|
|
13
|
+
.command("info")
|
|
14
|
+
.description("print package foundation metadata")
|
|
15
|
+
.action(() => {
|
|
16
|
+
const info = createRuntimeInfo();
|
|
17
|
+
process.stdout.write(`${JSON.stringify(info, null, 2)}\n`);
|
|
18
|
+
});
|
|
19
|
+
registerNodeRuntimeCommands(program);
|
|
20
|
+
registerNpmSyncCommand(program);
|
|
21
|
+
program.action(() => {
|
|
22
|
+
program.outputHelp();
|
|
23
|
+
});
|
|
24
|
+
return program;
|
|
25
|
+
}
|
|
26
|
+
export async function runCli(argv = process.argv) {
|
|
27
|
+
const program = createCli();
|
|
28
|
+
await program.parseAsync(argv);
|
|
29
|
+
}
|
|
30
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
31
|
+
runCli().catch((error) => {
|
|
32
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
+
process.stderr.write(`${message}\n`);
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAElF,MAAM,UAAU,SAAS;IACvB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,CAAC,6CAA6C,CAAC;SAC1D,OAAO,CAAC,cAAc,EAAE,eAAe,EAAE,8BAA8B,CAAC,CAAC;IAE5E,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,mCAAmC,CAAC;SAChD,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEL,2BAA2B,CAAC,OAAO,CAAC,CAAC;IACrC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEhC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE;QAClB,OAAO,CAAC,UAAU,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI;IAC9C,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAC5B,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACpD,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAChC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { InvalidArgumentError } from "commander";
|
|
2
|
+
import { installNodeRuntime } from "../runtime/node-installer.js";
|
|
3
|
+
import { validateVersionSelector } from "../runtime/node-release.js";
|
|
4
|
+
import { verifyNodeRuntime } from "../runtime/node-verify.js";
|
|
5
|
+
export function registerNodeRuntimeCommands(program) {
|
|
6
|
+
program
|
|
7
|
+
.command("install-node")
|
|
8
|
+
.description("install an official Node.js runtime into a target directory")
|
|
9
|
+
.requiredOption("--target <path>", "empty target directory for the managed runtime")
|
|
10
|
+
.option("--version <selector>", "Node.js selector: lts, latest, current, 22, 22.11.0, or v22.11.0", validateVersionOption)
|
|
11
|
+
.action(async (options, command) => {
|
|
12
|
+
const target = validateTargetOption(options.target);
|
|
13
|
+
const versionSelector = options.version;
|
|
14
|
+
try {
|
|
15
|
+
process.stdout.write(`Installing Node.js ${versionSelector ?? "22"} into ${target}\n`);
|
|
16
|
+
const result = await installNodeRuntime({
|
|
17
|
+
targetDirectory: target,
|
|
18
|
+
versionSelector,
|
|
19
|
+
onProgress: (progress) => {
|
|
20
|
+
if (progress.totalBytes && progress.totalBytes > 0) {
|
|
21
|
+
const percent = Math.floor((progress.receivedBytes / progress.totalBytes) * 100);
|
|
22
|
+
process.stdout.write(`Download progress: ${percent}%\r`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
process.stdout.write(`Downloaded ${progress.receivedBytes} bytes\r`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
process.stdout.write("\n");
|
|
30
|
+
process.stdout.write(`Node.js runtime installed successfully.\n`);
|
|
31
|
+
process.stdout.write(`Target: ${result.targetDirectory}\n`);
|
|
32
|
+
process.stdout.write(`Node.js: ${result.version}\n`);
|
|
33
|
+
process.stdout.write(`npm: ${result.npmVersion}\n`);
|
|
34
|
+
process.stdout.write(`node: ${result.nodePath}\n`);
|
|
35
|
+
process.stdout.write(`npm: ${result.npmPath}\n`);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
command.error(formatCommandError("install-node failed", error), {
|
|
39
|
+
exitCode: 1
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
program
|
|
44
|
+
.command("check-node")
|
|
45
|
+
.description("validate an existing HagicScript-managed Node.js runtime")
|
|
46
|
+
.requiredOption("--target <path>", "target runtime directory to validate")
|
|
47
|
+
.action(async (options, command) => {
|
|
48
|
+
const target = validateTargetOption(options.target);
|
|
49
|
+
const result = await verifyNodeRuntime(target);
|
|
50
|
+
if (!result.valid) {
|
|
51
|
+
process.stderr.write(`Node.js runtime is invalid.\n`);
|
|
52
|
+
process.stderr.write(`Target: ${result.targetDirectory}\n`);
|
|
53
|
+
process.stderr.write(`Reason: ${result.failureReason ?? "unknown failure"}\n`);
|
|
54
|
+
command.error("check-node failed", { exitCode: 1 });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
process.stdout.write(`Node.js runtime is valid.\n`);
|
|
58
|
+
process.stdout.write(`Target: ${result.targetDirectory}\n`);
|
|
59
|
+
process.stdout.write(`Node.js: ${result.nodeVersion}\n`);
|
|
60
|
+
process.stdout.write(`npm: ${result.npmVersion}\n`);
|
|
61
|
+
process.stdout.write(`node: ${result.nodePath}\n`);
|
|
62
|
+
process.stdout.write(`npm: ${result.npmPath}\n`);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function validateVersionOption(value) {
|
|
66
|
+
try {
|
|
67
|
+
validateVersionSelector(value);
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
throw new InvalidArgumentError(error instanceof Error ? error.message : String(error));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function validateTargetOption(value) {
|
|
75
|
+
const target = value?.trim();
|
|
76
|
+
if (!target) {
|
|
77
|
+
throw new InvalidArgumentError("--target must be a non-empty path.");
|
|
78
|
+
}
|
|
79
|
+
if (target.includes("\0")) {
|
|
80
|
+
throw new InvalidArgumentError("--target contains an invalid null byte.");
|
|
81
|
+
}
|
|
82
|
+
return target;
|
|
83
|
+
}
|
|
84
|
+
function formatCommandError(prefix, error) {
|
|
85
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
+
return `${prefix}: ${message}`;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=node-runtime-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-runtime-commands.js","sourceRoot":"","sources":["../../src/commands/node-runtime-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { InvalidArgumentError } from "commander";
|
|
2
|
+
import { NpmManifestValidationError, NpmSyncCommandError, syncNpmGlobals } from "../runtime/npm-sync.js";
|
|
3
|
+
export function registerNpmSyncCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("npm-sync")
|
|
6
|
+
.description("sync npm global packages in an explicit Node.js runtime")
|
|
7
|
+
.requiredOption("--runtime <path>", "target Node.js runtime directory")
|
|
8
|
+
.requiredOption("--manifest <path>", "npm-sync manifest JSON file")
|
|
9
|
+
.action(async (options, command) => {
|
|
10
|
+
const runtimePath = validatePathOption(options.runtime, "--runtime");
|
|
11
|
+
const manifestPath = validatePathOption(options.manifest, "--manifest");
|
|
12
|
+
try {
|
|
13
|
+
await syncNpmGlobals({
|
|
14
|
+
runtimePath,
|
|
15
|
+
manifestPath,
|
|
16
|
+
onLog: printNpmSyncLog
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
command.error(formatNpmSyncError(error), { exitCode: 1 });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function validatePathOption(value, optionName) {
|
|
25
|
+
const normalized = value?.trim();
|
|
26
|
+
if (!normalized) {
|
|
27
|
+
throw new InvalidArgumentError(`${optionName} must be a non-empty path.`);
|
|
28
|
+
}
|
|
29
|
+
if (normalized.includes("\0")) {
|
|
30
|
+
throw new InvalidArgumentError(`${optionName} contains an invalid null byte.`);
|
|
31
|
+
}
|
|
32
|
+
return normalized;
|
|
33
|
+
}
|
|
34
|
+
function printNpmSyncLog(event) {
|
|
35
|
+
switch (event.type) {
|
|
36
|
+
case "manifest-loaded":
|
|
37
|
+
process.stdout.write(`Manifest validated: ${event.manifestPath} (${event.packageCount} packages)\n`);
|
|
38
|
+
break;
|
|
39
|
+
case "runtime-valid":
|
|
40
|
+
process.stdout.write(`Runtime validated: ${event.runtime.targetDirectory}\n`);
|
|
41
|
+
process.stdout.write(`node: ${event.runtime.nodePath} (${event.runtime.nodeVersion})\n`);
|
|
42
|
+
process.stdout.write(`npm: ${event.runtime.npmPath} (${event.runtime.npmVersion})\n`);
|
|
43
|
+
break;
|
|
44
|
+
case "inventory":
|
|
45
|
+
process.stdout.write(`Detected global packages: ${Object.keys(event.packages).sort().length}\n`);
|
|
46
|
+
break;
|
|
47
|
+
case "planned-action":
|
|
48
|
+
process.stdout.write(`Plan: ${event.action.packageName} ${event.action.action} installed=${event.action.installedVersion ?? "missing"} required=${event.action.requiredRange} selector=${event.action.selectedInstallSelector}\n`);
|
|
49
|
+
break;
|
|
50
|
+
case "skip":
|
|
51
|
+
process.stdout.write(`Skip: ${event.action.packageName} already satisfies range\n`);
|
|
52
|
+
break;
|
|
53
|
+
case "install-start":
|
|
54
|
+
process.stdout.write(`Install: ${event.action.packageName} using ${event.action.selectedInstallSelector}\n`);
|
|
55
|
+
break;
|
|
56
|
+
case "install-complete":
|
|
57
|
+
process.stdout.write(`Synced: ${event.action.packageName} (${event.action.action})\n`);
|
|
58
|
+
break;
|
|
59
|
+
case "summary":
|
|
60
|
+
printSummary(event.summary);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function printSummary(summary) {
|
|
65
|
+
process.stdout.write(`npm-sync complete.\n`);
|
|
66
|
+
process.stdout.write(`Runtime: ${summary.runtime.targetDirectory}\n`);
|
|
67
|
+
process.stdout.write(`Manifest: ${summary.manifestPath}\n`);
|
|
68
|
+
process.stdout.write(`Packages: ${summary.packageCount}\n`);
|
|
69
|
+
process.stdout.write(`No-op: ${summary.noopCount}\n`);
|
|
70
|
+
process.stdout.write(`Changed: ${summary.changedCount}\n`);
|
|
71
|
+
}
|
|
72
|
+
function formatNpmSyncError(error) {
|
|
73
|
+
if (error instanceof NpmManifestValidationError) {
|
|
74
|
+
return error.message;
|
|
75
|
+
}
|
|
76
|
+
if (error instanceof NpmSyncCommandError) {
|
|
77
|
+
const lines = [error.message];
|
|
78
|
+
if (error.packageName) {
|
|
79
|
+
lines.push(`Package: ${error.packageName}`);
|
|
80
|
+
}
|
|
81
|
+
lines.push(`Command: ${error.command} ${error.args.join(" ")}`);
|
|
82
|
+
if (error.stderr.trim().length > 0) {
|
|
83
|
+
lines.push(`stderr: ${error.stderr.trim()}`);
|
|
84
|
+
}
|
|
85
|
+
if (error.stdout.trim().length > 0) {
|
|
86
|
+
lines.push(`stdout: ${error.stdout.trim()}`);
|
|
87
|
+
}
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
return error instanceof Error ? error.message : String(error);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=npm-sync-commands.js.map
|