dsh-vscode-mode 0.1.17 → 0.1.19

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
@@ -1243,15 +1243,18 @@ async function appendArchiveEntries(ctx, cwd, entries, session) {
1243
1243
  console.error("edrv appendArchiveEntries failed", error);
1244
1244
  }
1245
1245
  }
1246
- /** 归档记录:标记 archived、按批次写入归档、落盘工作区桶。 */
1247
- async function archiveRecords(ctx, session, cwd, bucket, recs, reason) {
1246
+ /**
1247
+ * 归档记录:标记 archived、按批次写入归档、落盘工作区桶。
1248
+ * @param opts.deferSave 为 true 时只写归档、不落盘桶(由批量调用方统一 saveBucket 一次)
1249
+ */
1250
+ async function archiveRecords(ctx, session, cwd, bucket, recs, reason, opts) {
1248
1251
  if (!recs.length) return;
1249
1252
  const fresh = recs.filter((r) => !r.archived);
1250
1253
  for (const r of recs) r.archived = true;
1251
1254
  const entries = [];
1252
1255
  for (const list of groupByBatch(recs).values()) entries.push(archiveEntryFor(list, cwd, reason));
1253
1256
  await appendArchiveEntries(ctx, cwd, entries, session);
1254
- if (fresh.length) await saveBucket(ctx, cwd, bucket, session);
1257
+ if (fresh.length && !opts?.deferSave) await saveBucket(ctx, cwd, bucket, session);
1255
1258
  }
1256
1259
  //#endregion
1257
1260
  //#region src/registry.ts
@@ -2437,6 +2440,53 @@ async function requireSession(ctx, sessionId) {
2437
2440
  cwd
2438
2441
  };
2439
2442
  }
2443
+ /**
2444
+ * 批量决策核心:一次会话/桶解析 + 逐项处理 + 统一落盘(accept/reject 单条与 decideBatch 共用)。
2445
+ * rejected 项先做回滚,失败记入该项 error 且不改决策;本批次新增"已解决"记录一次性归档,
2446
+ * 有任何成功项则整桶只写盘一次,避免逐条读写整个 sidecar。
2447
+ * @author ddj 2026年08月25号
2448
+ * @param items 决策项(按数组顺序处理,rejected 的先后即回滚顺序)
2449
+ * @returns 逐项结果(ok 项含更新后的记录视图)
2450
+ */
2451
+ async function applyDecisions(ctx, session, cwd, bucket, items) {
2452
+ const results = [];
2453
+ const resolved = [];
2454
+ let changed = false;
2455
+ for (const item of items) {
2456
+ const record = bucket.get(item.callId);
2457
+ if (!record) {
2458
+ results.push({
2459
+ callId: item.callId,
2460
+ ok: false,
2461
+ error: "记录不存在"
2462
+ });
2463
+ continue;
2464
+ }
2465
+ if (item.decision === "rejected") {
2466
+ const outcome = (item.scope ?? "call") === "hunk" ? await revertHunk(ctx, session, record, item.hunkIndex ?? -1) : await revertCall(ctx, session, record);
2467
+ if (!outcome.ok) {
2468
+ results.push({
2469
+ callId: item.callId,
2470
+ ok: false,
2471
+ error: outcome.error
2472
+ });
2473
+ continue;
2474
+ }
2475
+ }
2476
+ const wasResolved = recordResolved(record);
2477
+ markDecision(record, item.scope ?? "call", item.hunkIndex, item.decision);
2478
+ changed = true;
2479
+ if (!wasResolved && recordResolved(record)) resolved.push(record);
2480
+ results.push({
2481
+ callId: item.callId,
2482
+ ok: true,
2483
+ record: recView(record)
2484
+ });
2485
+ }
2486
+ if (resolved.length) await archiveRecords(ctx, session, cwd, bucket, resolved, items.some((item) => item.decision === "rejected") ? "已处理(回滚)" : "已处理", { deferSave: true });
2487
+ if (changed) await saveBucket(ctx, cwd, bucket, session);
2488
+ return results;
2489
+ }
2440
2490
  /** 各方法 handler 表(类型由 shared/rpc 的 RpcHandlerMap 约束)。 */
