dsh-code-server-app 0.1.37 → 0.1.38
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.en.md +64 -43
- package/README.md +64 -42
- package/lib/index.js +12 -6
- package/lib/vendor.js +21 -11
- package/package.json +4 -7
- package/scripts/vendor-repacks.mjs +269 -31
- package/vendor/VENDOR.json +1 -1
- package/scripts/vendor-code-server-pkg.mjs +0 -137
package/README.en.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
> - Microsoft **open-source** extensions (Python, TypeScript debugger, ESLint, …) are mirrored on Open VSX and install normally by search;
|
|
11
11
|
> - **If you need a proprietary Microsoft extension**: download the `.vsix` from the Marketplace page and install it manually with `code-server --install-extension <file>` (or drop it into `--extensions-dir`).
|
|
12
12
|
|
|
13
|
-
A static profile plugin (npm package with host + client bundle) that
|
|
13
|
+
A static profile plugin (npm package with host + client bundle) that ships [code-server](https://github.com/coder/code-server) as a **platform-specific sub-package dependency** (a pack-time artifact at `vendor/code-server` → `@jinsiyu/dshcs-code-server-<platform>-<arch>`, with no install scripts and no postinstall) and runs it outside the plugin directory. VS Code's inner dependencies and the prebuilt native modules are **all installed by the package manager together with the plugin** — no global npm install, no `bin` configuration, no profile config changes, no second install command.
|
|
14
14
|
|
|
15
15
|
## UI carrier (chosen by the DSH version, feature-detected at runtime)
|
|
16
16
|
|
|
@@ -59,51 +59,56 @@ cd C:\Users\User\Desktop\dsh-code-server-app
|
|
|
59
59
|
pnpm install # dev deps (esbuild + motion); allowBuilds is explicit → no postinstall runs
|
|
60
60
|
pnpm run build:client # src/factory.js → lib/client.js (not committed; must be built first)
|
|
61
61
|
pnpm run vendor:check # optional: show the bundled code-server version vs npm latest
|
|
62
|
-
pnpm run vendor:code-server # produce vendor/code-server (code-server + its own deps)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
pnpm
|
|
66
|
-
|
|
62
|
+
pnpm run vendor:code-server # ① produce vendor/code-server (code-server + its own deps)
|
|
63
|
+
pnpm run repack:code-server -- --target win32-arm64,win32-x64 --pack # ② platform sub-packages (incl. argon2)
|
|
64
|
+
node scripts/vendor-repacks.mjs --target win32-arm64,win32-x64 --pack # ③ build/repack the VS Code natives
|
|
65
|
+
pnpm run publish:repacks # ④ publish every @jinsiyu/* sub-package
|
|
66
|
+
pnpm pack # ⑤ → dsh-code-server-app-<version>.tgz (~105KB)
|
|
67
|
+
npm publish dsh-code-server-app-<version>.tgz --access public # ⑥ publish the plugin itself (same verified tarball)
|
|
67
68
|
```
|
|
68
69
|
|
|
69
70
|
| Goal | Command |
|
|
70
71
|
|---|---|
|
|
71
|
-
| **Build the latest code-server from npm** | `pnpm run vendor:latest` (= `--force`): snapshots `code-server@latest` into `vendor/code-server`; afterwards you **must** re-run `vendor-repacks.mjs`
|
|
72
|
+
| **Build the latest code-server from npm** | `pnpm run vendor:latest` (= `--force`): snapshots `code-server@latest` into `vendor/code-server`; afterwards you **must** re-run `repack:code-server` (republish the sub-packages) and `vendor-repacks.mjs` (the inner dependency versions change) |
|
|
72
73
|
| **Pin a version** | `pnpm run vendor:code-server -- --version 4.136.2` |
|
|
73
74
|
| **Snapshot from an existing tree** | `pnpm run vendor:code-server -- --from <code-server dir>` (seconds) |
|
|
75
|
+
| **Rebuild the code-server sub-packages** | `pnpm run repack:code-server -- --target win32-arm64,win32-x64 --pack` (x64 compiles argon2 and checks the PE machine type) |
|
|
74
76
|
| **Rebuild prebuilt natives** | `node scripts/vendor-repacks.mjs [--from <existing full install>] --target win32-arm64,win32-x64 --pack` (without `--from` it npm-installs and compiles the source tree itself — slow) |
|
|
75
|
-
| **Publish
|
|
77
|
+
| **Publish sub-packages** | `pnpm run publish:repacks` (`--dry-run` to preview; `--only <substr>` to filter; `--otp <code>` / `--limit N` for 2FA) |
|
|
76
78
|
| **Publish the plugin itself** | `npm publish dsh-code-server-app-<version>.tgz --access public` (publishes the exact tarball that was verified; no re-packing) |
|
|
77
79
|
| **Just report versions** | `pnpm run vendor:check` |
|
|
78
80
|
|
|
79
81
|
> `pnpm pack`'s `prepack` runs the vendor-code-server script once; when `vendor/code-server` already exists it is
|
|
80
82
|
> a **no-op that takes seconds**, so after ordinary code changes you can just run `pnpm pack` (it will never
|
|
81
83
|
> silently upgrade code-server). Upgrading code-server requires an explicit `pnpm run vendor:latest`
|
|
82
|
-
> (or `--force` / `--version`) **plus** republishing the
|
|
84
|
+
> (or `--force` / `--version`) **plus** republishing the sub-packages.
|
|
83
85
|
|
|
84
86
|
## Install the plugin (one command; all dependencies installed by the package manager)
|
|
85
87
|
|
|
86
88
|
```powershell
|
|
87
89
|
# no postinstall in the package → no pnpm approve-builds / allowBuilds; one command installs everything
|
|
88
|
-
dsh plugin --profile web add dsh-code-server-app@0.1.
|
|
90
|
+
dsh plugin --profile web add dsh-code-server-app@0.1.37
|
|
89
91
|
# a local tarball works the same way:
|
|
90
|
-
dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app\dsh-code-server-app-0.1.
|
|
92
|
+
dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app\dsh-code-server-app-0.1.37.tgz
|
|
91
93
|
```
|
|
92
94
|
|
|
93
|
-
Ready to use immediately — **no second step, no "Install environment", no install-guide modal
|
|
95
|
+
Ready to use immediately — **no second step, no "Install environment", no install-guide modal**.
|
|
96
|
+
Since 0.1.37 the main package is only **~105KB** (the plugin's own code); everything else is dependencies:
|
|
94
97
|
|
|
95
|
-
- the
|
|
96
|
-
|
|
98
|
+
- **the code-server tree** (`lib/vscode` 196.9MB + its own 136 runtime dependencies) ships as a **platform-specific
|
|
99
|
+
sub-package** `@jinsiyu/dshcs-code-server-<platform>-<arch>@<code-server version>` (gated by `os`/`cpu`, listed in
|
|
100
|
+
the plugin's `optionalDependencies`) → pnpm picks the right one for the architecture; it runs from
|
|
101
|
+
`<profile>\node_modules\@jinsiyu\dshcs-code-server-win32-arm64\code-server`;
|
|
97
102
|
- the **pure-JS part** of VS Code's inner dependencies (35 packages: xterm / katex / typescript / ws / tar …) is
|
|
98
103
|
declared in the plugin's `dependencies` and installed by pnpm into the profile's `node_modules` (hoisted);
|
|
99
104
|
- the **packages that need compiling** (node-pty / @vscode/sqlite3 / kerberos / koffi / ssh2 / cpu-features /
|
|
100
105
|
@parcel/watcher / @vscode/windows-* … 16 in total) are provided as prebuilt `@jinsiyu/dshcs-*` packages,
|
|
101
106
|
pulled back under their **original names** by the **platform aggregator**
|
|
102
|
-
`@jinsiyu/dsh-code-server-runtime-<platform>-<arch>` using `npm:` aliases
|
|
103
|
-
`optionalDependencies` (gated by `os`/`cpu`), so pnpm **auto-selects the right one for the current
|
|
104
|
-
architecture**;
|
|
107
|
+
`@jinsiyu/dsh-code-server-runtime-<platform>-<arch>` using `npm:` aliases;
|
|
105
108
|
- consequently the dependency graph contains **no package with pre/install/postinstall or a `binding.gyp`** →
|
|
106
|
-
no profile `allowBuilds`, no build script ever runs, and **the user machine needs no C++ toolchain
|
|
109
|
+
no profile `allowBuilds`, no build script ever runs, and **the user machine needs no C++ toolchain**;
|
|
110
|
+
- **upgrading the plugin no longer re-downloads code-server**: the sub-package is cached by version, so only a
|
|
111
|
+
code-server version change pulls those ~58MB again.
|
|
107
112
|
|
|
108
113
|
### Install mechanism (why it is built this way)
|
|
109
114
|
|
|
@@ -112,11 +117,16 @@ Ready to use immediately — **no second step, no "Install environment", no inst
|
|
|
112
117
|
"requires build" and must be approved through the **host profile's** `pnpm-workspace.yaml` (`allowBuilds`),
|
|
113
118
|
otherwise `dsh plugin add` exits 1 with `[ERR_PNPM_IGNORED_BUILDS]`. A dependency's own `pnpm.allowBuilds`,
|
|
114
119
|
`.npmrc`, the `patch:` protocol and `optionalDependencies` are all ineffective (measured 2026-09, pnpm 11.25);
|
|
115
|
-
- **the code-server tree**
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
- **the code-server tree** is prepared at pack time with `npm install code-server@<version> --ignore-scripts`
|
|
121
|
+
(skips the official `sh ./postinstall.sh` — there is no `sh` on Windows and the script only accepts npm/yarn
|
|
122
|
+
user agents, so it always fails under pnpm) → supply the argon2 native binary (no Windows prebuild exists;
|
|
123
|
+
compile with `node-gyp-build`, or reuse an existing `argon2.node` via `DSHCS_ARGON2_BINARY`) → strip leftover
|
|
124
|
+
install scripts → snapshot to `vendor/code-server/`;
|
|
125
|
+
- `scripts/vendor-code-server-pkg.mjs` then turns it into **platform sub-packages**: the tree lives in an inner
|
|
126
|
+
`code-server/` directory (npm/pnpm packing **always excludes the package root's `node_modules`**; a subdirectory
|
|
127
|
+
covered by `files` is included), and the sub-package declares **no `dependencies`** (those 136 packages are
|
|
128
|
+
already files inside `code-server/node_modules`; declaring them would make pnpm install a second copy).
|
|
129
|
+
`os`/`cpu` gated, each with its own compiled argon2 (arm64 0xaa64 / x64 0x8664);
|
|
120
130
|
- **packages that need compiling** are repacked by `scripts/vendor-repacks.mjs` into `@jinsiyu/dshcs-*`:
|
|
121
131
|
copy the already-compiled package directory → **delete `scripts` / `files` / `binding.gyp` / `.hooks` /
|
|
122
132
|
`.npmignore`** (keeping the compiled `.node` and every runtime file) → rewrite dependencies that belong to the
|
|
@@ -125,14 +135,21 @@ Ready to use immediately — **no second step, no "Install environment", no inst
|
|
|
125
135
|
`"node-pty": "npm:@jinsiyu/dshcs-node-pty@1.2.0-beta.15"`), so VS Code's `require('node-pty')` needs no change.
|
|
126
136
|
The aggregator itself is `os`/`cpu` gated, and the plugin declares both win32-arm64 and win32-x64 in
|
|
127
137
|
`optionalDependencies` → one command picks the right one automatically;
|
|
128
|
-
- **resolution path**:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
>
|
|
138
|
+
- **resolution path**: the host resolves the runtime root with
|
|
139
|
+
`require.resolve('@jinsiyu/dshcs-code-server-<platform>-<arch>/package.json')` (then the inner `code-server/`
|
|
140
|
+
directory) and launches `code-server/out/node/entry.js`; VS Code's inner dependencies are resolved upward from
|
|
141
|
+
there: `code-server/node_modules` → the sub-package's `node_modules` → `<profile>/node_modules` (hoisted
|
|
142
|
+
layout), exactly what the runtime sees. The in-package `vendor/code-server` is only a development/legacy
|
|
143
|
+
fallback.
|
|
144
|
+
|
|
145
|
+
> **Size note**: the plugin tarball is **~105KB**; each `@jinsiyu/dshcs-code-server-win32-*` sub-package is
|
|
146
|
+
> **~58–60MB** (249MB unpacked); the inner dependencies and prebuilt natives add ~250MB. A full install downloads
|
|
147
|
+
> roughly 310MB. Neither `vendor/` nor `repack/` is tracked by git (see `.gitignore`).
|
|
148
|
+
|
|
149
|
+
> **Upgrading from ≤ 0.1.36**: the in-package `vendor/code-server/` moved into the platform sub-packages and the
|
|
150
|
+
> main package shrank to ~105KB. The upgrade command is unchanged
|
|
151
|
+
> (`dsh plugin --profile web add dsh-code-server-app@<version>`); the old `vendor/` disappears with the old
|
|
152
|
+
> package directory.
|
|
136
153
|
|
|
137
154
|
> **Upgrading from ≤ 0.1.35**: the old install root `<profile>\.code-server-app` (with ~1.4GB of inner
|
|
138
155
|
> dependencies) and the "Install environment" step are gone. The new version detects the old root and logs that it
|
|
@@ -140,9 +157,10 @@ Ready to use immediately — **no second step, no "Install environment", no inst
|
|
|
140
157
|
> `dsh-code-server-app: false` entries in the profile's `pnpm-workspace.yaml` can be removed too (no build
|
|
141
158
|
> approval is needed any more).
|
|
142
159
|
|
|
143
|
-
> **Uninstall**: `dsh plugin --profile web remove dsh-code-server-app` is enough
|
|
144
|
-
>
|
|
145
|
-
>
|
|
160
|
+
> **Uninstall**: `dsh plugin --profile web remove dsh-code-server-app` is enough; the code-server sub-package and
|
|
161
|
+
> the natives are separate dependencies, so to remove everything run e.g.
|
|
162
|
+
> `dsh plugin --profile web remove @jinsiyu/dshcs-code-server-win32-arm64` (or `pnpm remove` inside the profile);
|
|
163
|
+
> if an old install root is still around, delete `<profile>\.code-server-app` manually.
|
|
146
164
|
|
|
147
165
|
> After install/dependency changes, **restart `dsh web`** (the static plugin row and host probe paths load at startup).
|
|
148
166
|
|
|
@@ -196,19 +214,22 @@ dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app
|
|
|
196
214
|
**latest** version; or use `pnpm run vendor:code-server -- --version 4.136.2` / `DSHCS_CODE_SERVER_VERSION`.
|
|
197
215
|
With an existing `vendor/code-server`, a plain `pnpm pack` never upgrades (it is a no-op).
|
|
198
216
|
- **Check first**: `pnpm run vendor:check` prints the bundled version / npm latest.
|
|
199
|
-
- **A version bump requires republishing
|
|
200
|
-
code-server):
|
|
201
|
-
`pnpm run
|
|
202
|
-
`
|
|
217
|
+
- **A version bump requires republishing two kinds of sub-packages** (the inner dependency versions change with
|
|
218
|
+
code-server):
|
|
219
|
+
1. `pnpm run repack:code-server -- --target win32-arm64,win32-x64 --pack` → the new code-server sub-packages;
|
|
220
|
+
2. `node scripts/vendor-repacks.mjs --target win32-arm64,win32-x64 --pack` → the prebuilt natives (also rewrites
|
|
221
|
+
the plugin's pure-JS `dependencies` and both aggregator versions);
|
|
222
|
+
3. `pnpm run publish:repacks` → publish; then bump the plugin version → `pnpm pack` → publish the plugin.
|
|
203
223
|
- **No runtime auto-upgrade anymore**: nothing fetches latest at startup; the version is fully determined by the bundled artifact.
|
|
204
224
|
- Bundled locally right now: `code-server@4.136.2` (with Code 1.136.1).
|
|
205
225
|
|
|
206
226
|
### Compatibility with the old install locations
|
|
207
227
|
|
|
208
|
-
Host probe order:
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
228
|
+
Host probe order: `@jinsiyu/dshcs-code-server-<platform>-<arch>/code-server` (**the real layout since 0.1.37**) >
|
|
229
|
+
the in-package `vendor/code-server` (0.1.36 and earlier / development) > the old install root
|
|
230
|
+
`<profile>\.code-server-app\node_modules\code-server` (0.1.35 and earlier) > plugin-internal
|
|
231
|
+
`node_modules/code-server` (development) > PATH/config `bin`. The old root is only mentioned in a startup log
|
|
232
|
+
line; nothing writes to it any more.
|
|
212
233
|
|
|
213
234
|
## Settings card (Settings → Plugins → Code Server)
|
|
214
235
|
|
|
@@ -233,7 +254,7 @@ package manager, and the card only reports the result.
|
|
|
233
254
|
|
|
234
255
|
| Key | Default | Description |
|
|
235
256
|
|---|---|---|
|
|
236
|
-
| `bin` | `code-server` (placeholder) | Launch priority: explicit `bin` in config > the
|
|
257
|
+
| `bin` | `code-server` (placeholder) | Launch priority: explicit `bin` in config > the platform sub-package `@jinsiyu/dshcs-code-server-<platform>-<arch>/code-server/out/node/entry.js` > the in-package `vendor/code-server` > the old install root `.code-server-app` > plugin-internal `node_modules` > `code-server` on PATH. None present → startup error with troubleshooting hints |
|
|
237
258
|
| `host` | `127.0.0.1` | Bind address; `auth: none` only allows loopback (localhost/127.0.0.1/::1) |
|
|
238
259
|
| `port` | `8090` | Port; on conflict startup fails with diagnostics (no automatic port change) |
|
|
239
260
|
| `auth` | `none` | `none` \| `password`; non-loopback host automatically requires password |
|
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
> - **需要微软专有扩展时**:从 Marketplace 网页下载 `.vsix`,用 `code-server --install-extension <文件>`(或放入 `--extensions-dir`)手动安装,即可在插件列表使用。
|
|
12
12
|
|
|
13
13
|
静态 profile 插件(npm 包形态,host + client bundle),把 [code-server](https://github.com/coder/code-server)
|
|
14
|
-
|
|
14
|
+
**以平台专属子包的形式随插件依赖安装**(打包期产物 `vendor/code-server` → `@jinsiyu/dshcs-code-server-<平台>-<架构>`,
|
|
15
|
+
无安装脚本、无 postinstall),插件目录外就地运行;
|
|
15
16
|
VS Code 内部依赖与预编译原生模块**全部由包管理器随插件一起装好** —— 无需全局 npm 安装、无需配置 `bin`、
|
|
16
17
|
无需改 profile 配置、无需第二条安装命令。
|
|
17
18
|
|
|
@@ -55,9 +56,10 @@ VS Code 内部依赖与预编译原生模块**全部由包管理器随插件一
|
|
|
55
56
|
"打包(如何出包)"执行 `pnpm install` → `pnpm run build:client` → `pnpm run vendor:code-server` →
|
|
56
57
|
(发布预编译原生包)→ `pnpm pack` + `dsh plugin --profile web add` 即可。
|
|
57
58
|
|
|
58
|
-
> 本机(BM: Windows 11 ARM64)实测:`code-server@4.136.2`(with Code 1.136.1)
|
|
59
|
-
>
|
|
60
|
-
>
|
|
59
|
+
> 本机(BM: Windows 11 ARM64)实测:`code-server@4.136.2`(with Code 1.136.1)由平台子包
|
|
60
|
+
> `@jinsiyu/dshcs-code-server-win32-arm64` 提供(主包 0.1.37 仅 105KB),
|
|
61
|
+
> 35 个纯 JS 内部依赖 + 16 个预编译原生包(经平台聚合包装回原名)由 pnpm 一条命令装好 →
|
|
62
|
+
> healthz 200 → 运行中切换 cwd 重启 → 停止 → 回收全链路验证。
|
|
61
63
|
|
|
62
64
|
## 打包(如何出包)
|
|
63
65
|
|
|
@@ -66,48 +68,54 @@ cd C:\Users\User\Desktop\dsh-code-server-app
|
|
|
66
68
|
pnpm install # 开发依赖(esbuild + motion);allowBuilds 已显式声明 → 不执行任何 postinstall
|
|
67
69
|
pnpm run build:client # src/factory.js → lib/client.js(不入库,必须先构建)
|
|
68
70
|
pnpm run vendor:check # 可选:查看内置 code-server 版本 vs npm 最新版
|
|
69
|
-
pnpm run vendor:code-server # 生成 vendor/code-server(code-server 本体 + 自身依赖)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
pnpm
|
|
73
|
-
|
|
71
|
+
pnpm run vendor:code-server # ① 生成 vendor/code-server(code-server 本体 + 自身依赖)
|
|
72
|
+
pnpm run repack:code-server -- --target win32-arm64,win32-x64 --pack # ② 打成平台专属子包(含 argon2 原生)
|
|
73
|
+
node scripts/vendor-repacks.mjs --target win32-arm64,win32-x64 --pack # ③ 生成/重打包 VS Code 原生包
|
|
74
|
+
pnpm run publish:repacks # ④ 发布全部 @jinsiyu/* 子包(需 npm 登录)
|
|
75
|
+
pnpm pack # ⑤ → dsh-code-server-app-<version>.tgz(约 105KB)
|
|
76
|
+
npm publish dsh-code-server-app-<version>.tgz --access public # ⑥ 发布插件本体(同一次验证的 tarball)
|
|
74
77
|
```
|
|
75
78
|
|
|
76
79
|
| 目标 | 命令 |
|
|
77
80
|
|---|---|
|
|
78
|
-
| **打 npm 最新版 code-server** | `pnpm run vendor:latest`(= `--force`):从 registry 取 `code-server@latest` 快照到 `vendor/code-server`;之后**必须**重跑 `vendor-repacks.mjs`
|
|
81
|
+
| **打 npm 最新版 code-server** | `pnpm run vendor:latest`(= `--force`):从 registry 取 `code-server@latest` 快照到 `vendor/code-server`;之后**必须**重跑 `repack:code-server`(重发子包)与 `vendor-repacks.mjs`(内部依赖版本会变) |
|
|
79
82
|
| **指定版本** | `pnpm run vendor:code-server -- --version 4.136.2` |
|
|
80
83
|
| **从已装好的树快照** | `pnpm run vendor:code-server -- --from <code-server 目录>`(秒级) |
|
|
84
|
+
| **重打 code-server 子包** | `pnpm run repack:code-server -- --target win32-arm64,win32-x64 --pack`(x64 会现编 argon2 并校验 PE) |
|
|
81
85
|
| **重建预编译原生包** | `node scripts/vendor-repacks.mjs [--from <已完整安装的树>] --target win32-arm64,win32-x64 --pack`(不给 `--from` 会自己 npm install 解包 + 编译,耗时) |
|
|
82
|
-
|
|
|
86
|
+
| **发布子包** | `pnpm run publish:repacks`(`--dry-run` 预览;`--only <子串>` 过滤;`--otp <code>` / `--limit N` 应对 2FA) |
|
|
83
87
|
| **发布插件本体** | `npm publish dsh-code-server-app-<version>.tgz --access public`(发布**已验证过的那份 tarball**,不会重新打包) |
|
|
84
88
|
| **只报告版本** | `pnpm run vendor:check` |
|
|
85
89
|
|
|
86
90
|
> `pnpm pack` 的 `prepack` 会自动跑一次 `vendor-code-server` 脚本;`vendor/code-server` 已存在时它是
|
|
87
91
|
> **秒级 no-op**,所以日常只改插件代码的话直接 `pnpm pack` 即可(不会偷偷升级 code-server)。
|
|
88
|
-
> 升级 code-server 必须显式 `pnpm run vendor:latest`(或 `--force`/`--version`)
|
|
92
|
+
> 升级 code-server 必须显式 `pnpm run vendor:latest`(或 `--force`/`--version`),并重发子包。
|
|
89
93
|
|
|
90
94
|
## 安装插件(一条命令;依赖全部由包管理器装好)
|
|
91
95
|
|
|
92
96
|
```powershell
|
|
93
97
|
# 包内无 postinstall → 无需 pnpm approve-builds / allowBuilds;一条命令装完
|
|
94
|
-
dsh plugin --profile web add dsh-code-server-app@0.1.
|
|
98
|
+
dsh plugin --profile web add dsh-code-server-app@0.1.37
|
|
95
99
|
# 本地 tarball 同理:
|
|
96
|
-
dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app\dsh-code-server-app-0.1.
|
|
100
|
+
dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app\dsh-code-server-app-0.1.37.tgz
|
|
97
101
|
```
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
装完即用,**没有第二步、没有「安装环境」、不弹安装指引**。0.1.37 起主包只有 **~105KB**(插件自身代码),
|
|
104
|
+
其余全部是依赖:
|
|
100
105
|
|
|
101
|
-
-
|
|
102
|
-
|
|
106
|
+
- **code-server 本体**(含 `lib/vscode` 196.9MB + 它自带的 136 个运行时依赖)打成**平台专属子包**
|
|
107
|
+
`@jinsiyu/dshcs-code-server-<platform>-<arch>@<code-server 版本>`(os/cpu 限定,
|
|
108
|
+
挂在插件 `optionalDependencies`)→ pnpm 按架构自动选中,运行根在
|
|
109
|
+
`<profile>\node_modules\@jinsiyu\dshcs-code-server-win32-arm64\code-server`;
|
|
103
110
|
- VS Code 内部依赖里**纯 JS 的部分**(35 个:xterm / katex / typescript / ws / tar …)写在插件
|
|
104
|
-
`dependencies`,由 pnpm
|
|
111
|
+
`dependencies`,由 pnpm 装到 profile 的 `node_modules`(hoisted);
|
|
105
112
|
- **需要编译的原生包**(node-pty / @vscode/sqlite3 / kerberos / koffi / ssh2 / cpu-features /
|
|
106
113
|
@parcel/watcher / @vscode/windows-* …共 16 个)由 `@jinsiyu/dshcs-*` 预编译包提供,
|
|
107
114
|
经**平台聚合包** `@jinsiyu/dsh-code-server-runtime-<platform>-<arch>` 用 `npm:` 别名装回**原始名字**;
|
|
108
|
-
聚合包挂在插件 `optionalDependencies` 上(os/cpu 限定)→ pnpm **按架构自动选中**当前平台那一份;
|
|
109
115
|
- 因此依赖图里**没有任何带 pre/install/postinstall 或 binding.gyp 的包** →
|
|
110
|
-
不需要 profile 的 `allowBuilds`、不执行任何构建、**使用者机器不需要 C++
|
|
116
|
+
不需要 profile 的 `allowBuilds`、不执行任何构建、**使用者机器不需要 C++ 工具链**;
|
|
117
|
+
- **升级插件不再重下 code-server**:子包版本按 code-server 版本缓存,pnpm 会直接复用;
|
|
118
|
+
只有 code-server 版本变化时才重新下载那 ~58MB。
|
|
111
119
|
|
|
112
120
|
### 安装机制(为什么这样设计)
|
|
113
121
|
|
|
@@ -115,32 +123,43 @@ dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app\dsh-code-
|
|
|
115
123
|
的包都被判定"需要构建",必须由**宿主 profile** 的 `pnpm-workspace.yaml` 用 `allowBuilds` 批准,
|
|
116
124
|
否则 `dsh plugin add` 直接 `[ERR_PNPM_IGNORED_BUILDS]` exit 1。依赖包自己的 `pnpm.allowBuilds`、
|
|
117
125
|
`.npmrc`、`patch:` 协议、`optionalDependencies` 全都不起作用(实测 2026-09,pnpm 11.25);
|
|
118
|
-
- **code-server
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
126
|
+
- **code-server 本体**打包期用 `npm install code-server@<版本> --ignore-scripts`(跳过官方
|
|
127
|
+
`sh ./postinstall.sh`:Windows 无 sh,且它只认 npm/yarn 的 user-agent)拿到树 → 补齐 argon2 native
|
|
128
|
+
(win32-arm64 上游无预编译;可复用本机已有 `argon2.node`,见 `DSHCS_ARGON2_BINARY`)→
|
|
129
|
+
剥掉残留安装脚本 → 快照到 `vendor/code-server/`;
|
|
130
|
+
- 随后 `scripts/vendor-code-server-pkg.mjs` 把它打成**平台子包**:树放在包内子目录 `code-server/`
|
|
131
|
+
(npm/pnpm 打包**永远排除包根目录的 node_modules**,放在被 `files` 覆盖的子目录里才会随包发布),
|
|
132
|
+
子包**不写 `dependencies`**(那 136 个依赖已经作为文件打包在 `code-server/node_modules` 里,
|
|
133
|
+
写成 dependencies 会让 pnpm 再装一份);`os`/`cpu` 限定 + 各自编译好的 argon2(arm64 0xaa64 / x64 0x8664);
|
|
134
|
+
- **需要编译的包**由 `scripts/vendor-repacks.mjs` 重打包成 `@jinsiyu/dshcs-*`:
|
|
123
135
|
复制已编译的包目录 → **删除 `scripts` / `files` / `binding.gyp` / `.hooks` / `.npmignore`**
|
|
124
136
|
(保留编译好的 `.node` 与全部运行时文件)→ 依赖里的同集包改成 `npm:` 别名 → 平台专属的加
|
|
125
137
|
`os`/`cpu` 与 `-<platform>-<arch>` 后缀;
|
|
126
138
|
- **平台聚合包**把重打包包按原始名字装回去(如 `"node-pty": "npm:@jinsiyu/dshcs-node-pty@1.2.0-beta.15"`),
|
|
127
139
|
于是 VS Code 内部代码 `require('node-pty')` 不用改;聚合包本身 `os`/`cpu` 限定,
|
|
128
140
|
插件 `optionalDependencies` 同时声明 win32-arm64 与 win32-x64 两份 → 一条命令自动选对;
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
|
|
141
|
+
- **解析路径**:host 用 `require.resolve('@jinsiyu/dshcs-code-server-<平台>-<架构>/package.json')`
|
|
142
|
+
找到运行根(子目录 `code-server/`),入口 `code-server/out/node/entry.js`;
|
|
143
|
+
VS Code 内部依赖从该运行根向上查找:`code-server/node_modules` → 子包 `node_modules` →
|
|
144
|
+
`<profile>/node_modules`(hoisted 布局),与运行时完全一致。包内 `vendor/code-server` 仅作
|
|
145
|
+
开发期/兼容回退。
|
|
132
146
|
|
|
133
|
-
> **体积提示**:插件 tarball 约 **
|
|
134
|
-
>
|
|
135
|
-
>
|
|
147
|
+
> **体积提示**:插件 tarball 约 **105KB**;`@jinsiyu/dshcs-code-server-win32-*` 子包各约 **58–60MB**
|
|
148
|
+
> (解包 ~249MB);内部依赖与预编译原生包约 250MB。全部合计安装下载约 310MB。
|
|
149
|
+
> `vendor/` 与 `repack/` 都不入 git(见 `.gitignore`)。
|
|
150
|
+
|
|
151
|
+
> **从 ≤ 0.1.36 升级**:插件包内的 `vendor/code-server/` 已移出到平台子包,主包瘦身到 ~105KB;
|
|
152
|
+
> 升级命令不变(一条 `dsh plugin --profile web add dsh-code-server-app@<版本>`),
|
|
153
|
+
> 旧的 `vendor/` 会随旧版本包目录一起被 pnpm 清掉。
|
|
136
154
|
|
|
137
155
|
> **从 ≤ 0.1.35 升级**:旧版的安装根 `<profile>\.code-server-app`(含约 1.4GB 内部依赖)与
|
|
138
156
|
> 「安装环境」步骤都不再需要 —— 新版本会检测到它并打一条日志提示可安全删除:
|
|
139
157
|
> `Remove-Item -Recurse -Force <profile>\.code-server-app`。profile 的 `pnpm-workspace.yaml` 里
|
|
140
158
|
> 若还留着 `dsh-code-server-app: false` 之类的旧条目,也可以删掉(新版不再需要任何构建许可)。
|
|
141
159
|
|
|
142
|
-
> **卸载**:`dsh plugin --profile web remove dsh-code-server-app`
|
|
143
|
-
>
|
|
160
|
+
> **卸载**:`dsh plugin --profile web remove dsh-code-server-app` 即可;code-server 子包与原生包
|
|
161
|
+
> 是独立依赖,若要彻底清干净可再 `dsh plugin --profile web remove @jinsiyu/dshcs-code-server-win32-arm64`
|
|
162
|
+
> (或直接在 profile 里 `pnpm remove`);若还残留旧安装根,再手动删除 `<profile>\.code-server-app`。
|
|
144
163
|
|
|
145
164
|
> 安装/依赖变化后请**重启 `dsh web`**(静态插件行与 host 探测路径在启动时加载)。
|
|
146
165
|
|
|
@@ -151,8 +170,9 @@ dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app
|
|
|
151
170
|
```
|
|
152
171
|
|
|
153
172
|
> 源码路径以 `link:` 安装。开发机上没有 `vendor/code-server` 时先 `pnpm run vendor:code-server`;
|
|
154
|
-
>
|
|
155
|
-
>
|
|
173
|
+
> 没有平台子包时 host 会回退到包内 `vendor/code-server`(两种布局都支持)。
|
|
174
|
+
> 依赖(内部 JS 依赖 + 平台子包 + 聚合包)同样由 pnpm 安装 —— 本地未发布的 `@jinsiyu/*` 需先发布,
|
|
175
|
+
> 或把 `repack/tgz/*.tgz` 以 `file:` 依赖临时装进 profile(见 `.tmp-verify.mjs`)。
|
|
156
176
|
>
|
|
157
177
|
> **改动 client bundle**:编辑 `src/factory.js` 后执行 `pnpm run build:client`
|
|
158
178
|
> 重新生成 `lib/client.js`(仓库不跟踪该产物;浏览器刷新即生效,host 无需重启)。
|
|
@@ -191,17 +211,19 @@ dsh plugin --profile web add C:\Users\User\Desktop\dsh-code-server-app
|
|
|
191
211
|
也可 `pnpm run vendor:code-server -- --version 4.136.2` 或设 `DSHCS_CODE_SERVER_VERSION`。
|
|
192
212
|
已有 `vendor/code-server` 时,不带 `--force`/`--version` 不会升级(日常 `pnpm pack` 是 no-op)。
|
|
193
213
|
- **先查再升**:`pnpm run vendor:check` 打印「内置版本 / npm latest」。
|
|
194
|
-
-
|
|
195
|
-
`
|
|
196
|
-
`
|
|
197
|
-
|
|
214
|
+
- **换版本后要重发两类子包**(内部依赖版本会跟着 code-server 变):
|
|
215
|
+
1. `pnpm run repack:code-server -- --target win32-arm64,win32-x64 --pack` → 新版本号的 code-server 平台子包;
|
|
216
|
+
2. `node scripts/vendor-repacks.mjs --target win32-arm64,win32-x64 --pack` → 预编译原生包(并把新的
|
|
217
|
+
「纯 JS 直装集」写进插件 `dependencies`、更新两个聚合包版本);
|
|
218
|
+
3. `pnpm run publish:repacks` → 发布;然后 bump 插件版本 → `pnpm pack` → 发布插件。
|
|
198
219
|
- **不再有运行期自动升级**:不会在启动时联网取 latest;版本完全由内置产物决定。
|
|
199
220
|
- 本机当前内置:`code-server@4.136.2`(with Code 1.136.1)。
|
|
200
221
|
|
|
201
222
|
### 兼容旧安装位
|
|
202
223
|
|
|
203
|
-
host
|
|
204
|
-
|
|
224
|
+
host 探测顺序:`@jinsiyu/dshcs-code-server-<平台>-<架构>/code-server`(**0.1.37+ 正式布局**)> 插件包内
|
|
225
|
+
`vendor/code-server`(0.1.36 及更早 / 开发期)> 旧版安装根
|
|
226
|
+
`<profile>\.code-server-app\node_modules\code-server`(兼容 0.1.35 及更早)> 插件包内
|
|
205
227
|
`node_modules/code-server`(开发期)> PATH/配置 `bin`。旧安装根只在启动日志里提示可删除,不再被写入。
|
|
206
228
|
|
|
207
229
|
## 设置卡片(设置 → 插件 → Code Server)
|
|
@@ -226,7 +248,7 @@ host 探测顺序:`<插件>/vendor/code-server`(**正式布局,就地运行**)>
|
|
|
226
248
|
|
|
227
249
|
| 键 | 默认 | 说明 |
|
|
228
250
|
|---|---|---|
|
|
229
|
-
| `bin` | `code-server`(占位) | 启动优先级:本配置显式 `bin` >
|
|
251
|
+
| `bin` | `code-server`(占位) | 启动优先级:本配置显式 `bin` > 平台子包 `@jinsiyu/dshcs-code-server-<平台>-<架构>/code-server/out/node/entry.js` > 包内 `vendor/code-server` > 旧安装根 `.code-server-app` > 插件包内 `node_modules` > PATH 中的 `code-server`。都不存在时启动报错并给出排查提示 |
|
|
230
252
|
| `host` | `127.0.0.1` | 绑定地址;`auth: none` 仅允许回环(localhost/127.0.0.1/::1) |
|
|
231
253
|
| `port` | `8090` | 端口;被占用时启动失败并给出诊断(不自动换端口) |
|
|
232
254
|
| `auth` | `none` | `none` \| `password`;非回环 host 自动要求 password |
|
package/lib/index.js
CHANGED
|
@@ -213,7 +213,9 @@ function declaredInnerDeps() {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
/** 从 code-server 运行位置解析内部依赖(与运行时同一套向上查找规则)。
|
|
216
|
+
/** 从 code-server 运行位置解析内部依赖(与运行时同一套向上查找规则)。
|
|
217
|
+
* 先试 `<name>/package.json`(code-server 本体包没有入口文件,ESM-only 包也没有 require 入口),
|
|
218
|
+
* 再退回 `<name>` 本身。 */
|
|
217
219
|
function checkInnerDeps() {
|
|
218
220
|
const declared = declaredInnerDeps();
|
|
219
221
|
const root = codeServerRoot();
|
|
@@ -221,12 +223,16 @@ function checkInnerDeps() {
|
|
|
221
223
|
const missing = [];
|
|
222
224
|
let resolved = 0;
|
|
223
225
|
for (const name of declared) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
226
|
+
let ok = false;
|
|
227
|
+
for (const spec of [`${name}/package.json`, name]) {
|
|
228
|
+
try {
|
|
229
|
+
from.resolve(spec);
|
|
230
|
+
ok = true;
|
|
231
|
+
break;
|
|
232
|
+
} catch { /* 试下一个 */ }
|
|
229
233
|
}
|
|
234
|
+
if (ok) resolved += 1;
|
|
235
|
+
else missing.push(name);
|
|
230
236
|
}
|
|
231
237
|
return { declared: declared.length, resolved, missing };
|
|
232
238
|
}
|
package/lib/vendor.js
CHANGED
|
@@ -37,27 +37,37 @@ export function legacyInstallRoot() {
|
|
|
37
37
|
return profileRoot !== null ? join(profileRoot, APP_DIR_NAME) : null;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
export function codeServerPackageName(
|
|
42
|
-
const key = `${platform}-${arch}`;
|
|
40
|
+
/** code-server 本体包名(0.1.38+ 平台无关):取插件 dependencies 里的 @<scope>/dshcs-code-server。 */
|
|
41
|
+
export function codeServerPackageName() {
|
|
43
42
|
try {
|
|
44
43
|
const manifest = JSON.parse(readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf8'));
|
|
45
|
-
const declared = { ...(manifest.
|
|
46
|
-
const hit = Object.keys(declared).find((name) =>
|
|
44
|
+
const declared = { ...(manifest.dependencies ?? {}), ...(manifest.optionalDependencies ?? {}) };
|
|
45
|
+
const hit = Object.keys(declared).find((name) => /^@[^/]+\/dshcs-code-server$/.test(name));
|
|
47
46
|
if (hit !== undefined) return hit;
|
|
48
47
|
} catch { /* 回退默认 scope */ }
|
|
49
|
-
return
|
|
48
|
+
return '@jinsiyu/dshcs-code-server';
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
/** code-server
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
/** 旧版(0.1.37)平台专属 code-server 子包名,仅作兼容回退。 */
|
|
52
|
+
export function legacyCodeServerPackageName(platform = process.platform, arch = process.arch) {
|
|
53
|
+
return `@jinsiyu/dshcs-code-server-${platform}-${arch}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 解析某个包目录下的 code-server 运行根(包内布局:<pkg>/code-server/**)。 */
|
|
57
|
+
function rootOfPackage(name) {
|
|
56
58
|
try {
|
|
57
59
|
const manifest = require_.resolve(`${name}/package.json`);
|
|
58
60
|
const root = join(dirname(manifest), 'code-server');
|
|
59
61
|
if (existsSync(join(root, 'out', 'node', 'entry.js'))) return root;
|
|
60
|
-
} catch { /*
|
|
62
|
+
} catch { /* 未安装 */ }
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** code-server 运行根:① 本体包(0.1.38+ 平台无关)> ② 旧平台子包(0.1.37)> ③ 包内 vendor(开发期)。
|
|
67
|
+
* @returns {string|null} 绝对路径,如 <profile>\node_modules\@jinsiyu\dshcs-code-server\code-server */
|
|
68
|
+
export function codeServerRoot() {
|
|
69
|
+
const root = rootOfPackage(codeServerPackageName()) ?? rootOfPackage(legacyCodeServerPackageName());
|
|
70
|
+
if (root !== null) return root;
|
|
61
71
|
if (existsSync(join(VENDOR_TREE, 'out', 'node', 'entry.js'))) return VENDOR_TREE;
|
|
62
72
|
return null;
|
|
63
73
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-code-server-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.38",
|
|
4
4
|
"description": "Integrate code-server (VS Code in the browser) into DSH Web and Desktop: right-sidebar tab (DSH >= 0.1.5-alpha.1) with a floating-ball fallback for older hosts, over the Connection /api channel (ctx.connection.fetch; no webServer dependency) with host-side process lifecycle.",
|
|
5
5
|
"homepage": "https://github.com/jinsiyu/dsh-code-server-app",
|
|
6
6
|
"repository": {
|
|
@@ -46,7 +46,6 @@
|
|
|
46
46
|
"assets/favicon.svg",
|
|
47
47
|
"assets/extensions/dshcs-open-file",
|
|
48
48
|
"scripts/vendor-code-server.mjs",
|
|
49
|
-
"scripts/vendor-code-server-pkg.mjs",
|
|
50
49
|
"scripts/vendor-repacks.mjs",
|
|
51
50
|
"vendor/VENDOR.json",
|
|
52
51
|
"cordis.patch.yml",
|
|
@@ -60,6 +59,7 @@
|
|
|
60
59
|
},
|
|
61
60
|
"license": "MIT",
|
|
62
61
|
"dependencies": {
|
|
62
|
+
"@jinsiyu/dshcs-code-server": "4.136.2",
|
|
63
63
|
"@microsoft/1ds-core-js": "3.2.13",
|
|
64
64
|
"@microsoft/1ds-post-js": "3.2.13",
|
|
65
65
|
"@vscode/iconv-lite-umd": "0.7.1",
|
|
@@ -97,17 +97,14 @@
|
|
|
97
97
|
"zod": "4.4.3"
|
|
98
98
|
},
|
|
99
99
|
"optionalDependencies": {
|
|
100
|
-
"@jinsiyu/dsh-code-server-runtime-win32-arm64": "^0.1.
|
|
101
|
-
"@jinsiyu/dsh-code-server-runtime-win32-x64": "^0.1.
|
|
102
|
-
"@jinsiyu/dshcs-code-server-win32-arm64": "4.136.2",
|
|
103
|
-
"@jinsiyu/dshcs-code-server-win32-x64": "4.136.2"
|
|
100
|
+
"@jinsiyu/dsh-code-server-runtime-win32-arm64": "^0.1.38",
|
|
101
|
+
"@jinsiyu/dsh-code-server-runtime-win32-x64": "^0.1.38"
|
|
104
102
|
},
|
|
105
103
|
"scripts": {
|
|
106
104
|
"vendor:code-server": "node scripts/vendor-code-server.mjs",
|
|
107
105
|
"vendor:latest": "node scripts/vendor-code-server.mjs --force",
|
|
108
106
|
"vendor:check": "node scripts/vendor-code-server.mjs --check",
|
|
109
107
|
"repack:build": "node scripts/vendor-repacks.mjs",
|
|
110
|
-
"repack:code-server": "node scripts/vendor-code-server-pkg.mjs",
|
|
111
108
|
"publish:repacks": "node scripts/publish-repacks.mjs",
|
|
112
109
|
"build:client": "node scripts/build-client.mjs"
|
|
113
110
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
// scripts/vendor-repacks.mjs —
|
|
1
|
+
// scripts/vendor-repacks.mjs — 打包期把 code-server 本体与「pnpm 拒绝安装」的原生包全部打成可安装的预编译包。
|
|
2
2
|
//
|
|
3
3
|
// 为什么:pnpm 认为「含安装脚本」或「含 binding.gyp / .hooks」的包需要构建,必须由宿主
|
|
4
|
-
// pnpm-workspace.yaml 的 allowBuilds 批准,否则 dsh plugin add 直接 exit 1。
|
|
5
|
-
//
|
|
4
|
+
// pnpm-workspace.yaml 的 allowBuilds 批准,否则 dsh plugin add 直接 exit 1。code-server 本体、
|
|
5
|
+
// argon2 与 VS Code 内部依赖里的一批原生包都属于这一类。
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
7
|
+
// 产物(全部由本脚本统一生成,再由 scripts/publish-repacks.mjs 统一发布):
|
|
8
|
+
// ① @<scope>/dshcs-code-server@<code-server 版本> 平台无关:vendor/code-server 的树
|
|
9
|
+
// (out/ + lib/vscode + 自带运行时依赖),**去掉 node_modules/argon2**;
|
|
10
|
+
// ② @<scope>/dshcs-argon2-<platform>-<arch>@<argon2 版本> 平台专属:argon2 + 该架构编译好的 .node
|
|
11
|
+
// (与其它原生包同一套规则:删 scripts/files/binding.gyp、删 prebuilds 统一走 build/Release);
|
|
12
|
+
// ③ @<scope>/dshcs-<名字>[-<platform>-<arch>]@<版本> VS Code 内部依赖里需要构建的包
|
|
13
|
+
// (node-pty / @vscode/sqlite3 / kerberos / koffi / ssh2 / …),
|
|
14
|
+
// 依赖链上命中它们的包也一并重打包(含 optionalDependencies,如 @vscode/proxy-agent → windows-ca-certs);
|
|
15
|
+
// ④ @<scope>/dsh-code-server-runtime-<platform>-<arch>@<插件版本> 平台聚合包:
|
|
16
|
+
// dependencies 用 npm: 别名把 ②③ 装回**原始名字**(argon2 / node-pty / @vscode/sqlite3 / …),
|
|
17
|
+
// 这样 code-server 与 VS Code 的 require 不用改,插件只需按 os/cpu 声明 ①(常规依赖)+ ④(可选依赖)。
|
|
17
18
|
//
|
|
18
19
|
// 结果:pnpm install 不再遇到任何带构建信号的包 → 无需 allowBuilds、无需「安装环境」步骤。
|
|
19
20
|
//
|
|
@@ -48,6 +49,10 @@ const argValue = (n) => { const a = argValues(n); return a.length > 0 ? a[a.leng
|
|
|
48
49
|
const FROM = argValue('--from');
|
|
49
50
|
const SCOPE = argValue('--scope') ?? '@jinsiyu';
|
|
50
51
|
const DO_PACK = process.argv.includes('--pack');
|
|
52
|
+
// --reuse:复用 repack/build 里已有的原生包(不重新 analyze/交叉编译),只重建
|
|
53
|
+
// code-server 本体包、argon2 平台包、平台聚合包与插件 package.json。
|
|
54
|
+
// 适用于「原生包没变、只调整打包结构」的场景(本机已无可分析的完整源树时也用它)。
|
|
55
|
+
const REUSE = process.argv.includes('--reuse');
|
|
51
56
|
const TARGETS = argValues('--target');
|
|
52
57
|
// Copilot 整树排除:620MB、依赖链里还有带脚本的包,且 code-server 里用不到。
|
|
53
58
|
const EXCLUDE = [/^@github\//, /^@vscode\/copilot-api$/];
|
|
@@ -309,22 +314,233 @@ function prepareSourceTree() {
|
|
|
309
314
|
return tree;
|
|
310
315
|
}
|
|
311
316
|
|
|
317
|
+
/** PE machine(0x8664=x64 / 0xaa64=arm64),用于交叉编译后的静态校验。 */
|
|
318
|
+
function peMachine(file) {
|
|
319
|
+
try {
|
|
320
|
+
const b = readFileSync(file);
|
|
321
|
+
if (b[0] !== 0x4d || b[1] !== 0x5a) return null;
|
|
322
|
+
const off = b.readUInt32LE(0x3c);
|
|
323
|
+
if (b.toString('ascii', off, off + 4) !== 'PE\u0000\u0000') return null;
|
|
324
|
+
return `0x${b.readUInt16LE(off + 4).toString(16)}`;
|
|
325
|
+
} catch { return null; }
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function nodeGypCli() {
|
|
329
|
+
const cli = join(process.env.APPDATA ?? '', 'npm', 'node_modules', 'node-gyp', 'bin', 'node-gyp.js');
|
|
330
|
+
if (!existsSync(cli)) throw new Error('找不到 node-gyp(需全局安装 node-gyp)');
|
|
331
|
+
return cli;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** ① code-server 本体(平台无关):vendor/code-server → repack/build/code-server/。
|
|
335
|
+
* 去掉平台专属的 node_modules/argon2 —— 它由 @<scope>/dshcs-argon2-<platform>-<arch> 按架构提供。 */
|
|
336
|
+
function buildCodeServerPackage() {
|
|
337
|
+
const vendorTree = join(pkgRoot, 'vendor', 'code-server');
|
|
338
|
+
if (!existsSync(join(vendorTree, 'out', 'node', 'entry.js'))) {
|
|
339
|
+
throw new Error('缺少 vendor/code-server;先运行 `node scripts/vendor-code-server.mjs`');
|
|
340
|
+
}
|
|
341
|
+
const version = readJson(join(vendorTree, 'package.json'))?.version;
|
|
342
|
+
if (typeof version !== 'string') throw new Error('读不到 code-server 版本');
|
|
343
|
+
const dir = join(OUT, 'build', 'code-server');
|
|
344
|
+
rmSync(dir, { recursive: true, force: true });
|
|
345
|
+
mkdirSync(dir, { recursive: true });
|
|
346
|
+
console.log(`[repack] code-server 本体(平台无关)→ ${relative(pkgRoot, join(dir, 'code-server'))}(argon2 由平台包提供)`);
|
|
347
|
+
cpSync(vendorTree, join(dir, 'code-server'), {
|
|
348
|
+
recursive: true,
|
|
349
|
+
dereference: false,
|
|
350
|
+
maxRetries: 6,
|
|
351
|
+
retryDelay: 250,
|
|
352
|
+
});
|
|
353
|
+
// 删掉平台专属的 argon2(整目录,避免嵌套解析遮蔽 <profile>/node_modules/argon2)
|
|
354
|
+
rmSync(join(dir, 'code-server', 'node_modules', 'argon2'), { recursive: true, force: true });
|
|
355
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify({
|
|
356
|
+
name: `${SCOPE}/dshcs-code-server`,
|
|
357
|
+
version,
|
|
358
|
+
description: `code-server ${version} (out/ + lib/vscode + its runtime dependencies), repacked so pnpm installs it `
|
|
359
|
+
+ `without any build script. The platform-specific argon2 binary is provided by ${SCOPE}/dshcs-argon2-<platform>-<arch>.`,
|
|
360
|
+
files: ['code-server'],
|
|
361
|
+
license: 'MIT',
|
|
362
|
+
repository: readJson(join(pkgRoot, 'package.json'))?.repository ?? undefined,
|
|
363
|
+
}, null, 2) + '\n', 'utf8');
|
|
364
|
+
const name = `${SCOPE}/dshcs-code-server`;
|
|
365
|
+
return { dir, name, version, file: tgzName(name, version) };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** ② argon2 平台二进制包(每个目标一个):@<scope>/dshcs-argon2-<target>@<argon2 版本>。
|
|
369
|
+
* 与其它原生包同一套规则:删 scripts/files/binding.gyp,保留 build/Release 里的 .node;
|
|
370
|
+
* prebuilds/ 一律删掉(统一走 build/Release,避免 node-gyp-build 在 win32-x64 选到上游 .glibc 命名文件)。 */
|
|
371
|
+
function buildArgon2Package(target) {
|
|
372
|
+
const [platform, arch] = target.split('-');
|
|
373
|
+
const src = join(pkgRoot, 'vendor', 'code-server', 'node_modules', 'argon2');
|
|
374
|
+
if (!existsSync(join(src, 'package.json'))) throw new Error('缺少 vendor/code-server/node_modules/argon2');
|
|
375
|
+
const version = readJson(join(src, 'package.json')).version;
|
|
376
|
+
const dir = join(OUT, 'build', `argon2-${target}`);
|
|
377
|
+
rmSync(dir, { recursive: true, force: true });
|
|
378
|
+
mkdirSync(dirname(dir), { recursive: true });
|
|
379
|
+
cpSync(src, dir, { recursive: true, maxRetries: 6, retryDelay: 250 }); // dest 不存在 → 内容平铺到 dir
|
|
380
|
+
rmSync(join(dir, 'build'), { recursive: true, force: true }); // 重新编译,避免带走 host 架构产物
|
|
381
|
+
|
|
382
|
+
console.log(`[repack] argon2 ${target}: node-gyp rebuild --arch=${arch} …`);
|
|
383
|
+
const res = spawnSync(process.execPath, [nodeGypCli(), 'rebuild', `--arch=${arch}`], { cwd: dir, stdio: 'inherit' });
|
|
384
|
+
if ((res.status ?? 1) !== 0) throw new Error(`argon2 ${target} 编译失败 (${res.status})`);
|
|
385
|
+
// 编译完成后才剥掉构建信号:删 prebuilds(统一走 build/Release)、binding.gyp、中间产物
|
|
386
|
+
rmSync(join(dir, 'prebuilds'), { recursive: true, force: true });
|
|
387
|
+
rmSync(join(dir, 'binding.gyp'), { force: true });
|
|
388
|
+
rmSync(join(dir, '.npmignore'), { force: true });
|
|
389
|
+
rmSync(join(dir, 'build', 'gyp'), { recursive: true, force: true }); // 中间产物,别进包
|
|
390
|
+
const bin = join(dir, 'build', 'Release', 'argon2.node');
|
|
391
|
+
if (!existsSync(bin)) throw new Error(`argon2 ${target} 缺 build/Release/argon2.node`);
|
|
392
|
+
const want = arch === 'x64' ? '0x8664' : arch === 'arm64' ? '0xaa64' : null;
|
|
393
|
+
const machine = peMachine(bin);
|
|
394
|
+
if (want !== null && machine !== want) throw new Error(`argon2 ${target} PE machine=${machine},期望 ${want}`);
|
|
395
|
+
|
|
396
|
+
const manifest = readJson(join(dir, 'package.json'));
|
|
397
|
+
delete manifest.scripts;
|
|
398
|
+
delete manifest.files;
|
|
399
|
+
manifest.name = `${SCOPE}/dshcs-argon2-${target}`;
|
|
400
|
+
manifest.version = version;
|
|
401
|
+
manifest.os = [platform];
|
|
402
|
+
manifest.cpu = [arch];
|
|
403
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
404
|
+
console.log(` ✓ argon2 ${target} → ${machine} (${manifest.name}@${version})`);
|
|
405
|
+
return { dir, name: manifest.name, version, file: tgzName(manifest.name, version) };
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** 从已安装的 profile 的 node_modules 还原 host 平台映射(别名目录名 = 原始包名,清单名 = 重打包名)。
|
|
409
|
+
* 聚合包清单丢失时的兜底(例如上次构建中途失败)。 */
|
|
410
|
+
function hostMapFromProfile() {
|
|
411
|
+
const dshHome = process.env.DSH_HOME || join(process.env.USERPROFILE ?? process.env.HOME ?? '', '.dsh');
|
|
412
|
+
const profiles = join(dshHome, 'profiles');
|
|
413
|
+
if (!existsSync(profiles)) return null;
|
|
414
|
+
let best = null;
|
|
415
|
+
let bestProfile = null;
|
|
416
|
+
for (const name of readdirSync(profiles)) {
|
|
417
|
+
const nm = join(profiles, name, 'node_modules');
|
|
418
|
+
if (!existsSync(nm)) continue;
|
|
419
|
+
const map = new Map();
|
|
420
|
+
const visit = (dir, prefix) => {
|
|
421
|
+
let entries; try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
422
|
+
for (const ent of entries) {
|
|
423
|
+
if (!ent.isDirectory() || ent.name === '.bin' || ent.name === '.pnpm') continue;
|
|
424
|
+
const full = join(dir, ent.name);
|
|
425
|
+
if (ent.name.startsWith('@')) { visit(full, prefix + ent.name + '/'); continue; }
|
|
426
|
+
const m = readJson(join(full, 'package.json'));
|
|
427
|
+
if (m === null || typeof m.name !== 'string') continue;
|
|
428
|
+
if (!/^@[^/]+\/dshcs-/.test(m.name) || /dshcs-code-server/.test(m.name)) continue;
|
|
429
|
+
map.set(`${prefix}${ent.name}`, { pkgName: m.name, version: m.version });
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
visit(nm, '');
|
|
433
|
+
if (map.size > 0 && (best === null || map.size > best.size)) { best = map; bestProfile = name; }
|
|
434
|
+
}
|
|
435
|
+
if (best !== null) {
|
|
436
|
+
console.log(`[repack] --reuse:从 profile ${bestProfile} 的别名还原 ${best.size} 个映射`);
|
|
437
|
+
}
|
|
438
|
+
return best;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** --reuse:从现有 repack/build + 聚合包清单还原「重打包集」,不重新分析源树。
|
|
442
|
+
* @returns {{repack: Map<string,{pkg:{version:string},platformSpecific:boolean}>, declare:{name:string,version:string}[], reusedItems:{dir:string,file:string}[]}} */
|
|
443
|
+
function reuseExisting(targets, hostKey) {
|
|
444
|
+
const buildRoot = join(OUT, 'build');
|
|
445
|
+
if (!existsSync(buildRoot)) throw new Error('--reuse 需要 repack/build 已存在(先跑一次完整流程)');
|
|
446
|
+
const byTarget = new Map();
|
|
447
|
+
for (const target of targets) {
|
|
448
|
+
const agg = readJson(join(OUT, 'aggregator', target, 'package.json'));
|
|
449
|
+
if (agg === null) continue;
|
|
450
|
+
const map = new Map();
|
|
451
|
+
for (const [orig, spec] of Object.entries(agg.dependencies ?? {})) {
|
|
452
|
+
if (orig === 'argon2') continue; // argon2 由本脚本重建
|
|
453
|
+
const hit = /^npm:(.+)@([^@]+)$/.exec(spec);
|
|
454
|
+
if (hit === null) throw new Error(`无法解析聚合包依赖 ${orig}: ${spec}`);
|
|
455
|
+
map.set(orig, { pkgName: hit[1], version: hit[2] });
|
|
456
|
+
}
|
|
457
|
+
byTarget.set(target, map);
|
|
458
|
+
}
|
|
459
|
+
if (byTarget.size === 0) {
|
|
460
|
+
const base = hostMapFromProfile();
|
|
461
|
+
if (base === null) {
|
|
462
|
+
throw new Error('--reuse 需要 repack/aggregator/*/package.json 或一个已安装的 profile 用于还原映射');
|
|
463
|
+
}
|
|
464
|
+
byTarget.set(hostKey, base);
|
|
465
|
+
} else {
|
|
466
|
+
// 与已安装 profile 的别名取并集:聚合包清单可能在上一次失败的重建里丢过条目
|
|
467
|
+
const hostTarget = byTarget.has(hostKey) ? hostKey : targets[0];
|
|
468
|
+
const base = hostMapFromProfile();
|
|
469
|
+
if (base !== null) {
|
|
470
|
+
const merged = new Map(byTarget.get(hostTarget));
|
|
471
|
+
let added = 0;
|
|
472
|
+
for (const [orig, info] of base) {
|
|
473
|
+
if (!merged.has(orig)) { merged.set(orig, info); added += 1; }
|
|
474
|
+
}
|
|
475
|
+
if (added > 0) console.log(`[repack] --reuse:聚合包清单缺 ${added} 个条目 → 已用 profile 别名补齐`);
|
|
476
|
+
byTarget.set(hostTarget, merged);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const known = byTarget.get(hostKey) ?? byTarget.get(targets[0]);
|
|
480
|
+
// 其余目标:按后缀替换推导(平台专属包名只在结尾的 -<platform>-<arch> 上不同)
|
|
481
|
+
const knownTarget = byTarget.has(hostKey) ? hostKey : targets[0];
|
|
482
|
+
for (const target of targets) {
|
|
483
|
+
if (byTarget.has(target)) continue;
|
|
484
|
+
const map = new Map();
|
|
485
|
+
for (const [orig, info] of known) {
|
|
486
|
+
const pkgName = info.pkgName.endsWith(`-${knownTarget}`)
|
|
487
|
+
? `${info.pkgName.slice(0, -knownTarget.length)}${target}`
|
|
488
|
+
: info.pkgName;
|
|
489
|
+
map.set(orig, { pkgName, version: info.version });
|
|
490
|
+
}
|
|
491
|
+
byTarget.set(target, map);
|
|
492
|
+
}
|
|
493
|
+
const hostSet = byTarget.get(knownTarget);
|
|
494
|
+
const repack = new Map();
|
|
495
|
+
for (const [orig, info] of hostSet) {
|
|
496
|
+
repack.set(orig, { pkg: { version: info.version }, platformSpecific: info.pkgName.endsWith(`-${knownTarget}`) });
|
|
497
|
+
}
|
|
498
|
+
// 已有原生包目录 → plan 项;顺带清掉将被重建的 code-server / argon2 目录
|
|
499
|
+
const reusedItems = [];
|
|
500
|
+
for (const ent of readdirSync(buildRoot)) {
|
|
501
|
+
if (/^code-server/.test(ent) || /^argon2-/.test(ent)) {
|
|
502
|
+
rmSync(join(buildRoot, ent), { recursive: true, force: true });
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
const m = readJson(join(buildRoot, ent, 'package.json'));
|
|
506
|
+
if (m === null) continue;
|
|
507
|
+
reusedItems.push({ dir: join(buildRoot, ent), file: tgzName(m.name, m.version) });
|
|
508
|
+
}
|
|
509
|
+
// 纯 JS 直装集:插件现有 dependencies 里非 @jinsiyu 的项
|
|
510
|
+
const pluginPkg = readJson(join(pkgRoot, 'package.json'));
|
|
511
|
+
const declare = Object.entries(pluginPkg.dependencies ?? {})
|
|
512
|
+
.filter(([name]) => !/^@jinsiyu\//.test(name))
|
|
513
|
+
.map(([name, version]) => ({ name, version }));
|
|
514
|
+
rmSync(join(OUT, 'aggregator'), { recursive: true, force: true });
|
|
515
|
+
console.log(`[repack] --reuse:复用 ${reusedItems.length} 个已打包目录、${repack.size} 个重打包条目、${declare.length} 个纯 JS 直装依赖`);
|
|
516
|
+
return { repack, declare, reusedItems };
|
|
517
|
+
}
|
|
518
|
+
|
|
312
519
|
function main() {
|
|
313
|
-
const autoSource = FROM === null;
|
|
314
|
-
const sourceTree = autoSource ? prepareSourceTree() : FROM;
|
|
315
520
|
const hostKey = `${process.platform}-${process.arch}`;
|
|
316
521
|
const targets = TARGETS.length > 0 ? TARGETS : [hostKey];
|
|
317
522
|
const pluginVersion = readJson(join(pkgRoot, 'package.json'))?.version ?? '0.0.0';
|
|
318
523
|
|
|
319
|
-
|
|
524
|
+
let repack;
|
|
525
|
+
let declare;
|
|
526
|
+
let reusedItems = [];
|
|
527
|
+
let autoSourceTree = null;
|
|
528
|
+
if (REUSE) {
|
|
529
|
+
({ repack, declare, reusedItems } = reuseExisting(targets, hostKey));
|
|
530
|
+
} else {
|
|
531
|
+
const autoSource = FROM === null;
|
|
532
|
+
const sourceTree = autoSource ? prepareSourceTree() : FROM;
|
|
533
|
+
if (autoSource) autoSourceTree = sourceTree;
|
|
534
|
+
({ repack, declare } = analyze(sourceTree));
|
|
535
|
+
rmSync(OUT, { recursive: true, force: true });
|
|
536
|
+
}
|
|
320
537
|
console.log(`\n重打包集(${repack.size}):`);
|
|
321
538
|
for (const [name, r] of [...repack].sort()) {
|
|
322
539
|
console.log(` ${name}@${r.pkg.version} ${r.platformSpecific ? '[平台专属]' : '[全平台]'}`);
|
|
323
540
|
}
|
|
324
541
|
console.log(`\n直装集(${declare.length}): ${declare.map((d) => d.name).join(', ')}\n`);
|
|
325
542
|
|
|
326
|
-
|
|
327
|
-
mkdirSync(OUT, { recursive: true });
|
|
543
|
+
mkdirSync(join(OUT, 'build'), { recursive: true });
|
|
328
544
|
|
|
329
545
|
// 每个目标的包名映射
|
|
330
546
|
const byTarget = new Map();
|
|
@@ -370,13 +586,27 @@ function main() {
|
|
|
370
586
|
};
|
|
371
587
|
|
|
372
588
|
const plan = [];
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
378
|
-
|
|
589
|
+
// 0) 已打包的原生包(--reuse 模式)
|
|
590
|
+
for (const item of reusedItems) plan.push(item);
|
|
591
|
+
// 1) code-server 本体(平台无关,1 个包)+ argon2 平台二进制包(每目标 1 个,与其它原生包同一套规则)
|
|
592
|
+
const codeServerPkg = buildCodeServerPackage();
|
|
593
|
+
plan.push({ dir: codeServerPkg.dir, file: codeServerPkg.file });
|
|
594
|
+
const argon2ByTarget = new Map();
|
|
379
595
|
for (const target of targets) {
|
|
596
|
+
const pkg = buildArgon2Package(target);
|
|
597
|
+
argon2ByTarget.set(target, pkg);
|
|
598
|
+
plan.push({ dir: pkg.dir, file: pkg.file });
|
|
599
|
+
}
|
|
600
|
+
// 2) 全平台重打包包(从 host 树;--reuse 时用已打包目录)
|
|
601
|
+
if (!REUSE) {
|
|
602
|
+
for (const [name, r] of repack) {
|
|
603
|
+
if (r.platformSpecific) continue; // 平台专属的按目标处理
|
|
604
|
+
const dir = writeRepack(r.dir, hostMap.get(name), flat(name));
|
|
605
|
+
plan.push({ dir, file: tgzName(hostMap.get(name).pkgName, r.pkg.version) });
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
// 3) 平台专属包:host 用现成树,其它目标用交叉安装树(--reuse 时用已打包目录)
|
|
609
|
+
if (!REUSE) for (const target of targets) {
|
|
380
610
|
const map = byTarget.get(target);
|
|
381
611
|
const specs = [...repack].filter(([, r]) => r.platformSpecific).map(([name, r]) => ({ name, version: r.pkg.version }));
|
|
382
612
|
let crossTree = null;
|
|
@@ -394,7 +624,7 @@ function main() {
|
|
|
394
624
|
}
|
|
395
625
|
if (crossTree !== null) rmSync(crossTree, { recursive: true, force: true });
|
|
396
626
|
}
|
|
397
|
-
// 3) 聚合包(每平台一个):dependencies 用 npm: 别名把重打包包装回原名
|
|
627
|
+
// 3) 聚合包(每平台一个):dependencies 用 npm: 别名把重打包包装回原名(含 argon2)
|
|
398
628
|
for (const target of targets) {
|
|
399
629
|
const map = byTarget.get(target);
|
|
400
630
|
const aggName = `${SCOPE}/dsh-code-server-runtime-${target}`;
|
|
@@ -402,10 +632,13 @@ function main() {
|
|
|
402
632
|
mkdirSync(aggDir, { recursive: true });
|
|
403
633
|
const deps = {};
|
|
404
634
|
for (const [name] of repack) deps[name] = `npm:${map.get(name).pkgName}@${map.get(name).version}`;
|
|
635
|
+
// argon2:code-server 本体包不带原生二进制,由这里按平台装回原名 "argon2"
|
|
636
|
+
const argon2 = argon2ByTarget.get(target);
|
|
637
|
+
if (argon2 !== undefined) deps.argon2 = `npm:${argon2.name}@${argon2.version}`;
|
|
405
638
|
writeFileSync(join(aggDir, 'package.json'), JSON.stringify({
|
|
406
639
|
name: aggName,
|
|
407
640
|
version: pluginVersion,
|
|
408
|
-
description: `Prebuilt native modules for code-server on ${target} (node-pty, @vscode/sqlite3, kerberos, …), `
|
|
641
|
+
description: `Prebuilt native modules for code-server on ${target} (argon2, node-pty, @vscode/sqlite3, kerberos, …), `
|
|
409
642
|
+ 'so that installing the VS Code inner dependencies needs no build approval or C++ toolchain.',
|
|
410
643
|
os: [target.split('-')[0]],
|
|
411
644
|
cpu: [target.split('-')[1]],
|
|
@@ -419,14 +652,19 @@ function main() {
|
|
|
419
652
|
writeFileSync(join(OUT, 'pack-plan.json'), JSON.stringify(plan, null, 2) + '\n', 'utf8');
|
|
420
653
|
console.log(`[repack] 生成 ${plan.length} 个待打包目录 → repack/ (计划:repack/pack-plan.json)`);
|
|
421
654
|
|
|
422
|
-
// 4) 改写插件 package.json
|
|
655
|
+
// 4) 改写插件 package.json 的依赖:纯 JS 直装集 + code-server 本体包(平台无关);
|
|
656
|
+
// 平台专属的(16 个原生包 + argon2)通过聚合包按 os/cpu 自动选。
|
|
423
657
|
const pkgFile = join(pkgRoot, 'package.json');
|
|
424
658
|
const pluginPkg = readJson(pkgFile);
|
|
425
|
-
pluginPkg.dependencies = Object.fromEntries(
|
|
659
|
+
pluginPkg.dependencies = Object.fromEntries([
|
|
660
|
+
[codeServerPkg.name, codeServerPkg.version],
|
|
661
|
+
...declare.map((d) => [d.name, d.version]),
|
|
662
|
+
].sort(([a], [b]) => a.localeCompare(b)));
|
|
426
663
|
pluginPkg.optionalDependencies = Object.fromEntries(targets
|
|
427
664
|
.map((t) => [`${SCOPE}/dsh-code-server-runtime-${t}`, `^${pluginVersion}`]));
|
|
428
665
|
writeFileSync(pkgFile, JSON.stringify(pluginPkg, null, 2) + '\n', 'utf8');
|
|
429
|
-
console.log(`[repack] 已写入 package.json:dependencies ${
|
|
666
|
+
console.log(`[repack] 已写入 package.json:dependencies ${pluginPkg.dependencies ? Object.keys(pluginPkg.dependencies).length : 0} 个`
|
|
667
|
+
+ `(code-server 本体 + 纯 JS),optionalDependencies ${targets.length} 个平台聚合包`);
|
|
430
668
|
|
|
431
669
|
// 5) 可选:直接打包
|
|
432
670
|
if (DO_PACK) {
|
|
@@ -440,8 +678,8 @@ function main() {
|
|
|
440
678
|
console.log('[repack] 未加 --pack;在普通终端里执行 `node scripts/vendor-repacks.mjs --pack` 生成 tarball');
|
|
441
679
|
}
|
|
442
680
|
|
|
443
|
-
if (
|
|
444
|
-
rmSync(
|
|
681
|
+
if (autoSourceTree !== null) {
|
|
682
|
+
rmSync(autoSourceTree, { recursive: true, force: true });
|
|
445
683
|
console.log('[repack] 已清理自动准备的源树');
|
|
446
684
|
}
|
|
447
685
|
}
|
package/vendor/VENDOR.json
CHANGED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
// scripts/vendor-code-server-pkg.mjs — 把内置 code-server 树打成**平台专属子包**。
|
|
2
|
-
//
|
|
3
|
-
// 产物(每个目标一个,os/cpu 限定):
|
|
4
|
-
// repack/build/code-server-<target>/
|
|
5
|
-
// package.json @jinsiyu/dshcs-code-server-<target>@<code-server 版本>
|
|
6
|
-
// code-server/** 完整 code-server 树(out/ + lib/vscode + 自带的 136 个依赖)
|
|
7
|
-
//
|
|
8
|
-
// 为什么要放在子目录 code-server/ 而不是包根:npm/pnpm 打包**永远排除包根目录的 node_modules**,
|
|
9
|
-
// 放在被 files 覆盖的子目录里才会随包发布(主包 0.1.36 用的就是同一招)。
|
|
10
|
-
//
|
|
11
|
-
// 为什么子包不写 dependencies:那 136 个依赖已经作为文件打包在 code-server/node_modules 里,
|
|
12
|
-
// 写成 dependencies 会让 pnpm 再去 registry 装一份。留着 `dependencies` 字段的是嵌套的
|
|
13
|
-
// code-server/package.json(它只是普通文件,不被解析)。
|
|
14
|
-
//
|
|
15
|
-
// 平台差异只有 argon2 的原生二进制(win32-arm64 上游无预编译 → 打包期编译;
|
|
16
|
-
// win32-x64 用 `node-gyp rebuild --arch=x64` 现编,并校验 PE machine)。
|
|
17
|
-
//
|
|
18
|
-
// 用法:
|
|
19
|
-
// node scripts/vendor-code-server-pkg.mjs [--target win32-arm64,win32-x64] [--pack]
|
|
20
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
21
|
-
import { dirname, join, relative, resolve } from 'node:path';
|
|
22
|
-
import { fileURLToPath } from 'node:url';
|
|
23
|
-
import { spawnSync } from 'node:child_process';
|
|
24
|
-
|
|
25
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
26
|
-
const pkgRoot = resolve(here, '..');
|
|
27
|
-
const repackDir = join(pkgRoot, 'repack');
|
|
28
|
-
const buildDir = join(repackDir, 'build');
|
|
29
|
-
const tgzDir = join(repackDir, 'tgz');
|
|
30
|
-
const vendorTree = join(pkgRoot, 'vendor', 'code-server');
|
|
31
|
-
const npmCache = join(pkgRoot, '.npm-cache');
|
|
32
|
-
|
|
33
|
-
const argv = process.argv.slice(2);
|
|
34
|
-
const DO_PACK = argv.includes('--pack');
|
|
35
|
-
const TARGETS = (() => {
|
|
36
|
-
const i = argv.indexOf('--target');
|
|
37
|
-
if (i < 0 || argv[i + 1] === undefined) return [`${process.platform}-${process.arch}`];
|
|
38
|
-
return argv[i + 1].split(',').map((s) => s.trim()).filter(Boolean);
|
|
39
|
-
})();
|
|
40
|
-
|
|
41
|
-
const readJson = (p) => { try { return JSON.parse(readFileSync(p, 'utf8')); } catch { return null; } };
|
|
42
|
-
|
|
43
|
-
function npm(args, cwd) {
|
|
44
|
-
const cli = join(dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
|
45
|
-
const env = { ...process.env, npm_config_cache: npmCache, npm_config_update_notifier: 'false' };
|
|
46
|
-
const hasCli = existsSync(cli);
|
|
47
|
-
const cmd = hasCli ? process.execPath : (process.platform === 'win32' ? 'npm.cmd' : 'npm');
|
|
48
|
-
const full = hasCli ? [cli, ...args] : args;
|
|
49
|
-
const res = spawnSync(cmd, full, { cwd, shell: !hasCli && process.platform === 'win32', env, stdio: 'inherit' });
|
|
50
|
-
if ((res.status ?? 1) !== 0) throw new Error(`npm ${args.join(' ')} failed (${res.status})`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** PE machine(0x8664=x64 / 0xaa64=arm64),用于交叉编译后的静态校验。 */
|
|
54
|
-
function peMachine(file) {
|
|
55
|
-
try {
|
|
56
|
-
const b = readFileSync(file);
|
|
57
|
-
if (b[0] !== 0x4d || b[1] !== 0x5a) return null;
|
|
58
|
-
const off = b.readUInt32LE(0x3c);
|
|
59
|
-
if (b.toString('ascii', off, off + 4) !== 'PE\u0000\u0000') return null;
|
|
60
|
-
return `0x${b.readUInt16LE(off + 4).toString(16)}`;
|
|
61
|
-
} catch { return null; }
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** 为某个目标编译 argon2 原生模块(就地覆盖包内 build/Release/argon2.node)。 */
|
|
65
|
-
function buildArgon2(tree, arch) {
|
|
66
|
-
const argon2 = join(tree, 'node_modules', 'argon2');
|
|
67
|
-
if (!existsSync(join(argon2, 'binding.gyp'))) throw new Error(`argon2 不在位: ${argon2}`);
|
|
68
|
-
console.log(`[cs-pkg] 编译 argon2 (--arch=${arch}) …`);
|
|
69
|
-
const ng = join(process.env.APPDATA ?? '', 'npm', 'node_modules', 'node-gyp', 'bin', 'node-gyp.js');
|
|
70
|
-
const cli = existsSync(ng) ? ng : null;
|
|
71
|
-
if (cli === null) throw new Error('找不到 node-gyp(需全局安装 node-gyp)');
|
|
72
|
-
const res = spawnSync(process.execPath, [cli, 'rebuild', `--arch=${arch}`], { cwd: argon2, stdio: 'inherit' });
|
|
73
|
-
if ((res.status ?? 1) !== 0) throw new Error(`argon2 编译失败 (${res.status})`);
|
|
74
|
-
const bin = join(argon2, 'build', 'Release', 'argon2.node');
|
|
75
|
-
if (!existsSync(bin)) throw new Error(`argon2 编译产物缺失: ${bin}`);
|
|
76
|
-
return bin;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function main() {
|
|
80
|
-
if (!existsSync(join(vendorTree, 'out', 'node', 'entry.js'))) {
|
|
81
|
-
throw new Error('缺少 vendor/code-server;先运行 `node scripts/vendor-code-server.mjs`');
|
|
82
|
-
}
|
|
83
|
-
const csVersion = readJson(join(vendorTree, 'package.json'))?.version;
|
|
84
|
-
if (typeof csVersion !== 'string') throw new Error('读不到 code-server 版本');
|
|
85
|
-
const pluginPkg = readJson(join(pkgRoot, 'package.json'));
|
|
86
|
-
const scope = '@jinsiyu';
|
|
87
|
-
const hostKey = `${process.platform}-${process.arch}`;
|
|
88
|
-
const plan = [];
|
|
89
|
-
|
|
90
|
-
for (const target of TARGETS) {
|
|
91
|
-
const [platform, arch] = target.split('-');
|
|
92
|
-
if (platform === undefined || arch === undefined) throw new Error(`--target 需要 <platform>-<arch>,收到 ${target}`);
|
|
93
|
-
const outName = `code-server-${target}`;
|
|
94
|
-
const dir = join(buildDir, outName);
|
|
95
|
-
rmSync(dir, { recursive: true, force: true });
|
|
96
|
-
mkdirSync(dir, { recursive: true });
|
|
97
|
-
console.log(`[cs-pkg] 复制 vendor/code-server → ${relative(pkgRoot, join(dir, 'code-server'))}`);
|
|
98
|
-
cpSync(vendorTree, join(dir, 'code-server'), { recursive: true, dereference: false, maxRetries: 6, retryDelay: 250 });
|
|
99
|
-
|
|
100
|
-
const tree = join(dir, 'code-server');
|
|
101
|
-
// 目标架构的 argon2 原生二进制
|
|
102
|
-
const wantMachine = arch === 'x64' ? '0x8664' : arch === 'arm64' ? '0xaa64' : null;
|
|
103
|
-
const have = join(tree, 'node_modules', 'argon2', 'build', 'Release', 'argon2.node');
|
|
104
|
-
if (target !== hostKey) {
|
|
105
|
-
const bin = buildArgon2(tree, arch);
|
|
106
|
-
const m = peMachine(bin);
|
|
107
|
-
if (wantMachine !== null && m !== wantMachine) throw new Error(`argon2 PE machine=${m},期望 ${wantMachine}`);
|
|
108
|
-
console.log(`[cs-pkg] argon2 → ${relative(pkgRoot, bin)} (${m})`);
|
|
109
|
-
} else {
|
|
110
|
-
console.log(`[cs-pkg] argon2 沿用本机产物 (${peMachine(have) ?? '?'})`);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
writeFileSync(join(dir, 'package.json'), JSON.stringify({
|
|
114
|
-
name: `${scope}/dshcs-code-server-${target}`,
|
|
115
|
-
version: csVersion,
|
|
116
|
-
description: `Bundled code-server ${csVersion} tree for ${target} (out/ + lib/vscode + its ${readdirSync(join(tree, 'node_modules')).length} runtime deps), repacked so pnpm installs it without any build script.`,
|
|
117
|
-
os: [platform],
|
|
118
|
-
cpu: [arch],
|
|
119
|
-
files: ['code-server'],
|
|
120
|
-
license: 'MIT',
|
|
121
|
-
repository: pluginPkg?.repository ?? undefined,
|
|
122
|
-
}, null, 2) + '\n', 'utf8');
|
|
123
|
-
plan.push({ dir, file: `${`${scope}/dshcs-code-server-${target}`.replace(/^@/, '').replaceAll('/', '-')}-${csVersion}.tgz` });
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (DO_PACK) {
|
|
127
|
-
mkdirSync(tgzDir, { recursive: true });
|
|
128
|
-
for (const item of plan) {
|
|
129
|
-
console.log(`[cs-pkg] npm pack ${item.file}`);
|
|
130
|
-
npm(['pack', '--pack-destination', tgzDir], item.dir);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
console.log(`[cs-pkg] 完成:${plan.length} 个平台子包 → repack/build/${DO_PACK ? ' + repack/tgz/' : ''}`);
|
|
134
|
-
console.log('[cs-pkg] 下一步:`node scripts/publish-repacks.mjs --only dshcs-code-server` 发布(或用 --dry-run 预览)');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
main();
|