@yushaw/sanqian-chat 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -114,3 +114,24 @@ src/renderer/styles/
114
114
  - **Fixed**: `console.log` only outputs in `devMode`
115
115
  - **Fixed**: Global style pollution - default to `'safe'` mode (no Tailwind preflight)
116
116
  - **Fixed**: `cancelStream` now calls `sdk.cancelRun()` for real cancellation
117
+
118
+ ## Tech Debt / Future Optimizations
119
+
120
+ ### Low Priority (记录于 2026-01-05)
121
+
122
+ 1. **FloatingChat 命名优化**
123
+ - `FloatingChat` 实际是通用组件(embedded + floating),名字有误导
124
+ - 可考虑改名为 `ChatContainer` 或 `ChatView`
125
+ - 文件:`src/renderer/components/FloatingChat.tsx`
126
+
127
+ 2. **Header 按钮复用**
128
+ - `FloatingChat` 内联了 `<ModeToggleButton>` + `<AttachButton>`
129
+ - 可改用 `<PanelHeaderButtons />` 与 `CompactChat` 保持一致
130
+ - 文件:`src/renderer/components/FloatingChat.tsx:134-136`
131
+
132
+
133
+ 3. **useCallback 依赖优化** (微优化)
134
+ - `useAttachState.ts:68`: toggle 依赖 state,每次 state 变化重建
135
+ - `useChatPanel.ts:86`: toggleMode 依赖 mode,每次 mode 变化重建
136
+ - 可用 useRef 避免重建,但当前影响可忽略
137
+ - 文件:`src/renderer/hooks/useAttachState.ts`, `src/renderer/hooks/useChatPanel.ts`
@@ -57,6 +57,12 @@ interface ChatUiStrings {
57
57
  hitlInputRequest: string;
58
58
  hitlApprovalRequired: string;
59
59
  hitlInputRequired: string;
60
+ attachWindow: string;
61
+ detachWindow: string;
62
+ floatWindow: string;
63
+ embedWindow: string;
64
+ collapseSidebar: string;
65
+ history: string;
60
66
  }
61
67
  type ChatThemeMode = 'light' | 'dark' | 'auto';
62
68
  type ChatFontSize = 'small' | 'normal' | 'large' | 'extra-large';
@@ -154,6 +160,153 @@ interface FloatingWindowConfig {
154
160
  /** Optional full path for window state file */
155
161
  windowStatePath?: string;
156
162
  }
