dsh-code-server-app 0.3.13 → 0.3.15

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/lib/index.js CHANGED
@@ -276,11 +276,14 @@ export function clearObsoleteMarkers(extensionsDir, ids) {
276
276
  /** 内置扩展安装:每次启动调用 —— 缺失**或内容有变化**即同步(自愈,且插件升级后能更新已装的旧副本)。
277
277
  * 源目录里已不存在的文件会从目标里删掉(否则旧版本的 `lib/` 会一直留着)。
278
278
  * 同时清理"放错位置"的旧副本(用户级/内置两份同时存在会让 VS Code 打架),并清掉 `.obsolete` 自锁标记。
279
- * 导出供测试直接调(apply 期不装扩展,只有 start 才装);`options.treeRoot` 供测试注入假树。 */
279
+ * 导出供测试直接调(apply 期不装扩展,只有 start 才装);`options.treeRoot` 供测试注入假树。
280
+ * @returns {{updated: string[], cleared: string[]}} `updated` = 本次真的写了文件/删了文件的扩展名
281
+ * (adopt 路径据此判断"运行中的 IDE 里是旧代码");`cleared` = 本次清掉的 `.obsolete` 键。 */
280
282
  export function installBundledExtensions(extensionsDir, userDataDir, options = {}) {
281
283
  const here = path.dirname(fileURLToPath(import.meta.url));
282
284
  const treeRoot = options.treeRoot === undefined ? vsRoot() : options.treeRoot;
283
285
  const managedIds = [];
286
+ const updated = [];
284
287
  for (const ext of BUNDLED_EXTENSIONS) {
285
288
  try {
286
289
  const src = path.join(here, '..', 'assets', 'extensions', ext.name);
@@ -332,6 +335,7 @@ export function installBundledExtensions(extensionsDir, userDataDir, options = {
332
335
  }
333
336
  console.log(`[code-server] bundled extension ${ext.name} -> ${dst}${target.builtin ? ' (内置,不可卸载)' : ' (用户级,可禁用)'}`
334
337
  + `${stale.length > 0 ? ` [更新 ${stale.join(',')}]` : ''}${removed.length > 0 ? ` [清理 ${removed.join(',')}]` : ''}`);
338
+ if (stale.length > 0 || removed.length > 0) updated.push(ext.name);
335
339
  } catch (err) {
336
340
  console.warn(`[code-server] bundled extension ${ext.name} install failed:`, err && err.message ? err.message : String(err));
337
341
  }
@@ -342,6 +346,7 @@ export function installBundledExtensions(extensionsDir, userDataDir, options = {
342
346
  + '(留着的话扫描器会永远跳过这些扩展,编辑器桥就永远没有状态)');
343
347
  }
344
348
  void userDataDir;
349
+ return { updated, cleared };
345
350
  }
346
351
 
347
352
  /** 打开文件信号文件:<user-data>/User/dshcs-open.json(扩展轮询此文件)。 */
@@ -349,6 +354,36 @@ function openFileSignalPath(userDataDir) {
349
354
  return path.join(userDataDir, 'User', 'dshcs-open.json');
350
355
  }
351
356
 
357
+ /** 已安装的内置扩展里最新的文件 mtime(ms);取不到返回 null。
358
+ *
359
+ * 用途:**adopt(接管正在运行的 IDE)时判断"里面跑的是不是升级前的旧代码"**。
360
+ * 扩展代码只在扩展宿主进程启动时被加载一次 —— 文件是新的不代表跑着的进程里是新的。
361
+ * `mtime > IDE 进程启动时间` 说明这些文件是在该进程起来之后写的,那个进程不可能加载过它们。
362
+ * (可能偏保守:之后重载过窗口就没事了 —— 所以提示写成"可能/重载即可"。) */
363
+ export function newestBundledExtensionMtime(extensionsDir, options = {}) {
364
+ const treeRoot = options.treeRoot === undefined ? vsRoot() : options.treeRoot;
365
+ let newest = null;
366
+ for (const ext of BUNDLED_EXTENSIONS) {
367
+ const target = extensionTarget(extensionsDir, ext.name, ext.placement, treeRoot);
368
+ if (!fs.existsSync(target.dst)) continue;
369
+ let files;
370
+ try {
371
+ files = listExtensionFiles(target.dst);
372
+ } catch {
373
+ continue;
374
+ }
375
+ for (const rel of files) {
376
+ try {
377
+ const at = fs.statSync(path.join(target.dst, rel)).mtimeMs;
378
+ if (newest === null || at > newest) newest = at;
379
+ } catch {
380
+ // 单个文件 stat 失败不影响结论
381
+ }
382
+ }
383
+ }
384
+ return newest;
385
+ }
386
+
352
387
  /** 插件 package.json 里声明的内部依赖(纯 JS 直装集;排除 VS Code 树包本身)。 */
353
388
  function declaredInnerDeps() {
354
389
  try {
@@ -1185,6 +1220,13 @@ export async function apply(ctx, config) {
1185
1220
  console.warn('[code-server] 0.2.0 起不再支持口令认证(argon2 已移除),按 auth=none 运行');
1186
1221
  }
1187
1222
 
1223
+ // 数据目录(adopt 路径也要用:被接管的 IDE 同样需要最新的内置扩展文件)
1224
+ const root = dataRoot(cfg);
1225
+ const userDataDir = cfg.userDataDir || path.join(root, 'user-data');
1226
+ const extensionsDir = cfg.extensionsDir || path.join(root, 'extensions');
1227
+ fs.mkdirSync(userDataDir, { recursive: true });
1228
+ fs.mkdirSync(extensionsDir, { recursive: true });
1229
+
1188
1230
  // 端口占用则尝试 adopt(仅"显式指定端口"时;默认 port=0 由系统分配,不存在占用问题)。
1189
1231
  // 探针必须带路径令牌(被接管的实例是我们自己拉的,令牌在令牌文件里)——
1190
1232
  // 没有令牌文件说明那个实例不是本插件当前这代拉起来的,不接管。
@@ -1203,6 +1245,20 @@ export async function apply(ctx, config) {
1203
1245
  state.launchCwd = record.launchCwd ?? record.cwd ?? null;
1204
1246
  state.startedAt = record.startedAt ?? null;
1205
1247
  state.adopted = true;
1248
+ // 被接管的 IDE **不会**重新加载扩展:文件可以同步,但扩展宿主里跑的仍是上次启动时那份代码。
1249
+ // 桥的传输/协议变更(0.3.13 的 url → pipe)会让旧代码读到 v2 配置后休眠 —— 必须明说,否则
1250
+ // 表现又是那句无法自查的"编辑器还没有上报状态"。
1251
+ const synced = installBundledExtensions(extensionsDir, userDataDir);
1252
+ const newest = newestBundledExtensionMtime(extensionsDir);
1253
+ const staleCode = synced.updated.length > 0
1254
+ || (newest !== null && record.startedAt !== null && newest > record.startedAt);
1255
+ if (staleCode) {
1256
+ console.warn('[code-server] 内置扩展文件比当前 IDE 进程新'
1257
+ + `${synced.updated.length > 0 ? `(本次更新:${synced.updated.join(',')})` : ''}:`
1258
+ + '被接管的 IDE 不会重新加载扩展,里面跑的**可能仍是旧代码**。'
1259
+ + '若编辑器桥没有状态(editor_context 报"编辑器还没有上报状态"),'
1260
+ + '请在 Code Server 标签里重载一次窗口(或重启 IDE)让扩展宿主读到新代码');
1261
+ }
1206
1262
  adoptBridgeRuntime(record.pid, state.startedAt);
1207
1263
  return snapshot();
1208
1264
  }
@@ -1212,13 +1268,6 @@ export async function apply(ctx, config) {
1212
1268
  }
1213
1269
  }
1214
1270
 
1215
- // 重建数据目录
1216
- const root = dataRoot(cfg);
1217
- const userDataDir = cfg.userDataDir || path.join(root, 'user-data');
1218
- const extensionsDir = cfg.extensionsDir || path.join(root, 'extensions');
1219
- fs.mkdirSync(userDataDir, { recursive: true });
1220
- fs.mkdirSync(extensionsDir, { recursive: true });
1221
-
1222
1271
  // 安装树内自带扩展(dshcs-open-file:host 信号文件 → VS Code 打开文件;
1223
1272
  // dshcs-editor-bridge:编辑器桥的扩展侧,0.3.0)
1224
1273
  installBundledExtensions(extensionsDir, userDataDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-code-server-app",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "VS Code (from a code-server release) inside DSH: a right-sidebar tab driven by the plugin's own launcher over the in-process VS Code server (lib/launcher.mjs). Since 0.3.0 the bundle also ships an editor bridge (assets/extensions/dshcs-editor-bridge): a read-only channel between the in-tree VS Code extension host and DSH, giving the agent what only the editor knows (unsaved buffers, language-server diagnostics, the active selection) and letting editor gestures drive the session. The tab claims DSH file addresses (dsh-resource://file/**) by file type (setting claimExtensions), so the product's own produced-file chips, delivered-file previews and inline prose mentions open in the workbench. The IDE is a resident surface moved with Element.moveBefore instead of being remounted, so switching sidebar tabs no longer reloads it. Opening the tab switches the right sidebar to fullscreen by default (setting fullscreenOnOpen). Following a workspace switch is lightweight: the workbench re-navigates with the new ?folder= and the IDE process is not restarted (since 0.2.12). Requires a DSH with the right-sidebar services (sidebarRightTabs/sidebarRight, >= 0.1.5-alpha.1); older DSH versions get a single upgrade notice on the settings page and no other UI. Two serving modes: loopback port (default) or same-origin mount on DSH's own webServer (/code-server, protected by ctx.connection.requestRejection). No code-server Node layer, no argon2, no C++ toolchain.",
5
5
  "homepage": "https://github.com/jinsiyu/dsh-code-server-app",
6
6
  "repository": {
@@ -3,7 +3,7 @@
3
3
  "vscodeVersion": "1.137.0",
4
4
  "productPath": "stable-b11dabdaca0d3369986975be285db92c8795cea5",
5
5
  "layout": "vscode-only",
6
- "preparedAt": "2026-09-13T05:03:27.361Z",
6
+ "preparedAt": "2026-09-13T05:15:19.676Z",
7
7
  "source": "registry",
8
8
  "node": "v24.21.0",
9
9
  "platform": "win32",