dsh-mega-chat-nav 0.1.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 (192) hide show
  1. package/LICENSE +201 -0
  2. package/README.en.md +149 -0
  3. package/README.md +149 -0
  4. package/cordis.patch.yml +4 -0
  5. package/lib/client/NavOverlay.js +35 -0
  6. package/lib/client/NavRail.js +12 -0
  7. package/lib/client/QuestionNavSettingsTab.js +26 -0
  8. package/lib/client/QuestionNavStrip.js +555 -0
  9. package/lib/client/components/ConfigPanel.js +14 -0
  10. package/lib/client/components/DotRail.js +62 -0
  11. package/lib/client/components/NavOverlay.js +121 -0
  12. package/lib/client/components/NavRail.js +97 -0
  13. package/lib/client/components/RailDispatch.js +22 -0
  14. package/lib/client/components/RailHost.js +79 -0
  15. package/lib/client/components/SearchBox.js +66 -0
  16. package/lib/client/components/SettingsPage.js +46 -0
  17. package/lib/client/components/StandaloneSettings.js +16 -0
  18. package/lib/client/components/codex/CodexRail.js +139 -0
  19. package/lib/client/components/deepseek/DeepseekRail.js +264 -0
  20. package/lib/client/components/minimal/MinimalRail.js +135 -0
  21. package/lib/client/components/minimal/cards.js +32 -0
  22. package/lib/client/components/minimal/dot.js +11 -0
  23. package/lib/client/components/minimal/hint.js +30 -0
  24. package/lib/client/components/minimal/paging.js +5 -0
  25. package/lib/client/components/minimal/quick-settings.js +28 -0
  26. package/lib/client/components/minimal/search.js +67 -0
  27. package/lib/client/components/minimal/useRail.js +716 -0
  28. package/lib/client/components/rail/cards.js +32 -0
  29. package/lib/client/components/rail/hint.js +30 -0
  30. package/lib/client/components/rail/paging.js +5 -0
  31. package/lib/client/components/rail/quick-settings.js +28 -0
  32. package/lib/client/components/rail/search.js +76 -0
  33. package/lib/client/components/rail/useRail.js +845 -0
  34. package/lib/client/components/settings/SettingsPage.js +46 -0
  35. package/lib/client/components/settings/SettingsTab.js +17 -0
  36. package/lib/client/components/settings/StandaloneSettings.js +16 -0
  37. package/lib/client/components/shared/Cascade.js +26 -0
  38. package/lib/client/components/shared/ConfigPanel.js +27 -0
  39. package/lib/client/components/shared/Dot.js +8 -0
  40. package/lib/client/components/shared/Hint.js +5 -0
  41. package/lib/client/components/shared/PagingButton.js +5 -0
  42. package/lib/client/components/shared/RailShell.js +78 -0
  43. package/lib/client/components/shared/SearchBox.js +63 -0
  44. package/lib/client/components/shared/hooks.js +427 -0
  45. package/lib/client/components/shared/types.js +1 -0
  46. package/lib/client/config.js +1 -0
  47. package/lib/client/engines/jump.js +34 -0
  48. package/lib/client/engines/useAtBottom.js +25 -0
  49. package/lib/client/engines/useJump.js +40 -0
  50. package/lib/client/engines/useScrollSpy.js +88 -0
  51. package/lib/client/hooks.js +11 -0
  52. package/lib/client/index.js +312 -0
  53. package/lib/client/jump.js +255 -0
  54. package/lib/client/locales.js +142 -0
  55. package/lib/client/pure.js +61 -0
  56. package/lib/client/settings.js +369 -0
  57. package/lib/client/virtual/VirtualList.js +21 -0
  58. package/lib/client.js +3213 -0
  59. package/lib/compat.js +145 -0
  60. package/lib/config.js +37 -0
  61. package/lib/core/active-dot.js +17 -0
  62. package/lib/core/align.js +9 -0
  63. package/lib/core/config.js +37 -0
  64. package/lib/core/focus.js +38 -0
  65. package/lib/core/jump.js +98 -0
  66. package/lib/core/logic/active-dot.js +16 -0
  67. package/lib/core/logic/focus.js +34 -0
  68. package/lib/core/logic/jump.js +188 -0
  69. package/lib/core/logic/nodes.js +59 -0
  70. package/lib/core/model/nav-item.js +1 -0
  71. package/lib/core/model/turns.js +73 -0
  72. package/lib/core/nav-item.js +1 -0
  73. package/lib/core/nodes.js +57 -0
  74. package/lib/core/page-size.js +7 -0
  75. package/lib/core/question-entry.js +1 -0
  76. package/lib/core/time.js +23 -0
  77. package/lib/core/turn-dots.js +85 -0
  78. package/lib/core/utils/measure.js +24 -0
  79. package/lib/core/utils/time.js +26 -0
  80. package/lib/index.js +64 -0
  81. package/lib/nav-item.js +1 -0
  82. package/lib/nodes.js +59 -0
  83. package/lib/projection.js +126 -0
  84. package/lib/schema.js +26 -0
  85. package/lib/search.js +285 -0
  86. package/lib/settings.js +89 -0
  87. package/lib/types/client/NavOverlay.d.ts +18 -0
  88. package/lib/types/client/NavRail.d.ts +7 -0
  89. package/lib/types/client/QuestionNavSettingsTab.d.ts +16 -0
  90. package/lib/types/client/QuestionNavStrip.d.ts +48 -0
  91. package/lib/types/client/components/ConfigPanel.d.ts +14 -0
  92. package/lib/types/client/components/DotRail.d.ts +15 -0
  93. package/lib/types/client/components/NavOverlay.d.ts +30 -0
  94. package/lib/types/client/components/NavRail.d.ts +16 -0
  95. package/lib/types/client/components/RailDispatch.d.ts +8 -0
  96. package/lib/types/client/components/RailHost.d.ts +27 -0
  97. package/lib/types/client/components/SearchBox.d.ts +9 -0
  98. package/lib/types/client/components/SettingsPage.d.ts +9 -0
  99. package/lib/types/client/components/StandaloneSettings.d.ts +13 -0
  100. package/lib/types/client/components/codex/CodexRail.d.ts +3 -0
  101. package/lib/types/client/components/deepseek/DeepseekRail.d.ts +3 -0
  102. package/lib/types/client/components/minimal/MinimalRail.d.ts +8 -0
  103. package/lib/types/client/components/minimal/cards.d.ts +19 -0
  104. package/lib/types/client/components/minimal/dot.d.ts +14 -0
  105. package/lib/types/client/components/minimal/hint.d.ts +11 -0
  106. package/lib/types/client/components/minimal/paging.d.ts +10 -0
  107. package/lib/types/client/components/minimal/quick-settings.d.ts +8 -0
  108. package/lib/types/client/components/minimal/search.d.ts +27 -0
  109. package/lib/types/client/components/minimal/useRail.d.ts +90 -0
  110. package/lib/types/client/components/rail/cards.d.ts +19 -0
  111. package/lib/types/client/components/rail/hint.d.ts +11 -0
  112. package/lib/types/client/components/rail/paging.d.ts +10 -0
  113. package/lib/types/client/components/rail/quick-settings.d.ts +8 -0
  114. package/lib/types/client/components/rail/search.d.ts +34 -0
  115. package/lib/types/client/components/rail/useRail.d.ts +132 -0
  116. package/lib/types/client/components/settings/SettingsPage.d.ts +9 -0
  117. package/lib/types/client/components/settings/SettingsTab.d.ts +6 -0
  118. package/lib/types/client/components/settings/StandaloneSettings.d.ts +13 -0
  119. package/lib/types/client/components/shared/Cascade.d.ts +14 -0
  120. package/lib/types/client/components/shared/ConfigPanel.d.ts +8 -0
  121. package/lib/types/client/components/shared/Dot.d.ts +17 -0
  122. package/lib/types/client/components/shared/Hint.d.ts +6 -0
  123. package/lib/types/client/components/shared/PagingButton.d.ts +10 -0
  124. package/lib/types/client/components/shared/RailShell.d.ts +43 -0
  125. package/lib/types/client/components/shared/SearchBox.d.ts +18 -0
  126. package/lib/types/client/components/shared/hooks.d.ts +64 -0
  127. package/lib/types/client/components/shared/types.d.ts +101 -0
  128. package/lib/types/client/config.d.ts +9 -0
  129. package/lib/types/client/engines/jump.d.ts +17 -0
  130. package/lib/types/client/engines/useAtBottom.d.ts +1 -0
  131. package/lib/types/client/engines/useJump.d.ts +16 -0
  132. package/lib/types/client/engines/useScrollSpy.d.ts +12 -0
  133. package/lib/types/client/hooks.d.ts +7 -0
  134. package/lib/types/client/index.d.ts +31 -0
  135. package/lib/types/client/jump.d.ts +47 -0
  136. package/lib/types/client/locales.d.ts +142 -0
  137. package/lib/types/client/pure.d.ts +21 -0
  138. package/lib/types/client/settings.d.ts +173 -0
  139. package/lib/types/client/virtual/VirtualList.d.ts +15 -0
  140. package/lib/types/compat.d.ts +44 -0
  141. package/lib/types/config.d.ts +44 -0
  142. package/lib/types/core/active-dot.d.ts +15 -0
  143. package/lib/types/core/align.d.ts +10 -0
  144. package/lib/types/core/config.d.ts +44 -0
  145. package/lib/types/core/focus.d.ts +24 -0
  146. package/lib/types/core/jump.d.ts +39 -0
  147. package/lib/types/core/logic/active-dot.d.ts +15 -0
  148. package/lib/types/core/logic/focus.d.ts +22 -0
  149. package/lib/types/core/logic/jump.d.ts +39 -0
  150. package/lib/types/core/logic/nodes.d.ts +48 -0
  151. package/lib/types/core/model/nav-item.d.ts +12 -0
  152. package/lib/types/core/model/turns.d.ts +30 -0
  153. package/lib/types/core/nav-item.d.ts +12 -0
  154. package/lib/types/core/nodes.d.ts +43 -0
  155. package/lib/types/core/page-size.d.ts +8 -0
  156. package/lib/types/core/question-entry.d.ts +12 -0
  157. package/lib/types/core/time.d.ts +4 -0
  158. package/lib/types/core/turn-dots.d.ts +29 -0
  159. package/lib/types/core/utils/measure.d.ts +12 -0
  160. package/lib/types/core/utils/time.d.ts +4 -0
  161. package/lib/types/index.d.ts +4 -0
  162. package/lib/types/nav-item.d.ts +12 -0
  163. package/lib/types/nodes.d.ts +48 -0
  164. package/lib/types/projection.d.ts +71 -0
  165. package/lib/types/schema.d.ts +37 -0
  166. package/lib/types/search.d.ts +42 -0
  167. package/lib/types/settings.d.ts +99 -0
  168. package/package.json +71 -0
  169. package/src/client/components/RailDispatch.tsx +27 -0
  170. package/src/client/components/codex/CodexRail.tsx +348 -0
  171. package/src/client/components/deepseek/DeepseekRail.tsx +522 -0
  172. package/src/client/components/minimal/MinimalRail.tsx +324 -0
  173. package/src/client/components/minimal/dot.tsx +32 -0
  174. package/src/client/components/rail/cards.tsx +102 -0
  175. package/src/client/components/rail/hint.tsx +50 -0
  176. package/src/client/components/rail/paging.tsx +26 -0
  177. package/src/client/components/rail/quick-settings.tsx +130 -0
  178. package/src/client/components/rail/search.tsx +147 -0
  179. package/src/client/components/rail/useRail.ts +906 -0
  180. package/src/client/components/settings/SettingsPage.tsx +198 -0
  181. package/src/client/components/settings/StandaloneSettings.tsx +28 -0
  182. package/src/client/components/shared/types.ts +99 -0
  183. package/src/client/index.ts +388 -0
  184. package/src/client/jump.ts +293 -0
  185. package/src/client/locales.ts +143 -0
  186. package/src/client/settings.ts +482 -0
  187. package/src/client/styles.css +1580 -0
  188. package/src/compat.ts +161 -0
  189. package/src/index.ts +66 -0
  190. package/src/projection.ts +174 -0
  191. package/src/search.ts +291 -0
  192. package/src/settings.ts +169 -0
