dsh-vscode-mode 0.21.3 → 0.22.0

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/client.js CHANGED
@@ -3749,6 +3749,10 @@ window.__ModuleLoader__.load({
3749
3749
  return reviewBlocks(diff).map(placeRegion);
3750
3750
  }
3751
3751
  //#endregion
3752
+ //#region src/shared/pendingReview.ts
3753
+ /** 待审条目在面板列表里的 id 前缀;客户端与 Host 共用这一份口径。 */
3754
+ const PENDING_PREFIX = "pending:";
3755
+ //#endregion
3752
3756
  //#region src/shared/diff.ts
3753
3757
  /** 统一取对应 hunk;callHunk 只用于旧记录缺失 hunks 时兼容。 */
3754
3758
  function preciseHunk(record, idx) {
@@ -4045,6 +4049,7 @@ window.__ModuleLoader__.load({
4045
4049
  }
4046
4050
  //#endregion
4047
4051
  //#region src/client/state/diffSummary.ts
4052
+ /** Source-aware metadata projection; official patches never become legacy hunks. @author ddj 2026年10月26号 */
4048
4053
  /** @public @author ddj 2026年10月26号 @param path Functional local or remote identity. @returns Comparison key without rewriting remote case. */
4049
4054
  function diffPathKey(path) {
4050
4055
  if (/^[a-z]+:\/\//i.test(path)) return path;
@@ -4056,13 +4061,46 @@ window.__ModuleLoader__.load({
4056
4061
  const key = diffPathKey(path);
4057
4062
  return !!page?.overview?.coveredPaths.some((candidate) => diffPathKey(candidate) === key);
4058
4063
  }
4059
- /** @public @author ddj 2026年10月26号 @param records Tool-call history. @param page Official file navigation, never only its first 50 rows. @returns Official-first file counts; legacy paths remain explicitly labelled. */
4064
+ /**
4065
+ * @author ddj 2026年10月30号
4066
+ * @description: 取出本页待审条目(id 带待审前缀)并折算成文件行。
4067
+ * @param page 审查页
4068
+ * @returns 待审文件行与它们覆盖的路径键
4069
+ */
4070
+ function pendingRowsOf(page) {
4071
+ const rows = [];
4072
+ const covered = /* @__PURE__ */ new Set();
4073
+ for (const item of page?.items ?? []) {
4074
+ if (!item.id.startsWith("pending:")) continue;
4075
+ const path = item.currentPath || item.path;
4076
+ covered.add(diffPathKey(path));
4077
+ rows.push({
4078
+ path,
4079
+ label: item.display || path,
4080
+ recs: [],
4081
+ pending: item.decision === "pending" ? 1 : 0,
4082
+ added: item.added,
4083
+ deleted: item.deleted,
4084
+ sourceKind: "pending"
4085
+ });
4086
+ }
4087
+ return {
4088
+ rows,
4089
+ covered
4090
+ };
4091
+ }
4092
+ /** @public @author ddj 2026年10月26号 @param records Tool-call history. @param page Official file navigation, never only its first 50 rows. @returns Pending first, then official; legacy paths remain explicitly labelled. */
4060
4093
  function diffSummary(records, page) {
4061
- const legacy = summarize(records.filter((record) => !officialPath(record.path, page)));
4062
- const files = (page?.overview?.files ?? []).map((file) => ({
4063
- ...file,
4064
- recs: []
4065
- }));
4094
+ const pending = pendingRowsOf(page);
4095
+ const legacy = summarize(records.filter((record) => !pending.covered.has(diffPathKey(record.path)) && !officialPath(record.path, page)));
4096
+ const files = [...pending.rows];
4097
+ for (const file of page?.overview?.files ?? []) {
4098
+ if (pending.covered.has(diffPathKey(file.path))) continue;
4099
+ files.push({
4100
+ ...file,
4101
+ recs: []
4102
+ });
4103
+ }
4066
4104
  for (const file of legacy.files) files.push({
4067
4105
  ...file,
4068
4106
  sourceKind: "legacy"
@@ -381321,11 +381359,6 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
381321
381359
  }
381322
381360
  //#endregion
381323
381361
  //#region src/client/ui/shared.ts
381324
- /**
381325
- * dsh-vscode-mode client — UI 共用小工具(按钮样式/状态文案/等宽字体)。
381326
- * 迁移自原 src/client/index.ts 的 btn/badgeOf/MONO,语义不改。
381327
- * 作者 ddj 2026-08-20
381328
- */
381329
381362
  /** 次级按钮内联样式(accept=true 绿色 / false 红色)。 */
381330
381363
  function btn(accept) {
381331
381364
  return {
@@ -381338,10 +381371,6 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
381338
381371
  color: accept ? "var(--dsw-alias-state-success-primary,#2e9e44)" : "var(--dsw-alias-state-error-primary,#d9534f)"
381339
381372
  };
381340
381373
  }
381341
- /** 状态中文文案。 */
381342
- function badgeOf(status) {
381343
- return status === ST.ACCEPTED ? "已采纳" : status === ST.REJECTED ? "已拒绝" : "待处理";
381344
- }
381345
381374
  /** 等宽字体常量(差异行渲染用)。 */
381346
381375
  const MONO = {
381347
381376
  fontFamily: "var(--ds-font-family-code, ui-monospace, monospace)",
@@ -381408,6 +381437,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
381408
381437
  if (!controller.signal.aborted) setError(String(cause));
381409
381438
  }
381410
381439
  }
381440
+ const gaps = page?.gaps ?? [];
381411
381441
  return h("div", { style: { marginTop: 8 } }, h("label", null, h("input", {
381412
381442
  type: "checkbox",
381413
381443
  checked: history,
@@ -381415,10 +381445,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
381415
381445
  setHistory(!history);
381416
381446
  setCursor(0);
381417
381447
  }
381418
- }), "显示已处理及被替换的历史"), page?.gaps.map((gap) => h("div", {
381419
- key: `${gap.sessionId}:${gap.seq}`,
381420
- role: "status"
381421
- }, `轮次 ${gap.turn} 采集不完整:${gap.error}`)), error ? h("div", { role: "alert" }, error) : null, !page ? h("p", { role: "status" }, "正在读取官方审查记录…") : null, page && !page.items.length ? h("p", null, history ? "暂无已落盘历史。" : "没有待处理的官方记录;可切换查看历史。") : null, h("div", { style: {
381448
+ }), "显示已处理及被替换的历史"), error ? h("div", { role: "alert" }, error) : null, !page ? h("p", { role: "status" }, "正在读取官方审查记录…") : null, page && !page.items.length ? h("p", null, history ? "暂无已落盘历史。" : "没有待处理的官方记录;可切换查看历史。") : null, h("div", { style: {
381422
381449
  maxHeight: 210,
381423
381450
  overflow: "auto"
381424
381451
  } }, page?.items.map((item) => h("button", {
@@ -381427,19 +381454,33 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
381427
381454
  onClick: () => {
381428
381455
  select(item);
381429
381456
  },
381457
+ title: item.currentPath || item.path,
381430
381458
  style: {
381431
381459
  display: "block",
381432
381460
  width: "100%",
381433
381461
  textAlign: "left",
381434
- padding: "6px 4px"
381462
+ padding: "6px 4px",
381463
+ whiteSpace: "nowrap",
381464
+ overflow: "hidden",
381465
+ textOverflow: "ellipsis"
381435
381466
  }
381436
- }, `轮次 ${item.turn} · ${item.display} +${item.added} −${item.deleted} · ${item.decision}${item.current ? "" : "(已被同轮新版本替换)"}`))), cursor > 0 ? h("button", {
381467
+ }, item.id.startsWith("pending:") ? `【待审】${item.display} +${item.added} −${item.deleted} · ${item.decision}${item.kind === "oversized" ? " · 过大" : ""}` : `轮次 ${item.turn} · ${item.display} +${item.added} −${item.deleted} · ${item.decision}${item.current ? "" : "(已被同轮新版本替换)"}`))), cursor > 0 ? h("button", {
381437
381468
  type: "button",
381438
381469
  onClick: () => setCursor(Math.max(0, cursor - 50))
381439
381470
  }, "上一页") : null, page?.nextCursor !== null && page?.nextCursor !== void 0 ? h("button", {
381440
381471
  type: "button",
381441
381472
  onClick: () => setCursor(page.nextCursor)
381442
- }, "下一页") : null, detail ? h(PatchDetail, {
381473
+ }, "下一页") : null, gaps.length ? h("details", {
381474
+ key: "gaps",
381475
+ style: { marginTop: 6 }
381476
+ }, h("summary", { style: {
381477
+ cursor: "pointer",
381478
+ fontSize: 11
381479
+ } }, `采集不完整 ${gaps.length} 条(诊断信息)`), gaps.map((gap) => h("div", {
381480
+ key: `${gap.sessionId}:${gap.seq}`,
381481
+ role: "status",
381482
+ style: { fontSize: 11 }
381483
+ }, `轮次 ${gap.turn} 采集不完整:${gap.error}`))) : null, detail ? h(PatchDetail, {
381443
381484
  key: detail.item.id,
381444
381485
  sessionId: props.sessionId,
381445
381486
  detail,
@@ -381654,7 +381695,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
381654
381695
  source
381655
381696
  ]);
381656
381697
  let body;
381657
- const legacyFiles = sum.pendingFiles.filter((file) => file.sourceKind !== "official");
381698
+ const legacyFiles = sum.pendingFiles.filter((file) => file.sourceKind === "legacy");
381658
381699
  if (source === "official") body = react$1.default.createElement(react$1.default.Fragment, null, react$1.default.createElement("div", { className: "edrv-search-empty" }, "官方轮次净差异 · 原始历史只读;编辑按钮打开当前文件,保存不代表已审。"), review.error ? react$1.default.createElement("div", { role: "alert" }, review.error) : null, react$1.default.createElement(ReviewLedger, {
381659
381700
  key: sessionId + ":" + tab,
381660
381701
  sessionId,
@@ -382511,11 +382552,9 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382511
382552
  /** @public @author ddj 2026年10月27号 @param props Existing review callbacks and immutable record metadata. @returns Responsive review toolbar; no disk or decision side effects until an explicit action. */
382512
382553
  function OfficialDiffBar(props) {
382513
382554
  const { official, pendingRegions = [], staleRegions = [], diffIdx = 0 } = props;
382514
- const [expanded, setExpanded] = react$1.default.useState(false);
382515
382555
  const [menu, setMenu] = react$1.default.useState(null);
382516
382556
  const name = String(props.activePath || "").split(/[\\/]/).pop() || "当前文件";
382517
382557
  const detail = official.detail;
382518
- const records = official.records ?? [];
382519
382558
  const count = pendingRegions.length;
382520
382559
  const view = reviewBarView({
382521
382560
  jumps: count,
@@ -382532,11 +382571,6 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382532
382571
  function closeMenu() {
382533
382572
  setMenu(null);
382534
382573
  }
382535
- /** @private @author ddj 2026年10月27号 @param id Immutable record ID. @returns Select record and dismiss popup. */
382536
- function selectRecord(id) {
382537
- official.onSelect(id);
382538
- closeMenu();
382539
- }
382540
382574
  /** @private @author ddj 2026年10月27号 @param tab Existing launcher tab. @returns Open existing overview, never create another review entry. */
382541
382575
  function openOverview(tab) {
382542
382576
  props.onOpenLauncher(tab);
@@ -382554,16 +382588,6 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382554
382588
  onClick: action
382555
382589
  }, barIcon(mark));
382556
382590
  }
382557
- const recordTrigger = /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
382558
- size: "sm",
382559
- variant: "ghost",
382560
- className: "edrv-review-record",
382561
- "aria-label": "选择官方差异记录",
382562
- "aria-haspopup": "menu",
382563
- "aria-expanded": menu === "records",
382564
- disabled: !records.length,
382565
- onClick: () => setMenu(menu === "records" ? null : "records")
382566
- }, detail ? `轮次 ${detail.item.turn}` : "选择记录", barIcon("down"));
382567
382591
  const moreTrigger = /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
382568
382592
  size: "sm",
382569
382593
  variant: "ghost",
@@ -382600,22 +382624,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382600
382624
  }, name), /* @__PURE__ */ react$1.default.createElement("span", {
382601
382625
  className: "edrv-review-pending",
382602
382626
  title: view.pendingTitle
382603
- }, "待审 ", /* @__PURE__ */ react$1.default.createElement("strong", null, official.pending)), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
382604
- open: menu === "records",
382605
- anchor: recordTrigger,
382606
- items: records.map((item) => ({
382607
- id: item.id,
382608
- label: `轮次 ${item.turn} / 事件 ${item.seq}`
382609
- })),
382610
- selectedId: detail?.item.id,
382611
- onSelect: selectRecord,
382612
- onClose: closeMenu,
382613
- side: "top",
382614
- align: "end",
382615
- portal: true,
382616
- compact: true,
382617
- autoFocus: true
382618
- })), /* @__PURE__ */ react$1.default.createElement("div", { className: "edrv-review-tools" }, /* @__PURE__ */ react$1.default.createElement("div", {
382627
+ }, "待审 ", /* @__PURE__ */ react$1.default.createElement("strong", null, official.pending))), /* @__PURE__ */ react$1.default.createElement("div", { className: "edrv-review-tools" }, /* @__PURE__ */ react$1.default.createElement("div", {
382619
382628
  className: "edrv-review-nav",
382620
382629
  role: "group",
382621
382630
  "aria-label": "文件导航"
@@ -382642,15 +382651,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382642
382651
  onClick: props.onAcceptFile,
382643
382652
  disabled: props.reviewBatchBusy || !detail?.capability.keep,
382644
382653
  title: detail?.capability.keep ? view.keepHint : detail?.capability.reason
382645
- }, "Keep"), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
382646
- size: "sm",
382647
- variant: "ghost",
382648
- className: "edrv-review-details",
382649
- onClick: () => setExpanded(!expanded),
382650
- "aria-expanded": expanded,
382651
- "aria-label": expanded ? "收起差异" : "展开差异",
382652
- title: expanded ? "收起差异" : "展开差异"
382653
- }, "详情", barIcon(expanded ? "up" : "down")), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
382654
+ }, "Keep"), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
382654
382655
  open: menu === "more",
