dsh-input-traffic 0.2.8 → 0.2.10-beta.1

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 (39) hide show
  1. package/CHANGELOG.ja.md +78 -0
  2. package/CHANGELOG.ko.md +78 -0
  3. package/CHANGELOG.md +92 -0
  4. package/INSTALL.ja.md +151 -0
  5. package/INSTALL.ko.md +151 -0
  6. package/INSTALL.md +152 -0
  7. package/INSTALL.zh.md +151 -0
  8. package/README.en.md +63 -7
  9. package/README.ja.md +187 -0
  10. package/README.ko.md +181 -0
  11. package/README.md +86 -10
  12. package/dsh.plugin.json +13 -0
  13. package/lib/client.js +1433 -1338
  14. package/lib/client.js.map +1 -1
  15. package/lib/types/client/freeze-button.d.ts +16 -9
  16. package/lib/types/client/freeze-button.d.ts.map +1 -1
  17. package/lib/types/client/freeze-button.js +86 -55
  18. package/lib/types/client/freeze-button.js.map +1 -1
  19. package/lib/types/client/freeze-store.d.ts +17 -10
  20. package/lib/types/client/freeze-store.d.ts.map +1 -1
  21. package/lib/types/client/freeze-store.js +54 -38
  22. package/lib/types/client/freeze-store.js.map +1 -1
  23. package/lib/types/client/index.d.ts +47 -24
  24. package/lib/types/client/index.d.ts.map +1 -1
  25. package/lib/types/client/index.js +117 -79
  26. package/lib/types/client/index.js.map +1 -1
  27. package/lib/types/client/locales.d.ts +63 -58
  28. package/lib/types/client/locales.d.ts.map +1 -1
  29. package/lib/types/client/locales.js +211 -105
  30. package/lib/types/client/locales.js.map +1 -1
  31. package/lib/types/client/session-guard-bridge.d.ts +18 -0
  32. package/lib/types/client/session-guard-bridge.d.ts.map +1 -0
  33. package/lib/types/client/session-guard-bridge.js +42 -0
  34. package/lib/types/client/session-guard-bridge.js.map +1 -0
  35. package/lib/types/client/steer-queue-dock.d.ts +9 -1
  36. package/lib/types/client/steer-queue-dock.d.ts.map +1 -1
  37. package/lib/types/client/steer-queue-dock.js +6 -5
  38. package/lib/types/client/steer-queue-dock.js.map +1 -1
  39. package/package.json +15 -7