163
+ type ChatPanelMode = 'embedded' | 'floating';
164
+ type ChatPanelPosition = 'right' | 'left';
165
+ type AttachState = 'attached' | 'detached' | 'unavailable';
166
+ type AttachPosition = 'right' | 'left' | 'top' | 'bottom';
167
+ /**
168
+ * Window attachment configuration for floating mode
169
+ */
170
+ interface AttachConfig {
171
+ /**
172
+ * Target window to attach to (BrowserWindow instance)
173
+ */
174
+ window: unknown;
175
+ /**
176
+ * Attach position relative to target window
177
+ * @default 'right'
178
+ */
179
+ position?: AttachPosition;
180
+ /**
181
+ * Gap between windows (px)
182
+ * @default 0
183
+ */
184
+ gap?: number;
185
+ /**
186
+ * Sync height/width with target window
187
+ * @default true
188
+ */
189
+ syncSize?: boolean;
190
+ /**
191
+ * Behavior when target window is minimized
192
+ * @default 'hide'
193
+ */
194
+ onMinimize?: 'hide' | 'detach' | 'minimize';
195
+ /**
196
+ * Behavior when target window is closed
197
+ * @default 'hide'
198
+ */
199
+ onClose?: 'hide' | 'destroy';
200
+ /**
201
+ * Allow user to drag and detach
202
+ * @default true
203
+ */
204
+ allowDetach?: boolean;
205
+ /**
206
+ * Allow re-attach when dragged near target edge
207
+ * @default true
208
+ */
209
+ allowReattach?: boolean;
210
+ /**
211
+ * Distance threshold for re-attach (px)
212
+ * @default 20
213
+ */
214
+ reattachThreshold?: number;
215
+ }
216
+ /**
217
+ * ChatPanel configuration
218
+ */
219
+ interface ChatPanelConfig {
220
+ /**
221
+ * Host window (BaseWindow supports embedded, BrowserWindow floating only)
222
+ */
223
+ hostWindow: unknown;
224
+ /**
225
+ * Host window's main content view (required for embedded mode)
226
+ */
227
+ hostMainView?: unknown;
228
+ /**
229
+ * Initial mode
230
+ * @default 'embedded'
231
+ */
232
+ initialMode?: ChatPanelMode;
233
+ /**
234
+ * Embed position
235
+ * @default 'right'
236
+ */
237
+ position?: ChatPanelPosition;
238
+ /**
239
+ * Panel width
240
+ * @default 360
241
+ */
242
+ width?: number;
243
+ /**
244
+ * Minimum width
245
+ * @default 240
246
+ */
247
+ minWidth?: number;
248
+ /**
249
+ * Minimum host content width when showing panel.
250
+ * If window is too narrow, expand it to ensure main content has this width.
251
+ * Set to 0 to disable auto-expand.
252
+ * @default 0
253
+ */
254
+ minHostContentWidth?: number;
255
+ /**
256
+ * Allow resize
257
+ * @default true
258
+ */
259
+ resizable?: boolean;
260
+ /**
261
+ * Preload script path
262
+ */
263
+ preloadPath: string;
264
+ /**
265
+ * Renderer HTML path or URL
266
+ */
267
+ rendererPath: string;
268
+ /**
269
+ * Dev mode - load URL instead of file
270
+ */
271
+ devMode?: boolean;
272
+ /**
273
+ * SDK client getter
274
+ */
275
+ getClient: () => unknown;
276
+ /**
277
+ * Agent ID getter
278
+ */
279
+ getAgentId: () => string | null;
280
+ /**
281
+ * Layout change callback (for host app to adjust main content)
282
+ */
283
+ onLayoutChange?: (layout: {
284
+ mainWidth: number;
285
+ chatWidth: number;
286
+ chatVisible: boolean;
287
+ }) => void;
288
+ /**
289
+ * Shortcut configuration
290
+ */
291
+ shortcuts?: {
292
+ /** Toggle show/hide, false to disable */
293
+ toggle?: string | false;
294
+ /** Toggle mode, false to disable */
295
+ toggleMode?: string | false;
296
+ };
297
+ /**
298
+ * Floating window attach configuration
299
+ */
300
+ attach?: AttachConfig;
301
+ /**
302
+ * State persistence key
303
+ */
304
+ stateKey?: string;
305
+ /**
306
+ * UI config for renderer
307
+ */
308
+ uiConfig?: ChatUiConfigSerializable;
309
+ }
157
310
 
158
311
  /**
159
312
  * Chat Adapter Interface
@@ -327,4 +480,4 @@ declare function parseToolCalls(toolCalls: unknown): ToolCall[] | undefined;
327
480
  */
328
481
  declare function mergeConsecutiveAssistantMessages(rawMessages: ApiMessage[]): ChatMessage[];
329
482
 
330
- export { type ApiMessage, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type SdkAdapterConfig, type SendMessage, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };
483
+ export { type ApiMessage, type AttachConfig, type AttachPosition, type AttachState, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatPanelConfig, type ChatPanelMode, type ChatPanelPosition, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type SdkAdapterConfig, type SendMessage, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };
@@ -57,6 +57,12 @@ interface ChatUiStrings {
57
57
  hitlInputRequest: string;
58
58
  hitlApprovalRequired: string;
59
59
  hitlInputRequired: string;
60
+ attachWindow: string;
61
+ detachWindow: string;
62
+ floatWindow: string;
63
+ embedWindow: string;
64
+ collapseSidebar: string;
65
+ history: string;
60
66
  }
61
67
  type ChatThemeMode = 'light' | 'dark' | 'auto';
62
68
  type ChatFontSize = 'small' | 'normal' | 'large' | 'extra-large';
@@ -154,6 +160,153 @@ interface FloatingWindowConfig {
154
160
  /** Optional full path for window state file */
155
161
  windowStatePath?: string;
156
162
  }
