dsh-vscode-mode 0.21.2 → 0.21.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -477,19 +477,20 @@ DSH 每次启动监听随机端口,`http://127.0.0.1:<port>` 就是浏览器 o
477
477
 
478
478
  官方 `dsh plugin` 方式,三选一。下面以 `web` profile 为例;Desktop 或其他命名
479
479
  profile 请替换为实际目标,不要把示例目录当成当前运行 profile。升级前可阅读
480
+ **v0.21.3** 的 MCP 初始化失败结果与安全收尾解耦:已进入 startup 的调用者在失败或截止时间到达时及时收到拒绝,不再等待旧资源收尾;旧 work/close 未确认完成前仍占冷启动名额、阻止同 key 重建,确认收尾后才开始冷却。首次偶发超时根因仍未知,排队和其他屏障仍可能无界;本版当前 Host/GUI 未部署未验证,用户仅本批接受官方实装隔离模块与 JS 套件替代验收,见 [0.21.3 发布说明](docs/release-0.21.3.md)。官方 bridge 隔离 fixture 同步迁移到当前公开 native 执行器及批调用契约,不代表生产执行器故障修复。以下为历史版本事实,不代表本版现场验收:
480
481
  **v0.21.2** 的新版 DSH 会话 Controller 与 MCP 公开工具目录适配:任务发送按目标会话持有生命周期,受理不明时不跨通道重发;文件范围引用的剪贴板与降级文本保留行区间;MCP 初始化失败增加脱敏持久化诊断。当前 Web Host 已完成真实 CodeGraph 调用,但首次连接偶发超时根因尚未证实,不宣称已修复,见 [0.21.2 发布说明](docs/release-0.21.2.md)。保留以下历史版本能力与验收边界:
481
482
  **v0.21.1** 修复缺失历史文件:按完整快照显示整文件删除,Keep 保留删除、Undo 安全恢复快照,预览只读且拒绝覆盖重新出现的文件;真实 GUI 验收缺口已明确保留,见 [0.21.1 发布说明](docs/release-0.21.1.md)。保留 **v0.21.0** 新增 XLSX 基础编辑与浏览器导出副本,原件不自动写回,高级应用通过官方 Host 打开;官方差异定位统一 BOM 与 LF/CRLF/混合行尾口径,并区分内容缺失和多处命中。定位修复不扩展 CRLF patch Undo 能力,目标官方记录 ↑/↓ 的真实点击验收仍保留缺口。保留 **v0.20.5** 跨 DSH 实例只读互通——桌面端与 Web 端各自运行独立宿主时,官方审查列表/详情与工作区只读接口改按持久化会话头的 cwd 解析,另一实例创建的会话也能只读打开官方差异栏,写入类接口仍要求本端活跃会话。保留 **v0.20.4** 统一两套差异栏外观——非官方记录栏角标由内部术语「侧车记录」改为「历史改动」,悬停说明 Keep 只标记已看过、不改写磁盘,Undo 逐项校验后写回,两者都不影响官方审查;官方元数据不可用时给出可读原因与重试按钮,不再静默降级;「会话没在当前端激活」由红色告警改为中性说明。保留 v0.20.3 修复官方差异全部无法定位时差异栏无提示、上下箭头静默禁用(显示「无可跳转」与失效原因,Keep 说明只标记已采纳、不改写磁盘,会话缺失等宿主错误改为可读提示)、v0.20.2 的 MCP 状态告警收敛与原生确认弹窗,以及 v0.20.1 的文件内差异展示、块级/文件级安全审查和跨分页批量操作。升级后重启 DSH 并刷新页面;持久化与回退边界见 [0.20.0 发布说明](docs/release-0.20.0.md);从 0.14.2 或更旧版本升级还须阅读
482
483
  [0.14.3 数据迁移与回退说明](docs/release-0.14.3.md)。
483
484
 
484
485
  ```bash
485
486
  # ① Git 安装(clone + prepare 构建;推荐打固定 tag)
486
- dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.21.2
487
+ dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.21.3
487
488
 
488
489
  # ② npm 注册表(发布到 npm 后)
489
- dsh plugin --profile web add dsh-vscode-mode@0.21.2
490
+ dsh plugin --profile web add dsh-vscode-mode@0.21.3
490
491
 
491
492
  # ③ GitHub Release tgz 直装(Release asset 可用后)
492
- dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.21.2/dsh-vscode-mode-0.21.2.tgz
493
+ dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.21.3/dsh-vscode-mode-0.21.3.tgz
493
494
  ```
