dsh-code-server-app 0.1.41 → 0.1.43
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 +15 -3
- package/README.md +13 -3
- package/lib/index.js +14 -11
- package/lib/native.js +99 -1
- package/package.json +3 -1
- package/vendor/VENDOR.json +1 -1
package/README.en.md
CHANGED
|
@@ -61,11 +61,22 @@ pnpm run build:client # src/factory.js → lib/client.js (not committed; must
|
|
|
61
61
|
pnpm run vendor:check # optional: show the bundled code-server version vs npm latest
|
|
62
62
|
pnpm run vendor:code-server # ① produce vendor/code-server (the upstream tree)
|
|
63
63
|
pnpm run repack:build -- --target win32-arm64,win32-x64 --pack # ② one script builds every sub-package
|
|
64
|
-
pnpm run publish:repacks # ③ publish every @jinsiyu/* sub-package
|
|
64
|
+
pnpm run publish:repacks # ③ publish every @jinsiyu/* sub-package (default dist-tag: next)
|
|
65
65
|
pnpm pack # ④ → dsh-code-server-app-<version>.tgz (~107KB)
|
|
66
|
-
|
|
66
|
+
pnpm run publish:plugin # ⑤ publish the plugin itself (default dist-tag: next)
|
|
67
|
+
# once the user has restarted dsh web and confirmed it works, promote latest:
|
|
68
|
+
pnpm run promote -- <version>
|
|
67
69
|
```
|
|
68
70
|
|
|
71
|
+
> **dist-tag policy (mandatory)**: every release goes to **`next`** and **never touches `latest`**;
|
|
72
|
+
> `latest` always points at the most recent *confirmed bug-free* version and is only moved by
|
|
73
|
+
> `pnpm run promote -- <version>` (= `npm dist-tag add dsh-code-server-app@<version> latest`)
|
|
74
|
+
> **after the user restarts `dsh web` and confirms it works**. That way
|
|
75
|
+
> `dsh plugin add dsh-code-server-app` (no version) — and anything else resolving `latest` — never picks up an
|
|
76
|
+
> unverified build. Sub-packages (`@jinsiyu/dshcs-*`, the aggregators) are referenced by exact/caret versions,
|
|
77
|
+
> so their dist-tags do not affect resolution, but they default to `next` as well.
|
|
78
|
+
> Inspect the current tags with `npm dist-tag ls dsh-code-server-app`.
|
|
79
|
+
|
|
69
80
|
`repack:build` (`scripts/vendor-repacks.mjs`) is the **single script that produces every sub-package**:
|
|
70
81
|
|
|
71
82
|
| Sub-package | Content | os/cpu |
|
|
@@ -83,7 +94,8 @@ npm publish dsh-code-server-app-<version>.tgz --access public # ⑤ publish th
|
|
|
83
94
|
| **Rebuild every sub-package** | `pnpm run repack:build -- --target win32-arm64,win32-x64 --pack` (without `--from` it npm-installs and compiles the source tree itself — slow) |
|
|
84
95
|
| **Rebuild only the code-server/argon2 packages** | `node scripts/vendor-repacks.mjs --reuse --target win32-arm64,win32-x64 --pack` (reuses the natives already in `repack/build`, no source-tree analysis) |
|
|
85
96
|
| **Publish sub-packages** | `pnpm run publish:repacks` (`--dry-run` to preview; `--only <substr>` to filter; `--otp <code>` / `--limit N` for 2FA) |
|
|
86
|
-
| **Publish the plugin itself** | `
|
|
97
|
+
| **Publish the plugin itself** | `pnpm run publish:plugin` (publishes the exact tarball that was verified; no re-packing; default dist-tag `next`) |
|
|
98
|
+
| **Promote `latest`** | `pnpm run promote -- <version>` (only after the user restarted and confirmed; `--dry-run` shows the current tags first) |
|
|
87
99
|
| **Just report versions** | `pnpm run vendor:check` |
|
|
88
100
|
|
|
89
101
|
> `pnpm pack`'s `prepack` runs the vendor-code-server script once; when `vendor/code-server` already exists it is
|
package/README.md
CHANGED
|
@@ -70,11 +70,20 @@ pnpm run build:client # src/factory.js → lib/client.js(不入库,必须先
|
|
|
70
70
|
pnpm run vendor:check # 可选:查看内置 code-server 版本 vs npm 最新版
|
|
71
71
|
pnpm run vendor:code-server # ① 生成 vendor/code-server(上游 code-server 树)
|
|
72
72
|
pnpm run repack:build -- --target win32-arm64,win32-x64 --pack # ② 统一脚本产出全部子包(见下表)
|
|
73
|
-
pnpm run publish:repacks # ③ 发布全部 @jinsiyu/* 子包(
|
|
73
|
+
pnpm run publish:repacks # ③ 发布全部 @jinsiyu/* 子包(默认 dist-tag = next)
|
|
74
74
|
pnpm pack # ④ → dsh-code-server-app-<version>.tgz(约 107KB)
|
|
75
|
-
|
|
75
|
+
pnpm run publish:plugin # ⑤ 发布插件本体(默认 dist-tag = next)
|
|
76
|
+
# 用户重启 dsh web 确认无误后,再把 latest 推进到该版本:
|
|
77
|
+
pnpm run promote -- <version>
|
|
76
78
|
```
|
|
77
79
|
|
|
80
|
+
> **dist-tag 政策(必须遵守)**:发布一律发到 **`next`**,**不动 `latest`**;
|
|
81
|
+
> `latest` 只保留「最近一个确认无 bug 的版本」,由 `pnpm run promote -- <version>`
|
|
82
|
+
> (= `npm dist-tag add dsh-code-server-app@<version> latest`)在**用户重启 dsh web 确认无误后**才推进。
|
|
83
|
+
> 这样 `dsh plugin add dsh-code-server-app`(不带版本)和任何按 latest 安装的流程都不会拿到未验证的版本。
|
|
84
|
+
> 子包(`@jinsiyu/dshcs-*`、聚合包)被依赖以精确/插入符版本引用,dist-tag 不影响解析,但同样默认发 `next`。
|
|
85
|
+
> 查看当前标签:`npm dist-tag ls dsh-code-server-app`。
|
|
86
|
+
|
|
78
87
|
`repack:build`(`scripts/vendor-repacks.mjs`)是**唯一的子包产出脚本**,一次生成:
|
|
79
88
|
|
|
80
89
|
| 子包 | 内容 | os/cpu |
|
|
@@ -92,7 +101,8 @@ npm publish dsh-code-server-app-<version>.tgz --access public # ⑤ 发布插
|
|
|
92
101
|
| **完整重打子包** | `pnpm run repack:build -- --target win32-arm64,win32-x64 --pack`(不给 `--from` 会自动 npm install 解包 + 编译,耗时) |
|
|
93
102
|
| **只重打 code-server/argon2 包** | `node scripts/vendor-repacks.mjs --reuse --target win32-arm64,win32-x64 --pack`(复用 `repack/build` 里已有的原生包,不重新分析源树) |
|
|
94
103
|
| **发布子包** | `pnpm run publish:repacks`(`--dry-run` 预览;`--only <子串>` 过滤;`--otp <code>` / `--limit N` 应对 2FA) |
|
|
95
|
-
| **发布插件本体** | `
|
|
104
|
+
| **发布插件本体** | `pnpm run publish:plugin`(发布**已验证过的那份 tarball**,不会重新打包;默认 dist-tag = `next`) |
|
|
105
|
+
| **推进 latest** | `pnpm run promote -- <version>`(用户重启确认无误后;`--dry-run` 先看当前标签) |
|
|
96
106
|
| **只报告版本** | `pnpm run vendor:check` |
|
|
97
107
|
|
|
98
108
|
> `pnpm pack` 的 `prepack` 会自动跑一次 `vendor-code-server` 脚本;`vendor/code-server` 已存在时它是
|
package/lib/index.js
CHANGED
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
vendoredVersion,
|
|
49
49
|
vendorReady,
|
|
50
50
|
} from './vendor.js';
|
|
51
|
-
import { aliasNodePathDirs,
|
|
51
|
+
import { aliasNodePathDirs, ensureRuntimeLayout, resolveNativeDir, resolveRuntime, runtimePackageName, verifyNatives } from './native.js';
|
|
52
52
|
|
|
53
53
|
// schemastery 由 DSH 部署自带(官方核心依赖),仿 auto-open-web 的解析策略:
|
|
54
54
|
// 常规 import 优先,不可用时回退到全局 npm 布局的 DSH 部署副本。
|
|
@@ -645,8 +645,8 @@ export async function apply(ctx, config) {
|
|
|
645
645
|
|
|
646
646
|
let proc;
|
|
647
647
|
try {
|
|
648
|
-
//
|
|
649
|
-
|
|
648
|
+
// 启动前再自愈一次依赖布局(插件重装/树被替换后可能丢失;幂等且只做存在性检查)
|
|
649
|
+
ensureRuntimeLayout();
|
|
650
650
|
const isCmd = launch.kind === 'bin' && win32() && /\.cmd$/i.test(launch.command);
|
|
651
651
|
const command = launch.kind === 'node' ? process.execPath : launch.command;
|
|
652
652
|
const spawnArgs = launch.kind === 'node' ? [launch.script, ...args] : args;
|
|
@@ -880,14 +880,17 @@ export async function apply(ctx, config) {
|
|
|
880
880
|
}
|
|
881
881
|
|
|
882
882
|
state.env = envCheck();
|
|
883
|
-
//
|
|
884
|
-
// (
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
if (
|
|
890
|
-
console.
|
|
883
|
+
// 补齐 code-server 树里被"拍平"掉的依赖布局:
|
|
884
|
+
// ① VS Code 内部依赖目录(lib/vscode/node_modules、lib/vscode/extensions/node_modules)
|
|
885
|
+
// —— 老模型是 npm 装在树里的真实目录,新模型拍平在 profile 根;用显式路径找依赖的代码
|
|
886
|
+
// (如内置 TS 扩展找 tsserver.js)否则会报 "tsserver was deleted …";
|
|
887
|
+
// ② 聚合包带回的原生别名(ESM import 不认 NODE_PATH,只能靠目录链)。
|
|
888
|
+
const layout = ensureRuntimeLayout();
|
|
889
|
+
if (layout.created.length > 0) {
|
|
890
|
+
console.log(`[code-server] 已补齐 ${layout.created.length} 个依赖链接: ${layout.created.join(', ')}`);
|
|
891
|
+
}
|
|
892
|
+
if (layout.failed.length > 0) {
|
|
893
|
+
console.warn(`[code-server] 依赖链接创建失败: ${layout.failed.join('; ')}`);
|
|
891
894
|
}
|
|
892
895
|
if (!vendorReady()) {
|
|
893
896
|
console.warn(`[code-server] 找不到 code-server 运行树:平台子包 ${codeServerPackageName()} 未安装,`
|
package/lib/native.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// 2. 从 code-server 运行位置出发校验这些模块是否真的能 require 到;
|
|
14
14
|
// 3. 必要时在 code-server 树里补齐别名 junction(ESM import 不认 NODE_PATH,只能靠目录链)。
|
|
15
15
|
import { createRequire } from 'node:module';
|
|
16
|
-
import { existsSync, readFileSync, mkdirSync, symlinkSync } from 'node:fs';
|
|
16
|
+
import { existsSync, readFileSync, mkdirSync, symlinkSync, lstatSync, rmSync } from 'node:fs';
|
|
17
17
|
import { dirname, join } from 'node:path';
|
|
18
18
|
import { PACKAGE_ROOT, codeServerRoot, profileRootOf } from './vendor.js';
|
|
19
19
|
|
|
@@ -162,3 +162,101 @@ export function ensureAliasLinks() {
|
|
|
162
162
|
}
|
|
163
163
|
return { created, failed };
|
|
164
164
|
}
|
|
165
|
+
|
|
166
|
+
/** 从**插件依赖图**解析(插件 node_modules → <profile>/node_modules),返回**真正的包根目录**
|
|
167
|
+
* (有些包 `exports` 不暴露 `./package.json`,只能从入口文件往上找 name 匹配的目录)。
|
|
168
|
+
* 与 `resolveNativeDir` 的区别:不走 code-server 树(树里可能有别的同名版本,例如 code-server 自带的
|
|
169
|
+
* typescript 5.9.3,而 VS Code 要的是 inner deps 里那份)。 */
|
|
170
|
+
function packageRootFromPlugin(name) {
|
|
171
|
+
let from;
|
|
172
|
+
try {
|
|
173
|
+
from = createRequire(join(PACKAGE_ROOT, 'package.json'));
|
|
174
|
+
} catch { return null; }
|
|
175
|
+
try {
|
|
176
|
+
return dirname(from.resolve(`${name}/package.json`));
|
|
177
|
+
} catch { /* exports 未暴露 package.json → 退回入口文件 */ }
|
|
178
|
+
try {
|
|
179
|
+
let dir = dirname(from.resolve(name));
|
|
180
|
+
for (let i = 0; i < 8; i += 1) {
|
|
181
|
+
try {
|
|
182
|
+
const manifest = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
|
|
183
|
+
if (manifest.name === name) return dir;
|
|
184
|
+
} catch { /* 继续往上 */ }
|
|
185
|
+
const parent = dirname(dir);
|
|
186
|
+
if (parent === dir) break;
|
|
187
|
+
dir = parent;
|
|
188
|
+
}
|
|
189
|
+
} catch { /* 解析不了 */ }
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** 路径上是否已有东西(**包括断链的 junction**:code-server 树被 pnpm 重装后旧链接会变成断链,
|
|
194
|
+
* `existsSync` 对断链返回 false,直接再建会 EPERM)。 */
|
|
195
|
+
function pathEntryExists(target) {
|
|
196
|
+
try {
|
|
197
|
+
lstatSync(target);
|
|
198
|
+
return true;
|
|
199
|
+
} catch {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** 把 VS Code 的「内部依赖目录」用 junction 补回老布局。
|
|
205
|
+
*
|
|
206
|
+
* 为什么需要:老模型里 `lib/vscode/node_modules` 与 `lib/vscode/extensions/node_modules` 是 npm 在树里
|
|
207
|
+
* 装出来的**真实目录**;新模型把同一批依赖拍平装在 `<profile>/node_modules`,靠模块解析往上层找没问题,
|
|
208
|
+
* 但**用显式路径拼依赖的代码会失效** —— 例如内置 TypeScript 扩展(1.136.1 实测):
|
|
209
|
+
* `path.join(extensionPath, '..', 'node_modules', 'typescript', 'lib', 'tsserver.js')`
|
|
210
|
+
* 找不到就弹 "VS Code's tsserver was deleted by another application …"。
|
|
211
|
+
* 这里按两个 package.json 的 dependencies 逐个补 junction(指向插件依赖图里的真实包),幂等、可自愈。
|
|
212
|
+
* @returns {{created:string[], failed:string[]}} */
|
|
213
|
+
export function ensureInnerModuleLinks() {
|
|
214
|
+
const csRoot = codeServerRoot();
|
|
215
|
+
if (csRoot === null) return { created: [], failed: [] };
|
|
216
|
+
const vscode = join(csRoot, 'lib', 'vscode');
|
|
217
|
+
const targets = [
|
|
218
|
+
{ manifest: join(vscode, 'package.json'), dir: join(vscode, 'node_modules') },
|
|
219
|
+
{ manifest: join(vscode, 'extensions', 'package.json'), dir: join(vscode, 'extensions', 'node_modules') },
|
|
220
|
+
];
|
|
221
|
+
const created = [];
|
|
222
|
+
const failed = [];
|
|
223
|
+
for (const { manifest, dir } of targets) {
|
|
224
|
+
let deps;
|
|
225
|
+
try {
|
|
226
|
+
deps = JSON.parse(readFileSync(manifest, 'utf8')).dependencies ?? {};
|
|
227
|
+
} catch { continue; }
|
|
228
|
+
for (const name of Object.keys(deps)) {
|
|
229
|
+
const link = join(dir, name);
|
|
230
|
+
if (existsSync(join(link, 'package.json'))) continue; // 链接有效(真实目录或有效 junction)
|
|
231
|
+
if (pathEntryExists(link)) {
|
|
232
|
+
// 断链(树被重装过)→ 清掉重建
|
|
233
|
+
try {
|
|
234
|
+
rmSync(link, { recursive: true, force: true });
|
|
235
|
+
} catch (error) {
|
|
236
|
+
failed.push(`${name}: 旧链接清理失败 ${error && error.code ? error.code : error}`);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const target = packageRootFromPlugin(name);
|
|
241
|
+
if (target === null) continue; // 该依赖没装(envCheck 会另行报告)
|
|
242
|
+
try {
|
|
243
|
+
mkdirSync(dirname(link), { recursive: true });
|
|
244
|
+
symlinkSync(target, link, process.platform === 'win32' ? 'junction' : 'dir');
|
|
245
|
+
created.push(name);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
failed.push(`${name}: ${error && error.code ? error.code : error}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return { created, failed };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** 一次性补齐两类链接:VS Code 内部依赖目录 + 聚合包别名。 */
|
|
255
|
+
export function ensureRuntimeLayout() {
|
|
256
|
+
const inner = ensureInnerModuleLinks();
|
|
257
|
+
const aliases = ensureAliasLinks();
|
|
258
|
+
return {
|
|
259
|
+
created: [...inner.created, ...aliases.created],
|
|
260
|
+
failed: [...inner.failed, ...aliases.failed],
|
|
261
|
+
};
|
|
262
|
+
}
|
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.43",
|
|
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": {
|
|
@@ -106,6 +106,8 @@
|
|
|
106
106
|
"vendor:check": "node scripts/vendor-code-server.mjs --check",
|
|
107
107
|
"repack:build": "node scripts/vendor-repacks.mjs",
|
|
108
108
|
"publish:repacks": "node scripts/publish-repacks.mjs",
|
|
109
|
+
"publish:plugin": "node scripts/publish-plugin.mjs",
|
|
110
|
+
"promote": "node scripts/promote.mjs",
|
|
109
111
|
"build:client": "node scripts/build-client.mjs"
|
|
110
112
|
}
|
|
111
113
|
}
|