@@ -1,56 +1,87 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- /**
3
- * Session freeze/resume control, mounted in the composer's right tool row
4
- * (`conversation.input.right`) so it is reachable before anything queues.
5
- *
6
- * Peak-hour pause semantics: freeze does NOT interrupt the running turn —it
7
- * finishes naturally. The queued messages are detached (removed, preserved in
8
- * the shared store), so the driver finds no pending work and stops after the
9
- * current turn. Resume re-submits the preserved texts, waking the driver and
10
- * continuing the queue.
11
- */
12
- import { useSyncExternalStore } from 'react';
13
- import { freezeStore } from "./freeze-store.js";
14
- import css from './freeze-button.module.css';
15
- /**
16
- * Freeze/resume toggle for the peak-hour scenario.
17
- * @param props - slot props; the session snapshot drives the detach list.
18
- */
19
- export function FreezeButton({ session, updateQueue, cancel, send, notify, t }) {
20
- const { frozen } = useSyncExternalStore(freezeStore.subscribe, freezeStore.getSnapshot);
21
- const freeze = async () => {
22
- const queued = session.queue.filter(row => row.placement === 'queued');
23
- // Preserve plain-text copies; non-text rows cannot be re-sent and are
24
- // released by the freeze (documented limitation).
25
- const pending = queued.flatMap(row => row.text === null ? [] : [{ text: row.text, tier: 'queue' }]);
26
- // Detach every queued row: the running turn finishes naturally, then the
27
- // driver finds no pending work and stops.
28
- await Promise.all(queued.map(row => updateQueue(row.id, { kind: 'remove' }).catch(() => undefined)));
29
- freezeStore.set({ frozen: true, pending });
30
- };
31
- const resume = async () => {
32
- const pending = freezeStore.getSnapshot().pending;
33
- freezeStore.set({ frozen: false, pending: [] });
34
- try {
35
- // Re-submit the preserved queue in FIFO order honoring each entry's
36
- // planned insertion tier: a force (red) entry interrupts the current
37
- // run first so it is consumed immediately; safe_point/later entries
38
- // flow through the wake-and-continue chain.
39
- for (const entry of pending) {
40
- if (entry.tier === 'force')
41
- await cancel();
42
- await send(entry.text);
43
- }
44
- }
45
- catch {
46
- notify('error', t('steer.resumeFailed'));
47
- }
48
- };
49
- return (_jsx("button", { type: "button", className: css.freeze, "aria-label": frozen ? t('steer.resume') : t('steer.freeze'), "aria-pressed": frozen || undefined, title: frozen ? t('steer.frozen') : undefined, onClick: () => {
50
- if (frozen)
51
- void resume();
52
- else
53
- void freeze();
54
- }, children: _jsx("span", { className: css.label, children: frozen ? t('steer.resume') : t('steer.freeze') }) }));
55
- }
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Session freeze/resume control, mounted in the composer's right tool row
4
+ * (`conversation.input.right`) so it is reachable before anything queues.
5
+ *
6
+ * Peak-hour pause semantics: freeze does NOT interrupt the running turn —it
7
+ * finishes naturally. The queued messages are detached (removed, preserved in
8
+ * the shared store), so the driver finds no pending work and stops after the
9
+ * current turn. Resume re-submits the preserved texts, waking the driver and
10
+ * continuing the queue.
11
+ *
12
+ * dsh-session-guard 协作(D8 fail-open):
13
+ * - 冻结 = 前端摘队列(本插件)+ composer block(阻止新输入漏进对话) + 尽力调服务端
14
+ * sessionGuard.stopNextTurn(停掉 session 下一回合;session-guard 未装时静默跳过)。
15
+ * - 解冻 = 清 composer block + **先** await sessionGuard.resume(让被打断回合的自然
16
+ * 下一步先发生),**再**重投队列(later 级条目因此排在自然 next turn 之后,不再插队)。
17
+ * - 本插件只做冻结增强,不承担重试/暂停决策(归后端,D9)。
18
+ */
19
+ import { useSyncExternalStore } from 'react';
20
+ import { freezeStore } from "./freeze-store.js";
21
+ import { sessionGuardResume, sessionGuardStopNextTurn } from "./session-guard-bridge.js";
22
+ import css from './freeze-button.module.css';
23
+ /**
24
+ * Freeze/resume toggle for the peak-hour scenario.
25
+ * @param props - slot props; the session snapshot drives the detach list.
26
+ */
27
+ export function FreezeButton({ useSession, updateQueue, cancel, send, sendSteer, sessionId, setComposerBlock, notify, t }) {
28
+ // The freeze store is keyed by session: read the owning session's snapshot.
29
+ const sid = sessionId ?? '';
30
+ const { frozen } = useSyncExternalStore(freezeStore.subscribe, () => freezeStore.getSnapshot(sid));
31
+ const queue = useSession(s => s.queue);
32
+ const freeze = async () => {
33
+ // Detach every pending input row — queued (next-turn) and already-steered
34
+ // (next-step) alike — so nothing stays in the live queue while frozen.
35
+ // Steered rows keep their next intent as a safe_point plan for resume.
36
+ const rows = queue.filter(row => row.placement === 'queued' || row.placement === 'steering');
37
+ // Preserve plain-text copies; non-text rows cannot be re-sent and are
38
+ // released by the freeze (documented limitation).
39
+ const pending = rows.flatMap(row => row.text === null ? [] : [{ text: row.text, tier: row.placement === 'steering' ? 'safe_point' : 'queue' }]);
40
+ // Detach every pending row: the running turn finishes naturally, then the
41
+ // driver finds no pending work and stops.
42
+ await Promise.all(rows.map(row => updateQueue(row.id, { kind: 'remove' }).catch(() => undefined)));
43
+ freezeStore.set(sid, { frozen: true, pending });
44
+ // Raise the composer block: while frozen the composer is inert, so plain
45
+ // Enter can never leak a new message into the conversation (busyEnter
46
+ // only gates busy sessions; an idle/paused session would send directly).
47
+ setComposerBlock?.(t('steer.frozenInput'));
48
+ // 服务端:停掉 session 下一回合(fail-open,session-guard 未装则静默)。
49
+ if (sessionId !== undefined)
50
+ void sessionGuardStopNextTurn(sessionId);
51
+ };
52
+ const resume = async () => {
53
+ const pending = freezeStore.getSnapshot(sid).pending;
54
+ freezeStore.set(sid, { frozen: false, pending: [] });
55
+ setComposerBlock?.(undefined);
56
+ try {
57
+ // 先恢复服务端会话:被打断回合的自然下一步(deferredTools 续跑)先发生。
58
+ // 之后再重投队列 —— later 级条目经 send 进入 next-turn,排在自然 next turn
59
+ // 之后;safe_point/force 仍按各自语义插队。顺序倒置会让 later 抢在自然
60
+ // next turn 前被消费(idle 态 send 立即唤醒新回合)。
61
+ if (sessionId !== undefined)
62
+ await sessionGuardResume(sessionId);
63
+ // Re-submit the preserved queue in FIFO order honoring each entry's
64
+ // planned insertion tier: force (red) interrupts the current run first,
65
+ // safe_point (yellow) steers into the next step, queue (green) flows
66
+ // through the wake-and-continue chain.
67
+ for (const entry of pending) {
68
+ if (entry.tier === 'force')
69
+ await cancel();
70
+ if (entry.tier === 'safe_point' && sendSteer !== undefined)
71
+ await sendSteer(entry.text);
72
+ else
73
+ await send(entry.text);
74
+ }
75
+ }
76
+ catch {
77
+ notify('error', t('steer.resumeFailed'));
78
+ }
79
+ };
80
+ return (_jsx("button", { type: "button", className: css.freeze, "aria-label": frozen ? t('steer.resume') : t('steer.freeze'), "aria-pressed": frozen || undefined, title: frozen ? t('steer.frozen') : undefined, onClick: () => {
81
+ if (frozen)
82
+ void resume();
83
+ else
84
+ void freeze();
85
+ }, children: _jsx("span", { className: css.label, children: frozen ? t('steer.resume') : t('steer.freeze') }) }));
86
+ }
56
87
  //# sourceMappingURL=freeze-button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"freeze-button.js","sourceRoot":"","sources":["../../../src/client/freeze-button.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAG5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,GAAG,MAAM,4BAA4B,CAAA;AAK5C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAqB;IAC/F,MAAM,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAAC,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,CAAA;IAEvF,MAAM,MAAM,GAAG,KAAK,IAAmB,EAAE;QACvC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAA;QACtE,sEAAsE;QACtE,kDAAkD;QAClD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,OAAgB,EAAE,CAAC,CAAC,CAAA;QAC5G,yEAAyE;QACzE,0CAA0C;QAC1C,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CACjC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAC/D,CAAC,CAAA;QACF,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC5C,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,KAAK,IAAmB,EAAE;QACvC,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC,OAAO,CAAA;QACjD,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAA;QAC/C,IAAI,CAAC;YACH,oEAAoE;YACpE,qEAAqE;YACrE,oEAAoE;YACpE,4CAA4C;YAC5C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;oBAAE,MAAM,MAAM,EAAE,CAAA;gBAC1C,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACxB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAC1C,CAAC;IACH,CAAC,CAAA;IAED,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,GAAG,CAAC,MAAM,gBACT,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,kBAC5C,MAAM,IAAI,SAAS,EACjC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,EAC7C,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,MAAM;gBAAE,KAAK,MAAM,EAAE,CAAA;;gBACpB,KAAK,MAAM,EAAE,CAAA;QACpB,CAAC,YAED,eAAM,SAAS,EAAE,GAAG,CAAC,KAAK,YAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAAQ,GAC5E,CACV,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"freeze-button.js","sourceRoot":"","sources":["../../../src/client/freeze-button.tsx"],"names":[],"mappings":"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"}
