dsh-input-traffic 0.2.7 → 0.2.9

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.
Files changed (36) hide show
  1. package/README.en.md +47 -6
  2. package/README.md +60 -9
  3. package/lib/client.js +158 -104
  4. package/lib/client.js.map +1 -1
  5. package/lib/types/client/auto-continue-core.d.ts +103 -0
  6. package/lib/types/client/auto-continue-core.d.ts.map +1 -0
  7. package/lib/types/client/auto-continue-core.js +131 -0
  8. package/lib/types/client/auto-continue-core.js.map +1 -0
  9. package/lib/types/client/auto-continue-store.d.ts +41 -0
  10. package/lib/types/client/auto-continue-store.d.ts.map +1 -0
  11. package/lib/types/client/auto-continue-store.js +93 -0
  12. package/lib/types/client/auto-continue-store.js.map +1 -0
  13. package/lib/types/client/freeze-button.d.ts +1 -1
  14. package/lib/types/client/freeze-button.d.ts.map +1 -1
  15. package/lib/types/client/freeze-button.js +30 -6
  16. package/lib/types/client/freeze-button.js.map +1 -1
  17. package/lib/types/client/freeze-store.d.ts +17 -10
  18. package/lib/types/client/freeze-store.d.ts.map +1 -1
  19. package/lib/types/client/freeze-store.js +54 -38
  20. package/lib/types/client/freeze-store.js.map +1 -1
  21. package/lib/types/client/index.d.ts.map +1 -1
  22. package/lib/types/client/index.js +15 -12
  23. package/lib/types/client/index.js.map +1 -1
  24. package/lib/types/client/locales.d.ts +1 -0
  25. package/lib/types/client/locales.d.ts.map +1 -1
  26. package/lib/types/client/locales.js +2 -0
  27. package/lib/types/client/locales.js.map +1 -1
  28. package/lib/types/client/session-guard-bridge.d.ts +18 -0
  29. package/lib/types/client/session-guard-bridge.d.ts.map +1 -0
  30. package/lib/types/client/session-guard-bridge.js +42 -0
  31. package/lib/types/client/session-guard-bridge.js.map +1 -0
  32. package/lib/types/client/steer-queue-dock.d.ts +9 -3
  33. package/lib/types/client/steer-queue-dock.d.ts.map +1 -1
  34. package/lib/types/client/steer-queue-dock.js +6 -5
  35. package/lib/types/client/steer-queue-dock.js.map +1 -1
  36. package/package.json +104 -104