382655
382656
  anchor: moreTrigger,
382656
382657
  items: [{
@@ -382673,12 +382674,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382673
382674
  }, view.notice) : null, props.reviewError ? /* @__PURE__ */ react$1.default.createElement("div", {
382674
382675
  className: props.reviewErrorTone === "info" ? "edrv-review-notice" : "edrv-review-notice edrv-review-error",
382675
382676
  role: props.reviewErrorTone === "info" ? "status" : "alert"
382676
- }, props.reviewError) : null, expanded ? /* @__PURE__ */ react$1.default.createElement("div", { className: "edrv-review-body" }, /* @__PURE__ */ react$1.default.createElement(ReviewLedger, {
382677
- key: `${official.sessionId}:${official.path}`,
382678
- sessionId: official.sessionId,
382679
- first: official.page,
382680
- path: official.path
382681
- })) : null);
382677
+ }, props.reviewError) : null);
382682
382678
  }
382683
382679
  //#endregion
382684
382680
  //#region src/client/ui/SidecarDiffBar.tsx
@@ -382693,7 +382689,6 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382693
382689
  function SidecarDiffBar(props) {
382694
382690
  const pendingRegions = props.pendingRegions ?? [];
382695
382691
  const staleRegions = props.staleRegions ?? [];
382696
- const [expanded, setExpanded] = react$1.default.useState(false);
382697
382692
  const [menu, setMenu] = react$1.default.useState(null);
382698
382693
  const name = String(props.activePath || "").split(/[\\/]/).pop() || "当前文件";
382699
382694
  const count = pendingRegions.length;
@@ -382736,20 +382731,6 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382736
382731
  "aria-expanded": menu === "more",
382737
382732
  onClick: () => setMenu(menu === "more" ? null : "more")
382738
382733
  }, barIcon("more"));