@@ -1,12 +1,17 @@
1
1
  /**
2
- * Session-freeze store shared by the composer freeze button (the control)
3
- * and the steering dock (the banner/disabled states).
2
+ * Session-scoped freeze store shared by the composer freeze button (the
3
+ * control) and the steering dock (the banner/disabled states).
4
4
  *
5
5
  * The queue is fully decoupled from freezing: freezing only stops the agent
6
6
  * from consuming the queue (the detached entries are preserved here so the
7
7
  * driver finds no pending work and stops). While frozen the entries stay
8
8
  * fully editable — text, order and the planned insertion tier (now/next/
9
9
  * later) can all change; resume re-submits the queue honoring those tiers.
10
+ *
11
+ * State is keyed by session id so freezing one session never leaks into
12
+ * another: each session holds its own `frozen` flag and detached queue, and
13
+ * mutating one session's queue only re-renders that session's consumers
14
+ * (`useSyncExternalStore` bails on unchanged references for the others).
10
15
  */
11
16
  /** Insertion tier planned for one detached queued message. */
12
17
  export type FrozenTier = 'queue' | 'safe_point' | 'force';
@@ -22,20 +27,22 @@ export interface FreezeState {
22
27
  }
23
28
  /** Minimal snapshot store (no runtime dependency, stable identity per mount). */