494
495
 
495
496
  > **DSH 版本政策(0.17.0 起)**:六项 DSH peer 仍统一声明为 `*`,另以
@@ -830,6 +831,7 @@ Keep All / Undo All 却是亮的。修复:单文件 Keep / Undo 覆盖冲突
830
831
  完整变更见 [GitHub Releases](https://github.com/Lenonss/DSH_VsCodeMode/releases)。
831
832
  近期关键版本:
832
833
 
834
+ - **v0.21.3**:MCP 初始化失败时分离调用者结果与安全收尾,已进入 startup 的调用者及时收到失败;旧 work/close 未完成仍占槽并阻止同 key 重建,清理失败不开放替代连接,收尾完成才开始冷却。不宣称解决首次偶发超时、gamma 排队或整体流程有界。当前 Host/GUI 未部署未验证,用户仅本批接受替代验收;不自动部署或重启。见 [发布说明](docs/release-0.21.3.md)。
833
835
  - **v0.21.2**:适配新版 DSH Session Controller 与 MCP 公开工具目录;固定目标任务发送持有会话直到完成或卸载,受理不明时不跨通道重发。范围文件引用的模型文本、剪贴板与纯文本降级保持一致。MCP 初始化失败记录阶段、耗时和脱敏错误链;迁移官方 native/PTC 执行器集成测试并增加可选真实 CodeGraph stdio 验证。当前 Web Host 真实工具调用已通过,首次连接偶发超时根因仍未证实;不自动部署或重启。见 [发布说明](docs/release-0.21.2.md)。
834
836
  - **v0.21.1**:缺失历史文件读取完整快照并整文件显示删除行;Keep 保留删除,Undo 安全恢复当前展示快照,不覆盖重新出现的文件。删除预览只读,单文件和批量操作统一处理,记录变化或证据不足时停止。真实 GUI 验收缺口已获用户接受;发布不自动部署,升级后重启 DSH 并刷新页面。见 [发布说明](docs/release-0.21.1.md)。
835
837
  - **v0.21.0**:新增 XLSX 基础编辑、多工作表与浏览器导出副本,原件不自动写回;不支持结构只读预览,高级应用经官方 Host 打开原件。编辑状态仅在当前页面内保留,不承诺刷新或崩溃恢复。官方差异定位统一 BOM 与 LF/CRLF/混合行尾口径,区分内容缺失与多处命中,保持原始字节及写回校验边界;不扩展 CRLF patch Undo 能力,目标官方记录 ↑/↓ 的真实点击仍未验收。升级后重启 DSH 并刷新页面;发布不自动部署当前实例。
package/lib/client.js.map CHANGED
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/lib/client.js.map
3
- size: 35441122 bytes
4
- sha256: 7a0cd42b2d95ee169d929a0582c16b5732f1e05419aebc39c8d665bf7785e490
3
+ size: 35443071 bytes
4
+ sha256: 628a3079abf2c9880fe64f234fcffcf2fe857313b9759f0900125c4b0ba0b78d
package/lib/index.js CHANGED
@@ -1213,6 +1213,7 @@ var McpPool = class {
1213
1213
  queuedAt: Date.now(),
1214
1214
  phaseAt: Date.now(),
1215
1215
  ready: Promise.resolve(),
1216
+ quiescence: Promise.resolve(),
1216
1217
  live: true,
1217
1218
  calls: Promise.resolve()
1218
1219
  };
@@ -1233,21 +1234,36 @@ var McpPool = class {
1233
1234
  }
1234
1235
  };
1235
1236
  }