382739
- const body = expanded ? /* @__PURE__ */ react$1.default.createElement("div", { className: "edrv-review-body" }, pendingRegions.map((region) => {
382740
- const key = callIdAttr(region.callId, region.idx);
382741
- return /* @__PURE__ */ react$1.default.createElement("div", {
382742
- key,
382743
- className: "edrv-diffrow",
382744
- "data-edrv-hunk": key,
382745
- title: "跳转到 L" + (region.start ?? "?"),
382746
- onClick: () => props.onJump?.(region)
382747
- }, /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-diffrow-l" }, "L" + (region.start ?? "?") + "-" + (region.end ?? "?")), (region.oldLines?.length ?? 0) > 0 ? /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-diffrow-o" }, "-" + (region.oldLines?.length ?? 0)) : null, (region.newLines?.length ?? 0) > 0 ? /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-diffrow-n" }, "+" + (region.newLines?.length ?? 0)) : null, region.create ? /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-diffrow-tag" }, "新建") : null);
382748
- }), staleRegions.map((region) => /* @__PURE__ */ react$1.default.createElement("div", {
382749
- key: "stale" + callIdAttr(region.callId, region.idx),
382750
- className: "edrv-diffrow edrv-diffrow-stale",
382751
- title: "差异无法定位(文件可能已被手动修改)"
382752
- }, /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-diffrow-l" }, "L" + (region.start ?? "?") + " 无法定位"), /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-diffrow-tag" }, "冲突/需刷新"), /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-diffrow-tag" }, badgeOf(region.status ?? ""))))) : null;
382753
382734
  return /* @__PURE__ */ react$1.default.createElement("div", {
382754
382735
  className: "edrv-diffbar edrv-diffbar-dock edrv-reviewbar",
382755
382736
  "data-edrv-diffbox": "1",
@@ -382816,15 +382797,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382816
382797
  onClick: props.onAcceptFile,
382817
382798
  disabled: !canDecide,
382818
382799
  title: props.missingDeletion ? "保持文件删除并结清覆盖的待审历史记录,不写文件" : SIDECAR_KEEP_TITLE
382819
- }, "Keep"), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
382820
- size: "sm",
382821
- variant: "ghost",
382822
- className: "edrv-review-details",
382823
- onClick: () => setExpanded(!expanded),
382824
- "aria-expanded": expanded,
382825
- "aria-label": expanded ? "收起差异" : "展开差异",
382826
- title: expanded ? "收起差异" : "展开差异"
382827
- }, "详情", barIcon(expanded ? "up" : "down")), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
382800
+ }, "Keep"), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
382828
382801
  open: menu === "more",