@@ -0,0 +1,101 @@
1
+ import type { BandHeight, CardCount, CardItem, MarkTone, NavStyle, RailAlign, ScrollMode, SearchScope, ShowMode } from '../../settings.ts';
2
+ /** 会话投影 face 最小面 */
3
+ export interface ObservableFace {
4
+ getSnapshot: () => unknown;
5
+ subscribe: (listener: () => void) => () => void;
6
+ }
7
+ /** 回合标记:某回合的提问组(或一条未入投影的活提问) */
8
+ export interface RailMarker {
9
+ /** 归属回合;活提问(投影未收)为 null */
10
+ readonly turn: number | null;
11
+ /** 跳转锚点:组内首问的聊天 key */
12
+ readonly key: string;
13
+ /** 首问锚点序号 */
14
+ readonly seq: number;
15
+ /** 首问时间 */
16
+ readonly time: number;
17
+ /** 组内全部提问文本(按序) */
18
+ readonly texts: readonly string[];
19
+ /** 组内全部聊天 key(活合并去重用) */
20
+ readonly members: readonly string[];
21
+ /** 该轮性能指标(投影附带;缺数据时省略) */
22
+ readonly metrics?: {
23
+ durationMs: number;
24
+ firstTokenMs: number;
25
+ tokensPerSec: number;
26
+ };
27
+ }
28
+ /** 注册注入面(client/index.ts 装配;各风格经此拿数据与动作) */
29
+ export interface NavInjected {
30
+ readQuestions: (sessionId: string) => {
31
+ key: string;
32
+ anchorSeq: number;
33
+ seq: number;
34
+ time: number;
35
+ text: string;
36
+ }[];
37
+ subscribeList: (cb: () => void) => () => void;
38
+ subscribeContent: (sessionId: string, cb: () => void) => () => void;
39
+ questionProjection: (sessionId: string) => ObservableFace | undefined;
40
+ /** seq:目标轮序号(方向判定);currentSeq:当前阅读位置序号(可选,下方判定优先用) */
41
+ jump: (sessionId: string, key: string, seq?: number, currentSeq?: number) => void;
42
+ style: () => NavStyle;
43
+ setStyle: (style: NavStyle) => void;
44
+ align: () => RailAlign;
45
+ subscribeSettings: (cb: () => void) => () => void;
46
+ setAlign: (align: RailAlign) => void;
47
+ bandHeight: () => BandHeight;
48
+ setBandHeight: (band: BandHeight) => void;
49
+ scrollBehavior: () => ScrollMode;
50
+ setScrollMode: (mode: ScrollMode) => void;
51
+ showCount: () => ShowMode;
52
+ setShowCount: (mode: ShowMode) => void;
53
+ showSearch: () => ShowMode;
54
+ setShowSearch: (mode: ShowMode) => void;
55
+ showQuickSettings: () => ShowMode;
56
+ setShowQuickSettings: (mode: ShowMode) => void;
57
+ showFavorites: () => ShowMode;
58
+ setShowFavorites: (mode: ShowMode) => void;
59
+ showPaging: () => ShowMode;
60
+ setShowPaging: (mode: ShowMode) => void;
61
+ searchScopes: () => SearchScope[];
62
+ setSearchScopes: (scopes: SearchScope[]) => void;
63
+ railOffset: () => number;
64
+ setRailOffset: (offset: number) => void;
65
+ cardCount: () => CardCount;
66
+ setCardCount: (count: CardCount) => void;
67
+ cardItems: () => CardItem[];
68
+ setCardItems: (items: CardItem[]) => void;
69
+ markTone: () => MarkTone;
70
+ setMarkTone: (tone: MarkTone) => void;
71
+ }
72
+ /** 悬停聚焦窗口项 */
73
+ export interface FocusWindowItem {
74
+ dot: RailMarker;
75
+ distance: number;
76
+ }
77
+ /** 聚焦状态:卡片呈现所需几何 */
78
+ export interface FocusState {
79
+ key: string;
80
+ items: FocusWindowItem[];
81
+ centerY: number;
82
+ left?: number;
83
+ right?: number;
84
+ }
85
+ /** 会话列表最小面(useSessions selector) */
86
+ export interface SessionListLike {
87
+ current?: unknown;
88
+ byId?: Record<string, {
89
+ blank?: boolean;
90
+ }>;
91
+ }
92
+ /** 翻译函数面 */
93
+ export type Translate = (key: string, vars?: Record<string, string | number>) => string;
94
+ /** 会话选择器面(useSessions 最小面,宿主按风格组件注入) */
95
+ export type SessionSelector = <S>(selector: (s: SessionListLike) => S) => S;
96
+ /** 风格组件统一 props 面(各风格自治实现,但入参一致) */
97
+ export interface RailProps {
98
+ injected: NavInjected | undefined;
99
+ useSessions?: SessionSelector;
100
+ t: Translate;
101
+ }
@@ -0,0 +1,9 @@
1
+ import type { NavConfig } from '../schema.ts';
2
+ export interface ScopeLike {
3
+ getSnapshot(): {
4
+ value?: NavConfig;
5
+ };
6
+ subscribe(fn: () => void): () => void;
7
+ set(field: string, value: unknown): Promise<void>;
8
+ unset(field: string): Promise<void>;
9
+ }
@@ -0,0 +1,17 @@
1
+ export interface ScrollLike {
2
+ getBoundingClientRect(): DOMRect;
3
+ querySelectorAll(selectors: string): NodeListOf<Element>;
4
+ scrollTo(opts: {
5
+ top: number;
6
+ behavior?: ScrollBehavior;
7
+ }): void;
8
+ }
9
+ export interface JumpTarget {
10
+ key: string;
11
+ }
12
+ /** 在滚动容器内按锚点 key 定位行元素(持久 id 精确 → 13:input-message 前缀兜底) */
13
+ export declare function findAnchorRow(scrollHost: ParentNode, key: string): Element | null;
14
+ /** 平滑滚动到行(reduced-motion 用瞬时;返回是否成功) */
15
+ export declare function scrollToRow(scrollHost: ScrollLike, row: Element, behavior: ScrollBehavior): boolean;
16
+ /** 原文脉冲高亮:给目标行挂临时 class,pulseMs 后移除 */
17
+ export declare function pulseRow(row: Element, pulseMs: number): () => void;
@@ -0,0 +1 @@
1
+ export declare function useAtBottom(threshold?: number): boolean;
@@ -0,0 +1,16 @@
1
+ export interface SessionLike {
2
+ loadOlder(): Promise<void>;
3
+ getSnapshot(): {
4
+ hasMore: boolean;
5
+ loadingOlder: boolean;
6
+ };
7
+ }
8
+ export interface JumpOptions {
9
+ getSession?(): SessionLike | undefined;
10
+ maxPages?: number;
11
+ }
12
+ export declare function useJump(scrollBehavior: 'smooth' | 'instant', pulseMs: number, opts?: JumpOptions): {
13
+ failed: boolean;
14
+ jumping: boolean;
15
+ jump: (key: string) => Promise<void>;
16
+ };
@@ -0,0 +1,12 @@
1
+ import type { AnchorRule } from '../pure.ts';
2
+ /** 行锚点缓存:一次扫描建立 key → 行元素(MutationObserver 失效重扫) */
3
+ export declare function scanAnchors(root: ParentNode): Map<string, Element>;
4
+ export interface ScrollSpyOptions {
5
+ rule: AnchorRule;
6
+ /** nav item 候选键(= 投影 items 的 key 列表) */
7
+ keys: readonly string[];
8
+ enabled: boolean;
9
+ /** 触底判定(新消息跟随:仍在底部 → 最新) */
10
+ atBottom?(): boolean;
11
+ }
12
+ export declare function useScrollSpy(opts: ScrollSpyOptions): string | null;
@@ -0,0 +1,7 @@
1
+ import type { NavConfig } from '../schema.ts';
2
+ export declare function useScope(scope?: {
3
+ getSnapshot(): {
4
+ value?: NavConfig;
5
+ };
6
+ subscribe(fn: () => void): () => void;
7
+ }): NavConfig | undefined;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Browser-half entry for the dsh-mega-chat-nav plugin.
3
+ *
4
+ * Registers one surface into the frame-wide floating layer (`shell.overlay`):
5
+ * a vertical strip on the LEFT edge of the conversation column listing every
6
+ * user question in the current session as a small button, one dot per turn.
7
+ * Clicking a button scrolls the chat to that turn's first question.
8
+ *
9
+ * The dots are driven by the host-folded `msgNavMessages` session projection
10
+ * (registered by the plugin's host half): the projection registry folds the
11
+ * WHOLE event log without touching the chat's paged render window, the
12
+ * projection cache persists it, and the standard carriers (history tail-page
13
+ * baseline + session/projection push frames) keep it live. Live-window
14
+ * questions not yet recorded by the projection are merged on top so a
15
+ * just-sent question appears immediately.
16
+ *
17
+ * Failure policy: nothing here throws at apply time — an external plugin must
18
+ * never take the GUI down.
19
+ */
20
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
21
+ /** Services required by this plugin. */
22
+ export declare const inject: string[];
23
+ /** Single-instance guard: a duplicated client injection must not mount twice. */
24
+ declare global {
25
+ var __dshMegaChatNavApplied: boolean | undefined;
26
+ }
27
+ /**
28
+ * Register the mega-chat-nav surface.
29
+ * @param ctx - client root context.
30
+ */
31
+ export declare function apply(ctx: ClientContext): void;
@@ -0,0 +1,47 @@
1
+ /** 跳转循环所需的会话快照面 */
2
+ export interface JumpSnapshot {
3
+ openState: string;
4
+ hasMore: boolean;
5
+ loadingOlder: boolean;
6
+ rows: Iterable<{
7
+ key: string;
8
+ anchorSeq: number;
9
+ visibility?: string;
10
+ }>;
11
+ }
12
+ /** 外部端口:会话读写、DOM 行查找、滚动与时钟(由浏览器半装配) */
13
+ export interface JumpPorts {
14
+ snap: () => JumpSnapshot | undefined;
15
+ loadMore: () => Promise<void>;
16
+ active: () => boolean;
17
+ locate: (key: string) => HTMLElement | null;
18
+ reveal: (row: HTMLElement, mode: 'smooth' | 'instant') => void;
19
+ /** 会话滚动容器(虚拟渲染按 scrollTop 触发) */
20
+ scrollport: () => HTMLElement | null;
21
+ now: () => number;
22
+ sleep: (ms: number) => Promise<void>;
23
+ report?: (code: JumpFailureCode, fallback?: boolean) => void;
24
+ /** 扩窗加载进度(loading 状态 + 已加载页数),驱动「正在加载较早记录」提示 */
25
+ onLoading?: (loading: boolean, pages: number) => void;
26
+ }
27
+ export type JumpFailureCode = 'VIEW_INACTIVE' | 'TARGET_HIDDEN' | 'NOT_FOUND' | 'TIMEOUT';
28
+ interface JumpResult {
29
+ ok: boolean;
30
+ code?: JumpFailureCode;
31
+ fallback?: boolean;
32
+ }
33
+ interface JumpOptions {
34
+ totalTimeoutMs?: number;
35
+ maxPages?: number;
36
+ rowWaitMs?: number;
37
+ pollMs?: number;
38
+ }
39
+ /**
40
+ * 跳转到 key 对应行:
41
+ * - 目标已在渲染窗口 → 等待 DOM 并滚动;
42
+ * - 目标在下方/窗口内(targetSeq ≥ 渲染窗口最小值)→ 向下滚动定位(无需加载);
43
+ * - 目标更早(targetSeq < 渲染窗口最小值 或未知)→ 预算内 loadOlder 补历史,每页后向上滚动定位;
44
+ * - 全部失败 → 回退最近可渲染行。
45
+ */
46
+ export declare function goTo(ports: JumpPorts, key: string, options?: JumpOptions, mode?: 'smooth' | 'instant', targetSeq?: number, currentSeq?: number): Promise<JumpResult>;
47
+ export {};
@@ -0,0 +1,142 @@
1
+ /**
2
+ * mega-chat-nav 词条字典(zh/en)。注册于 `mega-chat-nav` 命名空间;
3
+ * key 经绑定翻译函数消费。
4
+ */
5
+ export declare const zh: {
6
+ readonly 'strip.empty': "本会话还没有提问";
7
+ readonly 'strip.up': "向上翻出更多提问圆点";
8
+ readonly 'strip.down': "向下翻出更多提问圆点";
9
+ readonly 'jump.inactive': "聊天视图未激活";
10
+ readonly 'jump.hidden': "目标无独立气泡,已定位到邻近内容";
11
+ readonly 'jump.notfound': "目标未加载或不存在(可能已压缩)";
12
+ readonly 'jump.timeout': "加载历史超时,可重试";
13
+ readonly 'jump.loading': "正在加载较早记录以定位(第 {n} 页)";
14
+ readonly 'search.historic': "另有 {n} 条来自更早历史";
15
+ readonly 'search.turnTitle': "第 {turn} 轮";
16
+ readonly 'search.tag.user': "用户";
17
+ readonly 'search.tag.assistant': "助手";
18
+ readonly 'search.tag.tool': "工具";
19
+ readonly 'settings.tab': "提问导航";
20
+ readonly label: "mega 导航";
21
+ readonly 'config.align': "对齐方式";
22
+ readonly 'config.railOffset': "导航栏偏移";
23
+ readonly 'config.railOffset.desc': "导航条与对话列边缘的距离(0-32px,随左右对齐自适应)。";
24
+ readonly 'settings.align.desc': "选择圆点导航条锚定在对话栏的哪一侧。";
25
+ readonly 'settings.align.left': "左侧";
26
+ readonly 'settings.align.right': "右侧";
27
+ readonly 'settings.hosted': "配置已收纳至 mega 设置中心";
28
+ readonly 'config.bandHeight': "节点栏高度";
29
+ readonly 'config.bandHeight.desc': "节点栏的最大高度。";
30
+ readonly 'config.bandHeight.compact': "紧凑";
31
+ readonly 'config.bandHeight.standard': "标准";
32
+ readonly 'config.bandHeight.tall': "高";
33
+ readonly 'config.title': "导航条设置";
34
+ readonly 'config.settings': "设置";
35
+ readonly 'config.close': "关闭";
36
+ readonly 'config.scrollBehavior': "跳转动画";
37
+ readonly 'config.scrollBehavior.desc': "点击跳转时消息滚入的动画方式。";
38
+ readonly 'config.scrollBehavior.smooth': "平滑";
39
+ readonly 'config.scrollBehavior.instant': "瞬时";
40
+ readonly 'config.showCount': "轮次总数";
41
+ readonly 'config.showPaging': "翻页标记";
42
+ readonly 'config.showQuickSettings': "设置按钮";
43
+ readonly 'config.showFavorites': "收藏按钮";
44
+ readonly 'config.searchScopes': "搜索内容";
45
+ readonly 'config.searchScopes.desc': "搜索哪些消息类型(多选;用户必选)。";
46
+ readonly 'config.searchScopes.user': "用户";
47
+ readonly 'config.searchScopes.assistant': "助手";
48
+ readonly 'config.searchScopes.tool': "工具";
49
+ readonly 'config.style': "风格";
50
+ readonly 'config.style.minimal': "简约";
51
+ readonly 'config.style.codex': "Codex";
52
+ readonly 'config.style.deepseek': "Deepseek Chat";
53
+ readonly 'config.cardCount': "悬停卡片数";
54
+ readonly 'config.cardCount.desc': "悬停节点时弹出的卡片数量(1/3/5 张)。";
55
+ readonly 'config.cardItems': "悬浮卡功能";
56
+ readonly 'config.cardItems.desc': "勾选悬浮卡显示的内容块(多选)。";
57
+ readonly 'config.cardItems.turn': "轮次";
58
+ readonly 'config.cardItems.duration': "用时";
59
+ readonly 'config.cardItems.favorite': "收藏";
60
+ readonly 'config.markTone': "刻度色调";
61
+ readonly 'config.markTone.desc': "codex 刻度条的明暗档:柔和低对比 / 深邃高对比(默认)。";
62
+ readonly 'config.markTone.soft': "柔和";
63
+ readonly 'config.markTone.deep': "深邃";
64
+ readonly 'fav.filter': "只看收藏";
65
+ readonly 'strip.noFavorites': "暂无收藏";
66
+ readonly 'config.showSearch': "搜索按钮";
67
+ readonly 'config.showMode.show': "显示";
68
+ readonly 'config.showMode.peek': "浮现";
69
+ readonly 'config.showMode.hide': "隐藏";
70
+ readonly 'search.placeholder': "搜索消息…";
71
+ readonly 'search.empty': "无匹配结果";
72
+ readonly 'search.loading': "正在搜索…";
73
+ };
74
+ export declare const en: {
75
+ readonly 'strip.empty': "No questions in this session yet";
76
+ readonly 'strip.up': "Reveal more question dots above";
77
+ readonly 'strip.down': "Reveal more question dots below";
78
+ readonly 'jump.inactive': "Chat view is not active";
79
+ readonly 'jump.hidden': "No dedicated bubble; landed on nearby content";
80
+ readonly 'jump.notfound': "Target not loaded or missing (maybe compacted)";
81
+ readonly 'jump.timeout': "Timed out loading history; retry";
82
+ readonly 'jump.loading': "Loading earlier records to locate (page {n})";
83
+ readonly 'search.historic': "{n} more from earlier history";
84
+ readonly 'search.turnTitle': "Turn {turn}";
85
+ readonly 'search.tag.user': "User";
86
+ readonly 'search.tag.assistant': "Assistant";
87
+ readonly 'search.tag.tool': "Tool";
88
+ readonly 'settings.tab': "Question Nav";
89
+ readonly label: "Mega Nav";
90
+ readonly 'config.align': "Alignment";
91
+ readonly 'config.railOffset': "Rail offset";
92
+ readonly 'config.railOffset.desc': "Distance between the rail and the conversation edge (0-32px, adapts to alignment).";
93
+ readonly 'settings.align.desc': "Choose which edge of the conversation column the dot rail anchors to.";
94
+ readonly 'settings.align.left': "Left";
95
+ readonly 'settings.align.right': "Right";
96
+ readonly 'settings.hosted': "Config is hosted in the mega settings center";
97
+ readonly 'config.bandHeight': "Band height";
98
+ readonly 'config.bandHeight.desc': "Max height of the dot band.";
99
+ readonly 'config.bandHeight.compact': "Compact";
100
+ readonly 'config.bandHeight.standard': "Standard";
101
+ readonly 'config.bandHeight.tall': "Tall";
102
+ readonly 'config.title': "Nav settings";
103
+ readonly 'config.settings': "Settings";
104
+ readonly 'config.close': "Close";
105
+ readonly 'config.scrollBehavior': "Jump animation";
106
+ readonly 'config.scrollBehavior.desc': "How the chat scrolls when jumping to a message.";
107
+ readonly 'config.scrollBehavior.smooth': "Smooth";
108
+ readonly 'config.scrollBehavior.instant': "Instant";
109
+ readonly 'config.showCount': "Turn count";
110
+ readonly 'config.showPaging': "Paging markers";
111
+ readonly 'config.showQuickSettings': "Settings button";
112
+ readonly 'config.showFavorites': "Favorite button";
113
+ readonly 'config.searchScopes': "Search content";
114
+ readonly 'config.searchScopes.desc': "Message types included in search (multi-select; user is required).";
115
+ readonly 'config.searchScopes.user': "User";
116
+ readonly 'config.searchScopes.assistant': "Assistant";
117
+ readonly 'config.searchScopes.tool': "Tool";
118
+ readonly 'config.style': "Style";
119
+ readonly 'config.style.minimal': "Minimal";
120
+ readonly 'config.style.codex': "Codex";
121
+ readonly 'config.style.deepseek': "Deepseek Chat";
122
+ readonly 'config.cardCount': "Card count";
123
+ readonly 'config.cardCount.desc': "Cascade cards shown on hover (1/3/5).";
124
+ readonly 'config.cardItems': "Card contents";
125
+ readonly 'config.cardItems.desc': "Content blocks shown on hover cards (multi-select).";
126
+ readonly 'config.cardItems.turn': "Turn";
127
+ readonly 'config.cardItems.duration': "Duration";
128
+ readonly 'config.cardItems.favorite': "Favorite";
129
+ readonly 'config.markTone': "Mark tone";
130
+ readonly 'config.markTone.desc': "Codex tick contrast: soft / deep (default).";
131
+ readonly 'config.markTone.soft': "Soft";
132
+ readonly 'config.markTone.deep': "Deep";
133
+ readonly 'fav.filter': "Favorites only";
134
+ readonly 'strip.noFavorites': "No favorites yet";
135
+ readonly 'config.showSearch': "Search button";
136
+ readonly 'config.showMode.show': "Show";
137
+ readonly 'config.showMode.peek': "Peek";
138
+ readonly 'config.showMode.hide': "Hide";
139
+ readonly 'search.placeholder': "Search messages…";
140
+ readonly 'search.empty': "No matches";
141
+ readonly 'search.loading': "Searching…";
142
+ };
@@ -0,0 +1,21 @@
1
+ export type AnchorRule = 'line40' | 'top' | 'center' | 'lastInteraction';
2
+ /** TabGate:chat 视图可见(R-10)——滚动容器存在且几何 >0 */
3
+ export declare function isChatViewVisible(doc: Document): boolean;
4
+ /** TabGate:Trajectory(轨迹)视图在场时 nav 停用 */
5
+ export declare function hasTrajectoryView(doc: Document): boolean;
6
+ /** 锚点规则 → 阅读线 Y(视口坐标系) */
7
+ export declare function readingLineY(viewport: {
8
+ top: number;
9
+ height: number;
10
+ }, rule: AnchorRule): number;
11
+ /** 距阅读线最近条目索引(40% 线主流判据;无条目返回 -1) */
12
+ export declare function nearestIndex(total: number, line: number, yOf: (i: number) => number): number;
13
+ /** 虚拟滚动窗口(可见 + 前后缓冲;hover/current 由调用方钉住) */
14
+ export declare function virtualWindow(total: number, scrollTop: number, viewportH: number, itemH: number, buffer?: number): {
15
+ start: number;
16
+ end: number;
17
+ };
18
+ /** 相对时间(秒/分钟/小时/天) */
19
+ export declare function formatTime(ts: number, now?: number): string;
20
+ /** 截断到 n 字符并加省略号 */
21
+ export declare function truncate(s: string, n: number): string;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Browser mirror of the `mega-chat-nav` settings namespace: reads the rail
3
+ * settings from the settings scope (`ctx.settingsScope.bind`) and routes the
4
+ * user's choices back through the host bridge (POST /mega-chat-nav/settings).
5
+ *
6
+ * 配置选项为本插件自有定义:此处为 client 半持有的同值副本(与 host 半
7
+ * src/settings.ts 一致;client bundle 不得依赖宿主包)。
8
+ *
9
+ * The settings surface is optional and may apply after this plugin, so the
10
+ * controller starts unbound and degrades to the defaults until {@link attach}
11
+ * binds the scope.
12
+ *
13
+ * @module dsh-mega-chat-nav/client/settings
14
+ */
15
+ import type { SettingsScope, SettingsScopeSpec } from '@deepseek-ai/dsh-client-runtime/client';
16
+ /** 风格选项:简约 / codex(时间线刻度)/ deepseek(用户消息面板,常态短横折叠) */
17
+ export declare const STYLE_OPTIONS: readonly ["minimal", "codex", "deepseek"];
18
+ export type NavStyle = typeof STYLE_OPTIONS[number];
19
+ /** 停靠侧选项 */
20
+ export declare const ALIGN_OPTIONS: readonly ["left", "right"];
21
+ export type RailAlign = typeof ALIGN_OPTIONS[number];
22
+ /** 节点栏条带高度档位 */
23
+ export declare const BAND_OPTIONS: readonly ["compact", "standard", "tall"];
24
+ export type BandHeight = typeof BAND_OPTIONS[number];
25
+ /** 跳转动画方式 */
26
+ export declare const SCROLL_OPTIONS: readonly ["smooth", "instant"];
27
+ export type ScrollMode = typeof SCROLL_OPTIONS[number];
28
+ /** 显示策略:常显 / 悬停浮现 / 隐藏 */
29
+ export declare const SHOW_OPTIONS: readonly ["show", "peek", "hide"];
30
+ export type ShowMode = typeof SHOW_OPTIONS[number];
31
+ /** 翻页标记显示策略(按风格独立默认):minimal 常显 / codex 隐藏 / deepseek 浮现 */
32
+ export declare const DEFAULT_PAGING: Record<NavStyle, ShowMode>;
33
+ /** 搜索内容范围(多选;用户必选) */
34
+ export declare const SEARCH_SCOPE_OPTIONS: readonly ["user", "assistant", "tool"];
35
+ export type SearchScope = typeof SEARCH_SCOPE_OPTIONS[number];
36
+ export declare const DEFAULT_SEARCH_SCOPES: SearchScope[];
37
+ /** 悬停卡片数量 */
38
+ export declare const CARD_OPTIONS: readonly [1, 3, 5];
39
+ export type CardCount = typeof CARD_OPTIONS[number];
40
+ /** 悬浮卡默认数量(按风格独立):minimal 3 张 / codex 1 张 / deepseek 1 张(无悬浮卡能力,占位) */
41
+ export declare const DEFAULT_CARD_COUNT: Record<NavStyle, CardCount>;
42
+ /** 悬浮卡内容块(多选) */
43
+ export declare const CARD_ITEM_OPTIONS: readonly ["turn", "duration", "favorite"];
44
+ export type CardItem = typeof CARD_ITEM_OPTIONS[number];
45
+ export declare const DEFAULT_CARD_ITEMS: CardItem[];
46
+ /** 刻度色调:柔和(低对比)/ 深邃(高对比、清晰) */
47
+ export declare const MARK_TONE_OPTIONS: readonly ["soft", "deep"];
48
+ export type MarkTone = typeof MARK_TONE_OPTIONS[number];
49
+ export declare const DEFAULT_MARK_TONE: MarkTone;
50
+ export declare const DEFAULT_STYLE: NavStyle;
51
+ export declare const DEFAULT_ALIGN: RailAlign;
52
+ export declare const DEFAULT_BAND: BandHeight;
53
+ export declare const DEFAULT_SCROLL: ScrollMode;
54
+ export declare const DEFAULT_SHOW: ShowMode;
55
+ /** 条带高度档位 → 像素(minimal/codex 共用基础几何;deepseek 行高 30px 自成一档)
56
+ * - minimal / codex:compact 140 / standard 210 / tall 280
57
+ * - deepseek:compact 160 / standard 220 / tall 280 */
58
+ export declare const BAND_HEIGHT_PX: Record<NavStyle, Record<BandHeight, number>>;
59
+ /** 风格能力:各风格声明自己的可选能力(组件与设置面据此取舍) */
60
+ export interface StyleCapabilities {
61
+ /** 悬停悬浮卡片(级联预览)——deepseek 面板自带消息预览,不需要 */
62
+ hoverCards: boolean;
63
+ /** ▲/▼ 翻页标志(deepseek 面板内滚动,不需要显式翻页按钮) */
64
+ paging: boolean;
65
+ }
66
+ /** 风格 → 能力表 */
67
+ export declare const STYLE_CAPABILITIES: Record<NavStyle, StyleCapabilities>;
68
+ /** 本插件设置命名空间 */
69
+ export declare const MGCN_NS = "mega-chat-nav";
70
+ /** 导航栏偏移(px)范围与默认值 */
71
+ export declare const RAIL_OFFSET_MIN = 0;
72
+ export declare const RAIL_OFFSET_MAX = 32;
73
+ export declare const DEFAULT_RAIL_OFFSET = 8;
74
+ /** The minimal face of the settings scope service this controller needs. */
75
+ export interface SettingsScopeBinderLike {
76
+ bind<T>(spec: SettingsScopeSpec<T>): SettingsScope<T>;
77
+ }
78
+ /** Snapshot consumed by the strip and the settings rows. */
79
+ export interface NavSettingsState {
80
+ /** Last accepted style. */
81
+ style: NavStyle;
82
+ /** Last accepted anchor edge (default while the scope is absent/loading). */
83
+ align: RailAlign;
84
+ /** Last accepted band height tier. */
85
+ bandHeight: BandHeight;
86
+ /** Last accepted jump scroll mode. */
87
+ scrollBehavior: ScrollMode;
88
+ /** Turn-count badge display mode. */
89
+ showCount: ShowMode;
90
+ /** Search button display mode. */
91
+ showSearch: ShowMode;
92
+ /** Quick settings gear display mode. */
93
+ showQuickSettings: ShowMode;
94
+ /** Favorite filter button display mode. */
95
+ showFavorites: ShowMode;
96
+ /** 翻页标记显示模式(show=常显 / peek=浮现 / hide=隐藏) */
97
+ showPaging: ShowMode;
98
+ /** 搜索内容范围(多选;用户必选) */
99
+ searchScopes: SearchScope[];
100
+ /** 导航栏偏移距离(px,随左右对齐自适应) */
101
+ railOffset: number;
102
+ /** Hover cascade card count. */
103
+ cardCount: CardCount;
104
+ /** 悬浮卡内容块(多选:轮次 / 用时 / 收藏) */
105
+ cardItems: CardItem[];
106
+ /** 刻度色调(codex 刻度轨;minimal 忽略) */
107
+ markTone: MarkTone;
108
+ /** Whether the user layer overrides the composition default. */
109
+ overridden: boolean;
110
+ }
111
+ /** Reactive handle over the plugin's durable settings section. */
112
+ export declare class NavSettingsController {
113
+ private scope;
114
+ private readonly listeners;
115
+ private unsubscribe;
116
+ private state;
117
+ /**
118
+ * Bind the namespace scope once the settings surface is present.
119
+ * A no-op after the first bind.
120
+ */
121
+ attach(binder: SettingsScopeBinderLike): void;
122
+ /** 当前生效风格的 styles.<style> 段(快照内读取,供逐风格独立取值) */
123
+ private styleSection;
124
+ private derive;
125
+ /** Release the scope subscription. */
126
+ dispose(): void;
127
+ /** 乐观提交:更新状态并立即通知(UI 即时反映) */
128
+ private commit;
129
+ /** 当前 general 段(setter 整段写回用) */
130
+ private get general();
131
+ /** 当前风格段的完整值(setter 局部 patch 的基础) */
132
+ private get styleValues();
133
+ /** 按当前风格构造 write 的 styles 段(只含当前风格键,绝不染指其他风格段) */
134
+ private stylePatch;
135
+ /** @returns the current state (stable reference until the next change). */
136
+ getSnapshot(): NavSettingsState;
137
+ /** Observe state replacements; returns the disposer. */
138
+ subscribe(listener: () => void): () => void;
139
+ /**
140
+ * 写回宿主:scope.set 契约只接受 section 内**标量**字段,嵌套 section
141
+ * (general/styles 对象)无法经它持久化,所以走 host 桥
142
+ * (POST /mega-chat-nav/settings → settings.update 深层 merge + revision 围栏)。
143
+ */
144
+ private write;
145
+ /** Route the user's anchor-edge choice to the Host document. */
146
+ setAlign(align: RailAlign): void;
147
+ /** Route the user's style choice to the Host document(切换后随即载入该风格自己的独立配置) */
148
+ setStyle(style: NavStyle): void;
149
+ /** Route the user's band-height choice to the Host document(写入当前风格的独立段) */
150
+ setBandHeight(band: BandHeight): void;
151
+ /** Route the user's scroll-mode choice to the Host document. */
152
+ setScrollMode(mode: ScrollMode): void;
153
+ /** Route the user's count-badge display mode to the Host document. */
154
+ setShowCount(mode: ShowMode): void;
155
+ /** Route the user's search-button display mode to the Host document. */
156
+ setShowSearch(mode: ShowMode): void;
157
+ /** Route the user's quick-settings display mode to the Host document. */
158
+ setShowQuickSettings(mode: ShowMode): void;
159
+ /** Route the user's favorite-button display mode to the Host document. */
160
+ setShowFavorites(mode: ShowMode): void;
161
+ /** Route the user's paging-marker display mode to the Host document(写入当前风格独立段) */
162
+ setShowPaging(mode: ShowMode): void;
163
+ /** Route the user's search-scope selection to the Host document(用户必选,强制保留且置于首位) */
164
+ setSearchScopes(scopes: SearchScope[]): void;
165
+ /** Route the user's rail-offset choice to the Host document(0-32px 取整钳制) */
166
+ setRailOffset(offset: number): void;
167
+ /** Route the user's cascade-card count to the Host document(写入当前风格的独立段) */
168
+ setCardCount(count: CardCount): void;
169
+ /** Route the user's card-content selection to the Host document(写入当前风格的独立段) */
170
+ setCardItems(items: CardItem[]): void;
171
+ /** Route the user's mark-tone choice to the Host document(codex 刻度色调;写入当前风格段) */
172
+ setMarkTone(tone: MarkTone): void;
173
+ }
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface VirtualListProps<T> {
3
+ items: readonly T[];
4
+ itemHeight: number;
5
+ viewportHeight: number;
6
+ scrollTop: number;
7
+ onScrollTopChange(top: number): void;
8
+ renderItem(item: T, index: number): ReactNode;
9
+ keyOf(item: T, index: number): string;
10
+ pinned?: ReadonlySet<string>;
11
+ overscan?: number;
12
+ listRef?: React.Ref<HTMLDivElement>;
13
+ onKeyDown?: (e: React.KeyboardEvent) => void;
14
+ }
15
+ export declare function VirtualList<T>(props: VirtualListProps<T>): ReactNode;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * dsh 版本校验器(纯函数,零依赖:宿主侧 / 单测均可用)。
3
+ *
4
+ * 语义(对齐官方 deepseek-harness tag 线,如 dsh-v0.1.1-rc.2):
5
+ * - 比较按语义化版本:主/次/修订号数值比较优先;
6
+ * - 同基线预发布排序:alpha < rc(标识符字典序),数字标识按数值比较;
7
+ * - 正式版(无预发布)高于同基线任意预发布(0.1.1 > 0.1.1-rc.2);
8
+ * - 支持操作符:> < =(另附 >= <=);
9
+ * - 通配:仅 '=' 支持,如 '0.1.1-*' 匹配该基线的任意预发布(0.1.1-rc.1 / 0.1.1-rc.2 …);
10
+ * '*' 作为标识段时吞掉其后的全部剩余标识。
11
+ */
12
+ export type DshCmpOp = '>' | '>=' | '<' | '<=' | '=';
13
+ /** 兼容策略:当前 dsh 版本与目标的比较约束。 */
14
+ export interface DshCompatPolicy {
15
+ op: DshCmpOp;
16
+ /**
17
+ * 目标版本(可含通配,如 0.1.1-*,仅 op='=' 生效)。
18
+ * 支持数组:命中其中任一版本即通过,如 ['0.1.1-*', '0.1.2-rc.1']。
19
+ */
20
+ target: string | readonly string[];
21
+ }
22
+ export interface DshVersionParts {
23
+ /** [major, minor, patch] */
24
+ base: [number, number, number];
25
+ /** 预发布标识数组(rc、alpha、数字…);无预发布 = null */
26
+ pre: string[] | null;
27
+ }
28
+ /** 解析 dsh 版本串;非法返回 null(不支持 x.y / 纯数字 etc.)。 */
29
+ export declare function parseDshVersion(v: string): DshVersionParts | null;
30
+ /**
31
+ * 语义化比较:a < b → -1;相等 → 0;a > b → 1;任一无法解析 → NaN。
32
+ */
33
+ export declare function compareDshVersions(a: string, b: string): number;
34
+ /** 操作符比较(非法版本一律 false)。 */
35
+ export declare function checkDshVersion(current: string, op: DshCmpOp, target: string): boolean;
36
+ /**
37
+ * 通配相等(仅配合 op='='):pattern 形如 0.1.1-*(任意预发布)、0.1.1-rc.*、
38
+ * 0.1.*(任意小版本)等;'*' 匹配 ≥1 个标识。例:0.1.1-* 命中 0.1.1-rc.1 / 0.1.1-rc.2。
39
+ */
40
+ export declare function wildcardEqual(version: string, pattern: string): boolean;
41
+ /** 策略校验:target 为数组时命中任一即通过;通配(如 0.1.1-*)仅在 op='=' 时参与。 */
42
+ export declare function checkDshPolicy(current: string, policy: DshCompatPolicy): boolean;
43
+ /** 不兼容时的控制台提示文案(xxx = 检测到的当前 dsh 版本)。 */
44
+ export declare function dshCompatMessage(pluginName: string, currentDshVersion: string): string;