1236
- /** @private @author ddj 2026年10月20号 @param entry New entry. @returns Queued initialization, bounded to two concurrent starts. */
1237
+ /** @private @author ddj 2026年10月29号 @param entry New entry. @returns Caller result, independent from the two-slot cleanup lifetime. */
1237
1238
  schedule(entry) {
1238
- return new Promise((resolve, reject) => {
1239
- /** @author ddj 2026年10月20号 Initializes a still-owned queue item. */
1240
- const run = async () => {
1241
- try {
1242
- await this.start(entry);
1243
- resolve();
1244
- } catch (error) {
1245
- reject(error);
1246
- }
1239
+ let result;
1240
+ const ready = new Promise((resolve, reject) => {
1241
+ result = {
1242
+ resolve,
1243
+ reject
1247
1244
  };
1248
- this.queue.push(run);
1249
- this.pump();
1250
1245
  });
1246
+ let lifetime;
1247
+ entry.quiescence = new Promise((resolve, reject) => {
1248
+ lifetime = {
1249
+ resolve,
1250
+ reject
1251
+ };
1252
+ });
1253
+ entry.quiescence.catch(() => void 0);
1254
+ /** @private @author ddj 2026年10月29号 Runs and observes the complete owned mount even after caller rejection. */
1255
+ const run = async () => {
1256
+ try {
1257
+ await this.start(entry, result);
1258
+ lifetime.resolve();
1259
+ } catch (error) {
1260
+ result.reject(error);
1261
+ lifetime.reject(error);
1262
+ }
1263
+ };
1264
+ this.queue.push(run);
1265
+ this.pump();
1266
+ return ready;
1251
1267
  }
1252
1268
  /** @private @author ddj 2026年10月20号 Advances FIFO work; each task holds its slot until startup or cleanup quiesces. */
1253
1269
  pump() {
@@ -1262,9 +1278,12 @@ var McpPool = class {
1262
1278
  this.jobs.add(job);
1263
1279
  }
1264
1280
  }
1265
- /** @private @author ddj 2026年10月20号 @param entry Connection to initialize. @returns Initialization completion, or failure after owned cleanup. */
1266
- async start(entry) {
1267
- if (!entry.live || this.stopped) throw new Error("MCP 启动已取消");
1281
+ /** @private @author ddj 2026年10月29号 @param entry Connection to initialize. @param result Caller settlement. @returns Full startup and cleanup lifetime. */
1282
+ async start(entry, result) {
1283
+ if (!entry.live || this.stopped) {
1284
+ result.reject(/* @__PURE__ */ new Error("MCP 启动已取消"));
1285
+ return;
1286
+ }
1268
1287
  entry.phase = "loading";
1269
1288
  entry.phaseAt = Date.now();
1270
1289
  entry.startAt = entry.phaseAt;
@@ -1280,42 +1299,52 @@ var McpPool = class {
1280
1299
  entry.phase = "ready";
1281
1300
  entry.finishedAt = Date.now();
1282
1301
  entry.connectedAt = entry.finishedAt;
1302
+ result.resolve();
1283
1303
  } catch (error) {
1284
- entry.error = "MCP 初始化失败或超时,请查看 Host 日志";
1304
+ if (!entry.cleanupFailed) entry.error = "MCP 初始化失败或超时;旧连接清理尚未确认,暂不能重建,请查看 Host 日志";
1285
1305
  const diagnostic = "MCP initialization failed; phase=" + entry.phase + "; transport=" + entry.spec.config.transport + "; elapsedMs=" + (Date.now() - entry.startAt) + "; " + mcpErrorText(error, entry.spec.config);
1286
1306
  debugRecord(this.ctx, entry.spec.workspace, diagnostic, "warn");
1287
1307
  entry.live = false;
1288
1308
  entry.phase = "stopping";
1289
- const closing = this.closeBridge(entry);
1290
- await Promise.allSettled([closing, work]);
1291
- entry.phase = "error";
1292
- entry.finishedAt = Date.now();
1293
- entry.retryAt = Date.now() + 5e3;
1294
- throw new Error(entry.error);
1309
+ result.reject(new Error(entry.error));
1310
+ await this.finishFailure(entry, work);
1295
1311
  } finally {
1296
1312
  if (timer) clearTimeout(timer);
1297
1313
  }
1298
1314
  }
1315
+ /** @private @author ddj 2026年10月29号 @param entry Failed generation. @param work Entire mount, including late factory cleanup. @returns Confirmed quiescence; throws when closure is unconfirmed. */
1316
+ async finishFailure(entry, work) {
1317
+ await Promise.allSettled([this.closeBridge(entry), work]);
1318
+ if (entry.cleanupFailed) throw new Error(entry.error);
1319
+ entry.phase = "error";
1320
+ entry.finishedAt = Date.now();
1321
+ entry.retryAt = entry.finishedAt + 5e3;
1322
+ entry.error = "MCP 初始化失败或超时,请查看 Host 日志";
1323
+ }
1299
1324
  /** @private @author ddj 2026年10月20号 @param entry Owned generation. @returns Official initial sync; never publishes after invalidation. */
1300
1325
  async mount(entry) {
1301
1326
  const official = await this.load();
1302
1327
  if (!entry.live || this.stopped) return;
1303
1328
  const bridge = await this.make();
1329
+ entry.bridge = bridge;
1304
1330
  if (!entry.live || this.stopped) {
1305
- await bridge.dispose();
1331
+ await this.closeBridge(entry);
1306
1332
  return;
1307
1333
  }
1308
- entry.bridge = bridge;
1309
1334
  entry.phase = "starting";
1310
1335
  entry.phaseAt = Date.now();
1311
1336
  entry.fiber = bridge.scope.ctx.plugin(official, entry.spec.config);
1312
1337
  await entry.fiber;
1313
1338
  if (entry.fiber?.state !== void 0 && entry.fiber.state !== 2) throw new Error("MCP 插件未完成激活");
1314
1339
  }
1315
- /** @private @author ddj 2026年10月20号 @param entry Connection to close. @returns Shared closure barrier; rejection retains a fenced entry. */
1340
+ /** @private @author ddj 2026年10月29号 @param entry Connection to close. @returns Shared closure barrier; synchronous throws and rejections retain a fenced entry. */
1316
1341
  async closeBridge(entry) {
1317
1342
  if (entry.close) return entry.close;
1318
- const close = entry.bridge?.dispose() ?? Promise.resolve();
1343
+ const bridge = entry.bridge;
1344
+ if (!bridge) return;
1345
+ /** @private @author ddj 2026年10月29号 @returns Deferred disposal so synchronous throws are owned by the shared barrier. */
1346
+ const dispose = () => bridge.dispose();
1347
+ const close = Promise.resolve().then(dispose);
1319
1348
  entry.close = close;
1320
1349
  try {
1321
1350
  await close;
@@ -1323,6 +1352,7 @@ var McpPool = class {
1323
1352
  entry.fiber = void 0;
1324
1353
  entry.close = void 0;
1325
1354
  } catch (error) {
1355
+ entry.cleanupFailed = true;
1326
1356
  entry.error = "MCP 释放未确认,禁止重建,请查看 Host 日志";
1327
1357
  this.ctx.logger?.warn?.("MCP cleanup failed: " + String(error));
1328
1358
  throw error;
@@ -1346,9 +1376,12 @@ var McpPool = class {
1346
1376
  entry.live = false;
1347
1377
  entry.phase = "stopping";
1348
1378
  if (entry.idle) clearTimeout(entry.idle);
1349
- await this.closeBridge(entry);
1350
- await entry.ready.catch(() => void 0);
1351
- await entry.calls.catch(() => void 0);
1379
+ const failure = (await Promise.allSettled([
1380
+ this.closeBridge(entry),
1381
+ entry.quiescence,
1382
+ entry.calls
1383
+ ])).find((closure) => closure.status === "rejected");
1384
+ if (failure?.status === "rejected") throw failure.reason;
1352
1385
  if (this.entries.get(entry.key) === entry) this.entries.delete(entry.key);
1353
1386
  }
1354
1387
  /** @public @author ddj 2026年10月20号 @param entry Authorized connection. @param action Per-call work retaining original execution identity. @param signal Caller cancellation. @returns Serialized shared result; no direct registry bypass is introduced here. */
@@ -1366,8 +1399,10 @@ var McpPool = class {
1366
1399
  /** @public @author ddj 2026年10月20号 @returns Full disposal of entries, queue, timers and owned work. */
1367
1400
  async dispose() {
1368
1401
  this.stopped = true;
1369
- await Promise.all([...this.entries.values()].map((entry) => this.retire(entry)));
1402
+ const closures = await Promise.allSettled([...this.entries.values()].map((entry) => this.retire(entry)));
1370
1403
  await Promise.all([...this.jobs]);
1404
+ const failure = closures.find((closure) => closure.status === "rejected");
1405
+ if (failure?.status === "rejected") throw failure.reason;
1371
1406
  }
1372
1407
  };
1373
1408
  //#endregion