382829
382802
  anchor: moreTrigger,
382830
382803
  items: [
@@ -382870,7 +382843,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
382870
382843
  }, view.notice) : null, props.reviewError ? /* @__PURE__ */ react$1.default.createElement("div", {
382871
382844
  className: props.reviewErrorTone === "info" ? "edrv-review-notice" : "edrv-review-notice edrv-review-error",
382872
382845
  role: props.reviewErrorTone === "info" ? "status" : "alert"
382873
- }, props.reviewError) : null, body);
382846
+ }, props.reviewError) : null);
382874
382847
  }
382875
382848
  //#endregion
382876
382849
  //#region src/client/ui/DiffBox.ts
@@ -384430,7 +384403,23 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
384430
384403
  }
384431
384404
  };
384432
384405
  }
384433
- /** @private @author ddj 2026年10月28号 @param ctx Lifecycle owner. @param sessions Public Controller. @param id Fixed target. @param text Task body. @returns Acceptance; failures never retry another transport. @sideEffects Retains one generation until completion or unload. */
384406
+ /** @private @author ddj 2026年10月29号 @param receipt Raw selected-channel receipt. @returns Explicit admission evidence and the historical boolean. */
384407
+ function taskReceipt(receipt) {
384408
+ const ok = receipt?.ok;
384409
+ if (ok === true) return {
384410
+ status: "accepted",
384411
+ legacyOk: true
384412
+ };
384413
+ if (ok === false) return {
384414
+ status: "rejected",
384415
+ legacyOk: false
384416
+ };
384417
+ return {
384418
+ status: "unknown",
384419
+ legacyOk: false
384420
+ };
384421
+ }
384422
+ /** @private @author ddj 2026年10月29号 @param ctx Lifecycle owner. @param sessions Public Controller. @param id Fixed target. @param text Task body. @returns Admission evidence without switching transport. @sideEffects Retains and releases exactly one generation. */
384434
384423
  async function sendOwned(ctx, sessions, id, text) {
384435
384424
  const controller = new AbortController();
384436
384425
  const reference = sessions.retain(id, {
@@ -384438,25 +384427,104 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
384438
384427
  signal: controller.signal
384439
384428
  });
384440
384429
  let released = false;
384441
- /** @private @author ddj 2026年10月28号 Cancel pending admission and release this exact generation once. */
384430
+ let cleanupFailed = false;
384431
+ /** @private @author ddj 2026年10月29号 Cancels and releases this exact generation once; remembers unload cleanup failures. */
384442
384432
  function release() {
384443
384433
  if (released) return;
384444
384434
  released = true;
384445
384435
  controller.abort();
384446
- reference.release();
384436
+ try {
384437
+ reference.release();
384438
+ } catch (error) {
384439
+ cleanupFailed = true;
384440
+ throw error;
384441
+ }
384447
384442
  }
384448
384443
  let remove;
384444
+ let started = false;
384445
+ let result = {
384446
+ status: "unavailable",
384447
+ legacyOk: false
384448
+ };
384449
384449
  try {
384450
384450
  remove = ctx.effect?.(() => release, "vscode-mode: task session reference");
384451
384451
  const binding = await reference.ready;
384452
- if (controller.signal.aborted) return false;
384453
- return (await binding.session.prompt([{
384454
- type: "text",
384455
- text
384456
- }], "queue", controller.signal)).ok === true;
384457
- } finally {
384452
+ if (controller.signal.aborted) result = {
384453
+ status: "cancelled",
384454
+ legacyOk: false
384455
+ };
384456
+ else {
384457
+ started = true;
384458
+ result = taskReceipt(await binding.session.prompt([{
384459
+ type: "text",
384460
+ text
384461
+ }], "queue", controller.signal));
384462
+ }
384463
+ } catch {
384464
+ result = {
384465
+ status: started ? "unknown" : "unavailable",
384466
+ legacyOk: false
384467
+ };
384468
+ }
384469
+ const cancelled = controller.signal.aborted;
384470
+ try {
384458
384471
  release();
384472
+ } catch {
384473
+ cleanupFailed = true;
384474
+ }
384475
+ try {
384459
384476
  remove?.();
384477
+ } catch {
384478
+ cleanupFailed = true;
384479
+ }
384480
+ if (cleanupFailed) result = {
384481
+ status: started ? "unknown" : "unavailable",
384482
+ legacyOk: false
384483
+ };
384484
+ if (cancelled) result = {
384485
+ status: "cancelled",
384486
+ legacyOk: result.legacyOk
384487
+ };
384488
+ return result;
384489
+ }
384490
+ /** @private @author ddj 2026年10月29号 @param ctx Service owner. @param id Fixed target. @param text Task body. @returns One legacy-channel attempt; no cross-channel retry. */
384491
+ async function sendLegacy(ctx, id, text) {
384492
+ const input = inputFor(ctx, id);
384493
+ if (typeof input?.setDraft === "function" && typeof input.submit === "function") {
384494
+ let submitted = false;
384495
+ try {
384496
+ input.setDraft(text);
384497
+ submitted = true;
384498
+ input.submit();
384499
+ return {
384500
+ status: "submitted",
384501
+ legacyOk: true
384502
+ };
384503
+ } catch {
384504
+ return {
384505
+ status: submitted ? "unknown" : "unavailable",
384506
+ legacyOk: false
384507
+ };
384508
+ }
384509
+ }
384510
+ const remote = ctx.get("remote.session");
384511
+ if (typeof remote?.prompt !== "function") return httpTaskResult(id, text);
384512
+ try {
384513
+ const payload = {
384514
+ sessionId: id,
384515
+ mode: "queue",
384516
+ content: [{
384517
+ type: "text",
384518
+ text
384519
+ }]
384520
+ };
384521
+ const receipt = await remote.prompt(slotArg(payload));
384522
+ return taskReceipt(receipt?.result ?? receipt);
384523
+ } catch {
384524
+ return {
384525
+ status: "unknown",
384526
+ legacyOk: false
384527
+ };
384460
384528
  }
384461
384529
  }
384462
384530
  /** apiproxy wire 端点(POST /api/<method>;浏览器同源 fetch 自带 cookie 鉴权;实证 401=未鉴权而非 404)。 */
@@ -384522,16 +384590,8 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
384522
384590
  const id = json?.result?.value?.sessionId;
384523
384591
  return json?.result?.ok === true && typeof id === "string" ? id : "";
384524
384592
  }
384525
- /**
384526
- * wire 直发 session/prompt(点击即发送方案):任务文本投给目标会话 agent。
384527
- * 契约 = 当前安装树 SessionsApi.prompt:`{sessionId, mode:'queue', content:[{type:'text',text}]}`。
384528
- * 发送成功会话即有内容 → 不再被 blank 隐藏(列表可见)。
384529
- * @author ddj 2026年09月23号
384530
- * @param sessionId 目标会话 id(新会话)
384531
- * @param text 任务文本
384532
- * @returns 是否受理
384533
- */
384534
- async function apiSessionPrompt(sessionId, text) {
384593
+ /** @private @author ddj 2026年10月29号 @param sessionId Fixed target. @param text Task body. @returns HTTP receipt evidence; errors after request entry are never safe rejection. */
384594
+ async function httpTaskResult(sessionId, text) {
384535
384595
  try {
384536
384596
  const payload = {
384537
384597
  sessionId,
@@ -384541,7 +384601,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
384541
384601
  text
384542
384602
  }]
384543
384603
  };
384544
- return (await (await fetch(appUrl(SESSION_PROMPT_PATH), {
384604
+ return taskReceipt((await (await fetch(appUrl(SESSION_PROMPT_PATH), {
384545
384605
  method: "POST",
384546
384606
  headers: { "content-type": "application/json" },
384547
384607
  body: JSON.stringify({
@@ -384550,9 +384610,12 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
384550
384610
  method: "session/prompt",
384551
384611
  payload: slotArg(payload)
384552
384612
  })
384553
- })).json().catch(() => null))?.result?.ok === true;
384613
+ })).json().catch(() => null))?.result);
384554
384614
  } catch {
384555
- return false;
384615
+ return {
384616
+ status: "unknown",
384617
+ legacyOk: false
384618
+ };
384556
384619
  }
384557
384620
  }
384558
384621
  /**
@@ -384755,44 +384818,35 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
384755
384818
  /**
384756
384819
  * 发送任务给目标会话 agent(点击即发送方案:任务落地会话即非 blank,列表可见)。
384757
384820
  * 新版持有目标 Controller 到 prompt 结束;旧版按能力选择唯一通道,不跨通道重发。
384758
- * @author ddj 2026年09月23号 / 2026年10月28号
384821
+ * @author ddj 2026年10月29号
384759
384822
  * @param sessionId 目标会话 id
384760
384823
  * @param text 任务文本
384761
- * @returns 是否受理
384824
+ * @returns 同一次调用的历史boolean语义,不能作为受理事实
384762
384825
  */
384763
- const sendTask = async (sessionId, text) => {
384764
- if (!sessionId) return false;
384826
+ const sendTask = async (sessionId, text) => (await sendTaskResult(sessionId, text)).legacyOk;
384827
+ /** @private @author ddj 2026年10月29号 @param sessionId Fixed target. @param text Task body. @returns Detailed evidence from exactly one selected transport. */
384828
+ async function sendTaskResult(sessionId, text) {
384829
+ if (!sessionId) return {
384830
+ status: "unavailable",
384831
+ legacyOk: false
384832
+ };
384765
384833
  try {
384766
384834
  const sessions = ctx.get("sessions");
384767
384835
  if (typeof sessions?.retain === "function") return await sendOwned(ctx, sessions, sessionId, text);
384768
- const input = inputFor(ctx, sessionId);
384769
- if (typeof input?.setDraft === "function" && typeof input.submit === "function") {
384770
- input.setDraft(text);
384771
- input.submit();
384772
- return true;
384773
- }
384774
- const remote = ctx.get("remote.session");
384775
- if (typeof remote?.prompt === "function") {
384776
- const payload = {
384777
- sessionId,
384778
- mode: "queue",
384779
- content: [{
384780
- type: "text",
384781
- text
384782
- }]
384783
- };
384784
- return rpcOk(await remote.prompt(slotArg(payload))).ok;
384785
- }
384786
- return await apiSessionPrompt(sessionId, text);
384836
+ return await sendLegacy(ctx, sessionId, text);
384787
384837
  } catch {
384788
- return false;
384838
+ return {
384839
+ status: "unavailable",
384840
+ legacyOk: false
384841
+ };
384789
384842
  }
384790
- };
384843
+ }
384791
384844
  return {
384792
384845
  appendReference,
384793
384846
  appendText,
384794
384847
  startDraftSession,
384795
- sendTask
384848
+ sendTask,
384849
+ sendTaskResult
384796
384850
  };
384797
384851
  }
384798
384852
  /**
@@ -393719,7 +393773,9 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
393719
393773
  ]);
393720
393774
  react$1.default.useEffect(() => {
393721
393775
  const controller = new AbortController();
393722
- if (!active || !review.page?.overview?.coveredPaths.some((path) => sameFile(path, active))) {
393776
+ const pendingPath = (review.page?.items ?? []).filter((item) => String(item.id).startsWith(PENDING_PREFIX)).map((item) => item.currentPath || item.path).find((path) => sameFile(path, active));
393777
+ const reviewPath = review.page?.overview?.coveredPaths.find((path) => sameFile(path, active)) ?? pendingPath;
393778
+ if (!active || !reviewPath) {
393723
393779
  setOfficialDetail(null);
393724
393780
  setOfficialRecords([]);
393725
393781
  return () => controller.abort();
@@ -393727,7 +393783,6 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
393727
393783
  /** @private @author ddj 2026年10月27号 Load the active file independently of the global history page. */
393728
393784
  async function loadReview() {
393729
393785
  try {
393730
- const reviewPath = review.page?.overview?.coveredPaths.find((path) => sameFile(path, active)) ?? active;
393731
393786
  const page = await rpc("edrv.review.list", {
393732
393787
  sessionId,
393733
393788
  path: reviewPath
@@ -407159,10 +407214,9 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
407159
407214
  }, [sessionId, stopDeepPoll]);
407160
407215
  /**
407161
407216
  * 深度分析入口(02-deep-session-prompt 修正版):**新建独立会话**承载任务
407162
- * (不污染当前对话),草稿箱填入分析任务(变更清单由 agent 自跑只读 svn status
407163
- * 取数,prompt 定长)→ 用户在新会话发送 → agent 投递方案回面板收件箱。
407164
- * 降级:不支持自动新建会话时回落当前对话注入 + notify 注明。
407165
- * @author ddj 2026年09月23号
407217
+ * (不污染当前对话),显式受理才等待方案;不明回执不重发或填入另一草稿。
407218
+ * 未发送或明确拒绝时仅填当前草稿,提示用户手动发送,prompt使用实际草稿会话。
407219
+ * @author ddj 2026年10月29号
407166
407220
  */
407167
407221
  const runDeepPlan = react$1.default.useCallback(() => {
407168
407222
  const live = ctxRef.current;
@@ -407178,32 +407232,58 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
407178
407232
  live?.notify?.("无法填入任务(无会话或输入框不可用)");
407179
407233
  return;
407180
407234
  }
407181
- /** 降级:当前对话注入(不支持自动新建会话时兜底)。 */
407182
- const degrade = (prompt) => {
407183
- add.appendText(sessionId, prompt).then((outcome) => {
407184
- if (outcome === "ok" || outcome === "busy") {
407185
- live?.notify?.("已填入当前对话(降级),任务已自动发送,请在本对话查看");
407186
- startDeepPoll(since);
407187
- } else live?.notify?.("发起失败:" + (outcome === "unavailable" ? "无会话或输入框不可用" : "输入框忙,请重试"));
407188
- });
407189
- };
407190
- /** 统一收尾(点击即发送方案):create 后构建 prompt(内嵌新会话 id)→ 发送任务。 */
407191
- const sendAndWatch = (id) => {
407192
- const prompt = buildAgentPrompt(wcRoot, id || sessionId || "");
407193
- if (!id || typeof add.sendTask !== "function") {
407194
- degrade(prompt);
407235
+ /** @private @author ddj 2026年10月29号 @returns Draft insertion only; never submits or starts a task poll. */
407236
+ async function draftCurrent() {
407237
+ if (!sessionId) {
407238
+ live?.notify?.("无法填入任务(无会话或输入框不可用)");
407195
407239
  return;
407196
407240
  }
407197
- add.sendTask(id, prompt).then((sent) => {
407198
- if (sent) {
407199
- live?.notify?.("已在新会话「AI 深度分析」发起任务并自动发送,请在左侧会话列表点开查看进度");
407200
- startDeepPoll(since);
407201
- } else degrade(prompt);
407202
- });
407203
- };
407204
- (add.startDraftSession ? add.startDraftSession(wcRoot || void 0) : Promise.resolve({ ok: false })).then((result) => {
407205
- sendAndWatch(result?.ok ? result.id : void 0);
407206
- });
407241
+ try {
407242
+ const outcome = await add.appendText(sessionId, buildAgentPrompt(wcRoot, sessionId));
407243
+ if (outcome === "ok" || outcome === "busy") live?.notify?.("已填入当前草稿,请手动发送");
407244
+ else live?.notify?.("发起失败:" + (outcome === "unavailable" ? "无会话或输入框不可用" : "输入框忙,请重试"));
407245
+ } catch {
407246
+ live?.notify?.("草稿填入失败,请检查当前输入框");
407247
+ }
407248
+ }
407249
+ /** @private @author ddj 2026年10月29号 @param id Created target. @returns One detailed send decision; ambiguous receipts never retry. */
407250
+ async function sendAndWatch(id) {
407251
+ if (!id) {
407252
+ await draftCurrent();
407253
+ return;
407254
+ }
407255
+ if (typeof add.sendTaskResult !== "function") {
407256
+ live?.notify?.("发送接口不支持受理确认,本次未自动发送,请手动处理");
407257
+ return;
407258
+ }
407259
+ let result;
407260
+ try {
407261
+ result = await add.sendTaskResult(id, buildAgentPrompt(wcRoot, id));
407262
+ } catch {
407263
+ result = {
407264
+ status: "unknown",
407265
+ legacyOk: false
407266
+ };
407267
+ }
407268
+ if (result?.status === "accepted") {
407269
+ live?.notify?.("已在新会话「AI 深度分析」受理任务,请在左侧会话列表点开查看进度");
407270
+ startDeepPoll(since);
407271
+ } else if (result?.status === "rejected" || result?.status === "unavailable") await draftCurrent();
407272
+ else if (result?.status === "cancelled") live?.notify?.("发送操作已取消,任务可能已提交,请检查目标会话:" + id);
407273
+ else if (result?.status === "submitted") live?.notify?.("已调用提交但受理未确认,请检查目标会话,不要重复发送:" + id);
407274
+ else live?.notify?.("任务受理未确认,请检查目标会话,不要重复发送:" + id);
407275
+ }
407276
+ /** @private @author ddj 2026年10月29号 @returns Creates a target before sending; creation failure can only insert a manual draft. */
407277
+ async function beginDeep() {
407278
+ let result;
407279
+ try {
407280
+ result = await add.startDraftSession?.(wcRoot || void 0);
407281
+ } catch {
407282
+ result = { ok: false };
407283
+ }
407284
+ await sendAndWatch(result?.ok ? result.id : void 0);
407285
+ }
407286
+ beginDeep();
407207
407287
  }, [
407208
407288
  aiBusy,
407209
407289
  aiRun,