24
29
  export declare const freezeStore: {
25
- getSnapshot(): FreezeState;
30
+ /** Snapshot for one session; reference-stable until that session changes. */
31
+ getSnapshot(sessionId: string): FreezeState;
26
32
  subscribe(listener: () => void): () => void;
27
- set(next: FreezeState): void;
33
+ /** Replace one session's state; unset sessions fall back to EMPTY. */
34
+ set(sessionId: string, next: FreezeState): void;
28
35
  };
29
- /** Reset for tests. */
36
+ /** Reset all sessions (for tests). */
30
37
  export declare function resetFreezeStore(): void;
31
38
  /** Append one queued message while frozen (new input lands in the detached queue). */
32
- export declare function pushPending(text: string, tier?: FrozenTier): void;
39
+ export declare function pushPending(sessionId: string, text: string, tier?: FrozenTier): void;
33
40
  /** Edit one detached queued message's text in place. */
34
- export declare function updatePendingAt(index: number, text: string): void;
41
+ export declare function updatePendingAt(sessionId: string, index: number, text: string): void;
35
42
  /** Change one detached queued message's planned insertion tier. */
36
- export declare function setTierAt(index: number, tier: FrozenTier): void;
43
+ export declare function setTierAt(sessionId: string, index: number, tier: FrozenTier): void;
37
44
  /** Remove one detached queued message. */
38
- export declare function removePendingAt(index: number): void;
45
+ export declare function removePendingAt(sessionId: string, index: number): void;
39
46
  /** Move one detached queued message to a new position (reorder while frozen). */
40
- export declare function movePending(from: number, to: number): void;
47
+ export declare function movePending(sessionId: string, from: number, to: number): void;
41
48
  //# sourceMappingURL=freeze-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"freeze-store.d.ts","sourceRoot":"","sources":["../../../src/client/freeze-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,8DAA8D;AAC9D,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,CAAA;AAEzD,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,wEAAwE;IACxE,OAAO,EAAE,SAAS,WAAW,EAAE,CAAA;CAChC;AAKD,iFAAiF;AACjF,eAAO,MAAM,WAAW;mBACP,WAAW;wBAGN,MAAM,IAAI,GAAG,MAAM,IAAI;cAIjC,WAAW,GAAG,IAAI;CAI7B,CAAA;AAED,uBAAuB;AACvB,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAoB,GAAG,IAAI,CAG1E;AAED,wDAAwD;AACxD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQjE;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAQ/D;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAQ1D"}