163
+ type ChatPanelMode = 'embedded' | 'floating';
164
+ type ChatPanelPosition = 'right' | 'left';
165
+ type AttachState = 'attached' | 'detached' | 'unavailable';
166
+ type AttachPosition = 'right' | 'left' | 'top' | 'bottom';
167
+ /**
168
+ * Window attachment configuration for floating mode
169
+ */
170
+ interface AttachConfig {
171
+ /**
172
+ * Target window to attach to (BrowserWindow instance)
173
+ */
174
+ window: unknown;
175
+ /**
176
+ * Attach position relative to target window
177
+ * @default 'right'
178
+ */
179
+ position?: AttachPosition;
180
+ /**
181
+ * Gap between windows (px)
182
+ * @default 0
183
+ */
184
+ gap?: number;
185
+ /**
186
+ * Sync height/width with target window
187
+ * @default true
188
+ */
189
+ syncSize?: boolean;
190
+ /**
191
+ * Behavior when target window is minimized
192
+ * @default 'hide'
193
+ */
194
+ onMinimize?: 'hide' | 'detach' | 'minimize';
195
+ /**
196
+ * Behavior when target window is closed
197
+ * @default 'hide'
198
+ */
199
+ onClose?: 'hide' | 'destroy';
200
+ /**
201
+ * Allow user to drag and detach
202
+ * @default true
203
+ */
204
+ allowDetach?: boolean;
205
+ /**
206
+ * Allow re-attach when dragged near target edge
207
+ * @default true
208
+ */
209
+ allowReattach?: boolean;
210
+ /**
211
+ * Distance threshold for re-attach (px)
212
+ * @default 20
213
+ */
214
+ reattachThreshold?: number;
215
+ }
216
+ /**
217
+ * ChatPanel configuration
218
+ */
219
+ interface ChatPanelConfig {
220
+ /**
221
+ * Host window (BaseWindow supports embedded, BrowserWindow floating only)
222
+ */
223
+ hostWindow: unknown;
224
+ /**
225
+ * Host window's main content view (required for embedded mode)
226
+ */
227
+ hostMainView?: unknown;
228
+ /**
229
+ * Initial mode
230
+ * @default 'embedded'
231
+ */
232
+ initialMode?: ChatPanelMode;
233
+ /**
234
+ * Embed position
235
+ * @default 'right'
236
+ */
237
+ position?: ChatPanelPosition;
238
+ /**
239
+ * Panel width
240
+ * @default 360
241
+ */
242
+ width?: number;
243
+ /**
244
+ * Minimum width
245
+ * @default 240
246
+ */
247
+ minWidth?: number;
248
+ /**
249
+ * Minimum host content width when showing panel.
250
+ * If window is too narrow, expand it to ensure main content has this width.
251
+ * Set to 0 to disable auto-expand.
252
+ * @default 0
253
+ */
254
+ minHostContentWidth?: number;
255
+ /**
256
+ * Allow resize
257
+ * @default true
258
+ */
259
+ resizable?: boolean;
260
+ /**
261
+ * Preload script path
262
+ */
263
+ preloadPath: string;
264
+ /**
265
+ * Renderer HTML path or URL
266
+ */
267
+ rendererPath: string;
268
+ /**
269
+ * Dev mode - load URL instead of file
270
+ */
271
+ devMode?: boolean;
272
+ /**
273
+ * SDK client getter
274
+ */
275
+ getClient: () => unknown;
276
+ /**
277
+ * Agent ID getter
278
+ */
279
+ getAgentId: () => string | null;
280
+ /**
281
+ * Layout change callback (for host app to adjust main content)
282
+ */
283
+ onLayoutChange?: (layout: {
284
+ mainWidth: number;
285
+ chatWidth: number;
286
+ chatVisible: boolean;
287
+ }) => void;
288
+ /**
289
+ * Shortcut configuration
290
+ */
291
+ shortcuts?: {
292
+ /** Toggle show/hide, false to disable */
293
+ toggle?: string | false;
294
+ /** Toggle mode, false to disable */
295
+ toggleMode?: string | false;
296
+ };
297
+ /**
298
+ * Floating window attach configuration
299
+ */
300
+ attach?: AttachConfig;
301
+ /**
302
+ * State persistence key
303
+ */
304
+ stateKey?: string;
305
+ /**
306
+ * UI config for renderer
307
+ */
308
+ uiConfig?: ChatUiConfigSerializable;
309
+ }
157
310
 
158
311
  /**
159
312
  * Chat Adapter Interface
@@ -327,4 +480,4 @@ declare function parseToolCalls(toolCalls: unknown): ToolCall[] | undefined;
327
480
  */
328
481
  declare function mergeConsecutiveAssistantMessages(rawMessages: ApiMessage[]): ChatMessage[];
329
482
 
330
- export { type ApiMessage, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type SdkAdapterConfig, type SendMessage, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };
483
+ export { type ApiMessage, type AttachConfig, type AttachPosition, type AttachState, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatPanelConfig, type ChatPanelMode, type ChatPanelPosition, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type SdkAdapterConfig, type SendMessage, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };