dsh-select-quote 0.3.12 → 0.3.13

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
@@ -88,7 +88,7 @@ dsh web --patch "$PWD/dev.patch.yml"
88
88
 
89
89
  ## 已知限制
90
90
 
91
- - **待发批注按会话持久化**:刷新页面、重启客户端后回到原会话,未发送的批注会原样回来(与草稿同在 localStorage,键各自独立);保留最近 20 个会话、7 天。发送即清除,切换会话跟着切,hero 里换工作区等于换会话,批注不跟着搬。同一会话开多个标签页时通过 `storage` 事件同步,按最后写入为准;一个标签发送清空后,另一个标签不会把旧批注写回。
91
+ - **待发批注按会话持久化**:刷新页面、重启客户端后回到原会话,未发送的批注会原样回来(与草稿同在 localStorage,键各自独立);保留最近 20 个会话、7 天。发送即清除,切换会话跟着切——正文的划词标记与输入框里的批注卡同进同退:分叉出的新会话不继承批注,也**不会**留下原会话的划词;切回原会话时两者一起恢复。hero 里换工作区等于换会话,批注不跟着搬。同一会话开多个标签页时通过 `storage` 事件同步,按最后写入为准;一个标签发送清空后,另一个标签不会把旧批注写回。
92
92
  - **占用了用户气泡的渲染**:本插件以 `priority: -10` 接管内置 `user` / `steering` 节点,再委托宿主 `UserMessageNodeView` 渲染(只改写 `node` 的文本块,剥掉协议)。其它插件若也想接管这两个键,优先级数值必须小于 `-10` 才会赢过本插件;被别的接管者赢走时,本插件不再折叠消息里的协议块。
93
93
  - **摘要宽度有限**:输入框上方只有一块摘要(约输入框的 1/5,148–220px),悬停列表里的原文和评论最多显示三行;编辑批注时原文完整显示,超过 132px 在框内滚动。
94
94
  - **划词只在对话区生效**:不介入编辑器、终端等面板。
package/lib/client.js CHANGED
@@ -1494,22 +1494,32 @@ ${atomRules}
1494
1494
  padding: 2px 0;
1495
1495
  }
1496
1496
 
1497
+ /* Both settings rows follow the Host pattern: copy on the left, control on
1498
+ the right. The trigger control wraps below only when the row is too narrow. */
1497
1499
  .dsq_settingsSection {
1498
1500
  display: flex;
1499
- flex-direction: column;
1500
- gap: 10px;
1501
+ align-items: center;
1502
+ justify-content: space-between;
1503
+ flex-wrap: wrap;
1504
+ gap: 8px 16px;
1501
1505
  }
1502
1506
 
1503
1507
  .dsq_settingsCopy {
1504
1508
  display: flex;
1509
+ min-width: 0;
1505
1510
  flex-direction: column;
1506
1511
  gap: 3px;
1507
1512
  }
1508
1513
 
1514
+ .dsq_settingsSection .dsq_settingsCopy {
1515
+ flex: 1 1 240px;
1516
+ }
1517
+
1509
1518
  .dsq_settingsLabel {
1510
1519
  color: var(--dsq-label);
1511
1520
  font-size: 13px;
1512
1521
  font-weight: 500;
1522
+ line-height: 18px;
1513
1523
  }
1514
1524
 
1515
1525
  .dsq_settingsHint {
@@ -1566,8 +1576,9 @@ ${atomRules}
1566
1576
 
1567
1577
  .dsq_seg {
1568
1578
  display: inline-flex;
1569
- align-self: flex-start;
1579
+ flex: none;
1570
1580
  gap: 2px;
1581
+ margin-left: auto;
1571
1582
  padding: 2px;
1572
1583
  border-radius: 8px;
1573
1584
  background: var(--dsq-fill-hover);
@@ -2875,11 +2886,25 @@ function clearAnnotations(sessionId) {
2875
2886
  * Called from render-phase bridges, so adoption is deferred to a microtask:
2876
2887
  * the resulting notify() must not land inside another component's render.
2877
2888
  * Re-binding the same session is a no-op.
2889
+ *
2890
+ * A rebind is itself a publication even when adoption changes nothing: the
2891
+ * host mints a brand-new session id on a fork (annotations are not
2892
+ * inherited), and subscribers like the pending-mark job sync must re-read
2893
+ * the new partition so the previous session's marks are dropped instead of
2894
+ * bleeding into the forked transcript while the composer card is already
2895
+ * gone.
2896
+ *
2897
+ * A bind superseded in the same tick adopts nothing: running its adoption
2898
+ * would publish a partition that is no longer active. Its stored data is
2899
+ * untouched and is picked up when that session is bound again.
2878
2900
  */
2879
2901
  function bindAnnotationSession(sessionId) {
2880
2902
  if (!sessionId || sessionId === runtime.sessionId) return;
2881
2903
  setRuntimeSession(sessionId);
2882
- queueMicrotask(() => adoptPersistedAnnotations(sessionId));
2904
+ queueMicrotask(() => {
2905
+ if (runtime.sessionId !== sessionId) return;
2906
+ if (!adoptPersistedAnnotations(sessionId)) notify();
2907
+ });
2883
2908
  }
2884
2909
  /**
2885
2910
  * Adopt persisted annotations for a session.
@@ -2887,9 +2912,13 @@ function bindAnnotationSession(sessionId) {
2887
2912
  * In-memory entries win on conflict — they can only be newer, because anything
2888
2913
  * added after the bind is persisted immediately. Annotations parked in the
2889
2914
  * memory-only bucket (added before the bind) move over as well.
2915
+ *
2916
+ * Returns whether the partition changed (and published): `false` means the
2917
+ * stored state already matched memory, so callers that also represent "the
2918
+ * active partition moved" (see `bindAnnotationSession`) still need to publish.
2890
2919
  */
2891
2920
  function adoptPersistedAnnotations(sessionId) {
2892
- if (!persistence) return;
2921
+ if (!persistence) return false;
2893
2922
  const stored = persistence.load(sessionId);
2894
2923
  const current = bySession.get(sessionId) ?? EMPTY$1;
2895
2924
  const orphaned = bySession.get(MEMORY_KEY) ?? EMPTY$1;
@@ -2897,10 +2926,11 @@ function adoptPersistedAnnotations(sessionId) {
2897
2926
  for (const item of stored) merged.set(item.id, item);
2898
2927
  for (const item of [...current, ...orphaned]) merged.set(item.id, item);
2899
2928
  const next = [...merged.values()];
2900
- if (next.length === current.length && next.every((item, i) => item.id === current[i]?.id) && orphaned.length === 0) return;
2929
+ if (next.length === current.length && next.every((item, i) => item.id === current[i]?.id) && orphaned.length === 0) return false;
2901
2930
  bySession.set(sessionId, next);
2902
2931
  if (orphaned.length > 0) bySession.delete(MEMORY_KEY);
2903
2932
  notify();
2933
+ return true;
2904
2934
  }
2905
2935
  /** Same ids in the same order, with the only mutable field (comment) equal. */
2906
2936
  function sameAnnotations(a, b) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-select-quote",
3
- "version": "0.3.12",
3
+ "version": "0.3.13",
4
4
  "description": "DeepSeek Harness web plugin: annotate text selected in the conversation — the selection rides along with your next message, is marked in the source text, and the model points back at it.",
5
5
  "keywords": [
6
6
  "deepseek",