dsh-code-server-app 0.1.32 → 0.1.37
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 +134 -90
- package/README.md +123 -88
- package/lib/client.js +3 -3
- package/lib/index.js +159 -90
- package/lib/native.js +86 -0
- package/lib/vendor.js +107 -0
- package/package.json +59 -11
- package/scripts/vendor-code-server-pkg.mjs +137 -0
- package/scripts/vendor-code-server.mjs +293 -0
- package/scripts/vendor-repacks.mjs +449 -0
- package/vendor/VENDOR.json +9 -0
- package/scripts/setup-code-server.mjs +0 -239
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
// scripts/setup-code-server.mjs — 按需安装 code-server(Windows 兼容)。
|
|
2
|
-
//
|
|
3
|
-
// 背景:code-server 的官方 postinstall 是 `sh ./postinstall.sh`(依赖 bash/symlink),
|
|
4
|
-
// Windows 无 sh 会直接失败;pnpm 的 build-scripts 许可只认宿主根 pnpm-workspace.yaml,
|
|
5
|
-
// 依赖包声明无效。因此把 code-server 从 dependencies 移除,改由本脚本用 **npm** 安装:
|
|
6
|
-
// - npm 读取安装根 package.json 的 allowScripts(code-server:false 跳过 sh;argon2/unrs
|
|
7
|
-
// true 构建 native)——无需 --ignore-scripts,无需改宿主配置,零报错;
|
|
8
|
-
// - 安装落在 **profile 专用目录**(--prefix 钉死),不写全局、不动 profile 顶层。
|
|
9
|
-
//
|
|
10
|
-
// 调用时机(插件安装期没有 postinstall,安装过程零脚本):
|
|
11
|
-
// - host 运行时:POST /code-server/setup(启动安装指引弹窗「开始安装」/ 设置卡片「安装环境」);
|
|
12
|
-
// - 手动:npm run setup:code-server / node scripts/setup-code-server.mjs。
|
|
13
|
-
//
|
|
14
|
-
// 幂等:code-server 已实例化(entry + VS Code 内部依赖 + argon2 native 均在)且版本与
|
|
15
|
-
// npm latest 一致则跳过;版本不一致则升级(每次调用都重新检查 → 自愈)。
|
|
16
|
-
import { spawnSync } from 'node:child_process';
|
|
17
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync, copyFileSync, readdirSync, rmSync } from 'node:fs';
|
|
18
|
-
import { dirname, join } from 'node:path';
|
|
19
|
-
import { fileURLToPath } from 'node:url';
|
|
20
|
-
|
|
21
|
-
const here = dirname(fileURLToPath(import.meta.url)); // .../dsh-code-server/scripts
|
|
22
|
-
const pkgRoot = join(here, '..'); // <profile>\node_modules\dsh-code-server
|
|
23
|
-
|
|
24
|
-
// 不锁定 code-server 版本:安装时总是取 npm 最新版(latest)。
|
|
25
|
-
// 可用环境变量 DSHCS_CODE_SERVER_VERSION 显式锁版本(如 "4.134.0"),缺省为空 = latest。
|
|
26
|
-
|
|
27
|
-
function run(cmd, args, cwd) {
|
|
28
|
-
const useShell = process.platform === 'win32';
|
|
29
|
-
const res = spawnSync(cmd, args, { cwd, stdio: 'inherit', shell: useShell });
|
|
30
|
-
if (res.status !== 0) throw new Error(`${cmd} ${args.join(' ')} failed (${res.status})`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function npm(cmdArgs, cwd) {
|
|
34
|
-
run(process.platform === 'win32' ? 'npm.cmd' : 'npm', cmdArgs, cwd);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** 查询 npm 最新 code-server 版本;失败(离线/网络/权限)返回 null。
|
|
38
|
-
* 优先直连 registry JSON API(子进程 Node ESM,无 npm 缓存写);失败再试 npm view。 */
|
|
39
|
-
function latestCodeServerVersion() {
|
|
40
|
-
try {
|
|
41
|
-
const code = "const r=await fetch('https://registry.npmjs.org/code-server/latest');const j=await r.json();process.stdout.write(j&&j.version||'')";
|
|
42
|
-
const res = spawnSync(process.execPath, ['--input-type=module', '-e', code], { encoding: 'utf8' });
|
|
43
|
-
const v = String(res.stdout || '').trim();
|
|
44
|
-
if (v !== '' && /^\d+\./.test(v)) return v;
|
|
45
|
-
} catch { /* fall through */ }
|
|
46
|
-
try {
|
|
47
|
-
const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
48
|
-
const res = spawnSync(npmBin, ['view', 'code-server', 'version'], { encoding: 'utf8', shell: process.platform === 'win32' });
|
|
49
|
-
if (res.status === 0) {
|
|
50
|
-
const v = String(res.stdout || '').trim();
|
|
51
|
-
if (v !== '' && /^\d+\./.test(v)) return v;
|
|
52
|
-
}
|
|
53
|
-
} catch { /* fall through */ }
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** 待安装的版本:DSHCS_CODE_SERVER_VERSION 优先(显式锁定),否则 latest 查询,再否则 latest 安装。 */
|
|
58
|
-
function desiredVersion() {
|
|
59
|
-
const locked = process.env.DSHCS_CODE_SERVER_VERSION;
|
|
60
|
-
if (typeof locked === 'string' && locked.trim() !== '') return locked.trim();
|
|
61
|
-
return latestCodeServerVersion(); // null → npm install code-server(不带版本)=latest
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** 已安装版本(读 cs/package.json);读取失败返回 null。 */
|
|
65
|
-
function installedVersion(cs) {
|
|
66
|
-
try {
|
|
67
|
-
const pkg = JSON.parse(readFileSync(join(cs, 'package.json'), 'utf8'));
|
|
68
|
-
return typeof pkg.version === 'string' ? pkg.version : null;
|
|
69
|
-
} catch {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function ensureNpmDeps(dir) {
|
|
75
|
-
if (!existsSync(join(dir, 'package.json'))) return;
|
|
76
|
-
// --omit=dev:只装生产依赖(native 模块在依赖 postinstall 内建)
|
|
77
|
-
npm(['install', '--omit=dev', '--no-audit', '--no-fund'], dir);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** 专用安装根:<profile>\.code-server-app(如 C:\Users\User\.dsh\profiles\web\.code-server-app),
|
|
81
|
-
* 与 profile 依赖树隔离(避免 npm 在 profile 根解析其他插件依赖触发 ERESOLVE)。
|
|
82
|
-
* 最终 code-server 位于:<profile>\.code-server-app\node_modules\code-server */
|
|
83
|
-
const APP_DIR_NAME = '.code-server-app';
|
|
84
|
-
|
|
85
|
-
function profileRootOf() {
|
|
86
|
-
// pkgRoot = <profile>\node_modules\dsh-code-server;向上两级 = <profile> 根;
|
|
87
|
-
// 上层存在 node_modules + package.json 视为 profile 布局
|
|
88
|
-
const profileRoot = join(pkgRoot, '..', '..');
|
|
89
|
-
const isProfileLayout = existsSync(join(profileRoot, 'node_modules')) && existsSync(join(profileRoot, 'package.json'));
|
|
90
|
-
return isProfileLayout ? profileRoot : null;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function findCodeServer() {
|
|
94
|
-
// 布局候选(与安装目标同顺序):
|
|
95
|
-
// 1. profile 专用目录:profileRoot\code-server-app\node_modules\code-server
|
|
96
|
-
// 2. 包内:pkgRoot/node_modules/code-server(开发期 link:/独立目录)
|
|
97
|
-
const profileRoot = profileRootOf();
|
|
98
|
-
const cands = [];
|
|
99
|
-
if (profileRoot !== null) {
|
|
100
|
-
cands.push(join(profileRoot, APP_DIR_NAME, 'node_modules', 'code-server'));
|
|
101
|
-
}
|
|
102
|
-
cands.push(join(pkgRoot, 'node_modules', 'code-server'));
|
|
103
|
-
for (const cand of cands) {
|
|
104
|
-
if (existsSync(cand)) return cand;
|
|
105
|
-
}
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function isComplete(cs) {
|
|
110
|
-
return existsSync(join(cs, 'out', 'node', 'entry.js')) &&
|
|
111
|
-
existsSync(join(cs, 'lib', 'vscode', 'node_modules', '@vscode', 'ripgrep')) &&
|
|
112
|
-
(existsSync(join(cs, 'node_modules', 'argon2', 'build', 'Release', 'argon2.node')) ||
|
|
113
|
-
existsSync(join(cs, 'node_modules', 'argon2', 'prebuilds')));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** 安装目标:
|
|
117
|
-
* 1. profile 布局 → <profile>\code-server-app(npm --prefix 装到
|
|
118
|
-
* <profile>\code-server-app\node_modules\code-server,独立项目,无 ERESOLVE);
|
|
119
|
-
* 2. 否则回退包内(工作区/独立目录场景)。 */
|
|
120
|
-
function installPrefix() {
|
|
121
|
-
const profileRoot = profileRootOf();
|
|
122
|
-
return profileRoot !== null ? join(profileRoot, APP_DIR_NAME) : pkgRoot;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function installCodeServer() {
|
|
126
|
-
const prefix = installPrefix();
|
|
127
|
-
const want = desiredVersion();
|
|
128
|
-
const versionSpec = typeof want === 'string' && want !== '' ? `code-server@${want}` : 'code-server';
|
|
129
|
-
console.log(`[setup-code-server] npm 自装 ${versionSpec}(latest)${
|
|
130
|
-
want != null ? '' : ''}(target: ${prefix} → node_modules/code-server)${
|
|
131
|
-
prefix === pkgRoot ? '(包内回退)' : '(profile 专用目录)'}…`);
|
|
132
|
-
// npm 读取 prefix 项目自己的 package.json 的 allowScripts;在安装根写一个最小配置,
|
|
133
|
-
// 让 code-server:false(跳过官方 sh postinstall)、argon2/unrs:true(native 构建)生效。
|
|
134
|
-
// allowScripts 不带版本号(任何 argon2/unrs 版本都构建 native,避免版本变化后失配)。
|
|
135
|
-
const appPkg = join(prefix, 'package.json');
|
|
136
|
-
if (!existsSync(appPkg)) {
|
|
137
|
-
try {
|
|
138
|
-
mkdirSync(prefix, { recursive: true });
|
|
139
|
-
writeFileSync(appPkg, JSON.stringify({
|
|
140
|
-
name: 'dsh-code-server-app',
|
|
141
|
-
private: true,
|
|
142
|
-
version: '0.0.0',
|
|
143
|
-
allowScripts: { 'code-server': false, 'argon2': true, 'unrs-resolver': true },
|
|
144
|
-
}, null, 2), 'utf8');
|
|
145
|
-
} catch (e) {
|
|
146
|
-
console.warn('[setup-code-server] 安装根 package.json 写入失败(allowScripts 可能不生效):', e.message);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
npm([
|
|
150
|
-
'install', versionSpec,
|
|
151
|
-
'--no-save', '--no-audit', '--no-fund', '--prefix', prefix,
|
|
152
|
-
], prefix);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function main() {
|
|
156
|
-
let cs = findCodeServer();
|
|
157
|
-
const want = desiredVersion();
|
|
158
|
-
const have = cs !== null ? installedVersion(cs) : null;
|
|
159
|
-
// 升级判定独立于 isComplete:已有实例且(有 latest 且版本不同)→ 重装到最新。
|
|
160
|
-
if (want != null && have !== null && have !== want) {
|
|
161
|
-
console.log(`[setup-code-server] 当前 code-server@${have},最新 ${want}——自动升级…`);
|
|
162
|
-
installCodeServer();
|
|
163
|
-
cs = findCodeServer();
|
|
164
|
-
} else if (cs !== null && isComplete(cs)) {
|
|
165
|
-
console.log(`[setup-code-server] code-server 已实例化(entry + 内部依赖 + native 均在),跳过${
|
|
166
|
-
have !== null ? `(版本 ${have})` : ''}` + (want != null ? `;latest: ${want}` : ''));
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
if (cs === null || !existsSync(join(cs, 'out', 'node', 'entry.js'))) {
|
|
170
|
-
installCodeServer();
|
|
171
|
-
cs = findCodeServer();
|
|
172
|
-
}
|
|
173
|
-
if (cs === null) {
|
|
174
|
-
console.warn('[setup-code-server] code-server 安装失败(未找到);请检查网络/npm 环境');
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
console.log('[setup-code-server] 补装 VS Code 内部依赖与原生模块…');
|
|
179
|
-
const vscode = join(cs, 'lib', 'vscode');
|
|
180
|
-
ensureNpmDeps(vscode);
|
|
181
|
-
ensureNpmDeps(join(vscode, 'extensions'));
|
|
182
|
-
|
|
183
|
-
// bin 入口:Windows 上官方 postinstall 是 mklink /J;此处用 cmdshim 拷贝兜底
|
|
184
|
-
try {
|
|
185
|
-
const bin = join(cs, 'bin');
|
|
186
|
-
mkdirSync(bin, { recursive: true });
|
|
187
|
-
const scriptsDir = join(cs, 'lib', 'vscode', 'bin');
|
|
188
|
-
const remote = join(scriptsDir, 'remote-cli');
|
|
189
|
-
if (existsSync(remote)) {
|
|
190
|
-
for (const name of readdirSync(remote)) {
|
|
191
|
-
if (name.endsWith('.cmd')) {
|
|
192
|
-
copyFileSync(join(remote, name), join(bin, 'code-server.cmd'));
|
|
193
|
-
console.log(`[setup-code-server] bin/code-server.cmd <- ${name}`);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
} catch (e) {
|
|
198
|
-
console.warn('[setup-code-server] bin 入口建立失败(不影响 runtime 启动,host 走 entry.js):', e.message);
|
|
199
|
-
}
|
|
200
|
-
console.log('[setup-code-server] 完成;entry:', existsSync(join(cs, 'out', 'node', 'entry.js')));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/** 错误标记文件:安装失败时写入(host status 读取 → client 弹窗给用户查看),
|
|
204
|
-
* 成功安装后删除。位置 = 安装根(与安装产物同目录,独立于 pnpm 日志)。 */
|
|
205
|
-
function errorMarkerPath() {
|
|
206
|
-
return join(installPrefix(), 'last-setup-error.json');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function writeErrorMarker(err) {
|
|
210
|
-
try {
|
|
211
|
-
const p = errorMarkerPath();
|
|
212
|
-
mkdirSync(dirname(p), { recursive: true });
|
|
213
|
-
writeFileSync(p, JSON.stringify({
|
|
214
|
-
at: new Date().toISOString(),
|
|
215
|
-
error: err && err.message ? err.message : String(err),
|
|
216
|
-
}, null, 2), 'utf8');
|
|
217
|
-
} catch { /* 标记失败不影响主流程 */ }
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function clearErrorMarker() {
|
|
221
|
-
try {
|
|
222
|
-
const p = errorMarkerPath();
|
|
223
|
-
if (existsSync(p)) rmSync(p, { force: true });
|
|
224
|
-
} catch { /* ignore */ }
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
main();
|
|
229
|
-
clearErrorMarker();
|
|
230
|
-
} catch (e) {
|
|
231
|
-
const msg = errText(e);
|
|
232
|
-
console.error('[setup-code-server] 安装失败(插件仍可启动;README 有恢复指引):', msg);
|
|
233
|
-
writeErrorMarker(e);
|
|
234
|
-
process.exitCode = 0; // 不阻断 pnpm/npm install
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function errText(e) {
|
|
238
|
-
return e && e.message ? e.message : String(e);
|
|
239
|
-
}
|