package/lib/client.js CHANGED
@@ -58,6 +58,7 @@ window.__ModuleLoader__.load({
58
58
  "steer.freeze": "冻结会话",
59
59
  "steer.resume": "恢复会话",
60
60
  "steer.frozen": "已冻结:当前轮次完成后暂停,排队消息将在恢复后继续",
61
+ "steer.frozenInput": "已冻结:输入已暂停,恢复后继续",
61
62
  "steer.frozenBadge": "已冻结",
62
63
  "steer.freezeFailed": "冻结失败,请重试。",
63
64
  "steer.resumeFailed": "恢复失败,请重试。"
@@ -109,21 +110,27 @@ window.__ModuleLoader__.load({
109
110
  "steer.freeze": "Freeze session",
110
111
  "steer.resume": "Resume session",
111
112
  "steer.frozen": "Frozen: the current turn finishes, then the queue pauses until resumed",
113
+ "steer.frozenInput": "Frozen: input paused, resume to continue",
112
114
  "steer.frozenBadge": "frozen",
113
115
  "steer.freezeFailed": "Freeze failed, please retry.",
114
116
  "steer.resumeFailed": "Resume failed, please retry."
115
117
  };
116
118
  //#endregion
117
119
  //#region src/client/freeze-store.ts
120
+ /** Session id → per-session freeze state. */
121
+ const states = /* @__PURE__ */ new Map();
118
122
  const listeners = /* @__PURE__ */ new Set();
119
- let state = {
123
+ /** Stable empty snapshot: `useSyncExternalStore` needs a reference-stable
124
+ * value for unset sessions so unchanged consumers never re-render. */
125
+ const EMPTY = {
120
126
  frozen: false,
121
127
  pending: []
122
128
  };
123
129
  /** Minimal snapshot store (no runtime dependency, stable identity per mount). */
124
130
  const freezeStore = {
125
- getSnapshot() {
126
- return state;
131
+ /** Snapshot for one session; reference-stable until that session changes. */
132
+ getSnapshot(sessionId) {
133
+ return states.get(sessionId) ?? EMPTY;
127
134
  },
128
135
  subscribe(listener) {
129
136
  listeners.add(listener);
@@ -131,71 +138,74 @@ window.__ModuleLoader__.load({
131
138
  listeners.delete(listener);
132
139
  };
133
140
  },
134
- set(next) {
135
- state = next;
136
- for (const listener of listeners) listener();
141
+ /** Replace one session's state; unset sessions fall back to EMPTY. */
142
+ set(sessionId, next) {
143
+ if (next.frozen === false && next.pending.length === 0) states.delete(sessionId);
144
+ else states.set(sessionId, next);
145
+ emit();
137
146
  }
138
147
  };
139
148
  /** Edit one detached queued message's text in place. */
140
- function updatePendingAt(index, text) {
141
- const pending = [...state.pending];
142
- if (index < 0 || index >= pending.length) return;
149
+ function updatePendingAt(sessionId, index, text) {
150
+ const pending = states.get(sessionId)?.pending;
151
+ if (pending === void 0) return;
143
152
  const entry = pending[index];
144
153
  if (entry === void 0) return;
145
- pending[index] = {
154
+ const next = [...pending];
155
+ next[index] = {
146
156
  ...entry,
147
157
  text
148
158
  };
149
- state = {
150
- ...state,
151
- pending
152
- };
153
- emit();
159
+ freezeStore.set(sessionId, {
160
+ frozen: true,
161
+ pending: next
162
+ });
154
163
  }
155
164
  /** Change one detached queued message's planned insertion tier. */
156
- function setTierAt(index, tier) {
157
- const pending = [...state.pending];
158
- if (index < 0 || index >= pending.length) return;
165
+ function setTierAt(sessionId, index, tier) {
166
+ const pending = states.get(sessionId)?.pending;
167
+ if (pending === void 0) return;
159
168
  const entry = pending[index];
160
169
  if (entry === void 0) return;
161
- pending[index] = {
170
+ const next = [...pending];
171
+ next[index] = {
162
172
  ...entry,
163
173
  tier
164
174
  };
165
- state = {
166
- ...state,
167
- pending
168
- };
169
- emit();
175
+ freezeStore.set(sessionId, {
176
+ frozen: true,
177
+ pending: next
178
+ });
170
179
  }
171
180
  /** Remove one detached queued message. */
172
- function removePendingAt(index) {
173
- if (index < 0 || index >= state.pending.length) return;
174
- state = {
175
- ...state,
176
- pending: state.pending.filter((_, i) => i !== index)
177
- };
178
- emit();
181
+ function removePendingAt(sessionId, index) {
182
+ const pending = states.get(sessionId)?.pending;
183
+ if (pending === void 0) return;
184
+ freezeStore.set(sessionId, {
185
+ frozen: true,
186
+ pending: pending.filter((_, i) => i !== index)
187
+ });
179
188
  }
180
189
  /** Move one detached queued message to a new position (reorder while frozen). */
181
- function movePending(from, to) {
190
+ function movePending(sessionId, from, to) {
182
191
  if (from === to) return;
183
- const pending = [...state.pending];
184
- const [moved] = pending.splice(from, 1);
192
+ const pending = states.get(sessionId)?.pending;
193
+ if (pending === void 0) return;
194
+ const next = [...pending];
195
+ const [moved] = next.splice(from, 1);
185
196
  if (moved === void 0) return;
186
- pending.splice(to, 0, moved);
187
- state = {
188
- ...state,
189
- pending
190
- };
191
- emit();
197
+ next.splice(to, 0, moved);
198
+ freezeStore.set(sessionId, {
199
+ frozen: true,
200
+ pending: next
201
+ });
192
202
  }
193
203
  function emit() {
194
204
  for (const listener of listeners) listener();
195
205
  }
196
206
  //#endregion
197
207
  //#region \0dsh-css:E:\test\rewrite-agently\dsh-input-traffic\src\client\steer-queue-dock.module.css.mjs
198
- const css$1 = ".cev0eq_dock{width:100%}.cev0eq_panel{background:var(--ds-color-surface,#fffc);border:1px solid var(--ds-color-border,#00000014);border-radius:10px;overflow:hidden}.cev0eq_toolbar{border-bottom:1px solid var(--ds-color-border,#0000000f);align-items:center;gap:8px;padding:4px 8px;display:flex}.cev0eq_header{color:var(--ds-color-text-secondary,#6b7280);cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:2px 6px;font-size:12px;display:inline-flex}.cev0eq_header:disabled{cursor:default}.cev0eq_lead{color:var(--ds-color-text-tertiary,#9ca3af);display:inline-flex}.cev0eq_count{font-weight:600}.cev0eq_chevron{color:var(--ds-color-text-tertiary,#9ca3af);display:inline-flex}.cev0eq_toolbarActions{margin-left:auto}.cev0eq_clear{color:var(--ds-color-text-secondary,#6b7280);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:4px;padding:3px 8px;font-size:12px;display:inline-flex}.cev0eq_freeze{border:1px solid var(--ds-color-border,#0000001f);color:var(--ds-color-text-secondary,#6b7280);cursor:pointer;background:0 0;border-radius:6px;align-items:center;gap:4px;padding:3px 8px;font-size:12px;display:inline-flex}.cev0eq_freeze[aria-pressed=true]{border-color:var(--ds-steer-green,#30a46c);color:var(--ds-steer-green,#30a46c)}.cev0eq_freeze:hover:not(:disabled){background:var(--ds-color-surface-hover,#0000000a)}.cev0eq_freeze:disabled{opacity:.5;cursor:default}.cev0eq_frozenBanner{border-bottom:1px solid var(--ds-color-border,#0000000f);background:color-mix(in srgb, var(--ds-steer-green,#30a46c) 8%, transparent);color:var(--ds-steer-green,#30a46c);padding:4px 10px;font-size:12px}.cev0eq_frozenList{margin:0;padding:4px;list-style:none}.cev0eq_frozenRow{border-radius:6px;align-items:center;gap:8px;padding:4px 6px;display:flex}.cev0eq_frozenMark{color:var(--ds-color-text-tertiary,#9ca3af);flex:none;margin-left:auto;font-size:11px}.cev0eq_clear:hover:not(:disabled){border-color:var(--ds-color-border,#0000001f);background:var(--ds-color-surface-hover,#0000000a)}.cev0eq_clear:disabled{opacity:.5;cursor:default}.cev0eq_clearConfirm{border-color:var(--ds-steer-red,#e5484d);color:var(--ds-steer-red,#e5484d)}.cev0eq_clearConfirm:hover:not(:disabled){border-color:var(--ds-steer-red,#e5484d);background:color-mix(in srgb, var(--ds-steer-red,#e5484d) 8%, transparent)}.cev0eq_clearCancel{color:var(--ds-color-text-secondary,#6b7280);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:4px;padding:3px 8px;font-size:12px;display:inline-flex}.cev0eq_clearCancel:hover:not(:disabled){background:var(--ds-color-surface-hover,#0000000a)}.cev0eq_clearLabel{font-size:12px}.cev0eq_list{margin:0;padding:4px;list-style:none}.cev0eq_row{border-radius:6px;align-items:center;gap:8px;padding:4px 6px;display:flex}.cev0eq_row[draggable=true]{cursor:grab}.cev0eq_row[draggable=true]:active{cursor:grabbing}.cev0eq_rowDragOver{outline:2px dashed var(--ds-color-border-strong,#00000040);outline-offset:-2px;background:var(--ds-color-surface-hover,#0000000d)}.cev0eq_row:hover{background:var(--ds-color-surface-hover,#00000008)}.cev0eq_row[data-editing]{align-items:flex-start}.cev0eq_preview{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--ds-color-text,#1f2937);flex:1;font-size:13px;overflow:hidden}.cev0eq_badge{white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:4px;padding:1px 6px;font-size:11px;line-height:16px;display:inline-flex}.cev0eq_badgeLabel{color:inherit}.cev0eq_badgeNow{color:var(--ds-steer-red,#e5484d);background:color-mix(in srgb, var(--ds-steer-red,#e5484d) 10%, transparent)}.cev0eq_badgeNext{color:var(--ds-steer-yellow,#e8a33d);background:color-mix(in srgb, var(--ds-steer-yellow,#e8a33d) 12%, transparent)}.cev0eq_badgeLater{color:var(--ds-steer-green,#30a46c);background:color-mix(in srgb, var(--ds-steer-green,#30a46c) 12%, transparent)}.cev0eq_badgeNow .cev0eq_dot{background:var(--ds-steer-red,#e5484d)}.cev0eq_badgeNext .cev0eq_dot{background:var(--ds-steer-yellow,#e8a33d)}.cev0eq_badgeLater .cev0eq_dot{background:var(--ds-steer-green,#30a46c)}.cev0eq_steeringList{margin:0;padding:0 4px 4px;list-style:none}.cev0eq_steeringList .cev0eq_row{opacity:.85}.cev0eq_editor{border:1px solid var(--ds-color-border,#00000026);background:var(--ds-color-surface,#fff);resize:none;border-radius:6px;flex:1;min-width:0;max-height:160px;padding:4px 6px;font-size:13px;line-height:20px;overflow-y:auto}.cev0eq_actions{align-items:center;gap:2px;display:inline-flex}.cev0eq_action{width:24px;height:24px;color:var(--ds-color-text-tertiary,#9ca3af);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.cev0eq_action:hover:not(:disabled){background:var(--ds-color-surface-hover,#0000000d);color:var(--ds-color-text,#1f2937)}.cev0eq_action:disabled{opacity:.4;cursor:default}.cev0eq_plan{border-left:1px solid var(--ds-color-border,#00000014);align-items:center;gap:2px;margin-left:4px;padding-left:6px;display:inline-flex}.cev0eq_tier{cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;display:inline-flex}.cev0eq_tier:hover:not(:disabled){border-color:var(--ds-color-border,#0003)}.cev0eq_tier:disabled{cursor:default}.cev0eq_tierLater{border-color:var(--ds-steer-green,#30a46c);background:color-mix(in srgb, var(--ds-steer-green,#30a46c) 12%, transparent)}.cev0eq_dot{border-radius:50%;width:10px;height:10px}.cev0eq_tierNow .cev0eq_dot{background:var(--ds-steer-red,#e5484d)}.cev0eq_tierNext .cev0eq_dot{background:var(--ds-steer-yellow,#e8a33d)}.cev0eq_tierLater .cev0eq_dot{background:var(--ds-steer-green,#30a46c)}";
208
+ const css$1 = ".cev0eq_dock{width:100%}.cev0eq_panel{background:var(--dsw-alias-bg-layer-1,#fffc);border:1px solid var(--dsw-alias-border-l2,#00000014);border-radius:10px;overflow:hidden}.cev0eq_toolbar{border-bottom:1px solid var(--dsw-alias-border-l2,#0000000f);align-items:center;gap:8px;padding:4px 8px;display:flex}.cev0eq_header{color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:2px 6px;font-size:12px;display:inline-flex}.cev0eq_header:disabled{cursor:default}.cev0eq_lead{color:var(--dsw-alias-label-tertiary,#9ca3af);display:inline-flex}.cev0eq_count{font-weight:600}.cev0eq_chevron{color:var(--dsw-alias-label-tertiary,#9ca3af);display:inline-flex}.cev0eq_toolbarActions{margin-left:auto}.cev0eq_clear{color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:4px;padding:3px 8px;font-size:12px;display:inline-flex}.cev0eq_freeze{border:1px solid var(--dsw-alias-border-l3,#0000001f);color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border-radius:6px;align-items:center;gap:4px;padding:3px 8px;font-size:12px;display:inline-flex}.cev0eq_freeze[aria-pressed=true]{border-color:var(--dsw-alias-state-success-primary,#30a46c);color:var(--dsw-alias-state-success-primary,#30a46c)}.cev0eq_freeze:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#0000000a)}.cev0eq_freeze:disabled{opacity:.5;cursor:default}.cev0eq_frozenBanner{border-bottom:1px solid var(--dsw-alias-border-l2,#0000000f);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#30a46c) 8%, transparent);color:var(--dsw-alias-state-success-primary,#30a46c);padding:4px 10px;font-size:12px}.cev0eq_frozenList{margin:0;padding:4px;list-style:none}.cev0eq_frozenRow{border-radius:6px;align-items:center;gap:8px;padding:4px 6px;display:flex}.cev0eq_frozenMark{color:var(--dsw-alias-label-tertiary,#9ca3af);flex:none;margin-left:auto;font-size:11px}.cev0eq_clear:hover:not(:disabled){border-color:var(--dsw-alias-border-l3,#0000001f);background:var(--dsw-alias-interactive-bg-hover,#0000000a)}.cev0eq_clear:disabled{opacity:.5;cursor:default}.cev0eq_clearConfirm{border-color:var(--dsw-alias-state-error-primary,#e5484d);color:var(--dsw-alias-state-error-primary,#e5484d)}.cev0eq_clearConfirm:hover:not(:disabled){border-color:var(--dsw-alias-state-error-primary,#e5484d);background:color-mix(in srgb, var(--dsw-alias-state-error-primary,#e5484d) 8%, transparent)}.cev0eq_clearCancel{color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:4px;padding:3px 8px;font-size:12px;display:inline-flex}.cev0eq_clearCancel:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#0000000a)}.cev0eq_clearLabel{font-size:12px}.cev0eq_list{margin:0;padding:4px;list-style:none}.cev0eq_row{border-radius:6px;align-items:center;gap:8px;padding:4px 6px;display:flex}.cev0eq_row[draggable=true]{cursor:grab}.cev0eq_row[draggable=true]:active{cursor:grabbing}.cev0eq_rowDragOver{outline:2px dashed var(--dsw-alias-border-l4,#00000040);outline-offset:-2px;background:var(--dsw-alias-interactive-bg-hover,#0000000d)}.cev0eq_row:hover{background:var(--dsw-alias-interactive-bg-hover,#00000008)}.cev0eq_row[data-editing]{align-items:flex-start}.cev0eq_preview{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary,#1f2937);flex:1;font-size:13px;overflow:hidden}.cev0eq_badge{white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:4px;padding:1px 6px;font-size:11px;line-height:16px;display:inline-flex}.cev0eq_badgeLabel{color:inherit}.cev0eq_badgeNow{color:var(--dsw-alias-state-error-primary,#e5484d);background:color-mix(in srgb, var(--dsw-alias-state-error-primary,#e5484d) 10%, transparent)}.cev0eq_badgeNext{color:var(--dsw-alias-state-warn-primary,#e8a33d);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary,#e8a33d) 12%, transparent)}.cev0eq_badgeLater{color:var(--dsw-alias-state-success-primary,#30a46c);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#30a46c) 12%, transparent)}.cev0eq_badgeNow .cev0eq_dot{background:var(--dsw-alias-state-error-primary,#e5484d)}.cev0eq_badgeNext .cev0eq_dot{background:var(--dsw-alias-state-warn-primary,#e8a33d)}.cev0eq_badgeLater .cev0eq_dot{background:var(--dsw-alias-state-success-primary,#30a46c)}.cev0eq_steeringList{margin:0;padding:0 4px 4px;list-style:none}.cev0eq_steeringList .cev0eq_row{opacity:.85}.cev0eq_editor{border:1px solid var(--dsw-alias-border-l3,#00000026);background:var(--dsw-alias-bg-layer-2,#fff);resize:none;border-radius:6px;flex:1;min-width:0;max-height:160px;padding:4px 6px;font-size:13px;line-height:20px;overflow-y:auto}.cev0eq_actions{align-items:center;gap:2px;display:inline-flex}.cev0eq_action{width:24px;height:24px;color:var(--dsw-alias-label-tertiary,#9ca3af);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.cev0eq_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#0000000d);color:var(--dsw-alias-label-primary,#1f2937)}.cev0eq_action:disabled{opacity:.4;cursor:default}.cev0eq_plan{border-left:1px solid var(--dsw-alias-border-l2,#00000014);align-items:center;gap:2px;margin-left:4px;padding-left:6px;display:inline-flex}.cev0eq_tier{cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;display:inline-flex}.cev0eq_tier:hover:not(:disabled){border-color:var(--dsw-alias-border-l4,#0003)}.cev0eq_tier:disabled{cursor:default}.cev0eq_tierLater{border-color:var(--dsw-alias-state-success-primary,#30a46c);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#30a46c) 12%, transparent)}.cev0eq_dot{border-radius:50%;width:10px;height:10px}.cev0eq_tierNow .cev0eq_dot{background:var(--dsw-alias-state-error-primary,#e5484d)}.cev0eq_tierNext .cev0eq_dot{background:var(--dsw-alias-state-warn-primary,#e8a33d)}.cev0eq_tierLater .cev0eq_dot{background:var(--dsw-alias-state-success-primary,#30a46c)}";
199
209
  const tagId$1 = "dsh-input-traffic/steer-queue-dock.module.css";
200
210
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
201
211
  const tag = document.createElement("style");
@@ -205,42 +215,42 @@ window.__ModuleLoader__.load({
205
215
  document.head.appendChild(tag);
206
216
  }
207
217
  var steer_queue_dock_module_css_default = {
208
- "badge": "cev0eq_badge",
209
- "editor": "cev0eq_editor",
210
- "panel": "cev0eq_panel",
211
- "freeze": "cev0eq_freeze",
212
- "header": "cev0eq_header",
213
- "count": "cev0eq_count",
214
- "dot": "cev0eq_dot",
215
- "tier": "cev0eq_tier",
216
- "chevron": "cev0eq_chevron",
218
+ "preview": "cev0eq_preview",
219
+ "action": "cev0eq_action",
220
+ "badgeLabel": "cev0eq_badgeLabel",
221
+ "frozenList": "cev0eq_frozenList",
222
+ "tierNext": "cev0eq_tierNext",
223
+ "badgeNext": "cev0eq_badgeNext",
224
+ "row": "cev0eq_row",
225
+ "clearConfirm": "cev0eq_clearConfirm",
217
226
  "clearLabel": "cev0eq_clearLabel",
227
+ "plan": "cev0eq_plan",
228
+ "rowDragOver": "cev0eq_rowDragOver",
229
+ "actions": "cev0eq_actions",
218
230
  "tierNow": "cev0eq_tierNow",
219
- "steeringList": "cev0eq_steeringList",
220
- "row": "cev0eq_row",
231
+ "badgeLater": "cev0eq_badgeLater",
232
+ "badge": "cev0eq_badge",
233
+ "lead": "cev0eq_lead",
234
+ "header": "cev0eq_header",
235
+ "list": "cev0eq_list",
221
236
  "frozenMark": "cev0eq_frozenMark",
222
- "tierLater": "cev0eq_tierLater",
223
- "actions": "cev0eq_actions",
224
- "dock": "cev0eq_dock",
237
+ "steeringList": "cev0eq_steeringList",
238
+ "tier": "cev0eq_tier",
239
+ "frozenRow": "cev0eq_frozenRow",
225
240
  "clear": "cev0eq_clear",
226
- "tierNext": "cev0eq_tierNext",
227
241
  "frozenBanner": "cev0eq_frozenBanner",
228
- "action": "cev0eq_action",
229
- "badgeNow": "cev0eq_badgeNow",
242
+ "dot": "cev0eq_dot",
243
+ "tierLater": "cev0eq_tierLater",
244
+ "chevron": "cev0eq_chevron",
245
+ "count": "cev0eq_count",
246
+ "panel": "cev0eq_panel",
230
247
  "toolbar": "cev0eq_toolbar",
231
- "list": "cev0eq_list",
232
- "clearConfirm": "cev0eq_clearConfirm",
233
- "preview": "cev0eq_preview",
234
- "badgeLabel": "cev0eq_badgeLabel",
235
- "plan": "cev0eq_plan",
236
- "clearCancel": "cev0eq_clearCancel",
237
- "rowDragOver": "cev0eq_rowDragOver",
238
248
  "toolbarActions": "cev0eq_toolbarActions",
239
- "lead": "cev0eq_lead",
240
- "frozenList": "cev0eq_frozenList",
241
- "badgeNext": "cev0eq_badgeNext",
242
- "badgeLater": "cev0eq_badgeLater",
243
- "frozenRow": "cev0eq_frozenRow"
249
+ "editor": "cev0eq_editor",
250
+ "dock": "cev0eq_dock",
251
+ "freeze": "cev0eq_freeze",
252
+ "badgeNow": "cev0eq_badgeNow",
253
+ "clearCancel": "cev0eq_clearCancel"
244
254
  };
245
255
  //#endregion
246
256
  //#region src/client/steer-queue-dock.tsx
@@ -298,7 +308,7 @@ window.__ModuleLoader__.load({
298
308
  * Queue strip with three-tier planning: one item renders directly; multiple
299
309
  * items default to a collapsible count header; an empty queue renders nothing.
300
310
  */
301
- function SteerQueueDock({ useSession, input, updateQueue, cancel, send, setDraft, notify, t }) {
311
+ function SteerQueueDock({ sessionId, useSession, input, updateQueue, cancel, send, setDraft, notify, t }) {
302
312
  const inbox = useSession((s) => s.queue);
303
313
  const queue = (0, react.useMemo)(() => inbox.filter((row) => row.placement === "queued"), [inbox]);
304
314
  const steering = (0, react.useMemo)(() => inbox.filter((row) => row.placement === "steering"), [inbox]);
@@ -319,7 +329,8 @@ window.__ModuleLoader__.load({
319
329
  return true;
320
330
  }
321
331
  });
322
- const { frozen, pending: frozenPending } = (0, react.useSyncExternalStore)(freezeStore.subscribe, freezeStore.getSnapshot);
332
+ const { frozen, pending: frozenPending } = (0, react.useSyncExternalStore)(freezeStore.subscribe, () => freezeStore.getSnapshot(sessionId ?? ""));
333
+ const sid = sessionId ?? "";
323
334
  const listId = (0, react.useId)();
324
335
  const editorRef = (0, react.useRef)(null);
325
336
  (0, react.useEffect)(() => {
@@ -507,7 +518,7 @@ window.__ModuleLoader__.load({
507
518
  setEditing(null);
508
519
  return;
509
520
  }
510
- updatePendingAt(index, text);
521
+ updatePendingAt(sid, index, text);
511
522
  setEditing(null);
512
523
  };
513
524
  /**
@@ -635,7 +646,7 @@ window.__ModuleLoader__.load({
635
646
  const from = dragIndex.current;
636
647
  dragIndex.current = null;
637
648
  setDragOver(null);
638
- if (from !== null) movePending(from, i);
649
+ if (from !== null) movePending(sid, from, i);
639
650
  },
640
651
  onDragEnd: () => {
641
652
  dragIndex.current = null;
@@ -721,7 +732,7 @@ window.__ModuleLoader__.load({
721
732
  className: steer_queue_dock_module_css_default.action,
722
733
  "aria-label": t("steer.moveUp"),
723
734
  disabled: i === 0,
724
- onClick: () => movePending(i, i - 1),
735
+ onClick: () => movePending(sid, i, i - 1),
725
736
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, {})
726
737
  })
727
738
  }),
@@ -735,7 +746,7 @@ window.__ModuleLoader__.load({
735
746
  className: steer_queue_dock_module_css_default.action,
736
747
  "aria-label": t("steer.moveDown"),
737
748
  disabled: i === frozenPending.length - 1,
738
- onClick: () => movePending(i, i + 1),
749
+ onClick: () => movePending(sid, i, i + 1),
739
750
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
740
751
  })
741
752
  }),
@@ -764,7 +775,7 @@ window.__ModuleLoader__.load({
764
775
  type: "button",
765
776
  className: steer_queue_dock_module_css_default.action,
766
777
  "aria-label": t("queue.remove"),
767
- onClick: () => removePendingAt(i),
778
+ onClick: () => removePendingAt(sid, i),
768
779
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
769
780
  })
770
781
  }),
@@ -782,7 +793,7 @@ window.__ModuleLoader__.load({
782
793
  className: `${steer_queue_dock_module_css_default.tier} ${steer_queue_dock_module_css_default.tierNow}`,
783
794
  "aria-label": t("steer.now"),
784
795
  "aria-pressed": entry.tier === "force" || void 0,
785
- onClick: () => setTierAt(i, "force"),
796
+ onClick: () => setTierAt(sid, i, "force"),
786
797
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
787
798
  className: steer_queue_dock_module_css_default.dot,
788
799
  "aria-hidden": true
@@ -798,7 +809,7 @@ window.__ModuleLoader__.load({
798
809
  className: `${steer_queue_dock_module_css_default.tier} ${steer_queue_dock_module_css_default.tierNext}`,
799
810
  "aria-label": t("steer.next"),
800
811
  "aria-pressed": entry.tier === "safe_point" || void 0,
801
- onClick: () => setTierAt(i, "safe_point"),
812
+ onClick: () => setTierAt(sid, i, "safe_point"),
802
813
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
803
814
  className: steer_queue_dock_module_css_default.dot,
804
815
  "aria-hidden": true
@@ -814,7 +825,7 @@ window.__ModuleLoader__.load({
814
825
  className: `${steer_queue_dock_module_css_default.tier} ${steer_queue_dock_module_css_default.tierLater}`,
815
826
  "aria-label": t("steer.later"),
816
827
  "aria-pressed": entry.tier === "queue" || void 0,
817
- onClick: () => setTierAt(i, "queue"),
828
+ onClick: () => setTierAt(sid, i, "queue"),
818
829
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
819
830
  className: steer_queue_dock_module_css_default.dot,
820
831
  "aria-hidden": true
@@ -1168,8 +1179,47 @@ window.__ModuleLoader__.load({
1168
1179
  });
1169
1180
  }
1170
1181
  //#endregion
1182
+ //#region src/client/session-guard-bridge.ts
1183
+ /**
1184
+ * input-traffic ↔ dsh-session-guard 透传桥(D8 fail-open)。
1185
+ *
1186
+ * input-traffic **只做冻结增强**(队列冻结/解冻),服务端会话门(暂停/恢复会话)
1187
+ * 归 dsh-session-guard 插件。冻结/解冻按钮触发时,尽力调用
1188
+ * `sessionGuard.stopNextTurn` / `resume`;**插件未装**(路由 404 / 网络失败 /
1189
+ * 返回错误)→ 静默跳过,**绝不报错**,前端冻结仍正常生效。
1190
+ *
1191
+ * 不吸收任何 auto-continue / 重试逻辑(重试归后端 dsh-session-guard,D9)。
1192
+ */
1193
+ /** 尽力调用 sessionGuard.stopNextTurn(停掉 session 下一回合)。失败静默。 */
1194
+ async function sessionGuardStopNextTurn(sessionId) {
1195
+ return callGuard(sessionId, "stopNextTurn");
1196
+ }
1197
+ /** 尽力调用 sessionGuard.resume。失败静默。 */
1198
+ async function sessionGuardResume(sessionId) {
1199
+ return callGuard(sessionId, "resume");
1200
+ }
1201
+ async function callGuard(sessionId, action) {
1202
+ try {
1203
+ const res = await fetch("/session-guard/rpc", {
1204
+ method: "POST",
1205
+ headers: { "content-type": "application/json" },
1206
+ body: JSON.stringify({
1207
+ sessionId,
1208
+ action
1209
+ })
1210
+ });
1211
+ if (!res.ok) return false;
1212
+ return (await res.json().catch(() => null))?.ok === true;
1213
+ } catch {
1214
+ return false;
1215
+ }
1216
+ }
1217
+ try {
1218
+ globalThis.__DSH_SESSION_GUARD_BRIDGE__ = true;
1219
+ } catch {}
1220
+ //#endregion
1171
1221
  //#region \0dsh-css:E:\test\rewrite-agently\dsh-input-traffic\src\client\freeze-button.module.css.mjs
1172
- const css = ".Klmgza_freeze{border:1px solid var(--ds-color-border,#0000001f);height:24px;color:var(--ds-color-text-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border-radius:6px;align-items:center;gap:4px;padding:0 8px;font-size:12px;display:inline-flex}.Klmgza_freeze:hover:not(:disabled){background:var(--ds-color-surface-hover,#0000000a)}.Klmgza_freeze[aria-pressed=true]{border-color:var(--ds-steer-green,#30a46c);color:var(--ds-steer-green,#30a46c);background:color-mix(in srgb, var(--ds-steer-green,#30a46c) 8%, transparent)}.Klmgza_label{font-size:12px}";
1222
+ const css = ".Klmgza_freeze{border:1px solid var(--dsw-alias-border-l3,#0000001f);height:24px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;white-space:nowrap;background:0 0;border-radius:6px;align-items:center;gap:4px;padding:0 8px;font-size:12px;display:inline-flex}.Klmgza_freeze:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#0000000a)}.Klmgza_freeze[aria-pressed=true]{border-color:var(--dsw-alias-state-success-primary,#30a46c);color:var(--dsw-alias-state-success-primary,#30a46c);background:color-mix(in srgb, var(--dsw-alias-state-success-primary,#30a46c) 8%, transparent)}.Klmgza_label{font-size:12px}";
1173
1223
  const tagId = "dsh-input-traffic/freeze-button.module.css";
1174
1224
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
1175
1225
  const tag = document.createElement("style");
@@ -1193,13 +1243,21 @@ window.__ModuleLoader__.load({
1193
1243
  * the shared store), so the driver finds no pending work and stops after the
1194
1244
  * current turn. Resume re-submits the preserved texts, waking the driver and
1195
1245
  * continuing the queue.
1246
+ *
1247
+ * dsh-session-guard 协作(D8 fail-open):
1248
+ * - 冻结 = 前端摘队列(本插件)+ composer block(阻止新输入漏进对话) + 尽力调服务端
1249
+ * sessionGuard.stopNextTurn(停掉 session 下一回合;session-guard 未装时静默跳过)。
1250
+ * - 解冻 = 清 composer block + **先** await sessionGuard.resume(让被打断回合的自然
1251
+ * 下一步先发生),**再**重投队列(later 级条目因此排在自然 next turn 之后,不再插队)。
1252
+ * - 本插件只做冻结增强,不承担重试/暂停决策(归后端,D9)。
1196
1253
  */
1197
1254
  /**
1198
1255
  * Freeze/resume toggle for the peak-hour scenario.
1199
1256
  * @param props - slot props; the session snapshot drives the detach list.
1200
1257
  */
1201
- function FreezeButton({ session, updateQueue, cancel, send, sendSteer, notify, t }) {
1202
- const { frozen } = (0, react.useSyncExternalStore)(freezeStore.subscribe, freezeStore.getSnapshot);
1258
+ function FreezeButton({ session, updateQueue, cancel, send, sendSteer, sessionId, setComposerBlock, notify, t }) {
1259
+ const sid = sessionId ?? "";
1260
+ const { frozen } = (0, react.useSyncExternalStore)(freezeStore.subscribe, () => freezeStore.getSnapshot(sid));
1203
1261
  const freeze = async () => {
1204
1262
  const rows = session.queue.filter((row) => row.placement === "queued" || row.placement === "steering");
1205
1263
  const pending = rows.flatMap((row) => row.text === null ? [] : [{
@@ -1207,21 +1265,25 @@ window.__ModuleLoader__.load({
1207
1265
  tier: row.placement === "steering" ? "safe_point" : "queue"
1208
1266
  }]);
1209
1267
  await Promise.all(rows.map((row) => updateQueue(row.id, { kind: "remove" }).catch(() => void 0)));
1210
- freezeStore.set({
1268
+ freezeStore.set(sid, {
1211
1269
  frozen: true,
1212
1270
  pending
1213
1271
  });
1272
+ setComposerBlock?.(t("steer.frozenInput"));
1273
+ if (sessionId !== void 0) sessionGuardStopNextTurn(sessionId);
1214
1274
  };
1215
1275
  const resume = async () => {
1216
- const pending = freezeStore.getSnapshot().pending;
1217
- freezeStore.set({
1276
+ const pending = freezeStore.getSnapshot(sid).pending;
1277
+ freezeStore.set(sid, {
1218
1278
  frozen: false,
1219
1279
  pending: []
1220
1280
  });
1281
+ setComposerBlock?.(void 0);
1221
1282
  try {
1283
+ if (sessionId !== void 0) await sessionGuardResume(sessionId);
1222
1284
  for (const entry of pending) {
1223
1285
  if (entry.tier === "force") await cancel();
1224
- if (entry.tier === "safe_point") await sendSteer(entry.text);
1286
+ if (entry.tier === "safe_point" && sendSteer !== void 0) await sendSteer(entry.text);
1225
1287
  else await send(entry.text);
1226
1288
  }
1227
1289
  } catch {
@@ -1264,21 +1326,10 @@ window.__ModuleLoader__.load({
1264
1326
  * @param actx - agent-scoped context of the owning session.
1265
1327
  * @param text - message text to deliver.
1266
1328
  */
1267
- function steerPrompt(ctx, actx, text) {
1268
- const session = ctx.sessions.sessionOf(actx);
1269
- if (session === void 0) return Promise.reject(/* @__PURE__ */ new Error("steer resume: session scope unavailable"));
1270
- return session.prompt([{
1271
- type: "text",
1272
- text
1273
- }], "steer").then((result) => {
1274
- if (!result.ok) {
1275
- const error = result.error ?? {
1276
- code: "unknown",
1277
- message: "steer prompt rejected"
1278
- };
1279
- throw new Error(`conversation.sendSteer failed: ${error.code}: ${error.message}`);
1280
- }
1281
- });
1329
+ function steerPrompt(actx, text) {
1330
+ const conversation = actx.get("conversation");
1331
+ if (conversation === void 0) return Promise.reject(/* @__PURE__ */ new Error("steer resume: conversation service unavailable"));
1332
+ return conversation.send(text);
1282
1333
  }
1283
1334
  /** Services required by the browser half. */
1284
1335
  const inject = [
@@ -1314,7 +1365,6 @@ window.__ModuleLoader__.load({
1314
1365
  updateQueue: (itemId, action) => conversation.updateQueue(itemId, action),
1315
1366
  cancel: () => conversation.cancel(),
1316
1367
  send: (text) => conversation.send(text),
1317
- sendSteer: (text) => steerPrompt(ctx, actx, text),
1318
1368
  setDraft: (text) => {
1319
1369
  conversation.input.for(actx).actions.setDraft(text);
1320
1370
  },
@@ -1338,12 +1388,16 @@ window.__ModuleLoader__.load({
1338
1388
  updateQueue: (itemId, action) => conversation.updateQueue(itemId, action),
1339
1389
  cancel: () => conversation.cancel(),
1340
1390
  send: (text) => conversation.send(text),
1341
- sendSteer: (text) => steerPrompt(ctx, actx, text),
1391
+ sendSteer: (text) => steerPrompt(actx, text),
1392
+ sessionId: String(sessionId),
1342
1393
  setDraft: (text) => {
1343
1394
  conversation.input.for(actx).actions.setDraft(text);
1344
1395
  },
1345
1396
  notify: (level, text) => {
1346
1397
  conversation.input.for(actx).notify(level, text);
1398
+ },
1399
+ setComposerBlock: (reason) => {
1400
+ conversation.blocks.set(sessionId, reason === void 0 ? void 0 : { reason });
1347
1401
  }
1348
1402
  };
1349
1403
  }