2441
2491
  function buildHandlers(ctx, registry, searcher = newSearcher(ctx)) {
2442
2492
  return {
@@ -2448,7 +2498,7 @@ function buildHandlers(ctx, registry, searcher = newSearcher(ctx)) {
2448
2498
  };
2449
2499
  const bucket = await bucketOf(registry, ctx, sc.cwd);
2450
2500
  const want = Array.isArray(args.callIds) ? new Set(args.callIds) : null;
2451
- if (!want) await autoArchiveStale(ctx, sc.session, sc.cwd, bucket);
2501
+ if (!want && args.skipStale !== true) await autoArchiveStale(ctx, sc.session, sc.cwd, bucket);
2452
2502
  const out = [];
2453
2503
  for (const rec of bucket.values()) {
2454
2504
  if (!want && rec.archived) continue;
@@ -2468,17 +2518,19 @@ function buildHandlers(ctx, registry, searcher = newSearcher(ctx)) {
2468
2518
  error: sc.err
2469
2519
  };
2470
2520
  const bucket = await bucketOf(registry, ctx, sc.cwd);
2471
- const record = bucket.get(args.callId);
2472
- if (!record) return {
2521
+ const item = (await applyDecisions(ctx, sc.session, sc.cwd, bucket, [{
2522
+ callId: args.callId,
2523
+ scope: args.scope,
2524
+ hunkIndex: args.hunkIndex,
2525
+ decision: "accepted"
2526
+ }]))[0];
2527
+ if (!item?.ok) return {
2473
2528
  ok: false,
2474
- error: "记录不存在"
2529
+ error: item?.error ?? "操作失败"
2475
2530
  };
2476
- markDecision(record, args.scope ?? "call", args.hunkIndex, "accepted");
2477
- if (recordResolved(record)) await archiveRecords(ctx, sc.session, sc.cwd, bucket, [record], "已处理");
2478
- else await saveBucket(ctx, sc.cwd, bucket, sc.session);
2479
2531
  return {
2480
2532
  ok: true,
2481
- record: recView(record)
2533
+ record: item.record
2482
2534
  };
2483
2535
  },
2484
2536
  "edrv.reject": async (args) => {
@@ -2488,24 +2540,31 @@ function buildHandlers(ctx, registry, searcher = newSearcher(ctx)) {
2488
2540
  error: sc.err
2489
2541
  };
2490
2542
  const bucket = await bucketOf(registry, ctx, sc.cwd);
2491
- const record = bucket.get(args.callId);
2492
- if (!record) return {
2543
+ const item = (await applyDecisions(ctx, sc.session, sc.cwd, bucket, [{
2544
+ callId: args.callId,
2545
+ scope: args.scope,
2546
+ hunkIndex: args.hunkIndex,
2547
+ decision: "rejected"
2548
+ }]))[0];
2549
+ if (!item?.ok) return {
2493
2550
  ok: false,
2494
- error: "记录不存在"
2551
+ error: item?.error ?? "操作失败"
2552
+ };
2553
+ return {
2554
+ ok: true,
2555
+ record: item.record
2495
2556
  };
2496
- const scope = args.scope ?? "call";
2497
- const outcome = scope === "hunk" ? await revertHunk(ctx, sc.session, record, args.hunkIndex ?? -1) : await revertCall(ctx, sc.session, record);
2498
- if (!outcome.ok) return {
2557
+ },
2558
+ "edrv.decideBatch": async (args) => {
2559
+ const sc = await requireSession(ctx, args.sessionId);
2560
+ if ("err" in sc) return {
2499
2561
  ok: false,
2500
- error: outcome.error
2562
+ error: sc.err
2501
2563
  };
2502
- markDecision(record, scope, args.hunkIndex, "rejected");
2503
- record.at = (/* @__PURE__ */ new Date()).toISOString();
2504
- if (recordResolved(record)) await archiveRecords(ctx, sc.session, sc.cwd, bucket, [record], "已处理(回滚)");
2505
- else await saveBucket(ctx, sc.cwd, bucket, sc.session);
2564
+ const bucket = await bucketOf(registry, ctx, sc.cwd);
2506
2565
  return {
2507
2566
  ok: true,
2508
- record: recView(record)
2567
+ results: await applyDecisions(ctx, sc.session, sc.cwd, bucket, Array.isArray(args.items) ? args.items : [])
2509
2568
  };
2510
2569
  },
2511
2570
  "edrv.read": async (args) => {