1
+ {"version":3,"file":"freeze-store.d.ts","sourceRoot":"","sources":["../../../src/client/freeze-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,8DAA8D;AAC9D,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,CAAA;AAEzD,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,wEAAwE;IACxE,OAAO,EAAE,SAAS,WAAW,EAAE,CAAA;CAChC;AAUD,iFAAiF;AACjF,eAAO,MAAM,WAAW;IACtB,6EAA6E;2BACtD,MAAM,GAAG,WAAW;wBAGvB,MAAM,IAAI,GAAG,MAAM,IAAI;IAI3C,sEAAsE;mBACvD,MAAM,QAAQ,WAAW,GAAG,IAAI;CAQhD,CAAA;AAED,sCAAsC;AACtC,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAoB,GAAG,IAAI,CAG7F;AAED,wDAAwD;AACxD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQpF;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAQlF;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAItE;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAS7E"}
@@ -1,83 +1,99 @@
1
1
  /**
2
- * Session-freeze store shared by the composer freeze button (the control)
3
- * and the steering dock (the banner/disabled states).
2
+ * Session-scoped freeze store shared by the composer freeze button (the
3
+ * control) and the steering dock (the banner/disabled states).
4
4
  *
5
5
  * The queue is fully decoupled from freezing: freezing only stops the agent
6
6
  * from consuming the queue (the detached entries are preserved here so the
7
7
  * driver finds no pending work and stops). While frozen the entries stay
8
8
  * fully editable — text, order and the planned insertion tier (now/next/
9
9
  * later) can all change; resume re-submits the queue honoring those tiers.
10
+ *
11
+ * State is keyed by session id so freezing one session never leaks into
12
+ * another: each session holds its own `frozen` flag and detached queue, and
13
+ * mutating one session's queue only re-renders that session's consumers
14
+ * (`useSyncExternalStore` bails on unchanged references for the others).
10
15
  */
16
+ /** Session id → per-session freeze state. */
17
+ const states = new Map();
11
18
  const listeners = new Set();
12
- let state = { frozen: false, pending: [] };
19
+ /** Stable empty snapshot: `useSyncExternalStore` needs a reference-stable
20
+ * value for unset sessions so unchanged consumers never re-render. */
21
+ const EMPTY = { frozen: false, pending: [] };
13
22
  /** Minimal snapshot store (no runtime dependency, stable identity per mount). */
14
23
  export const freezeStore = {
15
- getSnapshot() {
16
- return state;
24
+ /** Snapshot for one session; reference-stable until that session changes. */
25
+ getSnapshot(sessionId) {
26
+ return states.get(sessionId) ?? EMPTY;
17
27
  },
18
28
  subscribe(listener) {
19
29
  listeners.add(listener);
20
30
  return () => { listeners.delete(listener); };
21
31
  },
22
- set(next) {
23
- state = next;
24
- for (const listener of listeners)
25
- listener();
32
+ /** Replace one session's state; unset sessions fall back to EMPTY. */
33
+ set(sessionId, next) {
34
+ if (next.frozen === false && next.pending.length === 0) {
35
+ states.delete(sessionId);
36
+ }
37
+ else {
38
+ states.set(sessionId, next);
39
+ }
40
+ emit();
26
41
  },
27
42
  };
28
- /** Reset for tests. */
43
+ /** Reset all sessions (for tests). */
29
44
  export function resetFreezeStore() {
30
- state = { frozen: false, pending: [] };
31
- for (const listener of listeners)
32
- listener();
45
+ states.clear();
46
+ emit();
33
47
  }
34
48
  /** Append one queued message while frozen (new input lands in the detached queue). */
35
- export function pushPending(text, tier = 'queue') {
36
- state = { ...state, pending: [...state.pending, { text, tier }] };
37
- emit();
49
+ export function pushPending(sessionId, text, tier = 'queue') {
50
+ const cur = states.get(sessionId) ?? EMPTY;
51
+ freezeStore.set(sessionId, { ...cur, pending: [...cur.pending, { text, tier }] });
38
52
  }
39
53
  /** Edit one detached queued message's text in place. */
40
- export function updatePendingAt(index, text) {
41
- const pending = [...state.pending];
42
- if (index < 0 || index >= pending.length)
54
+ export function updatePendingAt(sessionId, index, text) {
55
+ const pending = states.get(sessionId)?.pending;
56
+ if (pending === undefined)
43
57
  return;
44
58
  const entry = pending[index];
45
59
  if (entry === undefined)
46
60
  return;
47
- pending[index] = { ...entry, text };
48
- state = { ...state, pending };
49
- emit();
61
+ const next = [...pending];
62
+ next[index] = { ...entry, text };
63
+ freezeStore.set(sessionId, { frozen: true, pending: next });
50
64
  }
51
65
  /** Change one detached queued message's planned insertion tier. */
52
- export function setTierAt(index, tier) {
53
- const pending = [...state.pending];
54
- if (index < 0 || index >= pending.length)
66
+ export function setTierAt(sessionId, index, tier) {
67
+ const pending = states.get(sessionId)?.pending;
68
+ if (pending === undefined)
55
69
  return;
56
70
  const entry = pending[index];
57
71
  if (entry === undefined)
58
72
  return;
59
- pending[index] = { ...entry, tier };
60
- state = { ...state, pending };
61
- emit();
73
+ const next = [...pending];
74
+ next[index] = { ...entry, tier };
75
+ freezeStore.set(sessionId, { frozen: true, pending: next });
62
76
  }
63
77
  /** Remove one detached queued message. */
64
- export function removePendingAt(index) {
65
- if (index < 0 || index >= state.pending.length)
78
+ export function removePendingAt(sessionId, index) {
79
+ const pending = states.get(sessionId)?.pending;
80
+ if (pending === undefined)
66
81
  return;
67
- state = { ...state, pending: state.pending.filter((_, i) => i !== index) };
68
- emit();
82
+ freezeStore.set(sessionId, { frozen: true, pending: pending.filter((_, i) => i !== index) });
69
83
  }
70
84
  /** Move one detached queued message to a new position (reorder while frozen). */
71
- export function movePending(from, to) {
85
+ export function movePending(sessionId, from, to) {
72
86
  if (from === to)
73
87
  return;
74
- const pending = [...state.pending];
75
- const [moved] = pending.splice(from, 1);
88
+ const pending = states.get(sessionId)?.pending;
89
+ if (pending === undefined)
90
+ return;
91
+ const next = [...pending];
92
+ const [moved] = next.splice(from, 1);
76
93
  if (moved === undefined)
77
94
  return;
78
- pending.splice(to, 0, moved);
79
- state = { ...state, pending };
80
- emit();
95
+ next.splice(to, 0, moved);
96
+ freezeStore.set(sessionId, { frozen: true, pending: next });
81
97
  }
82
98
  function emit() {
83
99
  for (const listener of listeners)
@@ -1 +1 @@
1
- {"version":3,"file":"freeze-store.js","sourceRoot":"","sources":["../../../src/client/freeze-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"freeze-store.js","sourceRoot":"","sources":["../../../src/client/freeze-store.ts"],"names":[],"mappings":"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"}
@@ -1,25 +1,48 @@
1
- /**
2
- * dsh-input-traffic —browser half.
3
- *
4
- * The whole takeover lives here:
5
- * 1. registers the `steer` dictionaries;
6
- * 2. pins `ui-conversation.busyEnter` to `queue` (plain Enter = green later)
7
- * so the hidden official row cannot leak a stale queue/steer preference;
8
- * 3. shadows the official queue dock (`conversation.input.dock` cell id
9
- * `queue`, priority -1) with the three-tier planning strip;
10
- * 4. shadows the official busy-Enter settings row (`settings.general.item`
11
- * cell id `composer-enter`, priority -1) with a null render.
12
- *
13
- * All @deepseek-ai/* imports are type-only: collaboration happens through
14
- * cordis services and slot registration only (client bundle purity).
15
- */
16
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
17
- /** Services required by the browser half. */
18
- export declare const inject: string[];
19
- /**
20
- * Client plugin body: dictionaries, busy-Enter pinning, and the two slot
21
- * shadowings.
22
- * @param ctx - client root context.
23
- */
24
- export declare function apply(ctx: ClientContext): void;
1
+ /**
2
+ * dsh-input-traffic —browser half.
3
+ *
4
+ * The whole takeover lives here:
5
+ * 1. registers the `steer` dictionaries;
6
+ * 2. pins `ui-conversation.busyEnter` to `queue` (plain Enter = green later)
7
+ * so the hidden official row cannot leak a stale queue/steer preference;
8
+ * 3. shadows the official queue dock (`conversation.input.dock` cell id
9
+ * `queue`, priority -1) with the three-tier planning strip;
10
+ * 4. shadows the official busy-Enter settings row (`settings.general.item`
11
+ * cell id `composer-enter`, priority -1) with a null render.
12
+ *
13
+ * ORDERING (why the dock registers at QUEUE_DOCK_ORDER instead of the
14
+ * official dock's 20): a list slot's DISPLAY position is decided by `order`
15
+ * alone — `ui-renderer/src/client/scoped-slots.tsx` maps the shadowing
16
+ * winners to rows and then sorts them by `order` (both 0.1.1 and 0.1.2) —
17
+ * while `priority` only decides which entry wins a shared cell id. Keeping
18
+ * the official 20 therefore left the strip above any later contributor
19
+ * (dsh-perm-gate's notice registers order 30), which pushed that notice
20
+ * between the queue strip and the composer card. A deliberately high order
21
+ * keeps the strip adjacent to the card; priority stays -1 so the cell
22
+ * takeover still holds.
23
+ *
24
+ * All @deepseek-ai/* imports are type-only: collaboration happens through
25
+ * cordis services and slot registration only (client bundle purity).
26
+ */
27
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
28
+ /**
29
+ * Display order of the queue strip inside `conversation.input.dock`.
30
+ *
31
+ * List rows render sorted by `order` ascending, so a value above every other
32
+ * contributor keeps the strip as the bottom-most entry of the band — directly
33
+ * on top of the composer card. Known contributors in both 0.1.1-rc.2 and
34
+ * 0.1.2-rc.1: `todo` 0, `goal` 10, official `queue` 20, `dsh-perm-gate.notice`
35
+ * 30. DSH has no "last" slot semantics, so this is a convention, not a
36
+ * structural guarantee: a third party registering a larger value could still
37
+ * land below us.
38
+ */
39
+ export declare const QUEUE_DOCK_ORDER = 1000;
40
+ /** Services required by the browser half. */
41
+ export declare const inject: string[];
42
+ /**
43
+ * Client plugin body: dictionaries, busy-Enter pinning, and the two slot
44
+ * shadowings.
45
+ * @param ctx - client root context.
46
+ */
47
+ export declare function apply(ctx: ClientContext): void;
25
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,wCAAwC,CAAA;AAgBtF,6CAA6C;AAC7C,eAAO,MAAM,MAAM,UAAmE,CAAA;AAEtF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA+D9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,wCAAwC,CAAA;AAgBtF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAA;AAkBpC,6CAA6C;AAC7C,eAAO,MAAM,MAAM,UAAmE,CAAA;AAEtF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyE9C"}